summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/bcachefs/alloc_background.c56
-rw-r--r--fs/bcachefs/alloc_background.h1
-rw-r--r--fs/bcachefs/bcachefs_format.h1
3 files changed, 38 insertions, 20 deletions
diff --git a/fs/bcachefs/alloc_background.c b/fs/bcachefs/alloc_background.c
index 59be66d8d9fc..a9150238d2d1 100644
--- a/fs/bcachefs/alloc_background.c
+++ b/fs/bcachefs/alloc_background.c
@@ -165,6 +165,7 @@ static int bch2_alloc_unpack_v3(struct bkey_alloc_unpacked *out,
out->oldest_gen = a.v->oldest_gen;
out->data_type = a.v->data_type;
out->need_discard = BCH_ALLOC_NEED_DISCARD(a.v);
+ out->need_inc_gen = BCH_ALLOC_NEED_INC_GEN(a.v);
out->journal_seq = le64_to_cpu(a.v->journal_seq);
#define x(_name, _bits) \
@@ -202,6 +203,7 @@ static void bch2_alloc_pack_v3(struct bkey_alloc_buf *dst,
a->v.data_type = src.data_type;
a->v.journal_seq = cpu_to_le64(src.journal_seq);
SET_BCH_ALLOC_NEED_DISCARD(&a->v, src.need_discard);
+ SET_BCH_ALLOC_NEED_INC_GEN(&a->v, src.need_inc_gen);
#define x(_name, _bits) \
nr_fields++; \
@@ -441,22 +443,18 @@ int bch2_trans_mark_alloc(struct btree_trans *trans,
unsigned flags)
{
struct bch_fs *c = trans->c;
- struct bch_dev *ca = bch_dev_bkey_exists(c, new->k.p.inode);
struct bkey_alloc_unpacked old_u = bch2_alloc_unpack(old);
struct bkey_alloc_unpacked new_u = bch2_alloc_unpack(bkey_i_to_s_c(new));
u64 old_lru, new_lru;
bool need_repack = false;
int ret = 0;
- if (old_u.data_type && !new_u.data_type && ca->mi.discard) {
- new_u.need_discard = true;
- need_repack = true;
- }
-
if (new_u.dirty_sectors > old_u.dirty_sectors ||
new_u.cached_sectors > old_u.cached_sectors) {
new_u.read_time = max_t(u64, 1, atomic64_read(&c->io_clock[READ].now));
new_u.write_time = max_t(u64, 1, atomic64_read(&c->io_clock[WRITE].now));
+ new_u.need_inc_gen = true;
+ new_u.need_discard = true;
need_repack = true;
}
@@ -464,6 +462,7 @@ int bch2_trans_mark_alloc(struct btree_trans *trans,
old_u.gen == new_u.gen &&
!bch2_bucket_is_open_safe(c, new->k.p.inode, new->k.p.offset)) {
new_u.gen++;
+ new_u.need_inc_gen = false;
need_repack = true;
}
@@ -741,7 +740,8 @@ err:
return ret < 0 ? ret : 0;
}
-static int bch2_clear_need_discard(struct btree_trans *trans, struct bpos pos)
+static int bch2_clear_need_discard(struct btree_trans *trans, struct bpos pos,
+ struct bch_dev *ca, bool *discard_done)
{
struct bch_fs *c = trans->c;
struct btree_iter iter;
@@ -758,6 +758,13 @@ static int bch2_clear_need_discard(struct btree_trans *trans, struct bpos pos)
goto out;
a = bch2_alloc_unpack(k);
+
+ if (a.need_inc_gen) {
+ a.gen++;
+ a.need_inc_gen = false;
+ goto write;
+ }
+
BUG_ON(a.journal_seq > c->journal.flushed_seq_ondisk);
if (bch2_fs_inconsistent_on(!a.need_discard, c,
@@ -767,7 +774,25 @@ static int bch2_clear_need_discard(struct btree_trans *trans, struct bpos pos)
goto out;
}
+ if (!*discard_done && ca->mi.discard && !c->opts.nochanges) {
+ /*
+ * This works without any other locks because this is the only
+ * thread that removes items from the need_discard tree
+ */
+ bch2_trans_unlock(trans);
+ blkdev_issue_discard(ca->disk_sb.bdev,
+ k.k->p.offset * ca->mi.bucket_size,
+ ca->mi.bucket_size,
+ GFP_KERNEL, 0);
+ *discard_done = true;
+
+ ret = bch2_trans_relock(trans);
+ if (ret)
+ goto out;
+ }
+
a.need_discard = false;
+write:
ret = bch2_alloc_write(trans, &iter, &a, 0);
out:
bch2_trans_iter_exit(trans, &iter);
@@ -788,6 +813,8 @@ static void bch2_do_discards_work(struct work_struct *work)
for_each_btree_key(&trans, iter, BTREE_ID_need_discard,
POS_MIN, 0, k, ret) {
+ bool discard_done = false;
+
if (ca && k.k->p.inode != ca->dev_idx) {
percpu_ref_put(&ca->io_ref);
ca = NULL;
@@ -808,20 +835,8 @@ static void bch2_do_discards_work(struct work_struct *work)
bch2_bucket_is_open_safe(c, k.k->p.inode, k.k->p.offset))
continue;
- bch2_trans_unlock(&trans);
-
- /*
- * This works without any other locks because this is the only
- * thread that removes items from the need_discard tree:
- */
- if (!c->opts.nochanges)
- blkdev_issue_discard(ca->disk_sb.bdev,
- k.k->p.offset * ca->mi.bucket_size,
- ca->mi.bucket_size,
- GFP_KERNEL, 0);
-
ret = __bch2_trans_do(&trans, NULL, NULL, 0,
- bch2_clear_need_discard(&trans, k.k->p));
+ bch2_clear_need_discard(&trans, k.k->p, ca, &discard_done));
if (ret)
break;
}
@@ -884,6 +899,7 @@ static int invalidate_one_bucket(struct btree_trans *trans, struct bch_dev *ca)
goto out;
a.gen++;
+ a.need_inc_gen = false;
a.data_type = 0;
a.dirty_sectors = 0;
a.cached_sectors = 0;
diff --git a/fs/bcachefs/alloc_background.h b/fs/bcachefs/alloc_background.h
index 7f4e1d8a93f2..06539e036f13 100644
--- a/fs/bcachefs/alloc_background.h
+++ b/fs/bcachefs/alloc_background.h
@@ -16,6 +16,7 @@ struct bkey_alloc_unpacked {
u8 oldest_gen;
u8 data_type;
bool need_discard:1;
+ bool need_inc_gen:1;
#define x(_name, _bits) u##_bits _name;
BCH_ALLOC_FIELDS_V2()
#undef x
diff --git a/fs/bcachefs/bcachefs_format.h b/fs/bcachefs/bcachefs_format.h
index bbc15aaea0af..bb54ac175b69 100644
--- a/fs/bcachefs/bcachefs_format.h
+++ b/fs/bcachefs/bcachefs_format.h
@@ -900,6 +900,7 @@ struct bch_alloc_v3 {
} __attribute__((packed, aligned(8)));
LE32_BITMASK(BCH_ALLOC_NEED_DISCARD,struct bch_alloc_v3, flags, 0, 1)
+LE32_BITMASK(BCH_ALLOC_NEED_INC_GEN,struct bch_alloc_v3, flags, 1, 2)
enum {
#define x(name, _bits) BCH_ALLOC_FIELD_V1_##name,