From: Greg Kroah-Hartman Date: Wed, 18 Dec 2013 20:56:14 +0000 (-0800) Subject: 3.12-stable patches X-Git-Tag: v3.4.75~8 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ba9a8ed03fb68ad625d3ae4e2ec242f15af11c01;p=thirdparty%2Fkernel%2Fstable-queue.git 3.12-stable patches added patches: btrfs-do-a-full-search-everytime-in-btrfs_search_old_slot.patch btrfs-do-not-run-snapshot-aware-defragment-on-error.patch btrfs-fix-a-crash-when-running-balance-and-defrag-concurrently.patch btrfs-fix-hole-check-in-log_one_extent.patch btrfs-fix-incorrect-inode-acl-reset.patch btrfs-fix-lockdep-error-in-async-commit.patch btrfs-fix-memory-leak-of-chunks-extent-map.patch btrfs-reset-intwrite-on-transaction-abort.patch btrfs-stop-using-vfs_read-in-send.patch btrfs-take-ordered-root-lock-when-removing-ordered-operations-inode.patch --- diff --git a/queue-3.12/btrfs-do-a-full-search-everytime-in-btrfs_search_old_slot.patch b/queue-3.12/btrfs-do-a-full-search-everytime-in-btrfs_search_old_slot.patch new file mode 100644 index 00000000000..faea3dca482 --- /dev/null +++ b/queue-3.12/btrfs-do-a-full-search-everytime-in-btrfs_search_old_slot.patch @@ -0,0 +1,57 @@ +From d4b4087c43cc00a196c5be57fac41f41309f1d56 Mon Sep 17 00:00:00 2001 +From: Josef Bacik +Date: Tue, 24 Sep 2013 14:09:34 -0400 +Subject: Btrfs: do a full search everytime in btrfs_search_old_slot + +From: Josef Bacik + +commit d4b4087c43cc00a196c5be57fac41f41309f1d56 upstream. + +While running some snashot aware defrag tests I noticed I was panicing every +once and a while in key_search. This is because of the optimization that says +if we find a key at slot 0 it will be at slot 0 all the way down the rest of the +tree. This isn't the case for btrfs_search_old_slot since it will likely replay +changes to a buffer if something has changed since we took our sequence number. +So short circuit this optimization by setting prev_cmp to -1 every time we call +key_search so we will do our normal binary search. With this patch I am no +longer seeing the panics I was seeing before. Thanks, + +Signed-off-by: Josef Bacik +Signed-off-by: Chris Mason +Signed-off-by: Greg Kroah-Hartman + +--- + fs/btrfs/ctree.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +--- a/fs/btrfs/ctree.c ++++ b/fs/btrfs/ctree.c +@@ -2758,7 +2758,7 @@ int btrfs_search_old_slot(struct btrfs_r + int level; + int lowest_unlock = 1; + u8 lowest_level = 0; +- int prev_cmp; ++ int prev_cmp = -1; + + lowest_level = p->lowest_level; + WARN_ON(p->nodes[0] != NULL); +@@ -2769,7 +2769,6 @@ int btrfs_search_old_slot(struct btrfs_r + } + + again: +- prev_cmp = -1; + b = get_old_root(root, time_seq); + level = btrfs_header_level(b); + p->locks[level] = BTRFS_READ_LOCK; +@@ -2787,6 +2786,11 @@ again: + */ + btrfs_unlock_up_safe(p, level + 1); + ++ /* ++ * Since we can unwind eb's we want to do a real search every ++ * time. ++ */ ++ prev_cmp = -1; + ret = key_search(b, key, level, &prev_cmp, &slot); + + if (level != 0) { diff --git a/queue-3.12/btrfs-do-not-run-snapshot-aware-defragment-on-error.patch b/queue-3.12/btrfs-do-not-run-snapshot-aware-defragment-on-error.patch new file mode 100644 index 00000000000..9dfe1de9f85 --- /dev/null +++ b/queue-3.12/btrfs-do-not-run-snapshot-aware-defragment-on-error.patch @@ -0,0 +1,131 @@ +From 6f519564d7d978c00351d9ab6abac3deeac31621 Mon Sep 17 00:00:00 2001 +From: Liu Bo +Date: Tue, 29 Oct 2013 10:45:05 +0800 +Subject: Btrfs: do not run snapshot-aware defragment on error + +From: Liu Bo + +commit 6f519564d7d978c00351d9ab6abac3deeac31621 upstream. + +If something wrong happens in write endio, running snapshot-aware defragment +can end up with undefined results, maybe a crash, so we should avoid it. + +In order to share similar code, this also adds a helper to free the struct for +snapshot-aware defrag. + +Signed-off-by: Liu Bo +Signed-off-by: Josef Bacik +Signed-off-by: Chris Mason +Signed-off-by: Greg Kroah-Hartman + +--- + fs/btrfs/inode.c | 47 ++++++++++++++++++++++++++++------------------- + 1 file changed, 28 insertions(+), 19 deletions(-) + +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -2367,10 +2367,23 @@ out_unlock: + return ret; + } + ++static void free_sa_defrag_extent(struct new_sa_defrag_extent *new) ++{ ++ struct old_sa_defrag_extent *old, *tmp; ++ ++ if (!new) ++ return; ++ ++ list_for_each_entry_safe(old, tmp, &new->head, list) { ++ list_del(&old->list); ++ kfree(old); ++ } ++ kfree(new); ++} ++ + static void relink_file_extents(struct new_sa_defrag_extent *new) + { + struct btrfs_path *path; +- struct old_sa_defrag_extent *old, *tmp; + struct sa_defrag_extent_backref *backref; + struct sa_defrag_extent_backref *prev = NULL; + struct inode *inode; +@@ -2413,16 +2426,11 @@ static void relink_file_extents(struct n + kfree(prev); + + btrfs_free_path(path); +- +- list_for_each_entry_safe(old, tmp, &new->head, list) { +- list_del(&old->list); +- kfree(old); +- } + out: ++ free_sa_defrag_extent(new); ++ + atomic_dec(&root->fs_info->defrag_running); + wake_up(&root->fs_info->transaction_wait); +- +- kfree(new); + } + + static struct new_sa_defrag_extent * +@@ -2432,7 +2440,7 @@ record_old_file_extents(struct inode *in + struct btrfs_root *root = BTRFS_I(inode)->root; + struct btrfs_path *path; + struct btrfs_key key; +- struct old_sa_defrag_extent *old, *tmp; ++ struct old_sa_defrag_extent *old; + struct new_sa_defrag_extent *new; + int ret; + +@@ -2480,7 +2488,7 @@ record_old_file_extents(struct inode *in + if (slot >= btrfs_header_nritems(l)) { + ret = btrfs_next_leaf(root, path); + if (ret < 0) +- goto out_free_list; ++ goto out_free_path; + else if (ret > 0) + break; + continue; +@@ -2509,7 +2517,7 @@ record_old_file_extents(struct inode *in + + old = kmalloc(sizeof(*old), GFP_NOFS); + if (!old) +- goto out_free_list; ++ goto out_free_path; + + offset = max(new->file_pos, key.offset); + end = min(new->file_pos + new->len, key.offset + num_bytes); +@@ -2531,15 +2539,10 @@ next: + + return new; + +-out_free_list: +- list_for_each_entry_safe(old, tmp, &new->head, list) { +- list_del(&old->list); +- kfree(old); +- } + out_free_path: + btrfs_free_path(path); + out_kfree: +- kfree(new); ++ free_sa_defrag_extent(new); + return NULL; + } + +@@ -2710,8 +2713,14 @@ out: + btrfs_remove_ordered_extent(inode, ordered_extent); + + /* for snapshot-aware defrag */ +- if (new) +- relink_file_extents(new); ++ if (new) { ++ if (ret) { ++ free_sa_defrag_extent(new); ++ atomic_dec(&root->fs_info->defrag_running); ++ } else { ++ relink_file_extents(new); ++ } ++ } + + /* once for us */ + btrfs_put_ordered_extent(ordered_extent); diff --git a/queue-3.12/btrfs-fix-a-crash-when-running-balance-and-defrag-concurrently.patch b/queue-3.12/btrfs-fix-a-crash-when-running-balance-and-defrag-concurrently.patch new file mode 100644 index 00000000000..cc60d4c6b3c --- /dev/null +++ b/queue-3.12/btrfs-fix-a-crash-when-running-balance-and-defrag-concurrently.patch @@ -0,0 +1,67 @@ +From 48ec47364b6d493f0a9cdc116977bf3f34e5c3ec Mon Sep 17 00:00:00 2001 +From: Liu Bo +Date: Wed, 30 Oct 2013 13:25:24 +0800 +Subject: Btrfs: fix a crash when running balance and defrag concurrently + +From: Liu Bo + +commit 48ec47364b6d493f0a9cdc116977bf3f34e5c3ec upstream. + +Running balance and defrag concurrently can end up with a crash: + +kernel BUG at fs/btrfs/relocation.c:4528! +RIP: 0010:[] [] btrfs_reloc_cow_block+ 0x1eb/0x230 [btrfs] +Call Trace: + [] ? update_ref_for_cow+0x241/0x380 [btrfs] + [] ? copy_extent_buffer+0xad/0x110 [btrfs] + [] __btrfs_cow_block+0x3a1/0x520 [btrfs] + [] btrfs_cow_block+0x116/0x1b0 [btrfs] + [] btrfs_search_slot+0x43d/0x970 [btrfs] + [] btrfs_lookup_file_extent+0x37/0x40 [btrfs] + [] __btrfs_drop_extents+0x11e/0xae0 [btrfs] + [] ? generic_bin_search.constprop.39+0x8d/0x1a0 [btrfs] + [] ? kmem_cache_alloc+0x1da/0x200 + [] ? btrfs_alloc_path+0x1a/0x20 [btrfs] + [] btrfs_drop_extents+0x60/0x90 [btrfs] + [] relink_extent_backref+0x2ed/0x780 [btrfs] + [] ? btrfs_submit_bio_hook+0x1e0/0x1e0 [btrfs] + [] ? iterate_inodes_from_logical+0x87/0xa0 [btrfs] + [] btrfs_finish_ordered_io+0x229/0xac0 [btrfs] + [] finish_ordered_fn+0x15/0x20 [btrfs] + [] worker_loop+0x125/0x4e0 [btrfs] + [] ? btrfs_queue_worker+0x300/0x300 [btrfs] + [] kthread+0xc0/0xd0 + [] ? insert_kthread_work+0x40/0x40 + [] ret_from_fork+0x7c/0xb0 + [] ? insert_kthread_work+0x40/0x40 +---------------------------------------------------------------------- + +It turns out to be that balance operation will bump root's @last_snapshot, +which enables snapshot-aware defrag path, and backref walking stuff will +find data reloc tree as refs' parent, and hit the BUG_ON() during COW. + +As data reloc tree's data is just for relocation purpose, and will be deleted right +after relocation is done, it's unnecessary to walk those refs belonged to data reloc +tree, it'd be better to skip them. + +Signed-off-by: Liu Bo +Signed-off-by: Josef Bacik +Signed-off-by: Chris Mason +Signed-off-by: Greg Kroah-Hartman + +--- + fs/btrfs/backref.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/fs/btrfs/backref.c ++++ b/fs/btrfs/backref.c +@@ -185,6 +185,9 @@ static int __add_prelim_ref(struct list_ + { + struct __prelim_ref *ref; + ++ if (root_id == BTRFS_DATA_RELOC_TREE_OBJECTID) ++ return 0; ++ + ref = kmem_cache_alloc(btrfs_prelim_ref_cache, gfp_mask); + if (!ref) + return -ENOMEM; diff --git a/queue-3.12/btrfs-fix-hole-check-in-log_one_extent.patch b/queue-3.12/btrfs-fix-hole-check-in-log_one_extent.patch new file mode 100644 index 00000000000..d19f7bb4d7e --- /dev/null +++ b/queue-3.12/btrfs-fix-hole-check-in-log_one_extent.patch @@ -0,0 +1,34 @@ +From ed9e8af88e2551aaa6bf51d8063a2493e2d71597 Mon Sep 17 00:00:00 2001 +From: Josef Bacik +Date: Mon, 14 Oct 2013 17:23:08 -0400 +Subject: Btrfs: fix hole check in log_one_extent + +From: Josef Bacik + +commit ed9e8af88e2551aaa6bf51d8063a2493e2d71597 upstream. + +I added an assert to make sure we were looking up aligned offsets for csums and +I tripped it when running xfstests. This is because log_one_extent was checking +if block_start == 0 for a hole instead of EXTENT_MAP_HOLE. This worked out fine +in practice it seems, but it adds a lot of extra work that is uneeded. With +this fix I'm no longer tripping my assert. Thanks, + +Signed-off-by: Josef Bacik +Signed-off-by: Chris Mason +Signed-off-by: Greg Kroah-Hartman + +--- + fs/btrfs/tree-log.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/btrfs/tree-log.c ++++ b/fs/btrfs/tree-log.c +@@ -3375,7 +3375,7 @@ static int log_one_extent(struct btrfs_t + btrfs_set_token_file_extent_type(leaf, fi, + BTRFS_FILE_EXTENT_REG, + &token); +- if (em->block_start == 0) ++ if (em->block_start == EXTENT_MAP_HOLE) + skip_csum = true; + } + diff --git a/queue-3.12/btrfs-fix-incorrect-inode-acl-reset.patch b/queue-3.12/btrfs-fix-incorrect-inode-acl-reset.patch new file mode 100644 index 00000000000..e6f9dae5da6 --- /dev/null +++ b/queue-3.12/btrfs-fix-incorrect-inode-acl-reset.patch @@ -0,0 +1,72 @@ +From 8185554d3eb09d23a805456b6fa98dcbb34aa518 Mon Sep 17 00:00:00 2001 +From: Filipe David Borba Manana +Date: Tue, 15 Oct 2013 18:44:00 +0100 +Subject: Btrfs: fix incorrect inode acl reset + +From: Filipe David Borba Manana + +commit 8185554d3eb09d23a805456b6fa98dcbb34aa518 upstream. + +When a directory has a default ACL and a subdirectory is created +under that directory, btrfs_init_acl() is called when the +subdirectory's inode is created to initialize the inode's ACL +(inherited from the parent directory) but it was clearing the ACL +from the inode after setting it if posix_acl_create() returned +success, instead of clearing it only if it returned an error. + +To reproduce this issue: + +$ mkfs.btrfs -f /dev/loop0 +$ mount /dev/loop0 /mnt +$ mkdir /mnt/acl +$ setfacl -d --set u::rwx,g::rwx,o::- /mnt/acl +$ getfacl /mnt/acl +user::rwx +group::rwx +other::r-x +default:user::rwx +default:group::rwx +default:other::--- + +$ mkdir /mnt/acl/dir1 +$ getfacl /mnt/acl/dir1 +user::rwx +group::rwx +other::--- + +After unmounting and mounting again the filesystem, fgetacl returned the +expected ACL: + +$ umount /mnt/acl +$ mount /dev/loop0 /mnt +$ getfacl /mnt/acl/dir1 +user::rwx +group::rwx +other::--- +default:user::rwx +default:group::rwx +default:other::--- + +Meaning that the underlying xattr was persisted. + +Reported-by: Giuseppe Fierro +Signed-off-by: Filipe David Borba Manana +Signed-off-by: Josef Bacik +Signed-off-by: Chris Mason +Signed-off-by: Greg Kroah-Hartman + +--- + fs/btrfs/acl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/btrfs/acl.c ++++ b/fs/btrfs/acl.c +@@ -229,7 +229,7 @@ int btrfs_init_acl(struct btrfs_trans_ha + if (ret > 0) { + /* we need an acl */ + ret = btrfs_set_acl(trans, inode, acl, ACL_TYPE_ACCESS); +- } else { ++ } else if (ret < 0) { + cache_no_acl(inode); + } + } else { diff --git a/queue-3.12/btrfs-fix-lockdep-error-in-async-commit.patch b/queue-3.12/btrfs-fix-lockdep-error-in-async-commit.patch new file mode 100644 index 00000000000..c52735bac74 --- /dev/null +++ b/queue-3.12/btrfs-fix-lockdep-error-in-async-commit.patch @@ -0,0 +1,84 @@ +From b1a06a4b574996692b72b742bf6e6aa0c711a948 Mon Sep 17 00:00:00 2001 +From: Liu Bo +Date: Wed, 6 Nov 2013 16:57:55 +0800 +Subject: Btrfs: fix lockdep error in async commit + +From: Liu Bo + +commit b1a06a4b574996692b72b742bf6e6aa0c711a948 upstream. + +Lockdep complains about btrfs's async commit: + +[ 2372.462171] [ BUG: bad unlock balance detected! ] +[ 2372.462191] 3.12.0+ #32 Tainted: G W +[ 2372.462209] ------------------------------------- +[ 2372.462228] ceph-osd/14048 is trying to release lock (sb_internal) at: +[ 2372.462275] [] btrfs_commit_transaction_async+0x1b0/0x2a0 [btrfs] +[ 2372.462305] but there are no more locks to release! +[ 2372.462324] +[ 2372.462324] other info that might help us debug this: +[ 2372.462349] no locks held by ceph-osd/14048. +[ 2372.462367] +[ 2372.462367] stack backtrace: +[ 2372.462386] CPU: 2 PID: 14048 Comm: ceph-osd Tainted: G W 3.12.0+ #32 +[ 2372.462414] Hardware name: To Be Filled By O.E.M. To Be Filled By O.E.M./To be filled by O.E.M., BIOS 080015 11/09/2011 +[ 2372.462455] ffffffffa022cb10 ffff88007490fd28 ffffffff816f094a ffff8800378aa320 +[ 2372.462491] ffff88007490fd50 ffffffff810adf4c ffff8800378aa320 ffff88009af97650 +[ 2372.462526] ffffffffa022cb10 ffff88007490fd88 ffffffff810b01ee ffff8800898c0000 +[ 2372.462562] Call Trace: +[ 2372.462584] [] ? btrfs_commit_transaction_async+0x1b0/0x2a0 [btrfs] +[ 2372.462619] [] dump_stack+0x45/0x56 +[ 2372.462642] [] print_unlock_imbalance_bug+0xec/0x100 +[ 2372.462677] [] ? btrfs_commit_transaction_async+0x1b0/0x2a0 [btrfs] +[ 2372.462710] [] lock_release+0x18e/0x210 +[ 2372.462742] [] btrfs_commit_transaction_async+0x1d6/0x2a0 [btrfs] +[ 2372.462783] [] btrfs_ioctl_start_sync+0x3e/0xc0 [btrfs] +[ 2372.462822] [] btrfs_ioctl+0x4c3/0x1f70 [btrfs] +[ 2372.462849] [] ? avc_has_perm+0x121/0x1b0 +[ 2372.462873] [] ? avc_has_perm+0x24/0x1b0 +[ 2372.462897] [] ? sched_clock_cpu+0xa8/0x100 +[ 2372.462922] [] do_vfs_ioctl+0x2e5/0x4e0 +[ 2372.462946] [] ? file_has_perm+0x86/0xa0 +[ 2372.462969] [] SyS_ioctl+0x81/0xa0 +[ 2372.462991] [] tracesys+0xdd/0xe2 + +==================================================== + +It's because that we don't do the right thing when checking if it's ok to +tell lockdep that we're trying to release the rwsem. + +If the trans handle's type is TRANS_ATTACH, we won't acquire the freeze rwsem, but +as TRANS_ATTACH fits the check (trans < TRANS_JOIN_NOLOCK), we'll release the freeze +rwsem, which makes lockdep complains a lot. + +Reported-by: Ma Jianpeng +Signed-off-by: Liu Bo +Signed-off-by: Miao Xie +Signed-off-by: Josef Bacik +Signed-off-by: Chris Mason +Signed-off-by: Greg Kroah-Hartman + +--- + fs/btrfs/transaction.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/fs/btrfs/transaction.c ++++ b/fs/btrfs/transaction.c +@@ -1453,7 +1453,7 @@ static void do_async_commit(struct work_ + * We've got freeze protection passed with the transaction. + * Tell lockdep about it. + */ +- if (ac->newtrans->type < TRANS_JOIN_NOLOCK) ++ if (ac->newtrans->type & __TRANS_FREEZABLE) + rwsem_acquire_read( + &ac->root->fs_info->sb->s_writers.lock_map[SB_FREEZE_FS-1], + 0, 1, _THIS_IP_); +@@ -1494,7 +1494,7 @@ int btrfs_commit_transaction_async(struc + * Tell lockdep we've released the freeze rwsem, since the + * async commit thread will be the one to unlock it. + */ +- if (trans->type < TRANS_JOIN_NOLOCK) ++ if (ac->newtrans->type & __TRANS_FREEZABLE) + rwsem_release( + &root->fs_info->sb->s_writers.lock_map[SB_FREEZE_FS-1], + 1, _THIS_IP_); diff --git a/queue-3.12/btrfs-fix-memory-leak-of-chunks-extent-map.patch b/queue-3.12/btrfs-fix-memory-leak-of-chunks-extent-map.patch new file mode 100644 index 00000000000..5cceaa62a6d --- /dev/null +++ b/queue-3.12/btrfs-fix-memory-leak-of-chunks-extent-map.patch @@ -0,0 +1,39 @@ +From 7d3d1744f8a7d62e4875bd69cc2192a939813880 Mon Sep 17 00:00:00 2001 +From: Liu Bo +Date: Sun, 29 Sep 2013 10:33:16 +0800 +Subject: Btrfs: fix memory leak of chunks' extent map + +From: Liu Bo + +commit 7d3d1744f8a7d62e4875bd69cc2192a939813880 upstream. + +As we're hold a ref on looking up the extent map, we need to drop the ref +before returning to callers. + +Signed-off-by: Liu Bo +Signed-off-by: Josef Bacik +Signed-off-by: Chris Mason +Signed-off-by: Greg Kroah-Hartman + +--- + fs/btrfs/volumes.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/fs/btrfs/volumes.c ++++ b/fs/btrfs/volumes.c +@@ -4488,6 +4488,7 @@ int btrfs_num_copies(struct btrfs_fs_inf + btrfs_crit(fs_info, "Invalid mapping for %Lu-%Lu, got " + "%Lu-%Lu\n", logical, logical+len, em->start, + em->start + em->len); ++ free_extent_map(em); + return 1; + } + +@@ -4668,6 +4669,7 @@ static int __btrfs_map_block(struct btrf + btrfs_crit(fs_info, "found a bad mapping, wanted %Lu, " + "found %Lu-%Lu\n", logical, em->start, + em->start + em->len); ++ free_extent_map(em); + return -EINVAL; + } + diff --git a/queue-3.12/btrfs-reset-intwrite-on-transaction-abort.patch b/queue-3.12/btrfs-reset-intwrite-on-transaction-abort.patch new file mode 100644 index 00000000000..ccd7b119486 --- /dev/null +++ b/queue-3.12/btrfs-reset-intwrite-on-transaction-abort.patch @@ -0,0 +1,31 @@ +From e0228285a8cad70e4b7b4833cc650e36ecd8de89 Mon Sep 17 00:00:00 2001 +From: Josef Bacik +Date: Fri, 20 Sep 2013 22:26:29 -0400 +Subject: Btrfs: reset intwrite on transaction abort + +From: Josef Bacik + +commit e0228285a8cad70e4b7b4833cc650e36ecd8de89 upstream. + +If we abort a transaction in the middle of a commit we weren't undoing the +intwrite locking. This patch fixes that problem. + +Signed-off-by: Josef Bacik +Signed-off-by: Chris Mason +Signed-off-by: Greg Kroah-Hartman + +--- + fs/btrfs/transaction.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/fs/btrfs/transaction.c ++++ b/fs/btrfs/transaction.c +@@ -1552,6 +1552,8 @@ static void cleanup_transaction(struct b + root->fs_info->running_transaction = NULL; + spin_unlock(&root->fs_info->trans_lock); + ++ if (trans->type & __TRANS_FREEZABLE) ++ sb_end_intwrite(root->fs_info->sb); + put_transaction(cur_trans); + put_transaction(cur_trans); + diff --git a/queue-3.12/btrfs-stop-using-vfs_read-in-send.patch b/queue-3.12/btrfs-stop-using-vfs_read-in-send.patch new file mode 100644 index 00000000000..1c711aa2f4e --- /dev/null +++ b/queue-3.12/btrfs-stop-using-vfs_read-in-send.patch @@ -0,0 +1,257 @@ +From ed2590953bd06b892f0411fc94e19175d32f197a Mon Sep 17 00:00:00 2001 +From: Josef Bacik +Date: Fri, 25 Oct 2013 11:36:01 -0400 +Subject: Btrfs: stop using vfs_read in send + +From: Josef Bacik + +commit ed2590953bd06b892f0411fc94e19175d32f197a upstream. + +Apparently we don't actually close the files until we return to userspace, so +stop using vfs_read in send. This is actually better for us since we can avoid +all the extra logic of holding the file we're sending open and making sure to +clean it up. This will fix people who have been hitting too many files open +errors when trying to send. Thanks, + +Signed-off-by: Josef Bacik +Signed-off-by: Chris Mason +Signed-off-by: Greg Kroah-Hartman + +--- + fs/btrfs/send.c | 175 +++++++++++++++++++++++--------------------------------- + 1 file changed, 72 insertions(+), 103 deletions(-) + +--- a/fs/btrfs/send.c ++++ b/fs/btrfs/send.c +@@ -121,7 +121,6 @@ struct send_ctx { + struct list_head name_cache_list; + int name_cache_size; + +- struct file *cur_inode_filp; + char *read_buf; + }; + +@@ -2120,77 +2119,6 @@ out: + } + + /* +- * Called for regular files when sending extents data. Opens a struct file +- * to read from the file. +- */ +-static int open_cur_inode_file(struct send_ctx *sctx) +-{ +- int ret = 0; +- struct btrfs_key key; +- struct path path; +- struct inode *inode; +- struct dentry *dentry; +- struct file *filp; +- int new = 0; +- +- if (sctx->cur_inode_filp) +- goto out; +- +- key.objectid = sctx->cur_ino; +- key.type = BTRFS_INODE_ITEM_KEY; +- key.offset = 0; +- +- inode = btrfs_iget(sctx->send_root->fs_info->sb, &key, sctx->send_root, +- &new); +- if (IS_ERR(inode)) { +- ret = PTR_ERR(inode); +- goto out; +- } +- +- dentry = d_obtain_alias(inode); +- inode = NULL; +- if (IS_ERR(dentry)) { +- ret = PTR_ERR(dentry); +- goto out; +- } +- +- path.mnt = sctx->mnt; +- path.dentry = dentry; +- filp = dentry_open(&path, O_RDONLY | O_LARGEFILE, current_cred()); +- dput(dentry); +- dentry = NULL; +- if (IS_ERR(filp)) { +- ret = PTR_ERR(filp); +- goto out; +- } +- sctx->cur_inode_filp = filp; +- +-out: +- /* +- * no xxxput required here as every vfs op +- * does it by itself on failure +- */ +- return ret; +-} +- +-/* +- * Closes the struct file that was created in open_cur_inode_file +- */ +-static int close_cur_inode_file(struct send_ctx *sctx) +-{ +- int ret = 0; +- +- if (!sctx->cur_inode_filp) +- goto out; +- +- ret = filp_close(sctx->cur_inode_filp, NULL); +- sctx->cur_inode_filp = NULL; +- +-out: +- return ret; +-} +- +-/* + * Sends a BTRFS_SEND_C_SUBVOL command/item to userspace + */ + static int send_subvol_begin(struct send_ctx *sctx) +@@ -3622,6 +3550,72 @@ out: + return ret; + } + ++static ssize_t fill_read_buf(struct send_ctx *sctx, u64 offset, u32 len) ++{ ++ struct btrfs_root *root = sctx->send_root; ++ struct btrfs_fs_info *fs_info = root->fs_info; ++ struct inode *inode; ++ struct page *page; ++ char *addr; ++ struct btrfs_key key; ++ pgoff_t index = offset >> PAGE_CACHE_SHIFT; ++ pgoff_t last_index; ++ unsigned pg_offset = offset & ~PAGE_CACHE_MASK; ++ ssize_t ret = 0; ++ ++ key.objectid = sctx->cur_ino; ++ key.type = BTRFS_INODE_ITEM_KEY; ++ key.offset = 0; ++ ++ inode = btrfs_iget(fs_info->sb, &key, root, NULL); ++ if (IS_ERR(inode)) ++ return PTR_ERR(inode); ++ ++ if (offset + len > i_size_read(inode)) { ++ if (offset > i_size_read(inode)) ++ len = 0; ++ else ++ len = offset - i_size_read(inode); ++ } ++ if (len == 0) ++ goto out; ++ ++ last_index = (offset + len - 1) >> PAGE_CACHE_SHIFT; ++ while (index <= last_index) { ++ unsigned cur_len = min_t(unsigned, len, ++ PAGE_CACHE_SIZE - pg_offset); ++ page = find_or_create_page(inode->i_mapping, index, GFP_NOFS); ++ if (!page) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ if (!PageUptodate(page)) { ++ btrfs_readpage(NULL, page); ++ lock_page(page); ++ if (!PageUptodate(page)) { ++ unlock_page(page); ++ page_cache_release(page); ++ ret = -EIO; ++ break; ++ } ++ } ++ ++ addr = kmap(page); ++ memcpy(sctx->read_buf + ret, addr + pg_offset, cur_len); ++ kunmap(page); ++ unlock_page(page); ++ page_cache_release(page); ++ index++; ++ pg_offset = 0; ++ len -= cur_len; ++ ret += cur_len; ++ } ++out: ++ iput(inode); ++ return ret; ++} ++ + /* + * Read some bytes from the current inode/file and send a write command to + * user space. +@@ -3630,35 +3624,20 @@ static int send_write(struct send_ctx *s + { + int ret = 0; + struct fs_path *p; +- loff_t pos = offset; +- int num_read = 0; +- mm_segment_t old_fs; ++ ssize_t num_read = 0; + + p = fs_path_alloc(); + if (!p) + return -ENOMEM; + +- /* +- * vfs normally only accepts user space buffers for security reasons. +- * we only read from the file and also only provide the read_buf buffer +- * to vfs. As this buffer does not come from a user space call, it's +- * ok to temporary allow kernel space buffers. +- */ +- old_fs = get_fs(); +- set_fs(KERNEL_DS); +- + verbose_printk("btrfs: send_write offset=%llu, len=%d\n", offset, len); + +- ret = open_cur_inode_file(sctx); +- if (ret < 0) +- goto out; +- +- ret = vfs_read(sctx->cur_inode_filp, sctx->read_buf, len, &pos); +- if (ret < 0) +- goto out; +- num_read = ret; +- if (!num_read) ++ num_read = fill_read_buf(sctx, offset, len); ++ if (num_read <= 0) { ++ if (num_read < 0) ++ ret = num_read; + goto out; ++ } + + ret = begin_cmd(sctx, BTRFS_SEND_C_WRITE); + if (ret < 0) +@@ -3677,7 +3656,6 @@ verbose_printk("btrfs: send_write offset + tlv_put_failure: + out: + fs_path_free(p); +- set_fs(old_fs); + if (ret < 0) + return ret; + return num_read; +@@ -4222,10 +4200,6 @@ static int changed_inode(struct send_ctx + u64 left_gen = 0; + u64 right_gen = 0; + +- ret = close_cur_inode_file(sctx); +- if (ret < 0) +- goto out; +- + sctx->cur_ino = key->objectid; + sctx->cur_inode_new_gen = 0; + +@@ -4686,11 +4660,6 @@ static int send_subvol(struct send_ctx * + } + + out: +- if (!ret) +- ret = close_cur_inode_file(sctx); +- else +- close_cur_inode_file(sctx); +- + free_recorded_refs(sctx); + return ret; + } diff --git a/queue-3.12/btrfs-take-ordered-root-lock-when-removing-ordered-operations-inode.patch b/queue-3.12/btrfs-take-ordered-root-lock-when-removing-ordered-operations-inode.patch new file mode 100644 index 00000000000..8667dcd629e --- /dev/null +++ b/queue-3.12/btrfs-take-ordered-root-lock-when-removing-ordered-operations-inode.patch @@ -0,0 +1,33 @@ +From 93858769172c4e3678917810e9d5de360eb991cc Mon Sep 17 00:00:00 2001 +From: Josef Bacik +Date: Mon, 28 Oct 2013 09:13:25 -0400 +Subject: Btrfs: take ordered root lock when removing ordered operations inode + +From: Josef Bacik + +commit 93858769172c4e3678917810e9d5de360eb991cc upstream. + +A user reported a list corruption warning from btrfs_remove_ordered_extent, it +is because we aren't taking the ordered_root_lock when we remove the inode from +the ordered operations list. Thanks, + +Signed-off-by: Josef Bacik +Signed-off-by: Chris Mason +Signed-off-by: Greg Kroah-Hartman + +--- + fs/btrfs/ordered-data.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/fs/btrfs/ordered-data.c ++++ b/fs/btrfs/ordered-data.c +@@ -537,7 +537,9 @@ void btrfs_remove_ordered_extent(struct + */ + if (RB_EMPTY_ROOT(&tree->tree) && + !mapping_tagged(inode->i_mapping, PAGECACHE_TAG_DIRTY)) { ++ spin_lock(&root->fs_info->ordered_root_lock); + list_del_init(&BTRFS_I(inode)->ordered_operations); ++ spin_unlock(&root->fs_info->ordered_root_lock); + } + + if (!root->nr_ordered_extents) { diff --git a/queue-3.12/series b/queue-3.12/series index 23b37845d01..c2db0092adf 100644 --- a/queue-3.12/series +++ b/queue-3.12/series @@ -103,3 +103,13 @@ sc1200_wdt-fix-oops.patch nfsv4-wait-on-recovery-for-async-session-errors.patch input-elantech-add-support-for-newer-august-2013-devices.patch revert-net-update-consumers-of-msg_more-to-recognize-msg_sendpage_notlast.patch +btrfs-do-a-full-search-everytime-in-btrfs_search_old_slot.patch +btrfs-reset-intwrite-on-transaction-abort.patch +btrfs-fix-memory-leak-of-chunks-extent-map.patch +btrfs-fix-hole-check-in-log_one_extent.patch +btrfs-fix-incorrect-inode-acl-reset.patch +btrfs-stop-using-vfs_read-in-send.patch +btrfs-take-ordered-root-lock-when-removing-ordered-operations-inode.patch +btrfs-do-not-run-snapshot-aware-defragment-on-error.patch +btrfs-fix-a-crash-when-running-balance-and-defrag-concurrently.patch +btrfs-fix-lockdep-error-in-async-commit.patch