]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
bcachefs: Knob for manual snapshot deletion
authorKent Overstreet <kent.overstreet@linux.dev>
Wed, 7 May 2025 18:26:18 +0000 (14:26 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Thu, 22 May 2025 00:14:49 +0000 (20:14 -0400)
Add 'opts.snapshot_deletion_enabled', enabled by default.

This may be turned off so that the new sysfs knob,
'internal/trigger_delete_dead_snapshots', may be used instead - this
will allow snapshot deletion to be profiled more easily.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/opts.h
fs/bcachefs/snapshot.c
fs/bcachefs/snapshot.h
fs/bcachefs/snapshot_types.h
fs/bcachefs/sysfs.c

index f4c014ad43c159acaf121a54477296e87cd9fef1..2a02606254b369c4ee8dad7bd1677ba0d96f06fc 100644 (file)
@@ -495,6 +495,12 @@ enum fsck_err_opts {
          OPT_BOOL(),                                                   \
          BCH_SB_REBALANCE_AC_ONLY,             false,                  \
          NULL,         "Enable rebalance while on mains power only\n") \
+       x(auto_snapshot_deletion,       u8,                             \
+         OPT_FS|OPT_MOUNT|OPT_RUNTIME,                                 \
+         OPT_BOOL(),                                                   \
+         BCH2_NO_SB_OPT,                       true,                   \
+         NULL,         "Enable automatic snapshot deletion: disable for debugging, or to\n"\
+                       "quiet the system when doing performance testing\n")\
        x(no_data_io,                   u8,                             \
          OPT_MOUNT,                                                    \
          OPT_BOOL(),                                                   \
index 9ec3275c7b0adb79363c0a2eea136663e92aa38d..c3dc450cbcecd815d9f4932ea4960015a5772e73 100644 (file)
@@ -1776,14 +1776,18 @@ static void bch2_snapshot_delete_nodes_to_text(struct printbuf *out, struct snap
        prt_newline(out);
 }
 
-int bch2_delete_dead_snapshots(struct bch_fs *c)
+int __bch2_delete_dead_snapshots(struct bch_fs *c)
 {
-       if (!test_and_clear_bit(BCH_FS_need_delete_dead_snapshots, &c->flags))
+       struct snapshot_delete *d = &c->snapshot_delete;
+       int ret = 0;
+
+       if (!mutex_trylock(&d->lock))
                return 0;
 
+       if (!test_and_clear_bit(BCH_FS_need_delete_dead_snapshots, &c->flags))
+               goto out_unlock;
+
        struct btree_trans *trans = bch2_trans_get(c);
-       struct snapshot_delete *d = &c->snapshot_delete;
-       int ret = 0;
 
        /*
         * For every snapshot node: If we have no live children and it's not
@@ -1857,11 +1861,21 @@ err:
        d->running = false;
        mutex_unlock(&d->progress_lock);
        bch2_trans_put(trans);
+out_unlock:
+       mutex_unlock(&d->lock);
        if (!bch2_err_matches(ret, EROFS))
                bch_err_fn(c, ret);
        return ret;
 }
 
+int bch2_delete_dead_snapshots(struct bch_fs *c)
+{
+       if (!c->opts.auto_snapshot_deletion)
+               return 0;
+
+       return __bch2_delete_dead_snapshots(c);
+}
+
 void bch2_delete_dead_snapshots_work(struct work_struct *work)
 {
        struct bch_fs *c = container_of(work, struct bch_fs, snapshot_delete.work);
@@ -1874,6 +1888,9 @@ void bch2_delete_dead_snapshots_work(struct work_struct *work)
 
 void bch2_delete_dead_snapshots_async(struct bch_fs *c)
 {
+       if (!c->opts.auto_snapshot_deletion)
+               return;
+
        if (!enumerated_ref_tryget(&c->writes, BCH_WRITE_REF_delete_dead_snapshots))
                return;
 
@@ -1977,6 +1994,7 @@ void bch2_fs_snapshots_exit(struct bch_fs *c)
 void bch2_fs_snapshots_init_early(struct bch_fs *c)
 {
        INIT_WORK(&c->snapshot_delete.work, bch2_delete_dead_snapshots_work);
+       mutex_init(&c->snapshot_delete.lock);
        mutex_init(&c->snapshot_delete.progress_lock);
        mutex_init(&c->snapshots_unlinked_lock);
 }
index 69c484b77729e8de40592a7797fe751a93eb87d3..63b9469eb1ebf04722360e7d1050fd101a6edc4d 100644 (file)
@@ -273,6 +273,7 @@ static inline int bch2_key_has_snapshot_overwrites(struct btree_trans *trans,
        return __bch2_key_has_snapshot_overwrites(trans, id, pos);
 }
 
+int __bch2_delete_dead_snapshots(struct bch_fs *);
 int bch2_delete_dead_snapshots(struct bch_fs *);
 void bch2_delete_dead_snapshots_work(struct work_struct *);
 void bch2_delete_dead_snapshots_async(struct bch_fs *);
index 1aa7a58442ae6a6bc7e4e806daa39b655b694823..0ab698f13e5c6aed5dbcc5d7476026b9828ddff7 100644 (file)
@@ -42,6 +42,7 @@ struct snapshot_interior_delete {
 typedef DARRAY(struct snapshot_interior_delete) interior_delete_list;
 
 struct snapshot_delete {
+       struct mutex            lock;
        struct work_struct      work;
 
        struct mutex            progress_lock;
index adf99a805a624bd7e6d6c448b542ca928908a15c..4c7d609d79fd3b1c94daf73461ccaa1ff3c69f47 100644 (file)
@@ -149,6 +149,7 @@ write_attribute(trigger_btree_key_cache_shrink);
 write_attribute(trigger_btree_updates);
 write_attribute(trigger_freelist_wakeup);
 write_attribute(trigger_recalc_capacity);
+write_attribute(trigger_delete_dead_snapshots);
 read_attribute(gc_gens_pos);
 
 read_attribute(uuid);
@@ -439,6 +440,9 @@ STORE(bch2_fs)
                up_read(&c->state_lock);
        }
 
+       if (attr == &sysfs_trigger_delete_dead_snapshots)
+               __bch2_delete_dead_snapshots(c);
+
 #ifdef CONFIG_BCACHEFS_TESTS
        if (attr == &sysfs_perf_test) {
                char *tmp = kstrdup(buf, GFP_KERNEL), *p = tmp;
@@ -568,6 +572,7 @@ struct attribute *bch2_fs_internal_files[] = {
        &sysfs_trigger_btree_updates,
        &sysfs_trigger_freelist_wakeup,
        &sysfs_trigger_recalc_capacity,
+       &sysfs_trigger_delete_dead_snapshots,
 
        &sysfs_gc_gens_pos,