diff options
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 36 |
1 files changed, 4 insertions, 32 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 080fe66c0349..d49fe8a0f6b5 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -617,7 +617,7 @@ fail: | |||
617 | return ret; | 617 | return ret; |
618 | } | 618 | } |
619 | 619 | ||
620 | static void btrfs_wait_nocow_write(struct btrfs_root *root) | 620 | static void btrfs_wait_for_no_snapshoting_writes(struct btrfs_root *root) |
621 | { | 621 | { |
622 | s64 writers; | 622 | s64 writers; |
623 | DEFINE_WAIT(wait); | 623 | DEFINE_WAIT(wait); |
@@ -649,7 +649,7 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir, | |||
649 | 649 | ||
650 | atomic_inc(&root->will_be_snapshoted); | 650 | atomic_inc(&root->will_be_snapshoted); |
651 | smp_mb__after_atomic(); | 651 | smp_mb__after_atomic(); |
652 | btrfs_wait_nocow_write(root); | 652 | btrfs_wait_for_no_snapshoting_writes(root); |
653 | 653 | ||
654 | ret = btrfs_start_delalloc_inodes(root, 0); | 654 | ret = btrfs_start_delalloc_inodes(root, 0); |
655 | if (ret) | 655 | if (ret) |
@@ -717,35 +717,6 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir, | |||
717 | if (ret) | 717 | if (ret) |
718 | goto fail; | 718 | goto fail; |
719 | 719 | ||
720 | /* | ||
721 | * If orphan cleanup did remove any orphans, it means the tree was | ||
722 | * modified and therefore the commit root is not the same as the | ||
723 | * current root anymore. This is a problem, because send uses the | ||
724 | * commit root and therefore can see inode items that don't exist | ||
725 | * in the current root anymore, and for example make calls to | ||
726 | * btrfs_iget, which will do tree lookups based on the current root | ||
727 | * and not on the commit root. Those lookups will fail, returning a | ||
728 | * -ESTALE error, and making send fail with that error. So make sure | ||
729 | * a send does not see any orphans we have just removed, and that it | ||
730 | * will see the same inodes regardless of whether a transaction | ||
731 | * commit happened before it started (meaning that the commit root | ||
732 | * will be the same as the current root) or not. | ||
733 | */ | ||
734 | if (readonly && pending_snapshot->snap->node != | ||
735 | pending_snapshot->snap->commit_root) { | ||
736 | trans = btrfs_join_transaction(pending_snapshot->snap); | ||
737 | if (IS_ERR(trans) && PTR_ERR(trans) != -ENOENT) { | ||
738 | ret = PTR_ERR(trans); | ||
739 | goto fail; | ||
740 | } | ||
741 | if (!IS_ERR(trans)) { | ||
742 | ret = btrfs_commit_transaction(trans, | ||
743 | pending_snapshot->snap); | ||
744 | if (ret) | ||
745 | goto fail; | ||
746 | } | ||
747 | } | ||
748 | |||
749 | inode = btrfs_lookup_dentry(dentry->d_parent->d_inode, dentry); | 720 | inode = btrfs_lookup_dentry(dentry->d_parent->d_inode, dentry); |
750 | if (IS_ERR(inode)) { | 721 | if (IS_ERR(inode)) { |
751 | ret = PTR_ERR(inode); | 722 | ret = PTR_ERR(inode); |
@@ -761,7 +732,8 @@ fail: | |||
761 | free: | 732 | free: |
762 | kfree(pending_snapshot); | 733 | kfree(pending_snapshot); |
763 | out: | 734 | out: |
764 | atomic_dec(&root->will_be_snapshoted); | 735 | if (atomic_dec_and_test(&root->will_be_snapshoted)) |
736 | wake_up_atomic_t(&root->will_be_snapshoted); | ||
765 | return ret; | 737 | return ret; |
766 | } | 738 | } |
767 | 739 | ||