aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/ioctl.c29
1 files changed, 29 insertions, 0 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 04ece8fab921..219e26fa9069 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -712,6 +712,35 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
712 if (ret) 712 if (ret)
713 goto fail; 713 goto fail;
714 714
715 /*
716 * If orphan cleanup did remove any orphans, it means the tree was
717 * modified and therefore the commit root is not the same as the
718 * current root anymore. This is a problem, because send uses the
719 * commit root and therefore can see inode items that don't exist
720 * in the current root anymore, and for example make calls to
721 * btrfs_iget, which will do tree lookups based on the current root
722 * and not on the commit root. Those lookups will fail, returning a
723 * -ESTALE error, and making send fail with that error. So make sure
724 * a send does not see any orphans we have just removed, and that it
725 * will see the same inodes regardless of whether a transaction
726 * commit happened before it started (meaning that the commit root
727 * will be the same as the current root) or not.
728 */
729 if (readonly && pending_snapshot->snap->node !=
730 pending_snapshot->snap->commit_root) {
731 trans = btrfs_join_transaction(pending_snapshot->snap);
732 if (IS_ERR(trans) && PTR_ERR(trans) != -ENOENT) {
733 ret = PTR_ERR(trans);
734 goto fail;
735 }
736 if (!IS_ERR(trans)) {
737 ret = btrfs_commit_transaction(trans,
738 pending_snapshot->snap);
739 if (ret)
740 goto fail;
741 }
742 }
743
715 inode = btrfs_lookup_dentry(dentry->d_parent->d_inode, dentry); 744 inode = btrfs_lookup_dentry(dentry->d_parent->d_inode, dentry);
716 if (IS_ERR(inode)) { 745 if (IS_ERR(inode)) {
717 ret = PTR_ERR(inode); 746 ret = PTR_ERR(inode);