From: Greg Kroah-Hartman Date: Thu, 7 Apr 2011 21:37:50 +0000 (-0700) Subject: .38 patches X-Git-Tag: v2.6.38.3~12 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=4be255705f09e3f7b99b3a9e9708d63b19aea23f;p=thirdparty%2Fkernel%2Fstable-queue.git .38 patches --- diff --git a/queue-2.6.38/series b/queue-2.6.38/series index 7f1fa22c176..58a1f878803 100644 --- a/queue-2.6.38/series +++ b/queue-2.6.38/series @@ -15,3 +15,8 @@ x86-64-mm-put-early-page-table-high.patch 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 diff --git a/queue-2.6.38/staging-hv-fix-garp-not-sent-after-quick-migration.patch b/queue-2.6.38/staging-hv-fix-garp-not-sent-after-quick-migration.patch new file mode 100644 index 00000000000..79b85b08ef0 --- /dev/null +++ b/queue-2.6.38/staging-hv-fix-garp-not-sent-after-quick-migration.patch @@ -0,0 +1,90 @@ +From c996edcf1c451b81740abbcca5257ed7e353fcc6 Mon Sep 17 00:00:00 2001 +From: Haiyang Zhang +Date: Wed, 6 Apr 2011 15:18:00 -0700 +Subject: staging: hv: Fix GARP not sent after Quick Migration + +From: Haiyang Zhang + +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 for reporting the bug and +testing the patch. + +Reported-by: Mike Surcouf +Tested-by: Mike Surcouf +Signed-off-by: Haiyang Zhang +Signed-off-by: Hank Janssen +Signed-off-by: Abhishek Kane +Signed-off-by: K. Y. Srinivasan +Signed-off-by: Greg Kroah-Hartman + +--- + 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); diff --git a/queue-2.6.38/staging-hv-use-sync_bitops-when-interacting-with-the-hypervisor.patch b/queue-2.6.38/staging-hv-use-sync_bitops-when-interacting-with-the-hypervisor.patch new file mode 100644 index 00000000000..55c96aac529 --- /dev/null +++ b/queue-2.6.38/staging-hv-use-sync_bitops-when-interacting-with-the-hypervisor.patch @@ -0,0 +1,103 @@ +From 22356585712d1ff08fbfed152edd8b386873b238 Mon Sep 17 00:00:00 2001 +From: Olaf Hering +Date: Mon, 21 Mar 2011 14:41:37 +0100 +Subject: staging: hv: use sync_bitops when interacting with the hypervisor + +From: Olaf Hering + +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 +Acked-by: Haiyang Zhang +Acked-by: Hank Janssen +Signed-off-by: Greg Kroah-Hartman + +--- + 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 ++#include + + + /* diff --git a/queue-2.6.38/staging-usbip-bugfix-add-number-of-packets-for-isochronous-frames.patch b/queue-2.6.38/staging-usbip-bugfix-add-number-of-packets-for-isochronous-frames.patch new file mode 100644 index 00000000000..82ecb6f2ae4 --- /dev/null +++ b/queue-2.6.38/staging-usbip-bugfix-add-number-of-packets-for-isochronous-frames.patch @@ -0,0 +1,68 @@ +From 1325f85fa49f57df034869de430f7c302ae23109 Mon Sep 17 00:00:00 2001 +From: Arjan Mels +Date: Tue, 5 Apr 2011 20:26:38 +0200 +Subject: staging: usbip: bugfix add number of packets for isochronous frames + +From: Arjan Mels + +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 +Cc: Takahiro Hirofuchi +Cc: Max Vozeler +Signed-off-by: Greg Kroah-Hartman + +--- + 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); + } + } diff --git a/queue-2.6.38/staging-usbip-bugfix-for-isochronous-packets-and-optimization.patch b/queue-2.6.38/staging-usbip-bugfix-for-isochronous-packets-and-optimization.patch new file mode 100644 index 00000000000..01bf90e3eb4 --- /dev/null +++ b/queue-2.6.38/staging-usbip-bugfix-for-isochronous-packets-and-optimization.patch @@ -0,0 +1,269 @@ +From 28276a28d8b3cd19f4449991faad4945fe557656 Mon Sep 17 00:00:00 2001 +From: Arjan Mels +Date: Tue, 5 Apr 2011 20:26:59 +0200 +Subject: staging: usbip: bugfix for isochronous packets and optimization + +From: Arjan Mels + +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 +Cc: Takahiro Hirofuchi +Cc: Max Vozeler +Signed-off-by: Greg Kroah-Hartman + +--- + 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); diff --git a/queue-2.6.38/staging-usbip-bugfixes-related-to-kthread-conversion.patch b/queue-2.6.38/staging-usbip-bugfixes-related-to-kthread-conversion.patch new file mode 100644 index 00000000000..62daa07bc5b --- /dev/null +++ b/queue-2.6.38/staging-usbip-bugfixes-related-to-kthread-conversion.patch @@ -0,0 +1,74 @@ +From d2dd0b07c3e725d386d20294ec906f7ddef207fa Mon Sep 17 00:00:00 2001 +From: Arjan Mels +Date: Tue, 5 Apr 2011 20:26:11 +0200 +Subject: staging: usbip: bugfixes related to kthread conversion + +From: Arjan Mels + +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 +Cc: Takahiro Hirofuchi +Cc: Max Vozeler +Cc: Arnd Bergmann +Signed-off-by: Greg Kroah-Hartman + +--- + 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; + } + + /*