Skip to content

Commit 2b9dbef

Browse files
Josef Bacikmasoncl
authored andcommitted
Btrfs: keep dropped roots in cache until transaction commit
When dropping a snapshot we need to account for the qgroup changes. If we drop the snapshot in all one go then the backref code will fail to find blocks from the snapshot we dropped since it won't be able to find the root in the fs root cache. This can lead to us failing to find refs from other roots that pointed at blocks in the now deleted root. To handle this we need to not remove the fs roots from the cache until after we process the qgroup operations. Do this by adding dropped roots to a list on the transaction, and letting the transaction remove the roots at the same time it drops the commit roots. This will keep all of the backref searching code in sync properly, and fixes a problem Mark was seeing with snapshot delete and qgroups. Thanks, Signed-off-by: Josef Bacik <jbacik@fb.com> Tested-by: Holger Hoffstätte <holger.hoffstaette@googlemail.com> Signed-off-by: Chris Mason <clm@fb.com>
1 parent 50745b0 commit 2b9dbef

File tree

3 files changed

+37
-2
lines changed

3 files changed

+37
-2
lines changed

fs/btrfs/extent-tree.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8665,7 +8665,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
86658665
}
86668666

86678667
if (test_bit(BTRFS_ROOT_IN_RADIX, &root->state)) {
8668-
btrfs_drop_and_free_fs_root(tree_root->fs_info, root);
8668+
btrfs_add_dropped_root(trans, root);
86698669
} else {
86708670
free_extent_buffer(root->node);
86718671
free_extent_buffer(root->commit_root);

fs/btrfs/transaction.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,18 @@ static noinline void switch_commit_roots(struct btrfs_transaction *trans,
117117
btrfs_unpin_free_ino(root);
118118
clear_btree_io_tree(&root->dirty_log_pages);
119119
}
120+
121+
/* We can free old roots now. */
122+
spin_lock(&trans->dropped_roots_lock);
123+
while (!list_empty(&trans->dropped_roots)) {
124+
root = list_first_entry(&trans->dropped_roots,
125+
struct btrfs_root, root_list);
126+
list_del_init(&root->root_list);
127+
spin_unlock(&trans->dropped_roots_lock);
128+
btrfs_drop_and_free_fs_root(fs_info, root);
129+
spin_lock(&trans->dropped_roots_lock);
130+
}
131+
spin_unlock(&trans->dropped_roots_lock);
120132
up_write(&fs_info->commit_root_sem);
121133
}
122134

@@ -255,11 +267,13 @@ static noinline int join_transaction(struct btrfs_root *root, unsigned int type)
255267
INIT_LIST_HEAD(&cur_trans->pending_ordered);
256268
INIT_LIST_HEAD(&cur_trans->dirty_bgs);
257269
INIT_LIST_HEAD(&cur_trans->io_bgs);
270+
INIT_LIST_HEAD(&cur_trans->dropped_roots);
258271
mutex_init(&cur_trans->cache_write_mutex);
259272
cur_trans->num_dirty_bgs = 0;
260273
spin_lock_init(&cur_trans->dirty_bgs_lock);
261274
INIT_LIST_HEAD(&cur_trans->deleted_bgs);
262275
spin_lock_init(&cur_trans->deleted_bgs_lock);
276+
spin_lock_init(&cur_trans->dropped_roots_lock);
263277
list_add_tail(&cur_trans->list, &fs_info->trans_list);
264278
extent_io_tree_init(&cur_trans->dirty_pages,
265279
fs_info->btree_inode->i_mapping);
@@ -336,6 +350,24 @@ static int record_root_in_trans(struct btrfs_trans_handle *trans,
336350
}
337351

338352

353+
void btrfs_add_dropped_root(struct btrfs_trans_handle *trans,
354+
struct btrfs_root *root)
355+
{
356+
struct btrfs_transaction *cur_trans = trans->transaction;
357+
358+
/* Add ourselves to the transaction dropped list */
359+
spin_lock(&cur_trans->dropped_roots_lock);
360+
list_add_tail(&root->root_list, &cur_trans->dropped_roots);
361+
spin_unlock(&cur_trans->dropped_roots_lock);
362+
363+
/* Make sure we don't try to update the root at commit time */
364+
spin_lock(&root->fs_info->fs_roots_radix_lock);
365+
radix_tree_tag_clear(&root->fs_info->fs_roots_radix,
366+
(unsigned long)root->root_key.objectid,
367+
BTRFS_ROOT_TRANS_TAG);
368+
spin_unlock(&root->fs_info->fs_roots_radix_lock);
369+
}
370+
339371
int btrfs_record_root_in_trans(struct btrfs_trans_handle *trans,
340372
struct btrfs_root *root)
341373
{

fs/btrfs/transaction.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ struct btrfs_transaction {
6565
struct list_head switch_commits;
6666
struct list_head dirty_bgs;
6767
struct list_head io_bgs;
68+
struct list_head dropped_roots;
6869
u64 num_dirty_bgs;
6970

7071
/*
@@ -76,6 +77,7 @@ struct btrfs_transaction {
7677
spinlock_t dirty_bgs_lock;
7778
struct list_head deleted_bgs;
7879
spinlock_t deleted_bgs_lock;
80+
spinlock_t dropped_roots_lock;
7981
struct btrfs_delayed_ref_root delayed_refs;
8082
int aborted;
8183
int dirty_bg_run;
@@ -216,5 +218,6 @@ int btrfs_transaction_blocked(struct btrfs_fs_info *info);
216218
int btrfs_transaction_in_commit(struct btrfs_fs_info *info);
217219
void btrfs_put_transaction(struct btrfs_transaction *transaction);
218220
void btrfs_apply_pending_changes(struct btrfs_fs_info *fs_info);
219-
221+
void btrfs_add_dropped_root(struct btrfs_trans_handle *trans,
222+
struct btrfs_root *root);
220223
#endif

0 commit comments

Comments
 (0)