ecryptfs-unlock-page-in-write_begin-error-path.patch
ecryptfs-ecryptfs_keyring_auth_tok_for_sig-bug-fix.patch
crypto-aesni-intel-fixed-problem-with-packets-that-are-not-multiple-of-64bytes.patch
+staging-usbip-bugfixes-related-to-kthread-conversion.patch
+staging-usbip-bugfix-add-number-of-packets-for-isochronous-frames.patch
+staging-usbip-bugfix-for-isochronous-packets-and-optimization.patch
+staging-hv-use-sync_bitops-when-interacting-with-the-hypervisor.patch
+staging-hv-fix-garp-not-sent-after-quick-migration.patch
--- /dev/null
+From c996edcf1c451b81740abbcca5257ed7e353fcc6 Mon Sep 17 00:00:00 2001
+From: Haiyang Zhang <haiyangz@microsoft.com>
+Date: Wed, 6 Apr 2011 15:18:00 -0700
+Subject: staging: hv: Fix GARP not sent after Quick Migration
+
+From: Haiyang Zhang <haiyangz@microsoft.com>
+
+commit c996edcf1c451b81740abbcca5257ed7e353fcc6 upstream.
+
+After Quick Migration, the network is not immediately operational in the
+current context when receiving RNDIS_STATUS_MEDIA_CONNECT event. So, I added
+another netif_notify_peers() into a scheduled work, otherwise GARP packet will
+not be sent after quick migration, and cause network disconnection.
+
+Thanks to Mike Surcouf <mike@surcouf.co.uk> for reporting the bug and
+testing the patch.
+
+Reported-by: Mike Surcouf <mike@surcouf.co.uk>
+Tested-by: Mike Surcouf <mike@surcouf.co.uk>
+Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
+Signed-off-by: Hank Janssen <hjanssen@microsoft.com>
+Signed-off-by: Abhishek Kane <v-abkane@microsoft.com>
+Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/staging/hv/netvsc_drv.c | 24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+--- a/drivers/staging/hv/netvsc_drv.c
++++ b/drivers/staging/hv/netvsc_drv.c
+@@ -46,6 +46,7 @@ struct net_device_context {
+ /* point back to our device context */
+ struct vm_device *device_ctx;
+ unsigned long avail;
++ struct work_struct work;
+ };
+
+ struct netvsc_driver_context {
+@@ -225,6 +226,7 @@ static void netvsc_linkstatus_callback(s
+ unsigned int status)
+ {
+ struct vm_device *device_ctx = to_vm_device(device_obj);
++ struct net_device_context *ndev_ctx;
+ struct net_device *net = dev_get_drvdata(&device_ctx->device);
+
+ if (!net) {
+@@ -237,6 +239,8 @@ static void netvsc_linkstatus_callback(s
+ netif_carrier_on(net);
+ netif_wake_queue(net);
+ netif_notify_peers(net);
++ ndev_ctx = netdev_priv(net);
++ schedule_work(&ndev_ctx->work);
+ } else {
+ netif_carrier_off(net);
+ netif_stop_queue(net);
+@@ -336,6 +340,25 @@ static const struct net_device_ops devic
+ .ndo_set_mac_address = eth_mac_addr,
+ };
+
++/*
++ * Send GARP packet to network peers after migrations.
++ * After Quick Migration, the network is not immediately operational in the
++ * current context when receiving RNDIS_STATUS_MEDIA_CONNECT event. So, add
++ * another netif_notify_peers() into a scheduled work, otherwise GARP packet
++ * will not be sent after quick migration, and cause network disconnection.
++ */
++static void netvsc_send_garp(struct work_struct *w)
++{
++ struct net_device_context *ndev_ctx;
++ struct net_device *net;
++
++ msleep(20);
++ ndev_ctx = container_of(w, struct net_device_context, work);
++ net = dev_get_drvdata(&ndev_ctx->device_ctx->device);
++ netif_notify_peers(net);
++}
++
++
+ static int netvsc_probe(struct device *device)
+ {
+ struct driver_context *driver_ctx =
+@@ -364,6 +387,7 @@ static int netvsc_probe(struct device *d
+ net_device_ctx->device_ctx = device_ctx;
+ net_device_ctx->avail = ring_size;
+ dev_set_drvdata(device, net);
++ INIT_WORK(&net_device_ctx->work, netvsc_send_garp);
+
+ /* Notify the netvsc driver of the new device */
+ ret = net_drv_obj->base.OnDeviceAdd(device_obj, &device_info);
--- /dev/null
+From 22356585712d1ff08fbfed152edd8b386873b238 Mon Sep 17 00:00:00 2001
+From: Olaf Hering <olaf@aepfle.de>
+Date: Mon, 21 Mar 2011 14:41:37 +0100
+Subject: staging: hv: use sync_bitops when interacting with the hypervisor
+
+From: Olaf Hering <olaf@aepfle.de>
+
+commit 22356585712d1ff08fbfed152edd8b386873b238 upstream.
+
+Locking is required when tweaking bits located in a shared page, use the
+sync_ version of bitops. Without this change vmbus_on_event() will miss
+events and as a result, vmbus_isr() will not schedule the receive tasklet.
+
+Signed-off-by: Olaf Hering <olaf@aepfle.de>
+Acked-by: Haiyang Zhang <haiyangz@microsoft.com>
+Acked-by: Hank Janssen <hjanssen@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/staging/hv/channel.c | 8 ++++----
+ drivers/staging/hv/connection.c | 4 ++--
+ drivers/staging/hv/vmbus_drv.c | 2 +-
+ drivers/staging/hv/vmbus_private.h | 1 +
+ 4 files changed, 8 insertions(+), 7 deletions(-)
+
+--- a/drivers/staging/hv/channel.c
++++ b/drivers/staging/hv/channel.c
+@@ -76,14 +76,14 @@ static void vmbus_setevent(struct vmbus_
+
+ if (channel->offermsg.monitor_allocated) {
+ /* Each u32 represents 32 channels */
+- set_bit(channel->offermsg.child_relid & 31,
++ sync_set_bit(channel->offermsg.child_relid & 31,
+ (unsigned long *) gVmbusConnection.SendInterruptPage +
+ (channel->offermsg.child_relid >> 5));
+
+ monitorpage = gVmbusConnection.MonitorPages;
+ monitorpage++; /* Get the child to parent monitor page */
+
+- set_bit(channel->monitor_bit,
++ sync_set_bit(channel->monitor_bit,
+ (unsigned long *)&monitorpage->trigger_group
+ [channel->monitor_grp].pending);
+
+@@ -99,7 +99,7 @@ static void VmbusChannelClearEvent(struc
+
+ if (Channel->offermsg.monitor_allocated) {
+ /* Each u32 represents 32 channels */
+- clear_bit(Channel->offermsg.child_relid & 31,
++ sync_clear_bit(Channel->offermsg.child_relid & 31,
+ (unsigned long *)gVmbusConnection.SendInterruptPage +
+ (Channel->offermsg.child_relid >> 5));
+
+@@ -107,7 +107,7 @@ static void VmbusChannelClearEvent(struc
+ (struct hv_monitor_page *)gVmbusConnection.MonitorPages;
+ monitorPage++; /* Get the child to parent monitor page */
+
+- clear_bit(Channel->monitor_bit,
++ sync_clear_bit(Channel->monitor_bit,
+ (unsigned long *)&monitorPage->trigger_group
+ [Channel->monitor_grp].Pending);
+ }
+--- a/drivers/staging/hv/connection.c
++++ b/drivers/staging/hv/connection.c
+@@ -281,7 +281,7 @@ void VmbusOnEvents(void)
+ for (dword = 0; dword < maxdword; dword++) {
+ if (recvInterruptPage[dword]) {
+ for (bit = 0; bit < 32; bit++) {
+- if (test_and_clear_bit(bit, (unsigned long *)&recvInterruptPage[dword])) {
++ if (sync_test_and_clear_bit(bit, (unsigned long *)&recvInterruptPage[dword])) {
+ relid = (dword << 5) + bit;
+ DPRINT_DBG(VMBUS, "event detected for relid - %d", relid);
+
+@@ -320,7 +320,7 @@ int VmbusPostMessage(void *buffer, size_
+ int VmbusSetEvent(u32 childRelId)
+ {
+ /* Each u32 represents 32 channels */
+- set_bit(childRelId & 31,
++ sync_set_bit(childRelId & 31,
+ (unsigned long *)gVmbusConnection.SendInterruptPage +
+ (childRelId >> 5));
+
+--- a/drivers/staging/hv/vmbus_drv.c
++++ b/drivers/staging/hv/vmbus_drv.c
+@@ -291,7 +291,7 @@ static int vmbus_on_isr(struct hv_driver
+ event = (union hv_synic_event_flags *)page_addr + VMBUS_MESSAGE_SINT;
+
+ /* Since we are a child, we only need to check bit 0 */
+- if (test_and_clear_bit(0, (unsigned long *) &event->flags32[0])) {
++ if (sync_test_and_clear_bit(0, (unsigned long *) &event->flags32[0])) {
+ DPRINT_DBG(VMBUS, "received event %d", event->flags32[0]);
+ ret |= 0x2;
+ }
+--- a/drivers/staging/hv/vmbus_private.h
++++ b/drivers/staging/hv/vmbus_private.h
+@@ -31,6 +31,7 @@
+ #include "channel_mgmt.h"
+ #include "ring_buffer.h"
+ #include <linux/list.h>
++#include <asm/sync_bitops.h>
+
+
+ /*
--- /dev/null
+From 1325f85fa49f57df034869de430f7c302ae23109 Mon Sep 17 00:00:00 2001
+From: Arjan Mels <arjan.mels@gmx.net>
+Date: Tue, 5 Apr 2011 20:26:38 +0200
+Subject: staging: usbip: bugfix add number of packets for isochronous frames
+
+From: Arjan Mels <arjan.mels@gmx.net>
+
+commit 1325f85fa49f57df034869de430f7c302ae23109 upstream.
+
+The number_of_packets was not transmitted for RET_SUBMIT packets. The
+linux client used the stored number_of_packet from the submitted
+request. The windows userland client does not do this however and needs
+to know the number_of_packets to determine the size of the transmission.
+
+Signed-off-by: Arjan Mels <arjan.mels@gmx.net>
+Cc: Takahiro Hirofuchi <hirofuchi@users.sourceforge.net>
+Cc: Max Vozeler <max@vozeler.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/staging/usbip/usbip_common.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/drivers/staging/usbip/usbip_common.c
++++ b/drivers/staging/usbip/usbip_common.c
+@@ -334,10 +334,11 @@ void usbip_dump_header(struct usbip_head
+ usbip_udbg("CMD_UNLINK: seq %u\n", pdu->u.cmd_unlink.seqnum);
+ break;
+ case USBIP_RET_SUBMIT:
+- usbip_udbg("RET_SUBMIT: st %d al %u sf %d ec %d\n",
++ usbip_udbg("RET_SUBMIT: st %d al %u sf %d #p %d ec %d\n",
+ pdu->u.ret_submit.status,
+ pdu->u.ret_submit.actual_length,
+ pdu->u.ret_submit.start_frame,
++ pdu->u.ret_submit.number_of_packets,
+ pdu->u.ret_submit.error_count);
+ case USBIP_RET_UNLINK:
+ usbip_udbg("RET_UNLINK: status %d\n", pdu->u.ret_unlink.status);
+@@ -625,6 +626,7 @@ static void usbip_pack_ret_submit(struct
+ rpdu->status = urb->status;
+ rpdu->actual_length = urb->actual_length;
+ rpdu->start_frame = urb->start_frame;
++ rpdu->number_of_packets = urb->number_of_packets;
+ rpdu->error_count = urb->error_count;
+ } else {
+ /* vhci_rx.c */
+@@ -632,6 +634,7 @@ static void usbip_pack_ret_submit(struct
+ urb->status = rpdu->status;
+ urb->actual_length = rpdu->actual_length;
+ urb->start_frame = rpdu->start_frame;
++ urb->number_of_packets = rpdu->number_of_packets;
+ urb->error_count = rpdu->error_count;
+ }
+ }
+@@ -700,11 +703,13 @@ static void correct_endian_ret_submit(st
+ cpu_to_be32s(&pdu->status);
+ cpu_to_be32s(&pdu->actual_length);
+ cpu_to_be32s(&pdu->start_frame);
++ cpu_to_be32s(&pdu->number_of_packets);
+ cpu_to_be32s(&pdu->error_count);
+ } else {
+ be32_to_cpus(&pdu->status);
+ be32_to_cpus(&pdu->actual_length);
+ be32_to_cpus(&pdu->start_frame);
++ cpu_to_be32s(&pdu->number_of_packets);
+ be32_to_cpus(&pdu->error_count);
+ }
+ }
--- /dev/null
+From 28276a28d8b3cd19f4449991faad4945fe557656 Mon Sep 17 00:00:00 2001
+From: Arjan Mels <arjan.mels@gmx.net>
+Date: Tue, 5 Apr 2011 20:26:59 +0200
+Subject: staging: usbip: bugfix for isochronous packets and optimization
+
+From: Arjan Mels <arjan.mels@gmx.net>
+
+commit 28276a28d8b3cd19f4449991faad4945fe557656 upstream.
+
+For isochronous packets the actual_length is the sum of the actual
+length of each of the packets, however between the packets might be
+padding, so it is not sufficient to just send the first actual_length
+bytes of the buffer. To fix this and simultanesouly optimize the
+bandwidth the content of the isochronous packets are send without the
+padding, the padding is restored on the receiving end.
+
+Signed-off-by: Arjan Mels <arjan.mels@gmx.net>
+Cc: Takahiro Hirofuchi <hirofuchi@users.sourceforge.net>
+Cc: Max Vozeler <max@vozeler.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/staging/usbip/stub_tx.c | 74 ++++++++++++++++++++++++++++-------
+ drivers/staging/usbip/usbip_common.c | 57 ++++++++++++++++++++++++++
+ drivers/staging/usbip/usbip_common.h | 2
+ drivers/staging/usbip/vhci_rx.c | 3 +
+ 4 files changed, 122 insertions(+), 14 deletions(-)
+
+--- a/drivers/staging/usbip/stub_tx.c
++++ b/drivers/staging/usbip/stub_tx.c
+@@ -169,7 +169,6 @@ static int stub_send_ret_submit(struct s
+ struct stub_priv *priv, *tmp;
+
+ struct msghdr msg;
+- struct kvec iov[3];
+ size_t txsize;
+
+ size_t total_size = 0;
+@@ -179,28 +178,73 @@ static int stub_send_ret_submit(struct s
+ struct urb *urb = priv->urb;
+ struct usbip_header pdu_header;
+ void *iso_buffer = NULL;
++ struct kvec *iov = NULL;
++ int iovnum = 0;
+
+ txsize = 0;
+ memset(&pdu_header, 0, sizeof(pdu_header));
+ memset(&msg, 0, sizeof(msg));
+- memset(&iov, 0, sizeof(iov));
+
+- usbip_dbg_stub_tx("setup txdata urb %p\n", urb);
++ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
++ iovnum = 2 + urb->number_of_packets;
++ else
++ iovnum = 2;
+
++ iov = kzalloc(iovnum * sizeof(struct kvec), GFP_KERNEL);
++
++ if (!iov) {
++ usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_MALLOC);
++ return -1;
++ }
++
++ iovnum = 0;
+
+ /* 1. setup usbip_header */
+ setup_ret_submit_pdu(&pdu_header, urb);
++ usbip_dbg_stub_tx("setup txdata seqnum: %d urb: %p\n",
++ pdu_header.base.seqnum, urb);
++ /*usbip_dump_header(pdu_header);*/
+ usbip_header_correct_endian(&pdu_header, 1);
+
+- iov[0].iov_base = &pdu_header;
+- iov[0].iov_len = sizeof(pdu_header);
++ iov[iovnum].iov_base = &pdu_header;
++ iov[iovnum].iov_len = sizeof(pdu_header);
++ iovnum++;
+ txsize += sizeof(pdu_header);
+
+ /* 2. setup transfer buffer */
+- if (usb_pipein(urb->pipe) && urb->actual_length > 0) {
+- iov[1].iov_base = urb->transfer_buffer;
+- iov[1].iov_len = urb->actual_length;
++ if (usb_pipein(urb->pipe) &&
++ usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS &&
++ urb->actual_length > 0) {
++ iov[iovnum].iov_base = urb->transfer_buffer;
++ iov[iovnum].iov_len = urb->actual_length;
++ iovnum++;
+ txsize += urb->actual_length;
++ } else if (usb_pipein(urb->pipe) &&
++ usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
++ /*
++ * For isochronous packets: actual length is the sum of
++ * the actual length of the individual, packets, but as
++ * the packet offsets are not changed there will be
++ * padding between the packets. To optimally use the
++ * bandwidth the padding is not transmitted.
++ */
++
++ int i;
++ for (i = 0; i < urb->number_of_packets; i++) {
++ iov[iovnum].iov_base = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
++ iov[iovnum].iov_len = urb->iso_frame_desc[i].actual_length;
++ iovnum++;
++ txsize += urb->iso_frame_desc[i].actual_length;
++ }
++
++ if (txsize != sizeof(pdu_header) + urb->actual_length) {
++ dev_err(&sdev->interface->dev,
++ "actual length of urb (%d) does not match iso packet sizes (%d)\n",
++ urb->actual_length, txsize-sizeof(pdu_header));
++ kfree(iov);
++ usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_TCP);
++ return -1;
++ }
+ }
+
+ /* 3. setup iso_packet_descriptor */
+@@ -211,32 +255,34 @@ static int stub_send_ret_submit(struct s
+ if (!iso_buffer) {
+ usbip_event_add(&sdev->ud,
+ SDEV_EVENT_ERROR_MALLOC);
++ kfree(iov);
+ return -1;
+ }
+
+- iov[2].iov_base = iso_buffer;
+- iov[2].iov_len = len;
++ iov[iovnum].iov_base = iso_buffer;
++ iov[iovnum].iov_len = len;
+ txsize += len;
++ iovnum++;
+ }
+
+- ret = kernel_sendmsg(sdev->ud.tcp_socket, &msg, iov,
+- 3, txsize);
++ ret = kernel_sendmsg(sdev->ud.tcp_socket, &msg,
++ iov, iovnum, txsize);
+ if (ret != txsize) {
+ dev_err(&sdev->interface->dev,
+ "sendmsg failed!, retval %d for %zd\n",
+ ret, txsize);
++ kfree(iov);
+ kfree(iso_buffer);
+ usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_TCP);
+ return -1;
+ }
+
++ kfree(iov);
+ kfree(iso_buffer);
+- usbip_dbg_stub_tx("send txdata\n");
+
+ total_size += txsize;
+ }
+
+-
+ spin_lock_irqsave(&sdev->priv_lock, flags);
+
+ list_for_each_entry_safe(priv, tmp, &sdev->priv_free, list) {
+--- a/drivers/staging/usbip/usbip_common.c
++++ b/drivers/staging/usbip/usbip_common.c
+@@ -835,6 +835,7 @@ int usbip_recv_iso(struct usbip_device *
+ int size = np * sizeof(*iso);
+ int i;
+ int ret;
++ int total_length = 0;
+
+ if (!usb_pipeisoc(urb->pipe))
+ return 0;
+@@ -864,19 +865,75 @@ int usbip_recv_iso(struct usbip_device *
+ return -EPIPE;
+ }
+
++
+ for (i = 0; i < np; i++) {
+ iso = buff + (i * sizeof(*iso));
+
+ usbip_iso_pakcet_correct_endian(iso, 0);
+ usbip_pack_iso(iso, &urb->iso_frame_desc[i], 0);
++ total_length += urb->iso_frame_desc[i].actual_length;
+ }
+
+ kfree(buff);
+
++ if (total_length != urb->actual_length) {
++ dev_err(&urb->dev->dev,
++ "total length of iso packets (%d) not equal to actual length of buffer (%d)\n",
++ total_length, urb->actual_length);
++
++ if (ud->side == USBIP_STUB)
++ usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
++ else
++ usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
++
++ return -EPIPE;
++ }
++
+ return ret;
+ }
+ EXPORT_SYMBOL_GPL(usbip_recv_iso);
+
++/*
++ * This functions restores the padding which was removed for optimizing
++ * the bandwidth during transfer over tcp/ip
++ *
++ * buffer and iso packets need to be stored and be in propeper endian in urb
++ * before calling this function
++ */
++int usbip_pad_iso(struct usbip_device *ud, struct urb *urb)
++{
++ int np = urb->number_of_packets;
++ int i;
++ int ret;
++ int actualoffset = urb->actual_length;
++
++ if (!usb_pipeisoc(urb->pipe))
++ return 0;
++
++ /* if no packets or length of data is 0, then nothing to unpack */
++ if (np == 0 || urb->actual_length == 0)
++ return 0;
++
++ /*
++ * if actual_length is transfer_buffer_length then no padding is
++ * present.
++ */
++ if (urb->actual_length == urb->transfer_buffer_length)
++ return 0;
++
++ /*
++ * loop over all packets from last to first (to prevent overwritting
++ * memory when padding) and move them into the proper place
++ */
++ for (i = np-1; i > 0; i--) {
++ actualoffset -= urb->iso_frame_desc[i].actual_length;
++ memmove(urb->transfer_buffer + urb->iso_frame_desc[i].offset,
++ urb->transfer_buffer + actualoffset,
++ urb->iso_frame_desc[i].actual_length);
++ }
++ return ret;
++}
++EXPORT_SYMBOL_GPL(usbip_pad_iso);
+
+ /* some members of urb must be substituted before. */
+ int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb)
+--- a/drivers/staging/usbip/usbip_common.h
++++ b/drivers/staging/usbip/usbip_common.h
+@@ -393,6 +393,8 @@ void usbip_header_correct_endian(struct
+ int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb);
+ /* some members of urb must be substituted before. */
+ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb);
++/* some members of urb must be substituted before. */
++int usbip_pad_iso(struct usbip_device *ud, struct urb *urb);
+ void *usbip_alloc_iso_desc_pdu(struct urb *urb, ssize_t *bufflen);
+
+
+--- a/drivers/staging/usbip/vhci_rx.c
++++ b/drivers/staging/usbip/vhci_rx.c
+@@ -99,6 +99,9 @@ static void vhci_recv_ret_submit(struct
+ if (usbip_recv_iso(ud, urb) < 0)
+ return;
+
++ /* restore the padding in iso packets */
++ if (usbip_pad_iso(ud, urb) < 0)
++ return;
+
+ if (usbip_dbg_flag_vhci_rx)
+ usbip_dump_urb(urb);
--- /dev/null
+From d2dd0b07c3e725d386d20294ec906f7ddef207fa Mon Sep 17 00:00:00 2001
+From: Arjan Mels <arjan.mels@gmx.net>
+Date: Tue, 5 Apr 2011 20:26:11 +0200
+Subject: staging: usbip: bugfixes related to kthread conversion
+
+From: Arjan Mels <arjan.mels@gmx.net>
+
+commit d2dd0b07c3e725d386d20294ec906f7ddef207fa upstream.
+
+When doing a usb port reset do a queued reset instead to prevent a
+deadlock: the reset will cause the driver to unbind, causing the
+usb_driver_lock_for_reset to stall.
+
+Signed-off-by: Arjan Mels <arjan.mels@gmx.net>
+Cc: Takahiro Hirofuchi <hirofuchi@users.sourceforge.net>
+Cc: Max Vozeler <max@vozeler.com>
+Cc: Arnd Bergmann <arnd@arndb.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/staging/usbip/stub_rx.c | 40 +++++++++++++++-------------------------
+ 1 file changed, 15 insertions(+), 25 deletions(-)
+
+--- a/drivers/staging/usbip/stub_rx.c
++++ b/drivers/staging/usbip/stub_rx.c
+@@ -170,33 +170,23 @@ static int tweak_set_configuration_cmd(s
+
+ static int tweak_reset_device_cmd(struct urb *urb)
+ {
+- struct usb_ctrlrequest *req;
+- __u16 value;
+- __u16 index;
+- int ret;
++ struct stub_priv *priv = (struct stub_priv *) urb->context;
++ struct stub_device *sdev = priv->sdev;
+
+- req = (struct usb_ctrlrequest *) urb->setup_packet;
+- value = le16_to_cpu(req->wValue);
+- index = le16_to_cpu(req->wIndex);
++ usbip_uinfo("reset_device %s\n", dev_name(&urb->dev->dev));
+
+- usbip_uinfo("reset_device (port %d) to %s\n", index,
+- dev_name(&urb->dev->dev));
+-
+- /* all interfaces should be owned by usbip driver, so just reset it. */
+- ret = usb_lock_device_for_reset(urb->dev, NULL);
+- if (ret < 0) {
+- dev_err(&urb->dev->dev, "lock for reset\n");
+- return ret;
+- }
+-
+- /* try to reset the device */
+- ret = usb_reset_device(urb->dev);
+- if (ret < 0)
+- dev_err(&urb->dev->dev, "device reset\n");
+-
+- usb_unlock_device(urb->dev);
+-
+- return ret;
++ /*
++ * usb_lock_device_for_reset caused a deadlock: it causes the driver
++ * to unbind. In the shutdown the rx thread is signalled to shut down
++ * but this thread is pending in the usb_lock_device_for_reset.
++ *
++ * Instead queue the reset.
++ *
++ * Unfortunatly an existing usbip connection will be dropped due to
++ * driver unbinding.
++ */
++ usb_queue_reset_device(sdev->interface);
++ return 0;
+ }
+
+ /*