diff options
author | Filipe Manana <fdmanana@suse.com> | 2015-03-02 15:53:53 -0500 |
---|---|---|
committer | Chris Mason <clm@fb.com> | 2015-03-26 20:55:51 -0400 |
commit | 2f1f465ae6da244099af55c066e5355abd8ff620 (patch) | |
tree | 05e245ff3ad099a59616f39710737119cb0442df | |
parent | 5cc2b17e80cf5770f2e585c2d90fd8af1b901258 (diff) |
Btrfs: send, don't leave without decrementing clone root's send_progress
If the clone root was not readonly or the dead flag was set on it, we were
leaving without decrementing the root's send_progress counter (and before
we just incremented it). If a concurrent snapshot deletion was in progress
and ended up being aborted, it would be impossible to later attempt to
delete again the snapshot, since the root's send_in_progress counter could
never go back to 0.
We were also setting clone_sources_to_rollback to i + 1 too early - if we
bailed out because the clone root we got is not readonly or flagged as dead
we ended up later derreferencing a null pointer because we didn't assign
the clone root to sctx->clone_roots[i].root:
for (i = 0; sctx && i < clone_sources_to_rollback; i++)
btrfs_root_dec_send_in_progress(
sctx->clone_roots[i].root);
So just don't increment the send_in_progress counter if the root is readonly
or flagged as dead.
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.cz>
Signed-off-by: Chris Mason <clm@fb.com>
-rw-r--r-- | fs/btrfs/send.c | 4 |
1 files changed, 2 insertions, 2 deletions
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 6ec28f13659e..571de5a08fe7 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c | |||
@@ -5852,9 +5852,7 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_) | |||
5852 | ret = PTR_ERR(clone_root); | 5852 | ret = PTR_ERR(clone_root); |
5853 | goto out; | 5853 | goto out; |
5854 | } | 5854 | } |
5855 | clone_sources_to_rollback = i + 1; | ||
5856 | spin_lock(&clone_root->root_item_lock); | 5855 | spin_lock(&clone_root->root_item_lock); |
5857 | clone_root->send_in_progress++; | ||
5858 | if (!btrfs_root_readonly(clone_root) || | 5856 | if (!btrfs_root_readonly(clone_root) || |
5859 | btrfs_root_dead(clone_root)) { | 5857 | btrfs_root_dead(clone_root)) { |
5860 | spin_unlock(&clone_root->root_item_lock); | 5858 | spin_unlock(&clone_root->root_item_lock); |
@@ -5862,10 +5860,12 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_) | |||
5862 | ret = -EPERM; | 5860 | ret = -EPERM; |
5863 | goto out; | 5861 | goto out; |
5864 | } | 5862 | } |
5863 | clone_root->send_in_progress++; | ||
5865 | spin_unlock(&clone_root->root_item_lock); | 5864 | spin_unlock(&clone_root->root_item_lock); |
5866 | srcu_read_unlock(&fs_info->subvol_srcu, index); | 5865 | srcu_read_unlock(&fs_info->subvol_srcu, index); |
5867 | 5866 | ||
5868 | sctx->clone_roots[i].root = clone_root; | 5867 | sctx->clone_roots[i].root = clone_root; |
5868 | clone_sources_to_rollback = i + 1; | ||
5869 | } | 5869 | } |
5870 | vfree(clone_sources_tmp); | 5870 | vfree(clone_sources_tmp); |
5871 | clone_sources_tmp = NULL; | 5871 | clone_sources_tmp = NULL; |