From: Greg Kroah-Hartman Date: Wed, 3 Sep 2014 21:58:39 +0000 (-0700) Subject: 3.16-stable patches X-Git-Tag: v3.10.54~8 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=fbd8d8e4f11bd0f7145efcc9a0ed38297a4fe67b;p=thirdparty%2Fkernel%2Fstable-queue.git 3.16-stable patches added patches: arm-omap2-hwmod-rearm-wake-up-interrupts-for-dt-when-musb-is-idled.patch ext4-fix-incorect-journal-credits-reservation-in-ext4_zero_range.patch ext4-fix-same-dir-rename-when-inline-data-directory-overflows.patch ext4-fix-transaction-issues-for-ext4_fallocate-and-ext_zero_range.patch ext4-update-i_disksize-coherently-with-block-allocation-on-error-path.patch jbd2-fix-descriptor-block-size-handling-errors-with-journal_csum.patch jbd2-fix-infinite-loop-when-recovering-corrupt-journal-blocks.patch nfs-fix-proc-fs-nfsfs-servers-and-proc-fs-nfsfs-volumes.patch nfs-reject-changes-to-resvport-and-sharecache-during-remount.patch nfs3_list_one_acl-check-get_acl-result-with-is_err_or_null.patch nfsd-decrease-nfsd_users-in-nfsd_startup_generic-fail.patch nfsv3-fix-another-acl-regression.patch nfsv4-don-t-clear-the-open-state-when-we-just-did-an-open_downgrade.patch nfsv4-fix-problems-with-close-in-the-presence-of-a-delegation.patch staging-et131x-fix-errors-caused-by-phydev-addr-accesses-before-initialisation.patch staging-lustre-remove-circular-dependency-on-header.patch staging-r8188eu-add-new-usb-id.patch staging-rtl8188eu-add-0df6-0076-sitecom-europe-b.v.patch svcrdma-select-nfsv4.1-backchannel-transport-based-on-forward-channel.patch usb-ehci-using-windex-1-for-hub-port.patch usb-ftdi_sio-add-basic-micro-atom-nano-usb2serial-pid.patch usb-ftdi_sio-added-pid-for-new-ekey-device.patch usb-hub-prevent-hub-autosuspend-if-usbcore.autosuspend-is-1.patch usb-whiteheat-added-bounds-checking-for-bulk-command-response.patch usb-xhci-amd-chipset-also-needs-short-tx-quirk.patch usbcore-fix-wrong-device-in-an-error-message-in-hub_port_connect.patch vm_is_stack-use-for_each_thread-rather-then-buggy-while_each_thread.patch xhci-disable-streams-on-via-xhci-with-device-id-0x3432.patch xhci-rework-cycle-bit-checking-for-new-dequeue-pointers.patch xhci-treat-not-finding-the-event_seg-on-comp_stop-the-same-as-comp_stop_inval.patch --- diff --git a/queue-3.16/arm-omap2-hwmod-rearm-wake-up-interrupts-for-dt-when-musb-is-idled.patch b/queue-3.16/arm-omap2-hwmod-rearm-wake-up-interrupts-for-dt-when-musb-is-idled.patch new file mode 100644 index 00000000000..b07747ba497 --- /dev/null +++ b/queue-3.16/arm-omap2-hwmod-rearm-wake-up-interrupts-for-dt-when-musb-is-idled.patch @@ -0,0 +1,59 @@ +From cc824534d4fef0e46e4486d5c1e10d3c6b1ebadc Mon Sep 17 00:00:00 2001 +From: Tony Lindgren +Date: Mon, 25 Aug 2014 16:15:35 -0700 +Subject: ARM: OMAP2+: hwmod: Rearm wake-up interrupts for DT when MUSB is idled + +From: Tony Lindgren + +commit cc824534d4fef0e46e4486d5c1e10d3c6b1ebadc upstream. + +Looks like MUSB cable removal can cause wake-up interrupts to +stop working for device tree based booting at least for UART3 +even as nothing is dynamically remuxed. This can be fixed by +calling reconfigure_io_chain() for device tree based booting +in hwmod code. Note that we already do that for legacy booting +if the legacy mux is configured. + +My guess is that this is related to UART3 and MUSB ULPI +hsusb0_data0 and hsusb0_data1 support for Carkit mode that +somehow affect the configured IO chain for UART3 and require +rearming the wake-up interrupts. + +In general, for device tree based booting, pinctrl-single +calls the rearm hook that in turn calls reconfigure_io_chain +so calling reconfigure_io_chain should not be needed from the +hwmod code for other events. + +So let's limit the hwmod rearming of iochain only to +HWMOD_FORCE_MSTANDBY where MUSB is currently the only user +of it. If we see other devices needing similar changes we can +add more checks for it. + +Cc: Paul Walmsley +Signed-off-by: Tony Lindgren +Signed-off-by: Greg Kroah-Hartman + +--- + arch/arm/mach-omap2/omap_hwmod.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/arch/arm/mach-omap2/omap_hwmod.c ++++ b/arch/arm/mach-omap2/omap_hwmod.c +@@ -2185,6 +2185,8 @@ static int _enable(struct omap_hwmod *oh + oh->mux->pads_dynamic))) { + omap_hwmod_mux(oh->mux, _HWMOD_STATE_ENABLED); + _reconfigure_io_chain(); ++ } else if (oh->flags & HWMOD_FORCE_MSTANDBY) { ++ _reconfigure_io_chain(); + } + + _add_initiator_dep(oh, mpu_oh); +@@ -2291,6 +2293,8 @@ static int _idle(struct omap_hwmod *oh) + if (oh->mux && oh->mux->pads_dynamic) { + omap_hwmod_mux(oh->mux, _HWMOD_STATE_IDLE); + _reconfigure_io_chain(); ++ } else if (oh->flags & HWMOD_FORCE_MSTANDBY) { ++ _reconfigure_io_chain(); + } + + oh->_state = _HWMOD_STATE_IDLE; diff --git a/queue-3.16/ext4-fix-incorect-journal-credits-reservation-in-ext4_zero_range.patch b/queue-3.16/ext4-fix-incorect-journal-credits-reservation-in-ext4_zero_range.patch new file mode 100644 index 00000000000..be324aa5564 --- /dev/null +++ b/queue-3.16/ext4-fix-incorect-journal-credits-reservation-in-ext4_zero_range.patch @@ -0,0 +1,48 @@ +From 69dc9536405213c1d545fcace1fc15c481d00aae Mon Sep 17 00:00:00 2001 +From: Dmitry Monakhov +Date: Wed, 27 Aug 2014 18:33:49 -0400 +Subject: ext4: fix incorect journal credits reservation in ext4_zero_range + +From: Dmitry Monakhov + +commit 69dc9536405213c1d545fcace1fc15c481d00aae upstream. + +Currently we reserve only 4 blocks but in worst case scenario +ext4_zero_partial_blocks() may want to zeroout and convert two +non adjacent blocks. + +Signed-off-by: Dmitry Monakhov +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman + +--- + fs/ext4/extents.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -4730,6 +4730,7 @@ static long ext4_zero_range(struct file + loff_t new_size = 0; + int ret = 0; + int flags; ++ int credits; + int partial; + loff_t start, end; + ext4_lblk_t lblk; +@@ -4829,8 +4830,14 @@ static long ext4_zero_range(struct file + if (ret) + goto out_dio; + } +- +- handle = ext4_journal_start(inode, EXT4_HT_MISC, 4); ++ /* ++ * In worst case we have to writeout two nonadjacent unwritten ++ * blocks and update the inode ++ */ ++ credits = (2 * ext4_ext_index_trans_blocks(inode, 2)) + 1; ++ if (ext4_should_journal_data(inode)) ++ credits += 2; ++ handle = ext4_journal_start(inode, EXT4_HT_MISC, credits); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + ext4_std_error(inode->i_sb, ret); diff --git a/queue-3.16/ext4-fix-same-dir-rename-when-inline-data-directory-overflows.patch b/queue-3.16/ext4-fix-same-dir-rename-when-inline-data-directory-overflows.patch new file mode 100644 index 00000000000..1fb6fee01c1 --- /dev/null +++ b/queue-3.16/ext4-fix-same-dir-rename-when-inline-data-directory-overflows.patch @@ -0,0 +1,110 @@ +From d80d448c6c5bdd32605b78a60fe8081d82d4da0f Mon Sep 17 00:00:00 2001 +From: "Darrick J. Wong" +Date: Wed, 27 Aug 2014 18:40:09 -0400 +Subject: ext4: fix same-dir rename when inline data directory overflows + +From: "Darrick J. Wong" + +commit d80d448c6c5bdd32605b78a60fe8081d82d4da0f upstream. + +When performing a same-directory rename, it's possible that adding or +setting the new directory entry will cause the directory to overflow +the inline data area, which causes the directory to be converted to an +extent-based directory. Under this circumstance it is necessary to +re-read the directory when deleting the old dirent because the "old +directory" context still points to i_block in the inode table, which +is now an extent tree root! The delete fails with an FS error, and +the subsequent fsck complains about incorrect link counts and +hardlinked directories. + +Test case (originally found with flat_dir_test in the metadata_csum +test program): + +# mkfs.ext4 -O inline_data /dev/sda +# mount /dev/sda /mnt +# mkdir /mnt/x +# touch /mnt/x/changelog.gz /mnt/x/copyright /mnt/x/README.Debian +# sync +# for i in /mnt/x/*; do mv $i $i.longer; done +# ls -la /mnt/x/ +total 0 +-rw-r--r-- 1 root root 0 Aug 25 12:03 changelog.gz.longer +-rw-r--r-- 1 root root 0 Aug 25 12:03 copyright +-rw-r--r-- 1 root root 0 Aug 25 12:03 copyright.longer +-rw-r--r-- 1 root root 0 Aug 25 12:03 README.Debian.longer + +(Hey! Why are there four files now??) + +Signed-off-by: Darrick J. Wong +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman + +--- + fs/ext4/namei.c | 21 ++++++++++++++++++--- + 1 file changed, 18 insertions(+), 3 deletions(-) + +--- a/fs/ext4/namei.c ++++ b/fs/ext4/namei.c +@@ -3147,7 +3147,8 @@ static int ext4_find_delete_entry(handle + return retval; + } + +-static void ext4_rename_delete(handle_t *handle, struct ext4_renament *ent) ++static void ext4_rename_delete(handle_t *handle, struct ext4_renament *ent, ++ int force_reread) + { + int retval; + /* +@@ -3159,7 +3160,8 @@ static void ext4_rename_delete(handle_t + if (le32_to_cpu(ent->de->inode) != ent->inode->i_ino || + ent->de->name_len != ent->dentry->d_name.len || + strncmp(ent->de->name, ent->dentry->d_name.name, +- ent->de->name_len)) { ++ ent->de->name_len) || ++ force_reread) { + retval = ext4_find_delete_entry(handle, ent->dir, + &ent->dentry->d_name); + } else { +@@ -3210,6 +3212,7 @@ static int ext4_rename(struct inode *old + .dentry = new_dentry, + .inode = new_dentry->d_inode, + }; ++ int force_reread; + int retval; + + dquot_initialize(old.dir); +@@ -3271,6 +3274,15 @@ static int ext4_rename(struct inode *old + if (retval) + goto end_rename; + } ++ /* ++ * If we're renaming a file within an inline_data dir and adding or ++ * setting the new dirent causes a conversion from inline_data to ++ * extents/blockmap, we need to force the dirent delete code to ++ * re-read the directory, or else we end up trying to delete a dirent ++ * from what is now the extent tree root (or a block map). ++ */ ++ force_reread = (new.dir->i_ino == old.dir->i_ino && ++ ext4_test_inode_flag(new.dir, EXT4_INODE_INLINE_DATA)); + if (!new.bh) { + retval = ext4_add_entry(handle, new.dentry, old.inode); + if (retval) +@@ -3281,6 +3293,9 @@ static int ext4_rename(struct inode *old + if (retval) + goto end_rename; + } ++ if (force_reread) ++ force_reread = !ext4_test_inode_flag(new.dir, ++ EXT4_INODE_INLINE_DATA); + + /* + * Like most other Unix systems, set the ctime for inodes on a +@@ -3292,7 +3307,7 @@ static int ext4_rename(struct inode *old + /* + * ok, that's it + */ +- ext4_rename_delete(handle, &old); ++ ext4_rename_delete(handle, &old, force_reread); + + if (new.inode) { + ext4_dec_count(handle, new.inode); diff --git a/queue-3.16/ext4-fix-transaction-issues-for-ext4_fallocate-and-ext_zero_range.patch b/queue-3.16/ext4-fix-transaction-issues-for-ext4_fallocate-and-ext_zero_range.patch new file mode 100644 index 00000000000..582c274ca75 --- /dev/null +++ b/queue-3.16/ext4-fix-transaction-issues-for-ext4_fallocate-and-ext_zero_range.patch @@ -0,0 +1,189 @@ +From c174e6d6979a04b7b77b93f244396be4b81f8bfb Mon Sep 17 00:00:00 2001 +From: Dmitry Monakhov +Date: Wed, 27 Aug 2014 18:40:00 -0400 +Subject: ext4: fix transaction issues for ext4_fallocate and ext_zero_range + +From: Dmitry Monakhov + +commit c174e6d6979a04b7b77b93f244396be4b81f8bfb upstream. + +After commit f282ac19d86f we use different transactions for +preallocation and i_disksize update which result in complain from fsck +after power-failure. spotted by generic/019. IMHO this is regression +because fs becomes inconsistent, even more 'e2fsck -p' will no longer +works (which drives admins go crazy) Same transaction requirement +applies ctime,mtime updates + +testcase: xfstest generic/019 + +Signed-off-by: Dmitry Monakhov +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman + +--- + fs/ext4/extents.c | 68 +++++++++++++++++++++++++++--------------------------- + 1 file changed, 35 insertions(+), 33 deletions(-) + +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -4664,7 +4664,8 @@ retry: + } + + static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset, +- ext4_lblk_t len, int flags, int mode) ++ ext4_lblk_t len, loff_t new_size, ++ int flags, int mode) + { + struct inode *inode = file_inode(file); + handle_t *handle; +@@ -4673,8 +4674,10 @@ static int ext4_alloc_file_blocks(struct + int retries = 0; + struct ext4_map_blocks map; + unsigned int credits; ++ loff_t epos; + + map.m_lblk = offset; ++ map.m_len = len; + /* + * Don't normalize the request if it can fit in one extent so + * that it doesn't get unnecessarily split into multiple +@@ -4689,9 +4692,7 @@ static int ext4_alloc_file_blocks(struct + credits = ext4_chunk_trans_blocks(inode, len); + + retry: +- while (ret >= 0 && ret < len) { +- map.m_lblk = map.m_lblk + ret; +- map.m_len = len = len - ret; ++ while (ret >= 0 && len) { + handle = ext4_journal_start(inode, EXT4_HT_MAP_BLOCKS, + credits); + if (IS_ERR(handle)) { +@@ -4708,6 +4709,21 @@ retry: + ret2 = ext4_journal_stop(handle); + break; + } ++ map.m_lblk += ret; ++ map.m_len = len = len - ret; ++ epos = (loff_t)map.m_lblk << inode->i_blkbits; ++ inode->i_ctime = ext4_current_time(inode); ++ if (new_size) { ++ if (epos > new_size) ++ epos = new_size; ++ if (ext4_update_inode_size(inode, epos) & 0x1) ++ inode->i_mtime = inode->i_ctime; ++ } else { ++ if (epos > inode->i_size) ++ ext4_set_inode_flag(inode, ++ EXT4_INODE_EOFBLOCKS); ++ } ++ ext4_mark_inode_dirty(handle, inode); + ret2 = ext4_journal_stop(handle); + if (ret2) + break; +@@ -4731,7 +4747,7 @@ static long ext4_zero_range(struct file + int ret = 0; + int flags; + int credits; +- int partial; ++ int partial_begin, partial_end; + loff_t start, end; + ext4_lblk_t lblk; + struct address_space *mapping = inode->i_mapping; +@@ -4771,7 +4787,8 @@ static long ext4_zero_range(struct file + + if (start < offset || end > offset + len) + return -EINVAL; +- partial = (offset + len) & ((1 << blkbits) - 1); ++ partial_begin = offset & ((1 << blkbits) - 1); ++ partial_end = (offset + len) & ((1 << blkbits) - 1); + + lblk = start >> blkbits; + max_blocks = (end >> blkbits); +@@ -4805,7 +4822,7 @@ static long ext4_zero_range(struct file + * If we have a partial block after EOF we have to allocate + * the entire block. + */ +- if (partial) ++ if (partial_end) + max_blocks += 1; + } + +@@ -4813,6 +4830,7 @@ static long ext4_zero_range(struct file + + /* Now release the pages and zero block aligned part of pages*/ + truncate_pagecache_range(inode, start, end - 1); ++ inode->i_mtime = inode->i_ctime = ext4_current_time(inode); + + /* Wait all existing dio workers, newcomers will block on i_mutex */ + ext4_inode_block_unlocked_dio(inode); +@@ -4825,11 +4843,14 @@ static long ext4_zero_range(struct file + if (ret) + goto out_dio; + +- ret = ext4_alloc_file_blocks(file, lblk, max_blocks, flags, +- mode); ++ ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size, ++ flags, mode); + if (ret) + goto out_dio; + } ++ if (!partial_begin && !partial_end) ++ goto out_dio; ++ + /* + * In worst case we have to writeout two nonadjacent unwritten + * blocks and update the inode +@@ -4855,7 +4876,6 @@ static long ext4_zero_range(struct file + if ((offset + len) > i_size_read(inode)) + ext4_set_inode_flag(inode, EXT4_INODE_EOFBLOCKS); + } +- + ext4_mark_inode_dirty(handle, inode); + + /* Zero out partial block at the edges of the range */ +@@ -4882,7 +4902,6 @@ out_mutex: + long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) + { + struct inode *inode = file_inode(file); +- handle_t *handle; + loff_t new_size = 0; + unsigned int max_blocks; + int ret = 0; +@@ -4938,32 +4957,15 @@ long ext4_fallocate(struct file *file, i + goto out; + } + +- ret = ext4_alloc_file_blocks(file, lblk, max_blocks, flags, mode); ++ ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size, ++ flags, mode); + if (ret) + goto out; + +- handle = ext4_journal_start(inode, EXT4_HT_INODE, 2); +- if (IS_ERR(handle)) +- goto out; +- +- inode->i_ctime = ext4_current_time(inode); +- +- if (new_size) { +- if (ext4_update_inode_size(inode, new_size) & 0x1) +- inode->i_mtime = inode->i_ctime; +- } else { +- /* +- * Mark that we allocate beyond EOF so the subsequent truncate +- * can proceed even if the new size is the same as i_size. +- */ +- if ((offset + len) > i_size_read(inode)) +- ext4_set_inode_flag(inode, EXT4_INODE_EOFBLOCKS); ++ if (file->f_flags & O_SYNC && EXT4_SB(inode->i_sb)->s_journal) { ++ ret = jbd2_complete_transaction(EXT4_SB(inode->i_sb)->s_journal, ++ EXT4_I(inode)->i_sync_tid); + } +- ext4_mark_inode_dirty(handle, inode); +- if (file->f_flags & O_SYNC) +- ext4_handle_sync(handle); +- +- ext4_journal_stop(handle); + out: + mutex_unlock(&inode->i_mutex); + trace_ext4_fallocate_exit(inode, offset, max_blocks, ret); diff --git a/queue-3.16/ext4-update-i_disksize-coherently-with-block-allocation-on-error-path.patch b/queue-3.16/ext4-update-i_disksize-coherently-with-block-allocation-on-error-path.patch new file mode 100644 index 00000000000..130bc7430d1 --- /dev/null +++ b/queue-3.16/ext4-update-i_disksize-coherently-with-block-allocation-on-error-path.patch @@ -0,0 +1,66 @@ +From 6603120e96eae9a5d6228681ae55c7fdc998d1bb Mon Sep 17 00:00:00 2001 +From: Dmitry Monakhov +Date: Wed, 27 Aug 2014 18:40:03 -0400 +Subject: ext4: update i_disksize coherently with block allocation on error path + +From: Dmitry Monakhov + +commit 6603120e96eae9a5d6228681ae55c7fdc998d1bb upstream. + +In case of delalloc block i_disksize may be less than i_size. So we +have to update i_disksize each time we allocated and submitted some +blocks beyond i_disksize. We weren't doing this on the error paths, +so fix this. + +testcase: xfstest generic/019 + +Signed-off-by: Dmitry Monakhov +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman + +--- + fs/ext4/inode.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -2194,6 +2194,7 @@ static int mpage_map_and_submit_extent(h + struct ext4_map_blocks *map = &mpd->map; + int err; + loff_t disksize; ++ int progress = 0; + + mpd->io_submit.io_end->offset = + ((loff_t)map->m_lblk) << inode->i_blkbits; +@@ -2210,8 +2211,11 @@ static int mpage_map_and_submit_extent(h + * is non-zero, a commit should free up blocks. + */ + if ((err == -ENOMEM) || +- (err == -ENOSPC && ext4_count_free_clusters(sb))) ++ (err == -ENOSPC && ext4_count_free_clusters(sb))) { ++ if (progress) ++ goto update_disksize; + return err; ++ } + ext4_msg(sb, KERN_CRIT, + "Delayed block allocation failed for " + "inode %lu at logical offset %llu with" +@@ -2228,15 +2232,17 @@ static int mpage_map_and_submit_extent(h + *give_up_on_write = true; + return err; + } ++ progress = 1; + /* + * Update buffer state, submit mapped pages, and get us new + * extent to map + */ + err = mpage_map_and_submit_buffers(mpd); + if (err < 0) +- return err; ++ goto update_disksize; + } while (map->m_len); + ++update_disksize: + /* + * Update on-disk size after IO is submitted. Races with + * truncate are avoided by checking i_size under i_data_sem. diff --git a/queue-3.16/jbd2-fix-descriptor-block-size-handling-errors-with-journal_csum.patch b/queue-3.16/jbd2-fix-descriptor-block-size-handling-errors-with-journal_csum.patch new file mode 100644 index 00000000000..6ab5a4c5675 --- /dev/null +++ b/queue-3.16/jbd2-fix-descriptor-block-size-handling-errors-with-journal_csum.patch @@ -0,0 +1,490 @@ +From db9ee220361de03ee86388f9ea5e529eaad5323c Mon Sep 17 00:00:00 2001 +From: "Darrick J. Wong" +Date: Wed, 27 Aug 2014 18:40:07 -0400 +Subject: jbd2: fix descriptor block size handling errors with journal_csum + +From: "Darrick J. Wong" + +commit db9ee220361de03ee86388f9ea5e529eaad5323c upstream. + +It turns out that there are some serious problems with the on-disk +format of journal checksum v2. The foremost is that the function to +calculate descriptor tag size returns sizes that are too big. This +causes alignment issues on some architectures and is compounded by the +fact that some parts of jbd2 use the structure size (incorrectly) to +determine the presence of a 64bit journal instead of checking the +feature flags. + +Therefore, introduce journal checksum v3, which enlarges the +descriptor block tag format to allow for full 32-bit checksums of +journal blocks, fix the journal tag function to return the correct +sizes, and fix the jbd2 recovery code to use feature flags to +determine 64bitness. + +Add a few function helpers so we don't have to open-code quite so +many pieces. + +Switching to a 16-byte block size was found to increase journal size +overhead by a maximum of 0.1%, to convert a 32-bit journal with no +checksumming to a 32-bit journal with checksum v3 enabled. + +Signed-off-by: Darrick J. Wong +Reported-by: TR Reardon +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman + +--- + fs/ext4/super.c | 5 ++-- + fs/jbd2/commit.c | 21 ++++++++++--------- + fs/jbd2/journal.c | 56 +++++++++++++++++++++++++++++++++------------------ + fs/jbd2/recovery.c | 26 +++++++++++++---------- + fs/jbd2/revoke.c | 6 ++--- + include/linux/jbd2.h | 30 ++++++++++++++++++++++----- + 6 files changed, 95 insertions(+), 49 deletions(-) + +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -3185,9 +3185,9 @@ static int set_journal_csum_feature_set( + + if (EXT4_HAS_RO_COMPAT_FEATURE(sb, + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) { +- /* journal checksum v2 */ ++ /* journal checksum v3 */ + compat = 0; +- incompat = JBD2_FEATURE_INCOMPAT_CSUM_V2; ++ incompat = JBD2_FEATURE_INCOMPAT_CSUM_V3; + } else { + /* journal checksum v1 */ + compat = JBD2_FEATURE_COMPAT_CHECKSUM; +@@ -3209,6 +3209,7 @@ static int set_journal_csum_feature_set( + jbd2_journal_clear_features(sbi->s_journal, + JBD2_FEATURE_COMPAT_CHECKSUM, 0, + JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT | ++ JBD2_FEATURE_INCOMPAT_CSUM_V3 | + JBD2_FEATURE_INCOMPAT_CSUM_V2); + } + +--- a/fs/jbd2/commit.c ++++ b/fs/jbd2/commit.c +@@ -97,7 +97,7 @@ static void jbd2_commit_block_csum_set(j + struct commit_header *h; + __u32 csum; + +- if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) ++ if (!jbd2_journal_has_csum_v2or3(j)) + return; + + h = (struct commit_header *)(bh->b_data); +@@ -313,11 +313,11 @@ static __u32 jbd2_checksum_data(__u32 cr + return checksum; + } + +-static void write_tag_block(int tag_bytes, journal_block_tag_t *tag, ++static void write_tag_block(journal_t *j, journal_block_tag_t *tag, + unsigned long long block) + { + tag->t_blocknr = cpu_to_be32(block & (u32)~0); +- if (tag_bytes > JBD2_TAG_SIZE32) ++ if (JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_64BIT)) + tag->t_blocknr_high = cpu_to_be32((block >> 31) >> 1); + } + +@@ -327,7 +327,7 @@ static void jbd2_descr_block_csum_set(jo + struct jbd2_journal_block_tail *tail; + __u32 csum; + +- if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) ++ if (!jbd2_journal_has_csum_v2or3(j)) + return; + + tail = (struct jbd2_journal_block_tail *)(bh->b_data + j->j_blocksize - +@@ -340,12 +340,13 @@ static void jbd2_descr_block_csum_set(jo + static void jbd2_block_tag_csum_set(journal_t *j, journal_block_tag_t *tag, + struct buffer_head *bh, __u32 sequence) + { ++ journal_block_tag3_t *tag3 = (journal_block_tag3_t *)tag; + struct page *page = bh->b_page; + __u8 *addr; + __u32 csum32; + __be32 seq; + +- if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) ++ if (!jbd2_journal_has_csum_v2or3(j)) + return; + + seq = cpu_to_be32(sequence); +@@ -355,8 +356,10 @@ static void jbd2_block_tag_csum_set(jour + bh->b_size); + kunmap_atomic(addr); + +- /* We only have space to store the lower 16 bits of the crc32c. */ +- tag->t_checksum = cpu_to_be16(csum32); ++ if (JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V3)) ++ tag3->t_checksum = cpu_to_be32(csum32); ++ else ++ tag->t_checksum = cpu_to_be16(csum32); + } + /* + * jbd2_journal_commit_transaction +@@ -396,7 +399,7 @@ void jbd2_journal_commit_transaction(jou + LIST_HEAD(io_bufs); + LIST_HEAD(log_bufs); + +- if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2)) ++ if (jbd2_journal_has_csum_v2or3(journal)) + csum_size = sizeof(struct jbd2_journal_block_tail); + + /* +@@ -690,7 +693,7 @@ void jbd2_journal_commit_transaction(jou + tag_flag |= JBD2_FLAG_SAME_UUID; + + tag = (journal_block_tag_t *) tagp; +- write_tag_block(tag_bytes, tag, jh2bh(jh)->b_blocknr); ++ write_tag_block(journal, tag, jh2bh(jh)->b_blocknr); + tag->t_flags = cpu_to_be16(tag_flag); + jbd2_block_tag_csum_set(journal, tag, wbuf[bufs], + commit_transaction->t_tid); +--- a/fs/jbd2/journal.c ++++ b/fs/jbd2/journal.c +@@ -124,7 +124,7 @@ EXPORT_SYMBOL(__jbd2_debug); + /* Checksumming functions */ + static int jbd2_verify_csum_type(journal_t *j, journal_superblock_t *sb) + { +- if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) ++ if (!jbd2_journal_has_csum_v2or3(j)) + return 1; + + return sb->s_checksum_type == JBD2_CRC32C_CHKSUM; +@@ -145,7 +145,7 @@ static __be32 jbd2_superblock_csum(journ + + static int jbd2_superblock_csum_verify(journal_t *j, journal_superblock_t *sb) + { +- if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) ++ if (!jbd2_journal_has_csum_v2or3(j)) + return 1; + + return sb->s_checksum == jbd2_superblock_csum(j, sb); +@@ -153,7 +153,7 @@ static int jbd2_superblock_csum_verify(j + + static void jbd2_superblock_csum_set(journal_t *j, journal_superblock_t *sb) + { +- if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) ++ if (!jbd2_journal_has_csum_v2or3(j)) + return; + + sb->s_checksum = jbd2_superblock_csum(j, sb); +@@ -1522,21 +1522,29 @@ static int journal_get_superblock(journa + goto out; + } + +- if (JBD2_HAS_COMPAT_FEATURE(journal, JBD2_FEATURE_COMPAT_CHECKSUM) && +- JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2)) { ++ if (jbd2_journal_has_csum_v2or3(journal) && ++ JBD2_HAS_COMPAT_FEATURE(journal, JBD2_FEATURE_COMPAT_CHECKSUM)) { + /* Can't have checksum v1 and v2 on at the same time! */ + printk(KERN_ERR "JBD2: Can't enable checksumming v1 and v2 " + "at the same time!\n"); + goto out; + } + ++ if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2) && ++ JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V3)) { ++ /* Can't have checksum v2 and v3 at the same time! */ ++ printk(KERN_ERR "JBD2: Can't enable checksumming v2 and v3 " ++ "at the same time!\n"); ++ goto out; ++ } ++ + if (!jbd2_verify_csum_type(journal, sb)) { + printk(KERN_ERR "JBD2: Unknown checksum type\n"); + goto out; + } + + /* Load the checksum driver */ +- if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2)) { ++ if (jbd2_journal_has_csum_v2or3(journal)) { + journal->j_chksum_driver = crypto_alloc_shash("crc32c", 0, 0); + if (IS_ERR(journal->j_chksum_driver)) { + printk(KERN_ERR "JBD2: Cannot load crc32c driver.\n"); +@@ -1553,7 +1561,7 @@ static int journal_get_superblock(journa + } + + /* Precompute checksum seed for all metadata */ +- if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2)) ++ if (jbd2_journal_has_csum_v2or3(journal)) + journal->j_csum_seed = jbd2_chksum(journal, ~0, sb->s_uuid, + sizeof(sb->s_uuid)); + +@@ -1813,8 +1821,14 @@ int jbd2_journal_set_features (journal_t + if (!jbd2_journal_check_available_features(journal, compat, ro, incompat)) + return 0; + +- /* Asking for checksumming v2 and v1? Only give them v2. */ +- if (incompat & JBD2_FEATURE_INCOMPAT_CSUM_V2 && ++ /* If enabling v2 checksums, turn on v3 instead */ ++ if (incompat & JBD2_FEATURE_INCOMPAT_CSUM_V2) { ++ incompat &= ~JBD2_FEATURE_INCOMPAT_CSUM_V2; ++ incompat |= JBD2_FEATURE_INCOMPAT_CSUM_V3; ++ } ++ ++ /* Asking for checksumming v3 and v1? Only give them v3. */ ++ if (incompat & JBD2_FEATURE_INCOMPAT_CSUM_V3 && + compat & JBD2_FEATURE_COMPAT_CHECKSUM) + compat &= ~JBD2_FEATURE_COMPAT_CHECKSUM; + +@@ -1823,8 +1837,8 @@ int jbd2_journal_set_features (journal_t + + sb = journal->j_superblock; + +- /* If enabling v2 checksums, update superblock */ +- if (INCOMPAT_FEATURE_ON(JBD2_FEATURE_INCOMPAT_CSUM_V2)) { ++ /* If enabling v3 checksums, update superblock */ ++ if (INCOMPAT_FEATURE_ON(JBD2_FEATURE_INCOMPAT_CSUM_V3)) { + sb->s_checksum_type = JBD2_CRC32C_CHKSUM; + sb->s_feature_compat &= + ~cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM); +@@ -1842,8 +1856,7 @@ int jbd2_journal_set_features (journal_t + } + + /* Precompute checksum seed for all metadata */ +- if (JBD2_HAS_INCOMPAT_FEATURE(journal, +- JBD2_FEATURE_INCOMPAT_CSUM_V2)) ++ if (jbd2_journal_has_csum_v2or3(journal)) + journal->j_csum_seed = jbd2_chksum(journal, ~0, + sb->s_uuid, + sizeof(sb->s_uuid)); +@@ -1852,7 +1865,8 @@ int jbd2_journal_set_features (journal_t + /* If enabling v1 checksums, downgrade superblock */ + if (COMPAT_FEATURE_ON(JBD2_FEATURE_COMPAT_CHECKSUM)) + sb->s_feature_incompat &= +- ~cpu_to_be32(JBD2_FEATURE_INCOMPAT_CSUM_V2); ++ ~cpu_to_be32(JBD2_FEATURE_INCOMPAT_CSUM_V2 | ++ JBD2_FEATURE_INCOMPAT_CSUM_V3); + + sb->s_feature_compat |= cpu_to_be32(compat); + sb->s_feature_ro_compat |= cpu_to_be32(ro); +@@ -2165,16 +2179,20 @@ int jbd2_journal_blocks_per_page(struct + */ + size_t journal_tag_bytes(journal_t *journal) + { +- journal_block_tag_t tag; +- size_t x = 0; ++ size_t sz; ++ ++ if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V3)) ++ return sizeof(journal_block_tag3_t); ++ ++ sz = sizeof(journal_block_tag_t); + + if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2)) +- x += sizeof(tag.t_checksum); ++ sz += sizeof(__u16); + + if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) +- return x + JBD2_TAG_SIZE64; ++ return sz; + else +- return x + JBD2_TAG_SIZE32; ++ return sz - sizeof(__u32); + } + + /* +--- a/fs/jbd2/recovery.c ++++ b/fs/jbd2/recovery.c +@@ -181,7 +181,7 @@ static int jbd2_descr_block_csum_verify( + __be32 provided; + __u32 calculated; + +- if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) ++ if (!jbd2_journal_has_csum_v2or3(j)) + return 1; + + tail = (struct jbd2_journal_block_tail *)(buf + j->j_blocksize - +@@ -205,7 +205,7 @@ static int count_tags(journal_t *journal + int nr = 0, size = journal->j_blocksize; + int tag_bytes = journal_tag_bytes(journal); + +- if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2)) ++ if (jbd2_journal_has_csum_v2or3(journal)) + size -= sizeof(struct jbd2_journal_block_tail); + + tagp = &bh->b_data[sizeof(journal_header_t)]; +@@ -338,10 +338,11 @@ int jbd2_journal_skip_recovery(journal_t + return err; + } + +-static inline unsigned long long read_tag_block(int tag_bytes, journal_block_tag_t *tag) ++static inline unsigned long long read_tag_block(journal_t *journal, ++ journal_block_tag_t *tag) + { + unsigned long long block = be32_to_cpu(tag->t_blocknr); +- if (tag_bytes > JBD2_TAG_SIZE32) ++ if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) + block |= (u64)be32_to_cpu(tag->t_blocknr_high) << 32; + return block; + } +@@ -384,7 +385,7 @@ static int jbd2_commit_block_csum_verify + __be32 provided; + __u32 calculated; + +- if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) ++ if (!jbd2_journal_has_csum_v2or3(j)) + return 1; + + h = buf; +@@ -399,17 +400,21 @@ static int jbd2_commit_block_csum_verify + static int jbd2_block_tag_csum_verify(journal_t *j, journal_block_tag_t *tag, + void *buf, __u32 sequence) + { ++ journal_block_tag3_t *tag3 = (journal_block_tag3_t *)tag; + __u32 csum32; + __be32 seq; + +- if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) ++ if (!jbd2_journal_has_csum_v2or3(j)) + return 1; + + seq = cpu_to_be32(sequence); + csum32 = jbd2_chksum(j, j->j_csum_seed, (__u8 *)&seq, sizeof(seq)); + csum32 = jbd2_chksum(j, csum32, buf, j->j_blocksize); + +- return tag->t_checksum == cpu_to_be16(csum32); ++ if (JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V3)) ++ return tag3->t_checksum == cpu_to_be32(csum32); ++ else ++ return tag->t_checksum == cpu_to_be16(csum32); + } + + static int do_one_pass(journal_t *journal, +@@ -513,8 +518,7 @@ static int do_one_pass(journal_t *journa + switch(blocktype) { + case JBD2_DESCRIPTOR_BLOCK: + /* Verify checksum first */ +- if (JBD2_HAS_INCOMPAT_FEATURE(journal, +- JBD2_FEATURE_INCOMPAT_CSUM_V2)) ++ if (jbd2_journal_has_csum_v2or3(journal)) + descr_csum_size = + sizeof(struct jbd2_journal_block_tail); + if (descr_csum_size > 0 && +@@ -575,7 +579,7 @@ static int do_one_pass(journal_t *journa + unsigned long long blocknr; + + J_ASSERT(obh != NULL); +- blocknr = read_tag_block(tag_bytes, ++ blocknr = read_tag_block(journal, + tag); + + /* If the block has been +@@ -814,7 +818,7 @@ static int jbd2_revoke_block_csum_verify + __be32 provided; + __u32 calculated; + +- if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) ++ if (!jbd2_journal_has_csum_v2or3(j)) + return 1; + + tail = (struct jbd2_journal_revoke_tail *)(buf + j->j_blocksize - +--- a/fs/jbd2/revoke.c ++++ b/fs/jbd2/revoke.c +@@ -91,8 +91,8 @@ + #include + #include + #include +-#endif + #include ++#endif + + static struct kmem_cache *jbd2_revoke_record_cache; + static struct kmem_cache *jbd2_revoke_table_cache; +@@ -597,7 +597,7 @@ static void write_one_revoke_record(jour + offset = *offsetp; + + /* Do we need to leave space at the end for a checksum? */ +- if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2)) ++ if (jbd2_journal_has_csum_v2or3(journal)) + csum_size = sizeof(struct jbd2_journal_revoke_tail); + + /* Make sure we have a descriptor with space left for the record */ +@@ -644,7 +644,7 @@ static void jbd2_revoke_csum_set(journal + struct jbd2_journal_revoke_tail *tail; + __u32 csum; + +- if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) ++ if (!jbd2_journal_has_csum_v2or3(j)) + return; + + tail = (struct jbd2_journal_revoke_tail *)(bh->b_data + j->j_blocksize - +--- a/include/linux/jbd2.h ++++ b/include/linux/jbd2.h +@@ -159,7 +159,11 @@ typedef struct journal_header_s + * journal_block_tag (in the descriptor). The other h_chksum* fields are + * not used. + * +- * Checksum v1 and v2 are mutually exclusive features. ++ * If FEATURE_INCOMPAT_CSUM_V3 is set, the descriptor block uses ++ * journal_block_tag3_t to store a full 32-bit checksum. Everything else ++ * is the same as v2. ++ * ++ * Checksum v1, v2, and v3 are mutually exclusive features. + */ + struct commit_header { + __be32 h_magic; +@@ -179,6 +183,14 @@ struct commit_header { + * raw struct shouldn't be used for pointer math or sizeof() - use + * journal_tag_bytes(journal) instead to compute this. + */ ++typedef struct journal_block_tag3_s ++{ ++ __be32 t_blocknr; /* The on-disk block number */ ++ __be32 t_flags; /* See below */ ++ __be32 t_blocknr_high; /* most-significant high 32bits. */ ++ __be32 t_checksum; /* crc32c(uuid+seq+block) */ ++} journal_block_tag3_t; ++ + typedef struct journal_block_tag_s + { + __be32 t_blocknr; /* The on-disk block number */ +@@ -187,9 +199,6 @@ typedef struct journal_block_tag_s + __be32 t_blocknr_high; /* most-significant high 32bits. */ + } journal_block_tag_t; + +-#define JBD2_TAG_SIZE32 (offsetof(journal_block_tag_t, t_blocknr_high)) +-#define JBD2_TAG_SIZE64 (sizeof(journal_block_tag_t)) +- + /* Tail of descriptor block, for checksumming */ + struct jbd2_journal_block_tail { + __be32 t_checksum; /* crc32c(uuid+descr_block) */ +@@ -284,6 +293,7 @@ typedef struct journal_superblock_s + #define JBD2_FEATURE_INCOMPAT_64BIT 0x00000002 + #define JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT 0x00000004 + #define JBD2_FEATURE_INCOMPAT_CSUM_V2 0x00000008 ++#define JBD2_FEATURE_INCOMPAT_CSUM_V3 0x00000010 + + /* Features known to this kernel version: */ + #define JBD2_KNOWN_COMPAT_FEATURES JBD2_FEATURE_COMPAT_CHECKSUM +@@ -291,7 +301,8 @@ typedef struct journal_superblock_s + #define JBD2_KNOWN_INCOMPAT_FEATURES (JBD2_FEATURE_INCOMPAT_REVOKE | \ + JBD2_FEATURE_INCOMPAT_64BIT | \ + JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT | \ +- JBD2_FEATURE_INCOMPAT_CSUM_V2) ++ JBD2_FEATURE_INCOMPAT_CSUM_V2 | \ ++ JBD2_FEATURE_INCOMPAT_CSUM_V3) + + #ifdef __KERNEL__ + +@@ -1296,6 +1307,15 @@ static inline int tid_geq(tid_t x, tid_t + extern int jbd2_journal_blocks_per_page(struct inode *inode); + extern size_t journal_tag_bytes(journal_t *journal); + ++static inline int jbd2_journal_has_csum_v2or3(journal_t *journal) ++{ ++ if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2) || ++ JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V3)) ++ return 1; ++ ++ return 0; ++} ++ + /* + * We reserve t_outstanding_credits >> JBD2_CONTROL_BLOCKS_SHIFT for + * transaction control blocks. diff --git a/queue-3.16/jbd2-fix-infinite-loop-when-recovering-corrupt-journal-blocks.patch b/queue-3.16/jbd2-fix-infinite-loop-when-recovering-corrupt-journal-blocks.patch new file mode 100644 index 00000000000..75b3b188bcb --- /dev/null +++ b/queue-3.16/jbd2-fix-infinite-loop-when-recovering-corrupt-journal-blocks.patch @@ -0,0 +1,52 @@ +From 022eaa7517017efe4f6538750c2b59a804dc7df7 Mon Sep 17 00:00:00 2001 +From: "Darrick J. Wong" +Date: Wed, 27 Aug 2014 18:40:05 -0400 +Subject: jbd2: fix infinite loop when recovering corrupt journal blocks + +From: "Darrick J. Wong" + +commit 022eaa7517017efe4f6538750c2b59a804dc7df7 upstream. + +When recovering the journal, don't fall into an infinite loop if we +encounter a corrupt journal block. Instead, just skip the block and +return an error, which fails the mount and thus forces the user to run +a full filesystem fsck. + +Signed-off-by: Darrick J. Wong +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman + +--- + fs/jbd2/recovery.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/fs/jbd2/recovery.c ++++ b/fs/jbd2/recovery.c +@@ -426,6 +426,7 @@ static int do_one_pass(journal_t *journa + int tag_bytes = journal_tag_bytes(journal); + __u32 crc32_sum = ~0; /* Transactional Checksums */ + int descr_csum_size = 0; ++ int block_error = 0; + + /* + * First thing is to establish what we expect to find in the log +@@ -598,7 +599,8 @@ static int do_one_pass(journal_t *journa + "checksum recovering " + "block %llu in log\n", + blocknr); +- continue; ++ block_error = 1; ++ goto skip_write; + } + + /* Find a buffer for the new +@@ -797,7 +799,8 @@ static int do_one_pass(journal_t *journa + success = -EIO; + } + } +- ++ if (block_error && success == 0) ++ success = -EIO; + return success; + + failed: diff --git a/queue-3.16/nfs-fix-proc-fs-nfsfs-servers-and-proc-fs-nfsfs-volumes.patch b/queue-3.16/nfs-fix-proc-fs-nfsfs-servers-and-proc-fs-nfsfs-volumes.patch new file mode 100644 index 00000000000..56dc4afa3a2 --- /dev/null +++ b/queue-3.16/nfs-fix-proc-fs-nfsfs-servers-and-proc-fs-nfsfs-volumes.patch @@ -0,0 +1,282 @@ +From 65b38851a17472d31fec9019fc3a55b0802dab88 Mon Sep 17 00:00:00 2001 +From: "Eric W. Biederman" +Date: Thu, 31 Jul 2014 04:35:20 -0700 +Subject: NFS: Fix /proc/fs/nfsfs/servers and /proc/fs/nfsfs/volumes + +From: "Eric W. Biederman" + +commit 65b38851a17472d31fec9019fc3a55b0802dab88 upstream. + +The usage of pid_ns->child_reaper->nsproxy->net_ns in +nfs_server_list_open and nfs_client_list_open is not safe. + +/proc for a pid namespace can remain mounted after the all of the +process in that pid namespace have exited. There are also times +before the initial process in a pid namespace has started or after the +initial process in a pid namespace has exited where +pid_ns->child_reaper can be NULL or stale. Making the idiom +pid_ns->child_reaper->nsproxy a double whammy of problems. + +Luckily all that needs to happen is to move /proc/fs/nfsfs/servers and +/proc/fs/nfsfs/volumes under /proc/net to /proc/net/nfsfs/servers and +/proc/net/nfsfs/volumes and add a symlink from the original location, +and to use seq_open_net as it has been designed. + +Cc: Trond Myklebust +Cc: Stanislav Kinsbursky +Signed-off-by: "Eric W. Biederman" +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfs/client.c | 95 +++++++++++++++++++++++++++++++----------------------- + fs/nfs/inode.c | 3 + + fs/nfs/internal.h | 9 +++++ + fs/nfs/netns.h | 3 + + 4 files changed, 69 insertions(+), 41 deletions(-) + +--- a/fs/nfs/client.c ++++ b/fs/nfs/client.c +@@ -1205,7 +1205,7 @@ static const struct file_operations nfs_ + .open = nfs_server_list_open, + .read = seq_read, + .llseek = seq_lseek, +- .release = seq_release, ++ .release = seq_release_net, + .owner = THIS_MODULE, + }; + +@@ -1226,7 +1226,7 @@ static const struct file_operations nfs_ + .open = nfs_volume_list_open, + .read = seq_read, + .llseek = seq_lseek, +- .release = seq_release, ++ .release = seq_release_net, + .owner = THIS_MODULE, + }; + +@@ -1236,19 +1236,8 @@ static const struct file_operations nfs_ + */ + static int nfs_server_list_open(struct inode *inode, struct file *file) + { +- struct seq_file *m; +- int ret; +- struct pid_namespace *pid_ns = file->f_dentry->d_sb->s_fs_info; +- struct net *net = pid_ns->child_reaper->nsproxy->net_ns; +- +- ret = seq_open(file, &nfs_server_list_ops); +- if (ret < 0) +- return ret; +- +- m = file->private_data; +- m->private = net; +- +- return 0; ++ return seq_open_net(inode, file, &nfs_server_list_ops, ++ sizeof(struct seq_net_private)); + } + + /* +@@ -1256,7 +1245,7 @@ static int nfs_server_list_open(struct i + */ + static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos) + { +- struct nfs_net *nn = net_generic(m->private, nfs_net_id); ++ struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id); + + /* lock the list against modification */ + spin_lock(&nn->nfs_client_lock); +@@ -1268,7 +1257,7 @@ static void *nfs_server_list_start(struc + */ + static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos) + { +- struct nfs_net *nn = net_generic(p->private, nfs_net_id); ++ struct nfs_net *nn = net_generic(seq_file_net(p), nfs_net_id); + + return seq_list_next(v, &nn->nfs_client_list, pos); + } +@@ -1278,7 +1267,7 @@ static void *nfs_server_list_next(struct + */ + static void nfs_server_list_stop(struct seq_file *p, void *v) + { +- struct nfs_net *nn = net_generic(p->private, nfs_net_id); ++ struct nfs_net *nn = net_generic(seq_file_net(p), nfs_net_id); + + spin_unlock(&nn->nfs_client_lock); + } +@@ -1289,7 +1278,7 @@ static void nfs_server_list_stop(struct + static int nfs_server_list_show(struct seq_file *m, void *v) + { + struct nfs_client *clp; +- struct nfs_net *nn = net_generic(m->private, nfs_net_id); ++ struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id); + + /* display header on line 1 */ + if (v == &nn->nfs_client_list) { +@@ -1321,19 +1310,8 @@ static int nfs_server_list_show(struct s + */ + static int nfs_volume_list_open(struct inode *inode, struct file *file) + { +- struct seq_file *m; +- int ret; +- struct pid_namespace *pid_ns = file->f_dentry->d_sb->s_fs_info; +- struct net *net = pid_ns->child_reaper->nsproxy->net_ns; +- +- ret = seq_open(file, &nfs_volume_list_ops); +- if (ret < 0) +- return ret; +- +- m = file->private_data; +- m->private = net; +- +- return 0; ++ return seq_open_net(inode, file, &nfs_server_list_ops, ++ sizeof(struct seq_net_private)); + } + + /* +@@ -1341,7 +1319,7 @@ static int nfs_volume_list_open(struct i + */ + static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos) + { +- struct nfs_net *nn = net_generic(m->private, nfs_net_id); ++ struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id); + + /* lock the list against modification */ + spin_lock(&nn->nfs_client_lock); +@@ -1353,7 +1331,7 @@ static void *nfs_volume_list_start(struc + */ + static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos) + { +- struct nfs_net *nn = net_generic(p->private, nfs_net_id); ++ struct nfs_net *nn = net_generic(seq_file_net(p), nfs_net_id); + + return seq_list_next(v, &nn->nfs_volume_list, pos); + } +@@ -1363,7 +1341,7 @@ static void *nfs_volume_list_next(struct + */ + static void nfs_volume_list_stop(struct seq_file *p, void *v) + { +- struct nfs_net *nn = net_generic(p->private, nfs_net_id); ++ struct nfs_net *nn = net_generic(seq_file_net(p), nfs_net_id); + + spin_unlock(&nn->nfs_client_lock); + } +@@ -1376,7 +1354,7 @@ static int nfs_volume_list_show(struct s + struct nfs_server *server; + struct nfs_client *clp; + char dev[8], fsid[17]; +- struct nfs_net *nn = net_generic(m->private, nfs_net_id); ++ struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id); + + /* display header on line 1 */ + if (v == &nn->nfs_volume_list) { +@@ -1407,6 +1385,45 @@ static int nfs_volume_list_show(struct s + return 0; + } + ++int nfs_fs_proc_net_init(struct net *net) ++{ ++ struct nfs_net *nn = net_generic(net, nfs_net_id); ++ struct proc_dir_entry *p; ++ ++ nn->proc_nfsfs = proc_net_mkdir(net, "nfsfs", net->proc_net); ++ if (!nn->proc_nfsfs) ++ goto error_0; ++ ++ /* a file of servers with which we're dealing */ ++ p = proc_create("servers", S_IFREG|S_IRUGO, ++ nn->proc_nfsfs, &nfs_server_list_fops); ++ if (!p) ++ goto error_1; ++ ++ /* a file of volumes that we have mounted */ ++ p = proc_create("volumes", S_IFREG|S_IRUGO, ++ nn->proc_nfsfs, &nfs_volume_list_fops); ++ if (!p) ++ goto error_2; ++ return 0; ++ ++error_2: ++ remove_proc_entry("servers", nn->proc_nfsfs); ++error_1: ++ remove_proc_entry("fs/nfsfs", NULL); ++error_0: ++ return -ENOMEM; ++} ++ ++void nfs_fs_proc_net_exit(struct net *net) ++{ ++ struct nfs_net *nn = net_generic(net, nfs_net_id); ++ ++ remove_proc_entry("volumes", nn->proc_nfsfs); ++ remove_proc_entry("servers", nn->proc_nfsfs); ++ remove_proc_entry("fs/nfsfs", NULL); ++} ++ + /* + * initialise the /proc/fs/nfsfs/ directory + */ +@@ -1419,14 +1436,12 @@ int __init nfs_fs_proc_init(void) + goto error_0; + + /* a file of servers with which we're dealing */ +- p = proc_create("servers", S_IFREG|S_IRUGO, +- proc_fs_nfs, &nfs_server_list_fops); ++ p = proc_symlink("servers", proc_fs_nfs, "../../net/nfsfs/servers"); + if (!p) + goto error_1; + + /* a file of volumes that we have mounted */ +- p = proc_create("volumes", S_IFREG|S_IRUGO, +- proc_fs_nfs, &nfs_volume_list_fops); ++ p = proc_symlink("volumes", proc_fs_nfs, "../../net/nfsfs/volumes"); + if (!p) + goto error_2; + return 0; +--- a/fs/nfs/inode.c ++++ b/fs/nfs/inode.c +@@ -1840,11 +1840,12 @@ EXPORT_SYMBOL_GPL(nfs_net_id); + static int nfs_net_init(struct net *net) + { + nfs_clients_init(net); +- return 0; ++ return nfs_fs_proc_net_init(net); + } + + static void nfs_net_exit(struct net *net) + { ++ nfs_fs_proc_net_exit(net); + nfs_cleanup_cb_ident_idr(net); + } + +--- a/fs/nfs/internal.h ++++ b/fs/nfs/internal.h +@@ -195,7 +195,16 @@ extern struct rpc_clnt *nfs4_find_or_cre + #ifdef CONFIG_PROC_FS + extern int __init nfs_fs_proc_init(void); + extern void nfs_fs_proc_exit(void); ++extern int nfs_fs_proc_net_init(struct net *net); ++extern void nfs_fs_proc_net_exit(struct net *net); + #else ++static inline int nfs_fs_proc_net_init(struct net *net) ++{ ++ return 0; ++} ++static inline void nfs_fs_proc_net_exit(struct net *net) ++{ ++} + static inline int nfs_fs_proc_init(void) + { + return 0; +--- a/fs/nfs/netns.h ++++ b/fs/nfs/netns.h +@@ -29,6 +29,9 @@ struct nfs_net { + #endif + spinlock_t nfs_client_lock; + struct timespec boot_time; ++#ifdef CONFIG_PROC_FS ++ struct proc_dir_entry *proc_nfsfs; ++#endif + }; + + extern int nfs_net_id; diff --git a/queue-3.16/nfs-reject-changes-to-resvport-and-sharecache-during-remount.patch b/queue-3.16/nfs-reject-changes-to-resvport-and-sharecache-during-remount.patch new file mode 100644 index 00000000000..c2433e54dd8 --- /dev/null +++ b/queue-3.16/nfs-reject-changes-to-resvport-and-sharecache-during-remount.patch @@ -0,0 +1,53 @@ +From 71a6ec8ac587418ceb6b420def1ca44b334c1ff7 Mon Sep 17 00:00:00 2001 +From: Scott Mayhew +Date: Mon, 4 Aug 2014 17:37:27 -0400 +Subject: nfs: reject changes to resvport and sharecache during remount + +From: Scott Mayhew + +commit 71a6ec8ac587418ceb6b420def1ca44b334c1ff7 upstream. + +Commit c8e47028 made it possible to change resvport/noresvport and +sharecache/nosharecache via a remount operation, neither of which should be +allowed. + +Signed-off-by: Scott Mayhew +Fixes: c8e47028 (nfs: Apply NFS_MOUNT_CMP_FLAGMASK to nfs_compare_remount_data) +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfs/super.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +--- a/fs/nfs/super.c ++++ b/fs/nfs/super.c +@@ -2180,7 +2180,7 @@ out_no_address: + return -EINVAL; + } + +-#define NFS_MOUNT_CMP_FLAGMASK ~(NFS_MOUNT_INTR \ ++#define NFS_REMOUNT_CMP_FLAGMASK ~(NFS_MOUNT_INTR \ + | NFS_MOUNT_SECURE \ + | NFS_MOUNT_TCP \ + | NFS_MOUNT_VER3 \ +@@ -2188,15 +2188,16 @@ out_no_address: + | NFS_MOUNT_NONLM \ + | NFS_MOUNT_BROKEN_SUID \ + | NFS_MOUNT_STRICTLOCK \ +- | NFS_MOUNT_UNSHARED \ +- | NFS_MOUNT_NORESVPORT \ + | NFS_MOUNT_LEGACY_INTERFACE) + ++#define NFS_MOUNT_CMP_FLAGMASK (NFS_REMOUNT_CMP_FLAGMASK & \ ++ ~(NFS_MOUNT_UNSHARED | NFS_MOUNT_NORESVPORT)) ++ + static int + nfs_compare_remount_data(struct nfs_server *nfss, + struct nfs_parsed_mount_data *data) + { +- if ((data->flags ^ nfss->flags) & NFS_MOUNT_CMP_FLAGMASK || ++ if ((data->flags ^ nfss->flags) & NFS_REMOUNT_CMP_FLAGMASK || + data->rsize != nfss->rsize || + data->wsize != nfss->wsize || + data->version != nfss->nfs_client->rpc_ops->version || diff --git a/queue-3.16/nfs3_list_one_acl-check-get_acl-result-with-is_err_or_null.patch b/queue-3.16/nfs3_list_one_acl-check-get_acl-result-with-is_err_or_null.patch new file mode 100644 index 00000000000..9242ed6dda0 --- /dev/null +++ b/queue-3.16/nfs3_list_one_acl-check-get_acl-result-with-is_err_or_null.patch @@ -0,0 +1,37 @@ +From 7a9e75a185e6b3a3860e6a26fb6e88691fc2c9d9 Mon Sep 17 00:00:00 2001 +From: Andrey Utkin +Date: Sat, 26 Jul 2014 14:58:01 +0300 +Subject: nfs3_list_one_acl(): check get_acl() result with IS_ERR_OR_NULL + +From: Andrey Utkin + +commit 7a9e75a185e6b3a3860e6a26fb6e88691fc2c9d9 upstream. + +There was a check for result being not NULL. But get_acl() may return +NULL, or ERR_PTR, or actual pointer. +The purpose of the function where current change is done is to "list +ACLs only when they are available", so any error condition of get_acl() +mustn't be elevated, and returning 0 there is still valid. + +Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=81111 +Signed-off-by: Andrey Utkin +Reviewed-by: Christoph Hellwig +Fixes: 74adf83f5d77 (nfs: only show Posix ACLs in listxattr if actually...) +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfs/nfs3acl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/nfs/nfs3acl.c ++++ b/fs/nfs/nfs3acl.c +@@ -256,7 +256,7 @@ nfs3_list_one_acl(struct inode *inode, i + char *p = data + *result; + + acl = get_acl(inode, type); +- if (!acl) ++ if (IS_ERR_OR_NULL(acl)) + return 0; + + posix_acl_release(acl); diff --git a/queue-3.16/nfsd-decrease-nfsd_users-in-nfsd_startup_generic-fail.patch b/queue-3.16/nfsd-decrease-nfsd_users-in-nfsd_startup_generic-fail.patch new file mode 100644 index 00000000000..8585cabf412 --- /dev/null +++ b/queue-3.16/nfsd-decrease-nfsd_users-in-nfsd_startup_generic-fail.patch @@ -0,0 +1,46 @@ +From d9499a95716db0d4bc9b67e88fd162133e7d6b08 Mon Sep 17 00:00:00 2001 +From: Kinglong Mee +Date: Wed, 30 Jul 2014 21:26:05 +0800 +Subject: NFSD: Decrease nfsd_users in nfsd_startup_generic fail + +From: Kinglong Mee + +commit d9499a95716db0d4bc9b67e88fd162133e7d6b08 upstream. + +A memory allocation failure could cause nfsd_startup_generic to fail, in +which case nfsd_users wouldn't be incorrectly left elevated. + +After nfsd restarts nfsd_startup_generic will then succeed without doing +anything--the first consequence is likely nfs4_start_net finding a bad +laundry_wq and crashing. + +Signed-off-by: Kinglong Mee +Fixes: 4539f14981ce "nfsd: replace boolean nfsd_up flag by users counter" +Signed-off-by: J. Bruce Fields +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfsd/nfssvc.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -221,7 +221,8 @@ static int nfsd_startup_generic(int nrse + */ + ret = nfsd_racache_init(2*nrservs); + if (ret) +- return ret; ++ goto dec_users; ++ + ret = nfs4_state_start(); + if (ret) + goto out_racache; +@@ -229,6 +230,8 @@ static int nfsd_startup_generic(int nrse + + out_racache: + nfsd_racache_shutdown(); ++dec_users: ++ nfsd_users--; + return ret; + } + diff --git a/queue-3.16/nfsv3-fix-another-acl-regression.patch b/queue-3.16/nfsv3-fix-another-acl-regression.patch new file mode 100644 index 00000000000..a297c63db1a --- /dev/null +++ b/queue-3.16/nfsv3-fix-another-acl-regression.patch @@ -0,0 +1,37 @@ +From f87d928f6d98644d39809a013a22f981d39017cf Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Sun, 24 Aug 2014 14:46:48 -0400 +Subject: NFSv3: Fix another acl regression + +From: Trond Myklebust + +commit f87d928f6d98644d39809a013a22f981d39017cf upstream. + +When creating a new object on the NFS server, we should not be sending +posix setacl requests unless the preceding posix_acl_create returned a +non-trivial acl. Doing so, causes Solaris servers in particular to +return an EINVAL. + +Fixes: 013cdf1088d72 (nfs: use generic posix ACL infrastructure,,,) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1132786 +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfs/nfs3acl.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/fs/nfs/nfs3acl.c ++++ b/fs/nfs/nfs3acl.c +@@ -129,7 +129,10 @@ static int __nfs3_proc_setacls(struct in + .rpc_argp = &args, + .rpc_resp = &fattr, + }; +- int status; ++ int status = 0; ++ ++ if (acl == NULL && (!S_ISDIR(inode->i_mode) || dfacl == NULL)) ++ goto out; + + status = -EOPNOTSUPP; + if (!nfs_server_capable(inode, NFS_CAP_ACLS)) diff --git a/queue-3.16/nfsv4-don-t-clear-the-open-state-when-we-just-did-an-open_downgrade.patch b/queue-3.16/nfsv4-don-t-clear-the-open-state-when-we-just-did-an-open_downgrade.patch new file mode 100644 index 00000000000..c15776d2e1e --- /dev/null +++ b/queue-3.16/nfsv4-don-t-clear-the-open-state-when-we-just-did-an-open_downgrade.patch @@ -0,0 +1,57 @@ +From 412f6c4c26fb1eba8844290663837561ac53fa6e Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Mon, 25 Aug 2014 22:09:08 -0400 +Subject: NFSv4: Don't clear the open state when we just did an OPEN_DOWNGRADE + +From: Trond Myklebust + +commit 412f6c4c26fb1eba8844290663837561ac53fa6e upstream. + +If we did an OPEN_DOWNGRADE, then the right thing to do on success, is +to apply the new open mode to the struct nfs4_state. Instead, we were +unconditionally clearing the state, making it appear to our state +machinery as if we had just performed a CLOSE. + +Fixes: 226056c5c312b (NFSv4: Use correct locking when updating nfs4_state...) +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfs/nfs4proc.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +--- a/fs/nfs/nfs4proc.c ++++ b/fs/nfs/nfs4proc.c +@@ -2545,6 +2545,7 @@ static void nfs4_close_done(struct rpc_t + struct nfs4_closedata *calldata = data; + struct nfs4_state *state = calldata->state; + struct nfs_server *server = NFS_SERVER(calldata->inode); ++ nfs4_stateid *res_stateid = NULL; + + dprintk("%s: begin!\n", __func__); + if (!nfs4_sequence_done(task, &calldata->res.seq_res)) +@@ -2555,12 +2556,12 @@ static void nfs4_close_done(struct rpc_t + */ + switch (task->tk_status) { + case 0: +- if (calldata->roc) ++ res_stateid = &calldata->res.stateid; ++ if (calldata->arg.fmode == 0 && calldata->roc) + pnfs_roc_set_barrier(state->inode, + calldata->roc_barrier); +- nfs_clear_open_stateid(state, &calldata->res.stateid, 0); + renew_lease(server, calldata->timestamp); +- goto out_release; ++ break; + case -NFS4ERR_ADMIN_REVOKED: + case -NFS4ERR_STALE_STATEID: + case -NFS4ERR_OLD_STATEID: +@@ -2574,7 +2575,7 @@ static void nfs4_close_done(struct rpc_t + goto out_release; + } + } +- nfs_clear_open_stateid(state, NULL, calldata->arg.fmode); ++ nfs_clear_open_stateid(state, res_stateid, calldata->arg.fmode); + out_release: + nfs_release_seqid(calldata->arg.seqid); + nfs_refresh_inode(calldata->inode, calldata->res.fattr); diff --git a/queue-3.16/nfsv4-fix-problems-with-close-in-the-presence-of-a-delegation.patch b/queue-3.16/nfsv4-fix-problems-with-close-in-the-presence-of-a-delegation.patch new file mode 100644 index 00000000000..45adc00fa81 --- /dev/null +++ b/queue-3.16/nfsv4-fix-problems-with-close-in-the-presence-of-a-delegation.patch @@ -0,0 +1,63 @@ +From aee7af356e151494d5014f57b33460b162f181b5 Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Mon, 25 Aug 2014 22:33:12 -0400 +Subject: NFSv4: Fix problems with close in the presence of a delegation + +From: Trond Myklebust + +commit aee7af356e151494d5014f57b33460b162f181b5 upstream. + +In the presence of delegations, we can no longer assume that the +state->n_rdwr, state->n_rdonly, state->n_wronly reflect the open +stateid share mode, and so we need to calculate the initial value +for calldata->arg.fmode using the state->flags. + +Reported-by: James Drews +Fixes: 88069f77e1ac5 (NFSv41: Fix a potential state leakage when...) +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfs/nfs4proc.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +--- a/fs/nfs/nfs4proc.c ++++ b/fs/nfs/nfs4proc.c +@@ -2587,6 +2587,7 @@ static void nfs4_close_prepare(struct rp + struct nfs4_closedata *calldata = data; + struct nfs4_state *state = calldata->state; + struct inode *inode = calldata->inode; ++ bool is_rdonly, is_wronly, is_rdwr; + int call_close = 0; + + dprintk("%s: begin!\n", __func__); +@@ -2594,18 +2595,24 @@ static void nfs4_close_prepare(struct rp + goto out_wait; + + task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; +- calldata->arg.fmode = FMODE_READ|FMODE_WRITE; + spin_lock(&state->owner->so_lock); ++ is_rdwr = test_bit(NFS_O_RDWR_STATE, &state->flags); ++ is_rdonly = test_bit(NFS_O_RDONLY_STATE, &state->flags); ++ is_wronly = test_bit(NFS_O_WRONLY_STATE, &state->flags); ++ /* Calculate the current open share mode */ ++ calldata->arg.fmode = 0; ++ if (is_rdonly || is_rdwr) ++ calldata->arg.fmode |= FMODE_READ; ++ if (is_wronly || is_rdwr) ++ calldata->arg.fmode |= FMODE_WRITE; + /* Calculate the change in open mode */ + if (state->n_rdwr == 0) { + if (state->n_rdonly == 0) { +- call_close |= test_bit(NFS_O_RDONLY_STATE, &state->flags); +- call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags); ++ call_close |= is_rdonly || is_rdwr; + calldata->arg.fmode &= ~FMODE_READ; + } + if (state->n_wronly == 0) { +- call_close |= test_bit(NFS_O_WRONLY_STATE, &state->flags); +- call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags); ++ call_close |= is_wronly || is_rdwr; + calldata->arg.fmode &= ~FMODE_WRITE; + } + } diff --git a/queue-3.16/series b/queue-3.16/series index 7397288a183..0744dc8afbe 100644 --- a/queue-3.16/series +++ b/queue-3.16/series @@ -94,3 +94,33 @@ mei-reset-client-state-on-queued-connect-request.patch mei-nfc-fix-memory-leak-in-error-path.patch ext4-propagate-errors-up-to-ext4_find_entry-s-callers.patch ext4-move-i_size-i_disksize-update-routines-to-helper-function.patch +ext4-fix-incorect-journal-credits-reservation-in-ext4_zero_range.patch +ext4-fix-transaction-issues-for-ext4_fallocate-and-ext_zero_range.patch +ext4-update-i_disksize-coherently-with-block-allocation-on-error-path.patch +ext4-fix-same-dir-rename-when-inline-data-directory-overflows.patch +jbd2-fix-infinite-loop-when-recovering-corrupt-journal-blocks.patch +jbd2-fix-descriptor-block-size-handling-errors-with-journal_csum.patch +staging-lustre-remove-circular-dependency-on-header.patch +staging-et131x-fix-errors-caused-by-phydev-addr-accesses-before-initialisation.patch +staging-rtl8188eu-add-0df6-0076-sitecom-europe-b.v.patch +staging-r8188eu-add-new-usb-id.patch +xhci-treat-not-finding-the-event_seg-on-comp_stop-the-same-as-comp_stop_inval.patch +usb-xhci-amd-chipset-also-needs-short-tx-quirk.patch +xhci-rework-cycle-bit-checking-for-new-dequeue-pointers.patch +xhci-disable-streams-on-via-xhci-with-device-id-0x3432.patch +arm-omap2-hwmod-rearm-wake-up-interrupts-for-dt-when-musb-is-idled.patch +usb-ftdi_sio-add-basic-micro-atom-nano-usb2serial-pid.patch +usb-ftdi_sio-added-pid-for-new-ekey-device.patch +usb-whiteheat-added-bounds-checking-for-bulk-command-response.patch +usb-ehci-using-windex-1-for-hub-port.patch +usb-hub-prevent-hub-autosuspend-if-usbcore.autosuspend-is-1.patch +usbcore-fix-wrong-device-in-an-error-message-in-hub_port_connect.patch +nfsd-decrease-nfsd_users-in-nfsd_startup_generic-fail.patch +nfs-fix-proc-fs-nfsfs-servers-and-proc-fs-nfsfs-volumes.patch +nfs3_list_one_acl-check-get_acl-result-with-is_err_or_null.patch +nfs-reject-changes-to-resvport-and-sharecache-during-remount.patch +svcrdma-select-nfsv4.1-backchannel-transport-based-on-forward-channel.patch +nfsv3-fix-another-acl-regression.patch +nfsv4-don-t-clear-the-open-state-when-we-just-did-an-open_downgrade.patch +nfsv4-fix-problems-with-close-in-the-presence-of-a-delegation.patch +vm_is_stack-use-for_each_thread-rather-then-buggy-while_each_thread.patch diff --git a/queue-3.16/staging-et131x-fix-errors-caused-by-phydev-addr-accesses-before-initialisation.patch b/queue-3.16/staging-et131x-fix-errors-caused-by-phydev-addr-accesses-before-initialisation.patch new file mode 100644 index 00000000000..743ab8eda20 --- /dev/null +++ b/queue-3.16/staging-et131x-fix-errors-caused-by-phydev-addr-accesses-before-initialisation.patch @@ -0,0 +1,189 @@ +From ec0a38bf8b28b036202070cf3ef271e343d9eafc Mon Sep 17 00:00:00 2001 +From: Mark Einon +Date: Sun, 10 Aug 2014 22:16:55 +0100 +Subject: staging: et131x: Fix errors caused by phydev->addr accesses before initialisation + +From: Mark Einon + +commit ec0a38bf8b28b036202070cf3ef271e343d9eafc upstream. + +Fix two reported bugs, caused by et131x_adapter->phydev->addr being accessed +before it is initialised, by: + +- letting et131x_mii_write() take a phydev address, instead of using the one + stored in adapter by default. This is so et131x_mdio_write() can use it's own + addr value. +- removing implementation of et131x_mdio_reset(), as it's not needed. +- moving a call to et131x_disable_phy_coma() in et131x_pci_setup(), which uses + phydev->addr, until after the mdiobus has been registered. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=80751 +Link: https://bugzilla.kernel.org/show_bug.cgi?id=77121 +Signed-off-by: Mark Einon +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/et131x/et131x.c | 68 +++++++++++++++------------------------- + 1 file changed, 27 insertions(+), 41 deletions(-) + +--- a/drivers/staging/et131x/et131x.c ++++ b/drivers/staging/et131x/et131x.c +@@ -1423,22 +1423,16 @@ static int et131x_mii_read(struct et131x + * @reg: the register to read + * @value: 16-bit value to write + */ +-static int et131x_mii_write(struct et131x_adapter *adapter, u8 reg, u16 value) ++static int et131x_mii_write(struct et131x_adapter *adapter, u8 addr, u8 reg, ++ u16 value) + { + struct mac_regs __iomem *mac = &adapter->regs->mac; +- struct phy_device *phydev = adapter->phydev; + int status = 0; +- u8 addr; + u32 delay = 0; + u32 mii_addr; + u32 mii_cmd; + u32 mii_indicator; + +- if (!phydev) +- return -EIO; +- +- addr = phydev->addr; +- + /* Save a local copy of the registers we are dealing with so we can + * set them back + */ +@@ -1633,17 +1627,7 @@ static int et131x_mdio_write(struct mii_ + struct net_device *netdev = bus->priv; + struct et131x_adapter *adapter = netdev_priv(netdev); + +- return et131x_mii_write(adapter, reg, value); +-} +- +-static int et131x_mdio_reset(struct mii_bus *bus) +-{ +- struct net_device *netdev = bus->priv; +- struct et131x_adapter *adapter = netdev_priv(netdev); +- +- et131x_mii_write(adapter, MII_BMCR, BMCR_RESET); +- +- return 0; ++ return et131x_mii_write(adapter, phy_addr, reg, value); + } + + /* et1310_phy_power_switch - PHY power control +@@ -1658,18 +1642,20 @@ static int et131x_mdio_reset(struct mii_ + static void et1310_phy_power_switch(struct et131x_adapter *adapter, bool down) + { + u16 data; ++ struct phy_device *phydev = adapter->phydev; + + et131x_mii_read(adapter, MII_BMCR, &data); + data &= ~BMCR_PDOWN; + if (down) + data |= BMCR_PDOWN; +- et131x_mii_write(adapter, MII_BMCR, data); ++ et131x_mii_write(adapter, phydev->addr, MII_BMCR, data); + } + + /* et131x_xcvr_init - Init the phy if we are setting it into force mode */ + static void et131x_xcvr_init(struct et131x_adapter *adapter) + { + u16 lcr2; ++ struct phy_device *phydev = adapter->phydev; + + /* Set the LED behavior such that LED 1 indicates speed (off = + * 10Mbits, blink = 100Mbits, on = 1000Mbits) and LED 2 indicates +@@ -1690,7 +1676,7 @@ static void et131x_xcvr_init(struct et13 + else + lcr2 |= (LED_VAL_LINKON << LED_TXRX_SHIFT); + +- et131x_mii_write(adapter, PHY_LED_2, lcr2); ++ et131x_mii_write(adapter, phydev->addr, PHY_LED_2, lcr2); + } + } + +@@ -3645,14 +3631,14 @@ static void et131x_adjust_link(struct ne + + et131x_mii_read(adapter, PHY_MPHY_CONTROL_REG, + ®ister18); +- et131x_mii_write(adapter, PHY_MPHY_CONTROL_REG, +- register18 | 0x4); +- et131x_mii_write(adapter, PHY_INDEX_REG, ++ et131x_mii_write(adapter, phydev->addr, ++ PHY_MPHY_CONTROL_REG, register18 | 0x4); ++ et131x_mii_write(adapter, phydev->addr, PHY_INDEX_REG, + register18 | 0x8402); +- et131x_mii_write(adapter, PHY_DATA_REG, ++ et131x_mii_write(adapter, phydev->addr, PHY_DATA_REG, + register18 | 511); +- et131x_mii_write(adapter, PHY_MPHY_CONTROL_REG, +- register18); ++ et131x_mii_write(adapter, phydev->addr, ++ PHY_MPHY_CONTROL_REG, register18); + } + + et1310_config_flow_control(adapter); +@@ -3664,7 +3650,8 @@ static void et131x_adjust_link(struct ne + et131x_mii_read(adapter, PHY_CONFIG, ®); + reg &= ~ET_PHY_CONFIG_TX_FIFO_DEPTH; + reg |= ET_PHY_CONFIG_FIFO_DEPTH_32; +- et131x_mii_write(adapter, PHY_CONFIG, reg); ++ et131x_mii_write(adapter, phydev->addr, PHY_CONFIG, ++ reg); + } + + et131x_set_rx_dma_timer(adapter); +@@ -3677,14 +3664,14 @@ static void et131x_adjust_link(struct ne + + et131x_mii_read(adapter, PHY_MPHY_CONTROL_REG, + ®ister18); +- et131x_mii_write(adapter, PHY_MPHY_CONTROL_REG, +- register18 | 0x4); +- et131x_mii_write(adapter, PHY_INDEX_REG, +- register18 | 0x8402); +- et131x_mii_write(adapter, PHY_DATA_REG, +- register18 | 511); +- et131x_mii_write(adapter, PHY_MPHY_CONTROL_REG, +- register18); ++ et131x_mii_write(adapter, phydev->addr, ++ PHY_MPHY_CONTROL_REG, register18 | 0x4); ++ et131x_mii_write(adapter, phydev->addr, ++ PHY_INDEX_REG, register18 | 0x8402); ++ et131x_mii_write(adapter, phydev->addr, ++ PHY_DATA_REG, register18 | 511); ++ et131x_mii_write(adapter, phydev->addr, ++ PHY_MPHY_CONTROL_REG, register18); + } + + /* Free the packets being actively sent & stopped */ +@@ -4646,10 +4633,6 @@ static int et131x_pci_setup(struct pci_d + /* Copy address into the net_device struct */ + memcpy(netdev->dev_addr, adapter->addr, ETH_ALEN); + +- /* Init variable for counting how long we do not have link status */ +- adapter->boot_coma = 0; +- et1310_disable_phy_coma(adapter); +- + rc = -ENOMEM; + + /* Setup the mii_bus struct */ +@@ -4665,7 +4648,6 @@ static int et131x_pci_setup(struct pci_d + adapter->mii_bus->priv = netdev; + adapter->mii_bus->read = et131x_mdio_read; + adapter->mii_bus->write = et131x_mdio_write; +- adapter->mii_bus->reset = et131x_mdio_reset; + adapter->mii_bus->irq = kmalloc_array(PHY_MAX_ADDR, sizeof(int), + GFP_KERNEL); + if (!adapter->mii_bus->irq) +@@ -4689,6 +4671,10 @@ static int et131x_pci_setup(struct pci_d + /* Setup et1310 as per the documentation */ + et131x_adapter_setup(adapter); + ++ /* Init variable for counting how long we do not have link status */ ++ adapter->boot_coma = 0; ++ et1310_disable_phy_coma(adapter); ++ + /* We can enable interrupts now + * + * NOTE - Because registration of interrupt handler is done in the diff --git a/queue-3.16/staging-lustre-remove-circular-dependency-on-header.patch b/queue-3.16/staging-lustre-remove-circular-dependency-on-header.patch new file mode 100644 index 00000000000..2bef4c01668 --- /dev/null +++ b/queue-3.16/staging-lustre-remove-circular-dependency-on-header.patch @@ -0,0 +1,49 @@ +From e409842a03b0c2c41c0959fef8a7563208af36c1 Mon Sep 17 00:00:00 2001 +From: Pranith Kumar +Date: Tue, 5 Aug 2014 12:27:15 -0400 +Subject: staging: lustre: Remove circular dependency on header + +From: Pranith Kumar + +commit e409842a03b0c2c41c0959fef8a7563208af36c1 upstream. + +The following patch fixes a build error on sparc32. I think it should go to +stable 3.16. + +Remove a circular dependency on atomic.h header file which leads to compilation +failure on sparc32 as reported here: +http://kisskb.ellerman.id.au/kisskb/buildresult/11340509/ + +The specific dependency is as follows: + +In file included from arch/sparc/include/asm/smp_32.h:24:0, + from arch/sparc/include/asm/smp.h:6, + from arch/sparc/include/asm/switch_to_32.h:4, + from arch/sparc/include/asm/switch_to.h:6, + from arch/sparc/include/asm/ptrace.h:84, + from arch/sparc/include/asm/processor_32.h:16, + from arch/sparc/include/asm/processor.h:6, + from arch/sparc/include/asm/barrier_32.h:4, + from arch/sparc/include/asm/barrier.h:6, + from arch/sparc/include/asm/atomic_32.h:17, + from arch/sparc/include/asm/atomic.h:6, + from drivers/staging/lustre/lustre/obdclass/class_obd.c:38 + +Signed-off-by: Pranith Kumar +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/lustre/lustre/obdclass/class_obd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/staging/lustre/lustre/obdclass/class_obd.c ++++ b/drivers/staging/lustre/lustre/obdclass/class_obd.c +@@ -35,7 +35,7 @@ + */ + + #define DEBUG_SUBSYSTEM S_CLASS +-# include ++# include + + #include + #include diff --git a/queue-3.16/staging-r8188eu-add-new-usb-id.patch b/queue-3.16/staging-r8188eu-add-new-usb-id.patch new file mode 100644 index 00000000000..54aa6f6d58a --- /dev/null +++ b/queue-3.16/staging-r8188eu-add-new-usb-id.patch @@ -0,0 +1,29 @@ +From a2fa6721c7237b5a666f16f732628c0c09c0b954 Mon Sep 17 00:00:00 2001 +From: Larry Finger +Date: Mon, 25 Aug 2014 16:05:38 -0500 +Subject: staging: r8188eu: Add new USB ID + +From: Larry Finger + +commit a2fa6721c7237b5a666f16f732628c0c09c0b954 upstream. + +The Elecom WDC-150SU2M uses this chip. + +Reported-by: Hiroki Kondo +Signed-off-by: Larry Finger +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/rtl8188eu/os_dep/usb_intf.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c ++++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c +@@ -54,6 +54,7 @@ static struct usb_device_id rtw_usb_id_t + {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x0179)}, /* 8188ETV */ + /*=== Customer ID ===*/ + /****** 8188EUS ********/ ++ {USB_DEVICE(0x056e, 0x4008)}, /* Elecom WDC-150SU2M */ + {USB_DEVICE(0x07b8, 0x8179)}, /* Abocom - Abocom */ + {USB_DEVICE(0x2001, 0x330F)}, /* DLink DWA-125 REV D1 */ + {USB_DEVICE(0x2001, 0x3310)}, /* Dlink DWA-123 REV D1 */ diff --git a/queue-3.16/staging-rtl8188eu-add-0df6-0076-sitecom-europe-b.v.patch b/queue-3.16/staging-rtl8188eu-add-0df6-0076-sitecom-europe-b.v.patch new file mode 100644 index 00000000000..2374201ad27 --- /dev/null +++ b/queue-3.16/staging-rtl8188eu-add-0df6-0076-sitecom-europe-b.v.patch @@ -0,0 +1,31 @@ +From 8626d524ef08f10fccc0c41e5f75aef8235edf47 Mon Sep 17 00:00:00 2001 +From: Holger Paradies +Date: Wed, 13 Aug 2014 13:22:49 -0500 +Subject: staging/rtl8188eu: add 0df6:0076 Sitecom Europe B.V. + +From: Holger Paradies + +commit 8626d524ef08f10fccc0c41e5f75aef8235edf47 upstream. + +The stick is not recognized. +This dongle uses r8188eu but usb-id is missing. +3.16.0 + +Signed-off-by: Holger Paradies +Signed-off-by: Larry Finger +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/rtl8188eu/os_dep/usb_intf.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c ++++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c +@@ -57,6 +57,7 @@ static struct usb_device_id rtw_usb_id_t + {USB_DEVICE(0x07b8, 0x8179)}, /* Abocom - Abocom */ + {USB_DEVICE(0x2001, 0x330F)}, /* DLink DWA-125 REV D1 */ + {USB_DEVICE(0x2001, 0x3310)}, /* Dlink DWA-123 REV D1 */ ++ {USB_DEVICE(0x0df6, 0x0076)}, /* Sitecom N150 v2 */ + {} /* Terminating entry */ + }; + diff --git a/queue-3.16/svcrdma-select-nfsv4.1-backchannel-transport-based-on-forward-channel.patch b/queue-3.16/svcrdma-select-nfsv4.1-backchannel-transport-based-on-forward-channel.patch new file mode 100644 index 00000000000..672f98120f8 --- /dev/null +++ b/queue-3.16/svcrdma-select-nfsv4.1-backchannel-transport-based-on-forward-channel.patch @@ -0,0 +1,93 @@ +From 3c45ddf823d679a820adddd53b52c6699c9a05ac Mon Sep 17 00:00:00 2001 +From: Chuck Lever +Date: Wed, 16 Jul 2014 15:38:32 -0400 +Subject: svcrdma: Select NFSv4.1 backchannel transport based on forward channel + +From: Chuck Lever + +commit 3c45ddf823d679a820adddd53b52c6699c9a05ac upstream. + +The current code always selects XPRT_TRANSPORT_BC_TCP for the back +channel, even when the forward channel was not TCP (eg, RDMA). When +a 4.1 mount is attempted with RDMA, the server panics in the TCP BC +code when trying to send CB_NULL. + +Instead, construct the transport protocol number from the forward +channel transport or'd with XPRT_TRANSPORT_BC. Transports that do +not support bi-directional RPC will not have registered a "BC" +transport, causing create_backchannel_client() to fail immediately. + +Fixes: https://bugzilla.linux-nfs.org/show_bug.cgi?id=265 +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfsd/nfs4callback.c | 3 ++- + include/linux/sunrpc/svc_xprt.h | 1 + + net/sunrpc/svcsock.c | 2 ++ + net/sunrpc/xprt.c | 2 +- + net/sunrpc/xprtrdma/svc_rdma_transport.c | 1 + + 5 files changed, 7 insertions(+), 2 deletions(-) + +--- a/fs/nfsd/nfs4callback.c ++++ b/fs/nfsd/nfs4callback.c +@@ -689,7 +689,8 @@ static int setup_callback_client(struct + clp->cl_cb_session = ses; + args.bc_xprt = conn->cb_xprt; + args.prognumber = clp->cl_cb_session->se_cb_prog; +- args.protocol = XPRT_TRANSPORT_BC_TCP; ++ args.protocol = conn->cb_xprt->xpt_class->xcl_ident | ++ XPRT_TRANSPORT_BC; + args.authflavor = ses->se_cb_sec.flavor; + } + /* Create RPC client */ +--- a/include/linux/sunrpc/svc_xprt.h ++++ b/include/linux/sunrpc/svc_xprt.h +@@ -33,6 +33,7 @@ struct svc_xprt_class { + struct svc_xprt_ops *xcl_ops; + struct list_head xcl_list; + u32 xcl_max_payload; ++ int xcl_ident; + }; + + /* +--- a/net/sunrpc/svcsock.c ++++ b/net/sunrpc/svcsock.c +@@ -692,6 +692,7 @@ static struct svc_xprt_class svc_udp_cla + .xcl_owner = THIS_MODULE, + .xcl_ops = &svc_udp_ops, + .xcl_max_payload = RPCSVC_MAXPAYLOAD_UDP, ++ .xcl_ident = XPRT_TRANSPORT_UDP, + }; + + static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv) +@@ -1292,6 +1293,7 @@ static struct svc_xprt_class svc_tcp_cla + .xcl_owner = THIS_MODULE, + .xcl_ops = &svc_tcp_ops, + .xcl_max_payload = RPCSVC_MAXPAYLOAD_TCP, ++ .xcl_ident = XPRT_TRANSPORT_TCP, + }; + + void svc_init_xprt_sock(void) +--- a/net/sunrpc/xprt.c ++++ b/net/sunrpc/xprt.c +@@ -1306,7 +1306,7 @@ struct rpc_xprt *xprt_create_transport(s + } + } + spin_unlock(&xprt_list_lock); +- printk(KERN_ERR "RPC: transport (%d) not supported\n", args->ident); ++ dprintk("RPC: transport (%d) not supported\n", args->ident); + return ERR_PTR(-EIO); + + found: +--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c +@@ -92,6 +92,7 @@ struct svc_xprt_class svc_rdma_class = { + .xcl_owner = THIS_MODULE, + .xcl_ops = &svc_rdma_ops, + .xcl_max_payload = RPCSVC_MAXPAYLOAD_TCP, ++ .xcl_ident = XPRT_TRANSPORT_RDMA, + }; + + struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *xprt) diff --git a/queue-3.16/usb-ehci-using-windex-1-for-hub-port.patch b/queue-3.16/usb-ehci-using-windex-1-for-hub-port.patch new file mode 100644 index 00000000000..8d350b83291 --- /dev/null +++ b/queue-3.16/usb-ehci-using-windex-1-for-hub-port.patch @@ -0,0 +1,34 @@ +From 5cbcc35e5bf0eae3c7494ce3efefffc9977827ae Mon Sep 17 00:00:00 2001 +From: Peter Chen +Date: Tue, 5 Aug 2014 08:28:19 +0800 +Subject: usb: ehci: using wIndex + 1 for hub port + +From: Peter Chen + +commit 5cbcc35e5bf0eae3c7494ce3efefffc9977827ae upstream. + +The roothub's index per controller is from 0, but the hub port index per hub +is from 1, this patch fixes "can't find device at roohub" problem for connecting +test fixture at roohub when do USB-IF Embedded Host High-Speed Electrical Test. + +This patch is for v3.12+. + +Signed-off-by: Peter Chen +Acked-by: Alan Stern +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/host/ehci-hub.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/usb/host/ehci-hub.c ++++ b/drivers/usb/host/ehci-hub.c +@@ -1230,7 +1230,7 @@ int ehci_hub_control( + if (selector == EHSET_TEST_SINGLE_STEP_SET_FEATURE) { + spin_unlock_irqrestore(&ehci->lock, flags); + retval = ehset_single_step_set_feature(hcd, +- wIndex); ++ wIndex + 1); + spin_lock_irqsave(&ehci->lock, flags); + break; + } diff --git a/queue-3.16/usb-ftdi_sio-add-basic-micro-atom-nano-usb2serial-pid.patch b/queue-3.16/usb-ftdi_sio-add-basic-micro-atom-nano-usb2serial-pid.patch new file mode 100644 index 00000000000..32262714a13 --- /dev/null +++ b/queue-3.16/usb-ftdi_sio-add-basic-micro-atom-nano-usb2serial-pid.patch @@ -0,0 +1,42 @@ +From 6552cc7f09261db2aeaae389aa2c05a74b3a93b4 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Wed, 13 Aug 2014 17:56:52 +0200 +Subject: USB: ftdi_sio: add Basic Micro ATOM Nano USB2Serial PID + +From: Johan Hovold + +commit 6552cc7f09261db2aeaae389aa2c05a74b3a93b4 upstream. + +Add device id for Basic Micro ATOM Nano USB2Serial adapters. + +Reported-by: Nicolas Alt +Tested-by: Nicolas Alt +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/ftdi_sio.c | 1 + + drivers/usb/serial/ftdi_sio_ids.h | 2 ++ + 2 files changed, 3 insertions(+) + +--- a/drivers/usb/serial/ftdi_sio.c ++++ b/drivers/usb/serial/ftdi_sio.c +@@ -151,6 +151,7 @@ static const struct usb_device_id id_tab + { USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CANDAPTER_PID) }, ++ { USB_DEVICE(FTDI_VID, FTDI_BM_ATOM_NANO_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_NXTCAM_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_EV3CON_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_0_PID) }, +--- a/drivers/usb/serial/ftdi_sio_ids.h ++++ b/drivers/usb/serial/ftdi_sio_ids.h +@@ -42,6 +42,8 @@ + /* www.candapter.com Ewert Energy Systems CANdapter device */ + #define FTDI_CANDAPTER_PID 0x9F80 /* Product Id */ + ++#define FTDI_BM_ATOM_NANO_PID 0xa559 /* Basic Micro ATOM Nano USB2Serial */ ++ + /* + * Texas Instruments XDS100v2 JTAG / BeagleBone A3 + * http://processors.wiki.ti.com/index.php/XDS100 diff --git a/queue-3.16/usb-ftdi_sio-added-pid-for-new-ekey-device.patch b/queue-3.16/usb-ftdi_sio-added-pid-for-new-ekey-device.patch new file mode 100644 index 00000000000..73768bb2af9 --- /dev/null +++ b/queue-3.16/usb-ftdi_sio-added-pid-for-new-ekey-device.patch @@ -0,0 +1,46 @@ +From 646907f5bfb0782c731ae9ff6fb63471a3566132 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ja=C5=A1a=20Bartelj?= +Date: Sat, 16 Aug 2014 12:44:27 +0200 +Subject: USB: ftdi_sio: Added PID for new ekey device +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: JaÅ¡a Bartelj + +commit 646907f5bfb0782c731ae9ff6fb63471a3566132 upstream. + +Added support to the ftdi_sio driver for ekey Converter USB which +uses an FT232BM chip. + +Signed-off-by: JaÅ¡a Bartelj +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/ftdi_sio.c | 2 ++ + drivers/usb/serial/ftdi_sio_ids.h | 5 +++++ + 2 files changed, 7 insertions(+) + +--- a/drivers/usb/serial/ftdi_sio.c ++++ b/drivers/usb/serial/ftdi_sio.c +@@ -948,6 +948,8 @@ static const struct usb_device_id id_tab + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_2_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_3_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_4_PID) }, ++ /* ekey Devices */ ++ { USB_DEVICE(FTDI_VID, FTDI_EKEY_CONV_USB_PID) }, + /* Infineon Devices */ + { USB_DEVICE_INTERFACE_NUMBER(INFINEON_VID, INFINEON_TRIBOARD_PID, 1) }, + { } /* Terminating entry */ +--- a/drivers/usb/serial/ftdi_sio_ids.h ++++ b/drivers/usb/serial/ftdi_sio_ids.h +@@ -1380,3 +1380,8 @@ + #define BRAINBOXES_US_160_6_PID 0x9006 /* US-160 16xRS232 1Mbaud Port 11 and 12 */ + #define BRAINBOXES_US_160_7_PID 0x9007 /* US-160 16xRS232 1Mbaud Port 13 and 14 */ + #define BRAINBOXES_US_160_8_PID 0x9008 /* US-160 16xRS232 1Mbaud Port 15 and 16 */ ++ ++/* ++ * ekey biometric systems GmbH (http://ekey.net/) ++ */ ++#define FTDI_EKEY_CONV_USB_PID 0xCB08 /* Converter USB */ diff --git a/queue-3.16/usb-hub-prevent-hub-autosuspend-if-usbcore.autosuspend-is-1.patch b/queue-3.16/usb-hub-prevent-hub-autosuspend-if-usbcore.autosuspend-is-1.patch new file mode 100644 index 00000000000..df1de71ee8e --- /dev/null +++ b/queue-3.16/usb-hub-prevent-hub-autosuspend-if-usbcore.autosuspend-is-1.patch @@ -0,0 +1,43 @@ +From bdd405d2a5287bdb9b04670ea255e1f122138e66 Mon Sep 17 00:00:00 2001 +From: Roger Quadros +Date: Mon, 4 Aug 2014 12:44:46 +0300 +Subject: usb: hub: Prevent hub autosuspend if usbcore.autosuspend is -1 + +From: Roger Quadros + +commit bdd405d2a5287bdb9b04670ea255e1f122138e66 upstream. + +If user specifies that USB autosuspend must be disabled by module +parameter "usbcore.autosuspend=-1" then we must prevent +autosuspend of USB hub devices as well. + +commit 596d789a211d introduced in v3.8 changed the original behaivour +and stopped respecting the usbcore.autosuspend parameter for hubs. + +Fixes: 596d789a211d "USB: set hub's default autosuspend delay as 0" + +Signed-off-by: Roger Quadros +Tested-by: Michael Welling +Acked-by: Alan Stern +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/core/hub.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -1728,8 +1728,12 @@ static int hub_probe(struct usb_interfac + * - Change autosuspend delay of hub can avoid unnecessary auto + * suspend timer for hub, also may decrease power consumption + * of USB bus. ++ * ++ * - If user has indicated to prevent autosuspend by passing ++ * usbcore.autosuspend = -1 then keep autosuspend disabled. + */ +- pm_runtime_set_autosuspend_delay(&hdev->dev, 0); ++ if (hdev->dev.power.autosuspend_delay >= 0) ++ pm_runtime_set_autosuspend_delay(&hdev->dev, 0); + + /* + * Hubs have proper suspend/resume support, except for root hubs diff --git a/queue-3.16/usb-whiteheat-added-bounds-checking-for-bulk-command-response.patch b/queue-3.16/usb-whiteheat-added-bounds-checking-for-bulk-command-response.patch new file mode 100644 index 00000000000..5082e8fd4ee --- /dev/null +++ b/queue-3.16/usb-whiteheat-added-bounds-checking-for-bulk-command-response.patch @@ -0,0 +1,45 @@ +From 6817ae225cd650fb1c3295d769298c38b1eba818 Mon Sep 17 00:00:00 2001 +From: James Forshaw +Date: Sat, 23 Aug 2014 14:39:48 -0700 +Subject: USB: whiteheat: Added bounds checking for bulk command response + +From: James Forshaw + +commit 6817ae225cd650fb1c3295d769298c38b1eba818 upstream. + +This patch fixes a potential security issue in the whiteheat USB driver +which might allow a local attacker to cause kernel memory corrpution. This +is due to an unchecked memcpy into a fixed size buffer (of 64 bytes). On +EHCI and XHCI busses it's possible to craft responses greater than 64 +bytes leading a buffer overflow. + +Signed-off-by: James Forshaw +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/whiteheat.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/drivers/usb/serial/whiteheat.c ++++ b/drivers/usb/serial/whiteheat.c +@@ -514,6 +514,10 @@ static void command_port_read_callback(s + dev_dbg(&urb->dev->dev, "%s - command_info is NULL, exiting.\n", __func__); + return; + } ++ if (!urb->actual_length) { ++ dev_dbg(&urb->dev->dev, "%s - empty response, exiting.\n", __func__); ++ return; ++ } + if (status) { + dev_dbg(&urb->dev->dev, "%s - nonzero urb status: %d\n", __func__, status); + if (status != -ENOENT) +@@ -534,7 +538,8 @@ static void command_port_read_callback(s + /* These are unsolicited reports from the firmware, hence no + waiting command to wakeup */ + dev_dbg(&urb->dev->dev, "%s - event received\n", __func__); +- } else if (data[0] == WHITEHEAT_GET_DTR_RTS) { ++ } else if ((data[0] == WHITEHEAT_GET_DTR_RTS) && ++ (urb->actual_length - 1 <= sizeof(command_info->result_buffer))) { + memcpy(command_info->result_buffer, &data[1], + urb->actual_length - 1); + command_info->command_finished = WHITEHEAT_CMD_COMPLETE; diff --git a/queue-3.16/usb-xhci-amd-chipset-also-needs-short-tx-quirk.patch b/queue-3.16/usb-xhci-amd-chipset-also-needs-short-tx-quirk.patch new file mode 100644 index 00000000000..f20537ff18b --- /dev/null +++ b/queue-3.16/usb-xhci-amd-chipset-also-needs-short-tx-quirk.patch @@ -0,0 +1,48 @@ +From 2597fe99bb0259387111d0431691f5daac84f5a5 Mon Sep 17 00:00:00 2001 +From: Huang Rui +Date: Tue, 19 Aug 2014 15:17:57 +0300 +Subject: usb: xhci: amd chipset also needs short TX quirk + +From: Huang Rui + +commit 2597fe99bb0259387111d0431691f5daac84f5a5 upstream. + +AMD xHC also needs short tx quirk after tested on most of chipset +generations. That's because there is the same incorrect behavior like +Fresco Logic host. Please see below message with on USB webcam +attached on xHC host: + +[ 139.262944] xhci_hcd 0000:00:10.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? +[ 139.266934] xhci_hcd 0000:00:10.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? +[ 139.270913] xhci_hcd 0000:00:10.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? +[ 139.274937] xhci_hcd 0000:00:10.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? +[ 139.278914] xhci_hcd 0000:00:10.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? +[ 139.282936] xhci_hcd 0000:00:10.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? +[ 139.286915] xhci_hcd 0000:00:10.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? +[ 139.290938] xhci_hcd 0000:00:10.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? +[ 139.294913] xhci_hcd 0000:00:10.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? +[ 139.298917] xhci_hcd 0000:00:10.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? + +Reported-by: Arindam Nath +Tested-by: Shriraj-Rai P +Signed-off-by: Huang Rui +Signed-off-by: Mathias Nyman +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/host/xhci-pci.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/usb/host/xhci-pci.c ++++ b/drivers/usb/host/xhci-pci.c +@@ -101,6 +101,10 @@ static void xhci_pci_quirks(struct devic + /* AMD PLL quirk */ + if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info()) + xhci->quirks |= XHCI_AMD_PLL_FIX; ++ ++ if (pdev->vendor == PCI_VENDOR_ID_AMD) ++ xhci->quirks |= XHCI_TRUST_TX_LENGTH; ++ + if (pdev->vendor == PCI_VENDOR_ID_INTEL) { + xhci->quirks |= XHCI_LPM_SUPPORT; + xhci->quirks |= XHCI_INTEL_HOST; diff --git a/queue-3.16/usbcore-fix-wrong-device-in-an-error-message-in-hub_port_connect.patch b/queue-3.16/usbcore-fix-wrong-device-in-an-error-message-in-hub_port_connect.patch new file mode 100644 index 00000000000..4f0de4d6652 --- /dev/null +++ b/queue-3.16/usbcore-fix-wrong-device-in-an-error-message-in-hub_port_connect.patch @@ -0,0 +1,44 @@ +From dd5f5006d1035547559c8a90781a7e249787a7a2 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Tue, 19 Aug 2014 17:37:55 +0200 +Subject: usbcore: Fix wrong device in an error message in hub_port_connect() + +From: Takashi Iwai + +commit dd5f5006d1035547559c8a90781a7e249787a7a2 upstream. + +The commit [5ee0f803cc3a: usbcore: don't log on consecutive debounce +failures of the same port] added the check of the reliable port, but +it also replaced the device argument to dev_err() wrongly, which leads +to a NULL dereference. + +This patch restores the right device, port_dev->dev. Also, since +dev_err() itself shows the port number, reduce the port number shown +in the error message, essentially reverting to the state before the +commit 5ee0f803cc3a. + +[The fix suggested by Hannes, and the error message cleanup suggested + by Alan Stern] + +Fixes: 5ee0f803cc3a ('usbcore: don't log on consecutive debounce failures of the same port') +Reported-by: Hannes Reinecke +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/core/hub.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -4619,9 +4619,7 @@ static void hub_port_connect(struct usb_ + if (status != -ENODEV && + port1 != unreliable_port && + printk_ratelimit()) +- dev_err(&udev->dev, "connect-debounce failed, port %d disabled\n", +- port1); +- ++ dev_err(&port_dev->dev, "connect-debounce failed\n"); + portstatus &= ~USB_PORT_STAT_CONNECTION; + unreliable_port = port1; + } else { diff --git a/queue-3.16/vm_is_stack-use-for_each_thread-rather-then-buggy-while_each_thread.patch b/queue-3.16/vm_is_stack-use-for_each_thread-rather-then-buggy-while_each_thread.patch new file mode 100644 index 00000000000..e868fead710 --- /dev/null +++ b/queue-3.16/vm_is_stack-use-for_each_thread-rather-then-buggy-while_each_thread.patch @@ -0,0 +1,50 @@ +From 4449a51a7c281602d3a385044ab928322a122a02 Mon Sep 17 00:00:00 2001 +From: Oleg Nesterov +Date: Fri, 8 Aug 2014 14:19:17 -0700 +Subject: vm_is_stack: use for_each_thread() rather then buggy while_each_thread() + +From: Oleg Nesterov + +commit 4449a51a7c281602d3a385044ab928322a122a02 upstream. + +Aleksei hit the soft lockup during reading /proc/PID/smaps. David +investigated the problem and suggested the right fix. + +while_each_thread() is racy and should die, this patch updates +vm_is_stack(). + +Signed-off-by: Oleg Nesterov +Reported-by: Aleksei Besogonov +Tested-by: Aleksei Besogonov +Suggested-by: David Rientjes +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + mm/util.c | 9 +++------ + 1 file changed, 3 insertions(+), 6 deletions(-) + +--- a/mm/util.c ++++ b/mm/util.c +@@ -277,17 +277,14 @@ pid_t vm_is_stack(struct task_struct *ta + + if (in_group) { + struct task_struct *t; +- rcu_read_lock(); +- if (!pid_alive(task)) +- goto done; + +- t = task; +- do { ++ rcu_read_lock(); ++ for_each_thread(task, t) { + if (vm_is_stack_for_task(t, vma)) { + ret = t->pid; + goto done; + } +- } while_each_thread(task, t); ++ } + done: + rcu_read_unlock(); + } diff --git a/queue-3.16/xhci-disable-streams-on-via-xhci-with-device-id-0x3432.patch b/queue-3.16/xhci-disable-streams-on-via-xhci-with-device-id-0x3432.patch new file mode 100644 index 00000000000..a7743469ff6 --- /dev/null +++ b/queue-3.16/xhci-disable-streams-on-via-xhci-with-device-id-0x3432.patch @@ -0,0 +1,41 @@ +From e21eba05afd288a227320f797864ddd859397eed Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Mon, 25 Aug 2014 12:21:56 +0200 +Subject: xhci: Disable streams on Via XHCI with device-id 0x3432 + +From: Hans de Goede + +commit e21eba05afd288a227320f797864ddd859397eed upstream. + +This is a bit bigger hammer then I would like to use for this, but for now +it will have to make do. I'm working on getting my hands on one of these so +that I can try to get streams to work (with a quirk flag if necessary) and +then we can re-enable them. + +For now this at least makes uas capable disk enclosures work again by forcing +fallback to the usb-storage driver. + +https://bugzilla.kernel.org/show_bug.cgi?id=79511 + +Signed-off-by: Hans de Goede +Acked-by: Mathias Nyman +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/host/xhci-pci.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/drivers/usb/host/xhci-pci.c ++++ b/drivers/usb/host/xhci-pci.c +@@ -155,6 +155,11 @@ static void xhci_pci_quirks(struct devic + if (pdev->vendor == PCI_VENDOR_ID_VIA) + xhci->quirks |= XHCI_RESET_ON_RESUME; + ++ /* See https://bugzilla.kernel.org/show_bug.cgi?id=79511 */ ++ if (pdev->vendor == PCI_VENDOR_ID_VIA && ++ pdev->device == 0x3432) ++ xhci->quirks |= XHCI_BROKEN_STREAMS; ++ + if (xhci->quirks & XHCI_RESET_ON_RESUME) + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "QUIRK: Resetting on resume"); diff --git a/queue-3.16/xhci-rework-cycle-bit-checking-for-new-dequeue-pointers.patch b/queue-3.16/xhci-rework-cycle-bit-checking-for-new-dequeue-pointers.patch new file mode 100644 index 00000000000..763c68eef4d --- /dev/null +++ b/queue-3.16/xhci-rework-cycle-bit-checking-for-new-dequeue-pointers.patch @@ -0,0 +1,179 @@ +From 365038d83313951d6ace15342eb24624bbef1666 Mon Sep 17 00:00:00 2001 +From: Mathias Nyman +Date: Tue, 19 Aug 2014 15:17:58 +0300 +Subject: xhci: rework cycle bit checking for new dequeue pointers + +From: Mathias Nyman + +commit 365038d83313951d6ace15342eb24624bbef1666 upstream. + +When we manually need to move the TR dequeue pointer we need to set the +correct cycle bit as well. Previously we used the trb pointer from the +last event received as a base, but this was changed in +commit 1f81b6d22a59 ("usb: xhci: Prefer endpoint context dequeue pointer") +to use the dequeue pointer from the endpoint context instead + +It turns out some Asmedia controllers advance the dequeue pointer +stored in the endpoint context past the event triggering TRB, and +this messed up the way the cycle bit was calculated. + +Instead of adding a quirk or complicating the already hard to follow cycle bit +code, the whole cycle bit calculation is now simplified and adapted to handle +event and endpoint context dequeue pointer differences. + +Fixes: 1f81b6d22a59 ("usb: xhci: Prefer endpoint context dequeue pointer") +Reported-by: Maciej Puzio +Reported-by: Evan Langlois +Reviewed-by: Julius Werner +Tested-by: Maciej Puzio +Tested-by: Evan Langlois +Signed-off-by: Mathias Nyman +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/host/xhci-ring.c | 101 ++++++++++++++++--------------------------- + drivers/usb/host/xhci.c | 3 + + 2 files changed, 42 insertions(+), 62 deletions(-) + +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -364,32 +364,6 @@ static void ring_doorbell_for_active_rin + } + } + +-/* +- * Find the segment that trb is in. Start searching in start_seg. +- * If we must move past a segment that has a link TRB with a toggle cycle state +- * bit set, then we will toggle the value pointed at by cycle_state. +- */ +-static struct xhci_segment *find_trb_seg( +- struct xhci_segment *start_seg, +- union xhci_trb *trb, int *cycle_state) +-{ +- struct xhci_segment *cur_seg = start_seg; +- struct xhci_generic_trb *generic_trb; +- +- while (cur_seg->trbs > trb || +- &cur_seg->trbs[TRBS_PER_SEGMENT - 1] < trb) { +- generic_trb = &cur_seg->trbs[TRBS_PER_SEGMENT - 1].generic; +- if (generic_trb->field[3] & cpu_to_le32(LINK_TOGGLE)) +- *cycle_state ^= 0x1; +- cur_seg = cur_seg->next; +- if (cur_seg == start_seg) +- /* Looped over the entire list. Oops! */ +- return NULL; +- } +- return cur_seg; +-} +- +- + static struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci, + unsigned int slot_id, unsigned int ep_index, + unsigned int stream_id) +@@ -459,9 +433,12 @@ void xhci_find_new_dequeue_state(struct + struct xhci_virt_device *dev = xhci->devs[slot_id]; + struct xhci_virt_ep *ep = &dev->eps[ep_index]; + struct xhci_ring *ep_ring; +- struct xhci_generic_trb *trb; ++ struct xhci_segment *new_seg; ++ union xhci_trb *new_deq; + dma_addr_t addr; + u64 hw_dequeue; ++ bool cycle_found = false; ++ bool td_last_trb_found = false; + + ep_ring = xhci_triad_to_transfer_ring(xhci, slot_id, + ep_index, stream_id); +@@ -486,45 +463,45 @@ void xhci_find_new_dequeue_state(struct + hw_dequeue = le64_to_cpu(ep_ctx->deq); + } + +- /* Find virtual address and segment of hardware dequeue pointer */ +- state->new_deq_seg = ep_ring->deq_seg; +- state->new_deq_ptr = ep_ring->dequeue; +- while (xhci_trb_virt_to_dma(state->new_deq_seg, state->new_deq_ptr) +- != (dma_addr_t)(hw_dequeue & ~0xf)) { +- next_trb(xhci, ep_ring, &state->new_deq_seg, +- &state->new_deq_ptr); +- if (state->new_deq_ptr == ep_ring->dequeue) { +- WARN_ON(1); +- return; +- } +- } ++ new_seg = ep_ring->deq_seg; ++ new_deq = ep_ring->dequeue; ++ state->new_cycle_state = hw_dequeue & 0x1; ++ + /* +- * Find cycle state for last_trb, starting at old cycle state of +- * hw_dequeue. If there is only one segment ring, find_trb_seg() will +- * return immediately and cannot toggle the cycle state if this search +- * wraps around, so add one more toggle manually in that case. ++ * We want to find the pointer, segment and cycle state of the new trb ++ * (the one after current TD's last_trb). We know the cycle state at ++ * hw_dequeue, so walk the ring until both hw_dequeue and last_trb are ++ * found. + */ +- state->new_cycle_state = hw_dequeue & 0x1; +- if (ep_ring->first_seg == ep_ring->first_seg->next && +- cur_td->last_trb < state->new_deq_ptr) +- state->new_cycle_state ^= 0x1; ++ do { ++ if (!cycle_found && xhci_trb_virt_to_dma(new_seg, new_deq) ++ == (dma_addr_t)(hw_dequeue & ~0xf)) { ++ cycle_found = true; ++ if (td_last_trb_found) ++ break; ++ } ++ if (new_deq == cur_td->last_trb) ++ td_last_trb_found = true; + +- state->new_deq_ptr = cur_td->last_trb; +- xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, +- "Finding segment containing last TRB in TD."); +- state->new_deq_seg = find_trb_seg(state->new_deq_seg, +- state->new_deq_ptr, &state->new_cycle_state); +- if (!state->new_deq_seg) { +- WARN_ON(1); +- return; +- } ++ if (cycle_found && ++ TRB_TYPE_LINK_LE32(new_deq->generic.field[3]) && ++ new_deq->generic.field[3] & cpu_to_le32(LINK_TOGGLE)) ++ state->new_cycle_state ^= 0x1; ++ ++ next_trb(xhci, ep_ring, &new_seg, &new_deq); ++ ++ /* Search wrapped around, bail out */ ++ if (new_deq == ep->ring->dequeue) { ++ xhci_err(xhci, "Error: Failed finding new dequeue state\n"); ++ state->new_deq_seg = NULL; ++ state->new_deq_ptr = NULL; ++ return; ++ } ++ ++ } while (!cycle_found || !td_last_trb_found); + +- /* Increment to find next TRB after last_trb. Cycle if appropriate. */ +- trb = &state->new_deq_ptr->generic; +- if (TRB_TYPE_LINK_LE32(trb->field[3]) && +- (trb->field[3] & cpu_to_le32(LINK_TOGGLE))) +- state->new_cycle_state ^= 0x1; +- next_trb(xhci, ep_ring, &state->new_deq_seg, &state->new_deq_ptr); ++ state->new_deq_seg = new_seg; ++ state->new_deq_ptr = new_deq; + + /* Don't update the ring cycle state for the producer (us). */ + xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -2891,6 +2891,9 @@ void xhci_cleanup_stalled_ring(struct xh + ep_index, ep->stopped_stream, ep->stopped_td, + &deq_state); + ++ if (!deq_state.new_deq_ptr || !deq_state.new_deq_seg) ++ return; ++ + /* HW with the reset endpoint quirk will use the saved dequeue state to + * issue a configure endpoint command later. + */ diff --git a/queue-3.16/xhci-treat-not-finding-the-event_seg-on-comp_stop-the-same-as-comp_stop_inval.patch b/queue-3.16/xhci-treat-not-finding-the-event_seg-on-comp_stop-the-same-as-comp_stop_inval.patch new file mode 100644 index 00000000000..1400d446726 --- /dev/null +++ b/queue-3.16/xhci-treat-not-finding-the-event_seg-on-comp_stop-the-same-as-comp_stop_inval.patch @@ -0,0 +1,42 @@ +From 9a54886342e227433aebc9d374f8ae268a836475 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 19 Aug 2014 15:17:56 +0300 +Subject: xhci: Treat not finding the event_seg on COMP_STOP the same as COMP_STOP_INVAL + +From: Hans de Goede + +commit 9a54886342e227433aebc9d374f8ae268a836475 upstream. + +When using a Renesas uPD720231 chipset usb-3 uas to sata bridge with a 120G +Crucial M500 ssd, model string: Crucial_ CT120M500SSD1, together with a +the integrated Intel xhci controller on a Haswell laptop: + +00:14.0 USB controller [0c03]: Intel Corporation 8 Series USB xHCI HC [8086:9c31] (rev 04) + +The following error gets logged to dmesg: + +xhci error: Transfer event TRB DMA ptr not part of current TD + +Treating COMP_STOP the same as COMP_STOP_INVAL when no event_seg gets found +fixes this. + +Signed-off-by: Hans de Goede +Signed-off-by: Mathias Nyman +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/host/xhci-ring.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -2483,7 +2483,8 @@ static int handle_tx_event(struct xhci_h + * last TRB of the previous TD. The command completion handle + * will take care the rest. + */ +- if (!event_seg && trb_comp_code == COMP_STOP_INVAL) { ++ if (!event_seg && (trb_comp_code == COMP_STOP || ++ trb_comp_code == COMP_STOP_INVAL)) { + ret = 0; + goto cleanup; + }