]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 1 Mar 2016 22:00:38 +0000 (14:00 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 1 Mar 2016 22:00:38 +0000 (14:00 -0800)
added patches:
alsa-hda-apply-clock-gate-workaround-to-skylake-too.patch
alsa-hda-fixing-background-noise-on-dell-inspiron-3162.patch
arcv2-smp-emulate-ipi-to-self-using-software-triggered-interrupt.patch
arcv2-star-9000950267-handle-return-from-intr-to-delay-slot-2.patch
cdc-acm-exclude-samsung-phone-04e8-685d.patch
libata-fix-sff-host-state-machine-locking-while-polling.patch
mac80211-requeue-work-after-scan-complete-for-all-vif-types.patch
perf-stat-do-not-clean-event-s-private-stats.patch
qla2xxx-fix-stale-pointer-access.patch
revert-workqueue-make-sure-delayed-work-run-in-local-cpu.patch
rfkill-fix-rfkill_fop_read-wait_event-usage.patch
spi-atmel-fix-gpio-chip-select-in-case-of-non-dt-platform.patch
target-fix-lun_reset-active-i-o-handling-for-ack_kref.patch
target-fix-lun_reset-active-tmr-descriptor-handling.patch
target-fix-race-with-scf_send_delayed_tas-handling.patch
target-fix-remote-port-tmr-abort-se_cmd-fabric-stop.patch
target-fix-tas-handling-for-multi-session-se_node_acls.patch
tick-nohz-set-the-correct-expiry-when-switching-to-nohz-lowres-mode.patch
workqueue-handle-numa_no_node-for-unbound-pool_workqueue-lookup.patch

20 files changed:
queue-4.4/alsa-hda-apply-clock-gate-workaround-to-skylake-too.patch [new file with mode: 0644]
queue-4.4/alsa-hda-fixing-background-noise-on-dell-inspiron-3162.patch [new file with mode: 0644]
queue-4.4/arcv2-smp-emulate-ipi-to-self-using-software-triggered-interrupt.patch [new file with mode: 0644]
queue-4.4/arcv2-star-9000950267-handle-return-from-intr-to-delay-slot-2.patch [new file with mode: 0644]
queue-4.4/cdc-acm-exclude-samsung-phone-04e8-685d.patch [new file with mode: 0644]
queue-4.4/libata-fix-sff-host-state-machine-locking-while-polling.patch [new file with mode: 0644]
queue-4.4/mac80211-requeue-work-after-scan-complete-for-all-vif-types.patch [new file with mode: 0644]
queue-4.4/perf-stat-do-not-clean-event-s-private-stats.patch [new file with mode: 0644]
queue-4.4/qla2xxx-fix-stale-pointer-access.patch [new file with mode: 0644]
queue-4.4/revert-workqueue-make-sure-delayed-work-run-in-local-cpu.patch [new file with mode: 0644]
queue-4.4/rfkill-fix-rfkill_fop_read-wait_event-usage.patch [new file with mode: 0644]
queue-4.4/series
queue-4.4/spi-atmel-fix-gpio-chip-select-in-case-of-non-dt-platform.patch [new file with mode: 0644]
queue-4.4/target-fix-lun_reset-active-i-o-handling-for-ack_kref.patch [new file with mode: 0644]
queue-4.4/target-fix-lun_reset-active-tmr-descriptor-handling.patch [new file with mode: 0644]
queue-4.4/target-fix-race-with-scf_send_delayed_tas-handling.patch [new file with mode: 0644]
queue-4.4/target-fix-remote-port-tmr-abort-se_cmd-fabric-stop.patch [new file with mode: 0644]
queue-4.4/target-fix-tas-handling-for-multi-session-se_node_acls.patch [new file with mode: 0644]
queue-4.4/tick-nohz-set-the-correct-expiry-when-switching-to-nohz-lowres-mode.patch [new file with mode: 0644]
queue-4.4/workqueue-handle-numa_no_node-for-unbound-pool_workqueue-lookup.patch [new file with mode: 0644]

diff --git a/queue-4.4/alsa-hda-apply-clock-gate-workaround-to-skylake-too.patch b/queue-4.4/alsa-hda-apply-clock-gate-workaround-to-skylake-too.patch
new file mode 100644 (file)
index 0000000..956fb95
--- /dev/null
@@ -0,0 +1,92 @@
+From 7e31a0159461818a1bda49662921b98a29c1187b Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Mon, 22 Feb 2016 15:18:13 +0100
+Subject: ALSA: hda - Apply clock gate workaround to Skylake, too
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit 7e31a0159461818a1bda49662921b98a29c1187b upstream.
+
+Some Skylake machines show the codec probe errors in certain
+situations, e.g. HP Z240 desktop fails to probe the onboard Realtek
+codec at reloading the snd-hda-intel module like:
+  snd_hda_intel 0000:00:1f.3: spurious response 0x200:0x2, last cmd=0x000000
+  snd_hda_intel 0000:00:1f.3: azx_get_response timeout, switching to polling mode: lastcmd=0x000f0000
+  snd_hda_intel 0000:00:1f.3: No response from codec, disabling MSI: last cmd=0x000f0000
+  snd_hda_intel 0000:00:1f.3: Codec #0 probe error; disabling it...
+  hdaudio hdaudioC0D2: no AFG or MFG node found
+  snd_hda_intel 0000:00:1f.3: no codecs initialized
+
+Also, HP G470 G3 suffers from the similar problem, as reported in
+bugzilla below.  On this machine, the codec probe error appears even
+at a fresh boot.
+
+As Libin suggested, the same workaround used for Broxton in the commit
+[6639484ddaf6: ALSA: hda - disable dynamic clock gating on Broxton
+ before reset] can be applied for Skylake in order to fix this problem.
+The Intel HW team also confirmed that this is needed for SKL.
+
+This patch makes the workaround applied to both SKL and BXT
+platforms.  The referred macros are moved and one superfluous macro
+(IS_BROXTON()) is another one (IS_BXT()) as well.
+
+Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=112731
+Suggested-by: Libin Yang <libin.yang@linux.intel.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/pci/hda/hda_intel.c |   16 +++++++---------
+ 1 file changed, 7 insertions(+), 9 deletions(-)
+
+--- a/sound/pci/hda/hda_intel.c
++++ b/sound/pci/hda/hda_intel.c
+@@ -357,7 +357,10 @@ enum {
+                                       ((pci)->device == 0x0d0c) || \
+                                       ((pci)->device == 0x160c))
+-#define IS_BROXTON(pci)       ((pci)->device == 0x5a98)
++#define IS_SKL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa170)
++#define IS_SKL_LP(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9d70)
++#define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98)
++#define IS_SKL_PLUS(pci) (IS_SKL(pci) || IS_SKL_LP(pci) || IS_BXT(pci))
+ static char *driver_short_names[] = {
+       [AZX_DRIVER_ICH] = "HDA Intel",
+@@ -534,13 +537,13 @@ static void hda_intel_init_chip(struct a
+       if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
+               snd_hdac_set_codec_wakeup(bus, true);
+-      if (IS_BROXTON(pci)) {
++      if (IS_SKL_PLUS(pci)) {
+               pci_read_config_dword(pci, INTEL_HDA_CGCTL, &val);
+               val = val & ~INTEL_HDA_CGCTL_MISCBDCGE;
+               pci_write_config_dword(pci, INTEL_HDA_CGCTL, val);
+       }
+       azx_init_chip(chip, full_reset);
+-      if (IS_BROXTON(pci)) {
++      if (IS_SKL_PLUS(pci)) {
+               pci_read_config_dword(pci, INTEL_HDA_CGCTL, &val);
+               val = val | INTEL_HDA_CGCTL_MISCBDCGE;
+               pci_write_config_dword(pci, INTEL_HDA_CGCTL, val);
+@@ -549,7 +552,7 @@ static void hda_intel_init_chip(struct a
+               snd_hdac_set_codec_wakeup(bus, false);
+       /* reduce dma latency to avoid noise */
+-      if (IS_BROXTON(pci))
++      if (IS_BXT(pci))
+               bxt_reduce_dma_latency(chip);
+ }
+@@ -971,11 +974,6 @@ static int azx_resume(struct device *dev
+ /* put codec down to D3 at hibernation for Intel SKL+;
+  * otherwise BIOS may still access the codec and screw up the driver
+  */
+-#define IS_SKL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa170)
+-#define IS_SKL_LP(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9d70)
+-#define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98)
+-#define IS_SKL_PLUS(pci) (IS_SKL(pci) || IS_SKL_LP(pci) || IS_BXT(pci))
+-
+ static int azx_freeze_noirq(struct device *dev)
+ {
+       struct pci_dev *pci = to_pci_dev(dev);
diff --git a/queue-4.4/alsa-hda-fixing-background-noise-on-dell-inspiron-3162.patch b/queue-4.4/alsa-hda-fixing-background-noise-on-dell-inspiron-3162.patch
new file mode 100644 (file)
index 0000000..dae2ef0
--- /dev/null
@@ -0,0 +1,63 @@
+From 3b43b71f05d3ecd01c4116254666d9492301697d Mon Sep 17 00:00:00 2001
+From: Kai-Heng Feng <kaihengfeng@gmail.com>
+Date: Thu, 25 Feb 2016 15:19:38 +0800
+Subject: ALSA: hda - Fixing background noise on Dell Inspiron 3162
+
+From: Kai-Heng Feng <kaihengfeng@gmail.com>
+
+commit 3b43b71f05d3ecd01c4116254666d9492301697d upstream.
+
+After login to the desktop on Dell Inspiron 3162,
+there's a very loud background noise comes from the builtin speaker.
+The noise does not go away even if the speaker is muted.
+
+The noise disappears after using the aamix fixup.
+
+Codec: Realtek ALC3234
+Address: 0
+AFG Function Id: 0x1 (unsol 1)
+    Vendor Id: 0x10ec0255
+    Subsystem Id: 0x10280725
+    Revision Id: 0x100002
+    No Modem Function Group found
+
+BugLink: http://bugs.launchpad.net/bugs/1549620
+Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/pci/hda/patch_realtek.c |    8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -4749,6 +4749,7 @@ enum {
+       ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE,
+       ALC293_FIXUP_LENOVO_SPK_NOISE,
+       ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY,
++      ALC255_FIXUP_DELL_SPK_NOISE,
+ };
+ static const struct hda_fixup alc269_fixups[] = {
+@@ -5368,6 +5369,12 @@ static const struct hda_fixup alc269_fix
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc233_fixup_lenovo_line2_mic_hotkey,
+       },
++      [ALC255_FIXUP_DELL_SPK_NOISE] = {
++              .type = HDA_FIXUP_FUNC,
++              .v.func = alc_fixup_disable_aamix,
++              .chained = true,
++              .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE
++      },
+ };
+ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
+@@ -5410,6 +5417,7 @@ static const struct snd_pci_quirk alc269
+       SND_PCI_QUIRK(0x1028, 0x06df, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
+       SND_PCI_QUIRK(0x1028, 0x06e0, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
+       SND_PCI_QUIRK(0x1028, 0x0704, "Dell XPS 13", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE),
++      SND_PCI_QUIRK(0x1028, 0x0725, "Dell Inspiron 3162", ALC255_FIXUP_DELL_SPK_NOISE),
+       SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
diff --git a/queue-4.4/arcv2-smp-emulate-ipi-to-self-using-software-triggered-interrupt.patch b/queue-4.4/arcv2-smp-emulate-ipi-to-self-using-software-triggered-interrupt.patch
new file mode 100644 (file)
index 0000000..093c0c3
--- /dev/null
@@ -0,0 +1,132 @@
+From bb143f814ea488769ca2e79e0b376139cb5f134b Mon Sep 17 00:00:00 2001
+From: Vineet Gupta <vgupta@synopsys.com>
+Date: Tue, 23 Feb 2016 11:55:16 +0530
+Subject: ARCv2: SMP: Emulate IPI to self using software triggered interrupt
+
+From: Vineet Gupta <vgupta@synopsys.com>
+
+commit bb143f814ea488769ca2e79e0b376139cb5f134b upstream.
+
+ARConnect/MCIP Inter-Core-Interrupt module can't send interrupt to
+local core. So use core intc capability to trigger software
+interrupt to self, using an unsued IRQ #21.
+
+This showed up as csd deadlock with LTP trace_sched on a dual core
+system. This test acts as scheduler fuzzer, triggering all sorts of
+schedulting activity. Trouble starts with IPI to self, which doesn't get
+delivered (effectively lost due to H/w capability), but the msg intended
+to be sent remain enqueued in per-cpu @ipi_data.
+
+All subsequent IPIs to this core from other cores get elided due to the
+IPI coalescing optimization in ipi_send_msg_one() where a pending msg
+implies an IPI already sent and assumes other core is yet to ack it.
+After the elided IPI, other core simply goes into csd_lock_wait()
+but never comes out as this core never sees the interrupt.
+
+Fixes STAR 9001008624
+
+Cc: Peter Zijlstra <peterz@infradead.org>
+Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/arc/include/asm/irqflags-arcv2.h |   11 +++++++++++
+ arch/arc/kernel/entry-arcv2.S         |   11 ++++++-----
+ arch/arc/kernel/mcip.c                |   15 +++++++++++++++
+ 3 files changed, 32 insertions(+), 5 deletions(-)
+
+--- a/arch/arc/include/asm/irqflags-arcv2.h
++++ b/arch/arc/include/asm/irqflags-arcv2.h
+@@ -22,6 +22,7 @@
+ #define AUX_IRQ_CTRL          0x00E
+ #define AUX_IRQ_ACT           0x043   /* Active Intr across all levels */
+ #define AUX_IRQ_LVL_PEND      0x200   /* Pending Intr across all levels */
++#define AUX_IRQ_HINT          0x201   /* For generating Soft Interrupts */
+ #define AUX_IRQ_PRIORITY      0x206
+ #define ICAUSE                        0x40a
+ #define AUX_IRQ_SELECT                0x40b
+@@ -112,6 +113,16 @@ static inline int arch_irqs_disabled(voi
+       return arch_irqs_disabled_flags(arch_local_save_flags());
+ }
++static inline void arc_softirq_trigger(int irq)
++{
++      write_aux_reg(AUX_IRQ_HINT, irq);
++}
++
++static inline void arc_softirq_clear(int irq)
++{
++      write_aux_reg(AUX_IRQ_HINT, 0);
++}
++
+ #else
+ .macro IRQ_DISABLE  scratch
+--- a/arch/arc/kernel/entry-arcv2.S
++++ b/arch/arc/kernel/entry-arcv2.S
+@@ -45,11 +45,12 @@ VECTOR     reserved                ; Reserved slots
+ VECTOR        handle_interrupt        ; (16) Timer0
+ VECTOR        handle_interrupt        ; unused (Timer1)
+ VECTOR        handle_interrupt        ; unused (WDT)
+-VECTOR        handle_interrupt        ; (19) ICI (inter core interrupt)
+-VECTOR        handle_interrupt
+-VECTOR        handle_interrupt
+-VECTOR        handle_interrupt
+-VECTOR        handle_interrupt        ; (23) End of fixed IRQs
++VECTOR        handle_interrupt        ; (19) Inter core Interrupt (IPI)
++VECTOR        handle_interrupt        ; (20) perf Interrupt
++VECTOR        handle_interrupt        ; (21) Software Triggered Intr (Self IPI)
++VECTOR        handle_interrupt        ; unused
++VECTOR        handle_interrupt        ; (23) unused
++# End of fixed IRQs
+ .rept CONFIG_ARC_NUMBER_OF_INTERRUPTS - 8
+       VECTOR  handle_interrupt
+--- a/arch/arc/kernel/mcip.c
++++ b/arch/arc/kernel/mcip.c
+@@ -11,9 +11,12 @@
+ #include <linux/smp.h>
+ #include <linux/irq.h>
+ #include <linux/spinlock.h>
++#include <asm/irqflags-arcv2.h>
+ #include <asm/mcip.h>
+ #include <asm/setup.h>
++#define SOFTIRQ_IRQ   21
++
+ static char smp_cpuinfo_buf[128];
+ static int idu_detected;
+@@ -22,6 +25,7 @@ static DEFINE_RAW_SPINLOCK(mcip_lock);
+ static void mcip_setup_per_cpu(int cpu)
+ {
+       smp_ipi_irq_setup(cpu, IPI_IRQ);
++      smp_ipi_irq_setup(cpu, SOFTIRQ_IRQ);
+ }
+ static void mcip_ipi_send(int cpu)
+@@ -29,6 +33,12 @@ static void mcip_ipi_send(int cpu)
+       unsigned long flags;
+       int ipi_was_pending;
++      /* ARConnect can only send IPI to others */
++      if (unlikely(cpu == raw_smp_processor_id())) {
++              arc_softirq_trigger(SOFTIRQ_IRQ);
++              return;
++      }
++
+       /*
+        * NOTE: We must spin here if the other cpu hasn't yet
+        * serviced a previous message. This can burn lots
+@@ -63,6 +73,11 @@ static void mcip_ipi_clear(int irq)
+       unsigned long flags;
+       unsigned int __maybe_unused copy;
++      if (unlikely(irq == SOFTIRQ_IRQ)) {
++              arc_softirq_clear(irq);
++              return;
++      }
++
+       raw_spin_lock_irqsave(&mcip_lock, flags);
+       /* Who sent the IPI */
diff --git a/queue-4.4/arcv2-star-9000950267-handle-return-from-intr-to-delay-slot-2.patch b/queue-4.4/arcv2-star-9000950267-handle-return-from-intr-to-delay-slot-2.patch
new file mode 100644 (file)
index 0000000..522a310
--- /dev/null
@@ -0,0 +1,102 @@
+From cbfe74a753e877b49dc54e9b04d5d42230ca0aed Mon Sep 17 00:00:00 2001
+From: Vineet Gupta <vgupta@synopsys.com>
+Date: Fri, 8 Jan 2016 12:29:10 +0530
+Subject: ARCv2: STAR 9000950267: Handle return from intr to Delay Slot #2
+
+From: Vineet Gupta <vgupta@synopsys.com>
+
+commit cbfe74a753e877b49dc54e9b04d5d42230ca0aed upstream.
+
+Returning to delay slot, riding an interrupti, had one loose end.
+AUX_USER_SP used for restoring user mode SP upon RTIE was not being
+setup from orig task's saved value, causing task to use wrong SP,
+leading to ProtV errors.
+
+The reason being:
+ - INTERRUPT_EPILOGUE returns to a kernel trampoline, thus not expected to restore it
+ - EXCEPTION_EPILOGUE is not used at all
+
+Fix that by restoring AUX_USER_SP explicitly in the trampoline.
+
+This was broken in the original workaround, but the error scenarios got
+reduced considerably since v3.14 due to following:
+
+ 1. The Linuxthreads.old based userspace at the time caused many more
+    exceptions in delay slot than the current NPTL based one.
+    Infact with current userspace the error doesn't happen at all.
+
+ 2. Return from interrupt (delay slot or otherwise) doesn't get exercised much
+    after commit 4de0e52867d8 ("Really Re-enable interrupts to avoid deadlocks")
+    since IRQ_ACTIVE.active being clear means most returns are as if from pure
+    kernel (even for active interrupts)
+
+Infact the issue only happened in an experimental branch where I was tinkering with
+reverted 4de0e52867d8
+
+Fixes: 4255b07f2c9c ("ARCv2: STAR 9000793984: Handle return from intr to Delay Slot")
+Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/arc/kernel/entry-arcv2.S |   19 ++++++++++++++++++-
+ 1 file changed, 18 insertions(+), 1 deletion(-)
+
+--- a/arch/arc/kernel/entry-arcv2.S
++++ b/arch/arc/kernel/entry-arcv2.S
+@@ -211,7 +211,11 @@ debug_marker_syscall:
+ ; (since IRQ NOT allowed in DS in ARCv2, this can only happen if orig
+ ; entry was via Exception in DS which got preempted in kernel).
+ ;
+-; IRQ RTIE won't reliably restore DE bit and/or BTA, needs handling
++; IRQ RTIE won't reliably restore DE bit and/or BTA, needs workaround
++;
++; Solution is return from Intr w/o any delay slot quirks into a kernel trampoline
++; and from pure kernel mode return to delay slot which handles DS bit/BTA correctly
++
+ .Lintr_ret_to_delay_slot:
+ debug_marker_ds:
+@@ -222,18 +226,23 @@ debug_marker_ds:
+       ld      r2, [sp, PT_ret]
+       ld      r3, [sp, PT_status32]
++      ; STAT32 for Int return created from scratch
++      ; (No delay dlot, disable Further intr in trampoline)
++
+       bic     r0, r3, STATUS_U_MASK|STATUS_DE_MASK|STATUS_IE_MASK|STATUS_L_MASK
+       st      r0, [sp, PT_status32]
+       mov     r1, .Lintr_ret_to_delay_slot_2
+       st      r1, [sp, PT_ret]
++      ; Orig exception PC/STAT32 safekept @orig_r0 and @event stack slots
+       st      r2, [sp, 0]
+       st      r3, [sp, 4]
+       b       .Lisr_ret_fast_path
+ .Lintr_ret_to_delay_slot_2:
++      ; Trampoline to restore orig exception PC/STAT32/BTA/AUX_USER_SP
+       sub     sp, sp, SZ_PT_REGS
+       st      r9, [sp, -4]
+@@ -243,11 +252,19 @@ debug_marker_ds:
+       ld      r9, [sp, 4]
+       sr      r9, [erstatus]
++      ; restore AUX_USER_SP if returning to U mode
++      bbit0   r9, STATUS_U_BIT, 1f
++      ld      r9, [sp, PT_sp]
++      sr      r9, [AUX_USER_SP]
++
++1:
+       ld      r9, [sp, 8]
+       sr      r9, [erbta]
+       ld      r9, [sp, -4]
+       add     sp, sp, SZ_PT_REGS
++
++      ; return from pure kernel mode to delay slot
+       rtie
+ END(ret_from_exception)
diff --git a/queue-4.4/cdc-acm-exclude-samsung-phone-04e8-685d.patch b/queue-4.4/cdc-acm-exclude-samsung-phone-04e8-685d.patch
new file mode 100644 (file)
index 0000000..54620c3
--- /dev/null
@@ -0,0 +1,33 @@
+From e912e685f372ab62a2405a1acd923597f524e94a Mon Sep 17 00:00:00 2001
+From: Oliver Neukum <oneukum@suse.com>
+Date: Mon, 18 Jan 2016 15:45:18 +0100
+Subject: cdc-acm:exclude Samsung phone 04e8:685d
+
+From: Oliver Neukum <oneukum@suse.com>
+
+commit e912e685f372ab62a2405a1acd923597f524e94a upstream.
+
+This phone needs to be handled by a specialised firmware tool
+and is reported to crash irrevocably if cdc-acm takes it.
+
+Signed-off-by: Oliver Neukum <oneukum@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/class/cdc-acm.c |    5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/usb/class/cdc-acm.c
++++ b/drivers/usb/class/cdc-acm.c
+@@ -1841,6 +1841,11 @@ static const struct usb_device_id acm_id
+       },
+ #endif
++      /*Samsung phone in firmware update mode */
++      { USB_DEVICE(0x04e8, 0x685d),
++      .driver_info = IGNORE_DEVICE,
++      },
++
+       /* Exclude Infineon Flash Loader utility */
+       { USB_DEVICE(0x058b, 0x0041),
+       .driver_info = IGNORE_DEVICE,
diff --git a/queue-4.4/libata-fix-sff-host-state-machine-locking-while-polling.patch b/queue-4.4/libata-fix-sff-host-state-machine-locking-while-polling.patch
new file mode 100644 (file)
index 0000000..523a9c3
--- /dev/null
@@ -0,0 +1,183 @@
+From 8eee1d3ed5b6fc8e14389567c9a6f53f82bb7224 Mon Sep 17 00:00:00 2001
+From: Tejun Heo <tj@kernel.org>
+Date: Mon, 1 Feb 2016 11:33:21 -0500
+Subject: libata: fix sff host state machine locking while polling
+
+From: Tejun Heo <tj@kernel.org>
+
+commit 8eee1d3ed5b6fc8e14389567c9a6f53f82bb7224 upstream.
+
+The bulk of ATA host state machine is implemented by
+ata_sff_hsm_move().  The function is called from either the interrupt
+handler or, if polling, a work item.  Unlike from the interrupt path,
+the polling path calls the function without holding the host lock and
+ata_sff_hsm_move() selectively grabs the lock.
+
+This is completely broken.  If an IRQ triggers while polling is in
+progress, the two can easily race and end up accessing the hardware
+and updating state machine state at the same time.  This can put the
+state machine in an illegal state and lead to a crash like the
+following.
+
+  kernel BUG at drivers/ata/libata-sff.c:1302!
+  invalid opcode: 0000 [#1] SMP DEBUG_PAGEALLOC KASAN
+  Modules linked in:
+  CPU: 1 PID: 10679 Comm: syz-executor Not tainted 4.5.0-rc1+ #300
+  Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
+  task: ffff88002bd00000 ti: ffff88002e048000 task.ti: ffff88002e048000
+  RIP: 0010:[<ffffffff83a83409>]  [<ffffffff83a83409>] ata_sff_hsm_move+0x619/0x1c60
+  ...
+  Call Trace:
+   <IRQ>
+   [<ffffffff83a84c31>] __ata_sff_port_intr+0x1e1/0x3a0 drivers/ata/libata-sff.c:1584
+   [<ffffffff83a85611>] ata_bmdma_port_intr+0x71/0x400 drivers/ata/libata-sff.c:2877
+   [<     inline     >] __ata_sff_interrupt drivers/ata/libata-sff.c:1629
+   [<ffffffff83a85bf3>] ata_bmdma_interrupt+0x253/0x580 drivers/ata/libata-sff.c:2902
+   [<ffffffff81479f98>] handle_irq_event_percpu+0x108/0x7e0 kernel/irq/handle.c:157
+   [<ffffffff8147a717>] handle_irq_event+0xa7/0x140 kernel/irq/handle.c:205
+   [<ffffffff81484573>] handle_edge_irq+0x1e3/0x8d0 kernel/irq/chip.c:623
+   [<     inline     >] generic_handle_irq_desc include/linux/irqdesc.h:146
+   [<ffffffff811a92bc>] handle_irq+0x10c/0x2a0 arch/x86/kernel/irq_64.c:78
+   [<ffffffff811a7e4d>] do_IRQ+0x7d/0x1a0 arch/x86/kernel/irq.c:240
+   [<ffffffff86653d4c>] common_interrupt+0x8c/0x8c arch/x86/entry/entry_64.S:520
+   <EOI>
+   [<     inline     >] rcu_lock_acquire include/linux/rcupdate.h:490
+   [<     inline     >] rcu_read_lock include/linux/rcupdate.h:874
+   [<ffffffff8164b4a1>] filemap_map_pages+0x131/0xba0 mm/filemap.c:2145
+   [<     inline     >] do_fault_around mm/memory.c:2943
+   [<     inline     >] do_read_fault mm/memory.c:2962
+   [<     inline     >] do_fault mm/memory.c:3133
+   [<     inline     >] handle_pte_fault mm/memory.c:3308
+   [<     inline     >] __handle_mm_fault mm/memory.c:3418
+   [<ffffffff816efb16>] handle_mm_fault+0x2516/0x49a0 mm/memory.c:3447
+   [<ffffffff8127dc16>] __do_page_fault+0x376/0x960 arch/x86/mm/fault.c:1238
+   [<ffffffff8127e358>] trace_do_page_fault+0xe8/0x420 arch/x86/mm/fault.c:1331
+   [<ffffffff8126f514>] do_async_page_fault+0x14/0xd0 arch/x86/kernel/kvm.c:264
+   [<ffffffff86655578>] async_page_fault+0x28/0x30 arch/x86/entry/entry_64.S:986
+
+Fix it by ensuring that the polling path is holding the host lock
+before entering ata_sff_hsm_move() so that all hardware accesses and
+state updates are performed under the host lock.
+
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Reported-and-tested-by: Dmitry Vyukov <dvyukov@google.com>
+Link: http://lkml.kernel.org/g/CACT4Y+b_JsOxJu2EZyEf+mOXORc_zid5V1-pLZSroJVxyWdSpw@mail.gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/ata/libata-sff.c |   32 +++++++++++---------------------
+ 1 file changed, 11 insertions(+), 21 deletions(-)
+
+--- a/drivers/ata/libata-sff.c
++++ b/drivers/ata/libata-sff.c
+@@ -997,12 +997,9 @@ static inline int ata_hsm_ok_in_wq(struc
+ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq)
+ {
+       struct ata_port *ap = qc->ap;
+-      unsigned long flags;
+       if (ap->ops->error_handler) {
+               if (in_wq) {
+-                      spin_lock_irqsave(ap->lock, flags);
+-
+                       /* EH might have kicked in while host lock is
+                        * released.
+                        */
+@@ -1014,8 +1011,6 @@ static void ata_hsm_qc_complete(struct a
+                               } else
+                                       ata_port_freeze(ap);
+                       }
+-
+-                      spin_unlock_irqrestore(ap->lock, flags);
+               } else {
+                       if (likely(!(qc->err_mask & AC_ERR_HSM)))
+                               ata_qc_complete(qc);
+@@ -1024,10 +1019,8 @@ static void ata_hsm_qc_complete(struct a
+               }
+       } else {
+               if (in_wq) {
+-                      spin_lock_irqsave(ap->lock, flags);
+                       ata_sff_irq_on(ap);
+                       ata_qc_complete(qc);
+-                      spin_unlock_irqrestore(ap->lock, flags);
+               } else
+                       ata_qc_complete(qc);
+       }
+@@ -1048,9 +1041,10 @@ int ata_sff_hsm_move(struct ata_port *ap
+ {
+       struct ata_link *link = qc->dev->link;
+       struct ata_eh_info *ehi = &link->eh_info;
+-      unsigned long flags = 0;
+       int poll_next;
++      lockdep_assert_held(ap->lock);
++
+       WARN_ON_ONCE((qc->flags & ATA_QCFLAG_ACTIVE) == 0);
+       /* Make sure ata_sff_qc_issue() does not throw things
+@@ -1112,14 +1106,6 @@ fsm_start:
+                       }
+               }
+-              /* Send the CDB (atapi) or the first data block (ata pio out).
+-               * During the state transition, interrupt handler shouldn't
+-               * be invoked before the data transfer is complete and
+-               * hsm_task_state is changed. Hence, the following locking.
+-               */
+-              if (in_wq)
+-                      spin_lock_irqsave(ap->lock, flags);
+-
+               if (qc->tf.protocol == ATA_PROT_PIO) {
+                       /* PIO data out protocol.
+                        * send first data block.
+@@ -1135,9 +1121,6 @@ fsm_start:
+                       /* send CDB */
+                       atapi_send_cdb(ap, qc);
+-              if (in_wq)
+-                      spin_unlock_irqrestore(ap->lock, flags);
+-
+               /* if polling, ata_sff_pio_task() handles the rest.
+                * otherwise, interrupt handler takes over from here.
+                */
+@@ -1361,12 +1344,14 @@ static void ata_sff_pio_task(struct work
+       u8 status;
+       int poll_next;
++      spin_lock_irq(ap->lock);
++
+       BUG_ON(ap->sff_pio_task_link == NULL);
+       /* qc can be NULL if timeout occurred */
+       qc = ata_qc_from_tag(ap, link->active_tag);
+       if (!qc) {
+               ap->sff_pio_task_link = NULL;
+-              return;
++              goto out_unlock;
+       }
+ fsm_start:
+@@ -1381,11 +1366,14 @@ fsm_start:
+        */
+       status = ata_sff_busy_wait(ap, ATA_BUSY, 5);
+       if (status & ATA_BUSY) {
++              spin_unlock_irq(ap->lock);
+               ata_msleep(ap, 2);
++              spin_lock_irq(ap->lock);
++
+               status = ata_sff_busy_wait(ap, ATA_BUSY, 10);
+               if (status & ATA_BUSY) {
+                       ata_sff_queue_pio_task(link, ATA_SHORT_PAUSE);
+-                      return;
++                      goto out_unlock;
+               }
+       }
+@@ -1402,6 +1390,8 @@ fsm_start:
+        */
+       if (poll_next)
+               goto fsm_start;
++out_unlock:
++      spin_unlock_irq(ap->lock);
+ }
+ /**
diff --git a/queue-4.4/mac80211-requeue-work-after-scan-complete-for-all-vif-types.patch b/queue-4.4/mac80211-requeue-work-after-scan-complete-for-all-vif-types.patch
new file mode 100644 (file)
index 0000000..2051182
--- /dev/null
@@ -0,0 +1,115 @@
+From 4fa11ec726a32ea6dd768dbb2e2af3453a98ec0a Mon Sep 17 00:00:00 2001
+From: Sachin Kulkarni <Sachin.Kulkarni@imgtec.com>
+Date: Tue, 12 Jan 2016 14:30:19 +0530
+Subject: mac80211: Requeue work after scan complete for all VIF types.
+
+From: Sachin Kulkarni <Sachin.Kulkarni@imgtec.com>
+
+commit 4fa11ec726a32ea6dd768dbb2e2af3453a98ec0a upstream.
+
+During a sw scan ieee80211_iface_work ignores work items for all vifs.
+However after the scan complete work is requeued only for STA, ADHOC
+and MESH iftypes.
+
+This occasionally results in event processing getting delayed/not
+processed for iftype AP when it coexists with a STA. This can result
+in data halt and eventually disconnection on the AP interface.
+
+Signed-off-by: Sachin Kulkarni <Sachin.Kulkarni@imgtec.com>
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/mac80211/ibss.c |    1 -
+ net/mac80211/mesh.c |   11 -----------
+ net/mac80211/mesh.h |    4 ----
+ net/mac80211/mlme.c |    2 --
+ net/mac80211/scan.c |   12 +++++++++++-
+ 5 files changed, 11 insertions(+), 19 deletions(-)
+
+--- a/net/mac80211/ibss.c
++++ b/net/mac80211/ibss.c
+@@ -1732,7 +1732,6 @@ void ieee80211_ibss_notify_scan_complete
+               if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
+                       continue;
+               sdata->u.ibss.last_scan_completed = jiffies;
+-              ieee80211_queue_work(&local->hw, &sdata->work);
+       }
+       mutex_unlock(&local->iflist_mtx);
+ }
+--- a/net/mac80211/mesh.c
++++ b/net/mac80211/mesh.c
+@@ -1370,17 +1370,6 @@ out:
+       sdata_unlock(sdata);
+ }
+-void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local)
+-{
+-      struct ieee80211_sub_if_data *sdata;
+-
+-      rcu_read_lock();
+-      list_for_each_entry_rcu(sdata, &local->interfaces, list)
+-              if (ieee80211_vif_is_mesh(&sdata->vif) &&
+-                  ieee80211_sdata_running(sdata))
+-                      ieee80211_queue_work(&local->hw, &sdata->work);
+-      rcu_read_unlock();
+-}
+ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
+ {
+--- a/net/mac80211/mesh.h
++++ b/net/mac80211/mesh.h
+@@ -362,14 +362,10 @@ static inline bool mesh_path_sel_is_hwmp
+       return sdata->u.mesh.mesh_pp_id == IEEE80211_PATH_PROTOCOL_HWMP;
+ }
+-void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local);
+-
+ void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata);
+ void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata);
+ void ieee80211s_stop(void);
+ #else
+-static inline void
+-ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) {}
+ static inline bool mesh_path_sel_is_hwmp(struct ieee80211_sub_if_data *sdata)
+ { return false; }
+ static inline void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata)
+--- a/net/mac80211/mlme.c
++++ b/net/mac80211/mlme.c
+@@ -4003,8 +4003,6 @@ static void ieee80211_restart_sta_timer(
+               if (!ieee80211_hw_check(&sdata->local->hw, CONNECTION_MONITOR))
+                       ieee80211_queue_work(&sdata->local->hw,
+                                            &sdata->u.mgd.monitor_work);
+-              /* and do all the other regular work too */
+-              ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+       }
+ }
+--- a/net/mac80211/scan.c
++++ b/net/mac80211/scan.c
+@@ -314,6 +314,7 @@ static void __ieee80211_scan_completed(s
+       bool was_scanning = local->scanning;
+       struct cfg80211_scan_request *scan_req;
+       struct ieee80211_sub_if_data *scan_sdata;
++      struct ieee80211_sub_if_data *sdata;
+       lockdep_assert_held(&local->mtx);
+@@ -373,7 +374,16 @@ static void __ieee80211_scan_completed(s
+       ieee80211_mlme_notify_scan_completed(local);
+       ieee80211_ibss_notify_scan_completed(local);
+-      ieee80211_mesh_notify_scan_completed(local);
++
++      /* Requeue all the work that might have been ignored while
++       * the scan was in progress; if there was none this will
++       * just be a no-op for the particular interface.
++       */
++      list_for_each_entry_rcu(sdata, &local->interfaces, list) {
++              if (ieee80211_sdata_running(sdata))
++                      ieee80211_queue_work(&sdata->local->hw, &sdata->work);
++      }
++
+       if (was_scanning)
+               ieee80211_start_next_roc(local);
+ }
diff --git a/queue-4.4/perf-stat-do-not-clean-event-s-private-stats.patch b/queue-4.4/perf-stat-do-not-clean-event-s-private-stats.patch
new file mode 100644 (file)
index 0000000..833c74c
--- /dev/null
@@ -0,0 +1,47 @@
+From 3f416f22d1e21709a631189ba169f76fd267b374 Mon Sep 17 00:00:00 2001
+From: Jiri Olsa <jolsa@kernel.org>
+Date: Wed, 20 Jan 2016 12:56:34 +0100
+Subject: perf stat: Do not clean event's private stats
+
+From: Jiri Olsa <jolsa@kernel.org>
+
+commit 3f416f22d1e21709a631189ba169f76fd267b374 upstream.
+
+Mel reported stddev reporting was broken due to following commit:
+
+       106a94a0f8c2 ("perf stat: Introduce read_counters function")
+
+This commit merged interval and overall counters reading into single
+read_counters function.
+
+The old interval code cleaned the stddev data for some reason (it's
+never displayed in interval mode) and the mentioned commit kept on
+cleaning the stddev data in merged function, which resulted in the
+stddev not being displayed.
+
+Removing the wrong stddev data cleanup init_stats call.
+
+Reported-and-Tested-by: Mel Gorman <mgorman@techsingularity.net>
+Signed-off-by: Jiri Olsa <jolsa@kernel.org>
+Cc: David Ahern <dsahern@gmail.com>
+Cc: Namhyung Kim <namhyung@kernel.org>
+Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
+Fixes: 106a94a0f8c2 ("perf stat: Introduce read_counters function")
+Link: http://lkml.kernel.org/r/1453290995-18485-4-git-send-email-jolsa@kernel.org
+Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/perf/util/stat.c |    1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/tools/perf/util/stat.c
++++ b/tools/perf/util/stat.c
+@@ -310,7 +310,6 @@ int perf_stat_process_counter(struct per
+       int i, ret;
+       aggr->val = aggr->ena = aggr->run = 0;
+-      init_stats(ps->res_stats);
+       if (counter->per_pkg)
+               zero_per_pkg(counter);
diff --git a/queue-4.4/qla2xxx-fix-stale-pointer-access.patch b/queue-4.4/qla2xxx-fix-stale-pointer-access.patch
new file mode 100644 (file)
index 0000000..1b19e88
--- /dev/null
@@ -0,0 +1,190 @@
+From cb43285ff7039fe3c4b0bc476e6d6569c31104f3 Mon Sep 17 00:00:00 2001
+From: Quinn Tran <quinn.tran@qlogic.com>
+Date: Thu, 4 Feb 2016 11:45:16 -0500
+Subject: qla2xxx: Fix stale pointer access.
+
+From: Quinn Tran <quinn.tran@qlogic.com>
+
+commit cb43285ff7039fe3c4b0bc476e6d6569c31104f3 upstream.
+
+[ Upstream Commit 84e32a06f4f8756ce9ec3c8dc7e97896575f0771 ]
+
+Commit 84e32a0 ("qla2xxx: Use pci_enable_msix_range() instead of
+pci_enable_msix()") introduced a regression when target mode is enabled.
+In qla24xx_enable_msix(), ha->max_rsp_queues was incorrectly set
+to a value higher than the number of response queues allocated causing
+an invalid dereference. Specifically here in qla2x00_init_rings():
+    *rsp->in_ptr = 0;
+
+Add additional check to make sure the pointer is valid. following
+call stack will be seen
+
+---- 8< ----
+RIP: 0010:[<ffffffffa02ccadc>]  [<ffffffffa02ccadc>] qla2x00_init_rings+0xdc/0x320 [qla2xxx]
+RSP: 0018:ffff880429447dd8  EFLAGS: 00010082
+....
+Call Trace:
+[<ffffffffa02ceb40>] qla2x00_abort_isp+0x170/0x6b0 [qla2xxx]
+[<ffffffffa02c6f77>] qla2x00_do_dpc+0x357/0x7f0 [qla2xxx]
+[<ffffffffa02c6c20>] ? qla2x00_relogin+0x260/0x260 [qla2xxx]
+[<ffffffff8107d2c9>] kthread+0xc9/0xe0
+[<ffffffff8107d200>] ? flush_kthread_worker+0x90/0x90
+[<ffffffff8172cc6f>] ret_from_fork+0x3f/0x70
+[<ffffffff8107d200>] ? flush_kthread_worker+0x90/0x90
+---- 8< ----
+
+Signed-off-by: Quinn Tran <quinn.tran@qlogic.com>
+Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
+Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/scsi/qla2xxx/qla_init.c |   10 +++++-----
+ drivers/scsi/qla2xxx/qla_isr.c  |    4 ++--
+ drivers/scsi/qla2xxx/qla_mid.c  |    4 ++--
+ drivers/scsi/qla2xxx/qla_os.c   |    6 ++++++
+ drivers/scsi/qla2xxx/qla_tmpl.c |   16 ++++++++++++++++
+ 5 files changed, 31 insertions(+), 9 deletions(-)
+
+--- a/drivers/scsi/qla2xxx/qla_init.c
++++ b/drivers/scsi/qla2xxx/qla_init.c
+@@ -2192,7 +2192,7 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
+       /* Clear outstanding commands array. */
+       for (que = 0; que < ha->max_req_queues; que++) {
+               req = ha->req_q_map[que];
+-              if (!req)
++              if (!req || !test_bit(que, ha->req_qid_map))
+                       continue;
+               req->out_ptr = (void *)(req->ring + req->length);
+               *req->out_ptr = 0;
+@@ -2209,7 +2209,7 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
+       for (que = 0; que < ha->max_rsp_queues; que++) {
+               rsp = ha->rsp_q_map[que];
+-              if (!rsp)
++              if (!rsp || !test_bit(que, ha->rsp_qid_map))
+                       continue;
+               rsp->in_ptr = (void *)(rsp->ring + rsp->length);
+               *rsp->in_ptr = 0;
+@@ -4961,7 +4961,7 @@ qla25xx_init_queues(struct qla_hw_data *
+       for (i = 1; i < ha->max_rsp_queues; i++) {
+               rsp = ha->rsp_q_map[i];
+-              if (rsp) {
++              if (rsp && test_bit(i, ha->rsp_qid_map)) {
+                       rsp->options &= ~BIT_0;
+                       ret = qla25xx_init_rsp_que(base_vha, rsp);
+                       if (ret != QLA_SUCCESS)
+@@ -4976,8 +4976,8 @@ qla25xx_init_queues(struct qla_hw_data *
+       }
+       for (i = 1; i < ha->max_req_queues; i++) {
+               req = ha->req_q_map[i];
+-              if (req) {
+-              /* Clear outstanding commands array. */
++              if (req && test_bit(i, ha->req_qid_map)) {
++                      /* Clear outstanding commands array. */
+                       req->options &= ~BIT_0;
+                       ret = qla25xx_init_req_que(base_vha, req);
+                       if (ret != QLA_SUCCESS)
+--- a/drivers/scsi/qla2xxx/qla_isr.c
++++ b/drivers/scsi/qla2xxx/qla_isr.c
+@@ -3018,9 +3018,9 @@ qla24xx_enable_msix(struct qla_hw_data *
+                   "MSI-X: Failed to enable support "
+                   "-- %d/%d\n Retry with %d vectors.\n",
+                   ha->msix_count, ret, ret);
++              ha->msix_count = ret;
++              ha->max_rsp_queues = ha->msix_count - 1;
+       }
+-      ha->msix_count = ret;
+-      ha->max_rsp_queues = ha->msix_count - 1;
+       ha->msix_entries = kzalloc(sizeof(struct qla_msix_entry) *
+                               ha->msix_count, GFP_KERNEL);
+       if (!ha->msix_entries) {
+--- a/drivers/scsi/qla2xxx/qla_mid.c
++++ b/drivers/scsi/qla2xxx/qla_mid.c
+@@ -600,7 +600,7 @@ qla25xx_delete_queues(struct scsi_qla_ho
+       /* Delete request queues */
+       for (cnt = 1; cnt < ha->max_req_queues; cnt++) {
+               req = ha->req_q_map[cnt];
+-              if (req) {
++              if (req && test_bit(cnt, ha->req_qid_map)) {
+                       ret = qla25xx_delete_req_que(vha, req);
+                       if (ret != QLA_SUCCESS) {
+                               ql_log(ql_log_warn, vha, 0x00ea,
+@@ -614,7 +614,7 @@ qla25xx_delete_queues(struct scsi_qla_ho
+       /* Delete response queues */
+       for (cnt = 1; cnt < ha->max_rsp_queues; cnt++) {
+               rsp = ha->rsp_q_map[cnt];
+-              if (rsp) {
++              if (rsp && test_bit(cnt, ha->rsp_qid_map)) {
+                       ret = qla25xx_delete_rsp_que(vha, rsp);
+                       if (ret != QLA_SUCCESS) {
+                               ql_log(ql_log_warn, vha, 0x00eb,
+--- a/drivers/scsi/qla2xxx/qla_os.c
++++ b/drivers/scsi/qla2xxx/qla_os.c
+@@ -397,6 +397,9 @@ static void qla2x00_free_queues(struct q
+       int cnt;
+       for (cnt = 0; cnt < ha->max_req_queues; cnt++) {
++              if (!test_bit(cnt, ha->req_qid_map))
++                      continue;
++
+               req = ha->req_q_map[cnt];
+               qla2x00_free_req_que(ha, req);
+       }
+@@ -404,6 +407,9 @@ static void qla2x00_free_queues(struct q
+       ha->req_q_map = NULL;
+       for (cnt = 0; cnt < ha->max_rsp_queues; cnt++) {
++              if (!test_bit(cnt, ha->rsp_qid_map))
++                      continue;
++
+               rsp = ha->rsp_q_map[cnt];
+               qla2x00_free_rsp_que(ha, rsp);
+       }
+--- a/drivers/scsi/qla2xxx/qla_tmpl.c
++++ b/drivers/scsi/qla2xxx/qla_tmpl.c
+@@ -395,6 +395,10 @@ qla27xx_fwdt_entry_t263(struct scsi_qla_
+       if (ent->t263.queue_type == T263_QUEUE_TYPE_REQ) {
+               for (i = 0; i < vha->hw->max_req_queues; i++) {
+                       struct req_que *req = vha->hw->req_q_map[i];
++
++                      if (!test_bit(i, vha->hw->req_qid_map))
++                              continue;
++
+                       if (req || !buf) {
+                               length = req ?
+                                   req->length : REQUEST_ENTRY_CNT_24XX;
+@@ -408,6 +412,10 @@ qla27xx_fwdt_entry_t263(struct scsi_qla_
+       } else if (ent->t263.queue_type == T263_QUEUE_TYPE_RSP) {
+               for (i = 0; i < vha->hw->max_rsp_queues; i++) {
+                       struct rsp_que *rsp = vha->hw->rsp_q_map[i];
++
++                      if (!test_bit(i, vha->hw->rsp_qid_map))
++                              continue;
++
+                       if (rsp || !buf) {
+                               length = rsp ?
+                                   rsp->length : RESPONSE_ENTRY_CNT_MQ;
+@@ -634,6 +642,10 @@ qla27xx_fwdt_entry_t274(struct scsi_qla_
+       if (ent->t274.queue_type == T274_QUEUE_TYPE_REQ_SHAD) {
+               for (i = 0; i < vha->hw->max_req_queues; i++) {
+                       struct req_que *req = vha->hw->req_q_map[i];
++
++                      if (!test_bit(i, vha->hw->req_qid_map))
++                              continue;
++
+                       if (req || !buf) {
+                               qla27xx_insert16(i, buf, len);
+                               qla27xx_insert16(1, buf, len);
+@@ -645,6 +657,10 @@ qla27xx_fwdt_entry_t274(struct scsi_qla_
+       } else if (ent->t274.queue_type == T274_QUEUE_TYPE_RSP_SHAD) {
+               for (i = 0; i < vha->hw->max_rsp_queues; i++) {
+                       struct rsp_que *rsp = vha->hw->rsp_q_map[i];
++
++                      if (!test_bit(i, vha->hw->rsp_qid_map))
++                              continue;
++
+                       if (rsp || !buf) {
+                               qla27xx_insert16(i, buf, len);
+                               qla27xx_insert16(1, buf, len);
diff --git a/queue-4.4/revert-workqueue-make-sure-delayed-work-run-in-local-cpu.patch b/queue-4.4/revert-workqueue-make-sure-delayed-work-run-in-local-cpu.patch
new file mode 100644 (file)
index 0000000..712c32a
--- /dev/null
@@ -0,0 +1,75 @@
+From 041bd12e272c53a35c54c13875839bcb98c999ce Mon Sep 17 00:00:00 2001
+From: Tejun Heo <tj@kernel.org>
+Date: Tue, 9 Feb 2016 16:11:26 -0500
+Subject: Revert "workqueue: make sure delayed work run in local cpu"
+
+From: Tejun Heo <tj@kernel.org>
+
+commit 041bd12e272c53a35c54c13875839bcb98c999ce upstream.
+
+This reverts commit 874bbfe600a660cba9c776b3957b1ce393151b76.
+
+Workqueue used to implicity guarantee that work items queued without
+explicit CPU specified are put on the local CPU.  Recent changes in
+timer broke the guarantee and led to vmstat breakage which was fixed
+by 176bed1de5bf ("vmstat: explicitly schedule per-cpu work on the CPU
+we need it to run on").
+
+vmstat is the most likely to expose the issue and it's quite possible
+that there are other similar problems which are a lot more difficult
+to trigger.  As a preventive measure, 874bbfe600a6 ("workqueue: make
+sure delayed work run in local cpu") was applied to restore the local
+CPU guarnatee.  Unfortunately, the change exposed a bug in timer code
+which got fixed by 22b886dd1018 ("timers: Use proper base migration in
+add_timer_on()").  Due to code restructuring, the commit couldn't be
+backported beyond certain point and stable kernels which only had
+874bbfe600a6 started crashing.
+
+The local CPU guarantee was accidental more than anything else and we
+want to get rid of it anyway.  As, with the vmstat case fixed,
+874bbfe600a6 is causing more problems than it's fixing, it has been
+decided to take the chance and officially break the guarantee by
+reverting the commit.  A debug feature will be added to force foreign
+CPU assignment to expose cases relying on the guarantee and fixes for
+the individual cases will be backported to stable as necessary.
+
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Fixes: 874bbfe600a6 ("workqueue: make sure delayed work run in local cpu")
+Link: http://lkml.kernel.org/g/20160120211926.GJ10810@quack.suse.cz
+Cc: Mike Galbraith <umgwanakikbuti@gmail.com>
+Cc: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Cc: Daniel Bilik <daniel.bilik@neosystem.cz>
+Cc: Jan Kara <jack@suse.cz>
+Cc: Shaohua Li <shli@fb.com>
+Cc: Sasha Levin <sasha.levin@oracle.com>
+Cc: Ben Hutchings <ben@decadent.org.uk>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: Daniel Bilik <daniel.bilik@neosystem.cz>
+Cc: Jiri Slaby <jslaby@suse.cz>
+Cc: Michal Hocko <mhocko@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ kernel/workqueue.c |    8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/kernel/workqueue.c
++++ b/kernel/workqueue.c
+@@ -1468,13 +1468,13 @@ static void __queue_delayed_work(int cpu
+       timer_stats_timer_set_start_info(&dwork->timer);
+       dwork->wq = wq;
+-      /* timer isn't guaranteed to run in this cpu, record earlier */
+-      if (cpu == WORK_CPU_UNBOUND)
+-              cpu = raw_smp_processor_id();
+       dwork->cpu = cpu;
+       timer->expires = jiffies + delay;
+-      add_timer_on(timer, cpu);
++      if (unlikely(cpu != WORK_CPU_UNBOUND))
++              add_timer_on(timer, cpu);
++      else
++              add_timer(timer);
+ }
+ /**
diff --git a/queue-4.4/rfkill-fix-rfkill_fop_read-wait_event-usage.patch b/queue-4.4/rfkill-fix-rfkill_fop_read-wait_event-usage.patch
new file mode 100644 (file)
index 0000000..d70c3ef
--- /dev/null
@@ -0,0 +1,63 @@
+From 6736fde9672ff6717ac576e9bba2fd5f3dfec822 Mon Sep 17 00:00:00 2001
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Tue, 26 Jan 2016 11:29:03 +0100
+Subject: rfkill: fix rfkill_fop_read wait_event usage
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+commit 6736fde9672ff6717ac576e9bba2fd5f3dfec822 upstream.
+
+The code within wait_event_interruptible() is called with
+!TASK_RUNNING, so mustn't call any functions that can sleep,
+like mutex_lock().
+
+Since we re-check the list_empty() in a loop after the wait,
+it's safe to simply use list_empty() without locking.
+
+This bug has existed forever, but was only discovered now
+because all userspace implementations, including the default
+'rfkill' tool, use poll() or select() to get a readable fd
+before attempting to read.
+
+Fixes: c64fb01627e24 ("rfkill: create useful userspace interface")
+Reported-by: Dmitry Vyukov <dvyukov@google.com>
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/rfkill/core.c |   16 ++++------------
+ 1 file changed, 4 insertions(+), 12 deletions(-)
+
+--- a/net/rfkill/core.c
++++ b/net/rfkill/core.c
+@@ -1095,17 +1095,6 @@ static unsigned int rfkill_fop_poll(stru
+       return res;
+ }
+-static bool rfkill_readable(struct rfkill_data *data)
+-{
+-      bool r;
+-
+-      mutex_lock(&data->mtx);
+-      r = !list_empty(&data->events);
+-      mutex_unlock(&data->mtx);
+-
+-      return r;
+-}
+-
+ static ssize_t rfkill_fop_read(struct file *file, char __user *buf,
+                              size_t count, loff_t *pos)
+ {
+@@ -1122,8 +1111,11 @@ static ssize_t rfkill_fop_read(struct fi
+                       goto out;
+               }
+               mutex_unlock(&data->mtx);
++              /* since we re-check and it just compares pointers,
++               * using !list_empty() without locking isn't a problem
++               */
+               ret = wait_event_interruptible(data->read_wait,
+-                                             rfkill_readable(data));
++                                             !list_empty(&data->events));
+               mutex_lock(&data->mtx);
+               if (ret)
index e270955b32635d7a52b537c6ab1a7da44c099d73..a55467c7ed31ebf36c10e248400aee45205c765d 100644 (file)
@@ -267,3 +267,22 @@ libceph-don-t-spam-dmesg-with-stray-reply-warnings.patch
 sd-optimal-i-o-size-is-in-bytes-not-sectors.patch
 staging-speakup-fix-getting-port-information.patch
 revert-staging-panel-usleep_range-is-preferred-over-udelay.patch
+cdc-acm-exclude-samsung-phone-04e8-685d.patch
+perf-stat-do-not-clean-event-s-private-stats.patch
+tick-nohz-set-the-correct-expiry-when-switching-to-nohz-lowres-mode.patch
+rfkill-fix-rfkill_fop_read-wait_event-usage.patch
+mac80211-requeue-work-after-scan-complete-for-all-vif-types.patch
+workqueue-handle-numa_no_node-for-unbound-pool_workqueue-lookup.patch
+revert-workqueue-make-sure-delayed-work-run-in-local-cpu.patch
+alsa-hda-apply-clock-gate-workaround-to-skylake-too.patch
+alsa-hda-fixing-background-noise-on-dell-inspiron-3162.patch
+target-fix-lun_reset-active-i-o-handling-for-ack_kref.patch
+target-fix-lun_reset-active-tmr-descriptor-handling.patch
+target-fix-tas-handling-for-multi-session-se_node_acls.patch
+target-fix-remote-port-tmr-abort-se_cmd-fabric-stop.patch
+target-fix-race-with-scf_send_delayed_tas-handling.patch
+spi-atmel-fix-gpio-chip-select-in-case-of-non-dt-platform.patch
+qla2xxx-fix-stale-pointer-access.patch
+libata-fix-sff-host-state-machine-locking-while-polling.patch
+arcv2-star-9000950267-handle-return-from-intr-to-delay-slot-2.patch
+arcv2-smp-emulate-ipi-to-self-using-software-triggered-interrupt.patch
diff --git a/queue-4.4/spi-atmel-fix-gpio-chip-select-in-case-of-non-dt-platform.patch b/queue-4.4/spi-atmel-fix-gpio-chip-select-in-case-of-non-dt-platform.patch
new file mode 100644 (file)
index 0000000..4ee5274
--- /dev/null
@@ -0,0 +1,36 @@
+From 70f340df24518d36eeaefb6652d492f250115c19 Mon Sep 17 00:00:00 2001
+From: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+Date: Wed, 27 Jan 2016 17:48:32 +0100
+Subject: spi: atmel: fix gpio chip-select in case of non-DT platform
+
+From: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+
+commit 70f340df24518d36eeaefb6652d492f250115c19 upstream.
+
+The non-DT platform that uses this driver (actually the AVR32) was taking a bad
+branch for determining if the IP would use gpio for CS.
+Adding the presence of DT as a condition fixes this issue.
+
+Fixes: 4820303480a1 ("spi: atmel: add support for the internal chip-select of the spi controller")
+Reported-by: Mans Rullgard <mans@mansr.com>
+Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+[nicolas.ferre@atmel.com: extract from ml discussion]
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Tested-by: Mans Rullgard <mans@mansr.com>
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/spi/spi-atmel.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/spi/spi-atmel.c
++++ b/drivers/spi/spi-atmel.c
+@@ -1571,6 +1571,7 @@ static int atmel_spi_probe(struct platfo
+       as->use_cs_gpios = true;
+       if (atmel_spi_is_v2(as) &&
++          pdev->dev.of_node &&
+           !of_get_property(pdev->dev.of_node, "cs-gpios", NULL)) {
+               as->use_cs_gpios = false;
+               master->num_chipselect = 4;
diff --git a/queue-4.4/target-fix-lun_reset-active-i-o-handling-for-ack_kref.patch b/queue-4.4/target-fix-lun_reset-active-i-o-handling-for-ack_kref.patch
new file mode 100644 (file)
index 0000000..aee206e
--- /dev/null
@@ -0,0 +1,377 @@
+From febe562c20dfa8f33bee7d419c6b517986a5aa33 Mon Sep 17 00:00:00 2001
+From: Nicholas Bellinger <nab@linux-iscsi.org>
+Date: Mon, 11 Jan 2016 21:31:09 -0800
+Subject: target: Fix LUN_RESET active I/O handling for ACK_KREF
+
+From: Nicholas Bellinger <nab@linux-iscsi.org>
+
+commit febe562c20dfa8f33bee7d419c6b517986a5aa33 upstream.
+
+This patch fixes a NULL pointer se_cmd->cmd_kref < 0
+refcount bug during TMR LUN_RESET with active se_cmd
+I/O, that can be triggered during se_cmd descriptor
+shutdown + release via core_tmr_drain_state_list() code.
+
+To address this bug, add common __target_check_io_state()
+helper for ABORT_TASK + LUN_RESET w/ CMD_T_COMPLETE
+checking, and set CMD_T_ABORTED + obtain ->cmd_kref for
+both cases ahead of last target_put_sess_cmd() after
+TFO->aborted_task() -> transport_cmd_finish_abort()
+callback has completed.
+
+It also introduces SCF_ACK_KREF to determine when
+transport_cmd_finish_abort() needs to drop the second
+extra reference, ahead of calling target_put_sess_cmd()
+for the final kref_put(&se_cmd->cmd_kref).
+
+It also updates transport_cmd_check_stop() to avoid
+holding se_cmd->t_state_lock while dropping se_cmd
+device state via target_remove_from_state_list(), now
+that core_tmr_drain_state_list() is holding the
+se_device lock while checking se_cmd state from
+within TMR logic.
+
+Finally, move transport_put_cmd() release of SGL +
+TMR + extended CDB memory into target_free_cmd_mem()
+in order to avoid potential resource leaks in TMR
+ABORT_TASK + LUN_RESET code-paths.  Also update
+target_release_cmd_kref() accordingly.
+
+Reviewed-by: Quinn Tran <quinn.tran@qlogic.com>
+Cc: Himanshu Madhani <himanshu.madhani@qlogic.com>
+Cc: Sagi Grimberg <sagig@mellanox.com>
+Cc: Christoph Hellwig <hch@lst.de>
+Cc: Hannes Reinecke <hare@suse.de>
+Cc: Andy Grover <agrover@redhat.com>
+Cc: Mike Christie <mchristi@redhat.com>
+Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/target/target_core_tmr.c       |   69 ++++++++++++++++++++++-----------
+ drivers/target/target_core_transport.c |   67 +++++++++++++-------------------
+ include/target/target_core_base.h      |    1 
+ 3 files changed, 76 insertions(+), 61 deletions(-)
+
+--- a/drivers/target/target_core_tmr.c
++++ b/drivers/target/target_core_tmr.c
+@@ -107,6 +107,34 @@ static int target_check_cdb_and_preempt(
+       return 1;
+ }
++static bool __target_check_io_state(struct se_cmd *se_cmd)
++{
++      struct se_session *sess = se_cmd->se_sess;
++
++      assert_spin_locked(&sess->sess_cmd_lock);
++      WARN_ON_ONCE(!irqs_disabled());
++      /*
++       * If command already reached CMD_T_COMPLETE state within
++       * target_complete_cmd(), this se_cmd has been passed to
++       * fabric driver and will not be aborted.
++       *
++       * Otherwise, obtain a local se_cmd->cmd_kref now for TMR
++       * ABORT_TASK + LUN_RESET for CMD_T_ABORTED processing as
++       * long as se_cmd->cmd_kref is still active unless zero.
++       */
++      spin_lock(&se_cmd->t_state_lock);
++      if (se_cmd->transport_state & CMD_T_COMPLETE) {
++              pr_debug("Attempted to abort io tag: %llu already complete,"
++                      " skipping\n", se_cmd->tag);
++              spin_unlock(&se_cmd->t_state_lock);
++              return false;
++      }
++      se_cmd->transport_state |= CMD_T_ABORTED;
++      spin_unlock(&se_cmd->t_state_lock);
++
++      return kref_get_unless_zero(&se_cmd->cmd_kref);
++}
++
+ void core_tmr_abort_task(
+       struct se_device *dev,
+       struct se_tmr_req *tmr,
+@@ -130,34 +158,22 @@ void core_tmr_abort_task(
+               if (tmr->ref_task_tag != ref_tag)
+                       continue;
+-              if (!kref_get_unless_zero(&se_cmd->cmd_kref))
+-                      continue;
+-
+               printk("ABORT_TASK: Found referenced %s task_tag: %llu\n",
+                       se_cmd->se_tfo->get_fabric_name(), ref_tag);
+-              spin_lock(&se_cmd->t_state_lock);
+-              if (se_cmd->transport_state & CMD_T_COMPLETE) {
+-                      printk("ABORT_TASK: ref_tag: %llu already complete,"
+-                             " skipping\n", ref_tag);
+-                      spin_unlock(&se_cmd->t_state_lock);
++              if (!__target_check_io_state(se_cmd)) {
+                       spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+-
+                       target_put_sess_cmd(se_cmd);
+-
+                       goto out;
+               }
+-              se_cmd->transport_state |= CMD_T_ABORTED;
+-              spin_unlock(&se_cmd->t_state_lock);
+-
+               list_del_init(&se_cmd->se_cmd_list);
+               spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+               cancel_work_sync(&se_cmd->work);
+               transport_wait_for_tasks(se_cmd);
+-              target_put_sess_cmd(se_cmd);
+               transport_cmd_finish_abort(se_cmd, true);
++              target_put_sess_cmd(se_cmd);
+               printk("ABORT_TASK: Sending TMR_FUNCTION_COMPLETE for"
+                               " ref_tag: %llu\n", ref_tag);
+@@ -242,8 +258,10 @@ static void core_tmr_drain_state_list(
+       struct list_head *preempt_and_abort_list)
+ {
+       LIST_HEAD(drain_task_list);
++      struct se_session *sess;
+       struct se_cmd *cmd, *next;
+       unsigned long flags;
++      int rc;
+       /*
+        * Complete outstanding commands with TASK_ABORTED SAM status.
+@@ -282,6 +300,16 @@ static void core_tmr_drain_state_list(
+               if (prout_cmd == cmd)
+                       continue;
++              sess = cmd->se_sess;
++              if (WARN_ON_ONCE(!sess))
++                      continue;
++
++              spin_lock(&sess->sess_cmd_lock);
++              rc = __target_check_io_state(cmd);
++              spin_unlock(&sess->sess_cmd_lock);
++              if (!rc)
++                      continue;
++
+               list_move_tail(&cmd->state_list, &drain_task_list);
+               cmd->state_active = false;
+       }
+@@ -289,7 +317,7 @@ static void core_tmr_drain_state_list(
+       while (!list_empty(&drain_task_list)) {
+               cmd = list_entry(drain_task_list.next, struct se_cmd, state_list);
+-              list_del(&cmd->state_list);
++              list_del_init(&cmd->state_list);
+               pr_debug("LUN_RESET: %s cmd: %p"
+                       " ITT/CmdSN: 0x%08llx/0x%08x, i_state: %d, t_state: %d"
+@@ -313,16 +341,11 @@ static void core_tmr_drain_state_list(
+                * loop above, but we do it down here given that
+                * cancel_work_sync may block.
+                */
+-              if (cmd->t_state == TRANSPORT_COMPLETE)
+-                      cancel_work_sync(&cmd->work);
+-
+-              spin_lock_irqsave(&cmd->t_state_lock, flags);
+-              target_stop_cmd(cmd, &flags);
+-
+-              cmd->transport_state |= CMD_T_ABORTED;
+-              spin_unlock_irqrestore(&cmd->t_state_lock, flags);
++              cancel_work_sync(&cmd->work);
++              transport_wait_for_tasks(cmd);
+               core_tmr_handle_tas_abort(tmr_nacl, cmd, tas);
++              target_put_sess_cmd(cmd);
+       }
+ }
+--- a/drivers/target/target_core_transport.c
++++ b/drivers/target/target_core_transport.c
+@@ -528,9 +528,6 @@ void transport_deregister_session(struct
+ }
+ EXPORT_SYMBOL(transport_deregister_session);
+-/*
+- * Called with cmd->t_state_lock held.
+- */
+ static void target_remove_from_state_list(struct se_cmd *cmd)
+ {
+       struct se_device *dev = cmd->se_dev;
+@@ -555,10 +552,6 @@ static int transport_cmd_check_stop(stru
+ {
+       unsigned long flags;
+-      spin_lock_irqsave(&cmd->t_state_lock, flags);
+-      if (write_pending)
+-              cmd->t_state = TRANSPORT_WRITE_PENDING;
+-
+       if (remove_from_lists) {
+               target_remove_from_state_list(cmd);
+@@ -568,6 +561,10 @@ static int transport_cmd_check_stop(stru
+               cmd->se_lun = NULL;
+       }
++      spin_lock_irqsave(&cmd->t_state_lock, flags);
++      if (write_pending)
++              cmd->t_state = TRANSPORT_WRITE_PENDING;
++
+       /*
+        * Determine if frontend context caller is requesting the stopping of
+        * this command for frontend exceptions.
+@@ -621,6 +618,8 @@ static void transport_lun_remove_cmd(str
+ void transport_cmd_finish_abort(struct se_cmd *cmd, int remove)
+ {
++      bool ack_kref = (cmd->se_cmd_flags & SCF_ACK_KREF);
++
+       if (cmd->se_cmd_flags & SCF_SE_LUN_CMD)
+               transport_lun_remove_cmd(cmd);
+       /*
+@@ -632,7 +631,7 @@ void transport_cmd_finish_abort(struct s
+       if (transport_cmd_check_stop_to_fabric(cmd))
+               return;
+-      if (remove)
++      if (remove && ack_kref)
+               transport_put_cmd(cmd);
+ }
+@@ -700,7 +699,7 @@ void target_complete_cmd(struct se_cmd *
+        * Check for case where an explicit ABORT_TASK has been received
+        * and transport_wait_for_tasks() will be waiting for completion..
+        */
+-      if (cmd->transport_state & CMD_T_ABORTED &&
++      if (cmd->transport_state & CMD_T_ABORTED ||
+           cmd->transport_state & CMD_T_STOP) {
+               spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+               complete_all(&cmd->t_transport_stop_comp);
+@@ -2213,20 +2212,14 @@ static inline void transport_free_pages(
+ }
+ /**
+- * transport_release_cmd - free a command
+- * @cmd:       command to free
++ * transport_put_cmd - release a reference to a command
++ * @cmd:       command to release
+  *
+- * This routine unconditionally frees a command, and reference counting
+- * or list removal must be done in the caller.
++ * This routine releases our reference to the command and frees it if possible.
+  */
+-static int transport_release_cmd(struct se_cmd *cmd)
++static int transport_put_cmd(struct se_cmd *cmd)
+ {
+       BUG_ON(!cmd->se_tfo);
+-
+-      if (cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)
+-              core_tmr_release_req(cmd->se_tmr_req);
+-      if (cmd->t_task_cdb != cmd->__t_task_cdb)
+-              kfree(cmd->t_task_cdb);
+       /*
+        * If this cmd has been setup with target_get_sess_cmd(), drop
+        * the kref and call ->release_cmd() in kref callback.
+@@ -2234,18 +2227,6 @@ static int transport_release_cmd(struct
+       return target_put_sess_cmd(cmd);
+ }
+-/**
+- * transport_put_cmd - release a reference to a command
+- * @cmd:       command to release
+- *
+- * This routine releases our reference to the command and frees it if possible.
+- */
+-static int transport_put_cmd(struct se_cmd *cmd)
+-{
+-      transport_free_pages(cmd);
+-      return transport_release_cmd(cmd);
+-}
+-
+ void *transport_kmap_data_sg(struct se_cmd *cmd)
+ {
+       struct scatterlist *sg = cmd->t_data_sg;
+@@ -2443,14 +2424,13 @@ static void transport_write_pending_qf(s
+ int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks)
+ {
+-      unsigned long flags;
+       int ret = 0;
+       if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD)) {
+               if (wait_for_tasks && (cmd->se_cmd_flags & SCF_SCSI_TMR_CDB))
+-                       transport_wait_for_tasks(cmd);
++                      transport_wait_for_tasks(cmd);
+-              ret = transport_release_cmd(cmd);
++              ret = transport_put_cmd(cmd);
+       } else {
+               if (wait_for_tasks)
+                       transport_wait_for_tasks(cmd);
+@@ -2459,11 +2439,8 @@ int transport_generic_free_cmd(struct se
+                * has already added se_cmd to state_list, but fabric has
+                * failed command before I/O submission.
+                */
+-              if (cmd->state_active) {
+-                      spin_lock_irqsave(&cmd->t_state_lock, flags);
++              if (cmd->state_active)
+                       target_remove_from_state_list(cmd);
+-                      spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+-              }
+               if (cmd->se_lun)
+                       transport_lun_remove_cmd(cmd);
+@@ -2508,6 +2485,16 @@ out:
+ }
+ EXPORT_SYMBOL(target_get_sess_cmd);
++static void target_free_cmd_mem(struct se_cmd *cmd)
++{
++      transport_free_pages(cmd);
++
++      if (cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)
++              core_tmr_release_req(cmd->se_tmr_req);
++      if (cmd->t_task_cdb != cmd->__t_task_cdb)
++              kfree(cmd->t_task_cdb);
++}
++
+ static void target_release_cmd_kref(struct kref *kref)
+ {
+       struct se_cmd *se_cmd = container_of(kref, struct se_cmd, cmd_kref);
+@@ -2517,17 +2504,20 @@ static void target_release_cmd_kref(stru
+       spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
+       if (list_empty(&se_cmd->se_cmd_list)) {
+               spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
++              target_free_cmd_mem(se_cmd);
+               se_cmd->se_tfo->release_cmd(se_cmd);
+               return;
+       }
+       if (se_sess->sess_tearing_down && se_cmd->cmd_wait_set) {
+               spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
++              target_free_cmd_mem(se_cmd);
+               complete(&se_cmd->cmd_wait_comp);
+               return;
+       }
+       list_del(&se_cmd->se_cmd_list);
+       spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
++      target_free_cmd_mem(se_cmd);
+       se_cmd->se_tfo->release_cmd(se_cmd);
+ }
+@@ -2539,6 +2529,7 @@ int target_put_sess_cmd(struct se_cmd *s
+       struct se_session *se_sess = se_cmd->se_sess;
+       if (!se_sess) {
++              target_free_cmd_mem(se_cmd);
+               se_cmd->se_tfo->release_cmd(se_cmd);
+               return 1;
+       }
+--- a/include/target/target_core_base.h
++++ b/include/target/target_core_base.h
+@@ -138,6 +138,7 @@ enum se_cmd_flags_table {
+       SCF_COMPARE_AND_WRITE           = 0x00080000,
+       SCF_COMPARE_AND_WRITE_POST      = 0x00100000,
+       SCF_PASSTHROUGH_PROT_SG_TO_MEM_NOALLOC = 0x00200000,
++      SCF_ACK_KREF                    = 0x00400000,
+ };
+ /* struct se_dev_entry->lun_flags and struct se_lun->lun_access */
diff --git a/queue-4.4/target-fix-lun_reset-active-tmr-descriptor-handling.patch b/queue-4.4/target-fix-lun_reset-active-tmr-descriptor-handling.patch
new file mode 100644 (file)
index 0000000..daba7bf
--- /dev/null
@@ -0,0 +1,149 @@
+From a6d9bb1c9605cd4f44e2d8290dc4d0e88f20292d Mon Sep 17 00:00:00 2001
+From: Nicholas Bellinger <nab@linux-iscsi.org>
+Date: Mon, 11 Jan 2016 21:53:05 -0800
+Subject: target: Fix LUN_RESET active TMR descriptor handling
+
+From: Nicholas Bellinger <nab@linux-iscsi.org>
+
+commit a6d9bb1c9605cd4f44e2d8290dc4d0e88f20292d upstream.
+
+This patch fixes a NULL pointer se_cmd->cmd_kref < 0
+refcount bug during TMR LUN_RESET with active TMRs,
+triggered during se_cmd + se_tmr_req descriptor
+shutdown + release via core_tmr_drain_tmr_list().
+
+To address this bug, go ahead and obtain a local
+kref_get_unless_zero(&se_cmd->cmd_kref) for active I/O
+to set CMD_T_ABORTED, and transport_wait_for_tasks()
+followed by the final target_put_sess_cmd() to drop
+the local ->cmd_kref.
+
+Also add two new checks within target_tmr_work() to
+avoid CMD_T_ABORTED -> TFO->queue_tm_rsp() callbacks
+ahead of invoking the backend -> fabric put in
+transport_cmd_check_stop_to_fabric().
+
+For good measure, also change core_tmr_release_req()
+to use list_del_init() ahead of se_tmr_req memory
+free.
+
+Reviewed-by: Quinn Tran <quinn.tran@qlogic.com>
+Cc: Himanshu Madhani <himanshu.madhani@qlogic.com>
+Cc: Sagi Grimberg <sagig@mellanox.com>
+Cc: Christoph Hellwig <hch@lst.de>
+Cc: Hannes Reinecke <hare@suse.de>
+Cc: Andy Grover <agrover@redhat.com>
+Cc: Mike Christie <mchristi@redhat.com>
+Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/target/target_core_tmr.c       |   22 +++++++++++++++++++++-
+ drivers/target/target_core_transport.c |   17 +++++++++++++++++
+ 2 files changed, 38 insertions(+), 1 deletion(-)
+
+--- a/drivers/target/target_core_tmr.c
++++ b/drivers/target/target_core_tmr.c
+@@ -68,7 +68,7 @@ void core_tmr_release_req(struct se_tmr_
+       if (dev) {
+               spin_lock_irqsave(&dev->se_tmr_lock, flags);
+-              list_del(&tmr->tmr_list);
++              list_del_init(&tmr->tmr_list);
+               spin_unlock_irqrestore(&dev->se_tmr_lock, flags);
+       }
+@@ -194,9 +194,11 @@ static void core_tmr_drain_tmr_list(
+       struct list_head *preempt_and_abort_list)
+ {
+       LIST_HEAD(drain_tmr_list);
++      struct se_session *sess;
+       struct se_tmr_req *tmr_p, *tmr_pp;
+       struct se_cmd *cmd;
+       unsigned long flags;
++      bool rc;
+       /*
+        * Release all pending and outgoing TMRs aside from the received
+        * LUN_RESET tmr..
+@@ -222,17 +224,31 @@ static void core_tmr_drain_tmr_list(
+               if (target_check_cdb_and_preempt(preempt_and_abort_list, cmd))
+                       continue;
++              sess = cmd->se_sess;
++              if (WARN_ON_ONCE(!sess))
++                      continue;
++
++              spin_lock(&sess->sess_cmd_lock);
+               spin_lock(&cmd->t_state_lock);
+               if (!(cmd->transport_state & CMD_T_ACTIVE)) {
+                       spin_unlock(&cmd->t_state_lock);
++                      spin_unlock(&sess->sess_cmd_lock);
+                       continue;
+               }
+               if (cmd->t_state == TRANSPORT_ISTATE_PROCESSING) {
+                       spin_unlock(&cmd->t_state_lock);
++                      spin_unlock(&sess->sess_cmd_lock);
+                       continue;
+               }
++              cmd->transport_state |= CMD_T_ABORTED;
+               spin_unlock(&cmd->t_state_lock);
++              rc = kref_get_unless_zero(&cmd->cmd_kref);
++              spin_unlock(&sess->sess_cmd_lock);
++              if (!rc) {
++                      printk("LUN_RESET TMR: non-zero kref_get_unless_zero\n");
++                      continue;
++              }
+               list_move_tail(&tmr_p->tmr_list, &drain_tmr_list);
+       }
+       spin_unlock_irqrestore(&dev->se_tmr_lock, flags);
+@@ -246,7 +262,11 @@ static void core_tmr_drain_tmr_list(
+                       (preempt_and_abort_list) ? "Preempt" : "", tmr_p,
+                       tmr_p->function, tmr_p->response, cmd->t_state);
++              cancel_work_sync(&cmd->work);
++              transport_wait_for_tasks(cmd);
++
+               transport_cmd_finish_abort(cmd, 1);
++              target_put_sess_cmd(cmd);
+       }
+ }
+--- a/drivers/target/target_core_transport.c
++++ b/drivers/target/target_core_transport.c
+@@ -2891,8 +2891,17 @@ static void target_tmr_work(struct work_
+       struct se_cmd *cmd = container_of(work, struct se_cmd, work);
+       struct se_device *dev = cmd->se_dev;
+       struct se_tmr_req *tmr = cmd->se_tmr_req;
++      unsigned long flags;
+       int ret;
++      spin_lock_irqsave(&cmd->t_state_lock, flags);
++      if (cmd->transport_state & CMD_T_ABORTED) {
++              tmr->response = TMR_FUNCTION_REJECTED;
++              spin_unlock_irqrestore(&cmd->t_state_lock, flags);
++              goto check_stop;
++      }
++      spin_unlock_irqrestore(&cmd->t_state_lock, flags);
++
+       switch (tmr->function) {
+       case TMR_ABORT_TASK:
+               core_tmr_abort_task(dev, tmr, cmd->se_sess);
+@@ -2925,9 +2934,17 @@ static void target_tmr_work(struct work_
+               break;
+       }
++      spin_lock_irqsave(&cmd->t_state_lock, flags);
++      if (cmd->transport_state & CMD_T_ABORTED) {
++              spin_unlock_irqrestore(&cmd->t_state_lock, flags);
++              goto check_stop;
++      }
+       cmd->t_state = TRANSPORT_ISTATE_PROCESSING;
++      spin_unlock_irqrestore(&cmd->t_state_lock, flags);
++
+       cmd->se_tfo->queue_tm_rsp(cmd);
++check_stop:
+       transport_cmd_check_stop_to_fabric(cmd);
+ }
diff --git a/queue-4.4/target-fix-race-with-scf_send_delayed_tas-handling.patch b/queue-4.4/target-fix-race-with-scf_send_delayed_tas-handling.patch
new file mode 100644 (file)
index 0000000..607c0bc
--- /dev/null
@@ -0,0 +1,141 @@
+From 310d3d314be7f0a84011ebdc4bdccbcae9755a87 Mon Sep 17 00:00:00 2001
+From: Nicholas Bellinger <nab@linux-iscsi.org>
+Date: Fri, 5 Feb 2016 14:51:36 -0800
+Subject: target: Fix race with SCF_SEND_DELAYED_TAS handling
+
+From: Nicholas Bellinger <nab@linux-iscsi.org>
+
+commit 310d3d314be7f0a84011ebdc4bdccbcae9755a87 upstream.
+
+This patch fixes a race between setting of SCF_SEND_DELAYED_TAS
+in transport_send_task_abort(), and check of the same bit in
+transport_check_aborted_status().
+
+It adds a __transport_check_aborted_status() version that is
+used by target_execute_cmd() when se_cmd->t_state_lock is
+held, and a transport_check_aborted_status() wrapper for
+all other existing callers.
+
+Also, it handles the case where the check happens before
+transport_send_task_abort() gets called.  For this, go
+ahead and set SCF_SEND_DELAYED_TAS early when necessary,
+and have transport_send_task_abort() send the abort.
+
+Cc: Quinn Tran <quinn.tran@qlogic.com>
+Cc: Himanshu Madhani <himanshu.madhani@qlogic.com>
+Cc: Sagi Grimberg <sagig@mellanox.com>
+Cc: Christoph Hellwig <hch@lst.de>
+Cc: Hannes Reinecke <hare@suse.de>
+Cc: Andy Grover <agrover@redhat.com>
+Cc: Mike Christie <mchristi@redhat.com>
+Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/target/target_core_transport.c |   53 +++++++++++++++++++++++++--------
+ 1 file changed, 41 insertions(+), 12 deletions(-)
+
+--- a/drivers/target/target_core_transport.c
++++ b/drivers/target/target_core_transport.c
+@@ -1849,19 +1849,21 @@ static bool target_handle_task_attr(stru
+       return true;
+ }
++static int __transport_check_aborted_status(struct se_cmd *, int);
++
+ void target_execute_cmd(struct se_cmd *cmd)
+ {
+       /*
+-       * If the received CDB has aleady been aborted stop processing it here.
+-       */
+-      if (transport_check_aborted_status(cmd, 1))
+-              return;
+-
+-      /*
+        * Determine if frontend context caller is requesting the stopping of
+        * this command for frontend exceptions.
++       *
++       * If the received CDB has aleady been aborted stop processing it here.
+        */
+       spin_lock_irq(&cmd->t_state_lock);
++      if (__transport_check_aborted_status(cmd, 1)) {
++              spin_unlock_irq(&cmd->t_state_lock);
++              return;
++      }
+       if (cmd->transport_state & CMD_T_STOP) {
+               pr_debug("%s:%d CMD_T_STOP for ITT: 0x%08llx\n",
+                       __func__, __LINE__, cmd->tag);
+@@ -2902,28 +2904,49 @@ transport_send_check_condition_and_sense
+ }
+ EXPORT_SYMBOL(transport_send_check_condition_and_sense);
+-int transport_check_aborted_status(struct se_cmd *cmd, int send_status)
++static int __transport_check_aborted_status(struct se_cmd *cmd, int send_status)
++      __releases(&cmd->t_state_lock)
++      __acquires(&cmd->t_state_lock)
+ {
++      assert_spin_locked(&cmd->t_state_lock);
++      WARN_ON_ONCE(!irqs_disabled());
++
+       if (!(cmd->transport_state & CMD_T_ABORTED))
+               return 0;
+-
+       /*
+        * If cmd has been aborted but either no status is to be sent or it has
+        * already been sent, just return
+        */
+-      if (!send_status || !(cmd->se_cmd_flags & SCF_SEND_DELAYED_TAS))
++      if (!send_status || !(cmd->se_cmd_flags & SCF_SEND_DELAYED_TAS)) {
++              if (send_status)
++                      cmd->se_cmd_flags |= SCF_SEND_DELAYED_TAS;
+               return 1;
++      }
+-      pr_debug("Sending delayed SAM_STAT_TASK_ABORTED status for CDB: 0x%02x ITT: 0x%08llx\n",
+-               cmd->t_task_cdb[0], cmd->tag);
++      pr_debug("Sending delayed SAM_STAT_TASK_ABORTED status for CDB:"
++              " 0x%02x ITT: 0x%08llx\n", cmd->t_task_cdb[0], cmd->tag);
+       cmd->se_cmd_flags &= ~SCF_SEND_DELAYED_TAS;
+       cmd->scsi_status = SAM_STAT_TASK_ABORTED;
+       trace_target_cmd_complete(cmd);
++
++      spin_unlock_irq(&cmd->t_state_lock);
+       cmd->se_tfo->queue_status(cmd);
++      spin_lock_irq(&cmd->t_state_lock);
+       return 1;
+ }
++
++int transport_check_aborted_status(struct se_cmd *cmd, int send_status)
++{
++      int ret;
++
++      spin_lock_irq(&cmd->t_state_lock);
++      ret = __transport_check_aborted_status(cmd, send_status);
++      spin_unlock_irq(&cmd->t_state_lock);
++
++      return ret;
++}
+ EXPORT_SYMBOL(transport_check_aborted_status);
+ void transport_send_task_abort(struct se_cmd *cmd)
+@@ -2945,11 +2968,17 @@ void transport_send_task_abort(struct se
+        */
+       if (cmd->data_direction == DMA_TO_DEVICE) {
+               if (cmd->se_tfo->write_pending_status(cmd) != 0) {
+-                      cmd->transport_state |= CMD_T_ABORTED;
++                      spin_lock_irqsave(&cmd->t_state_lock, flags);
++                      if (cmd->se_cmd_flags & SCF_SEND_DELAYED_TAS) {
++                              spin_unlock_irqrestore(&cmd->t_state_lock, flags);
++                              goto send_abort;
++                      }
+                       cmd->se_cmd_flags |= SCF_SEND_DELAYED_TAS;
++                      spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+                       return;
+               }
+       }
++send_abort:
+       cmd->scsi_status = SAM_STAT_TASK_ABORTED;
+       transport_lun_remove_cmd(cmd);
diff --git a/queue-4.4/target-fix-remote-port-tmr-abort-se_cmd-fabric-stop.patch b/queue-4.4/target-fix-remote-port-tmr-abort-se_cmd-fabric-stop.patch
new file mode 100644 (file)
index 0000000..1556f46
--- /dev/null
@@ -0,0 +1,441 @@
+From 0f4a943168f31d29a1701908931acaba518b131a Mon Sep 17 00:00:00 2001
+From: Nicholas Bellinger <nab@linux-iscsi.org>
+Date: Tue, 19 Jan 2016 15:23:02 -0800
+Subject: target: Fix remote-port TMR ABORT + se_cmd fabric stop
+
+From: Nicholas Bellinger <nab@linux-iscsi.org>
+
+commit 0f4a943168f31d29a1701908931acaba518b131a upstream.
+
+To address the bug where fabric driver level shutdown
+of se_cmd occurs at the same time when TMR CMD_T_ABORTED
+is happening resulting in a -1 ->cmd_kref, this patch
+adds a CMD_T_FABRIC_STOP bit that is used to determine
+when TMR + driver I_T nexus shutdown is happening
+concurrently.
+
+It changes target_sess_cmd_list_set_waiting() to obtain
+se_cmd->cmd_kref + set CMD_T_FABRIC_STOP, and drop local
+reference in target_wait_for_sess_cmds() and invoke extra
+target_put_sess_cmd() during Task Aborted Status (TAS)
+when necessary.
+
+Also, it adds a new target_wait_free_cmd() wrapper around
+transport_wait_for_tasks() for the special case within
+transport_generic_free_cmd() to set CMD_T_FABRIC_STOP,
+and is now aware of CMD_T_ABORTED + CMD_T_TAS status
+bits to know when an extra transport_put_cmd() during
+TAS is required.
+
+Note transport_generic_free_cmd() is expected to block on
+cmd->cmd_wait_comp in order to follow what iscsi-target
+expects during iscsi_conn context se_cmd shutdown.
+
+Cc: Quinn Tran <quinn.tran@qlogic.com>
+Cc: Himanshu Madhani <himanshu.madhani@qlogic.com>
+Cc: Sagi Grimberg <sagig@mellanox.com>
+Cc: Christoph Hellwig <hch@lst.de>
+Cc: Hannes Reinecke <hare@suse.de>
+Cc: Andy Grover <agrover@redhat.com>
+Cc: Mike Christie <mchristi@redhat.com>
+Signed-off-by: Nicholas Bellinger <nab@daterainc.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/target/target_core_tmr.c       |   54 ++++++++----
+ drivers/target/target_core_transport.c |  145 +++++++++++++++++++++++++--------
+ include/target/target_core_base.h      |    2 
+ 3 files changed, 150 insertions(+), 51 deletions(-)
+
+--- a/drivers/target/target_core_tmr.c
++++ b/drivers/target/target_core_tmr.c
+@@ -75,16 +75,18 @@ void core_tmr_release_req(struct se_tmr_
+       kfree(tmr);
+ }
+-static void core_tmr_handle_tas_abort(
+-      struct se_session *tmr_sess,
+-      struct se_cmd *cmd,
+-      int tas)
++static void core_tmr_handle_tas_abort(struct se_cmd *cmd, int tas)
+ {
+-      bool remove = true;
++      unsigned long flags;
++      bool remove = true, send_tas;
+       /*
+        * TASK ABORTED status (TAS) bit support
+        */
+-      if (tmr_sess && tmr_sess != cmd->se_sess && tas) {
++      spin_lock_irqsave(&cmd->t_state_lock, flags);
++      send_tas = (cmd->transport_state & CMD_T_TAS);
++      spin_unlock_irqrestore(&cmd->t_state_lock, flags);
++
++      if (send_tas) {
+               remove = false;
+               transport_send_task_abort(cmd);
+       }
+@@ -107,7 +109,8 @@ static int target_check_cdb_and_preempt(
+       return 1;
+ }
+-static bool __target_check_io_state(struct se_cmd *se_cmd)
++static bool __target_check_io_state(struct se_cmd *se_cmd,
++                                  struct se_session *tmr_sess, int tas)
+ {
+       struct se_session *sess = se_cmd->se_sess;
+@@ -115,21 +118,32 @@ static bool __target_check_io_state(stru
+       WARN_ON_ONCE(!irqs_disabled());
+       /*
+        * If command already reached CMD_T_COMPLETE state within
+-       * target_complete_cmd(), this se_cmd has been passed to
+-       * fabric driver and will not be aborted.
++       * target_complete_cmd() or CMD_T_FABRIC_STOP due to shutdown,
++       * this se_cmd has been passed to fabric driver and will
++       * not be aborted.
+        *
+        * Otherwise, obtain a local se_cmd->cmd_kref now for TMR
+        * ABORT_TASK + LUN_RESET for CMD_T_ABORTED processing as
+        * long as se_cmd->cmd_kref is still active unless zero.
+        */
+       spin_lock(&se_cmd->t_state_lock);
+-      if (se_cmd->transport_state & CMD_T_COMPLETE) {
+-              pr_debug("Attempted to abort io tag: %llu already complete,"
++      if (se_cmd->transport_state & (CMD_T_COMPLETE | CMD_T_FABRIC_STOP)) {
++              pr_debug("Attempted to abort io tag: %llu already complete or"
++                      " fabric stop, skipping\n", se_cmd->tag);
++              spin_unlock(&se_cmd->t_state_lock);
++              return false;
++      }
++      if (sess->sess_tearing_down || se_cmd->cmd_wait_set) {
++              pr_debug("Attempted to abort io tag: %llu already shutdown,"
+                       " skipping\n", se_cmd->tag);
+               spin_unlock(&se_cmd->t_state_lock);
+               return false;
+       }
+       se_cmd->transport_state |= CMD_T_ABORTED;
++
++      if ((tmr_sess != se_cmd->se_sess) && tas)
++              se_cmd->transport_state |= CMD_T_TAS;
++
+       spin_unlock(&se_cmd->t_state_lock);
+       return kref_get_unless_zero(&se_cmd->cmd_kref);
+@@ -161,7 +175,7 @@ void core_tmr_abort_task(
+               printk("ABORT_TASK: Found referenced %s task_tag: %llu\n",
+                       se_cmd->se_tfo->get_fabric_name(), ref_tag);
+-              if (!__target_check_io_state(se_cmd)) {
++              if (!__target_check_io_state(se_cmd, se_sess, 0)) {
+                       spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+                       target_put_sess_cmd(se_cmd);
+                       goto out;
+@@ -230,7 +244,8 @@ static void core_tmr_drain_tmr_list(
+               spin_lock(&sess->sess_cmd_lock);
+               spin_lock(&cmd->t_state_lock);
+-              if (!(cmd->transport_state & CMD_T_ACTIVE)) {
++              if (!(cmd->transport_state & CMD_T_ACTIVE) ||
++                   (cmd->transport_state & CMD_T_FABRIC_STOP)) {
+                       spin_unlock(&cmd->t_state_lock);
+                       spin_unlock(&sess->sess_cmd_lock);
+                       continue;
+@@ -240,15 +255,22 @@ static void core_tmr_drain_tmr_list(
+                       spin_unlock(&sess->sess_cmd_lock);
+                       continue;
+               }
++              if (sess->sess_tearing_down || cmd->cmd_wait_set) {
++                      spin_unlock(&cmd->t_state_lock);
++                      spin_unlock(&sess->sess_cmd_lock);
++                      continue;
++              }
+               cmd->transport_state |= CMD_T_ABORTED;
+               spin_unlock(&cmd->t_state_lock);
+               rc = kref_get_unless_zero(&cmd->cmd_kref);
+-              spin_unlock(&sess->sess_cmd_lock);
+               if (!rc) {
+                       printk("LUN_RESET TMR: non-zero kref_get_unless_zero\n");
++                      spin_unlock(&sess->sess_cmd_lock);
+                       continue;
+               }
++              spin_unlock(&sess->sess_cmd_lock);
++
+               list_move_tail(&tmr_p->tmr_list, &drain_tmr_list);
+       }
+       spin_unlock_irqrestore(&dev->se_tmr_lock, flags);
+@@ -325,7 +347,7 @@ static void core_tmr_drain_state_list(
+                       continue;
+               spin_lock(&sess->sess_cmd_lock);
+-              rc = __target_check_io_state(cmd);
++              rc = __target_check_io_state(cmd, tmr_sess, tas);
+               spin_unlock(&sess->sess_cmd_lock);
+               if (!rc)
+                       continue;
+@@ -364,7 +386,7 @@ static void core_tmr_drain_state_list(
+               cancel_work_sync(&cmd->work);
+               transport_wait_for_tasks(cmd);
+-              core_tmr_handle_tas_abort(tmr_sess, cmd, tas);
++              core_tmr_handle_tas_abort(cmd, tas);
+               target_put_sess_cmd(cmd);
+       }
+ }
+--- a/drivers/target/target_core_transport.c
++++ b/drivers/target/target_core_transport.c
+@@ -2422,18 +2422,33 @@ static void transport_write_pending_qf(s
+       }
+ }
++static bool
++__transport_wait_for_tasks(struct se_cmd *, bool, bool *, bool *,
++                         unsigned long *flags);
++
++static void target_wait_free_cmd(struct se_cmd *cmd, bool *aborted, bool *tas)
++{
++      unsigned long flags;
++
++      spin_lock_irqsave(&cmd->t_state_lock, flags);
++      __transport_wait_for_tasks(cmd, true, aborted, tas, &flags);
++      spin_unlock_irqrestore(&cmd->t_state_lock, flags);
++}
++
+ int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks)
+ {
+       int ret = 0;
++      bool aborted = false, tas = false;
+       if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD)) {
+               if (wait_for_tasks && (cmd->se_cmd_flags & SCF_SCSI_TMR_CDB))
+-                      transport_wait_for_tasks(cmd);
++                      target_wait_free_cmd(cmd, &aborted, &tas);
+-              ret = transport_put_cmd(cmd);
++              if (!aborted || tas)
++                      ret = transport_put_cmd(cmd);
+       } else {
+               if (wait_for_tasks)
+-                      transport_wait_for_tasks(cmd);
++                      target_wait_free_cmd(cmd, &aborted, &tas);
+               /*
+                * Handle WRITE failure case where transport_generic_new_cmd()
+                * has already added se_cmd to state_list, but fabric has
+@@ -2445,7 +2460,20 @@ int transport_generic_free_cmd(struct se
+               if (cmd->se_lun)
+                       transport_lun_remove_cmd(cmd);
+-              ret = transport_put_cmd(cmd);
++              if (!aborted || tas)
++                      ret = transport_put_cmd(cmd);
++      }
++      /*
++       * If the task has been internally aborted due to TMR ABORT_TASK
++       * or LUN_RESET, target_core_tmr.c is responsible for performing
++       * the remaining calls to target_put_sess_cmd(), and not the
++       * callers of this function.
++       */
++      if (aborted) {
++              pr_debug("Detected CMD_T_ABORTED for ITT: %llu\n", cmd->tag);
++              wait_for_completion(&cmd->cmd_wait_comp);
++              cmd->se_tfo->release_cmd(cmd);
++              ret = 1;
+       }
+       return ret;
+ }
+@@ -2500,6 +2528,7 @@ static void target_release_cmd_kref(stru
+       struct se_cmd *se_cmd = container_of(kref, struct se_cmd, cmd_kref);
+       struct se_session *se_sess = se_cmd->se_sess;
+       unsigned long flags;
++      bool fabric_stop;
+       spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
+       if (list_empty(&se_cmd->se_cmd_list)) {
+@@ -2508,13 +2537,19 @@ static void target_release_cmd_kref(stru
+               se_cmd->se_tfo->release_cmd(se_cmd);
+               return;
+       }
+-      if (se_sess->sess_tearing_down && se_cmd->cmd_wait_set) {
++
++      spin_lock(&se_cmd->t_state_lock);
++      fabric_stop = (se_cmd->transport_state & CMD_T_FABRIC_STOP);
++      spin_unlock(&se_cmd->t_state_lock);
++
++      if (se_cmd->cmd_wait_set || fabric_stop) {
++              list_del_init(&se_cmd->se_cmd_list);
+               spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+               target_free_cmd_mem(se_cmd);
+               complete(&se_cmd->cmd_wait_comp);
+               return;
+       }
+-      list_del(&se_cmd->se_cmd_list);
++      list_del_init(&se_cmd->se_cmd_list);
+       spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+       target_free_cmd_mem(se_cmd);
+@@ -2546,6 +2581,7 @@ void target_sess_cmd_list_set_waiting(st
+ {
+       struct se_cmd *se_cmd;
+       unsigned long flags;
++      int rc;
+       spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
+       if (se_sess->sess_tearing_down) {
+@@ -2555,8 +2591,15 @@ void target_sess_cmd_list_set_waiting(st
+       se_sess->sess_tearing_down = 1;
+       list_splice_init(&se_sess->sess_cmd_list, &se_sess->sess_wait_list);
+-      list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list)
+-              se_cmd->cmd_wait_set = 1;
++      list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list) {
++              rc = kref_get_unless_zero(&se_cmd->cmd_kref);
++              if (rc) {
++                      se_cmd->cmd_wait_set = 1;
++                      spin_lock(&se_cmd->t_state_lock);
++                      se_cmd->transport_state |= CMD_T_FABRIC_STOP;
++                      spin_unlock(&se_cmd->t_state_lock);
++              }
++      }
+       spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+ }
+@@ -2569,15 +2612,25 @@ void target_wait_for_sess_cmds(struct se
+ {
+       struct se_cmd *se_cmd, *tmp_cmd;
+       unsigned long flags;
++      bool tas;
+       list_for_each_entry_safe(se_cmd, tmp_cmd,
+                               &se_sess->sess_wait_list, se_cmd_list) {
+-              list_del(&se_cmd->se_cmd_list);
++              list_del_init(&se_cmd->se_cmd_list);
+               pr_debug("Waiting for se_cmd: %p t_state: %d, fabric state:"
+                       " %d\n", se_cmd, se_cmd->t_state,
+                       se_cmd->se_tfo->get_cmd_state(se_cmd));
++              spin_lock_irqsave(&se_cmd->t_state_lock, flags);
++              tas = (se_cmd->transport_state & CMD_T_TAS);
++              spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
++
++              if (!target_put_sess_cmd(se_cmd)) {
++                      if (tas)
++                              target_put_sess_cmd(se_cmd);
++              }
++
+               wait_for_completion(&se_cmd->cmd_wait_comp);
+               pr_debug("After cmd_wait_comp: se_cmd: %p t_state: %d"
+                       " fabric state: %d\n", se_cmd, se_cmd->t_state,
+@@ -2599,53 +2652,75 @@ void transport_clear_lun_ref(struct se_l
+       wait_for_completion(&lun->lun_ref_comp);
+ }
+-/**
+- * transport_wait_for_tasks - wait for completion to occur
+- * @cmd:      command to wait
+- *
+- * Called from frontend fabric context to wait for storage engine
+- * to pause and/or release frontend generated struct se_cmd.
+- */
+-bool transport_wait_for_tasks(struct se_cmd *cmd)
++static bool
++__transport_wait_for_tasks(struct se_cmd *cmd, bool fabric_stop,
++                         bool *aborted, bool *tas, unsigned long *flags)
++      __releases(&cmd->t_state_lock)
++      __acquires(&cmd->t_state_lock)
+ {
+-      unsigned long flags;
+-      spin_lock_irqsave(&cmd->t_state_lock, flags);
++      assert_spin_locked(&cmd->t_state_lock);
++      WARN_ON_ONCE(!irqs_disabled());
++
++      if (fabric_stop)
++              cmd->transport_state |= CMD_T_FABRIC_STOP;
++
++      if (cmd->transport_state & CMD_T_ABORTED)
++              *aborted = true;
++
++      if (cmd->transport_state & CMD_T_TAS)
++              *tas = true;
++
+       if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD) &&
+-          !(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) {
+-              spin_unlock_irqrestore(&cmd->t_state_lock, flags);
++          !(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB))
+               return false;
+-      }
+       if (!(cmd->se_cmd_flags & SCF_SUPPORTED_SAM_OPCODE) &&
+-          !(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) {
+-              spin_unlock_irqrestore(&cmd->t_state_lock, flags);
++          !(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB))
+               return false;
+-      }
+-      if (!(cmd->transport_state & CMD_T_ACTIVE)) {
+-              spin_unlock_irqrestore(&cmd->t_state_lock, flags);
++      if (!(cmd->transport_state & CMD_T_ACTIVE))
++              return false;
++
++      if (fabric_stop && *aborted)
+               return false;
+-      }
+       cmd->transport_state |= CMD_T_STOP;
+-      pr_debug("wait_for_tasks: Stopping %p ITT: 0x%08llx i_state: %d, t_state: %d, CMD_T_STOP\n",
+-              cmd, cmd->tag, cmd->se_tfo->get_cmd_state(cmd), cmd->t_state);
++      pr_debug("wait_for_tasks: Stopping %p ITT: 0x%08llx i_state: %d,"
++               " t_state: %d, CMD_T_STOP\n", cmd, cmd->tag,
++               cmd->se_tfo->get_cmd_state(cmd), cmd->t_state);
+-      spin_unlock_irqrestore(&cmd->t_state_lock, flags);
++      spin_unlock_irqrestore(&cmd->t_state_lock, *flags);
+       wait_for_completion(&cmd->t_transport_stop_comp);
+-      spin_lock_irqsave(&cmd->t_state_lock, flags);
++      spin_lock_irqsave(&cmd->t_state_lock, *flags);
+       cmd->transport_state &= ~(CMD_T_ACTIVE | CMD_T_STOP);
+-      pr_debug("wait_for_tasks: Stopped wait_for_completion(&cmd->t_transport_stop_comp) for ITT: 0x%08llx\n",
+-              cmd->tag);
++      pr_debug("wait_for_tasks: Stopped wait_for_completion(&cmd->"
++               "t_transport_stop_comp) for ITT: 0x%08llx\n", cmd->tag);
++
++      return true;
++}
++
++/**
++ * transport_wait_for_tasks - wait for completion to occur
++ * @cmd:      command to wait
++ *
++ * Called from frontend fabric context to wait for storage engine
++ * to pause and/or release frontend generated struct se_cmd.
++ */
++bool transport_wait_for_tasks(struct se_cmd *cmd)
++{
++      unsigned long flags;
++      bool ret, aborted = false, tas = false;
++      spin_lock_irqsave(&cmd->t_state_lock, flags);
++      ret = __transport_wait_for_tasks(cmd, false, &aborted, &tas, &flags);
+       spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+-      return true;
++      return ret;
+ }
+ EXPORT_SYMBOL(transport_wait_for_tasks);
+--- a/include/target/target_core_base.h
++++ b/include/target/target_core_base.h
+@@ -491,6 +491,8 @@ struct se_cmd {
+ #define CMD_T_DEV_ACTIVE      (1 << 7)
+ #define CMD_T_REQUEST_STOP    (1 << 8)
+ #define CMD_T_BUSY            (1 << 9)
++#define CMD_T_TAS             (1 << 10)
++#define CMD_T_FABRIC_STOP     (1 << 11)
+       spinlock_t              t_state_lock;
+       struct kref             cmd_kref;
+       struct completion       t_transport_stop_comp;
diff --git a/queue-4.4/target-fix-tas-handling-for-multi-session-se_node_acls.patch b/queue-4.4/target-fix-tas-handling-for-multi-session-se_node_acls.patch
new file mode 100644 (file)
index 0000000..6916093
--- /dev/null
@@ -0,0 +1,106 @@
+From ebde1ca5a908b10312db4ecd7553e3ba039319ab Mon Sep 17 00:00:00 2001
+From: Nicholas Bellinger <nab@linux-iscsi.org>
+Date: Sat, 16 Jan 2016 12:49:49 -0800
+Subject: target: Fix TAS handling for multi-session se_node_acls
+
+From: Nicholas Bellinger <nab@linux-iscsi.org>
+
+commit ebde1ca5a908b10312db4ecd7553e3ba039319ab upstream.
+
+This patch fixes a bug in TMR task aborted status (TAS)
+handling when multiple sessions are connected to the
+same target WWPN endpoint and se_node_acl descriptor,
+resulting in TASK_ABORTED status to not be generated
+for aborted se_cmds on the remote port.
+
+This is due to core_tmr_handle_tas_abort() incorrectly
+comparing se_node_acl instead of se_session, for which
+the multi-session case is expected to be sharing the
+same se_node_acl.
+
+Instead, go ahead and update core_tmr_handle_tas_abort()
+to compare tmr_sess + cmd->se_sess in order to determine
+if the LUN_RESET was received on a different I_T nexus,
+and TASK_ABORTED status response needs to be generated.
+
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Cc: Quinn Tran <quinn.tran@qlogic.com>
+Cc: Himanshu Madhani <himanshu.madhani@qlogic.com>
+Cc: Sagi Grimberg <sagig@mellanox.com>
+Cc: Hannes Reinecke <hare@suse.de>
+Cc: Andy Grover <agrover@redhat.com>
+Cc: Mike Christie <mchristi@redhat.com>
+Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/target/target_core_tmr.c |   16 +++++++++-------
+ 1 file changed, 9 insertions(+), 7 deletions(-)
+
+--- a/drivers/target/target_core_tmr.c
++++ b/drivers/target/target_core_tmr.c
+@@ -76,7 +76,7 @@ void core_tmr_release_req(struct se_tmr_
+ }
+ static void core_tmr_handle_tas_abort(
+-      struct se_node_acl *tmr_nacl,
++      struct se_session *tmr_sess,
+       struct se_cmd *cmd,
+       int tas)
+ {
+@@ -84,7 +84,7 @@ static void core_tmr_handle_tas_abort(
+       /*
+        * TASK ABORTED status (TAS) bit support
+        */
+-      if ((tmr_nacl && (tmr_nacl != cmd->se_sess->se_node_acl)) && tas) {
++      if (tmr_sess && tmr_sess != cmd->se_sess && tas) {
+               remove = false;
+               transport_send_task_abort(cmd);
+       }
+@@ -273,7 +273,7 @@ static void core_tmr_drain_tmr_list(
+ static void core_tmr_drain_state_list(
+       struct se_device *dev,
+       struct se_cmd *prout_cmd,
+-      struct se_node_acl *tmr_nacl,
++      struct se_session *tmr_sess,
+       int tas,
+       struct list_head *preempt_and_abort_list)
+ {
+@@ -364,7 +364,7 @@ static void core_tmr_drain_state_list(
+               cancel_work_sync(&cmd->work);
+               transport_wait_for_tasks(cmd);
+-              core_tmr_handle_tas_abort(tmr_nacl, cmd, tas);
++              core_tmr_handle_tas_abort(tmr_sess, cmd, tas);
+               target_put_sess_cmd(cmd);
+       }
+ }
+@@ -377,6 +377,7 @@ int core_tmr_lun_reset(
+ {
+       struct se_node_acl *tmr_nacl = NULL;
+       struct se_portal_group *tmr_tpg = NULL;
++      struct se_session *tmr_sess = NULL;
+       int tas;
+         /*
+        * TASK_ABORTED status bit, this is configurable via ConfigFS
+@@ -395,8 +396,9 @@ int core_tmr_lun_reset(
+        * or struct se_device passthrough..
+        */
+       if (tmr && tmr->task_cmd && tmr->task_cmd->se_sess) {
+-              tmr_nacl = tmr->task_cmd->se_sess->se_node_acl;
+-              tmr_tpg = tmr->task_cmd->se_sess->se_tpg;
++              tmr_sess = tmr->task_cmd->se_sess;
++              tmr_nacl = tmr_sess->se_node_acl;
++              tmr_tpg = tmr_sess->se_tpg;
+               if (tmr_nacl && tmr_tpg) {
+                       pr_debug("LUN_RESET: TMR caller fabric: %s"
+                               " initiator port %s\n",
+@@ -409,7 +411,7 @@ int core_tmr_lun_reset(
+               dev->transport->name, tas);
+       core_tmr_drain_tmr_list(dev, tmr, preempt_and_abort_list);
+-      core_tmr_drain_state_list(dev, prout_cmd, tmr_nacl, tas,
++      core_tmr_drain_state_list(dev, prout_cmd, tmr_sess, tas,
+                               preempt_and_abort_list);
+       /*
diff --git a/queue-4.4/tick-nohz-set-the-correct-expiry-when-switching-to-nohz-lowres-mode.patch b/queue-4.4/tick-nohz-set-the-correct-expiry-when-switching-to-nohz-lowres-mode.patch
new file mode 100644 (file)
index 0000000..754684d
--- /dev/null
@@ -0,0 +1,42 @@
+From 1ca8ec532fc2d986f1f4a319857bb18e0c9739b4 Mon Sep 17 00:00:00 2001
+From: Wanpeng Li <kernellwp@gmail.com>
+Date: Wed, 27 Jan 2016 19:26:07 +0800
+Subject: tick/nohz: Set the correct expiry when switching to nohz/lowres mode
+
+From: Wanpeng Li <kernellwp@gmail.com>
+
+commit 1ca8ec532fc2d986f1f4a319857bb18e0c9739b4 upstream.
+
+commit 0ff53d096422 sets the next tick interrupt to the last jiffies update,
+i.e. in the past, because the forward operation is invoked before the set
+operation. There is no resulting damage (yet), but we get an extra pointless
+tick interrupt.
+
+Revert the order so we get the next tick interrupt in the future.
+
+Fixes: commit 0ff53d096422 "tick: sched: Force tick interrupt and get rid of softirq magic"
+Signed-off-by: Wanpeng Li <wanpeng.li@hotmail.com>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Frederic Weisbecker <fweisbec@gmail.com>
+Link: http://lkml.kernel.org/r/1453893967-3458-1-git-send-email-wanpeng.li@hotmail.com
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ kernel/time/tick-sched.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/kernel/time/tick-sched.c
++++ b/kernel/time/tick-sched.c
+@@ -977,9 +977,9 @@ static void tick_nohz_switch_to_nohz(voi
+       /* Get the next period */
+       next = tick_init_jiffy_update();
+-      hrtimer_forward_now(&ts->sched_timer, tick_period);
+       hrtimer_set_expires(&ts->sched_timer, next);
+-      tick_program_event(next, 1);
++      hrtimer_forward_now(&ts->sched_timer, tick_period);
++      tick_program_event(hrtimer_get_expires(&ts->sched_timer), 1);
+       tick_nohz_activate(ts, NOHZ_MODE_LOWRES);
+ }
diff --git a/queue-4.4/workqueue-handle-numa_no_node-for-unbound-pool_workqueue-lookup.patch b/queue-4.4/workqueue-handle-numa_no_node-for-unbound-pool_workqueue-lookup.patch
new file mode 100644 (file)
index 0000000..5d513b0
--- /dev/null
@@ -0,0 +1,63 @@
+From d6e022f1d207a161cd88e08ef0371554680ffc46 Mon Sep 17 00:00:00 2001
+From: Tejun Heo <tj@kernel.org>
+Date: Wed, 3 Feb 2016 13:54:25 -0500
+Subject: workqueue: handle NUMA_NO_NODE for unbound pool_workqueue lookup
+
+From: Tejun Heo <tj@kernel.org>
+
+commit d6e022f1d207a161cd88e08ef0371554680ffc46 upstream.
+
+When looking up the pool_workqueue to use for an unbound workqueue,
+workqueue assumes that the target CPU is always bound to a valid NUMA
+node.  However, currently, when a CPU goes offline, the mapping is
+destroyed and cpu_to_node() returns NUMA_NO_NODE.
+
+This has always been broken but hasn't triggered often enough before
+874bbfe600a6 ("workqueue: make sure delayed work run in local cpu").
+After the commit, workqueue forcifully assigns the local CPU for
+delayed work items without explicit target CPU to fix a different
+issue.  This widens the window where CPU can go offline while a
+delayed work item is pending causing delayed work items dispatched
+with target CPU set to an already offlined CPU.  The resulting
+NUMA_NO_NODE mapping makes workqueue try to queue the work item on a
+NULL pool_workqueue and thus crash.
+
+While 874bbfe600a6 has been reverted for a different reason making the
+bug less visible again, it can still happen.  Fix it by mapping
+NUMA_NO_NODE to the default pool_workqueue from unbound_pwq_by_node().
+This is a temporary workaround.  The long term solution is keeping CPU
+-> NODE mapping stable across CPU off/online cycles which is being
+worked on.
+
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Reported-by: Mike Galbraith <umgwanakikbuti@gmail.com>
+Cc: Tang Chen <tangchen@cn.fujitsu.com>
+Cc: Rafael J. Wysocki <rafael@kernel.org>
+Cc: Len Brown <len.brown@intel.com>
+Link: http://lkml.kernel.org/g/1454424264.11183.46.camel@gmail.com
+Link: http://lkml.kernel.org/g/1453702100-2597-1-git-send-email-tangchen@cn.fujitsu.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ kernel/workqueue.c |   10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/kernel/workqueue.c
++++ b/kernel/workqueue.c
+@@ -568,6 +568,16 @@ static struct pool_workqueue *unbound_pw
+                                                 int node)
+ {
+       assert_rcu_or_wq_mutex_or_pool_mutex(wq);
++
++      /*
++       * XXX: @node can be NUMA_NO_NODE if CPU goes offline while a
++       * delayed item is pending.  The plan is to keep CPU -> NODE
++       * mapping valid and stable across CPU on/offlines.  Once that
++       * happens, this workaround can be removed.
++       */
++      if (unlikely(node == NUMA_NO_NODE))
++              return wq->dfl_pwq;
++
+       return rcu_dereference_raw(wq->numa_pwq_tbl[node]);
+ }