From: Greg Kroah-Hartman Date: Tue, 1 Mar 2016 22:00:38 +0000 (-0800) Subject: 4.4-stable patches X-Git-Tag: v3.10.99~12 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=049c6daa133aaeb5ac6b8b072624c53d34710fe2;p=thirdparty%2Fkernel%2Fstable-queue.git 4.4-stable patches 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 --- 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 index 00000000000..956fb9571ae --- /dev/null +++ b/queue-4.4/alsa-hda-apply-clock-gate-workaround-to-skylake-too.patch @@ -0,0 +1,92 @@ +From 7e31a0159461818a1bda49662921b98a29c1187b Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Mon, 22 Feb 2016 15:18:13 +0100 +Subject: ALSA: hda - Apply clock gate workaround to Skylake, too + +From: Takashi Iwai + +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 +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..dae2ef012e4 --- /dev/null +++ b/queue-4.4/alsa-hda-fixing-background-noise-on-dell-inspiron-3162.patch @@ -0,0 +1,63 @@ +From 3b43b71f05d3ecd01c4116254666d9492301697d Mon Sep 17 00:00:00 2001 +From: Kai-Heng Feng +Date: Thu, 25 Feb 2016 15:19:38 +0800 +Subject: ALSA: hda - Fixing background noise on Dell Inspiron 3162 + +From: Kai-Heng Feng + +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 +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..093c0c3938f --- /dev/null +++ b/queue-4.4/arcv2-smp-emulate-ipi-to-self-using-software-triggered-interrupt.patch @@ -0,0 +1,132 @@ +From bb143f814ea488769ca2e79e0b376139cb5f134b Mon Sep 17 00:00:00 2001 +From: Vineet Gupta +Date: Tue, 23 Feb 2016 11:55:16 +0530 +Subject: ARCv2: SMP: Emulate IPI to self using software triggered interrupt + +From: Vineet Gupta + +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 +Signed-off-by: Vineet Gupta +Signed-off-by: Greg Kroah-Hartman + +--- + 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 + #include + #include ++#include + #include + #include + ++#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 index 00000000000..522a310b362 --- /dev/null +++ b/queue-4.4/arcv2-star-9000950267-handle-return-from-intr-to-delay-slot-2.patch @@ -0,0 +1,102 @@ +From cbfe74a753e877b49dc54e9b04d5d42230ca0aed Mon Sep 17 00:00:00 2001 +From: Vineet Gupta +Date: Fri, 8 Jan 2016 12:29:10 +0530 +Subject: ARCv2: STAR 9000950267: Handle return from intr to Delay Slot #2 + +From: Vineet Gupta + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..54620c39294 --- /dev/null +++ b/queue-4.4/cdc-acm-exclude-samsung-phone-04e8-685d.patch @@ -0,0 +1,33 @@ +From e912e685f372ab62a2405a1acd923597f524e94a Mon Sep 17 00:00:00 2001 +From: Oliver Neukum +Date: Mon, 18 Jan 2016 15:45:18 +0100 +Subject: cdc-acm:exclude Samsung phone 04e8:685d + +From: Oliver Neukum + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..523a9c31165 --- /dev/null +++ b/queue-4.4/libata-fix-sff-host-state-machine-locking-while-polling.patch @@ -0,0 +1,183 @@ +From 8eee1d3ed5b6fc8e14389567c9a6f53f82bb7224 Mon Sep 17 00:00:00 2001 +From: Tejun Heo +Date: Mon, 1 Feb 2016 11:33:21 -0500 +Subject: libata: fix sff host state machine locking while polling + +From: Tejun Heo + +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:[] [] ata_sff_hsm_move+0x619/0x1c60 + ... + Call Trace: + + [] __ata_sff_port_intr+0x1e1/0x3a0 drivers/ata/libata-sff.c:1584 + [] ata_bmdma_port_intr+0x71/0x400 drivers/ata/libata-sff.c:2877 + [< inline >] __ata_sff_interrupt drivers/ata/libata-sff.c:1629 + [] ata_bmdma_interrupt+0x253/0x580 drivers/ata/libata-sff.c:2902 + [] handle_irq_event_percpu+0x108/0x7e0 kernel/irq/handle.c:157 + [] handle_irq_event+0xa7/0x140 kernel/irq/handle.c:205 + [] handle_edge_irq+0x1e3/0x8d0 kernel/irq/chip.c:623 + [< inline >] generic_handle_irq_desc include/linux/irqdesc.h:146 + [] handle_irq+0x10c/0x2a0 arch/x86/kernel/irq_64.c:78 + [] do_IRQ+0x7d/0x1a0 arch/x86/kernel/irq.c:240 + [] common_interrupt+0x8c/0x8c arch/x86/entry/entry_64.S:520 + + [< inline >] rcu_lock_acquire include/linux/rcupdate.h:490 + [< inline >] rcu_read_lock include/linux/rcupdate.h:874 + [] 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 + [] handle_mm_fault+0x2516/0x49a0 mm/memory.c:3447 + [] __do_page_fault+0x376/0x960 arch/x86/mm/fault.c:1238 + [] trace_do_page_fault+0xe8/0x420 arch/x86/mm/fault.c:1331 + [] do_async_page_fault+0x14/0xd0 arch/x86/kernel/kvm.c:264 + [] 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 +Reported-and-tested-by: Dmitry Vyukov +Link: http://lkml.kernel.org/g/CACT4Y+b_JsOxJu2EZyEf+mOXORc_zid5V1-pLZSroJVxyWdSpw@mail.gmail.com +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..205118281b0 --- /dev/null +++ b/queue-4.4/mac80211-requeue-work-after-scan-complete-for-all-vif-types.patch @@ -0,0 +1,115 @@ +From 4fa11ec726a32ea6dd768dbb2e2af3453a98ec0a Mon Sep 17 00:00:00 2001 +From: Sachin Kulkarni +Date: Tue, 12 Jan 2016 14:30:19 +0530 +Subject: mac80211: Requeue work after scan complete for all VIF types. + +From: Sachin Kulkarni + +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 +Signed-off-by: Johannes Berg +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..833c74cee83 --- /dev/null +++ b/queue-4.4/perf-stat-do-not-clean-event-s-private-stats.patch @@ -0,0 +1,47 @@ +From 3f416f22d1e21709a631189ba169f76fd267b374 Mon Sep 17 00:00:00 2001 +From: Jiri Olsa +Date: Wed, 20 Jan 2016 12:56:34 +0100 +Subject: perf stat: Do not clean event's private stats + +From: Jiri Olsa + +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 +Signed-off-by: Jiri Olsa +Cc: David Ahern +Cc: Namhyung Kim +Cc: Peter Zijlstra +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..1b19e88380c --- /dev/null +++ b/queue-4.4/qla2xxx-fix-stale-pointer-access.patch @@ -0,0 +1,190 @@ +From cb43285ff7039fe3c4b0bc476e6d6569c31104f3 Mon Sep 17 00:00:00 2001 +From: Quinn Tran +Date: Thu, 4 Feb 2016 11:45:16 -0500 +Subject: qla2xxx: Fix stale pointer access. + +From: Quinn Tran + +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:[] [] qla2x00_init_rings+0xdc/0x320 [qla2xxx] +RSP: 0018:ffff880429447dd8 EFLAGS: 00010082 +.... +Call Trace: +[] qla2x00_abort_isp+0x170/0x6b0 [qla2xxx] +[] qla2x00_do_dpc+0x357/0x7f0 [qla2xxx] +[] ? qla2x00_relogin+0x260/0x260 [qla2xxx] +[] kthread+0xc9/0xe0 +[] ? flush_kthread_worker+0x90/0x90 +[] ret_from_fork+0x3f/0x70 +[] ? flush_kthread_worker+0x90/0x90 +---- 8< ---- + +Signed-off-by: Quinn Tran +Signed-off-by: Himanshu Madhani +Signed-off-by: Nicholas Bellinger +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..712c32abd3c --- /dev/null +++ b/queue-4.4/revert-workqueue-make-sure-delayed-work-run-in-local-cpu.patch @@ -0,0 +1,75 @@ +From 041bd12e272c53a35c54c13875839bcb98c999ce Mon Sep 17 00:00:00 2001 +From: Tejun Heo +Date: Tue, 9 Feb 2016 16:11:26 -0500 +Subject: Revert "workqueue: make sure delayed work run in local cpu" + +From: Tejun Heo + +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 +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 +Cc: Henrique de Moraes Holschuh +Cc: Daniel Bilik +Cc: Jan Kara +Cc: Shaohua Li +Cc: Sasha Levin +Cc: Ben Hutchings +Cc: Thomas Gleixner +Cc: Daniel Bilik +Cc: Jiri Slaby +Cc: Michal Hocko +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..d70c3ef7a3f --- /dev/null +++ b/queue-4.4/rfkill-fix-rfkill_fop_read-wait_event-usage.patch @@ -0,0 +1,63 @@ +From 6736fde9672ff6717ac576e9bba2fd5f3dfec822 Mon Sep 17 00:00:00 2001 +From: Johannes Berg +Date: Tue, 26 Jan 2016 11:29:03 +0100 +Subject: rfkill: fix rfkill_fop_read wait_event usage + +From: Johannes Berg + +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 +Signed-off-by: Johannes Berg +Signed-off-by: Greg Kroah-Hartman + +--- + 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) diff --git a/queue-4.4/series b/queue-4.4/series index e270955b326..a55467c7ed3 100644 --- a/queue-4.4/series +++ b/queue-4.4/series @@ -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 index 00000000000..4ee5274eced --- /dev/null +++ b/queue-4.4/spi-atmel-fix-gpio-chip-select-in-case-of-non-dt-platform.patch @@ -0,0 +1,36 @@ +From 70f340df24518d36eeaefb6652d492f250115c19 Mon Sep 17 00:00:00 2001 +From: Cyrille Pitchen +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 + +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 +Signed-off-by: Cyrille Pitchen +[nicolas.ferre@atmel.com: extract from ml discussion] +Signed-off-by: Nicolas Ferre +Tested-by: Mans Rullgard +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..aee206e5809 --- /dev/null +++ b/queue-4.4/target-fix-lun_reset-active-i-o-handling-for-ack_kref.patch @@ -0,0 +1,377 @@ +From febe562c20dfa8f33bee7d419c6b517986a5aa33 Mon Sep 17 00:00:00 2001 +From: Nicholas Bellinger +Date: Mon, 11 Jan 2016 21:31:09 -0800 +Subject: target: Fix LUN_RESET active I/O handling for ACK_KREF + +From: Nicholas Bellinger + +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 +Cc: Himanshu Madhani +Cc: Sagi Grimberg +Cc: Christoph Hellwig +Cc: Hannes Reinecke +Cc: Andy Grover +Cc: Mike Christie +Signed-off-by: Nicholas Bellinger +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..daba7bf9b77 --- /dev/null +++ b/queue-4.4/target-fix-lun_reset-active-tmr-descriptor-handling.patch @@ -0,0 +1,149 @@ +From a6d9bb1c9605cd4f44e2d8290dc4d0e88f20292d Mon Sep 17 00:00:00 2001 +From: Nicholas Bellinger +Date: Mon, 11 Jan 2016 21:53:05 -0800 +Subject: target: Fix LUN_RESET active TMR descriptor handling + +From: Nicholas Bellinger + +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 +Cc: Himanshu Madhani +Cc: Sagi Grimberg +Cc: Christoph Hellwig +Cc: Hannes Reinecke +Cc: Andy Grover +Cc: Mike Christie +Signed-off-by: Nicholas Bellinger +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..607c0bcb4af --- /dev/null +++ b/queue-4.4/target-fix-race-with-scf_send_delayed_tas-handling.patch @@ -0,0 +1,141 @@ +From 310d3d314be7f0a84011ebdc4bdccbcae9755a87 Mon Sep 17 00:00:00 2001 +From: Nicholas Bellinger +Date: Fri, 5 Feb 2016 14:51:36 -0800 +Subject: target: Fix race with SCF_SEND_DELAYED_TAS handling + +From: Nicholas Bellinger + +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 +Cc: Himanshu Madhani +Cc: Sagi Grimberg +Cc: Christoph Hellwig +Cc: Hannes Reinecke +Cc: Andy Grover +Cc: Mike Christie +Signed-off-by: Nicholas Bellinger +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..1556f46986a --- /dev/null +++ b/queue-4.4/target-fix-remote-port-tmr-abort-se_cmd-fabric-stop.patch @@ -0,0 +1,441 @@ +From 0f4a943168f31d29a1701908931acaba518b131a Mon Sep 17 00:00:00 2001 +From: Nicholas Bellinger +Date: Tue, 19 Jan 2016 15:23:02 -0800 +Subject: target: Fix remote-port TMR ABORT + se_cmd fabric stop + +From: Nicholas Bellinger + +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 +Cc: Himanshu Madhani +Cc: Sagi Grimberg +Cc: Christoph Hellwig +Cc: Hannes Reinecke +Cc: Andy Grover +Cc: Mike Christie +Signed-off-by: Nicholas Bellinger +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..691609304b7 --- /dev/null +++ b/queue-4.4/target-fix-tas-handling-for-multi-session-se_node_acls.patch @@ -0,0 +1,106 @@ +From ebde1ca5a908b10312db4ecd7553e3ba039319ab Mon Sep 17 00:00:00 2001 +From: Nicholas Bellinger +Date: Sat, 16 Jan 2016 12:49:49 -0800 +Subject: target: Fix TAS handling for multi-session se_node_acls + +From: Nicholas Bellinger + +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 +Cc: Quinn Tran +Cc: Himanshu Madhani +Cc: Sagi Grimberg +Cc: Hannes Reinecke +Cc: Andy Grover +Cc: Mike Christie +Signed-off-by: Nicholas Bellinger +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..754684dd477 --- /dev/null +++ b/queue-4.4/tick-nohz-set-the-correct-expiry-when-switching-to-nohz-lowres-mode.patch @@ -0,0 +1,42 @@ +From 1ca8ec532fc2d986f1f4a319857bb18e0c9739b4 Mon Sep 17 00:00:00 2001 +From: Wanpeng Li +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 + +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 +Cc: Peter Zijlstra +Cc: Frederic Weisbecker +Link: http://lkml.kernel.org/r/1453893967-3458-1-git-send-email-wanpeng.li@hotmail.com +Signed-off-by: Thomas Gleixner +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..5d513b03158 --- /dev/null +++ b/queue-4.4/workqueue-handle-numa_no_node-for-unbound-pool_workqueue-lookup.patch @@ -0,0 +1,63 @@ +From d6e022f1d207a161cd88e08ef0371554680ffc46 Mon Sep 17 00:00:00 2001 +From: Tejun Heo +Date: Wed, 3 Feb 2016 13:54:25 -0500 +Subject: workqueue: handle NUMA_NO_NODE for unbound pool_workqueue lookup + +From: Tejun Heo + +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 +Reported-by: Mike Galbraith +Cc: Tang Chen +Cc: Rafael J. Wysocki +Cc: Len Brown +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 + +--- + 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]); + } +