From: Greg Kroah-Hartman Date: Wed, 3 Sep 2014 21:35:58 +0000 (-0700) Subject: 3.14-stable patches X-Git-Tag: v3.10.54~12 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=91530f93bdf4da458aac239e5cc7cea3546e12dd;p=thirdparty%2Fkernel%2Fstable-queue.git 3.14-stable patches added patches: btrfs-fix-compressed-write-corruption-on-enospc.patch btrfs-fix-crash-on-endio-of-reading-corrupted-block.patch btrfs-fix-csum-tree-corruption-duplicate-and-outdated-checksums.patch btrfs-fix-memory-corruption-by-ulist_add_merge-on-32bit-arch.patch btrfs-read-lock-extent-buffer-while-walking-backrefs.patch mei-nfc-fix-memory-leak-in-error-path.patch mei-reset-client-state-on-queued-connect-request.patch --- diff --git a/queue-3.14/btrfs-fix-compressed-write-corruption-on-enospc.patch b/queue-3.14/btrfs-fix-compressed-write-corruption-on-enospc.patch new file mode 100644 index 00000000000..35b4cd6ca98 --- /dev/null +++ b/queue-3.14/btrfs-fix-compressed-write-corruption-on-enospc.patch @@ -0,0 +1,45 @@ +From ce62003f690dff38d3164a632ec69efa15c32cbf Mon Sep 17 00:00:00 2001 +From: Liu Bo +Date: Thu, 24 Jul 2014 22:48:05 +0800 +Subject: Btrfs: fix compressed write corruption on enospc + +From: Liu Bo + +commit ce62003f690dff38d3164a632ec69efa15c32cbf upstream. + +When failing to allocate space for the whole compressed extent, we'll +fallback to uncompressed IO, but we've forgotten to redirty the pages +which belong to this compressed extent, and these 'clean' pages will +simply skip 'submit' part and go to endio directly, at last we got data +corruption as we write nothing. + +Signed-off-by: Liu Bo +Tested-By: Martin Steigerwald +Signed-off-by: Chris Mason +Signed-off-by: Greg Kroah-Hartman + +--- + fs/btrfs/inode.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -701,6 +701,18 @@ retry: + unlock_extent(io_tree, async_extent->start, + async_extent->start + + async_extent->ram_size - 1); ++ ++ /* ++ * we need to redirty the pages if we decide to ++ * fallback to uncompressed IO, otherwise we ++ * will not submit these pages down to lower ++ * layers. ++ */ ++ extent_range_redirty_for_io(inode, ++ async_extent->start, ++ async_extent->start + ++ async_extent->ram_size - 1); ++ + goto retry; + } + goto out_free; diff --git a/queue-3.14/btrfs-fix-crash-on-endio-of-reading-corrupted-block.patch b/queue-3.14/btrfs-fix-crash-on-endio-of-reading-corrupted-block.patch new file mode 100644 index 00000000000..8167412f44e --- /dev/null +++ b/queue-3.14/btrfs-fix-crash-on-endio-of-reading-corrupted-block.patch @@ -0,0 +1,43 @@ +From 38c1c2e44bacb37efd68b90b3f70386a8ee370ee Mon Sep 17 00:00:00 2001 +From: Liu Bo +Date: Tue, 19 Aug 2014 23:33:13 +0800 +Subject: Btrfs: fix crash on endio of reading corrupted block + +From: Liu Bo + +commit 38c1c2e44bacb37efd68b90b3f70386a8ee370ee upstream. + +The crash is + +------------[ cut here ]------------ +kernel BUG at fs/btrfs/extent_io.c:2124! +[...] +Workqueue: btrfs-endio normal_work_helper [btrfs] +RIP: 0010:[] [] end_bio_extent_readpage+0xb45/0xcd0 [btrfs] + +This is in fact a regression. + +It is because we forgot to increase @offset properly in reading corrupted block, +so that the @offset remains, and this leads to checksum errors while reading +left blocks queued up in the same bio, and then ends up with hiting the above +BUG_ON. + +Reported-by: Chris Murphy +Signed-off-by: Liu Bo +Signed-off-by: Chris Mason +Signed-off-by: Greg Kroah-Hartman + +--- + fs/btrfs/extent_io.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/fs/btrfs/extent_io.c ++++ b/fs/btrfs/extent_io.c +@@ -2525,6 +2525,7 @@ static void end_bio_extent_readpage(stru + test_bit(BIO_UPTODATE, &bio->bi_flags); + if (err) + uptodate = 0; ++ offset += len; + continue; + } + } diff --git a/queue-3.14/btrfs-fix-csum-tree-corruption-duplicate-and-outdated-checksums.patch b/queue-3.14/btrfs-fix-csum-tree-corruption-duplicate-and-outdated-checksums.patch new file mode 100644 index 00000000000..6eb12ab7982 --- /dev/null +++ b/queue-3.14/btrfs-fix-csum-tree-corruption-duplicate-and-outdated-checksums.patch @@ -0,0 +1,106 @@ +From 27b9a8122ff71a8cadfbffb9c4f0694300464f3b Mon Sep 17 00:00:00 2001 +From: Filipe Manana +Date: Sat, 9 Aug 2014 21:22:27 +0100 +Subject: Btrfs: fix csum tree corruption, duplicate and outdated checksums + +From: Filipe Manana + +commit 27b9a8122ff71a8cadfbffb9c4f0694300464f3b upstream. + +Under rare circumstances we can end up leaving 2 versions of a checksum +for the same file extent range. + +The reason for this is that after calling btrfs_next_leaf we process +slot 0 of the leaf it returns, instead of processing the slot set in +path->slots[0]. Most of the time (by far) path->slots[0] is 0, but after +btrfs_next_leaf() releases the path and before it searches for the next +leaf, another task might cause a split of the next leaf, which migrates +some of its keys to the leaf we were processing before calling +btrfs_next_leaf(). In this case btrfs_next_leaf() returns again the +same leaf but with path->slots[0] having a slot number corresponding +to the first new key it got, that is, a slot number that didn't exist +before calling btrfs_next_leaf(), as the leaf now has more keys than +it had before. So we must really process the returned leaf starting at +path->slots[0] always, as it isn't always 0, and the key at slot 0 can +have an offset much lower than our search offset/bytenr. + +For example, consider the following scenario, where we have: + +sums->bytenr: 40157184, sums->len: 16384, sums end: 40173568 +four 4kb file data blocks with offsets 40157184, 40161280, 40165376, 40169472 + + Leaf N: + + slot = 0 slot = btrfs_header_nritems() - 1 + |-------------------------------------------------------------------| + | [(CSUM CSUM 39239680), size 8] ... [(CSUM CSUM 40116224), size 4] | + |-------------------------------------------------------------------| + + Leaf N + 1: + + slot = 0 slot = btrfs_header_nritems() - 1 + |--------------------------------------------------------------------| + | [(CSUM CSUM 40161280), size 32] ... [((CSUM CSUM 40615936), size 8 | + |--------------------------------------------------------------------| + +Because we are at the last slot of leaf N, we call btrfs_next_leaf() to +find the next highest key, which releases the current path and then searches +for that next key. However after releasing the path and before finding that +next key, the item at slot 0 of leaf N + 1 gets moved to leaf N, due to a call +to ctree.c:push_leaf_left() (via ctree.c:split_leaf()), and therefore +btrfs_next_leaf() will returns us a path again with leaf N but with the slot +pointing to its new last key (CSUM CSUM 40161280). This new version of leaf N +is then: + + slot = 0 slot = btrfs_header_nritems() - 2 slot = btrfs_header_nritems() - 1 + |----------------------------------------------------------------------------------------------------| + | [(CSUM CSUM 39239680), size 8] ... [(CSUM CSUM 40116224), size 4] [(CSUM CSUM 40161280), size 32] | + |----------------------------------------------------------------------------------------------------| + +And incorrecly using slot 0, makes us set next_offset to 39239680 and we jump +into the "insert:" label, which will set tmp to: + + tmp = min((sums->len - total_bytes) >> blocksize_bits, + (next_offset - file_key.offset) >> blocksize_bits) = + min((16384 - 0) >> 12, (39239680 - 40157184) >> 12) = + min(4, (u64)-917504 = 18446744073708634112 >> 12) = 4 + +and + + ins_size = csum_size * tmp = 4 * 4 = 16 bytes. + +In other words, we insert a new csum item in the tree with key +(CSUM_OBJECTID CSUM_KEY 40157184 = sums->bytenr) that contains the checksums +for all the data (4 blocks of 4096 bytes each = sums->len). Which is wrong, +because the item with key (CSUM CSUM 40161280) (the one that was moved from +leaf N + 1 to the end of leaf N) contains the old checksums of the last 12288 +bytes of our data and won't get those old checksums removed. + +So this leaves us 2 different checksums for 3 4kb blocks of data in the tree, +and breaks the logical rule: + + Key_N+1.offset >= Key_N.offset + length_of_data_its_checksums_cover + +An obvious bad effect of this is that a subsequent csum tree lookup to get +the checksum of any of the blocks with logical offset of 40161280, 40165376 +or 40169472 (the last 3 4kb blocks of file data), will get the old checksums. + +Signed-off-by: Filipe Manana +Signed-off-by: Chris Mason +Signed-off-by: Greg Kroah-Hartman + +--- + fs/btrfs/file-item.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/btrfs/file-item.c ++++ b/fs/btrfs/file-item.c +@@ -756,7 +756,7 @@ again: + found_next = 1; + if (ret != 0) + goto insert; +- slot = 0; ++ slot = path->slots[0]; + } + btrfs_item_key_to_cpu(path->nodes[0], &found_key, slot); + if (found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || diff --git a/queue-3.14/btrfs-fix-memory-corruption-by-ulist_add_merge-on-32bit-arch.patch b/queue-3.14/btrfs-fix-memory-corruption-by-ulist_add_merge-on-32bit-arch.patch new file mode 100644 index 00000000000..b0b00ac8b8a --- /dev/null +++ b/queue-3.14/btrfs-fix-memory-corruption-by-ulist_add_merge-on-32bit-arch.patch @@ -0,0 +1,115 @@ +From 4eb1f66dce6c4dc28dd90a7ffbe6b2b1cb08aa4e Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Mon, 28 Jul 2014 10:57:04 +0200 +Subject: Btrfs: Fix memory corruption by ulist_add_merge() on 32bit arch + +From: Takashi Iwai + +commit 4eb1f66dce6c4dc28dd90a7ffbe6b2b1cb08aa4e upstream. + +We've got bug reports that btrfs crashes when quota is enabled on +32bit kernel, typically with the Oops like below: + BUG: unable to handle kernel NULL pointer dereference at 00000004 + IP: [] find_parent_nodes+0x360/0x1380 [btrfs] + *pde = 00000000 + Oops: 0000 [#1] SMP + CPU: 0 PID: 151 Comm: kworker/u8:2 Tainted: G S W 3.15.2-1.gd43d97e-default #1 + Workqueue: btrfs-qgroup-rescan normal_work_helper [btrfs] + task: f1478130 ti: f147c000 task.ti: f147c000 + EIP: 0060:[] EFLAGS: 00010213 CPU: 0 + EIP is at find_parent_nodes+0x360/0x1380 [btrfs] + EAX: f147dda8 EBX: f147ddb0 ECX: 00000011 EDX: 00000000 + ESI: 00000000 EDI: f147dda4 EBP: f147ddf8 ESP: f147dd38 + DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 + CR0: 8005003b CR2: 00000004 CR3: 00bf3000 CR4: 00000690 + Stack: + 00000000 00000000 f147dda4 00000050 00000001 00000000 00000001 00000050 + 00000001 00000000 d3059000 00000001 00000022 000000a8 00000000 00000000 + 00000000 000000a1 00000000 00000000 00000001 00000000 00000000 11800000 + Call Trace: + [] __btrfs_find_all_roots+0x9d/0xf0 [btrfs] + [] btrfs_qgroup_rescan_worker+0x401/0x760 [btrfs] + [] normal_work_helper+0xc8/0x270 [btrfs] + [] process_one_work+0x11b/0x390 + [] worker_thread+0x101/0x340 + [] kthread+0x9b/0xb0 + [] ret_from_kernel_thread+0x21/0x30 + [] kthread_create_on_node+0x110/0x110 + +This indicates a NULL corruption in prefs_delayed list. The further +investigation and bisection pointed that the call of ulist_add_merge() +results in the corruption. + +ulist_add_merge() takes u64 as aux and writes a 64bit value into +old_aux. The callers of this function in backref.c, however, pass a +pointer of a pointer to old_aux. That is, the function overwrites +64bit value on 32bit pointer. This caused a NULL in the adjacent +variable, in this case, prefs_delayed. + +Here is a quick attempt to band-aid over this: a new function, +ulist_add_merge_ptr() is introduced to pass/store properly a pointer +value instead of u64. There are still ugly void ** cast remaining +in the callers because void ** cannot be taken implicitly. But, it's +safer than explicit cast to u64, anyway. + +Bugzilla: https://bugzilla.novell.com/show_bug.cgi?id=887046 +Signed-off-by: Takashi Iwai +Signed-off-by: Chris Mason +Signed-off-by: Greg Kroah-Hartman + +--- + fs/btrfs/backref.c | 11 +++++------ + fs/btrfs/ulist.h | 15 +++++++++++++++ + 2 files changed, 20 insertions(+), 6 deletions(-) + +--- a/fs/btrfs/backref.c ++++ b/fs/btrfs/backref.c +@@ -275,9 +275,8 @@ static int add_all_parents(struct btrfs_ + } + if (ret > 0) + goto next; +- ret = ulist_add_merge(parents, eb->start, +- (uintptr_t)eie, +- (u64 *)&old, GFP_NOFS); ++ ret = ulist_add_merge_ptr(parents, eb->start, ++ eie, (void **)&old, GFP_NOFS); + if (ret < 0) + break; + if (!ret && extent_item_pos) { +@@ -992,9 +991,9 @@ again: + goto out; + ref->inode_list = eie; + } +- ret = ulist_add_merge(refs, ref->parent, +- (uintptr_t)ref->inode_list, +- (u64 *)&eie, GFP_NOFS); ++ ret = ulist_add_merge_ptr(refs, ref->parent, ++ ref->inode_list, ++ (void **)&eie, GFP_NOFS); + if (ret < 0) + goto out; + if (!ret && extent_item_pos) { +--- a/fs/btrfs/ulist.h ++++ b/fs/btrfs/ulist.h +@@ -57,6 +57,21 @@ void ulist_free(struct ulist *ulist); + int ulist_add(struct ulist *ulist, u64 val, u64 aux, gfp_t gfp_mask); + int ulist_add_merge(struct ulist *ulist, u64 val, u64 aux, + u64 *old_aux, gfp_t gfp_mask); ++ ++/* just like ulist_add_merge() but take a pointer for the aux data */ ++static inline int ulist_add_merge_ptr(struct ulist *ulist, u64 val, void *aux, ++ void **old_aux, gfp_t gfp_mask) ++{ ++#if BITS_PER_LONG == 32 ++ u64 old64 = (uintptr_t)*old_aux; ++ int ret = ulist_add_merge(ulist, val, (uintptr_t)aux, &old64, gfp_mask); ++ *old_aux = (void *)((uintptr_t)old64); ++ return ret; ++#else ++ return ulist_add_merge(ulist, val, (u64)aux, (u64 *)old_aux, gfp_mask); ++#endif ++} ++ + struct ulist_node *ulist_next(struct ulist *ulist, + struct ulist_iterator *uiter); + diff --git a/queue-3.14/btrfs-read-lock-extent-buffer-while-walking-backrefs.patch b/queue-3.14/btrfs-read-lock-extent-buffer-while-walking-backrefs.patch new file mode 100644 index 00000000000..af7d4ab4503 --- /dev/null +++ b/queue-3.14/btrfs-read-lock-extent-buffer-while-walking-backrefs.patch @@ -0,0 +1,34 @@ +From 6f7ff6d7832c6be13e8c95598884dbc40ad69fb7 Mon Sep 17 00:00:00 2001 +From: Filipe Manana +Date: Wed, 2 Jul 2014 20:07:54 +0100 +Subject: Btrfs: read lock extent buffer while walking backrefs + +From: Filipe Manana + +commit 6f7ff6d7832c6be13e8c95598884dbc40ad69fb7 upstream. + +Before processing the extent buffer, acquire a read lock on it, so +that we're safe against concurrent updates on the extent buffer. + +Signed-off-by: Filipe Manana +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 +@@ -984,8 +984,11 @@ again: + ret = -EIO; + goto out; + } ++ btrfs_tree_read_lock(eb); ++ btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK); + ret = find_extent_in_eb(eb, bytenr, + *extent_item_pos, &eie); ++ btrfs_tree_read_unlock_blocking(eb); + free_extent_buffer(eb); + if (ret < 0) + goto out; diff --git a/queue-3.14/mei-nfc-fix-memory-leak-in-error-path.patch b/queue-3.14/mei-nfc-fix-memory-leak-in-error-path.patch new file mode 100644 index 00000000000..1870bf7c4a7 --- /dev/null +++ b/queue-3.14/mei-nfc-fix-memory-leak-in-error-path.patch @@ -0,0 +1,58 @@ +From 8e8248b1369c97c7bb6f8bcaee1f05deeabab8ef Mon Sep 17 00:00:00 2001 +From: Alexander Usyskin +Date: Tue, 12 Aug 2014 18:07:57 +0300 +Subject: mei: nfc: fix memory leak in error path + +From: Alexander Usyskin + +commit 8e8248b1369c97c7bb6f8bcaee1f05deeabab8ef upstream. + +NFC will leak buffer if send failed. +Use single exit point that does the freeing + +Signed-off-by: Alexander Usyskin +Signed-off-by: Tomas Winkler +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/misc/mei/nfc.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +--- a/drivers/misc/mei/nfc.c ++++ b/drivers/misc/mei/nfc.c +@@ -342,9 +342,10 @@ static int mei_nfc_send(struct mei_cl_de + ndev = (struct mei_nfc_dev *) cldev->priv_data; + dev = ndev->cl->dev; + ++ err = -ENOMEM; + mei_buf = kzalloc(length + MEI_NFC_HEADER_SIZE, GFP_KERNEL); + if (!mei_buf) +- return -ENOMEM; ++ goto out; + + hdr = (struct mei_nfc_hci_hdr *) mei_buf; + hdr->cmd = MEI_NFC_CMD_HCI_SEND; +@@ -354,12 +355,9 @@ static int mei_nfc_send(struct mei_cl_de + hdr->data_size = length; + + memcpy(mei_buf + MEI_NFC_HEADER_SIZE, buf, length); +- + err = __mei_cl_send(ndev->cl, mei_buf, length + MEI_NFC_HEADER_SIZE); + if (err < 0) +- return err; +- +- kfree(mei_buf); ++ goto out; + + if (!wait_event_interruptible_timeout(ndev->send_wq, + ndev->recv_req_id == ndev->req_id, HZ)) { +@@ -368,7 +366,8 @@ static int mei_nfc_send(struct mei_cl_de + } else { + ndev->req_id++; + } +- ++out: ++ kfree(mei_buf); + return err; + } + diff --git a/queue-3.14/mei-reset-client-state-on-queued-connect-request.patch b/queue-3.14/mei-reset-client-state-on-queued-connect-request.patch new file mode 100644 index 00000000000..f6c6103a848 --- /dev/null +++ b/queue-3.14/mei-reset-client-state-on-queued-connect-request.patch @@ -0,0 +1,37 @@ +From 73ab4232388b7a08f17c8d08141ff2099fa0b161 Mon Sep 17 00:00:00 2001 +From: Alexander Usyskin +Date: Tue, 12 Aug 2014 18:07:56 +0300 +Subject: mei: reset client state on queued connect request + +From: Alexander Usyskin + +commit 73ab4232388b7a08f17c8d08141ff2099fa0b161 upstream. + +If connect request is queued (e.g. device in pg) set client state +to initializing, thus avoid preliminary exit in wait if current +state is disconnected. + +This is regression from: + +commit e4d8270e604c3202131bac607969605ac397b893 +Author: Alexander Usyskin +mei: set connecting state just upon connection request is sent to the fw + +Signed-off-by: Alexander Usyskin +Signed-off-by: Tomas Winkler +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/misc/mei/client.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/misc/mei/client.c ++++ b/drivers/misc/mei/client.c +@@ -564,6 +564,7 @@ int mei_cl_connect(struct mei_cl *cl, st + cl->timer_count = MEI_CONNECT_TIMEOUT; + list_add_tail(&cb->list, &dev->ctrl_rd_list.list); + } else { ++ cl->state = MEI_FILE_INITIALIZING; + list_add_tail(&cb->list, &dev->ctrl_wr_list.list); + } + diff --git a/queue-3.14/series b/queue-3.14/series index 6875a2197b1..741c0b11b52 100644 --- a/queue-3.14/series +++ b/queue-3.14/series @@ -58,3 +58,10 @@ x86-efi-enforce-config_relocatable-for-efi-boot-stub.patch x86-xen-use-vmap-to-map-grant-table-pages-in-pvh-guests.patch x86-xen-resume-timer-irqs-early.patch hpsa-fix-bad-enomem-return-value-in-hpsa_big_passthru_ioctl.patch +btrfs-fix-memory-corruption-by-ulist_add_merge-on-32bit-arch.patch +btrfs-fix-csum-tree-corruption-duplicate-and-outdated-checksums.patch +btrfs-read-lock-extent-buffer-while-walking-backrefs.patch +btrfs-fix-compressed-write-corruption-on-enospc.patch +btrfs-fix-crash-on-endio-of-reading-corrupted-block.patch +mei-reset-client-state-on-queued-connect-request.patch +mei-nfc-fix-memory-leak-in-error-path.patch