From 37fad9497f5d37d89ed06faa64d580d1451be664 Mon Sep 17 00:00:00 2001
From: Kent Overstreet <kent.overstreet@linux.dev>
Date: Fri, 29 Sep 2023 01:15:33 -0400
Subject: bcachefs: snapshot_create_lock

Add a new lock for snapshot creation - this addresses a few races with
logged operations and snapshot deletion.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
---
 fs/bcachefs/snapshot.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

(limited to 'fs/bcachefs/snapshot.c')

diff --git a/fs/bcachefs/snapshot.c b/fs/bcachefs/snapshot.c
index b8c32d1cbd76..4982468bfe11 100644
--- a/fs/bcachefs/snapshot.c
+++ b/fs/bcachefs/snapshot.c
@@ -1447,6 +1447,8 @@ int bch2_delete_dead_snapshots(struct bch_fs *c)
 		}
 	}
 
+	down_write(&c->snapshot_create_lock);
+
 	for_each_btree_key(trans, iter, BTREE_ID_snapshots,
 			   POS_MIN, 0, k, ret) {
 		u32 snapshot = k.k->p.offset;
@@ -1457,6 +1459,9 @@ int bch2_delete_dead_snapshots(struct bch_fs *c)
 	}
 	bch2_trans_iter_exit(trans, &iter);
 
+	if (ret)
+		goto err_create_lock;
+
 	/*
 	 * Fixing children of deleted snapshots can't be done completely
 	 * atomically, if we crash between here and when we delete the interior
@@ -1467,14 +1472,14 @@ int bch2_delete_dead_snapshots(struct bch_fs *c)
 				  NULL, NULL, BTREE_INSERT_NOFAIL,
 		bch2_fix_child_of_deleted_snapshot(trans, &iter, k, &deleted_interior));
 	if (ret)
-		goto err;
+		goto err_create_lock;
 
 	darray_for_each(deleted, i) {
 		ret = commit_do(trans, NULL, NULL, 0,
 			bch2_snapshot_node_delete(trans, *i));
 		if (ret) {
 			bch_err_msg(c, ret, "deleting snapshot %u", *i);
-			goto err;
+			goto err_create_lock;
 		}
 	}
 
@@ -1483,11 +1488,13 @@ int bch2_delete_dead_snapshots(struct bch_fs *c)
 			bch2_snapshot_node_delete(trans, *i));
 		if (ret) {
 			bch_err_msg(c, ret, "deleting snapshot %u", *i);
-			goto err;
+			goto err_create_lock;
 		}
 	}
 
 	clear_bit(BCH_FS_HAVE_DELETED_SNAPSHOTS, &c->flags);
+err_create_lock:
+	up_write(&c->snapshot_create_lock);
 err:
 	darray_exit(&deleted_interior);
 	darray_exit(&deleted);
-- 
cgit