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