aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-10-18 16:32:17 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-10-18 16:32:17 -0400
commitef161ea1ff96337cbe2253afb72636474d90598e (patch)
tree58fa11ed86de6069d81a5f5b09310ae2a9bd0c70 /fs
parent8ccf863f09bbff209b124cbd90644c0b75b8fefd (diff)
parentd37973082b453ba6b89ec07eb7b84305895d35e1 (diff)
Merge branch 'for-linus-update' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs
Pull btrfs data corruption fix from Chris Mason: "I'm testing a pull with more fixes, but wanted to get this one out so Greg can pick it up. The corruption isn't easy to hit, you have to do a readonly snapshot and have orphans in the snapshot. But my review and testing missed the bug. Filipe has added a better xfstest to cover it" * 'for-linus-update' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs: Revert "Btrfs: race free update of commit root for ro snapshots"
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/inode.c36
-rw-r--r--fs/btrfs/ioctl.c33
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)
5261 iput(inode); 5261 iput(inode);
5262 inode = ERR_PTR(ret); 5262 inode = ERR_PTR(ret);
5263 } 5263 }
5264 /*
5265 * If orphan cleanup did remove any orphans, it means the tree
5266 * was modified and therefore the commit root is not the same as
5267 * the current root anymore. This is a problem, because send
5268 * uses the commit root and therefore can see inode items that
5269 * don't exist in the current root anymore, and for example make
5270 * calls to btrfs_iget, which will do tree lookups based on the
5271 * current root and not on the commit root. Those lookups will
5272 * fail, returning a -ESTALE error, and making send fail with
5273 * that error. So make sure a send does not see any orphans we
5274 * have just removed, and that it will see the same inodes
5275 * regardless of whether a transaction commit happened before
5276 * it started (meaning that the commit root will be the same as
5277 * the current root) or not.
5278 */
5279 if (sub_root->node != sub_root->commit_root) {
5280 u64 sub_flags = btrfs_root_flags(&sub_root->root_item);
5281
5282 if (sub_flags & BTRFS_ROOT_SUBVOL_RDONLY) {
5283 struct extent_buffer *eb;
5284
5285 /*
5286 * Assert we can't have races between dentry
5287 * lookup called through the snapshot creation
5288 * ioctl and the VFS.
5289 */
5290 ASSERT(mutex_is_locked(&dir->i_mutex));
5291
5292 down_write(&root->fs_info->commit_root_sem);
5293 eb = sub_root->commit_root;
5294 sub_root->commit_root =
5295 btrfs_root_node(sub_root);
5296 up_write(&root->fs_info->commit_root_sem);
5297 free_extent_buffer(eb);
5298 }
5299 }
5300 } 5264 }
5301 5265
5302 return inode; 5266 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,
713 if (ret) 713 if (ret)
714 goto fail; 714 goto fail;
715 715
716 ret = btrfs_orphan_cleanup(pending_snapshot->snap);
717 if (ret)
718 goto fail;
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
716 inode = btrfs_lookup_dentry(dentry->d_parent->d_inode, dentry); 749 inode = btrfs_lookup_dentry(dentry->d_parent->d_inode, dentry);
717 if (IS_ERR(inode)) { 750 if (IS_ERR(inode)) {
718 ret = PTR_ERR(inode); 751 ret = PTR_ERR(inode);