for-5.1-part2-tag
-----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE8rQSAMVO+zA4DBdWxWXV+ddtWDsFAlyHwgcACgkQxWXV+ddt WDvfFQ//VBO8Rnz0+V4XbxaIaz25EbCjR4cBuXwwXyl8HPJMZBvBPqW0LVXtV0eP SwK0A5qiWqaXgWNpByD43AvgizZuWF/9SvxebaCKTjSK5t9TuXpR27vJNnHJf0L0 o4DeMXlgd8yE8yZstQo7UnLWfNU69v6Pi3Zbar/7IIJ0sVVCPMMoGoARZDlQ+w0M wwppi04+a6bnAUbqpnWiL0a8++WX6gqP7MovqLRgf/up4cmzmDFoV7b/7pbvZxNv LrKQBmJZQq44bW4TXMzhpkrIGyzrrUQuBhpbYJus9yZYqS6Owkzl5AQpdzo9reg2 V35xOkOZbXxqdOTGY0he9Z6wxJL+ocfryfRyA2hE4gXbCAnfFqIRyFicpTXuXxwg RBan8VLB+1iC7j9djX/sP/uCH3tsPgN4WnjdZgnkUOkUhTuvpPw/A9bp6Uqfjr6g JU0o/TlCC8npaveUQsuNbqyVYgPk58d9by12HsSW7UaA8ENyHz62+zoiv9jX/uZY Tl4t2L+MKxEcsd0KEKEQpV+0hV56GtYcIZIqJTe9WFmPBHmEH3PCHDx4A5LrYveO hC+hGAnX9xWK4XIr8T3ck1tsnxNApD25pmKSivadUiVJqOrPpJFyZb3aztcKcx4Y sDbZdOV7XHq6ACrIhLoxpYWQc27v1FqrWVqsF51wo07I3meUVaA= =u4Kf -----END PGP SIGNATURE----- Merge tag 'for-5.1-part2-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux Pull btrfs fixes from David Sterba: "Correctness and a deadlock fixes" * tag 'for-5.1-part2-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: btrfs: zstd: ensure reclaim timer is properly cleaned up btrfs: move ulist allocation out of transaction in quota enable btrfs: save drop_progress if we drop refs at all btrfs: check for refs on snapshot delete resume Btrfs: fix deadlock between clone/dedupe and rename Btrfs: fix corruption reading shared and compressed extents after hole punching
This commit is contained in:
commit
92825b0298
|
@ -1210,6 +1210,8 @@ enum {
|
|||
* Set for the subvolume tree owning the reloc tree.
|
||||
*/
|
||||
BTRFS_ROOT_DEAD_RELOC_TREE,
|
||||
/* Mark dead root stored on device whose cleanup needs to be resumed */
|
||||
BTRFS_ROOT_DEAD_TREE,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -8764,6 +8764,8 @@ struct walk_control {
|
|||
u64 refs[BTRFS_MAX_LEVEL];
|
||||
u64 flags[BTRFS_MAX_LEVEL];
|
||||
struct btrfs_key update_progress;
|
||||
struct btrfs_key drop_progress;
|
||||
int drop_level;
|
||||
int stage;
|
||||
int level;
|
||||
int shared_level;
|
||||
|
@ -8771,6 +8773,7 @@ struct walk_control {
|
|||
int keep_locks;
|
||||
int reada_slot;
|
||||
int reada_count;
|
||||
int restarted;
|
||||
};
|
||||
|
||||
#define DROP_REFERENCE 1
|
||||
|
@ -8933,6 +8936,33 @@ static noinline int walk_down_proc(struct btrfs_trans_handle *trans,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is used to verify a ref exists for this root to deal with a bug where we
|
||||
* would have a drop_progress key that hadn't been updated properly.
|
||||
*/
|
||||
static int check_ref_exists(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, u64 bytenr, u64 parent,
|
||||
int level)
|
||||
{
|
||||
struct btrfs_path *path;
|
||||
struct btrfs_extent_inline_ref *iref;
|
||||
int ret;
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = lookup_extent_backref(trans, path, &iref, bytenr,
|
||||
root->fs_info->nodesize, parent,
|
||||
root->root_key.objectid, level, 0);
|
||||
btrfs_free_path(path);
|
||||
if (ret == -ENOENT)
|
||||
return 0;
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* helper to process tree block pointer.
|
||||
*
|
||||
|
@ -9087,6 +9117,23 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
|
|||
parent = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we had a drop_progress we need to verify the refs are set
|
||||
* as expected. If we find our ref then we know that from here
|
||||
* on out everything should be correct, and we can clear the
|
||||
* ->restarted flag.
|
||||
*/
|
||||
if (wc->restarted) {
|
||||
ret = check_ref_exists(trans, root, bytenr, parent,
|
||||
level - 1);
|
||||
if (ret < 0)
|
||||
goto out_unlock;
|
||||
if (ret == 0)
|
||||
goto no_delete;
|
||||
ret = 0;
|
||||
wc->restarted = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reloc tree doesn't contribute to qgroup numbers, and we have
|
||||
* already accounted them at merge time (replace_path),
|
||||
|
@ -9102,13 +9149,23 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
|
|||
ret);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to update the next key in our walk control so we can
|
||||
* update the drop_progress key accordingly. We don't care if
|
||||
* find_next_key doesn't find a key because that means we're at
|
||||
* the end and are going to clean up now.
|
||||
*/
|
||||
wc->drop_level = level;
|
||||
find_next_key(path, level, &wc->drop_progress);
|
||||
|
||||
ret = btrfs_free_extent(trans, root, bytenr, fs_info->nodesize,
|
||||
parent, root->root_key.objectid,
|
||||
level - 1, 0);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
no_delete:
|
||||
*lookup_info = 1;
|
||||
ret = 1;
|
||||
|
||||
|
@ -9425,6 +9482,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
|
|||
}
|
||||
}
|
||||
|
||||
wc->restarted = test_bit(BTRFS_ROOT_DEAD_TREE, &root->state);
|
||||
wc->level = level;
|
||||
wc->shared_level = -1;
|
||||
wc->stage = DROP_REFERENCE;
|
||||
|
@ -9452,12 +9510,14 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
|
|||
}
|
||||
|
||||
if (wc->stage == DROP_REFERENCE) {
|
||||
level = wc->level;
|
||||
btrfs_node_key(path->nodes[level],
|
||||
&root_item->drop_progress,
|
||||
path->slots[level]);
|
||||
root_item->drop_level = level;
|
||||
wc->drop_level = wc->level;
|
||||
btrfs_node_key_to_cpu(path->nodes[wc->drop_level],
|
||||
&wc->drop_progress,
|
||||
path->slots[wc->drop_level]);
|
||||
}
|
||||
btrfs_cpu_key_to_disk(&root_item->drop_progress,
|
||||
&wc->drop_progress);
|
||||
root_item->drop_level = wc->drop_level;
|
||||
|
||||
BUG_ON(wc->level == 0);
|
||||
if (btrfs_should_end_transaction(trans) ||
|
||||
|
|
|
@ -2995,11 +2995,11 @@ static int __do_readpage(struct extent_io_tree *tree,
|
|||
*/
|
||||
if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags) &&
|
||||
prev_em_start && *prev_em_start != (u64)-1 &&
|
||||
*prev_em_start != em->orig_start)
|
||||
*prev_em_start != em->start)
|
||||
force_bio_submit = true;
|
||||
|
||||
if (prev_em_start)
|
||||
*prev_em_start = em->orig_start;
|
||||
*prev_em_start = em->start;
|
||||
|
||||
free_extent_map(em);
|
||||
em = NULL;
|
||||
|
|
|
@ -3207,21 +3207,6 @@ static long btrfs_ioctl_dev_info(struct btrfs_fs_info *fs_info,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void btrfs_double_inode_unlock(struct inode *inode1, struct inode *inode2)
|
||||
{
|
||||
inode_unlock(inode1);
|
||||
inode_unlock(inode2);
|
||||
}
|
||||
|
||||
static void btrfs_double_inode_lock(struct inode *inode1, struct inode *inode2)
|
||||
{
|
||||
if (inode1 < inode2)
|
||||
swap(inode1, inode2);
|
||||
|
||||
inode_lock_nested(inode1, I_MUTEX_PARENT);
|
||||
inode_lock_nested(inode2, I_MUTEX_CHILD);
|
||||
}
|
||||
|
||||
static void btrfs_double_extent_unlock(struct inode *inode1, u64 loff1,
|
||||
struct inode *inode2, u64 loff2, u64 len)
|
||||
{
|
||||
|
@ -3956,7 +3941,7 @@ static int btrfs_remap_file_range_prep(struct file *file_in, loff_t pos_in,
|
|||
if (same_inode)
|
||||
inode_lock(inode_in);
|
||||
else
|
||||
btrfs_double_inode_lock(inode_in, inode_out);
|
||||
lock_two_nondirectories(inode_in, inode_out);
|
||||
|
||||
/* don't make the dst file partly checksummed */
|
||||
if ((BTRFS_I(inode_in)->flags & BTRFS_INODE_NODATASUM) !=
|
||||
|
@ -4013,7 +3998,7 @@ static int btrfs_remap_file_range_prep(struct file *file_in, loff_t pos_in,
|
|||
if (same_inode)
|
||||
inode_unlock(inode_in);
|
||||
else
|
||||
btrfs_double_inode_unlock(inode_in, inode_out);
|
||||
unlock_two_nondirectories(inode_in, inode_out);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -4043,7 +4028,7 @@ loff_t btrfs_remap_file_range(struct file *src_file, loff_t off,
|
|||
if (same_inode)
|
||||
inode_unlock(src_inode);
|
||||
else
|
||||
btrfs_double_inode_unlock(src_inode, dst_inode);
|
||||
unlock_two_nondirectories(src_inode, dst_inode);
|
||||
|
||||
return ret < 0 ? ret : len;
|
||||
}
|
||||
|
|
|
@ -894,6 +894,12 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info)
|
|||
if (fs_info->quota_root)
|
||||
goto out;
|
||||
|
||||
fs_info->qgroup_ulist = ulist_alloc(GFP_KERNEL);
|
||||
if (!fs_info->qgroup_ulist) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* 1 for quota root item
|
||||
* 1 for BTRFS_QGROUP_STATUS item
|
||||
|
@ -909,13 +915,6 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info)
|
|||
goto out;
|
||||
}
|
||||
|
||||
fs_info->qgroup_ulist = ulist_alloc(GFP_KERNEL);
|
||||
if (!fs_info->qgroup_ulist) {
|
||||
ret = -ENOMEM;
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* initially create the quota tree
|
||||
*/
|
||||
|
|
|
@ -263,8 +263,10 @@ int btrfs_find_orphan_roots(struct btrfs_fs_info *fs_info)
|
|||
if (root) {
|
||||
WARN_ON(!test_bit(BTRFS_ROOT_ORPHAN_ITEM_INSERTED,
|
||||
&root->state));
|
||||
if (btrfs_root_refs(&root->root_item) == 0)
|
||||
if (btrfs_root_refs(&root->root_item) == 0) {
|
||||
set_bit(BTRFS_ROOT_DEAD_TREE, &root->state);
|
||||
btrfs_add_dead_root(root);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -310,8 +312,10 @@ int btrfs_find_orphan_roots(struct btrfs_fs_info *fs_info)
|
|||
break;
|
||||
}
|
||||
|
||||
if (btrfs_root_refs(&root->root_item) == 0)
|
||||
if (btrfs_root_refs(&root->root_item) == 0) {
|
||||
set_bit(BTRFS_ROOT_DEAD_TREE, &root->state);
|
||||
btrfs_add_dead_root(root);
|
||||
}
|
||||
}
|
||||
|
||||
btrfs_free_path(path);
|
||||
|
|
|
@ -195,8 +195,7 @@ static void zstd_cleanup_workspace_manager(void)
|
|||
struct workspace *workspace;
|
||||
int i;
|
||||
|
||||
del_timer(&wsm.timer);
|
||||
|
||||
spin_lock(&wsm.lock);
|
||||
for (i = 0; i < ZSTD_BTRFS_MAX_LEVEL; i++) {
|
||||
while (!list_empty(&wsm.idle_ws[i])) {
|
||||
workspace = container_of(wsm.idle_ws[i].next,
|
||||
|
@ -206,6 +205,9 @@ static void zstd_cleanup_workspace_manager(void)
|
|||
wsm.ops->free_workspace(&workspace->list);
|
||||
}
|
||||
}
|
||||
spin_unlock(&wsm.lock);
|
||||
|
||||
del_timer_sync(&wsm.timer);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue
Block a user