]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
.38 patches
authorGreg Kroah-Hartman <gregkh@suse.de>
Thu, 7 Apr 2011 21:37:50 +0000 (14:37 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 7 Apr 2011 21:37:50 +0000 (14:37 -0700)
queue-2.6.38/series
queue-2.6.38/staging-hv-fix-garp-not-sent-after-quick-migration.patch [new file with mode: 0644]
queue-2.6.38/staging-hv-use-sync_bitops-when-interacting-with-the-hypervisor.patch [new file with mode: 0644]
queue-2.6.38/staging-usbip-bugfix-add-number-of-packets-for-isochronous-frames.patch [new file with mode: 0644]
queue-2.6.38/staging-usbip-bugfix-for-isochronous-packets-and-optimization.patch [new file with mode: 0644]
queue-2.6.38/staging-usbip-bugfixes-related-to-kthread-conversion.patch [new file with mode: 0644]

index 7f1fa22c176f45beefa8faa21c74adedcd7550b6..58a1f878803e8f0bffa960ee0fb45f585cba3019 100644 (file)
@@ -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 (file)
index 0000000..79b85b0
--- /dev/null
@@ -0,0 +1,90 @@
+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);
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 (file)
index 0000000..55c96aa
--- /dev/null
@@ -0,0 +1,103 @@
+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>
+ /*
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 (file)
index 0000000..82ecb6f
--- /dev/null
@@ -0,0 +1,68 @@
+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);
+       }
+ }
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 (file)
index 0000000..01bf90e
--- /dev/null
@@ -0,0 +1,269 @@
+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);
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 (file)
index 0000000..62daa07
--- /dev/null
@@ -0,0 +1,74 @@
+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;
+ }
+ /*