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>
This commit is contained in:
@@ -117,6 +117,18 @@ static noinline void switch_commit_roots(struct btrfs_transaction *trans,
|
||||
btrfs_unpin_free_ino(root);
|
||||
clear_btree_io_tree(&root->dirty_log_pages);
|
||||
}
|
||||
|
||||
/* We can free old roots now. */
|
||||
spin_lock(&trans->dropped_roots_lock);
|
||||
while (!list_empty(&trans->dropped_roots)) {
|
||||
root = list_first_entry(&trans->dropped_roots,
|
||||
struct btrfs_root, root_list);
|
||||
list_del_init(&root->root_list);
|
||||
spin_unlock(&trans->dropped_roots_lock);
|
||||
btrfs_drop_and_free_fs_root(fs_info, root);
|
||||
spin_lock(&trans->dropped_roots_lock);
|
||||
}
|
||||
spin_unlock(&trans->dropped_roots_lock);
|
||||
up_write(&fs_info->commit_root_sem);
|
||||
}
|
||||
|
||||
@@ -255,11 +267,13 @@ loop:
|
||||
INIT_LIST_HEAD(&cur_trans->pending_ordered);
|
||||
INIT_LIST_HEAD(&cur_trans->dirty_bgs);
|
||||
INIT_LIST_HEAD(&cur_trans->io_bgs);
|
||||
INIT_LIST_HEAD(&cur_trans->dropped_roots);
|
||||
mutex_init(&cur_trans->cache_write_mutex);
|
||||
cur_trans->num_dirty_bgs = 0;
|
||||
spin_lock_init(&cur_trans->dirty_bgs_lock);
|
||||
INIT_LIST_HEAD(&cur_trans->deleted_bgs);
|
||||
spin_lock_init(&cur_trans->deleted_bgs_lock);
|
||||
spin_lock_init(&cur_trans->dropped_roots_lock);
|
||||
list_add_tail(&cur_trans->list, &fs_info->trans_list);
|
||||
extent_io_tree_init(&cur_trans->dirty_pages,
|
||||
fs_info->btree_inode->i_mapping);
|
||||
@@ -336,6 +350,24 @@ static int record_root_in_trans(struct btrfs_trans_handle *trans,
|
||||
}
|
||||
|
||||
|
||||
void btrfs_add_dropped_root(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root)
|
||||
{
|
||||
struct btrfs_transaction *cur_trans = trans->transaction;
|
||||
|
||||
/* Add ourselves to the transaction dropped list */
|
||||
spin_lock(&cur_trans->dropped_roots_lock);
|
||||
list_add_tail(&root->root_list, &cur_trans->dropped_roots);
|
||||
spin_unlock(&cur_trans->dropped_roots_lock);
|
||||
|
||||
/* Make sure we don't try to update the root at commit time */
|
||||
spin_lock(&root->fs_info->fs_roots_radix_lock);
|
||||
radix_tree_tag_clear(&root->fs_info->fs_roots_radix,
|
||||
(unsigned long)root->root_key.objectid,
|
||||
BTRFS_ROOT_TRANS_TAG);
|
||||
spin_unlock(&root->fs_info->fs_roots_radix_lock);
|
||||
}
|
||||
|
||||
int btrfs_record_root_in_trans(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root)
|
||||
{
|
||||
|
Reference in New Issue
Block a user