--- /dev/null
+From 3f12888dfae2a48741c4caa9214885b3aaf350f9 Mon Sep 17 00:00:00 2001
+From: Wenwen Wang <wang6495@umn.edu>
+Date: Sat, 5 May 2018 13:38:03 -0500
+Subject: ALSA: control: fix a redundant-copy issue
+
+From: Wenwen Wang <wang6495@umn.edu>
+
+commit 3f12888dfae2a48741c4caa9214885b3aaf350f9 upstream.
+
+In snd_ctl_elem_add_compat(), the fields of the struct 'data' need to be
+copied from the corresponding fields of the struct 'data32' in userspace.
+This is achieved by invoking copy_from_user() and get_user() functions. The
+problem here is that the 'type' field is copied twice. One is by
+copy_from_user() and one is by get_user(). Given that the 'type' field is
+not used between the two copies, the second copy is *completely* redundant
+and should be removed for better performance and cleanup. Also, these two
+copies can cause inconsistent data: as the struct 'data32' resides in
+userspace and a malicious userspace process can race to change the 'type'
+field between the two copies to cause inconsistent data. Depending on how
+the data is used in the future, such an inconsistency may cause potential
+security risks.
+
+For above reasons, we should take out the second copy.
+
+Signed-off-by: Wenwen Wang <wang6495@umn.edu>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/core/control_compat.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/sound/core/control_compat.c
++++ b/sound/core/control_compat.c
+@@ -400,8 +400,7 @@ static int snd_ctl_elem_add_compat(struc
+ if (copy_from_user(&data->id, &data32->id, sizeof(data->id)) ||
+ copy_from_user(&data->type, &data32->type, 3 * sizeof(u32)))
+ goto error;
+- if (get_user(data->owner, &data32->owner) ||
+- get_user(data->type, &data32->type))
++ if (get_user(data->owner, &data32->owner))
+ goto error;
+ switch (data->type) {
+ case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
--- /dev/null
+From c8beccc19b92f5172994c0732db689c08f4f98e5 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 8 May 2018 09:27:46 +0200
+Subject: ALSA: hda: Add Lenovo C50 All in one to the power_save blacklist
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+commit c8beccc19b92f5172994c0732db689c08f4f98e5 upstream.
+
+Power-saving is causing loud plops on the Lenovo C50 All in one, add it
+to the blacklist.
+
+BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1572975
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/pci/hda/hda_intel.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/sound/pci/hda/hda_intel.c
++++ b/sound/pci/hda/hda_intel.c
+@@ -2061,6 +2061,8 @@ static struct snd_pci_quirk power_save_b
+ SND_PCI_QUIRK(0x1849, 0x0c0c, "Asrock B85M-ITX", 0),
+ /* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
+ SND_PCI_QUIRK(0x1043, 0x8733, "Asus Prime X370-Pro", 0),
++ /* https://bugzilla.redhat.com/show_bug.cgi?id=1572975 */
++ SND_PCI_QUIRK(0x17aa, 0x36a7, "Lenovo C50 All in one", 0),
+ /* https://bugzilla.kernel.org/show_bug.cgi?id=198611 */
+ SND_PCI_QUIRK(0x17aa, 0x2227, "Lenovo X1 Carbon 3rd Gen", 0),
+ {}
--- /dev/null
+From 21493316a3c4598f308d5a9fa31cc74639c4caff Mon Sep 17 00:00:00 2001
+From: Federico Cuello <fedux@fedux.com.ar>
+Date: Wed, 9 May 2018 00:13:38 +0200
+Subject: ALSA: usb: mixer: volume quirk for CM102-A+/102S+
+
+From: Federico Cuello <fedux@fedux.com.ar>
+
+commit 21493316a3c4598f308d5a9fa31cc74639c4caff upstream.
+
+Currently it's not possible to set volume lower than 26% (it just mutes).
+
+Also fixes this warning:
+
+ Warning! Unlikely big volume range (=9472), cval->res is probably wrong.
+ [13] FU [PCM Playback Volume] ch = 2, val = -9473/-1/1
+
+, and volume works fine for full range.
+
+Signed-off-by: Federico Cuello <fedux@fedux.com.ar>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/usb/mixer.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/sound/usb/mixer.c
++++ b/sound/usb/mixer.c
+@@ -905,6 +905,14 @@ static void volume_control_quirks(struct
+ }
+ break;
+
++ case USB_ID(0x0d8c, 0x0103):
++ if (!strcmp(kctl->id.name, "PCM Playback Volume")) {
++ usb_audio_info(chip,
++ "set volume quirk for CM102-A+/102S+\n");
++ cval->min = -256;
++ }
++ break;
++
+ case USB_ID(0x0471, 0x0101):
+ case USB_ID(0x0471, 0x0104):
+ case USB_ID(0x0471, 0x0105):
--- /dev/null
+From bf308242ab98b5d1648c3663e753556bef9bec01 Mon Sep 17 00:00:00 2001
+From: Andre Przywara <andre.przywara@arm.com>
+Date: Fri, 11 May 2018 15:20:14 +0100
+Subject: KVM: arm/arm64: VGIC/ITS: protect kvm_read_guest() calls with SRCU lock
+
+From: Andre Przywara <andre.przywara@arm.com>
+
+commit bf308242ab98b5d1648c3663e753556bef9bec01 upstream.
+
+kvm_read_guest() will eventually look up in kvm_memslots(), which requires
+either to hold the kvm->slots_lock or to be inside a kvm->srcu critical
+section.
+In contrast to x86 and s390 we don't take the SRCU lock on every guest
+exit, so we have to do it individually for each kvm_read_guest() call.
+
+Provide a wrapper which does that and use that everywhere.
+
+Note that ending the SRCU critical section before returning from the
+kvm_read_guest() wrapper is safe, because the data has been *copied*, so
+we don't need to rely on valid references to the memslot anymore.
+
+Cc: Stable <stable@vger.kernel.org> # 4.8+
+Reported-by: Jan Glauber <jan.glauber@caviumnetworks.com>
+Signed-off-by: Andre Przywara <andre.przywara@arm.com>
+Acked-by: Christoffer Dall <christoffer.dall@arm.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/arm/include/asm/kvm_mmu.h | 16 ++++++++++++++++
+ arch/arm64/include/asm/kvm_mmu.h | 16 ++++++++++++++++
+ virt/kvm/arm/vgic/vgic-its.c | 15 ++++++++-------
+ 3 files changed, 40 insertions(+), 7 deletions(-)
+
+--- a/arch/arm/include/asm/kvm_mmu.h
++++ b/arch/arm/include/asm/kvm_mmu.h
+@@ -223,6 +223,22 @@ static inline unsigned int kvm_get_vmid_
+ return 8;
+ }
+
++/*
++ * We are not in the kvm->srcu critical section most of the time, so we take
++ * the SRCU read lock here. Since we copy the data from the user page, we
++ * can immediately drop the lock again.
++ */
++static inline int kvm_read_guest_lock(struct kvm *kvm,
++ gpa_t gpa, void *data, unsigned long len)
++{
++ int srcu_idx = srcu_read_lock(&kvm->srcu);
++ int ret = kvm_read_guest(kvm, gpa, data, len);
++
++ srcu_read_unlock(&kvm->srcu, srcu_idx);
++
++ return ret;
++}
++
+ static inline void *kvm_get_hyp_vector(void)
+ {
+ return kvm_ksym_ref(__kvm_hyp_vector);
+--- a/arch/arm64/include/asm/kvm_mmu.h
++++ b/arch/arm64/include/asm/kvm_mmu.h
+@@ -313,6 +313,22 @@ static inline unsigned int kvm_get_vmid_
+ return (cpuid_feature_extract_unsigned_field(reg, ID_AA64MMFR1_VMIDBITS_SHIFT) == 2) ? 16 : 8;
+ }
+
++/*
++ * We are not in the kvm->srcu critical section most of the time, so we take
++ * the SRCU read lock here. Since we copy the data from the user page, we
++ * can immediately drop the lock again.
++ */
++static inline int kvm_read_guest_lock(struct kvm *kvm,
++ gpa_t gpa, void *data, unsigned long len)
++{
++ int srcu_idx = srcu_read_lock(&kvm->srcu);
++ int ret = kvm_read_guest(kvm, gpa, data, len);
++
++ srcu_read_unlock(&kvm->srcu, srcu_idx);
++
++ return ret;
++}
++
+ #ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
+ #include <asm/mmu.h>
+
+--- a/virt/kvm/arm/vgic/vgic-its.c
++++ b/virt/kvm/arm/vgic/vgic-its.c
+@@ -208,8 +208,8 @@ static int update_lpi_config(struct kvm
+ u8 prop;
+ int ret;
+
+- ret = kvm_read_guest(kvm, propbase + irq->intid - GIC_LPI_OFFSET,
+- &prop, 1);
++ ret = kvm_read_guest_lock(kvm, propbase + irq->intid - GIC_LPI_OFFSET,
++ &prop, 1);
+
+ if (ret)
+ return ret;
+@@ -339,8 +339,9 @@ static int its_sync_lpi_pending_table(st
+ * this very same byte in the last iteration. Reuse that.
+ */
+ if (byte_offset != last_byte_offset) {
+- ret = kvm_read_guest(vcpu->kvm, pendbase + byte_offset,
+- &pendmask, 1);
++ ret = kvm_read_guest_lock(vcpu->kvm,
++ pendbase + byte_offset,
++ &pendmask, 1);
+ if (ret) {
+ kfree(intids);
+ return ret;
+@@ -628,7 +629,7 @@ static bool vgic_its_check_id(struct vgi
+ return false;
+
+ /* Each 1st level entry is represented by a 64-bit value. */
+- if (kvm_read_guest(its->dev->kvm,
++ if (kvm_read_guest_lock(its->dev->kvm,
+ BASER_ADDRESS(baser) + index * sizeof(indirect_ptr),
+ &indirect_ptr, sizeof(indirect_ptr)))
+ return false;
+@@ -1152,8 +1153,8 @@ static void vgic_its_process_commands(st
+ cbaser = CBASER_ADDRESS(its->cbaser);
+
+ while (its->cwriter != its->creadr) {
+- int ret = kvm_read_guest(kvm, cbaser + its->creadr,
+- cmd_buf, ITS_CMD_SIZE);
++ int ret = kvm_read_guest_lock(kvm, cbaser + its->creadr,
++ cmd_buf, ITS_CMD_SIZE);
+ /*
+ * If kvm_read_guest() fails, this could be due to the guest
+ * programming a bogus value in CBASER or something else going
--- /dev/null
+From 349524bc0da698ec77f2057cf4a4948eb6349265 Mon Sep 17 00:00:00 2001
+From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
+Date: Wed, 10 Jan 2018 17:10:12 +1100
+Subject: powerpc: Don't preempt_disable() in show_cpuinfo()
+
+From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
+
+commit 349524bc0da698ec77f2057cf4a4948eb6349265 upstream.
+
+This causes warnings from cpufreq mutex code. This is also rather
+unnecessary and ineffective. If we really want to prevent concurrent
+unplug, we could take the unplug read lock but I don't see this being
+critical.
+
+Fixes: cd77b5ce208c ("powerpc/powernv/cpufreq: Fix the frequency read by /proc/cpuinfo")
+Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Acked-by: Michal Suchanek <msuchanek@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/powerpc/kernel/setup-common.c | 11 -----------
+ 1 file changed, 11 deletions(-)
+
+--- a/arch/powerpc/kernel/setup-common.c
++++ b/arch/powerpc/kernel/setup-common.c
+@@ -228,14 +228,6 @@ static int show_cpuinfo(struct seq_file
+ unsigned short maj;
+ unsigned short min;
+
+- /* We only show online cpus: disable preempt (overzealous, I
+- * knew) to prevent cpu going down. */
+- preempt_disable();
+- if (!cpu_online(cpu_id)) {
+- preempt_enable();
+- return 0;
+- }
+-
+ #ifdef CONFIG_SMP
+ pvr = per_cpu(cpu_pvr, cpu_id);
+ #else
+@@ -340,9 +332,6 @@ static int show_cpuinfo(struct seq_file
+ #ifdef CONFIG_SMP
+ seq_printf(m, "\n");
+ #endif
+-
+- preempt_enable();
+-
+ /* If this is the last cpu, print the summary */
+ if (cpumask_next(cpu_id, cpu_online_mask) >= nr_cpu_ids)
+ show_cpuinfo_summary(m);
--- /dev/null
+From c7be96af89d4b53211862d8599b2430e8900ed92 Mon Sep 17 00:00:00 2001
+From: Waiman Long <Waiman.Long@hpe.com>
+Date: Wed, 14 Dec 2016 15:04:10 -0800
+Subject: signals: avoid unnecessary taking of sighand->siglock
+
+From: Waiman Long <Waiman.Long@hpe.com>
+
+commit c7be96af89d4b53211862d8599b2430e8900ed92 upstream.
+
+When running certain database workload on a high-end system with many
+CPUs, it was found that spinlock contention in the sigprocmask syscalls
+became a significant portion of the overall CPU cycles as shown below.
+
+ 9.30% 9.30% 905387 dataserver /proc/kcore 0x7fff8163f4d2
+ [k] _raw_spin_lock_irq
+ |
+ ---_raw_spin_lock_irq
+ |
+ |--99.34%-- __set_current_blocked
+ | sigprocmask
+ | sys_rt_sigprocmask
+ | system_call_fastpath
+ | |
+ | |--50.63%-- __swapcontext
+ | | |
+ | | |--99.91%-- upsleepgeneric
+ | |
+ | |--49.36%-- __setcontext
+ | | ktskRun
+
+Looking further into the swapcontext function in glibc, it was found that
+the function always call sigprocmask() without checking if there are
+changes in the signal mask.
+
+A check was added to the __set_current_blocked() function to avoid taking
+the sighand->siglock spinlock if there is no change in the signal mask.
+This will prevent unneeded spinlock contention when many threads are
+trying to call sigprocmask().
+
+With this patch applied, the spinlock contention in sigprocmask() was
+gone.
+
+Link: http://lkml.kernel.org/r/1474979209-11867-1-git-send-email-Waiman.Long@hpe.com
+Signed-off-by: Waiman Long <Waiman.Long@hpe.com>
+Acked-by: Oleg Nesterov <oleg@redhat.com>
+Cc: Ingo Molnar <mingo@kernel.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: Stas Sergeev <stsp@list.ru>
+Cc: Scott J Norton <scott.norton@hpe.com>
+Cc: Douglas Hatch <doug.hatch@hpe.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Mel Gorman <mgorman@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ include/linux/signal.h | 17 +++++++++++++++++
+ kernel/signal.c | 7 +++++++
+ 2 files changed, 24 insertions(+)
+
+--- a/include/linux/signal.h
++++ b/include/linux/signal.h
+@@ -97,6 +97,23 @@ static inline int sigisemptyset(sigset_t
+ }
+ }
+
++static inline int sigequalsets(const sigset_t *set1, const sigset_t *set2)
++{
++ switch (_NSIG_WORDS) {
++ case 4:
++ return (set1->sig[3] == set2->sig[3]) &&
++ (set1->sig[2] == set2->sig[2]) &&
++ (set1->sig[1] == set2->sig[1]) &&
++ (set1->sig[0] == set2->sig[0]);
++ case 2:
++ return (set1->sig[1] == set2->sig[1]) &&
++ (set1->sig[0] == set2->sig[0]);
++ case 1:
++ return set1->sig[0] == set2->sig[0];
++ }
++ return 0;
++}
++
+ #define sigmask(sig) (1UL << ((sig) - 1))
+
+ #ifndef __HAVE_ARCH_SIG_SETOPS
+--- a/kernel/signal.c
++++ b/kernel/signal.c
+@@ -2495,6 +2495,13 @@ void __set_current_blocked(const sigset_
+ {
+ struct task_struct *tsk = current;
+
++ /*
++ * In case the signal mask hasn't changed, there is nothing we need
++ * to do. The current->blocked shouldn't be modified by other task.
++ */
++ if (sigequalsets(&tsk->blocked, newset))
++ return;
++
+ spin_lock_irq(&tsk->sighand->siglock);
+ __set_task_blocked(tsk, newset);
+ spin_unlock_irq(&tsk->sighand->siglock);
--- /dev/null
+From 602805fb618b018b7a41fbb3f93c1992b078b1ae Mon Sep 17 00:00:00 2001
+From: Kamal Dasu <kdasu.kdev@gmail.com>
+Date: Thu, 26 Apr 2018 14:48:01 -0400
+Subject: spi: bcm-qspi: Always read and set BSPI_MAST_N_BOOT_CTRL
+
+From: Kamal Dasu <kdasu.kdev@gmail.com>
+
+commit 602805fb618b018b7a41fbb3f93c1992b078b1ae upstream.
+
+Always confirm the BSPI_MAST_N_BOOT_CTRL bit when enabling
+or disabling BSPI transfers.
+
+Fixes: 4e3b2d236fe00 ("spi: bcm-qspi: Add BSPI spi-nor flash controller driver")
+Signed-off-by: Kamal Dasu <kdasu.kdev@gmail.com>
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/spi/spi-bcm-qspi.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/spi/spi-bcm-qspi.c
++++ b/drivers/spi/spi-bcm-qspi.c
+@@ -514,7 +514,7 @@ static int bcm_qspi_bspi_set_mode(struct
+
+ static void bcm_qspi_enable_bspi(struct bcm_qspi *qspi)
+ {
+- if (!has_bspi(qspi) || (qspi->bspi_enabled))
++ if (!has_bspi(qspi))
+ return;
+
+ qspi->bspi_enabled = 1;
+@@ -529,7 +529,7 @@ static void bcm_qspi_enable_bspi(struct
+
+ static void bcm_qspi_disable_bspi(struct bcm_qspi *qspi)
+ {
+- if (!has_bspi(qspi) || (!qspi->bspi_enabled))
++ if (!has_bspi(qspi))
+ return;
+
+ qspi->bspi_enabled = 0;
--- /dev/null
+From 5eb9a07a4ae1008b67d8bcd47bddb3dae97456b7 Mon Sep 17 00:00:00 2001
+From: Kamal Dasu <kdasu.kdev@gmail.com>
+Date: Thu, 26 Apr 2018 14:48:00 -0400
+Subject: spi: bcm-qspi: Avoid setting MSPI_CDRAM_PCS for spi-nor master
+
+From: Kamal Dasu <kdasu.kdev@gmail.com>
+
+commit 5eb9a07a4ae1008b67d8bcd47bddb3dae97456b7 upstream.
+
+Added fix for probing of spi-nor device non-zero chip selects. Set
+MSPI_CDRAM_PCS (peripheral chip select) with spi master for MSPI
+controller and not for MSPI/BSPI spi-nor master controller. Ensure
+setting of cs bit in chip select register on chip select change.
+
+Fixes: fa236a7ef24048 ("spi: bcm-qspi: Add Broadcom MSPI driver")
+Signed-off-by: Kamal Dasu <kdasu.kdev@gmail.com>
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/spi/spi-bcm-qspi.c | 24 ++++++++++++++++--------
+ 1 file changed, 16 insertions(+), 8 deletions(-)
+
+--- a/drivers/spi/spi-bcm-qspi.c
++++ b/drivers/spi/spi-bcm-qspi.c
+@@ -543,16 +543,19 @@ static void bcm_qspi_disable_bspi(struct
+
+ static void bcm_qspi_chip_select(struct bcm_qspi *qspi, int cs)
+ {
+- u32 data = 0;
++ u32 rd = 0;
++ u32 wr = 0;
+
+- if (qspi->curr_cs == cs)
+- return;
+ if (qspi->base[CHIP_SELECT]) {
+- data = bcm_qspi_read(qspi, CHIP_SELECT, 0);
+- data = (data & ~0xff) | (1 << cs);
+- bcm_qspi_write(qspi, CHIP_SELECT, 0, data);
++ rd = bcm_qspi_read(qspi, CHIP_SELECT, 0);
++ wr = (rd & ~0xff) | (1 << cs);
++ if (rd == wr)
++ return;
++ bcm_qspi_write(qspi, CHIP_SELECT, 0, wr);
+ usleep_range(10, 20);
+ }
++
++ dev_dbg(&qspi->pdev->dev, "using cs:%d\n", cs);
+ qspi->curr_cs = cs;
+ }
+
+@@ -770,8 +773,13 @@ static int write_to_hw(struct bcm_qspi *
+ dev_dbg(&qspi->pdev->dev, "WR %04x\n", val);
+ }
+ mspi_cdram = MSPI_CDRAM_CONT_BIT;
+- mspi_cdram |= (~(1 << spi->chip_select) &
+- MSPI_CDRAM_PCS);
++
++ if (has_bspi(qspi))
++ mspi_cdram &= ~1;
++ else
++ mspi_cdram |= (~(1 << spi->chip_select) &
++ MSPI_CDRAM_PCS);
++
+ mspi_cdram |= ((tp.trans->bits_per_word <= 8) ? 0 :
+ MSPI_CDRAM_BITSE_BIT);
+
--- /dev/null
+From efc4a13724b852ddaa3358402a8dec024ffbcb17 Mon Sep 17 00:00:00 2001
+From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Date: Thu, 19 Apr 2018 19:53:32 +0300
+Subject: spi: pxa2xx: Allow 64-bit DMA
+
+From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+
+commit efc4a13724b852ddaa3358402a8dec024ffbcb17 upstream.
+
+Currently the 32-bit device address only is supported for DMA. However,
+starting from Intel Sunrisepoint PCH the DMA address of the device FIFO
+can be 64-bit.
+
+Change the respective variable to be compatible with DMA engine
+expectations, i.e. to phys_addr_t.
+
+Fixes: 34cadd9c1bcb ("spi: pxa2xx: Add support for Intel Sunrisepoint")
+Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/spi/spi-pxa2xx.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/spi/spi-pxa2xx.h
++++ b/drivers/spi/spi-pxa2xx.h
+@@ -38,7 +38,7 @@ struct driver_data {
+
+ /* SSP register addresses */
+ void __iomem *ioaddr;
+- u32 ssdr_physical;
++ phys_addr_t ssdr_physical;
+
+ /* SSP masks*/
+ u32 dma_cr1;
--- /dev/null
+From 45dd9b0666a162f8e4be76096716670cf1741f0e Mon Sep 17 00:00:00 2001
+From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>
+Date: Wed, 9 May 2018 14:36:09 -0400
+Subject: tracing/x86/xen: Remove zero data size trace events trace_xen_mmu_flush_tlb{_all}
+
+From: Steven Rostedt (VMware) <rostedt@goodmis.org>
+
+commit 45dd9b0666a162f8e4be76096716670cf1741f0e upstream.
+
+Doing an audit of trace events, I discovered two trace events in the xen
+subsystem that use a hack to create zero data size trace events. This is not
+what trace events are for. Trace events add memory footprint overhead, and
+if all you need to do is see if a function is hit or not, simply make that
+function noinline and use function tracer filtering.
+
+Worse yet, the hack used was:
+
+ __array(char, x, 0)
+
+Which creates a static string of zero in length. There's assumptions about
+such constructs in ftrace that this is a dynamic string that is nul
+terminated. This is not the case with these tracepoints and can cause
+problems in various parts of ftrace.
+
+Nuke the trace events!
+
+Link: http://lkml.kernel.org/r/20180509144605.5a220327@gandalf.local.home
+
+Cc: stable@vger.kernel.org
+Fixes: 95a7d76897c1e ("xen/mmu: Use Xen specific TLB flush instead of the generic one.")
+Reviewed-by: Juergen Gross <jgross@suse.com>
+Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/xen/mmu.c | 4 ----
+ include/trace/events/xen.h | 16 ----------------
+ 2 files changed, 20 deletions(-)
+
+--- a/arch/x86/xen/mmu.c
++++ b/arch/x86/xen/mmu.c
+@@ -1317,8 +1317,6 @@ void xen_flush_tlb_all(void)
+ struct mmuext_op *op;
+ struct multicall_space mcs;
+
+- trace_xen_mmu_flush_tlb_all(0);
+-
+ preempt_disable();
+
+ mcs = xen_mc_entry(sizeof(*op));
+@@ -1336,8 +1334,6 @@ static void xen_flush_tlb(void)
+ struct mmuext_op *op;
+ struct multicall_space mcs;
+
+- trace_xen_mmu_flush_tlb(0);
+-
+ preempt_disable();
+
+ mcs = xen_mc_entry(sizeof(*op));
+--- a/include/trace/events/xen.h
++++ b/include/trace/events/xen.h
+@@ -377,22 +377,6 @@ DECLARE_EVENT_CLASS(xen_mmu_pgd,
+ DEFINE_XEN_MMU_PGD_EVENT(xen_mmu_pgd_pin);
+ DEFINE_XEN_MMU_PGD_EVENT(xen_mmu_pgd_unpin);
+
+-TRACE_EVENT(xen_mmu_flush_tlb_all,
+- TP_PROTO(int x),
+- TP_ARGS(x),
+- TP_STRUCT__entry(__array(char, x, 0)),
+- TP_fast_assign((void)x),
+- TP_printk("%s", "")
+- );
+-
+-TRACE_EVENT(xen_mmu_flush_tlb,
+- TP_PROTO(int x),
+- TP_ARGS(x),
+- TP_STRUCT__entry(__array(char, x, 0)),
+- TP_fast_assign((void)x),
+- TP_printk("%s", "")
+- );
+-
+ TRACE_EVENT(xen_mmu_flush_tlb_single,
+ TP_PROTO(unsigned long addr),
+ TP_ARGS(addr),
--- /dev/null
+From 1e180f167d4e413afccbbb4a421b48b2de832549 Mon Sep 17 00:00:00 2001
+From: "Shuah Khan (Samsung OSG)" <shuah@kernel.org>
+Date: Mon, 30 Apr 2018 16:17:19 -0600
+Subject: usbip: usbip_host: delete device from busid_table after rebind
+
+From: Shuah Khan (Samsung OSG) <shuah@kernel.org>
+
+commit 1e180f167d4e413afccbbb4a421b48b2de832549 upstream.
+
+Device is left in the busid_table after unbind and rebind. Rebind
+initiates usb bus scan and the original driver claims the device.
+After rescan the device should be deleted from the busid_table as
+it no longer belongs to usbip_host.
+
+Fix it to delete the device after device_attach() succeeds.
+
+Signed-off-by: Shuah Khan (Samsung OSG) <shuah@kernel.org>
+Cc: stable <stable@vger.kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/usbip/stub_main.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/usb/usbip/stub_main.c
++++ b/drivers/usb/usbip/stub_main.c
+@@ -201,6 +201,9 @@ static ssize_t rebind_store(struct devic
+ if (!bid)
+ return -ENODEV;
+
++ /* mark the device for deletion so probe ignores it during rescan */
++ bid->status = STUB_BUSID_OTHER;
++
+ /* device_attach() callers should hold parent lock for USB */
+ if (bid->udev->dev.parent)
+ device_lock(bid->udev->dev.parent);
+@@ -212,6 +215,9 @@ static ssize_t rebind_store(struct devic
+ return ret;
+ }
+
++ /* delete device from busid_table */
++ del_match_busid((char *) buf);
++
+ return count;
+ }
+
--- /dev/null
+From c171654caa875919be3c533d3518da8be5be966e Mon Sep 17 00:00:00 2001
+From: "Shuah Khan (Samsung OSG)" <shuah@kernel.org>
+Date: Tue, 15 May 2018 17:57:23 -0600
+Subject: usbip: usbip_host: fix bad unlock balance during stub_probe()
+
+From: Shuah Khan (Samsung OSG) <shuah@kernel.org>
+
+commit c171654caa875919be3c533d3518da8be5be966e upstream.
+
+stub_probe() calls put_busid_priv() in an error path when device isn't
+found in the busid_table. Fix it by making put_busid_priv() safe to be
+called with null struct bus_id_priv pointer.
+
+This problem happens when "usbip bind" is run without loading usbip_host
+driver and then running modprobe. The first failed bind attempt unbinds
+the device from the original driver and when usbip_host is modprobed,
+stub_probe() runs and doesn't find the device in its busid table and calls
+put_busid_priv(0 with null bus_id_priv pointer.
+
+usbip-host 3-10.2: 3-10.2 is not in match_busid table... skip!
+
+[ 367.359679] =====================================
+[ 367.359681] WARNING: bad unlock balance detected!
+[ 367.359683] 4.17.0-rc4+ #5 Not tainted
+[ 367.359685] -------------------------------------
+[ 367.359688] modprobe/2768 is trying to release lock (
+[ 367.359689]
+==================================================================
+[ 367.359696] BUG: KASAN: null-ptr-deref in print_unlock_imbalance_bug+0x99/0x110
+[ 367.359699] Read of size 8 at addr 0000000000000058 by task modprobe/2768
+
+[ 367.359705] CPU: 4 PID: 2768 Comm: modprobe Not tainted 4.17.0-rc4+ #5
+
+Fixes: 22076557b07c ("usbip: usbip_host: fix NULL-ptr deref and use-after-free errors") in usb-linus
+Signed-off-by: Shuah Khan (Samsung OSG) <shuah@kernel.org>
+Cc: stable <stable@vger.kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/usbip/stub_main.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/usbip/stub_main.c
++++ b/drivers/usb/usbip/stub_main.c
+@@ -96,7 +96,8 @@ struct bus_id_priv *get_busid_priv(const
+
+ void put_busid_priv(struct bus_id_priv *bid)
+ {
+- spin_unlock(&bid->busid_lock);
++ if (bid)
++ spin_unlock(&bid->busid_lock);
+ }
+
+ static int add_match_busid(char *busid)
--- /dev/null
+From 22076557b07c12086eeb16b8ce2b0b735f7a27e7 Mon Sep 17 00:00:00 2001
+From: "Shuah Khan (Samsung OSG)" <shuah@kernel.org>
+Date: Mon, 14 May 2018 20:49:58 -0600
+Subject: usbip: usbip_host: fix NULL-ptr deref and use-after-free errors
+
+From: Shuah Khan (Samsung OSG) <shuah@kernel.org>
+
+commit 22076557b07c12086eeb16b8ce2b0b735f7a27e7 upstream.
+
+usbip_host updates device status without holding lock from stub probe,
+disconnect and rebind code paths. When multiple requests to import a
+device are received, these unprotected code paths step all over each
+other and drive fails with NULL-ptr deref and use-after-free errors.
+
+The driver uses a table lock to protect the busid array for adding and
+deleting busids to the table. However, the probe, disconnect and rebind
+paths get the busid table entry and update the status without holding
+the busid table lock. Add a new finer grain lock to protect the busid
+entry. This new lock will be held to search and update the busid entry
+fields from get_busid_idx(), add_match_busid() and del_match_busid().
+
+match_busid_show() does the same to access the busid entry fields.
+
+get_busid_priv() changed to return the pointer to the busid entry holding
+the busid lock. stub_probe(), stub_disconnect() and stub_device_rebind()
+call put_busid_priv() to release the busid lock before returning. This
+changes fixes the unprotected code paths eliminating the race conditions
+in updating the busid entries.
+
+Reported-by: Jakub Jirasek
+Signed-off-by: Shuah Khan (Samsung OSG) <shuah@kernel.org>
+Cc: stable <stable@vger.kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/usbip/stub.h | 2 ++
+ drivers/usb/usbip/stub_dev.c | 33 +++++++++++++++++++++++----------
+ drivers/usb/usbip/stub_main.c | 40 +++++++++++++++++++++++++++++++++++-----
+ 3 files changed, 60 insertions(+), 15 deletions(-)
+
+--- a/drivers/usb/usbip/stub.h
++++ b/drivers/usb/usbip/stub.h
+@@ -87,6 +87,7 @@ struct bus_id_priv {
+ struct stub_device *sdev;
+ struct usb_device *udev;
+ char shutdown_busid;
++ spinlock_t busid_lock;
+ };
+
+ /* stub_priv is allocated from stub_priv_cache */
+@@ -97,6 +98,7 @@ extern struct usb_device_driver stub_dri
+
+ /* stub_main.c */
+ struct bus_id_priv *get_busid_priv(const char *busid);
++void put_busid_priv(struct bus_id_priv *bid);
+ int del_match_busid(char *busid);
+ void stub_device_cleanup_urbs(struct stub_device *sdev);
+
+--- a/drivers/usb/usbip/stub_dev.c
++++ b/drivers/usb/usbip/stub_dev.c
+@@ -314,7 +314,7 @@ static int stub_probe(struct usb_device
+ struct stub_device *sdev = NULL;
+ const char *udev_busid = dev_name(&udev->dev);
+ struct bus_id_priv *busid_priv;
+- int rc;
++ int rc = 0;
+
+ dev_dbg(&udev->dev, "Enter probe\n");
+
+@@ -331,13 +331,15 @@ static int stub_probe(struct usb_device
+ * other matched drivers by the driver core.
+ * See driver_probe_device() in driver/base/dd.c
+ */
+- return -ENODEV;
++ rc = -ENODEV;
++ goto call_put_busid_priv;
+ }
+
+ if (udev->descriptor.bDeviceClass == USB_CLASS_HUB) {
+ dev_dbg(&udev->dev, "%s is a usb hub device... skip!\n",
+ udev_busid);
+- return -ENODEV;
++ rc = -ENODEV;
++ goto call_put_busid_priv;
+ }
+
+ if (!strcmp(udev->bus->bus_name, "vhci_hcd")) {
+@@ -345,13 +347,16 @@ static int stub_probe(struct usb_device
+ "%s is attached on vhci_hcd... skip!\n",
+ udev_busid);
+
+- return -ENODEV;
++ rc = -ENODEV;
++ goto call_put_busid_priv;
+ }
+
+ /* ok, this is my device */
+ sdev = stub_device_alloc(udev);
+- if (!sdev)
+- return -ENOMEM;
++ if (!sdev) {
++ rc = -ENOMEM;
++ goto call_put_busid_priv;
++ }
+
+ dev_info(&udev->dev,
+ "usbip-host: register new device (bus %u dev %u)\n",
+@@ -383,7 +388,9 @@ static int stub_probe(struct usb_device
+ }
+ busid_priv->status = STUB_BUSID_ALLOC;
+
+- return 0;
++ rc = 0;
++ goto call_put_busid_priv;
++
+ err_files:
+ usb_hub_release_port(udev->parent, udev->portnum,
+ (struct usb_dev_state *) udev);
+@@ -393,6 +400,9 @@ err_port:
+
+ busid_priv->sdev = NULL;
+ stub_device_free(sdev);
++
++call_put_busid_priv:
++ put_busid_priv(busid_priv);
+ return rc;
+ }
+
+@@ -431,7 +441,7 @@ static void stub_disconnect(struct usb_d
+ /* get stub_device */
+ if (!sdev) {
+ dev_err(&udev->dev, "could not get device");
+- return;
++ goto call_put_busid_priv;
+ }
+
+ dev_set_drvdata(&udev->dev, NULL);
+@@ -446,12 +456,12 @@ static void stub_disconnect(struct usb_d
+ (struct usb_dev_state *) udev);
+ if (rc) {
+ dev_dbg(&udev->dev, "unable to release port\n");
+- return;
++ goto call_put_busid_priv;
+ }
+
+ /* If usb reset is called from event handler */
+ if (usbip_in_eh(current))
+- return;
++ goto call_put_busid_priv;
+
+ /* shutdown the current connection */
+ shutdown_busid(busid_priv);
+@@ -464,6 +474,9 @@ static void stub_disconnect(struct usb_d
+
+ if (busid_priv->status == STUB_BUSID_ALLOC)
+ busid_priv->status = STUB_BUSID_ADDED;
++
++call_put_busid_priv:
++ put_busid_priv(busid_priv);
+ }
+
+ #ifdef CONFIG_PM
+--- a/drivers/usb/usbip/stub_main.c
++++ b/drivers/usb/usbip/stub_main.c
+@@ -40,6 +40,8 @@ static spinlock_t busid_table_lock;
+
+ static void init_busid_table(void)
+ {
++ int i;
++
+ /*
+ * This also sets the bus_table[i].status to
+ * STUB_BUSID_OTHER, which is 0.
+@@ -47,6 +49,9 @@ static void init_busid_table(void)
+ memset(busid_table, 0, sizeof(busid_table));
+
+ spin_lock_init(&busid_table_lock);
++
++ for (i = 0; i < MAX_BUSID; i++)
++ spin_lock_init(&busid_table[i].busid_lock);
+ }
+
+ /*
+@@ -58,15 +63,20 @@ static int get_busid_idx(const char *bus
+ int i;
+ int idx = -1;
+
+- for (i = 0; i < MAX_BUSID; i++)
++ for (i = 0; i < MAX_BUSID; i++) {
++ spin_lock(&busid_table[i].busid_lock);
+ if (busid_table[i].name[0])
+ if (!strncmp(busid_table[i].name, busid, BUSID_SIZE)) {
+ idx = i;
++ spin_unlock(&busid_table[i].busid_lock);
+ break;
+ }
++ spin_unlock(&busid_table[i].busid_lock);
++ }
+ return idx;
+ }
+
++/* Returns holding busid_lock. Should call put_busid_priv() to unlock */
+ struct bus_id_priv *get_busid_priv(const char *busid)
+ {
+ int idx;
+@@ -74,13 +84,21 @@ struct bus_id_priv *get_busid_priv(const
+
+ spin_lock(&busid_table_lock);
+ idx = get_busid_idx(busid);
+- if (idx >= 0)
++ if (idx >= 0) {
+ bid = &(busid_table[idx]);
++ /* get busid_lock before returning */
++ spin_lock(&bid->busid_lock);
++ }
+ spin_unlock(&busid_table_lock);
+
+ return bid;
+ }
+
++void put_busid_priv(struct bus_id_priv *bid)
++{
++ spin_unlock(&bid->busid_lock);
++}
++
+ static int add_match_busid(char *busid)
+ {
+ int i;
+@@ -93,15 +111,19 @@ static int add_match_busid(char *busid)
+ goto out;
+ }
+
+- for (i = 0; i < MAX_BUSID; i++)
++ for (i = 0; i < MAX_BUSID; i++) {
++ spin_lock(&busid_table[i].busid_lock);
+ if (!busid_table[i].name[0]) {
+ strlcpy(busid_table[i].name, busid, BUSID_SIZE);
+ if ((busid_table[i].status != STUB_BUSID_ALLOC) &&
+ (busid_table[i].status != STUB_BUSID_REMOV))
+ busid_table[i].status = STUB_BUSID_ADDED;
+ ret = 0;
++ spin_unlock(&busid_table[i].busid_lock);
+ break;
+ }
++ spin_unlock(&busid_table[i].busid_lock);
++ }
+
+ out:
+ spin_unlock(&busid_table_lock);
+@@ -122,6 +144,8 @@ int del_match_busid(char *busid)
+ /* found */
+ ret = 0;
+
++ spin_lock(&busid_table[idx].busid_lock);
++
+ if (busid_table[idx].status == STUB_BUSID_OTHER)
+ memset(busid_table[idx].name, 0, BUSID_SIZE);
+
+@@ -129,6 +153,7 @@ int del_match_busid(char *busid)
+ (busid_table[idx].status != STUB_BUSID_ADDED))
+ busid_table[idx].status = STUB_BUSID_REMOV;
+
++ spin_unlock(&busid_table[idx].busid_lock);
+ out:
+ spin_unlock(&busid_table_lock);
+
+@@ -141,9 +166,12 @@ static ssize_t show_match_busid(struct d
+ char *out = buf;
+
+ spin_lock(&busid_table_lock);
+- for (i = 0; i < MAX_BUSID; i++)
++ for (i = 0; i < MAX_BUSID; i++) {
++ spin_lock(&busid_table[i].busid_lock);
+ if (busid_table[i].name[0])
+ out += sprintf(out, "%s ", busid_table[i].name);
++ spin_unlock(&busid_table[i].busid_lock);
++ }
+ spin_unlock(&busid_table_lock);
+ out += sprintf(out, "\n");
+
+@@ -219,7 +247,7 @@ static void stub_device_rebind(void)
+ }
+ spin_unlock(&busid_table_lock);
+
+- /* now run rebind */
++ /* now run rebind - no need to hold locks. driver files are removed */
+ for (i = 0; i < MAX_BUSID; i++) {
+ if (busid_table[i].name[0] &&
+ busid_table[i].shutdown_busid) {
+@@ -249,6 +277,8 @@ static ssize_t rebind_store(struct devic
+
+ /* mark the device for deletion so probe ignores it during rescan */
+ bid->status = STUB_BUSID_OTHER;
++ /* release the busid lock */
++ put_busid_priv(bid);
+
+ ret = do_rebind((char *) buf, bid);
+ if (ret < 0)
--- /dev/null
+From 28b68acc4a88dcf91fd1dcf2577371dc9bf574cc Mon Sep 17 00:00:00 2001
+From: Shuah Khan <shuahkh@osg.samsung.com>
+Date: Wed, 11 Apr 2018 18:13:30 -0600
+Subject: usbip: usbip_host: refine probe and disconnect debug msgs to be useful
+
+From: Shuah Khan <shuahkh@osg.samsung.com>
+
+commit 28b68acc4a88dcf91fd1dcf2577371dc9bf574cc upstream.
+
+Refine probe and disconnect debug msgs to be useful and say what is
+in progress.
+
+Signed-off-by: Shuah Khan <shuahkh@osg.samsung.com>
+Cc: stable <stable@vger.kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/usbip/stub_dev.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/usbip/stub_dev.c
++++ b/drivers/usb/usbip/stub_dev.c
+@@ -316,7 +316,7 @@ static int stub_probe(struct usb_device
+ struct bus_id_priv *busid_priv;
+ int rc;
+
+- dev_dbg(&udev->dev, "Enter\n");
++ dev_dbg(&udev->dev, "Enter probe\n");
+
+ /* check we should claim or not by busid_table */
+ busid_priv = get_busid_priv(udev_busid);
+@@ -418,7 +418,7 @@ static void stub_disconnect(struct usb_d
+ struct bus_id_priv *busid_priv;
+ int rc;
+
+- dev_dbg(&udev->dev, "Enter\n");
++ dev_dbg(&udev->dev, "Enter disconnect\n");
+
+ busid_priv = get_busid_priv(udev_busid);
+ if (!busid_priv) {
--- /dev/null
+From 7510df3f29d44685bab7b1918b61a8ccd57126a9 Mon Sep 17 00:00:00 2001
+From: "Shuah Khan (Samsung OSG)" <shuah@kernel.org>
+Date: Mon, 30 Apr 2018 16:17:20 -0600
+Subject: usbip: usbip_host: run rebind from exit when module is removed
+
+From: Shuah Khan (Samsung OSG) <shuah@kernel.org>
+
+commit 7510df3f29d44685bab7b1918b61a8ccd57126a9 upstream.
+
+After removing usbip_host module, devices it releases are left without
+a driver. For example, when a keyboard or a mass storage device are
+bound to usbip_host when it is removed, these devices are no longer
+bound to any driver.
+
+Fix it to run device_attach() from the module exit routine to restore
+the devices to their original drivers. This includes cleanup changes
+and moving device_attach() code to a common routine to be called from
+rebind_store() and usbip_host_exit().
+
+Signed-off-by: Shuah Khan (Samsung OSG) <shuah@kernel.org>
+Cc: stable <stable@vger.kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/usbip/stub_dev.c | 6 ----
+ drivers/usb/usbip/stub_main.c | 60 +++++++++++++++++++++++++++++++++++-------
+ 2 files changed, 52 insertions(+), 14 deletions(-)
+
+--- a/drivers/usb/usbip/stub_dev.c
++++ b/drivers/usb/usbip/stub_dev.c
+@@ -462,12 +462,8 @@ static void stub_disconnect(struct usb_d
+ busid_priv->sdev = NULL;
+ stub_device_free(sdev);
+
+- if (busid_priv->status == STUB_BUSID_ALLOC) {
++ if (busid_priv->status == STUB_BUSID_ALLOC)
+ busid_priv->status = STUB_BUSID_ADDED;
+- } else {
+- busid_priv->status = STUB_BUSID_OTHER;
+- del_match_busid((char *)udev_busid);
+- }
+ }
+
+ #ifdef CONFIG_PM
+--- a/drivers/usb/usbip/stub_main.c
++++ b/drivers/usb/usbip/stub_main.c
+@@ -28,6 +28,7 @@
+ #define DRIVER_DESC "USB/IP Host Driver"
+
+ struct kmem_cache *stub_priv_cache;
++
+ /*
+ * busid_tables defines matching busids that usbip can grab. A user can change
+ * dynamically what device is locally used and what device is exported to a
+@@ -184,6 +185,51 @@ static ssize_t store_match_busid(struct
+ static DRIVER_ATTR(match_busid, S_IRUSR | S_IWUSR, show_match_busid,
+ store_match_busid);
+
++static int do_rebind(char *busid, struct bus_id_priv *busid_priv)
++{
++ int ret;
++
++ /* device_attach() callers should hold parent lock for USB */
++ if (busid_priv->udev->dev.parent)
++ device_lock(busid_priv->udev->dev.parent);
++ ret = device_attach(&busid_priv->udev->dev);
++ if (busid_priv->udev->dev.parent)
++ device_unlock(busid_priv->udev->dev.parent);
++ if (ret < 0) {
++ dev_err(&busid_priv->udev->dev, "rebind failed\n");
++ return ret;
++ }
++ return 0;
++}
++
++static void stub_device_rebind(void)
++{
++#if IS_MODULE(CONFIG_USBIP_HOST)
++ struct bus_id_priv *busid_priv;
++ int i;
++
++ /* update status to STUB_BUSID_OTHER so probe ignores the device */
++ spin_lock(&busid_table_lock);
++ for (i = 0; i < MAX_BUSID; i++) {
++ if (busid_table[i].name[0] &&
++ busid_table[i].shutdown_busid) {
++ busid_priv = &(busid_table[i]);
++ busid_priv->status = STUB_BUSID_OTHER;
++ }
++ }
++ spin_unlock(&busid_table_lock);
++
++ /* now run rebind */
++ for (i = 0; i < MAX_BUSID; i++) {
++ if (busid_table[i].name[0] &&
++ busid_table[i].shutdown_busid) {
++ busid_priv = &(busid_table[i]);
++ do_rebind(busid_table[i].name, busid_priv);
++ }
++ }
++#endif
++}
++
+ static ssize_t rebind_store(struct device_driver *dev, const char *buf,
+ size_t count)
+ {
+@@ -204,16 +250,9 @@ static ssize_t rebind_store(struct devic
+ /* mark the device for deletion so probe ignores it during rescan */
+ bid->status = STUB_BUSID_OTHER;
+
+- /* device_attach() callers should hold parent lock for USB */
+- if (bid->udev->dev.parent)
+- device_lock(bid->udev->dev.parent);
+- ret = device_attach(&bid->udev->dev);
+- if (bid->udev->dev.parent)
+- device_unlock(bid->udev->dev.parent);
+- if (ret < 0) {
+- dev_err(&bid->udev->dev, "rebind failed\n");
++ ret = do_rebind((char *) buf, bid);
++ if (ret < 0)
+ return ret;
+- }
+
+ /* delete device from busid_table */
+ del_match_busid((char *) buf);
+@@ -339,6 +378,9 @@ static void __exit usbip_host_exit(void)
+ */
+ usb_deregister_device_driver(&stub_driver);
+
++ /* initiate scan to attach devices */
++ stub_device_rebind();
++
+ kmem_cache_destroy(stub_priv_cache);
+ }
+