From: Greg Kroah-Hartman Date: Tue, 31 Jul 2012 20:03:57 +0000 (-0700) Subject: 3.0-stable patches X-Git-Tag: v3.0.39~11 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=f417b72036d3d6f7e63e69671f6cf463a9b08046;p=thirdparty%2Fkernel%2Fstable-queue.git 3.0-stable patches added patches: arm-omap2-opp-fix-to-ensure-check-of-right-oppdef-after-bad-one.patch scsi-avoid-dangling-pointer-in-scsi_requeue_command.patch scsi-fix-eh-wakeup-scsi_schedule_eh-vs-scsi_restart_operations.patch scsi-fix-hot-unplug-vs-async-scan-race.patch scsi-libsas-continue-revalidation.patch scsi-libsas-fix-sas_discover_devices-return-code-handling.patch --- diff --git a/queue-3.0/arm-omap2-opp-fix-to-ensure-check-of-right-oppdef-after-bad-one.patch b/queue-3.0/arm-omap2-opp-fix-to-ensure-check-of-right-oppdef-after-bad-one.patch new file mode 100644 index 00000000000..6ccb712f385 --- /dev/null +++ b/queue-3.0/arm-omap2-opp-fix-to-ensure-check-of-right-oppdef-after-bad-one.patch @@ -0,0 +1,57 @@ +From b110547e586eb5825bc1d04aa9147bff83b57672 Mon Sep 17 00:00:00 2001 +From: Nishanth Menon +Date: Fri, 18 May 2012 12:26:19 -0500 +Subject: ARM: OMAP2+: OPP: Fix to ensure check of right oppdef after bad one + +From: Nishanth Menon + +commit b110547e586eb5825bc1d04aa9147bff83b57672 upstream. + +Commit 9fa2df6b90786301b175e264f5fa9846aba81a65 +(ARM: OMAP2+: OPP: allow OPP enumeration to continue if device is not present) +makes the logic: +for (i = 0; i < opp_def_size; i++) { + + if (!oh || !oh->od) { + + continue; + } + +opp_def++; +} + +In short, the moment we hit a "Bad OPP", we end up looping the list +comparing against the bad opp definition pointer for the rest of the +iteration count. Instead, increment opp_def in the for loop itself +and allow continue to be used in code without much thought so that +we check the next set of OPP definition pointers :) + +Cc: Steve Sakoman +Cc: Tony Lindgren +Signed-off-by: Nishanth Menon +Signed-off-by: Kevin Hilman +Signed-off-by: Greg Kroah-Hartman + +--- + arch/arm/mach-omap2/opp.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/arch/arm/mach-omap2/opp.c ++++ b/arch/arm/mach-omap2/opp.c +@@ -53,7 +53,7 @@ int __init omap_init_opp_table(struct om + omap_table_init = 1; + + /* Lets now register with OPP library */ +- for (i = 0; i < opp_def_size; i++) { ++ for (i = 0; i < opp_def_size; i++, opp_def++) { + struct omap_hwmod *oh; + struct device *dev; + +@@ -86,7 +86,6 @@ int __init omap_init_opp_table(struct om + __func__, opp_def->freq, + opp_def->hwmod_name, i, r); + } +- opp_def++; + } + + return 0; diff --git a/queue-3.0/scsi-avoid-dangling-pointer-in-scsi_requeue_command.patch b/queue-3.0/scsi-avoid-dangling-pointer-in-scsi_requeue_command.patch new file mode 100644 index 00000000000..38935823020 --- /dev/null +++ b/queue-3.0/scsi-avoid-dangling-pointer-in-scsi_requeue_command.patch @@ -0,0 +1,55 @@ +From 940f5d47e2f2e1fa00443921a0abf4822335b54d Mon Sep 17 00:00:00 2001 +From: Bart Van Assche +Date: Fri, 29 Jun 2012 15:34:26 +0000 +Subject: SCSI: Avoid dangling pointer in scsi_requeue_command() + +From: Bart Van Assche + +commit 940f5d47e2f2e1fa00443921a0abf4822335b54d upstream. + +When we call scsi_unprep_request() the command associated with the request +gets destroyed and therefore drops its reference on the device. If this was +the only reference, the device may get released and we end up with a NULL +pointer deref when we call blk_requeue_request. + +Reported-by: Mike Christie +Signed-off-by: Bart Van Assche +Reviewed-by: Mike Christie +Reviewed-by: Tejun Heo +[jejb: enhance commend and add commit log for stable] +Signed-off-by: James Bottomley +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/scsi/scsi_lib.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +--- a/drivers/scsi/scsi_lib.c ++++ b/drivers/scsi/scsi_lib.c +@@ -481,15 +481,26 @@ void scsi_requeue_run_queue(struct work_ + */ + static void scsi_requeue_command(struct request_queue *q, struct scsi_cmnd *cmd) + { ++ struct scsi_device *sdev = cmd->device; + struct request *req = cmd->request; + unsigned long flags; + ++ /* ++ * We need to hold a reference on the device to avoid the queue being ++ * killed after the unlock and before scsi_run_queue is invoked which ++ * may happen because scsi_unprep_request() puts the command which ++ * releases its reference on the device. ++ */ ++ get_device(&sdev->sdev_gendev); ++ + spin_lock_irqsave(q->queue_lock, flags); + scsi_unprep_request(req); + blk_requeue_request(q, req); + spin_unlock_irqrestore(q->queue_lock, flags); + + scsi_run_queue(q); ++ ++ put_device(&sdev->sdev_gendev); + } + + void scsi_next_command(struct scsi_cmnd *cmd) diff --git a/queue-3.0/scsi-fix-eh-wakeup-scsi_schedule_eh-vs-scsi_restart_operations.patch b/queue-3.0/scsi-fix-eh-wakeup-scsi_schedule_eh-vs-scsi_restart_operations.patch new file mode 100644 index 00000000000..bf098cea774 --- /dev/null +++ b/queue-3.0/scsi-fix-eh-wakeup-scsi_schedule_eh-vs-scsi_restart_operations.patch @@ -0,0 +1,59 @@ +From 57fc2e335fd3c2f898ee73570dc81426c28dc7b4 Mon Sep 17 00:00:00 2001 +From: Dan Williams +Date: Thu, 21 Jun 2012 23:25:32 -0700 +Subject: SCSI: fix eh wakeup (scsi_schedule_eh vs scsi_restart_operations) + +From: Dan Williams + +commit 57fc2e335fd3c2f898ee73570dc81426c28dc7b4 upstream. + +Rapid ata hotplug on a libsas controller results in cases where libsas +is waiting indefinitely on eh to perform an ata probe. + +A race exists between scsi_schedule_eh() and scsi_restart_operations() +in the case when scsi_restart_operations() issues i/o to other devices +in the sas domain. When this happens the host state transitions from +SHOST_RECOVERY (set by scsi_schedule_eh) back to SHOST_RUNNING and +->host_busy is non-zero so we put the eh thread to sleep even though +->host_eh_scheduled is active. + +Before putting the error handler to sleep we need to check if the +host_state needs to return to SHOST_RECOVERY for another trip through +eh. Since i/o that is released by scsi_restart_operations has been +blocked for at least one eh cycle, this implementation allows those +i/o's to run before another eh cycle starts to discourage hung task +timeouts. + +Reported-by: Tom Jackson +Tested-by: Tom Jackson +Signed-off-by: Dan Williams +Signed-off-by: James Bottomley +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/scsi/scsi_error.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +--- a/drivers/scsi/scsi_error.c ++++ b/drivers/scsi/scsi_error.c +@@ -1665,6 +1665,20 @@ static void scsi_restart_operations(stru + * requests are started. + */ + scsi_run_host_queues(shost); ++ ++ /* ++ * if eh is active and host_eh_scheduled is pending we need to re-run ++ * recovery. we do this check after scsi_run_host_queues() to allow ++ * everything pent up since the last eh run a chance to make forward ++ * progress before we sync again. Either we'll immediately re-run ++ * recovery or scsi_device_unbusy() will wake us again when these ++ * pending commands complete. ++ */ ++ spin_lock_irqsave(shost->host_lock, flags); ++ if (shost->host_eh_scheduled) ++ if (scsi_host_set_state(shost, SHOST_RECOVERY)) ++ WARN_ON(scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY)); ++ spin_unlock_irqrestore(shost->host_lock, flags); + } + + /** diff --git a/queue-3.0/scsi-fix-hot-unplug-vs-async-scan-race.patch b/queue-3.0/scsi-fix-hot-unplug-vs-async-scan-race.patch new file mode 100644 index 00000000000..f4dc800249a --- /dev/null +++ b/queue-3.0/scsi-fix-hot-unplug-vs-async-scan-race.patch @@ -0,0 +1,118 @@ +From 3b661a92e869ebe2358de8f4b3230ad84f7fce51 Mon Sep 17 00:00:00 2001 +From: Dan Williams +Date: Thu, 21 Jun 2012 23:47:28 -0700 +Subject: SCSI: fix hot unplug vs async scan race + +From: Dan Williams + +commit 3b661a92e869ebe2358de8f4b3230ad84f7fce51 upstream. + +The following crash results from cases where the end_device has been +removed before scsi_sysfs_add_sdev has had a chance to run. + + BUG: unable to handle kernel NULL pointer dereference at 0000000000000098 + IP: [] sysfs_create_dir+0x32/0xb6 + ... + Call Trace: + [] kobject_add_internal+0x120/0x1e3 + [] ? trace_hardirqs_on+0xd/0xf + [] kobject_add_varg+0x41/0x50 + [] kobject_add+0x64/0x66 + [] device_add+0x12d/0x63a + [] ? _raw_spin_unlock_irqrestore+0x47/0x56 + [] ? module_refcount+0x89/0xa0 + [] scsi_sysfs_add_sdev+0x4e/0x28a + [] do_scan_async+0x9c/0x145 + +...teach scsi_sysfs_add_devices() to check for deleted devices() before +trying to add them, and teach scsi_remove_target() how to remove targets +that have not been added via device_add(). + +Reported-by: Dariusz Majchrzak +Signed-off-by: Dan Williams +Signed-off-by: James Bottomley +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/scsi/scsi_scan.c | 3 +++ + drivers/scsi/scsi_sysfs.c | 41 ++++++++++++++++++++++++++--------------- + 2 files changed, 29 insertions(+), 15 deletions(-) + +--- a/drivers/scsi/scsi_scan.c ++++ b/drivers/scsi/scsi_scan.c +@@ -1710,6 +1710,9 @@ static void scsi_sysfs_add_devices(struc + { + struct scsi_device *sdev; + shost_for_each_device(sdev, shost) { ++ /* target removed before the device could be added */ ++ if (sdev->sdev_state == SDEV_DEL) ++ continue; + if (!scsi_host_scan_allowed(shost) || + scsi_sysfs_add_sdev(sdev) != 0) + __scsi_remove_device(sdev); +--- a/drivers/scsi/scsi_sysfs.c ++++ b/drivers/scsi/scsi_sysfs.c +@@ -962,7 +962,6 @@ static void __scsi_remove_target(struct + struct scsi_device *sdev; + + spin_lock_irqsave(shost->host_lock, flags); +- starget->reap_ref++; + restart: + list_for_each_entry(sdev, &shost->__devices, siblings) { + if (sdev->channel != starget->channel || +@@ -976,14 +975,6 @@ static void __scsi_remove_target(struct + goto restart; + } + spin_unlock_irqrestore(shost->host_lock, flags); +- scsi_target_reap(starget); +-} +- +-static int __remove_child (struct device * dev, void * data) +-{ +- if (scsi_is_target_device(dev)) +- __scsi_remove_target(to_scsi_target(dev)); +- return 0; + } + + /** +@@ -996,14 +987,34 @@ static int __remove_child (struct device + */ + void scsi_remove_target(struct device *dev) + { +- if (scsi_is_target_device(dev)) { +- __scsi_remove_target(to_scsi_target(dev)); +- return; ++ struct Scsi_Host *shost = dev_to_shost(dev->parent); ++ struct scsi_target *starget, *found; ++ unsigned long flags; ++ ++ restart: ++ found = NULL; ++ spin_lock_irqsave(shost->host_lock, flags); ++ list_for_each_entry(starget, &shost->__targets, siblings) { ++ if (starget->state == STARGET_DEL) ++ continue; ++ if (starget->dev.parent == dev || &starget->dev == dev) { ++ found = starget; ++ found->reap_ref++; ++ break; ++ } + } ++ spin_unlock_irqrestore(shost->host_lock, flags); + +- get_device(dev); +- device_for_each_child(dev, NULL, __remove_child); +- put_device(dev); ++ if (found) { ++ __scsi_remove_target(found); ++ scsi_target_reap(found); ++ /* in the case where @dev has multiple starget children, ++ * continue removing. ++ * ++ * FIXME: does such a case exist? ++ */ ++ goto restart; ++ } + } + EXPORT_SYMBOL(scsi_remove_target); + diff --git a/queue-3.0/scsi-libsas-continue-revalidation.patch b/queue-3.0/scsi-libsas-continue-revalidation.patch new file mode 100644 index 00000000000..e446e5316b6 --- /dev/null +++ b/queue-3.0/scsi-libsas-continue-revalidation.patch @@ -0,0 +1,47 @@ +From 26f2f199ff150d8876b2641c41e60d1c92d2fb81 Mon Sep 17 00:00:00 2001 +From: Dan Williams +Date: Thu, 21 Jun 2012 23:36:15 -0700 +Subject: SCSI: libsas: continue revalidation + +From: Dan Williams + +commit 26f2f199ff150d8876b2641c41e60d1c92d2fb81 upstream. + +Continue running revalidation until no more broadcast devices are +discovered. Fixes cases where re-discovery completes too early in a +domain with multiple expanders with pending re-discovery events. +Servicing BCNs can get backed up behind error recovery. + +Signed-off-by: Dan Williams +Signed-off-by: James Bottomley +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/scsi/libsas/sas_expander.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/scsi/libsas/sas_expander.c ++++ b/drivers/scsi/libsas/sas_expander.c +@@ -1972,9 +1972,7 @@ int sas_ex_revalidate_domain(struct doma + struct domain_device *dev = NULL; + + res = sas_find_bcast_dev(port_dev, &dev); +- if (res) +- goto out; +- if (dev) { ++ while (res == 0 && dev) { + struct expander_device *ex = &dev->ex_dev; + int i = 0, phy_id; + +@@ -1986,8 +1984,10 @@ int sas_ex_revalidate_domain(struct doma + res = sas_rediscover(dev, phy_id); + i = phy_id + 1; + } while (i < ex->num_phys); ++ ++ dev = NULL; ++ res = sas_find_bcast_dev(port_dev, &dev); + } +-out: + return res; + } + diff --git a/queue-3.0/scsi-libsas-fix-sas_discover_devices-return-code-handling.patch b/queue-3.0/scsi-libsas-fix-sas_discover_devices-return-code-handling.patch new file mode 100644 index 00000000000..c61e0e6ef0c --- /dev/null +++ b/queue-3.0/scsi-libsas-fix-sas_discover_devices-return-code-handling.patch @@ -0,0 +1,126 @@ +From b17caa174a7e1fd2e17b26e210d4ee91c4c28b37 Mon Sep 17 00:00:00 2001 +From: Dan Williams +Date: Thu, 21 Jun 2012 23:36:20 -0700 +Subject: SCSI: libsas: fix sas_discover_devices return code handling + +From: Dan Williams + +commit b17caa174a7e1fd2e17b26e210d4ee91c4c28b37 upstream. + +commit 198439e4 [SCSI] libsas: do not set res = 0 in sas_ex_discover_dev() +commit 19252de6 [SCSI] libsas: fix wide port hotplug issues + +The above commits seem to have confused the return value of +sas_ex_discover_dev which is non-zero on failure and +sas_ex_join_wide_port which just indicates short circuiting discovery on +already established ports. The result is random discovery failures +depending on configuration. + +Calls to sas_ex_join_wide_port are the source of the trouble as its +return value is errantly assigned to 'res'. Convert it to bool and stop +returning its result up the stack. + +Tested-by: Dan Melnic +Reported-by: Dan Melnic +Signed-off-by: Dan Williams +Reviewed-by: Jack Wang +Signed-off-by: James Bottomley +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/scsi/libsas/sas_expander.c | 39 +++++++++++-------------------------- + 1 file changed, 12 insertions(+), 27 deletions(-) + +--- a/drivers/scsi/libsas/sas_expander.c ++++ b/drivers/scsi/libsas/sas_expander.c +@@ -770,7 +770,7 @@ static struct domain_device *sas_ex_disc + } + + /* See if this phy is part of a wide port */ +-static int sas_ex_join_wide_port(struct domain_device *parent, int phy_id) ++static bool sas_ex_join_wide_port(struct domain_device *parent, int phy_id) + { + struct ex_phy *phy = &parent->ex_dev.ex_phy[phy_id]; + int i; +@@ -786,11 +786,11 @@ static int sas_ex_join_wide_port(struct + sas_port_add_phy(ephy->port, phy->phy); + phy->port = ephy->port; + phy->phy_state = PHY_DEVICE_DISCOVERED; +- return 0; ++ return true; + } + } + +- return -ENODEV; ++ return false; + } + + static struct domain_device *sas_ex_discover_expander( +@@ -928,8 +928,7 @@ static int sas_ex_discover_dev(struct do + return res; + } + +- res = sas_ex_join_wide_port(dev, phy_id); +- if (!res) { ++ if (sas_ex_join_wide_port(dev, phy_id)) { + SAS_DPRINTK("Attaching ex phy%d to wide port %016llx\n", + phy_id, SAS_ADDR(ex_phy->attached_sas_addr)); + return res; +@@ -974,8 +973,7 @@ static int sas_ex_discover_dev(struct do + if (SAS_ADDR(ex->ex_phy[i].attached_sas_addr) == + SAS_ADDR(child->sas_addr)) { + ex->ex_phy[i].phy_state= PHY_DEVICE_DISCOVERED; +- res = sas_ex_join_wide_port(dev, i); +- if (!res) ++ if (sas_ex_join_wide_port(dev, i)) + SAS_DPRINTK("Attaching ex phy%d to wide port %016llx\n", + i, SAS_ADDR(ex->ex_phy[i].attached_sas_addr)); + +@@ -1838,32 +1836,20 @@ static int sas_discover_new(struct domai + { + struct ex_phy *ex_phy = &dev->ex_dev.ex_phy[phy_id]; + struct domain_device *child; +- bool found = false; +- int res, i; ++ int res; + + SAS_DPRINTK("ex %016llx phy%d new device attached\n", + SAS_ADDR(dev->sas_addr), phy_id); + res = sas_ex_phy_discover(dev, phy_id); + if (res) +- goto out; +- /* to support the wide port inserted */ +- for (i = 0; i < dev->ex_dev.num_phys; i++) { +- struct ex_phy *ex_phy_temp = &dev->ex_dev.ex_phy[i]; +- if (i == phy_id) +- continue; +- if (SAS_ADDR(ex_phy_temp->attached_sas_addr) == +- SAS_ADDR(ex_phy->attached_sas_addr)) { +- found = true; +- break; +- } +- } +- if (found) { +- sas_ex_join_wide_port(dev, phy_id); ++ return res; ++ ++ if (sas_ex_join_wide_port(dev, phy_id)) + return 0; +- } ++ + res = sas_ex_discover_devices(dev, phy_id); +- if (!res) +- goto out; ++ if (res) ++ return res; + list_for_each_entry(child, &dev->ex_dev.children, siblings) { + if (SAS_ADDR(child->sas_addr) == + SAS_ADDR(ex_phy->attached_sas_addr)) { +@@ -1873,7 +1859,6 @@ static int sas_discover_new(struct domai + break; + } + } +-out: + return res; + } + diff --git a/queue-3.0/series b/queue-3.0/series index e425f5e6f05..45c63c32ac1 100644 --- a/queue-3.0/series +++ b/queue-3.0/series @@ -2,3 +2,9 @@ mmc-sdhci-pci-cafe-has-broken-card-detection.patch powerpc-ftrace-fix-assembly-trampoline-register-usage.patch powerpc-add-memory-attribute-for-mfmsr.patch powerpc-fix-wrong-divisor-in-usecs_to_cputime.patch +scsi-libsas-continue-revalidation.patch +scsi-libsas-fix-sas_discover_devices-return-code-handling.patch +scsi-fix-eh-wakeup-scsi_schedule_eh-vs-scsi_restart_operations.patch +scsi-fix-hot-unplug-vs-async-scan-race.patch +scsi-avoid-dangling-pointer-in-scsi_requeue_command.patch +arm-omap2-opp-fix-to-ensure-check-of-right-oppdef-after-bad-one.patch