From: Greg Kroah-Hartman Date: Fri, 21 Sep 2012 17:56:32 +0000 (-0700) Subject: 3.4-stable patches X-Git-Tag: v3.0.44~80 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d9dddff49b6a04d9685c16d032296f4fcb628fc2;p=thirdparty%2Fkernel%2Fstable-queue.git 3.4-stable patches added patches: acpi-pm-fix-resource_lock-dead-lock-in-acpi_power_on_device.patch acpi-pm-use-kern_debug-when-no-power-resources-are-found.patch ahci-add-alternate-identifier-for-the-88se9172.patch digsig-add-hash-size-comparision-on-signature-verification.patch fs-proc-fix-potential-unregister_sysctl_table-hang.patch kobject-fix-oops-with-input0-bad-kobj_uevent_env-content-in-show_uevent.patch mmc-card-skip-secure-erase-on-movinand-causes-unrecoverable-corruption.patch mmc-mxs-mmc-fix-deadlock-in-sdio-irq-case.patch mmc-sdhci-esdhc-break-out-early-if-clock-is-0.patch oprofile-s390-fix-uninitialized-memory-access-when-writing-to-oprofilefs.patch perf_event-switch-to-internal-refcount-fix-race-with-close.patch redefine-atomic_init-and-atomic64_init-to-drop-the-casts.patch sound-tegra_alc5632-remove-hp-detect-gpio-inversion.patch sunrpc-fix-a-udp-transport-regression.patch --- diff --git a/queue-3.4/acpi-pm-fix-resource_lock-dead-lock-in-acpi_power_on_device.patch b/queue-3.4/acpi-pm-fix-resource_lock-dead-lock-in-acpi_power_on_device.patch new file mode 100644 index 00000000000..382b7115676 --- /dev/null +++ b/queue-3.4/acpi-pm-fix-resource_lock-dead-lock-in-acpi_power_on_device.patch @@ -0,0 +1,139 @@ +From 40bf66ec9791f1452b90b82aadc3b6e6aee201f5 Mon Sep 17 00:00:00 2001 +From: Lin Ming +Date: Fri, 14 Sep 2012 00:26:33 +0200 +Subject: ACPI / PM: Fix resource_lock dead lock in acpi_power_on_device + +From: Lin Ming + +commit 40bf66ec9791f1452b90b82aadc3b6e6aee201f5 upstream. + +Commit 0090def("ACPI: Add interface to register/unregister device +to/from power resources") used resource_lock to protect the devices list +that relies on power resource. It caused a mutex dead lock, as below + + acpi_power_on ---> lock resource_lock + __acpi_power_on + acpi_power_on_device + acpi_power_get_inferred_state + acpi_power_get_list_state ---> lock resource_lock + +This patch adds a new mutex "devices_lock" to protect the devices list +and calls acpi_power_on_device in acpi_power_on, instead of +__acpi_power_on, after the resource_lock is released. + +[rjw: Changed data type of a boolean variable to bool.] + +Signed-off-by: Lin Ming +Signed-off-by: Aaron Lu +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/acpi/power.c | 34 +++++++++++++++++++++++----------- + 1 file changed, 23 insertions(+), 11 deletions(-) + +--- a/drivers/acpi/power.c ++++ b/drivers/acpi/power.c +@@ -103,6 +103,7 @@ struct acpi_power_resource { + + /* List of devices relying on this power resource */ + struct acpi_power_resource_device *devices; ++ struct mutex devices_lock; + }; + + static struct list_head acpi_power_resource_list; +@@ -221,7 +222,6 @@ static void acpi_power_on_device(struct + + static int __acpi_power_on(struct acpi_power_resource *resource) + { +- struct acpi_power_resource_device *device_list = resource->devices; + acpi_status status = AE_OK; + + status = acpi_evaluate_object(resource->device->handle, "_ON", NULL, NULL); +@@ -234,19 +234,15 @@ static int __acpi_power_on(struct acpi_p + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Power resource [%s] turned on\n", + resource->name)); + +- while (device_list) { +- acpi_power_on_device(device_list->device); +- +- device_list = device_list->next; +- } +- + return 0; + } + + static int acpi_power_on(acpi_handle handle) + { + int result = 0; ++ bool resume_device = false; + struct acpi_power_resource *resource = NULL; ++ struct acpi_power_resource_device *device_list; + + result = acpi_power_get_context(handle, &resource); + if (result) +@@ -262,10 +258,25 @@ static int acpi_power_on(acpi_handle han + result = __acpi_power_on(resource); + if (result) + resource->ref_count--; ++ else ++ resume_device = true; + } + + mutex_unlock(&resource->resource_lock); + ++ if (!resume_device) ++ return result; ++ ++ mutex_lock(&resource->devices_lock); ++ ++ device_list = resource->devices; ++ while (device_list) { ++ acpi_power_on_device(device_list->device); ++ device_list = device_list->next; ++ } ++ ++ mutex_unlock(&resource->devices_lock); ++ + return result; + } + +@@ -351,7 +362,7 @@ static void __acpi_power_resource_unregi + if (acpi_power_get_context(res_handle, &resource)) + return; + +- mutex_lock(&resource->resource_lock); ++ mutex_lock(&resource->devices_lock); + prev = NULL; + curr = resource->devices; + while (curr) { +@@ -368,7 +379,7 @@ static void __acpi_power_resource_unregi + prev = curr; + curr = curr->next; + } +- mutex_unlock(&resource->resource_lock); ++ mutex_unlock(&resource->devices_lock); + } + + /* Unlink dev from all power resources in _PR0 */ +@@ -409,10 +420,10 @@ static int __acpi_power_resource_registe + + power_resource_device->device = powered_device; + +- mutex_lock(&resource->resource_lock); ++ mutex_lock(&resource->devices_lock); + power_resource_device->next = resource->devices; + resource->devices = power_resource_device; +- mutex_unlock(&resource->resource_lock); ++ mutex_unlock(&resource->devices_lock); + + return 0; + } +@@ -715,6 +726,7 @@ static int acpi_power_add(struct acpi_de + + resource->device = device; + mutex_init(&resource->resource_lock); ++ mutex_init(&resource->devices_lock); + strcpy(resource->name, device->pnp.bus_id); + strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME); + strcpy(acpi_device_class(device), ACPI_POWER_CLASS); diff --git a/queue-3.4/acpi-pm-use-kern_debug-when-no-power-resources-are-found.patch b/queue-3.4/acpi-pm-use-kern_debug-when-no-power-resources-are-found.patch new file mode 100644 index 00000000000..e22af58d354 --- /dev/null +++ b/queue-3.4/acpi-pm-use-kern_debug-when-no-power-resources-are-found.patch @@ -0,0 +1,37 @@ +From f25b70613c048ceb1df052576fda03321ebf41cf Mon Sep 17 00:00:00 2001 +From: Aaron Lu +Date: Fri, 14 Sep 2012 20:54:44 +0200 +Subject: ACPI / PM: Use KERN_DEBUG when no power resources are found + +From: Aaron Lu + +commit f25b70613c048ceb1df052576fda03321ebf41cf upstream. + +commit a606dac368eed5696fb38e16b1394f1d049c09e9 adds support to link +devices which have _PRx, if a device does not have _PRx, a warning +message will be printed. + +This commit is for ZPODD on Intel ZPODD capable platforms, on other +platforms, it has no problem if there is no power resource for this +device, so a warning here is not appropriate, change it to debug. + +Reported-by: Borislav Petkov +Signed-off-by: Aaron Lu +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/acpi/power.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/acpi/power.c ++++ b/drivers/acpi/power.c +@@ -468,7 +468,7 @@ int acpi_power_resource_register_device( + return ret; + + no_power_resource: +- printk(KERN_WARNING PREFIX "Invalid Power Resource to register!"); ++ printk(KERN_DEBUG PREFIX "Invalid Power Resource to register!"); + return -ENODEV; + } + diff --git a/queue-3.4/ahci-add-alternate-identifier-for-the-88se9172.patch b/queue-3.4/ahci-add-alternate-identifier-for-the-88se9172.patch new file mode 100644 index 00000000000..dae256f94d9 --- /dev/null +++ b/queue-3.4/ahci-add-alternate-identifier-for-the-88se9172.patch @@ -0,0 +1,32 @@ +From 17c60c6b763cb5b83b0185e7d38d01d18e55a05a Mon Sep 17 00:00:00 2001 +From: Alan Cox +Date: Tue, 4 Sep 2012 16:07:18 +0100 +Subject: ahci: Add alternate identifier for the 88SE9172 + +From: Alan Cox + +commit 17c60c6b763cb5b83b0185e7d38d01d18e55a05a upstream. + +This can also appear as 0x9192. Reported in bugzilla and confirmed with the +board documentation for these boards. + +Resolves-bug: https://bugzilla.kernel.org/show_bug.cgi?id=42970 +Signed-off-by: Alan Cox +Signed-off-by: Jeff Garzik +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/ata/ahci.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/ata/ahci.c ++++ b/drivers/ata/ahci.c +@@ -396,6 +396,8 @@ static const struct pci_device_id ahci_p + .driver_data = board_ahci_yes_fbs }, /* 88se9125 */ + { PCI_DEVICE(0x1b4b, 0x917a), + .driver_data = board_ahci_yes_fbs }, /* 88se9172 */ ++ { PCI_DEVICE(0x1b4b, 0x9192), ++ .driver_data = board_ahci_yes_fbs }, /* 88se9172 on some Gigabyte */ + { PCI_DEVICE(0x1b4b, 0x91a3), + .driver_data = board_ahci_yes_fbs }, + diff --git a/queue-3.4/digsig-add-hash-size-comparision-on-signature-verification.patch b/queue-3.4/digsig-add-hash-size-comparision-on-signature-verification.patch new file mode 100644 index 00000000000..8d78ec1a83f --- /dev/null +++ b/queue-3.4/digsig-add-hash-size-comparision-on-signature-verification.patch @@ -0,0 +1,40 @@ +From bc01637a80f5b670bd70a0279d3f93fa8de1c96d Mon Sep 17 00:00:00 2001 +From: Dmitry Kasatkin +Date: Wed, 12 Sep 2012 13:26:55 +0300 +Subject: digsig: add hash size comparision on signature verification + +From: Dmitry Kasatkin + +commit bc01637a80f5b670bd70a0279d3f93fa8de1c96d upstream. + +When pkcs_1_v1_5_decode_emsa() returns without error and hash sizes do +not match, hash comparision is not done and digsig_verify_rsa() returns +no error. This is a bug and this patch fixes it. + +The bug was introduced in v3.3 by commit b35e286a640f ("lib/digsig: +pkcs_1_v1_5_decode_emsa cleanup"). + +Signed-off-by: Dmitry Kasatkin +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + lib/digsig.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/lib/digsig.c ++++ b/lib/digsig.c +@@ -163,9 +163,11 @@ static int digsig_verify_rsa(struct key + memcpy(out1 + head, p, l); + + err = pkcs_1_v1_5_decode_emsa(out1, len, mblen, out2, &len); ++ if (err) ++ goto err; + +- if (!err && len == hlen) +- err = memcmp(out2, h, hlen); ++ if (len != hlen || memcmp(out2, h, hlen)) ++ err = -EINVAL; + + err: + mpi_free(in); diff --git a/queue-3.4/fs-proc-fix-potential-unregister_sysctl_table-hang.patch b/queue-3.4/fs-proc-fix-potential-unregister_sysctl_table-hang.patch new file mode 100644 index 00000000000..dd6f1f5e161 --- /dev/null +++ b/queue-3.4/fs-proc-fix-potential-unregister_sysctl_table-hang.patch @@ -0,0 +1,55 @@ +From 6bf6104573482570f7103d3e5ddf9574db43a363 Mon Sep 17 00:00:00 2001 +From: Francesco Ruggeri +Date: Thu, 13 Sep 2012 15:03:37 -0700 +Subject: fs/proc: fix potential unregister_sysctl_table hang + +From: Francesco Ruggeri + +commit 6bf6104573482570f7103d3e5ddf9574db43a363 upstream. + +The unregister_sysctl_table() function hangs if all references to its +ctl_table_header structure are not dropped. + +This can happen sometimes because of a leak in proc_sys_lookup(): +proc_sys_lookup() gets a reference to the table via lookup_entry(), but +it does not release it when a subsequent call to sysctl_follow_link() +fails. + +This patch fixes this leak by making sure the reference is always +dropped on return. + +See also commit 076c3eed2c31 ("sysctl: Rewrite proc_sys_lookup +introducing find_entry and lookup_entry") which reorganized this code in +3.4. + +Tested in Linux 3.4.4. + +Signed-off-by: Francesco Ruggeri +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + fs/proc/proc_sysctl.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +--- a/fs/proc/proc_sysctl.c ++++ b/fs/proc/proc_sysctl.c +@@ -462,9 +462,6 @@ static struct dentry *proc_sys_lookup(st + + err = ERR_PTR(-ENOMEM); + inode = proc_sys_make_inode(dir->i_sb, h ? h : head, p); +- if (h) +- sysctl_head_finish(h); +- + if (!inode) + goto out; + +@@ -473,6 +470,8 @@ static struct dentry *proc_sys_lookup(st + d_add(dentry, inode); + + out: ++ if (h) ++ sysctl_head_finish(h); + sysctl_head_finish(head); + return err; + } diff --git a/queue-3.4/kobject-fix-oops-with-input0-bad-kobj_uevent_env-content-in-show_uevent.patch b/queue-3.4/kobject-fix-oops-with-input0-bad-kobj_uevent_env-content-in-show_uevent.patch new file mode 100644 index 00000000000..c8dc5113c5a --- /dev/null +++ b/queue-3.4/kobject-fix-oops-with-input0-bad-kobj_uevent_env-content-in-show_uevent.patch @@ -0,0 +1,75 @@ +From 60e233a56609fd963c59e99bd75c663d63fa91b6 Mon Sep 17 00:00:00 2001 +From: Bjørn Mork +Date: Sun, 2 Sep 2012 15:41:34 +0200 +Subject: kobject: fix oops with "input0: bad kobj_uevent_env content in show_uevent()" + +From: Bjørn Mork + +commit 60e233a56609fd963c59e99bd75c663d63fa91b6 upstream. + +Fengguang Wu writes: + +> After the __devinit* removal series, I can still get kernel panic in +> show_uevent(). So there are more sources of bug.. +> +> Debug patch: +> +> @@ -343,8 +343,11 @@ static ssize_t show_uevent(struct device +> goto out; +> +> /* copy keys to file */ +> - for (i = 0; i < env->envp_idx; i++) +> + dev_err(dev, "uevent %d env[%d]: %s/.../%s\n", env->buflen, env->envp_idx, top_kobj->name, dev->kobj.name); +> + for (i = 0; i < env->envp_idx; i++) { +> + printk(KERN_ERR "uevent %d env[%d]: %s\n", (int)count, i, env->envp[i]); +> count += sprintf(&buf[count], "%s\n", env->envp[i]); +> + } +> +> Oops message, the env[] is again not properly initilized: +> +> [ 44.068623] input input0: uevent 61 env[805306368]: input0/.../input0 +> [ 44.069552] uevent 0 env[0]: (null) + +This is a completely different CONFIG_HOTPLUG problem, only +demonstrating another reason why CONFIG_HOTPLUG should go away. I had a +hard time trying to disable it anyway ;-) + +The problem this time is lots of code assuming that a call to +add_uevent_var() will guarantee that env->buflen > 0. This is not true +if CONFIG_HOTPLUG is unset. So things like this end up overwriting +env->envp_idx because the array index is -1: + + if (add_uevent_var(env, "MODALIAS=")) + return -ENOMEM; + len = input_print_modalias(&env->buf[env->buflen - 1], + sizeof(env->buf) - env->buflen, + dev, 0); + +Don't know what the best action is, given that there seem to be a *lot* +of this around the kernel. This patch "fixes" the problem for me, but I +don't know if it can be considered an appropriate fix. + +[ It is the correct fix for now, for 3.7 forcing CONFIG_HOTPLUG to +always be on is the longterm fix, but it's too late for 3.6 and older +kernels to resolve this that way - gregkh ] + +Reported-by: Fengguang Wu +Signed-off-by: Bjørn Mork +Tested-by: Fengguang Wu +Signed-off-by: Greg Kroah-Hartman + +--- + include/linux/kobject.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/include/linux/kobject.h ++++ b/include/linux/kobject.h +@@ -224,7 +224,7 @@ static inline int kobject_uevent_env(str + + static inline __printf(2, 3) + int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...) +-{ return 0; } ++{ return -ENOMEM; } + + static inline int kobject_action_type(const char *buf, size_t count, + enum kobject_action *type) diff --git a/queue-3.4/mmc-card-skip-secure-erase-on-movinand-causes-unrecoverable-corruption.patch b/queue-3.4/mmc-card-skip-secure-erase-on-movinand-causes-unrecoverable-corruption.patch new file mode 100644 index 00000000000..b1d4218a4fa --- /dev/null +++ b/queue-3.4/mmc-card-skip-secure-erase-on-movinand-causes-unrecoverable-corruption.patch @@ -0,0 +1,93 @@ +From 3550ccdb9d8d350e526b809bf3dd92b550a74fe1 Mon Sep 17 00:00:00 2001 +From: Ian Chen +Date: Wed, 29 Aug 2012 15:05:36 +0900 +Subject: mmc: card: Skip secure erase on MoviNAND; causes unrecoverable corruption. + +From: Ian Chen + +commit 3550ccdb9d8d350e526b809bf3dd92b550a74fe1 upstream. + +For several MoviNAND eMMC parts, there are known issues with secure +erase and secure trim. For these specific MoviNAND devices, we skip +these operations. + +Specifically, there is a bug in the eMMC firmware that causes +unrecoverable corruption when the MMC is erased with MMC_CAP_ERASE +enabled. + +References: + +http://forum.xda-developers.com/showthread.php?t=1644364 +https://plus.google.com/111398485184813224730/posts/21pTYfTsCkB#111398485184813224730/posts/21pTYfTsCkB + +Signed-off-by: Ian Chen +Reviewed-by: Namjae Jeon +Acked-by: Jaehoon Chung +Reviewed-by: Linus Walleij +Signed-off-by: Chris Ball +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/mmc/card/block.c | 26 +++++++++++++++++++++++++- + include/linux/mmc/card.h | 1 + + 2 files changed, 26 insertions(+), 1 deletion(-) + +--- a/drivers/mmc/card/block.c ++++ b/drivers/mmc/card/block.c +@@ -1430,7 +1430,8 @@ static int mmc_blk_issue_rq(struct mmc_q + /* complete ongoing async transfer before issuing discard */ + if (card->host->areq) + mmc_blk_issue_rw_rq(mq, NULL); +- if (req->cmd_flags & REQ_SECURE) ++ if (req->cmd_flags & REQ_SECURE && ++ !(card->quirks & MMC_QUIRK_SEC_ERASE_TRIM_BROKEN)) + ret = mmc_blk_issue_secdiscard_rq(mq, req); + else + ret = mmc_blk_issue_discard_rq(mq, req); +@@ -1730,6 +1731,7 @@ force_ro_fail: + #define CID_MANFID_SANDISK 0x2 + #define CID_MANFID_TOSHIBA 0x11 + #define CID_MANFID_MICRON 0x13 ++#define CID_MANFID_SAMSUNG 0x15 + + static const struct mmc_fixup blk_fixups[] = + { +@@ -1766,6 +1768,28 @@ static const struct mmc_fixup blk_fixups + MMC_FIXUP(CID_NAME_ANY, CID_MANFID_MICRON, 0x200, add_quirk_mmc, + MMC_QUIRK_LONG_READ_TIME), + ++ /* ++ * On these Samsung MoviNAND parts, performing secure erase or ++ * secure trim can result in unrecoverable corruption due to a ++ * firmware bug. ++ */ ++ MMC_FIXUP("M8G2FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, ++ MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), ++ MMC_FIXUP("MAG4FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, ++ MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), ++ MMC_FIXUP("MBG8FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, ++ MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), ++ MMC_FIXUP("MCGAFA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, ++ MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), ++ MMC_FIXUP("VAL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, ++ MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), ++ MMC_FIXUP("VYL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, ++ MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), ++ MMC_FIXUP("KYL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, ++ MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), ++ MMC_FIXUP("VZL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, ++ MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), ++ + END_FIXUP + }; + +--- a/include/linux/mmc/card.h ++++ b/include/linux/mmc/card.h +@@ -234,6 +234,7 @@ struct mmc_card { + #define MMC_QUIRK_BLK_NO_CMD23 (1<<7) /* Avoid CMD23 for regular multiblock */ + #define MMC_QUIRK_BROKEN_BYTE_MODE_512 (1<<8) /* Avoid sending 512 bytes in */ + #define MMC_QUIRK_LONG_READ_TIME (1<<9) /* Data read time > CSD says */ ++#define MMC_QUIRK_SEC_ERASE_TRIM_BROKEN (1<<10) /* Skip secure for erase/trim */ + /* byte mode */ + unsigned int poweroff_notify_state; /* eMMC4.5 notify feature */ + #define MMC_NO_POWER_NOTIFICATION 0 diff --git a/queue-3.4/mmc-mxs-mmc-fix-deadlock-in-sdio-irq-case.patch b/queue-3.4/mmc-mxs-mmc-fix-deadlock-in-sdio-irq-case.patch new file mode 100644 index 00000000000..4b21acdac5c --- /dev/null +++ b/queue-3.4/mmc-mxs-mmc-fix-deadlock-in-sdio-irq-case.patch @@ -0,0 +1,93 @@ +From 1af36b2a993dddfa3d6860ec4879c9e8abc9b976 Mon Sep 17 00:00:00 2001 +From: Lauri Hintsala +Date: Tue, 17 Jul 2012 17:16:09 +0300 +Subject: mmc: mxs-mmc: fix deadlock in SDIO IRQ case + +From: Lauri Hintsala + +commit 1af36b2a993dddfa3d6860ec4879c9e8abc9b976 upstream. + +Release the lock before mmc_signal_sdio_irq is called by mxs_mmc_irq_handler. + +Backtrace: +[ 79.660000] ============================================= +[ 79.660000] [ INFO: possible recursive locking detected ] +[ 79.660000] 3.4.0-00009-g3e96082-dirty #11 Not tainted +[ 79.660000] --------------------------------------------- +[ 79.660000] swapper/0 is trying to acquire lock: +[ 79.660000] (&(&host->lock)->rlock#2){-.....}, at: [] mxs_mmc_enable_sdio_irq+0x18/0xd4 +[ 79.660000] +[ 79.660000] but task is already holding lock: +[ 79.660000] (&(&host->lock)->rlock#2){-.....}, at: [] mxs_mmc_irq_handler+0x1c/0xe8 +[ 79.660000] +[ 79.660000] other info that might help us debug this: +[ 79.660000] Possible unsafe locking scenario: +[ 79.660000] +[ 79.660000] CPU0 +[ 79.660000] ---- +[ 79.660000] lock(&(&host->lock)->rlock#2); +[ 79.660000] lock(&(&host->lock)->rlock#2); +[ 79.660000] +[ 79.660000] *** DEADLOCK *** +[ 79.660000] +[ 79.660000] May be due to missing lock nesting notation +[ 79.660000] +[ 79.660000] 1 lock held by swapper/0: +[ 79.660000] #0: (&(&host->lock)->rlock#2){-.....}, at: [] mxs_mmc_irq_handler+0x1c/0xe8 +[ 79.660000] +[ 79.660000] stack backtrace: +[ 79.660000] [] (unwind_backtrace+0x0/0xf4) from [] (__lock_acquire+0x1948/0x1d48) +[ 79.660000] [] (__lock_acquire+0x1948/0x1d48) from [] (lock_acquire+0xe0/0xf8) +[ 79.660000] [] (lock_acquire+0xe0/0xf8) from [] (_raw_spin_lock_irqsave+0x44/0x58) +[ 79.660000] [] (_raw_spin_lock_irqsave+0x44/0x58) from [] (mxs_mmc_enable_sdio_irq+0x18/0xd4) +[ 79.660000] [] (mxs_mmc_enable_sdio_irq+0x18/0xd4) from [] (mxs_mmc_irq_handler+0xd4/0xe8) +[ 79.660000] [] (mxs_mmc_irq_handler+0xd4/0xe8) from [] (handle_irq_event_percpu+0x70/0x254) +[ 79.660000] [] (handle_irq_event_percpu+0x70/0x254) from [] (handle_irq_event+0x3c/0x5c) +[ 79.660000] [] (handle_irq_event+0x3c/0x5c) from [] (handle_level_irq+0x90/0x110) +[ 79.660000] [] (handle_level_irq+0x90/0x110) from [] (generic_handle_irq+0x38/0x50) +[ 79.660000] [] (generic_handle_irq+0x38/0x50) from [] (handle_IRQ+0x30/0x84) +[ 79.660000] [] (handle_IRQ+0x30/0x84) from [] (__irq_svc+0x38/0x60) +[ 79.660000] [] (__irq_svc+0x38/0x60) from [] (default_idle+0x2c/0x40) +[ 79.660000] [] (default_idle+0x2c/0x40) from [] (cpu_idle+0x64/0xcc) +[ 79.660000] [] (cpu_idle+0x64/0xcc) from [] (start_kernel+0x244/0x2c8) +[ 79.660000] BUG: spinlock lockup on CPU#0, swapper/0 +[ 79.660000] lock: c398cb2c, .magic: dead4ead, .owner: swapper/0, .owner_cpu: 0 +[ 79.660000] [] (unwind_backtrace+0x0/0xf4) from [] (do_raw_spin_lock+0xf0/0x144) +[ 79.660000] [] (do_raw_spin_lock+0xf0/0x144) from [] (_raw_spin_lock_irqsave+0x4c/0x58) +[ 79.660000] [] (_raw_spin_lock_irqsave+0x4c/0x58) from [] (mxs_mmc_enable_sdio_irq+0x18/0xd4) +[ 79.660000] [] (mxs_mmc_enable_sdio_irq+0x18/0xd4) from [] (mxs_mmc_irq_handler+0xd4/0xe8) +[ 79.660000] [] (mxs_mmc_irq_handler+0xd4/0xe8) from [] (handle_irq_event_percpu+0x70/0x254) +[ 79.660000] [] (handle_irq_event_percpu+0x70/0x254) from [] (handle_irq_event+0x3c/0x5c) +[ 79.660000] [] (handle_irq_event+0x3c/0x5c) from [] (handle_level_irq+0x90/0x110) +[ 79.660000] [] (handle_level_irq+0x90/0x110) from [] (generic_handle_irq+0x38/0x50) +[ 79.660000] [] (generic_handle_irq+0x38/0x50) from [] (handle_IRQ+0x30/0x84) +[ 79.660000] [] (handle_IRQ+0x30/0x84) from [] (__irq_svc+0x38/0x60) +[ 79.660000] [] (__irq_svc+0x38/0x60) from [] (default_idle+0x2c/0x40) +[ 79.660000] [] (default_idle+0x2c/0x40) from [] (cpu_idle+0x64/0xcc) +[ 79.660000] [] (cpu_idle+0x64/0xcc) from [] (start_kernel+0x244/0x2c8) + +Signed-off-by: Lauri Hintsala +Acked-by: Shawn Guo +Signed-off-by: Chris Ball +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/mmc/host/mxs-mmc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/mmc/host/mxs-mmc.c ++++ b/drivers/mmc/host/mxs-mmc.c +@@ -280,11 +280,11 @@ static irqreturn_t mxs_mmc_irq_handler(i + writel(stat & MXS_MMC_IRQ_BITS, + host->base + HW_SSP_CTRL1 + MXS_CLR_ADDR); + ++ spin_unlock(&host->lock); ++ + if ((stat & BM_SSP_CTRL1_SDIO_IRQ) && (stat & BM_SSP_CTRL1_SDIO_IRQ_EN)) + mmc_signal_sdio_irq(host->mmc); + +- spin_unlock(&host->lock); +- + if (stat & BM_SSP_CTRL1_RESP_TIMEOUT_IRQ) + cmd->error = -ETIMEDOUT; + else if (stat & BM_SSP_CTRL1_RESP_ERR_IRQ) diff --git a/queue-3.4/mmc-sdhci-esdhc-break-out-early-if-clock-is-0.patch b/queue-3.4/mmc-sdhci-esdhc-break-out-early-if-clock-is-0.patch new file mode 100644 index 00000000000..aece29821fa --- /dev/null +++ b/queue-3.4/mmc-sdhci-esdhc-break-out-early-if-clock-is-0.patch @@ -0,0 +1,43 @@ +From 74f330bceaa7b88d06062e1cac3d519a3dfc041e Mon Sep 17 00:00:00 2001 +From: Shawn Guo +Date: Wed, 22 Aug 2012 23:10:01 +0800 +Subject: mmc: sdhci-esdhc: break out early if clock is 0 + +From: Shawn Guo + +commit 74f330bceaa7b88d06062e1cac3d519a3dfc041e upstream. + +Since commit 30832ab56 ("mmc: sdhci: Always pass clock request value +zero to set_clock host op") was merged, esdhc_set_clock starts hitting +"if (clock == 0)" where ESDHC_SYSTEM_CONTROL has been operated. This +causes SDHCI card-detection function being broken. Fix the regression +by moving "if (clock == 0)" above ESDHC_SYSTEM_CONTROL operation. + +Signed-off-by: Shawn Guo +Signed-off-by: Chris Ball +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/mmc/host/sdhci-esdhc.h | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/mmc/host/sdhci-esdhc.h ++++ b/drivers/mmc/host/sdhci-esdhc.h +@@ -48,14 +48,14 @@ static inline void esdhc_set_clock(struc + int div = 1; + u32 temp; + ++ if (clock == 0) ++ goto out; ++ + temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); + temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN + | ESDHC_CLOCK_MASK); + sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); + +- if (clock == 0) +- goto out; +- + while (host->max_clk / pre_div / 16 > clock && pre_div < 256) + pre_div *= 2; + diff --git a/queue-3.4/oprofile-s390-fix-uninitialized-memory-access-when-writing-to-oprofilefs.patch b/queue-3.4/oprofile-s390-fix-uninitialized-memory-access-when-writing-to-oprofilefs.patch new file mode 100644 index 00000000000..07154b31eda --- /dev/null +++ b/queue-3.4/oprofile-s390-fix-uninitialized-memory-access-when-writing-to-oprofilefs.patch @@ -0,0 +1,71 @@ +From 81ff3478d9ba7f0b48b0abef740e542fd83adf79 Mon Sep 17 00:00:00 2001 +From: Robert Richter +Date: Thu, 19 Jul 2012 18:28:26 +0200 +Subject: oprofile, s390: Fix uninitialized memory access when writing to oprofilefs + +From: Robert Richter + +commit 81ff3478d9ba7f0b48b0abef740e542fd83adf79 upstream. + +If oprofilefs_ulong_from_user() is called with count equals zero, *val +remains unchanged. Depending on the implementation it might be +uninitialized. Fixing users of oprofilefs_ulong_ from_user(). + +We missed these s390 changes with: + + 913050b oprofile: Fix uninitialized memory access when writing to writing to oprofilefs + +Signed-off-by: Robert Richter +Signed-off-by: Greg Kroah-Hartman + +--- + arch/s390/oprofile/init.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +--- a/arch/s390/oprofile/init.c ++++ b/arch/s390/oprofile/init.c +@@ -171,7 +171,7 @@ static ssize_t hw_interval_write(struct + if (*offset) + return -EINVAL; + retval = oprofilefs_ulong_from_user(&val, buf, count); +- if (retval) ++ if (retval <= 0) + return retval; + if (val < oprofile_min_interval) + oprofile_hw_interval = oprofile_min_interval; +@@ -214,7 +214,7 @@ static ssize_t hwsampler_zero_write(stru + return -EINVAL; + + retval = oprofilefs_ulong_from_user(&val, buf, count); +- if (retval) ++ if (retval <= 0) + return retval; + if (val != 0) + return -EINVAL; +@@ -245,7 +245,7 @@ static ssize_t hwsampler_kernel_write(st + return -EINVAL; + + retval = oprofilefs_ulong_from_user(&val, buf, count); +- if (retval) ++ if (retval <= 0) + return retval; + + if (val != 0 && val != 1) +@@ -280,7 +280,7 @@ static ssize_t hwsampler_user_write(stru + return -EINVAL; + + retval = oprofilefs_ulong_from_user(&val, buf, count); +- if (retval) ++ if (retval <= 0) + return retval; + + if (val != 0 && val != 1) +@@ -319,7 +319,7 @@ static ssize_t timer_enabled_write(struc + return -EINVAL; + + retval = oprofilefs_ulong_from_user(&val, buf, count); +- if (retval) ++ if (retval <= 0) + return retval; + + if (val != 0 && val != 1) diff --git a/queue-3.4/perf_event-switch-to-internal-refcount-fix-race-with-close.patch b/queue-3.4/perf_event-switch-to-internal-refcount-fix-race-with-close.patch new file mode 100644 index 00000000000..614cdc0a99e --- /dev/null +++ b/queue-3.4/perf_event-switch-to-internal-refcount-fix-race-with-close.patch @@ -0,0 +1,217 @@ +From a6fa941d94b411bbd2b6421ffbde6db3c93e65ab Mon Sep 17 00:00:00 2001 +From: Al Viro +Date: Mon, 20 Aug 2012 14:59:25 +0100 +Subject: perf_event: Switch to internal refcount, fix race with close() + +From: Al Viro + +commit a6fa941d94b411bbd2b6421ffbde6db3c93e65ab upstream. + +Don't mess with file refcounts (or keep a reference to file, for +that matter) in perf_event. Use explicit refcount of its own +instead. Deal with the race between the final reference to event +going away and new children getting created for it by use of +atomic_long_inc_not_zero() in inherit_event(); just have the +latter free what it had allocated and return NULL, that works +out just fine (children of siblings of something doomed are +created as singletons, same as if the child of leader had been +created and immediately killed). + +Signed-off-by: Al Viro +Signed-off-by: Peter Zijlstra +Link: http://lkml.kernel.org/r/20120820135925.GG23464@ZenIV.linux.org.uk +Signed-off-by: Ingo Molnar +Signed-off-by: Greg Kroah-Hartman + +--- + include/linux/perf_event.h | 2 - + kernel/events/core.c | 62 +++++++++++++++++++++++---------------------- + 2 files changed, 34 insertions(+), 30 deletions(-) + +--- a/include/linux/perf_event.h ++++ b/include/linux/perf_event.h +@@ -925,7 +925,7 @@ struct perf_event { + struct hw_perf_event hw; + + struct perf_event_context *ctx; +- struct file *filp; ++ atomic_long_t refcount; + + /* + * These accumulate total time (in nanoseconds) that children +--- a/kernel/events/core.c ++++ b/kernel/events/core.c +@@ -2929,12 +2929,12 @@ EXPORT_SYMBOL_GPL(perf_event_release_ker + /* + * Called when the last reference to the file is gone. + */ +-static int perf_release(struct inode *inode, struct file *file) ++static void put_event(struct perf_event *event) + { +- struct perf_event *event = file->private_data; + struct task_struct *owner; + +- file->private_data = NULL; ++ if (!atomic_long_dec_and_test(&event->refcount)) ++ return; + + rcu_read_lock(); + owner = ACCESS_ONCE(event->owner); +@@ -2969,7 +2969,13 @@ static int perf_release(struct inode *in + put_task_struct(owner); + } + +- return perf_event_release_kernel(event); ++ perf_event_release_kernel(event); ++} ++ ++static int perf_release(struct inode *inode, struct file *file) ++{ ++ put_event(file->private_data); ++ return 0; + } + + u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running) +@@ -3222,7 +3228,7 @@ unlock: + + static const struct file_operations perf_fops; + +-static struct perf_event *perf_fget_light(int fd, int *fput_needed) ++static struct file *perf_fget_light(int fd, int *fput_needed) + { + struct file *file; + +@@ -3236,7 +3242,7 @@ static struct perf_event *perf_fget_ligh + return ERR_PTR(-EBADF); + } + +- return file->private_data; ++ return file; + } + + static int perf_event_set_output(struct perf_event *event, +@@ -3268,19 +3274,21 @@ static long perf_ioctl(struct file *file + + case PERF_EVENT_IOC_SET_OUTPUT: + { ++ struct file *output_file = NULL; + struct perf_event *output_event = NULL; + int fput_needed = 0; + int ret; + + if (arg != -1) { +- output_event = perf_fget_light(arg, &fput_needed); +- if (IS_ERR(output_event)) +- return PTR_ERR(output_event); ++ output_file = perf_fget_light(arg, &fput_needed); ++ if (IS_ERR(output_file)) ++ return PTR_ERR(output_file); ++ output_event = output_file->private_data; + } + + ret = perf_event_set_output(event, output_event); + if (output_event) +- fput_light(output_event->filp, fput_needed); ++ fput_light(output_file, fput_needed); + + return ret; + } +@@ -5920,6 +5928,7 @@ perf_event_alloc(struct perf_event_attr + + mutex_init(&event->mmap_mutex); + ++ atomic_long_set(&event->refcount, 1); + event->cpu = cpu; + event->attr = *attr; + event->group_leader = group_leader; +@@ -6230,12 +6239,12 @@ SYSCALL_DEFINE5(perf_event_open, + return event_fd; + + if (group_fd != -1) { +- group_leader = perf_fget_light(group_fd, &fput_needed); +- if (IS_ERR(group_leader)) { +- err = PTR_ERR(group_leader); ++ group_file = perf_fget_light(group_fd, &fput_needed); ++ if (IS_ERR(group_file)) { ++ err = PTR_ERR(group_file); + goto err_fd; + } +- group_file = group_leader->filp; ++ group_leader = group_file->private_data; + if (flags & PERF_FLAG_FD_OUTPUT) + output_event = group_leader; + if (flags & PERF_FLAG_FD_NO_GROUP) +@@ -6370,7 +6379,6 @@ SYSCALL_DEFINE5(perf_event_open, + put_ctx(gctx); + } + +- event->filp = event_file; + WARN_ON_ONCE(ctx->parent_ctx); + mutex_lock(&ctx->mutex); + +@@ -6460,7 +6468,6 @@ perf_event_create_kernel_counter(struct + goto err_free; + } + +- event->filp = NULL; + WARN_ON_ONCE(ctx->parent_ctx); + mutex_lock(&ctx->mutex); + perf_install_in_context(ctx, event, cpu); +@@ -6509,7 +6516,7 @@ static void sync_child_event(struct perf + * Release the parent event, if this was the last + * reference to it. + */ +- fput(parent_event->filp); ++ put_event(parent_event); + } + + static void +@@ -6585,9 +6592,8 @@ static void perf_event_exit_task_context + * + * __perf_event_exit_task() + * sync_child_event() +- * fput(parent_event->filp) +- * perf_release() +- * mutex_lock(&ctx->mutex) ++ * put_event() ++ * mutex_lock(&ctx->mutex) + * + * But since its the parent context it won't be the same instance. + */ +@@ -6655,7 +6661,7 @@ static void perf_free_event(struct perf_ + list_del_init(&event->child_list); + mutex_unlock(&parent->child_mutex); + +- fput(parent->filp); ++ put_event(parent); + + perf_group_detach(event); + list_del_event(event, ctx); +@@ -6735,6 +6741,12 @@ inherit_event(struct perf_event *parent_ + NULL, NULL); + if (IS_ERR(child_event)) + return child_event; ++ ++ if (!atomic_long_inc_not_zero(&parent_event->refcount)) { ++ free_event(child_event); ++ return NULL; ++ } ++ + get_ctx(child_ctx); + + /* +@@ -6776,14 +6788,6 @@ inherit_event(struct perf_event *parent_ + raw_spin_unlock_irqrestore(&child_ctx->lock, flags); + + /* +- * Get a reference to the parent filp - we will fput it +- * when the child event exits. This is safe to do because +- * we are in the parent and we know that the filp still +- * exists and has a nonzero count: +- */ +- atomic_long_inc(&parent_event->filp->f_count); +- +- /* + * Link this into the parent event's child list + */ + WARN_ON_ONCE(parent_event->ctx->parent_ctx); diff --git a/queue-3.4/redefine-atomic_init-and-atomic64_init-to-drop-the-casts.patch b/queue-3.4/redefine-atomic_init-and-atomic64_init-to-drop-the-casts.patch new file mode 100644 index 00000000000..c8a39ad1b99 --- /dev/null +++ b/queue-3.4/redefine-atomic_init-and-atomic64_init-to-drop-the-casts.patch @@ -0,0 +1,51 @@ +From 67a806d9499353fabd5b5ff07337f3aa88a1c3ba Mon Sep 17 00:00:00 2001 +From: Mel Gorman +Date: Sun, 19 Aug 2012 14:41:03 +1200 +Subject: Redefine ATOMIC_INIT and ATOMIC64_INIT to drop the casts + +From: Mel Gorman + +commit 67a806d9499353fabd5b5ff07337f3aa88a1c3ba upstream. + +The following build error occurred during an alpha build: + + net/core/sock.c:274:36: error: initializer element is not constant + +Dave Anglin says: +> Here is the line in sock.i: +> +> struct static_key memalloc_socks = ((struct static_key) { .enabled = +> ((atomic_t) { (0) }) }); + +The above line contains two compound literals. It also uses a designated +initializer to initialize the field enabled. A compound literal is not a +constant expression. + +The location of the above statement isn't fully clear, but if a compound +literal occurs outside the body of a function, the initializer list must +consist of constant expressions. + +Signed-off-by: Mel Gorman +Signed-off-by: Fengguang Wu +Signed-off-by: Michael Cree +Acked-by: Matt Turner +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + arch/alpha/include/asm/atomic.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/arch/alpha/include/asm/atomic.h ++++ b/arch/alpha/include/asm/atomic.h +@@ -14,8 +14,8 @@ + */ + + +-#define ATOMIC_INIT(i) ( (atomic_t) { (i) } ) +-#define ATOMIC64_INIT(i) ( (atomic64_t) { (i) } ) ++#define ATOMIC_INIT(i) { (i) } ++#define ATOMIC64_INIT(i) { (i) } + + #define atomic_read(v) (*(volatile int *)&(v)->counter) + #define atomic64_read(v) (*(volatile long *)&(v)->counter) diff --git a/queue-3.4/series b/queue-3.4/series index a6488d70df2..d6d27845410 100644 --- a/queue-3.4/series +++ b/queue-3.4/series @@ -54,3 +54,17 @@ staging-vt6656-failed-connection-incorrect-endian.patch staging-r8712u-fix-bug-in-r8712_recv_indicatepkt.patch staging-comedi-das08-correct-ao-output-for-das08jr-16-ao.patch usb-option-replace-zte-k5006-z-entry-with-vendor-class-rule.patch +fs-proc-fix-potential-unregister_sysctl_table-hang.patch +sound-tegra_alc5632-remove-hp-detect-gpio-inversion.patch +perf_event-switch-to-internal-refcount-fix-race-with-close.patch +acpi-pm-fix-resource_lock-dead-lock-in-acpi_power_on_device.patch +acpi-pm-use-kern_debug-when-no-power-resources-are-found.patch +mmc-mxs-mmc-fix-deadlock-in-sdio-irq-case.patch +mmc-sdhci-esdhc-break-out-early-if-clock-is-0.patch +mmc-card-skip-secure-erase-on-movinand-causes-unrecoverable-corruption.patch +oprofile-s390-fix-uninitialized-memory-access-when-writing-to-oprofilefs.patch +ahci-add-alternate-identifier-for-the-88se9172.patch +kobject-fix-oops-with-input0-bad-kobj_uevent_env-content-in-show_uevent.patch +redefine-atomic_init-and-atomic64_init-to-drop-the-casts.patch +digsig-add-hash-size-comparision-on-signature-verification.patch +sunrpc-fix-a-udp-transport-regression.patch diff --git a/queue-3.4/sound-tegra_alc5632-remove-hp-detect-gpio-inversion.patch b/queue-3.4/sound-tegra_alc5632-remove-hp-detect-gpio-inversion.patch new file mode 100644 index 00000000000..f5b81922ee1 --- /dev/null +++ b/queue-3.4/sound-tegra_alc5632-remove-hp-detect-gpio-inversion.patch @@ -0,0 +1,32 @@ +From c921928661eda599d73a6a86e58bdd5aecfa18cb Mon Sep 17 00:00:00 2001 +From: Stephen Warren +Date: Fri, 24 Aug 2012 21:20:15 -0600 +Subject: sound: tegra_alc5632: remove HP detect GPIO inversion + +From: Stephen Warren + +commit c921928661eda599d73a6a86e58bdd5aecfa18cb upstream. + +Both the schematics and practical testing show that the HP detect GPIO +is high when the headphones are plugged in. Hence, the snd_soc_jack_gpio +should not specify to invert the signal. + +Signed-off-by: Stephen Warren +Acked-by: Andrey Danin +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman + +--- + sound/soc/tegra/tegra_alc5632.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/sound/soc/tegra/tegra_alc5632.c ++++ b/sound/soc/tegra/tegra_alc5632.c +@@ -95,7 +95,6 @@ static struct snd_soc_jack_gpio tegra_al + .name = "Headset detection", + .report = SND_JACK_HEADSET, + .debounce_time = 150, +- .invert = 1, + }; + + static const struct snd_soc_dapm_widget tegra_alc5632_dapm_widgets[] = { diff --git a/queue-3.4/sunrpc-fix-a-udp-transport-regression.patch b/queue-3.4/sunrpc-fix-a-udp-transport-regression.patch new file mode 100644 index 00000000000..e6ba96bf484 --- /dev/null +++ b/queue-3.4/sunrpc-fix-a-udp-transport-regression.patch @@ -0,0 +1,155 @@ +From f39c1bfb5a03e2d255451bff05be0d7255298fa4 Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Fri, 7 Sep 2012 11:08:50 -0400 +Subject: SUNRPC: Fix a UDP transport regression + +From: Trond Myklebust + +commit f39c1bfb5a03e2d255451bff05be0d7255298fa4 upstream. + +Commit 43cedbf0e8dfb9c5610eb7985d5f21263e313802 (SUNRPC: Ensure that +we grab the XPRT_LOCK before calling xprt_alloc_slot) is causing +hangs in the case of NFS over UDP mounts. + +Since neither the UDP or the RDMA transport mechanism use dynamic slot +allocation, we can skip grabbing the socket lock for those transports. +Add a new rpc_xprt_op to allow switching between the TCP and UDP/RDMA +case. + +Note that the NFSv4.1 back channel assigns the slot directly +through rpc_run_bc_task, so we can ignore that case. + +Reported-by: Dick Streefland +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman + +--- + include/linux/sunrpc/xprt.h | 3 +++ + net/sunrpc/xprt.c | 34 ++++++++++++++++++++-------------- + net/sunrpc/xprtrdma/transport.c | 1 + + net/sunrpc/xprtsock.c | 3 +++ + 4 files changed, 27 insertions(+), 14 deletions(-) + +--- a/include/linux/sunrpc/xprt.h ++++ b/include/linux/sunrpc/xprt.h +@@ -114,6 +114,7 @@ struct rpc_xprt_ops { + void (*set_buffer_size)(struct rpc_xprt *xprt, size_t sndsize, size_t rcvsize); + int (*reserve_xprt)(struct rpc_xprt *xprt, struct rpc_task *task); + void (*release_xprt)(struct rpc_xprt *xprt, struct rpc_task *task); ++ void (*alloc_slot)(struct rpc_xprt *xprt, struct rpc_task *task); + void (*rpcbind)(struct rpc_task *task); + void (*set_port)(struct rpc_xprt *xprt, unsigned short port); + void (*connect)(struct rpc_task *task); +@@ -279,6 +280,8 @@ void xprt_connect(struct rpc_task *tas + void xprt_reserve(struct rpc_task *task); + int xprt_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task); + int xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task); ++void xprt_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task); ++void xprt_lock_and_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task); + int xprt_prepare_transmit(struct rpc_task *task); + void xprt_transmit(struct rpc_task *task); + void xprt_end_transmit(struct rpc_task *task); +--- a/net/sunrpc/xprt.c ++++ b/net/sunrpc/xprt.c +@@ -969,11 +969,11 @@ static bool xprt_dynamic_free_slot(struc + return false; + } + +-static void xprt_alloc_slot(struct rpc_task *task) ++void xprt_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task) + { +- struct rpc_xprt *xprt = task->tk_xprt; + struct rpc_rqst *req; + ++ spin_lock(&xprt->reserve_lock); + if (!list_empty(&xprt->free)) { + req = list_entry(xprt->free.next, struct rpc_rqst, rq_list); + list_del(&req->rq_list); +@@ -994,12 +994,29 @@ static void xprt_alloc_slot(struct rpc_t + default: + task->tk_status = -EAGAIN; + } ++ spin_unlock(&xprt->reserve_lock); + return; + out_init_req: + task->tk_status = 0; + task->tk_rqstp = req; + xprt_request_init(task, xprt); ++ spin_unlock(&xprt->reserve_lock); ++} ++EXPORT_SYMBOL_GPL(xprt_alloc_slot); ++ ++void xprt_lock_and_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task) ++{ ++ /* Note: grabbing the xprt_lock_write() ensures that we throttle ++ * new slot allocation if the transport is congested (i.e. when ++ * reconnecting a stream transport or when out of socket write ++ * buffer space). ++ */ ++ if (xprt_lock_write(xprt, task)) { ++ xprt_alloc_slot(xprt, task); ++ xprt_release_write(xprt, task); ++ } + } ++EXPORT_SYMBOL_GPL(xprt_lock_and_alloc_slot); + + static void xprt_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req) + { +@@ -1083,20 +1100,9 @@ void xprt_reserve(struct rpc_task *task) + if (task->tk_rqstp != NULL) + return; + +- /* Note: grabbing the xprt_lock_write() here is not strictly needed, +- * but ensures that we throttle new slot allocation if the transport +- * is congested (e.g. if reconnecting or if we're out of socket +- * write buffer space). +- */ + task->tk_timeout = 0; + task->tk_status = -EAGAIN; +- if (!xprt_lock_write(xprt, task)) +- return; +- +- spin_lock(&xprt->reserve_lock); +- xprt_alloc_slot(task); +- spin_unlock(&xprt->reserve_lock); +- xprt_release_write(xprt, task); ++ xprt->ops->alloc_slot(xprt, task); + } + + static inline __be32 xprt_alloc_xid(struct rpc_xprt *xprt) +--- a/net/sunrpc/xprtrdma/transport.c ++++ b/net/sunrpc/xprtrdma/transport.c +@@ -713,6 +713,7 @@ static void xprt_rdma_print_stats(struct + static struct rpc_xprt_ops xprt_rdma_procs = { + .reserve_xprt = xprt_rdma_reserve_xprt, + .release_xprt = xprt_release_xprt_cong, /* sunrpc/xprt.c */ ++ .alloc_slot = xprt_alloc_slot, + .release_request = xprt_release_rqst_cong, /* ditto */ + .set_retrans_timeout = xprt_set_retrans_timeout_def, /* ditto */ + .rpcbind = rpcb_getport_async, /* sunrpc/rpcb_clnt.c */ +--- a/net/sunrpc/xprtsock.c ++++ b/net/sunrpc/xprtsock.c +@@ -2433,6 +2433,7 @@ static void bc_destroy(struct rpc_xprt * + static struct rpc_xprt_ops xs_local_ops = { + .reserve_xprt = xprt_reserve_xprt, + .release_xprt = xs_tcp_release_xprt, ++ .alloc_slot = xprt_alloc_slot, + .rpcbind = xs_local_rpcbind, + .set_port = xs_local_set_port, + .connect = xs_connect, +@@ -2449,6 +2450,7 @@ static struct rpc_xprt_ops xs_udp_ops = + .set_buffer_size = xs_udp_set_buffer_size, + .reserve_xprt = xprt_reserve_xprt_cong, + .release_xprt = xprt_release_xprt_cong, ++ .alloc_slot = xprt_alloc_slot, + .rpcbind = rpcb_getport_async, + .set_port = xs_set_port, + .connect = xs_connect, +@@ -2466,6 +2468,7 @@ static struct rpc_xprt_ops xs_udp_ops = + static struct rpc_xprt_ops xs_tcp_ops = { + .reserve_xprt = xprt_reserve_xprt, + .release_xprt = xs_tcp_release_xprt, ++ .alloc_slot = xprt_lock_and_alloc_slot, + .rpcbind = rpcb_getport_async, + .set_port = xs_set_port, + .connect = xs_connect,