]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
bcachefs: discard fastpath now uses bch2_discard_one_bucket()
authorKent Overstreet <kent.overstreet@linux.dev>
Fri, 22 Nov 2024 01:09:45 +0000 (20:09 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sat, 21 Dec 2024 06:36:19 +0000 (01:36 -0500)
The discard bucket fastpath previously was using its own code for
discarding buckets and clearing them in the need_discard btree, which
didn't have any of the consistency checks of the main discard path.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/alloc_background.c

index ae9fdb5ad758f5e1554b606a4623a9151d84e7ea..1e9f53db4bb81e3259304cba96eaa4d5a1fcd763 100644 (file)
@@ -1725,7 +1725,8 @@ static int bch2_discard_one_bucket(struct btree_trans *trans,
                                   struct bch_dev *ca,
                                   struct btree_iter *need_discard_iter,
                                   struct bpos *discard_pos_done,
-                                  struct discard_buckets_state *s)
+                                  struct discard_buckets_state *s,
+                                  bool fastpath)
 {
        struct bch_fs *c = trans->c;
        struct bpos pos = need_discard_iter->pos;
@@ -1782,10 +1783,12 @@ static int bch2_discard_one_bucket(struct btree_trans *trans,
                goto out;
        }
 
-       if (discard_in_flight_add(ca, iter.pos.offset, true))
-               goto out;
+       if (!fastpath) {
+               if (discard_in_flight_add(ca, iter.pos.offset, true))
+                       goto out;
 
-       discard_locked = true;
+               discard_locked = true;
+       }
 
        if (!bkey_eq(*discard_pos_done, iter.pos) &&
            ca->mi.discard && !c->opts.nochanges) {
@@ -1799,6 +1802,7 @@ static int bch2_discard_one_bucket(struct btree_trans *trans,
                                     ca->mi.bucket_size,
                                     GFP_KERNEL);
                *discard_pos_done = iter.pos;
+               s->discarded++;
 
                ret = bch2_trans_relock_notrace(trans);
                if (ret)
@@ -1819,12 +1823,12 @@ commit:
                goto out;
 
        count_event(c, bucket_discard);
-       s->discarded++;
 out:
 fsck_err:
        if (discard_locked)
                discard_in_flight_remove(ca, iter.pos.offset);
-       s->seen++;
+       if (!ret)
+               s->seen++;
        bch2_trans_iter_exit(trans, &iter);
        printbuf_exit(&buf);
        return ret;
@@ -1848,7 +1852,7 @@ static void bch2_do_discards_work(struct work_struct *work)
                                   BTREE_ID_need_discard,
                                   POS(ca->dev_idx, 0),
                                   POS(ca->dev_idx, U64_MAX), 0, k,
-                       bch2_discard_one_bucket(trans, ca, &iter, &discard_pos_done, &s)));
+                       bch2_discard_one_bucket(trans, ca, &iter, &discard_pos_done, &s, false)));
 
        trace_discard_buckets(c, s.seen, s.open, s.need_journal_commit, s.discarded,
                              bch2_err_str(ret));
@@ -1881,27 +1885,31 @@ void bch2_do_discards(struct bch_fs *c)
                bch2_dev_do_discards(ca);
 }
 
-static int bch2_clear_bucket_needs_discard(struct btree_trans *trans, struct bpos bucket)
+static int bch2_do_discards_fast_one(struct btree_trans *trans,
+                                    struct bch_dev *ca,
+                                    u64 bucket,
+                                    struct bpos *discard_pos_done,
+                                    struct discard_buckets_state *s)
 {
-       struct btree_iter iter;
-       bch2_trans_iter_init(trans, &iter, BTREE_ID_alloc, bucket, BTREE_ITER_intent);
-       struct bkey_s_c k = bch2_btree_iter_peek_slot(&iter);
-       int ret = bkey_err(k);
-       if (ret)
-               goto err;
-
-       struct bkey_i_alloc_v4 *a = bch2_alloc_to_v4_mut(trans, k);
-       ret = PTR_ERR_OR_ZERO(a);
+       struct btree_iter need_discard_iter;
+       struct bkey_s_c discard_k = bch2_bkey_get_iter(trans, &need_discard_iter,
+                                       BTREE_ID_need_discard, POS(ca->dev_idx, bucket), 0);
+       int ret = bkey_err(discard_k);
        if (ret)
-               goto err;
+               return ret;
 
-       BUG_ON(a->v.dirty_sectors);
-       SET_BCH_ALLOC_V4_NEED_DISCARD(&a->v, false);
-       alloc_data_type_set(&a->v, a->v.data_type);
+       if (log_fsck_err_on(discard_k.k->type != KEY_TYPE_set,
+                           trans, discarding_bucket_not_in_need_discard_btree,
+                           "attempting to discard bucket %u:%llu not in need_discard btree",
+                           ca->dev_idx, bucket)) {
+               /* log it in the superblock and continue: */
+               goto out;
+       }
 
-       ret = bch2_trans_update(trans, &iter, &a->k_i, 0);
-err:
-       bch2_trans_iter_exit(trans, &iter);
+       ret = bch2_discard_one_bucket(trans, ca, &need_discard_iter, discard_pos_done, s, true);
+out:
+fsck_err:
+       bch2_trans_iter_exit(trans, &need_discard_iter);
        return ret;
 }
 
@@ -1909,6 +1917,10 @@ static void bch2_do_discards_fast_work(struct work_struct *work)
 {
        struct bch_dev *ca = container_of(work, struct bch_dev, discard_fast_work);
        struct bch_fs *c = ca->fs;
+       struct discard_buckets_state s = {};
+       struct bpos discard_pos_done = POS_MAX;
+       struct btree_trans *trans = bch2_trans_get(c);
+       int ret = 0;
 
        while (1) {
                bool got_bucket = false;
@@ -1929,16 +1941,8 @@ static void bch2_do_discards_fast_work(struct work_struct *work)
                if (!got_bucket)
                        break;
 
-               if (ca->mi.discard && !c->opts.nochanges)
-                       blkdev_issue_discard(ca->disk_sb.bdev,
-                                            bucket_to_sector(ca, bucket),
-                                            ca->mi.bucket_size,
-                                            GFP_KERNEL);
-
-               int ret = bch2_trans_commit_do(c, NULL, NULL,
-                       BCH_WATERMARK_btree|
-                       BCH_TRANS_COMMIT_no_enospc,
-                       bch2_clear_bucket_needs_discard(trans, POS(ca->dev_idx, bucket)));
+               ret = lockrestart_do(trans,
+                       bch2_do_discards_fast_one(trans, ca, bucket, &discard_pos_done, &s));
                bch_err_fn(c, ret);
 
                discard_in_flight_remove(ca, bucket);
@@ -1947,6 +1951,9 @@ static void bch2_do_discards_fast_work(struct work_struct *work)
                        break;
        }
 
+       trace_discard_buckets(c, s.seen, s.open, s.need_journal_commit, s.discarded, bch2_err_str(ret));
+
+       bch2_trans_put(trans);
        percpu_ref_put(&ca->io_ref);
        bch2_write_ref_put(c, BCH_WRITE_REF_discard_fast);
 }