summaryrefslogtreecommitdiffstats
path: root/fs/bcachefs/snapshot.c
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@linux.dev>2025-05-07 14:26:18 -0400
committerKent Overstreet <kent.overstreet@linux.dev>2025-05-21 20:14:49 -0400
commit8c69e2b52ea81b102ace48debd114467199ca77a (patch)
tree05cd41ba6d2009dfa8ba2fbae8b4a3aaa79ba33c /fs/bcachefs/snapshot.c
parentbcachefs: bcachefs_metadata_version_fast_device_removal (diff)
downloadlinux-8c69e2b52ea81b102ace48debd114467199ca77a.tar.gz
linux-8c69e2b52ea81b102ace48debd114467199ca77a.zip
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 <kent.overstreet@linux.dev>
Diffstat (limited to 'fs/bcachefs/snapshot.c')
-rw-r--r--fs/bcachefs/snapshot.c26
1 files changed, 22 insertions, 4 deletions
diff --git a/fs/bcachefs/snapshot.c b/fs/bcachefs/snapshot.c
index 9ec3275c7b0a..c3dc450cbcec 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);
}