From ec4608962ecc278b650169609f81f8467de8a84e Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Wed, 15 Oct 2014 12:47:23 -0400 Subject: [PATCH] Revert Btrfs ro snapshot commit that causes filesystem corruption --- ...e-free-update-of-commit-root-for-ro-.patch | 105 ++++++++++++++++++ kernel.spec | 7 ++ 2 files changed, 112 insertions(+) create mode 100644 Revert-Btrfs-race-free-update-of-commit-root-for-ro-.patch 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 +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 + diff --git a/kernel.spec b/kernel.spec index 44a5c0dd6..960816797 100644 --- a/kernel.spec +++ b/kernel.spec @@ -609,6 +609,8 @@ Patch26037: HID-usbhid-always-poll-quirk-for-Elan-Touchscreen-00.patch Patch26038: USB-quirks-device-qualifier-quirk-for-another-Elan-t.patch Patch26039: HID-usbhid-always-poll-quirk-for-Elan-Touchscreen-01.patch +Patch26040: Revert-Btrfs-race-free-update-of-commit-root-for-ro-.patch + # git clone ssh://git.fedorahosted.org/git/kernel-arm64.git, git diff master...devel Patch30000: kernel-arm64.patch @@ -1330,6 +1332,8 @@ ApplyPatch HID-usbhid-always-poll-quirk-for-Elan-Touchscreen-00.patch ApplyPatch USB-quirks-device-qualifier-quirk-for-another-Elan-t.patch ApplyPatch HID-usbhid-always-poll-quirk-for-Elan-Touchscreen-01.patch +ApplyPatch Revert-Btrfs-race-free-update-of-commit-root-for-ro-.patch + %if 0%{?aarch64patches} ApplyPatch kernel-arm64.patch %ifnarch aarch64 # this is stupid, but i want to notice before secondary koji does. @@ -2198,6 +2202,9 @@ fi # ||----w | # || || %changelog +* Wed Oct 15 2014 Josh Boyer +- Revert Btrfs ro snapshot commit that causes filesystem corruption + * Wed Oct 15 2014 Josh Boyer - 3.18.0-0.rc0.git9.1 - Linux v3.17-9670-g0429fbc0bdc2