summaryrefslogtreecommitdiffstats
path: root/Revert-Btrfs-race-free-update-of-commit-root-for-ro-.patch
diff options
context:
space:
mode:
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-.patch105
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
+