diff options
Diffstat (limited to 'Revert-Btrfs-race-free-update-of-commit-root-for-ro-.patch')
-rw-r--r-- | Revert-Btrfs-race-free-update-of-commit-root-for-ro-.patch | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/Revert-Btrfs-race-free-update-of-commit-root-for-ro-.patch b/Revert-Btrfs-race-free-update-of-commit-root-for-ro-.patch new file mode 100644 index 000000000..bc78069b5 --- /dev/null +++ b/Revert-Btrfs-race-free-update-of-commit-root-for-ro-.patch @@ -0,0 +1,105 @@ +From: Josh Boyer <jwboyer@fedoraproject.org> +Date: Wed, 15 Oct 2014 10:09:50 -0400 +Subject: [PATCH] Revert "Btrfs: race free update of commit root for ro + snapshots" + +This reverts commit 9c3b306e1c9e6be4be09e99a8fe2227d1005effc. +--- + fs/btrfs/inode.c | 36 ------------------------------------ + fs/btrfs/ioctl.c | 33 +++++++++++++++++++++++++++++++++ + 2 files changed, 33 insertions(+), 36 deletions(-) + +diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c +index fc9c0439caa3..d23362f4464e 100644 +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -5261,42 +5261,6 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry) + iput(inode); + inode = ERR_PTR(ret); + } +- /* +- * If orphan cleanup did remove any orphans, it means the tree +- * was modified and therefore the commit root is not the same as +- * the current root anymore. This is a problem, because send +- * uses the commit root and therefore can see inode items that +- * don't exist in the current root anymore, and for example make +- * calls to btrfs_iget, which will do tree lookups based on the +- * current root and not on the commit root. Those lookups will +- * fail, returning a -ESTALE error, and making send fail with +- * that error. So make sure a send does not see any orphans we +- * have just removed, and that it will see the same inodes +- * regardless of whether a transaction commit happened before +- * it started (meaning that the commit root will be the same as +- * the current root) or not. +- */ +- if (sub_root->node != sub_root->commit_root) { +- u64 sub_flags = btrfs_root_flags(&sub_root->root_item); +- +- if (sub_flags & BTRFS_ROOT_SUBVOL_RDONLY) { +- struct extent_buffer *eb; +- +- /* +- * Assert we can't have races between dentry +- * lookup called through the snapshot creation +- * ioctl and the VFS. +- */ +- ASSERT(mutex_is_locked(&dir->i_mutex)); +- +- down_write(&root->fs_info->commit_root_sem); +- eb = sub_root->commit_root; +- sub_root->commit_root = +- btrfs_root_node(sub_root); +- up_write(&root->fs_info->commit_root_sem); +- free_extent_buffer(eb); +- } +- } + } + + return inode; +diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c +index 0fe1aa047f15..8d2b76e29d3b 100644 +--- a/fs/btrfs/ioctl.c ++++ b/fs/btrfs/ioctl.c +@@ -713,6 +713,39 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir, + if (ret) + goto fail; + ++ ret = btrfs_orphan_cleanup(pending_snapshot->snap); ++ if (ret) ++ goto fail; ++ ++ /* ++ * If orphan cleanup did remove any orphans, it means the tree was ++ * modified and therefore the commit root is not the same as the ++ * current root anymore. This is a problem, because send uses the ++ * commit root and therefore can see inode items that don't exist ++ * in the current root anymore, and for example make calls to ++ * btrfs_iget, which will do tree lookups based on the current root ++ * and not on the commit root. Those lookups will fail, returning a ++ * -ESTALE error, and making send fail with that error. So make sure ++ * a send does not see any orphans we have just removed, and that it ++ * will see the same inodes regardless of whether a transaction ++ * commit happened before it started (meaning that the commit root ++ * will be the same as the current root) or not. ++ */ ++ if (readonly && pending_snapshot->snap->node != ++ pending_snapshot->snap->commit_root) { ++ trans = btrfs_join_transaction(pending_snapshot->snap); ++ if (IS_ERR(trans) && PTR_ERR(trans) != -ENOENT) { ++ ret = PTR_ERR(trans); ++ goto fail; ++ } ++ if (!IS_ERR(trans)) { ++ ret = btrfs_commit_transaction(trans, ++ pending_snapshot->snap); ++ if (ret) ++ goto fail; ++ } ++ } ++ + inode = btrfs_lookup_dentry(dentry->d_parent->d_inode, dentry); + if (IS_ERR(inode)) { + ret = PTR_ERR(inode); +-- +1.9.3 + |