From: Greg Kroah-Hartman Date: Tue, 13 Aug 2013 05:53:42 +0000 (-0700) Subject: 3.4-stable patches X-Git-Tag: v3.0.91~8 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ac1939356d893118d4b809e5c00cb4254d96ad39;p=thirdparty%2Fkernel%2Fstable-queue.git 3.4-stable patches added patches: cifs-extend-the-buffer-length-enought-for-sprintf-using.patch debugfs-debugfs_remove_recursive-must-not-rely-on-list_empty-d_subdirs.patch ext4-fix-mount-remount-error-messages-for-incompatible-mount-options.patch usb-core-don-t-try-to-reset_device-a-port-that-got-just-disconnected.patch --- diff --git a/queue-3.4/cifs-extend-the-buffer-length-enought-for-sprintf-using.patch b/queue-3.4/cifs-extend-the-buffer-length-enought-for-sprintf-using.patch new file mode 100644 index 00000000000..c5e723135c4 --- /dev/null +++ b/queue-3.4/cifs-extend-the-buffer-length-enought-for-sprintf-using.patch @@ -0,0 +1,99 @@ +From 057d6332b24a4497c55a761c83c823eed9e3f23b Mon Sep 17 00:00:00 2001 +From: Chen Gang +Date: Fri, 19 Jul 2013 09:01:36 +0800 +Subject: cifs: extend the buffer length enought for sprintf() using + +From: Chen Gang + +commit 057d6332b24a4497c55a761c83c823eed9e3f23b upstream. + +For cifs_set_cifscreds() in "fs/cifs/connect.c", 'desc' buffer length +is 'CIFSCREDS_DESC_SIZE' (56 is less than 256), and 'ses->domainName' +length may be "255 + '\0'". + +The related sprintf() may cause memory overflow, so need extend related +buffer enough to hold all things. + +It is also necessary to be sure of 'ses->domainName' must be less than +256, and define the related macro instead of hard code number '256'. + +Signed-off-by: Chen Gang +Reviewed-by: Jeff Layton +Reviewed-by: Shirish Pargaonkar +Reviewed-by: Scott Lovenberg +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman + +--- + fs/cifs/cifsencrypt.c | 2 +- + fs/cifs/cifsglob.h | 1 + + fs/cifs/connect.c | 7 ++++--- + fs/cifs/sess.c | 6 +++--- + 4 files changed, 9 insertions(+), 7 deletions(-) + +--- a/fs/cifs/cifsencrypt.c ++++ b/fs/cifs/cifsencrypt.c +@@ -369,7 +369,7 @@ find_domain_name(struct cifs_ses *ses, c + if (blobptr + attrsize > blobend) + break; + if (type == NTLMSSP_AV_NB_DOMAIN_NAME) { +- if (!attrsize) ++ if (!attrsize || attrsize >= CIFS_MAX_DOMAINNAME_LEN) + break; + if (!ses->domainName) { + ses->domainName = +--- a/fs/cifs/cifsglob.h ++++ b/fs/cifs/cifsglob.h +@@ -38,6 +38,7 @@ + #define MAX_TREE_SIZE (2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1) + #define MAX_SERVER_SIZE 15 + #define MAX_SHARE_SIZE 80 ++#define CIFS_MAX_DOMAINNAME_LEN 256 /* max domain name length */ + #define MAX_USERNAME_SIZE 256 /* reasonable maximum for current servers */ + #define MAX_PASSWORD_SIZE 512 /* max for windows seems to be 256 wide chars */ + +--- a/fs/cifs/connect.c ++++ b/fs/cifs/connect.c +@@ -1698,7 +1698,8 @@ cifs_parse_mount_options(const char *mou + if (string == NULL) + goto out_nomem; + +- if (strnlen(string, 256) == 256) { ++ if (strnlen(string, CIFS_MAX_DOMAINNAME_LEN) ++ == CIFS_MAX_DOMAINNAME_LEN) { + printk(KERN_WARNING "CIFS: domain name too" + " long\n"); + goto cifs_parse_mount_err; +@@ -2356,8 +2357,8 @@ cifs_put_smb_ses(struct cifs_ses *ses) + + #ifdef CONFIG_KEYS + +-/* strlen("cifs:a:") + INET6_ADDRSTRLEN + 1 */ +-#define CIFSCREDS_DESC_SIZE (7 + INET6_ADDRSTRLEN + 1) ++/* strlen("cifs:a:") + CIFS_MAX_DOMAINNAME_LEN + 1 */ ++#define CIFSCREDS_DESC_SIZE (7 + CIFS_MAX_DOMAINNAME_LEN + 1) + + /* Populate username and pw fields from keyring if possible */ + static int +--- a/fs/cifs/sess.c ++++ b/fs/cifs/sess.c +@@ -198,7 +198,7 @@ static void unicode_domain_string(char * + bytes_ret = 0; + } else + bytes_ret = cifs_strtoUTF16((__le16 *) bcc_ptr, ses->domainName, +- 256, nls_cp); ++ CIFS_MAX_DOMAINNAME_LEN, nls_cp); + bcc_ptr += 2 * bytes_ret; + bcc_ptr += 2; /* account for null terminator */ + +@@ -256,8 +256,8 @@ static void ascii_ssetup_strings(char ** + + /* copy domain */ + if (ses->domainName != NULL) { +- strncpy(bcc_ptr, ses->domainName, 256); +- bcc_ptr += strnlen(ses->domainName, 256); ++ strncpy(bcc_ptr, ses->domainName, CIFS_MAX_DOMAINNAME_LEN); ++ bcc_ptr += strnlen(ses->domainName, CIFS_MAX_DOMAINNAME_LEN); + } /* else we will send a null domain name + so the server will default to its own domain */ + *bcc_ptr = 0; diff --git a/queue-3.4/debugfs-debugfs_remove_recursive-must-not-rely-on-list_empty-d_subdirs.patch b/queue-3.4/debugfs-debugfs_remove_recursive-must-not-rely-on-list_empty-d_subdirs.patch new file mode 100644 index 00000000000..6043e08941d --- /dev/null +++ b/queue-3.4/debugfs-debugfs_remove_recursive-must-not-rely-on-list_empty-d_subdirs.patch @@ -0,0 +1,166 @@ +From 776164c1faac4966ab14418bb0922e1820da1d19 Mon Sep 17 00:00:00 2001 +From: Oleg Nesterov +Date: Fri, 26 Jul 2013 17:12:56 +0200 +Subject: debugfs: debugfs_remove_recursive() must not rely on list_empty(d_subdirs) + +From: Oleg Nesterov + +commit 776164c1faac4966ab14418bb0922e1820da1d19 upstream. + +debugfs_remove_recursive() is wrong, + +1. it wrongly assumes that !list_empty(d_subdirs) means that this + dir should be removed. + + This is not that bad by itself, but: + +2. if d_subdirs does not becomes empty after __debugfs_remove() + it gives up and silently fails, it doesn't even try to remove + other entries. + + However ->d_subdirs can be non-empty because it still has the + already deleted !debugfs_positive() entries. + +3. simple_release_fs() is called even if __debugfs_remove() fails. + +Suppose we have + + dir1/ + dir2/ + file2 + file1 + +and someone opens dir1/dir2/file2. + +Now, debugfs_remove_recursive(dir1/dir2) succeeds, and dir1/dir2 goes +away. + +But debugfs_remove_recursive(dir1) silently fails and doesn't remove +this directory. Because it tries to delete (the already deleted) +dir1/dir2/file2 again and then fails due to "Avoid infinite loop" +logic. + +Test-case: + + #!/bin/sh + + cd /sys/kernel/debug/tracing + echo 'p:probe/sigprocmask sigprocmask' >> kprobe_events + sleep 1000 < events/probe/sigprocmask/id & + echo -n >| kprobe_events + + [ -d events/probe ] && echo "ERR!! failed to rm probe" + +And after that it is not possible to create another probe entry. + +With this patch debugfs_remove_recursive() skips !debugfs_positive() +files although this is not strictly needed. The most important change +is that it does not try to make ->d_subdirs empty, it simply scans +the whole list(s) recursively and removes as much as possible. + +Link: http://lkml.kernel.org/r/20130726151256.GC19472@redhat.com + +Acked-by: Greg Kroah-Hartman +Signed-off-by: Oleg Nesterov +Signed-off-by: Steven Rostedt +Signed-off-by: Greg Kroah-Hartman + +--- + fs/debugfs/inode.c | 69 ++++++++++++++++------------------------------------- + 1 file changed, 22 insertions(+), 47 deletions(-) + +--- a/fs/debugfs/inode.c ++++ b/fs/debugfs/inode.c +@@ -527,8 +527,7 @@ EXPORT_SYMBOL_GPL(debugfs_remove); + */ + void debugfs_remove_recursive(struct dentry *dentry) + { +- struct dentry *child; +- struct dentry *parent; ++ struct dentry *child, *next, *parent; + + if (!dentry) + return; +@@ -538,61 +537,37 @@ void debugfs_remove_recursive(struct den + return; + + parent = dentry; ++ down: + mutex_lock(&parent->d_inode->i_mutex); ++ list_for_each_entry_safe(child, next, &parent->d_subdirs, d_u.d_child) { ++ if (!debugfs_positive(child)) ++ continue; + +- while (1) { +- /* +- * When all dentries under "parent" has been removed, +- * walk up the tree until we reach our starting point. +- */ +- if (list_empty(&parent->d_subdirs)) { +- mutex_unlock(&parent->d_inode->i_mutex); +- if (parent == dentry) +- break; +- parent = parent->d_parent; +- mutex_lock(&parent->d_inode->i_mutex); +- } +- child = list_entry(parent->d_subdirs.next, struct dentry, +- d_u.d_child); +- next_sibling: +- +- /* +- * If "child" isn't empty, walk down the tree and +- * remove all its descendants first. +- */ ++ /* perhaps simple_empty(child) makes more sense */ + if (!list_empty(&child->d_subdirs)) { + mutex_unlock(&parent->d_inode->i_mutex); + parent = child; +- mutex_lock(&parent->d_inode->i_mutex); +- continue; ++ goto down; + } +- __debugfs_remove(child, parent); +- if (parent->d_subdirs.next == &child->d_u.d_child) { +- /* +- * Try the next sibling. +- */ +- if (child->d_u.d_child.next != &parent->d_subdirs) { +- child = list_entry(child->d_u.d_child.next, +- struct dentry, +- d_u.d_child); +- goto next_sibling; +- } +- +- /* +- * Avoid infinite loop if we fail to remove +- * one dentry. +- */ +- mutex_unlock(&parent->d_inode->i_mutex); +- break; +- } +- simple_release_fs(&debugfs_mount, &debugfs_mount_count); ++ up: ++ if (!__debugfs_remove(child, parent)) ++ simple_release_fs(&debugfs_mount, &debugfs_mount_count); + } + +- parent = dentry->d_parent; ++ mutex_unlock(&parent->d_inode->i_mutex); ++ child = parent; ++ parent = parent->d_parent; + mutex_lock(&parent->d_inode->i_mutex); +- __debugfs_remove(dentry, parent); ++ ++ if (child != dentry) { ++ next = list_entry(child->d_u.d_child.next, struct dentry, ++ d_u.d_child); ++ goto up; ++ } ++ ++ if (!__debugfs_remove(child, parent)) ++ simple_release_fs(&debugfs_mount, &debugfs_mount_count); + mutex_unlock(&parent->d_inode->i_mutex); +- simple_release_fs(&debugfs_mount, &debugfs_mount_count); + } + EXPORT_SYMBOL_GPL(debugfs_remove_recursive); + diff --git a/queue-3.4/ext4-fix-mount-remount-error-messages-for-incompatible-mount-options.patch b/queue-3.4/ext4-fix-mount-remount-error-messages-for-incompatible-mount-options.patch new file mode 100644 index 00000000000..8958591b17c --- /dev/null +++ b/queue-3.4/ext4-fix-mount-remount-error-messages-for-incompatible-mount-options.patch @@ -0,0 +1,68 @@ +From 6ae6514b33f941d3386da0dfbe2942766eab1577 Mon Sep 17 00:00:00 2001 +From: Piotr Sarna +Date: Thu, 8 Aug 2013 23:02:24 -0400 +Subject: ext4: fix mount/remount error messages for incompatible mount options + +From: Piotr Sarna + +commit 6ae6514b33f941d3386da0dfbe2942766eab1577 upstream. + +Commit 5688978 ("ext4: improve handling of conflicting mount options") +introduced incorrect messages shown while choosing wrong mount options. + +First of all, both cases of incorrect mount options, +"data=journal,delalloc" and "data=journal,dioread_nolock" result in +the same error message. + +Secondly, the problem above isn't solved for remount option: the +mismatched parameter is simply ignored. Moreover, ext4_msg states +that remount with options "data=journal,delalloc" succeeded, which is +not true. + +To fix it up, I added a simple check after parse_options() call to +ensure that data=journal and delalloc/dioread_nolock parameters are +not present at the same time. + +Signed-off-by: Piotr Sarna +Acked-by: Bartlomiej Zolnierkiewicz +Signed-off-by: Kyungmin Park +Signed-off-by: "Theodore Ts'o" +Signed-off-by: Greg Kroah-Hartman + +--- + fs/ext4/super.c | 17 ++++++++++++++++- + 1 file changed, 16 insertions(+), 1 deletion(-) + +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -3232,7 +3232,7 @@ static int ext4_fill_super(struct super_ + } + if (test_opt(sb, DIOREAD_NOLOCK)) { + ext4_msg(sb, KERN_ERR, "can't mount with " +- "both data=journal and delalloc"); ++ "both data=journal and dioread_nolock"); + goto failed_mount; + } + if (test_opt(sb, DELALLOC)) +@@ -4397,6 +4397,21 @@ static int ext4_remount(struct super_blo + goto restore_opts; + } + ++ if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) { ++ if (test_opt2(sb, EXPLICIT_DELALLOC)) { ++ ext4_msg(sb, KERN_ERR, "can't mount with " ++ "both data=journal and delalloc"); ++ err = -EINVAL; ++ goto restore_opts; ++ } ++ if (test_opt(sb, DIOREAD_NOLOCK)) { ++ ext4_msg(sb, KERN_ERR, "can't mount with " ++ "both data=journal and dioread_nolock"); ++ err = -EINVAL; ++ goto restore_opts; ++ } ++ } ++ + if (sbi->s_mount_flags & EXT4_MF_FS_ABORTED) + ext4_abort(sb, "Abort forced by user"); + diff --git a/queue-3.4/series b/queue-3.4/series index db66863f7c1..08cd8fbab0a 100644 --- a/queue-3.4/series +++ b/queue-3.4/series @@ -7,3 +7,7 @@ virtio-console-fix-race-in-port_fops_open-and-port-unplug.patch virtio-console-clean-up-port-data-immediately-at-time-of-unplug.patch virtio-console-fix-raising-sigio-after-port-unplug.patch virtio-console-return-enodev-on-all-read-operations-after-unplug.patch +ext4-fix-mount-remount-error-messages-for-incompatible-mount-options.patch +cifs-extend-the-buffer-length-enought-for-sprintf-using.patch +usb-core-don-t-try-to-reset_device-a-port-that-got-just-disconnected.patch +debugfs-debugfs_remove_recursive-must-not-rely-on-list_empty-d_subdirs.patch diff --git a/queue-3.4/usb-core-don-t-try-to-reset_device-a-port-that-got-just-disconnected.patch b/queue-3.4/usb-core-don-t-try-to-reset_device-a-port-that-got-just-disconnected.patch new file mode 100644 index 00000000000..6352f94b530 --- /dev/null +++ b/queue-3.4/usb-core-don-t-try-to-reset_device-a-port-that-got-just-disconnected.patch @@ -0,0 +1,60 @@ +From 481f2d4f89f87a0baa26147f323380e31cfa7c44 Mon Sep 17 00:00:00 2001 +From: Julius Werner +Date: Tue, 30 Jul 2013 19:51:20 -0700 +Subject: usb: core: don't try to reset_device() a port that got just disconnected + +From: Julius Werner + +commit 481f2d4f89f87a0baa26147f323380e31cfa7c44 upstream. + +The USB hub driver's event handler contains a check to catch SuperSpeed +devices that transitioned into the SS.Inactive state and tries to fix +them with a reset. It decides whether to do a plain hub port reset or +call the usb_reset_device() function based on whether there was a device +attached to the port. + +However, there are device/hub combinations (found with a JetFlash +Transcend mass storage stick (8564:1000) on the root hub of an Intel +LynxPoint PCH) which can transition to the SS.Inactive state on +disconnect (and stay there long enough for the host to notice). In this +case, above-mentioned reset check will call usb_reset_device() on the +stale device data structure. The kernel will send pointless LPM control +messages to the no longer connected device address and can even cause +several 5 second khubd stalls on some (buggy?) host controllers, before +finally accepting the device's fate amongst a flurry of error messages. + +This patch makes the choice of reset dependent on the port status that +has just been read from the hub in addition to the existence of an +in-kernel data structure for the device, and only proceeds with the more +extensive reset if both are valid. + +Signed-off-by: Julius Werner +Signed-off-by: Sarah Sharp +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/core/hub.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -3890,7 +3890,8 @@ static void hub_events(void) + hub->hdev->children[i - 1]; + + dev_dbg(hub_dev, "warm reset port %d\n", i); +- if (!udev) { ++ if (!udev || !(portstatus & ++ USB_PORT_STAT_CONNECTION)) { + status = hub_port_reset(hub, i, + NULL, HUB_BH_RESET_TIME, + true); +@@ -3900,8 +3901,8 @@ static void hub_events(void) + usb_lock_device(udev); + status = usb_reset_device(udev); + usb_unlock_device(udev); ++ connect_change = 0; + } +- connect_change = 0; + } + + if (connect_change)