From: Kent Overstreet Date: Wed, 7 May 2025 18:26:18 +0000 (-0400) Subject: bcachefs: Knob for manual snapshot deletion X-Git-Tag: v6.16-rc1~211^2~87 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8c69e2b52ea81b102ace48debd114467199ca77a;p=thirdparty%2Flinux.git bcachefs: Knob for manual snapshot deletion 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 --- diff --git a/fs/bcachefs/opts.h b/fs/bcachefs/opts.h index f4c014ad43c15..2a02606254b36 100644 --- a/fs/bcachefs/opts.h +++ b/fs/bcachefs/opts.h @@ -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(), \ diff --git a/fs/bcachefs/snapshot.c b/fs/bcachefs/snapshot.c index 9ec3275c7b0ad..c3dc450cbcecd 100644 --- a/fs/bcachefs/snapshot.c +++ b/fs/bcachefs/snapshot.c @@ -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); } diff --git a/fs/bcachefs/snapshot.h b/fs/bcachefs/snapshot.h index 69c484b77729e..63b9469eb1ebf 100644 --- a/fs/bcachefs/snapshot.h +++ b/fs/bcachefs/snapshot.h @@ -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 *); diff --git a/fs/bcachefs/snapshot_types.h b/fs/bcachefs/snapshot_types.h index 1aa7a58442ae6..0ab698f13e5c6 100644 --- a/fs/bcachefs/snapshot_types.h +++ b/fs/bcachefs/snapshot_types.h @@ -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; diff --git a/fs/bcachefs/sysfs.c b/fs/bcachefs/sysfs.c index adf99a805a624..4c7d609d79fd3 100644 --- a/fs/bcachefs/sysfs.c +++ b/fs/bcachefs/sysfs.c @@ -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,