USB-IP patches
cover USB-IP patches
Here's 3 patches that adds USB-IP functionality code to the kernel tree.
It is against 2.6.27-rc4, and has been added to the -staging tree. If there are no major objections, I'll also queue it up in the usb tree for submission into 2.6.28.
The code is based on Takahiro's great work that has been sitting outside of the kernel for many many years now. Brian Merrell took the most recent version of the code, cleaned it up and sent it to me. I did more cleanup and split the patch into 3 pieces, making it a bit easier to work with.
There are still a number of checkpatch.pl warnings/errors emitted, and Brian said he would work on them in the upcoming weeks, but they don't distract from the basic functionality and a good review would be nice to have.
We do need some more documentation for how to use this code (you need the tools at usbip.sf.net), and how the sysfs files are exporting data to userspace. Brian, can you write up the sysfs interface in the format that Documentation/ABI/ details and also provide some kind of basic HOWTO to include in the kernel source tree?
thanks,
greg k-h
PATCH 1/3 USB: USB/IP: add common functions needed
From: Takahiro Hirofuchi <[email protected]>
This adds the common functions needed by both the host and client side of the USB/IP code.
Brian Merrell cleaned up a lot of this code and submitted it for inclusion. Greg also did a lot of cleanup.
--- drivers/usb/Kconfig | 2 drivers/usb/Makefile | 2 drivers/usb/ip/Kconfig | 14 drivers/usb/ip/Makefile | 6 drivers/usb/ip/usbip_common.c | 997 ++++++++++++++++++++++++++++++++++++++++++ drivers/usb/ip/usbip_common.h | 406 +++++++++++++++++ drivers/usb/ip/usbip_event.c | 141 +++++ 7 files changed, 1568 insertions(+)
drivers/usb/ip/Kconfig new file +14 -0
@@ -0,0 +1,14 @@ +config USB_IP_COMMON + tristate "USB IP support (EXPERIMENTAL)" + depends on USB && EXPERIMENTAL + default N + ---help--- + This enables pushing USB packets over IP to allow remote + machines access to USB devices directly. For more details, + and links to the userspace utility programs to let this work + properly, see http://usbip.naist.jp/ + + To compile this driver as a module, choose M here: the + module will be called usbip_common_mod. + + If unsure, say N.
drivers/usb/ip/Makefile new file +6 -0
@@ -0,0 +1,6 @@ +obj-$(CONFIG_USB_IP_COMMON) += usbip_common_mod.o +usbip_common_mod-objs := usbip_common.o usbip_event.o + +ifeq ($(CONFIG_USB_DEBUG),y) + EXTRA_CFLAGS += -DDEBUG +endif
drivers/usb/ip/usbip_common.c new file +997 -0
997 lines not on this page · raw message
drivers/usb/ip/usbip_common.h new file +406 -0
406 lines not on this page · raw message
drivers/usb/ip/usbip_event.c new file +141 -0
141 lines not on this page · raw message
drivers/usb/Kconfig +2 -0
@@ -101,6 +101,8 @@ source "drivers/usb/host/Kconfig" source "drivers/usb/musb/Kconfig" +source "drivers/usb/ip/Kconfig" + source "drivers/usb/class/Kconfig" source "drivers/usb/storage/Kconfig"
drivers/usb/Makefile +2 -0
@@ -19,6 +19,8 @@ obj-$(CONFIG_USB_R8A66597_HCD) += host/ obj-$(CONFIG_USB_C67X00_HCD) += c67x00/ +obj-$(CONFIG_USB_IP_COMMON) += ip/ + obj-$(CONFIG_USB_ACM) += class/ obj-$(CONFIG_USB_PRINTER) += class/
Re: [patch 01/03] USB: USB/IP: add common functions needed
Am Freitag 29 August 2008 01:00:31 schrieb [email protected]:
drivers/usb/ip/usbip_common.c line 58
Quoted 8 lines
From: Takahiro Hirofuchi <[email protected]>
drivers/usb/ip/usbip_common.c new file +6
-0+static ssize_t store_flag (struct device *dev,struct device_attribute *attr, +const char *buf,size_t count) +{ +unsigned long flag; + +sscanf (buf,"%lx" , &flag);
Needs error handling
drivers/usb/ip/usbip_common.c line 65
Quoted 7 lines
drivers/usb/ip/usbip_common.c new file +7
-0+ usbip_debug_flag = flag; + +return count; +} +DEVICE_ATTR (usbip_debug, (S_IRUGO |S_IWUSR ), show_flag, store_flag); + +static void usbip_dump_buffer (char *buff,int bufflen)
Such functions better print into a buffer, handed over in one go. Otherwise you can get results
-second message-
like this
Quoted 5 lines
drivers/usb/ip/usbip_common.c new file +5
-0+/* there may be more cases to tweak the flags. */ +static unsigned int tweak_transfer_flags (unsigned int flags) +{ + +if (flags &URB_NO_TRANSFER_DMA_MAP )
drivers/usb/ip/usbip_common.c line 639
Quoted 10 lines
drivers/usb/ip/usbip_common.c new file +10
-0+/* +* vhci_hcd does not provide DMA-mapped I/O. The upper +* driver does not need to set this flag. The remote +* usbip.ko does not still perform DMA-mapped I/O for +* DMA-caplable host controllers. So, clear this flag. +*/ + flags &= ~URB_NO_TRANSFER_DMA_MAP ; + +if (flags &URB_NO_SETUP_DMA_MAP ) + flags &= ~URB_NO_SETUP_DMA_MAP ;
There's no need to do this conditionally.
drivers/usb/ip/usbip_common.c line 862
Quoted 10 lines
drivers/usb/ip/usbip_common.c new file +10
-0+/* must free buffer */ +void *usbip_alloc_iso_desc_pdu (struct urb *urb,ssize_t *bufflen) +{ +void *buff; +struct usbip_iso_packet_descriptor *iso; +int np = urb->number_of_packets; +ssize_t size = np *sizeof (*iso); +int i; + + buff =kzalloc (size,GFP_KERNEL );
Are you sure you cannot badly recourse here?
Regards
Oliver
Re: [patch 01/03] USB: USB/IP: add common functions needed
In reply to [email protected]drivers/usb/ip/Kconfig line 9
Quoted 5 lines · Greg KH
From: Takahiro Hirofuchi
drivers/usb/ip/Kconfig new file +4
-0+ This enables pushing USB packets over IP to allow remote + machines access to USB devices directly. For more details, + and links to the userspace utility programs to let this work + properly, see http://usbip.naist.jp/
Connection to this site times out here and now. Did your LKML post cause a DoS attack?
Signature · 1 line
Alexander E. Patrakov
Re: [patch 01/03] USB: USB/IP: add common functions needed
Quoted 10 lines · Alexander E. Patrakov
drivers/usb/ip/Kconfig line 9
Quoted 5 lines · Greg KH
From: Takahiro Hirofuchi
drivers/usb/ip/Kconfig new file +4
-0+ This enables pushing USB packets over IP to allow remote + machines access to USB devices directly. For more details, + and links to the userspace utility programs to let this work + properly, see http://usbip.naist.jp/Connection to this site times out here and now. Did your LKML post cause a DoS attack?
The site has moved to usbip.sf.net, as stated in the 00/03 patch. That should be working.
thanks,
greg k-h
Re: [patch 01/03] USB: USB/IP: add common functions needed
In reply to [email protected]Quoted 11 lines · On Thu, 28 Aug 2008 16:00:31 -0700 [email protected] wrote:
From: Takahiro Hirofuchi <[email protected]>
This adds the common functions needed by both the host and client side of the USB/IP code.
Brian Merrell cleaned up a lot of this code and submitted it for inclusion. Greg also did a lot of cleanup.
...
drivers/usb/ip/usbip_common.c line 62
Quoted 10 lines
drivers/usb/ip/usbip_common.c new file +10
-0+static ssize_t store_flag (struct device *dev,struct device_attribute *attr, +const char *buf,size_t count) +{ +unsigned long flag; + +sscanf (buf,"%lx" , &flag); + usbip_debug_flag = flag; + +return count; +}
Local variable `flag' is unneeded.
It's a bit sloppy that a user can do
echo wibble > /sys/whatever-file-this-is
and that will set usbip_debug_flag to zero. We should have a library function somewhere which can be used for this very common pattern.
Something like
/*
* Convert an optionally NULL-terminated digit string into a long. Returns
* a -ve errno if an invalid character was detected. Otherwise returns the
* number of characters whcih were consumed from the input.
*/
int sysfs_parse_long(const char *buf, long *ret)
{
...
}then the above becomes
static ssize_t store_flag(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
return sysfs_parse_long(buf, &usbip_debug_flag);
}(probably wrong, but you get the idea).
Quoted 23 lines
drivers/usb/ip/usbip_common.c new file +22
-0+DEVICE_ATTR (usbip_debug, (S_IRUGO |S_IWUSR ), show_flag, store_flag); + +static void usbip_dump_buffer (char *buff,int bufflen) +{ +int i; + +if (bufflen >128 ) { +for (i =0 ; i <128 ; i++) { +if (i%24 ==0 ) +printk (" " ); +printk ("%02x " , (unsigned char ) buff[i]); +if (i%4 ==3 ) +printk ("| " ); +if (i%24 ==23 ) +printk ("\n" ); + } +printk ("... (%d byte)\n" , bufflen); +return ; + } + +for (i =0 ; i < bufflen; i++) { +if (i%24 ==0 )
drivers/usb/ip/usbip_common.c line 94
Quoted 10 lines
drivers/usb/ip/usbip_common.c new file +10
-0+printk (" " ); +printk ("%02x " , (unsigned char ) buff[i]); +if (i%4 ==3 ) +printk ("| " ); +if (i%24 ==23 ) +printk ("\n" ); + } +printk ("\n" ); + +}
Please use lib/hexdump.c
Quoted 269 lines
drivers/usb/ip/usbip_common.c new file +269
-0+static void usbip_dump_pipe (unsigned int p) +{ +unsigned char type =usb_pipetype (p); +unsigned char ep =usb_pipeendpoint (p); +unsigned char dev =usb_pipedevice (p); +unsigned char dir =usb_pipein (p); + +printk ("dev(%d) " , dev); +printk ("ep(%d) " , ep); +printk ("%s " , dir ?"IN" :"OUT" ); + +switch (type) { +case PIPE_ISOCHRONOUS : +printk ("%s " ,"ISO" ); +break ; +case PIPE_INTERRUPT : +printk ("%s " ,"INT" ); +break ; +case PIPE_CONTROL : +printk ("%s " ,"CTL" ); +break ; +case PIPE_BULK : +printk ("%s " ,"BLK" ); +break ; +default : +printk ("ERR" ); + } + +printk ("\n" ); + +} + +static void usbip_dump_usb_device (struct usb_device *udev) +{ +struct device *dev = &udev->dev; +int i; + +dev_dbg (dev," devnum(%d) devpath(%s)" , + udev->devnum, udev->devpath); + +switch (udev->speed) { +case USB_SPEED_HIGH : +printk (" SPD_HIGH" ); +break ; +case USB_SPEED_FULL : +printk (" SPD_FULL" ); +break ; +case USB_SPEED_LOW : +printk (" SPD_LOW" ); +break ; +case USB_SPEED_UNKNOWN : +printk (" SPD_UNKNOWN" ); +break ; +default : +printk (" SPD_ERROR" ); + } + +printk (" tt %p, ttport %d" , udev->tt, udev->ttport); +printk ("\n" ); + +dev_dbg (dev," " ); +for (i =0 ; i <16 ; i++) +printk (" %2u" , i); +printk ("\n" ); + +dev_dbg (dev," toggle0(IN) :" ); +for (i =0 ; i <16 ; i++) +printk (" %2u" , (udev->toggle[0 ] & (1 << i)) ?1 :0 ); +printk ("\n" ); + +dev_dbg (dev," toggle1(OUT):" ); +for (i =0 ; i <16 ; i++) +printk (" %2u" , (udev->toggle[1 ] & (1 << i)) ?1 :0 ); +printk ("\n" ); + + +dev_dbg (dev," epmaxp_in :" ); +for (i =0 ; i <16 ; i++) { +if (udev->ep_in[i]) +printk (" %2u" , +le16_to_cpu (udev->ep_in[i]->desc.wMaxPacketSize)); + } +printk ("\n" ); + +dev_dbg (dev," epmaxp_out :" ); +for (i =0 ; i <16 ; i++) { +if (udev->ep_out[i]) +printk (" %2u" , +le16_to_cpu (udev->ep_out[i]->desc.wMaxPacketSize)); + } +printk ("\n" ); + +dev_dbg (dev,"parent %p, bus %p\n" , udev->parent, udev->bus); + +dev_dbg (dev,"descriptor %p, config %p, actconfig %p, " +"rawdescriptors %p\n" , &udev->descriptor, udev->config, + udev->actconfig, udev->rawdescriptors); + +dev_dbg (dev,"have_langid %d, string_langid %d\n" , + udev->have_langid, udev->string_langid); + +dev_dbg (dev,"maxchild %d, children %p\n" , + udev->maxchild, udev->children); +} + +static void usbip_dump_request_type (__u8 rt) +{ +switch (rt &USB_RECIP_MASK ) { +case USB_RECIP_DEVICE : +printk ("DEVICE" ); +break ; +case USB_RECIP_INTERFACE : +printk ("INTERF" ); +break ; +case USB_RECIP_ENDPOINT : +printk ("ENDPOI" ); +break ; +case USB_RECIP_OTHER : +printk ("OTHER " ); +break ; +default : +printk ("------" ); + } +} + +static void usbip_dump_usb_ctrlrequest (struct usb_ctrlrequest *cmd) +{ +if (!cmd) { +printk (" %s : null pointer\n" , __FUNCTION__); +return ; + } + +printk (" " ); +printk ("bRequestType(%02X) " , cmd->bRequestType); +printk ("bRequest(%02X) " , cmd->bRequest); +printk ("wValue(%04X) " , cmd->wValue); +printk ("wIndex(%04X) " , cmd->wIndex); +printk ("wLength(%04X) " , cmd->wLength); + +printk ("\n " ); + +if ((cmd->bRequestType &USB_TYPE_MASK ) ==USB_TYPE_STANDARD ) { +printk ("STANDARD " ); +switch (cmd->bRequest) { +case USB_REQ_GET_STATUS : +printk ("GET_STATUS" ); +break ; +case USB_REQ_CLEAR_FEATURE : +printk ("CLEAR_FEAT" ); +break ; +case USB_REQ_SET_FEATURE : +printk ("SET_FEAT " ); +break ; +case USB_REQ_SET_ADDRESS : +printk ("SET_ADDRRS" ); +break ; +case USB_REQ_GET_DESCRIPTOR : +printk ("GET_DESCRI" ); +break ; +case USB_REQ_SET_DESCRIPTOR : +printk ("SET_DESCRI" ); +break ; +case USB_REQ_GET_CONFIGURATION : +printk ("GET_CONFIG" ); +break ; +case USB_REQ_SET_CONFIGURATION : +printk ("SET_CONFIG" ); +break ; +case USB_REQ_GET_INTERFACE : +printk ("GET_INTERF" ); +break ; +case USB_REQ_SET_INTERFACE : +printk ("SET_INTERF" ); +break ; +case USB_REQ_SYNCH_FRAME : +printk ("SYNC_FRAME" ); +break ; +default : +printk ("REQ(%02X) " , cmd->bRequest); + } + +printk (" " ); +usbip_dump_request_type (cmd->bRequestType); + + }else if ((cmd->bRequestType &USB_TYPE_MASK ) ==USB_TYPE_CLASS ) +printk ("CLASS " ); + +else if ((cmd->bRequestType &USB_TYPE_MASK ) ==USB_TYPE_VENDOR ) +printk ("VENDOR " ); + +else if ((cmd->bRequestType &USB_TYPE_MASK ) ==USB_TYPE_RESERVED ) +printk ("RESERVED" ); + +printk ("\n" ); +} + +void usbip_dump_urb (struct urb *urb) +{ +struct device *dev; + +if (!urb) { + printk(KERN_DEBUG KBUILD_MODNAME + ":%s: urb: null pointer!!\n", __func__); +return ; + } + +if (!urb->dev) { + printk(KERN_DEBUG KBUILD_MODNAME + ":%s: urb->dev: null pointer!!\n", __func__); +return ; + } + dev = &urb->dev->dev; + +dev_dbg (dev," urb :%p\n" , urb); +dev_dbg (dev," dev :%p\n" , urb->dev); + +usbip_dump_usb_device (urb->dev); + +dev_dbg (dev," pipe :%08x " , urb->pipe); + +usbip_dump_pipe (urb->pipe); + +dev_dbg (dev," status :%d\n" , urb->status); +dev_dbg (dev," transfer_flags :%08X\n" , urb->transfer_flags); +dev_dbg (dev," transfer_buffer :%p\n" , urb->transfer_buffer); +dev_dbg (dev," transfer_buffer_length:%d\n" , urb->transfer_buffer_length); +dev_dbg (dev," actual_length :%d\n" , urb->actual_length); +dev_dbg (dev," setup_packet :%p\n" , urb->setup_packet); + +if (urb->setup_packet &&usb_pipetype (urb->pipe) ==PIPE_CONTROL ) +usbip_dump_usb_ctrlrequest ( + (struct usb_ctrlrequest *)urb->setup_packet); + +dev_dbg (dev," start_frame :%d\n" , urb->start_frame); +dev_dbg (dev," number_of_packets :%d\n" , urb->number_of_packets); +dev_dbg (dev," interval :%d\n" , urb->interval); +dev_dbg (dev," error_count :%d\n" , urb->error_count); +dev_dbg (dev," context :%p\n" , urb->context); +dev_dbg (dev," complete :%p\n" , urb->complete); +} +EXPORT_SYMBOL (usbip_dump_urb); + +void usbip_dump_header (struct usbip_header *pdu) +{ +udbg ("BASE: cmd %u seq %u devid %u dir %u ep %u\n" , + pdu->base.command, + pdu->base.seqnum, + pdu->base.devid, + pdu->base.direction, + pdu->base.ep); + +switch (pdu->base.command) { +case USBIP_CMD_SUBMIT : +udbg ("CMD_SUBMIT: x_flags %u x_len %u sf %u #p %u iv %u\n" , + pdu->u.cmd_submit.transfer_flags, + pdu->u.cmd_submit.transfer_buffer_length, + pdu->u.cmd_submit.start_frame, + pdu->u.cmd_submit.number_of_packets, + pdu->u.cmd_submit.interval); +break ; +case USBIP_CMD_UNLINK : +udbg ("CMD_UNLINK: seq %u\n" , pdu->u.cmd_unlink.seqnum); +break ; +case USBIP_RET_SUBMIT : +udbg ("RET_SUBMIT: st %d al %u sf %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.error_count);
drivers/usb/ip/usbip_common.c line 374
Quoted 10 lines
drivers/usb/ip/usbip_common.c new file +10
-0+case USBIP_RET_UNLINK : +udbg ("RET_UNLINK: status %d\n" , pdu->u.ret_unlink.status); +break ; +default : +/* NOT REACHED */ +udbg ("UNKNOWN\n" ); + } +} +EXPORT_SYMBOL (usbip_dump_header); +
There's a heck of a lot of debugging code there. It'd be good to have some way of making it config-time optional, if it isn't already.
Quoted 17 lines
drivers/usb/ip/usbip_common.c new file +17
-0+/*-------------------------------------------------------------------------*/ +/* thread routines */ + +int usbip_thread (void *param) +{ +struct usbip_task *ut = param; + +if (!ut) +return -EINVAL ; + +lock_kernel (); +daemonize (ut->name); +allow_signal (SIGKILL ); + ut->thread = current; +unlock_kernel (); + +/* srv.rb must wait for rx_thread starting */
drivers/usb/ip/usbip_common.c line 402
Quoted 10 lines
drivers/usb/ip/usbip_common.c new file +10
-0+complete (&ut->thread_done); + +/* start of while loop */ + ut->loop_ops (ut); + +/* end of loop */ + ut->thread =NULL ; + +complete_and_exit (&ut->thread_done,0 ); +}
no no no no no. Use the kthread interface.
Quoted 20 lines
drivers/usb/ip/usbip_common.c new file +20
-0+void usbip_start_threads (struct usbip_device *ud) +{ +/* +* threads are invoked per one device (per one connection). +*/ +kernel_thread (usbip_thread, (void *)&ud->tcp_rx,0 ); +kernel_thread (usbip_thread, (void *)&ud->tcp_tx,0 ); + +/* confirm threads are starting */ +wait_for_completion (&ud->tcp_rx.thread_done); +wait_for_completion (&ud->tcp_tx.thread_done); +} +EXPORT_SYMBOL (usbip_start_threads); + +void usbip_stop_threads (struct usbip_device *ud) +{ +/* kill threads related to this sdev, if v.c. exists */ +if (ud->tcp_rx.thread !=NULL ) { +send_sig (SIGKILL , ud->tcp_rx.thread,1 ); +wait_for_completion (&ud->tcp_rx.thread_done);
drivers/usb/ip/usbip_common.c line 433
Quoted 10 lines
drivers/usb/ip/usbip_common.c new file +10
-0+udbg ("rx_thread for ud %p has finished\n" , ud); + } + +if (ud->tcp_tx.thread !=NULL ) { +send_sig (SIGKILL , ud->tcp_tx.thread,1 ); +wait_for_completion (&ud->tcp_tx.thread_done); +udbg ("tx_thread for ud %p has finished\n" , ud); + } +} +EXPORT_SYMBOL (usbip_stop_threads);
ditto
Quoted 5 lines
drivers/usb/ip/usbip_common.c new file +5
-0+void usbip_task_init (struct usbip_task *ut,char *name, +void (*loop_ops)(struct usbip_task *)) +{ + ut->thread =NULL ; +init_completion (&ut->thread_done);
drivers/usb/ip/usbip_common.c line 449
Quoted 10 lines
drivers/usb/ip/usbip_common.c new file +10
-0+ ut->name = name; + ut->loop_ops = loop_ops; +} +EXPORT_SYMBOL (usbip_task_init); + + +/*-------------------------------------------------------------------------*/ +/* socket routines */ + +/* Send/receive messages over TCP/IP. I refer drivers/block/nbd.c */
hey, that's networking stuff. Someone tell the networking developers?
Quoted 15 lines
drivers/usb/ip/usbip_common.c new file +15
-0+int usbip_xmit (int send,struct socket *sock,char *buf, +int size,int msg_flags) +{ +int result; +struct msghdr msg; +struct kvec iov; +int total =0 ; + +/* for blocks of if (dbg_flag_xmit) */ +char *bp = buf; +int osize = size; + +dbg_xmit ("enter\n" ); + +if (!sock || !buf || !size) {
drivers/usb/ip/usbip_common.c line 474
Quoted 10 lines
drivers/usb/ip/usbip_common.c new file +10
-0+printk (KERN_ERR "%s: invalid arg, sock %p buff %p size %d\n" , + __func__, sock, buf, size); +return -EINVAL ; + } + + +if (dbg_flag_xmit) { +if (send) { +if (!in_interrupt ()) +printk (KERN_DEBUG "%-10s:" , current->comm);
Use get_task_comm() here.
Review
Quoted 2 lines
(quoted diff) +2
-0+ else + printk(KERN_DEBUG "interupt :");
typo.
Quoted 35 lines
drivers/usb/ip/usbip_common.c new file +35
-0+ +printk ("%s: sending... , sock %p, buf %p, " +"size %d, msg_flags %d\n" , __func__, + sock, buf, size, msg_flags); +usbip_dump_buffer (buf, size); + } + } + + + do { + sock->sk->sk_allocation = GFP_NOIO; + iov.iov_base = buf; + iov.iov_len = size; + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_namelen = 0; + msg.msg_flags = msg_flags | MSG_NOSIGNAL; + + if (send) + result = kernel_sendmsg(sock, &msg, &iov, 1, size); + else + result = kernel_recvmsg(sock, &msg, &iov, 1, size, + MSG_WAITALL); + + if (result <= 0) { + udbg("usbip_xmit: %s sock %p buf %p size %u ret %d" + " total %d\n", + send ? "send" : "receive", sock, buf, + size, result, total); + goto err; + } + + size -= result;
drivers/usb/ip/usbip_common.c line 521
Quoted 10 lines
drivers/usb/ip/usbip_common.c new file +10
-0+ buf += result; + total += result; + + }while (size >0 ); + + +if (dbg_flag_xmit) { +if (!send) { +if (!in_interrupt ()) +printk (KERN_DEBUG "%-10s:" , current->comm);
ditto
Review
Quoted 2 lines
(quoted diff) +2
-0+ else + printk(KERN_DEBUG "interupt :");
ditto
Quoted 12 lines
drivers/usb/ip/usbip_common.c new file +12
-0+ +printk ("usbip_xmit: receiving....\n" ); +usbip_dump_buffer (bp, osize); +printk ("usbip_xmit: received, osize %d ret %d size %d " +"total %d\n" , osize, result, size, + total); + } + +if (send) +printk ("usbip_xmit: send, total %d\n" , total); + } +
drivers/usb/ip/usbip_common.c line 545
Quoted 10 lines
drivers/usb/ip/usbip_common.c new file +10
-0+return total; + +err: +return result; +} +EXPORT_SYMBOL (usbip_xmit); + + +/* now a usrland utility should set options. */ +#if 0
kill this?
Quoted 57 lines
drivers/usb/ip/usbip_common.c new file +57
-0+int setquickack (struct socket *socket) +{ +mm_segment_t oldfs; +int val =1 ; +int ret; + + oldfs =get_fs (); +set_fs (get_ds ()); + ret = socket->ops->setsockopt (socket,SOL_TCP ,TCP_QUICKACK , + (char __user *) &val,sizeof (ret)); +set_fs (oldfs); + +return ret; +} + +int setnodelay (struct socket *socket) +{ +mm_segment_t oldfs; +int val =1 ; +int ret; + + oldfs =get_fs (); +set_fs (get_ds ()); + ret = socket->ops->setsockopt (socket,SOL_TCP ,TCP_NODELAY , + (char __user *) &val,sizeof (ret)); +set_fs (oldfs); + +return ret; +} + +int setkeepalive (struct socket *socket) +{ +mm_segment_t oldfs; +int val =1 ; +int ret; + + oldfs =get_fs (); +set_fs (get_ds ()); + ret = socket->ops->setsockopt (socket,SOL_SOCKET ,SO_KEEPALIVE , + (char __user *) &val,sizeof (ret)); +set_fs (oldfs); + +return ret; +} + +void setreuse (struct socket *socket) +{ + socket->sk->sk_reuse =1 ; +} +#endif + +struct socket *sockfd_to_socket (unsigned int sockfd) +{ +struct socket *socket; +struct file *file; +struct inode *inode; +
drivers/usb/ip/usbip_common.c line 612
Quoted 10 lines
drivers/usb/ip/usbip_common.c new file +10
-0+ file =fget (sockfd); +if (!file) { +printk (KERN_ERR "%s: invalid sockfd\n" , __func__); +return NULL ; + } + + inode = file->f_dentry->d_inode; + +if (!inode || !S_ISSOCK (inode->i_mode)) +return NULL ;
Can file->f_dentry->d_inode ever be NULL??
Quoted 16 lines
drivers/usb/ip/usbip_common.c new file +16
-0+ socket =SOCKET_I (inode); + +return socket; +} +EXPORT_SYMBOL (sockfd_to_socket); + + + +/*-------------------------------------------------------------------------*/ +/* pdu routines */ + +/* there may be more cases to tweak the flags. */ +static unsigned int tweak_transfer_flags (unsigned int flags) +{ + +if (flags &URB_NO_TRANSFER_DMA_MAP )
drivers/usb/ip/usbip_common.c line 639
Quoted 10 lines
drivers/usb/ip/usbip_common.c new file +10
-0+/* +* vhci_hcd does not provide DMA-mapped I/O. The upper +* driver does not need to set this flag. The remote +* usbip.ko does not still perform DMA-mapped I/O for +* DMA-caplable host controllers. So, clear this flag. +*/ + flags &= ~URB_NO_TRANSFER_DMA_MAP ; + +if (flags &URB_NO_SETUP_DMA_MAP ) + flags &= ~URB_NO_SETUP_DMA_MAP ;
flags &= ~(URB_NO_TRANSFER_DMA_MAP|URB_NO_SETUP_DMA_MAP);
Quoted 44 lines
drivers/usb/ip/usbip_common.c new file +41
-0+return flags; +} + +static void usbip_pack_cmd_submit (struct usbip_header *pdu,struct urb *urb, +int pack) +{ +struct usbip_header_cmd_submit *spdu = &pdu->u.cmd_submit; + +/* +* Some members are not still implemented in usbip. I hope this issue +* will be discussed when usbip is ported to other operating systems. +*/ +if (pack) { +/* vhci_tx.c */ + spdu->transfer_flags = +tweak_transfer_flags (urb->transfer_flags); + spdu->transfer_buffer_length = urb->transfer_buffer_length; + spdu->start_frame = urb->start_frame; + spdu->number_of_packets = urb->number_of_packets; + spdu->interval = urb->interval; + }else { +/* stub_rx.c */ + urb->transfer_flags = spdu->transfer_flags; + + urb->transfer_buffer_length = spdu->transfer_buffer_length; + urb->start_frame = spdu->start_frame; + urb->number_of_packets = spdu->number_of_packets; + urb->interval = spdu->interval; + } +} +/* some members of urb must be substituted before. */ +int usbip_recv_iso (struct usbip_device *ud,struct urb *urb) +{ +void *buff; +struct usbip_iso_packet_descriptor *iso; +int np = urb->number_of_packets; +int size = np *sizeof (*iso); +int i; +int ret; + +if (!usb_pipeisoc (urb->pipe))
drivers/usb/ip/usbip_common.c
Quoted 10 lines
drivers/usb/ip/usbip_common.c new file +10
-0+return 0 ; + +/* my Bluetooth dongle gets ISO URBs which are np = 0 */ +if (np ==0 ) { +/* uinfo("iso np == 0\n"); */ +/* usbip_dump_urb(urb); */ +return 0 ; + } + + buff =kzalloc (size,GFP_KERNEL );
Do all these kzalloc()s really need to zero out the memory?
Quoted 47 lines
drivers/usb/ip/usbip_common.c new file +47
-0+if (!buff) +return -ENOMEM ; + + ret =usbip_xmit (0 , ud->tcp_socket, buff, size,0 ); +if (ret != size) { +dev_err (&urb->dev->dev,"recv iso_frame_descriptor, %d\n" , + ret); +kfree (buff); + +if (ud->side ==USBIP_STUB ) +usbip_event_add (ud,SDEV_EVENT_ERROR_TCP ); +else +usbip_event_add (ud,VDEV_EVENT_ERROR_TCP ); + +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 ); + } + + +kfree (buff); + +return ret; +} +EXPORT_SYMBOL (usbip_recv_iso); + + +/* some members of urb must be substituted before. */ +int usbip_recv_xbuff (struct usbip_device *ud,struct urb *urb) +{ +int ret; +int size; + +if (ud->side ==USBIP_STUB ) { +/* stub_rx.c */ +/* the direction of urb must be OUT. */ +if (usb_pipein (urb->pipe)) +return 0 ; + + size = urb->transfer_buffer_length; + }else { +/* vhci_rx.c */
drivers/usb/ip/usbip_common.c line 956
Quoted 10 lines
drivers/usb/ip/usbip_common.c new file +10
-0+/* the direction of urb must be IN. */ +if (usb_pipeout (urb->pipe)) +return 0 ; + + size = urb->actual_length; + } + +/* no need to recv xbuff */ +if (!(size >0 )) +return 0 ;
can `size' really be less than zero?
Quoted 51 lines
drivers/usb/ip/usbip_common.c new file +17
-0+ ret =usbip_xmit (0 , ud->tcp_socket, (char *)urb->transfer_buffer, + size,0 ); +if (ret != size) { +dev_err (&urb->dev->dev,"recv xbuf, %d\n" , ret); +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 (usbip_recv_xbuff); + +drivers/usb/ip/usbip_common.h new file +28
-0@@ -0,0 +1,406 @@ +/* +* Copyright (C) 2003-2008 Takahiro Hirofuchi +* +* This is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +* USA. +*/ + +#ifndef __VHCI_COMMON_H +#define __VHCI_COMMON_H + + +#include <linux/version.h> +#include <linux/usb.h> +#include <asm/byteorder.h> +#include <net/sock.h> +
drivers/usb/ip/usbip_common.h line 38
Quoted 10 lines
drivers/usb/ip/usbip_common.h new file +10
-0+/*-------------------------------------------------------------------------*/ + +/* +* define macros to print messages +*/ + +/** +* udbg - print debug messages if CONFIG_USB_DEBUG is defined +* @fmt: +* @args:
?
drivers/usb/ip/usbip_common.h line 41
Quoted 3 lines
drivers/usb/ip/usbip_common.h new file +3
-0+*/ + +#ifdef CONFIG_USB_DEBUG
Is it appropriate that this be under CONFIG_USB_DEBUG? Or should there be a usbip-specific config variable?
Quoted 20 lines
drivers/usb/ip/usbip_common.h new file +20
-0+#define udbg(fmt, args...) \ + do { \ + printk(KERN_DEBUG "%-10s:(%s,%d) %s: " fmt, \ + (in_interrupt() ? "interrupt" : (current)->comm),\ + __FILE__, __LINE__, __func__, ##args); \ + } while (0) + +#else /* CONFIG_USB_DEBUG */ + +#define udbg(fmt, args...) do { } while (0) + +#endif /* CONFIG_USB_DEBUG */ + + +enum { + usbip_debug_xmit = (1 <<0 ), + usbip_debug_sysfs = (1 <<1 ), + usbip_debug_urb = (1 <<2 ), + usbip_debug_eh = (1 <<3 ), +
drivers/usb/ip/usbip_common.h line 72
Quoted 10 lines
drivers/usb/ip/usbip_common.h new file +10
-0+ usbip_debug_stub_cmp = (1 <<8 ), + usbip_debug_stub_dev = (1 <<9 ), + usbip_debug_stub_rx = (1 <<10 ), + usbip_debug_stub_tx = (1 <<11 ), + + usbip_debug_vhci_rh = (1 <<8 ), + usbip_debug_vhci_hc = (1 <<9 ), + usbip_debug_vhci_rx = (1 <<10 ), + usbip_debug_vhci_tx = (1 <<11 ), + usbip_debug_vhci_sysfs = (1 <<12 )
There are four duplicates there. That seems odd.
Quoted 36 lines
drivers/usb/ip/usbip_common.h new file +35
-0+}; + +#define dbg_flag_xmit (usbip_debug_flag & usbip_debug_xmit) +#define dbg_flag_vhci_rh (usbip_debug_flag & usbip_debug_vhci_rh) +#define dbg_flag_vhci_hc (usbip_debug_flag & usbip_debug_vhci_hc) +#define dbg_flag_vhci_rx (usbip_debug_flag & usbip_debug_vhci_rx) +#define dbg_flag_vhci_tx (usbip_debug_flag & usbip_debug_vhci_tx) +#define dbg_flag_vhci_sysfs (usbip_debug_flag & usbip_debug_vhci_sysfs) +#define dbg_flag_stub_rx (usbip_debug_flag & usbip_debug_stub_rx) +#define dbg_flag_stub_tx (usbip_debug_flag & usbip_debug_stub_tx) +extern unsigned long usbip_debug_flag; +extern struct device_attribute dev_attr_usbip_debug; + +#define dbg_with_flag(flag, fmt, args...) \ + do { \ + if (flag & usbip_debug_flag) \ + udbg(fmt , ##args); \ + } while (0) + +#define dbg_sysfs(fmt, args...) \ + dbg_with_flag(usbip_debug_sysfs, fmt , ##args) +#define dbg_xmit(fmt, args...) \ + dbg_with_flag(usbip_debug_xmit, fmt , ##args) +#define dbg_urb(fmt, args...) \ + dbg_with_flag(usbip_debug_urb, fmt , ##args) +#define dbg_eh(fmt, args...) \ + dbg_with_flag(usbip_debug_eh, fmt , ##args) + +#define dbg_vhci_rh(fmt, args...) \ + dbg_with_flag(usbip_debug_vhci_rh, fmt , ##args) +#define dbg_vhci_hc(fmt, args...) \ + dbg_with_flag(usbip_debug_vhci_hc, fmt , ##args) +#define dbg_vhci_rx(fmt, args...) \ + dbg_with_flag(usbip_debug_vhci_rx, fmt , ##args) +#define dbg_vhci_tx(fmt, args...) \
drivers/usb/ip/usbip_common.h line 118
Quoted 10 lines
drivers/usb/ip/usbip_common.h new file +10
-0+ dbg_with_flag(usbip_debug_vhci_tx, fmt , ##args) +#define dbg_vhci_sysfs(fmt, args...) \ + dbg_with_flag(usbip_debug_vhci_sysfs, fmt , ##args) + +#define dbg_stub_cmp(fmt, args...) \ + dbg_with_flag(usbip_debug_stub_cmp, fmt , ##args) +#define dbg_stub_rx(fmt, args...) \ + dbg_with_flag(usbip_debug_stub_rx, fmt , ##args) +#define dbg_stub_tx(fmt, args...) \ + dbg_with_flag(usbip_debug_stub_tx, fmt , ##args)
This header adds a lot of symbols which have fairly generic-sounding names and which don't have "usbip" within them. There is a risk that we will later clash with some other header file's dbg_sysfs.
Quoted 12 lines
drivers/usb/ip/usbip_common.h new file +12
-0+ +/** +* uerr - print error messages +* @fmt: +* @args: +*/ +#define uerr(fmt, args...) \ + do { \ + printk(KERN_ERR "%-10s: ***ERROR*** (%s,%d) %s: " fmt, \ + (in_interrupt() ? "interrupt" : (current)->comm),\ + __FILE__, __LINE__, __func__, ##args); \ + } while (0)
drivers/usb/ip/usbip_common.h line 141
Quoted 10 lines
drivers/usb/ip/usbip_common.h new file +10
-0+ +/** +* uinfo - print information messages +* @fmt: +* @args: +*/ +#define uinfo(fmt, args...) \ + do { \ + printk(KERN_INFO "usbip: " fmt , ## args); \ + } while (0)
These two are risky also.
Quoted 11 lines
drivers/usb/ip/usbip_common.h new file +11
-0+ +/*-------------------------------------------------------------------------*/ + +/* +* USB/IP request headers. +* Currently, we define 4 request types: +* +* - CMD_SUBMIT transfers a USB request, corresponding to usb_submit_urb(). +* (client to server) +* - RET_RETURN transfers the result of CMD_SUBMIT. +* (server to client)
drivers/usb/ip/usbip_common.h line 163
Quoted 10 lines
drivers/usb/ip/usbip_common.h new file +10
-0+* - CMD_UNLINK transfers an unlink request of a pending USB request. +* (client to server) +* - RET_UNLINK transfers the result of CMD_UNLINK. +* (server to client) +* +* Note: The below request formats are based on the USB subsystem of Linux. Its +* details will be defined when other implementations come. +* +* +*/
I assume the below data structures are known about by userspace?
If so, the comment should make that very very clear. This is part of the kernel ABI.
Is this interface versioned? If not, should it be?
This header doesn't appear to have __KERNEL__ guards. Should we be aiming to be able to use this header directly within userspace compilation?
Quoted 42 lines
drivers/usb/ip/usbip_common.h new file +39
-0+/* +* A basic header followed by other additional headers. +*/ +struct usbip_header_basic { +#define USBIP_CMD_SUBMIT 0x0001 +#define USBIP_CMD_UNLINK 0x0002 +#define USBIP_RET_SUBMIT 0x0003 +#define USBIP_RET_UNLINK 0x0004 +__u32 command; + +/* sequencial number which identifies requests. +* incremented per connections */ +__u32 seqnum; + +/* devid is used to specify a remote USB device uniquely instead +* of busnum and devnum in Linux. In the case of Linux stub_driver, +* this value is ((busnum << 16) | devnum) */ +__u32 devid; + +#define USBIP_DIR_OUT 0 +#define USBIP_DIR_IN 1 +__u32 direction; +__u32 ep;/* endpoint number */ +} __attribute__ ((packed)); + + + +int usbip_xmit (int ,struct socket *,char *,int ,int ); +int usbip_sendmsg (struct socket *,struct msghdr *,int ); + + +static inline int interface_to_busnum (struct usb_interface *interface) +{ +struct usb_device *udev =interface_to_usbdev (interface); +return udev->bus->busnum; +} + +static inline int interface_to_devnum (struct usb_interface *interface) +{
drivers/usb/ip/usbip_common.h
Quoted 10 lines
drivers/usb/ip/usbip_common.h new file +10
-0+struct usb_device *udev =interface_to_usbdev (interface); +return udev->devnum; +} + +static inline int interface_to_infnum (struct usb_interface *interface) +{ +return interface->cur_altsetting->desc.bInterfaceNumber; +} + +#if 0
kill?
Quoted 23 lines
drivers/usb/ip/usbip_common.h new file +20
-0+int setnodelay (struct socket *); +int setquickack (struct socket *); +int setkeepalive (struct socket *socket); +void setreuse (struct socket *); +#endif + +struct socket *sockfd_to_socket (unsigned int ); +int set_sockaddr (struct socket *socket,struct sockaddr_storage *ss); + +void usbip_dump_urb (struct urb *purb); +void usbip_dump_header (struct usbip_header *pdu); + + +static void event_handler_loop (struct usbip_task *ut) +{ + struct usbip_device *ud = container_of(ut, struct usbip_device, eh); + +while (1 ) { +if (signal_pending (current)) { +dbg_eh ("signal catched!\n" );
drivers/usb/ip/usbip_common.h
Quoted 10 lines
drivers/usb/ip/usbip_common.h new file +10
-0+break ; + } + +if (event_handler (ud) <0 ) +break ; + +wait_event_interruptible (ud->eh_waitq,usbip_event_happend (ud)); +dbg_eh ("wakeup\n" ); + } +}
hm. So we sit there waiting for a wakeup and each time one occurs we will assume that there is a single event waiting at ut->event.
I don't see handshaking in event_handler(). It looks like this will be rich with races and overruns. But I didn't look for the sending side.
Quoted 27 lines
drivers/usb/ip/usbip_common.h new file +27
-0+void usbip_start_eh (struct usbip_device *ud) +{ +struct usbip_task *eh = &ud->eh; + +init_waitqueue_head (&ud->eh_waitq); + ud->event =0 ; + +usbip_task_init (eh,"usbip_eh" , event_handler_loop); + +kernel_thread (usbip_thread, (void *)eh,0 ); + +wait_for_completion (&eh->thread_done); +} +EXPORT_SYMBOL (usbip_start_eh); + +void usbip_stop_eh (struct usbip_device *ud) +{ +struct usbip_task *eh = &ud->eh; + +wait_for_completion (&eh->thread_done); +dbg_eh ("usbip_eh has finished\n" ); +} +EXPORT_SYMBOL (usbip_stop_eh); + +void usbip_event_add (struct usbip_device *ud,unsigned long event) +{ +spin_lock (&ud->lock);
drivers/usb/ip/usbip_common.h
Quoted 10 lines
drivers/usb/ip/usbip_common.h new file +10
-0+ + ud->event |= event; + +wake_up (&ud->eh_waitq); + +spin_unlock (&ud->lock); +} +EXPORT_SYMBOL (usbip_event_add); + +int usbip_event_happend (struct usbip_device *ud)
"happened"
drivers/usb/ip/usbip_common.h
Quoted 2 lines
drivers/usb/ip/usbip_common.h new file +2
-0+{ +int happend =0 ;
"happened"
drivers/usb/ip/usbip_common.h
Quoted 10 lines
drivers/usb/ip/usbip_common.h new file +10
-0+spin_lock (&ud->lock); + +if (ud->event !=0 ) + happend =1 ; + +spin_unlock (&ud->lock); + +return happend; +} +EXPORT_SYMBOL (usbip_event_happend);
It all does look rather racy. In what context does usbip_recv_iso() get called? I hope it isn't rx interrupt :(
Quoted 21 lines
drivers/usb/Kconfig +2
-0@@ -101,6 +101,8 @@ source "drivers/usb/host/Kconfig" source "drivers/usb/musb/Kconfig" +source "drivers/usb/ip/Kconfig" + source "drivers/usb/class/Kconfig" source "drivers/usb/storage/Kconfig"drivers/usb/Makefile +2
-0@@ -19,6 +19,8 @@ obj-$(CONFIG_USB_R8A66597_HCD) += host/ obj-$(CONFIG_USB_C67X00_HCD) += c67x00/ +obj-$(CONFIG_USB_IP_COMMON) += ip/ + obj-$(CONFIG_USB_ACM) += class/ obj-$(CONFIG_USB_PRINTER) += class/
PATCH 2/3 USB: USB/IP: add client driver
In reply to [email protected]From: Takahiro Hirofuchi <[email protected]>
This adds the USB IP client driver
Brian Merrell cleaned up a lot of this code and submitted it for inclusion. Greg also did a lot of cleanup.
--- drivers/usb/ip/Kconfig | 10 drivers/usb/ip/Makefile | 3 drivers/usb/ip/vhci.h | 142 ++++ drivers/usb/ip/vhci_hcd.c | 1282 ++++++++++++++++++++++++++++++++++++++++++++ drivers/usb/ip/vhci_rx.c | 251 ++++++++ drivers/usb/ip/vhci_sysfs.c | 250 ++++++++ drivers/usb/ip/vhci_tx.c | 239 ++++++++ 7 files changed, 2177 insertions(+)
drivers/usb/ip/Kconfig +10 -0
@@ -12,3 +12,13 @@ config USB_IP_COMMON module will be called usbip_common_mod. If unsure, say N. + +config USB_IP_VHCI_HCD + tristate "USB IP client driver" + depends on USB_IP_COMMON + ---help--- + This enables the USB IP host controller driver which will + run on the client machine. + + To compile this driver as a module, choose M here: the + module will be called vhci_hcd.
drivers/usb/ip/Makefile +3 -0
@@ -1,6 +1,9 @@ obj-$(CONFIG_USB_IP_COMMON) += usbip_common_mod.o usbip_common_mod-objs := usbip_common.o usbip_event.o +obj-$(CONFIG_USB_IP_VHCI_HCD) += vhci-hcd.o +vhci-hcd-objs := vhci_sysfs.o vhci_tx.o vhci_rx.o vhci_hcd.o + ifeq ($(CONFIG_USB_DEBUG),y) EXTRA_CFLAGS += -DDEBUG endif
drivers/usb/ip/vhci.h new file +142 -0
142 lines not on this page · raw message
drivers/usb/ip/vhci_hcd.c new file +1282 -0
1,282 lines not on this page · raw message
drivers/usb/ip/vhci_rx.c new file +251 -0
251 lines not on this page · raw message
drivers/usb/ip/vhci_sysfs.c new file +250 -0
250 lines not on this page · raw message
drivers/usb/ip/vhci_tx.c new file +239 -0
239 lines not on this page · raw message
Re: [patch 02/03] USB: USB/IP: add client driver
Am Freitag 29 August 2008 01:00:35 schrieb [email protected]:
drivers/usb/ip/vhci_hcd.c line 366
Quoted 10 lines
From: Takahiro Hirofuchi <[email protected]>
drivers/usb/ip/vhci_hcd.c new file +8
-0+ dum->port_status[rhport] |= + (1 <<USB_PORT_FEAT_C_SUSPEND ); + dum->port_status[rhport] &= + ~(1 <<USB_PORT_FEAT_SUSPEND ); + dum->resuming =0 ; + dum->re_timeout =0 ; +/* if (dum->driver && dum->driver->resume) { +* spin_unlock (&dum->lock);
I realise it is commented out, but still.
The resume method may sleep. It is documented as such. Thus it can reenable interrupts. Therefore you can deadlock if you don't use irqrestore.
Quoted 5 lines
drivers/usb/ip/vhci_hcd.c new file +5
-0+static void vhci_tx_urb (struct urb *urb) +{ +struct vhci_device *vdev =get_vdev (urb->dev); +struct vhci_priv *priv; +unsigned long flag;
drivers/usb/ip/vhci_hcd.c line 522
Quoted 10 lines
drivers/usb/ip/vhci_hcd.c new file +10
-0+ +if (!vdev) { +err ("could not get virtual device" ); +/* BUG(); */ +return ; + } + +spin_lock_irqsave (&vdev->priv_lock, flag); + + priv =kzalloc (sizeof (struct vhci_priv ),GFP_ATOMIC );
There's no reason to hold the lock longer than necessary by allocating memory in the lock section.
[..]
drivers/usb/ip/vhci_hcd.c line 543
Quoted 2 lines
drivers/usb/ip/vhci_hcd.c new file +2
-0+wake_up (&vdev->waitq_tx); +spin_unlock_irqrestore (&vdev->priv_lock, flag);
again
drivers/usb/ip/vhci_hcd.c line 548
Quoted 3 lines
drivers/usb/ip/vhci_hcd.c new file +3
-0+static int vhci_urb_enqueue (struct usb_hcd *hcd,struct urb *urb, +gfp_t mem_flags) +{
This is called in the context of usb_submit_urb()
[..]
drivers/usb/ip/vhci_hcd.c line 574
Quoted 1 line
drivers/usb/ip/vhci_hcd.c new file +1
-0+ ret =usb_hcd_link_urb_to_ep (hcd, urb);
This can fail for any urb due to urb->reject
drivers/usb/ip/vhci_hcd.c line 576
Quoted 2 lines
drivers/usb/ip/vhci_hcd.c new file +2
-0+if (ret) + goto no_need_unlink;
The branch would be taken
[..]
drivers/usb/ip/vhci_hcd.c line 654
Quoted 4 lines
drivers/usb/ip/vhci_hcd.c new file +4
-0+no_need_unlink: +spin_unlock_irqrestore (&the_controller->lock, flags); + +usb_hcd_giveback_urb (vhci_to_hcd (the_controller), urb, urb->status);
This calls urb->complete. If the completion handler takes a spinlock which is held when usb_submit_urb() was called, you deadlock.
Quoted 1 line
+static int
vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
[..]
drivers/usb/ip/vhci_hcd.c line 797
Quoted 3 lines
drivers/usb/ip/vhci_hcd.c new file +3
-0+spin_unlock_irqrestore (&the_controller->lock, flags); +usb_hcd_giveback_urb (vhci_to_hcd (the_controller), urb, + urb->status);
This must be called with interrupts disabled.
drivers/usb/ip/vhci_hcd.c line 805
Quoted 8 lines
drivers/usb/ip/vhci_hcd.c new file +8
-0+spin_lock_irqsave (&the_controller->lock, flags); + } + +spin_unlock_irqrestore (&the_controller->lock, flags); + +dbg_vhci_hc ("leave\n" ); +return 0 ; +}
Regards
Oliver
Re: [patch 02/03] USB: USB/IP: add client driver
In reply to [email protected]Quoted 17 lines
drivers/usb/ip/vhci_hcd.c new file +17
-0+static int vhci_urb_enqueue (struct usb_hcd *hcd,struct urb *urb, +gfp_t mem_flags) +{ +struct device *dev = &urb->dev->dev; +int ret =0 ; +unsigned long flags; + +dbg_vhci_hc ("enter, usb_hcd %p urb %p mem_flags %d\n" , + hcd, urb, mem_flags); + +/* patch to usb_sg_init() is in 2.5.60 */ +BUG_ON (!urb->transfer_buffer && urb->transfer_buffer_length); + +spin_lock_irqsave (&the_controller->lock, flags); + +/* check HC is active or not */ +if (!HC_IS_RUNNING (hcd->state)) {
drivers/usb/ip/vhci_hcd.c line 572
Quoted 10 lines
drivers/usb/ip/vhci_hcd.c new file +10
-0+dev_err (dev,"HC is not running\n" ); +spin_unlock_irqrestore (&the_controller->lock, flags); +return -ENODEV ; + } + +if (urb->status != -EINPROGRESS ) { +dev_err (dev,"URB already unlinked!, status %d\n" , urb->status); +spin_unlock_irqrestore (&the_controller->lock, flags); +return urb->status; + }
Neither of these two tests is necessary. They are both carried out by usb_hcd_link_urb_to_ep().
drivers/usb/ip/vhci_hcd.c line 576
Quoted 4 lines
drivers/usb/ip/vhci_hcd.c new file +4
-0+ + ret =usb_hcd_link_urb_to_ep (hcd, urb); +if (ret) + goto no_need_unlink;
This is wrong. The driver should simply return ret; it should not giveback the URB.
drivers/usb/ip/vhci_hcd.c line 579
Quoted 3 lines
drivers/usb/ip/vhci_hcd.c new file +3
-0+ +/* +* The enumelation process is as follows;
It would be nice to avoid Japanese-isms in the comments.
drivers/usb/ip/vhci_hcd.c line 586
Quoted 7 lines
drivers/usb/ip/vhci_hcd.c new file +7
-0+* +* 1. Get_Descriptor request to DevAddrs(0) EndPoint(0) +* to get max packet length of default pipe +* +* 2. Set_Address request to DevAddr(0) EndPoint(0) +* +*/
Rather than deal with simulating initialization commands in difficult contexts, it would be better to change usbcore. We should recognize the existence of "virtual" USB devices which don't need address assignment or re-enumeration following reset. Then much of the following code wouldn't be needed.
Quoted 108 lines
drivers/usb/ip/vhci_hcd.c new file +108
-0+ +if (usb_pipedevice (urb->pipe) ==0 ) { +__u8 type =usb_pipetype (urb->pipe); +struct usb_ctrlrequest *ctrlreq = + (struct usb_ctrlrequest *) urb->setup_packet; +struct vhci_device *vdev = +port_to_vdev (the_controller->pending_port); + +if (type !=PIPE_CONTROL || !ctrlreq) { +dev_err (dev,"invalid request to devnum 0\n" ); + ret =EINVAL ; + goto no_need_xmit; + } + +switch (ctrlreq->bRequest) { +case USB_REQ_SET_ADDRESS : +/* set_address may come when a device is reset */ +dev_info (dev,"SetAddress Request (%d) to port %d\n" , + ctrlreq->wValue, vdev->rhport); + + vdev->udev = urb->dev; + +spin_lock (&vdev->ud.lock); + vdev->ud.status =VDEV_ST_USED ; +spin_unlock (&vdev->ud.lock); + +if (urb->status == -EINPROGRESS ) { +/* This request is successfully completed. */ +/* If not -EINPROGRESS, possibly unlinked. */ + urb->status =0 ; + } + + goto no_need_xmit; + +case USB_REQ_GET_DESCRIPTOR : +if (ctrlreq->wValue == (USB_DT_DEVICE <<8 )) +dbg_vhci_hc ("Not yet?: " +"Get_Descriptor to device 0 " +"(get max pipe size)\n" ); + +/* FIXME: reference count? (usb_get_dev()) */ + vdev->udev = urb->dev; + goto out; + +default : +/* NOT REACHED */ +dev_err (dev,"invalid request to devnum 0 bRequest %u, " +"wValue %u\n" , ctrlreq->bRequest, + ctrlreq->wValue); + ret = -EINVAL ; + goto no_need_xmit; + } + + } + +out: +vhci_tx_urb (urb); + +spin_unlock_irqrestore (&the_controller->lock, flags); + +return 0 ; + +no_need_xmit: +usb_hcd_unlink_urb_from_ep (hcd, urb); +no_need_unlink: +spin_unlock_irqrestore (&the_controller->lock, flags); + +usb_hcd_giveback_urb (vhci_to_hcd (the_controller), urb, urb->status); + +return 0 ; +} + +/* +* vhci_rx gives back the urb after receiving the reply of the urb. If an +* unlink pdu is sent or not, vhci_rx receives a normal return pdu and gives +* back its urb. For the driver unlinking the urb, the content of the urb is +* not important, but the calling to its completion handler is important; the +* completion of unlinking is notified by the completion handler. +* +* +* CLIENT SIDE +* +* - When vhci_hcd receives RET_SUBMIT, +* +* - case 1a). the urb of the pdu is not unlinking. +* - normal case +* => just give back the urb +* +* - case 1b). the urb of the pdu is unlinking. +* - usbip.ko will return a reply of the unlinking request. +* => give back the urb now and go to case 2b). +* +* - When vhci_hcd receives RET_UNLINK, +* +* - case 2a). a submit request is still pending in vhci_hcd. +* - urb was really pending in usbip.ko and urb_unlink_urb() was +* completed there. +* => free a pending submit request +* => notify unlink completeness by giving back the urb +* +* - case 2b). a submit request is *not* pending in vhci_hcd. +* - urb was already given back to the core driver. +* => do not give back the urb +* +* +* SERVER SIDE +* +* - When usbip receives CMD_UNLINK,
drivers/usb/ip/vhci_hcd.c line 704
Quoted 10 lines
drivers/usb/ip/vhci_hcd.c new file +10
-0+* +* - case 3a). the urb of the unlink request is now in submission. +* => do usb_unlink_urb(). +* => after the unlink is completed, send RET_UNLINK. +* +* - case 3b). the urb of the unlink request is not in submission. +* - may be already completed or never be received +* => send RET_UNLINK +* +*/
While I don't fully grasp these comments, they don't seem entirely right. Maybe my understanding is just weak, though.
For example, there's never any need to notify that an unlink has completed. In fact, unlinks don't complete at all -- URBs complete but unlinks don't.
Perhaps the trickiest part is what happens when you try to unlink before the submit request has been accepted by the server. This could be handled in a couple of ways: The server could refuse the submit request, or the client could send the unlink message after the submit response is received.
But I don't see why the client would ever want to call usb_hcd_giveback_urb() from within the dequeue method. Unless perhaps the URB is still on a submit queue, waiting to be sent to the server.
Quoted 8 lines
drivers/usb/ip/vhci_hcd.c new file +8
-0+static int vhci_urb_dequeue (struct usb_hcd *hcd,struct urb *urb,int status) +{ +unsigned long flags; +struct vhci_priv *priv; +struct vhci_device *vdev; + +uinfo ("vhci_hcd: dequeue a urb %p\n" , urb); +
drivers/usb/ip/vhci_hcd.c line 722
Quoted 10 lines
drivers/usb/ip/vhci_hcd.c new file +10
-0+ +spin_lock_irqsave (&the_controller->lock, flags); + + priv = urb->hcpriv; +if (!priv) { +/* URB was never linked! or will be soon given back by +* vhci_rx. */ +spin_unlock_irqrestore (&the_controller->lock, flags); +return 0 ; + }
This test shouldn't be needed; the spinlock should prevent it from ever succeeding.
drivers/usb/ip/vhci_hcd.c line 729
Quoted 7 lines
drivers/usb/ip/vhci_hcd.c new file +7
-0+ + { +int ret =0 ; + ret =usb_hcd_check_unlink_urb (hcd, urb, status); +if (ret) { +spin_unlock_irqrestore (&the_controller->lock, flags); +return 0 ;
Don't return 0, return ret.
Quoted 50 lines
drivers/usb/ip/vhci_hcd.c new file +50
-0+ } + } + +/* send unlink request here? */ + vdev = priv->vdev; + +if (!vdev->ud.tcp_socket) { +/* tcp connection is closed */ +unsigned long flags2; + +spin_lock_irqsave (&vdev->priv_lock, flags2); + +uinfo ("vhci_hcd: device %p seems to be disconnected\n" , vdev); +list_del (&priv->list); +kfree (priv); + urb->hcpriv =NULL ; + +spin_unlock_irqrestore (&vdev->priv_lock, flags2); + + }else { +/* tcp connection is alive */ +unsigned long flags2; +struct vhci_unlink *unlink; + +spin_lock_irqsave (&vdev->priv_lock, flags2); + +/* setup CMD_UNLINK pdu */ + unlink =kzalloc (sizeof (struct vhci_unlink ),GFP_ATOMIC ); +if (!unlink) { +uerr ("malloc vhci_unlink\n" ); +spin_unlock_irqrestore (&vdev->priv_lock, flags2); +spin_unlock_irqrestore (&the_controller->lock, flags); +usbip_event_add (&vdev->ud,VDEV_EVENT_ERROR_MALLOC ); +return -ENOMEM ; + } + + unlink->seqnum =atomic_inc_return (&the_controller->seqnum); +if (unlink->seqnum ==0xffff ) +uinfo ("seqnum max\n" ); + + unlink->unlink_seqnum = priv->seqnum; + +uinfo ("vhci_hcd: device %p seems to be still connected\n" , + vdev); + +/* send cmd_unlink and try to cancel the pending URB in the +* peer */ +list_add_tail (&unlink->list, &vdev->unlink_tx); +wake_up (&vdev->waitq_tx); +
drivers/usb/ip/vhci_hcd.c line 789
Quoted 10 lines
drivers/usb/ip/vhci_hcd.c new file +10
-0+spin_unlock_irqrestore (&vdev->priv_lock, flags2); + } + + +/* +* If tcp connection is alive, we have sent CMD_UNLINK. +* vhci_rx will receive RET_UNLINK and give back the URB. +* Otherwise, we give back it here. +*/ +if (!vdev->ud.tcp_socket) {
Why is this test repeated? Couldn't the code be moved up into the previous test?
Quoted 6 lines
drivers/usb/ip/vhci_hcd.c new file +6
-0+/* tcp connection is closed */ +uinfo ("vhci_hcd: vhci_urb_dequeue() gives back urb %p\n" , urb); + +usb_hcd_unlink_urb_from_ep (hcd, urb); + +spin_unlock_irqrestore (&the_controller->lock, flags);
drivers/usb/ip/vhci_hcd.c line 805
Quoted 10 lines
drivers/usb/ip/vhci_hcd.c new file +10
-0+usb_hcd_giveback_urb (vhci_to_hcd (the_controller), urb, + urb->status); +spin_lock_irqsave (&the_controller->lock, flags); + } + +spin_unlock_irqrestore (&the_controller->lock, flags); + +dbg_vhci_hc ("leave\n" ); +return 0 ; +}
WHy is there special code for unlinking URBs after the TCP connection has gone down? Shouldn't all outstanding URBs immediately complete with -ESHUTDOWN status?
Alan Stern
PATCH 3/3 USB: USB/IP: add host driver
In reply to [email protected]From: Takahiro Hirofuchi <[email protected]>
This adds the USB IP client driver
Brian Merrell cleaned up a lot of this code and submitted it for inclusion. Greg also did a lot of cleanup.
--- drivers/usb/ip/Kconfig | 10 drivers/usb/ip/Makefile | 3 drivers/usb/ip/stub.h | 95 ++++++ drivers/usb/ip/stub_dev.c | 483 +++++++++++++++++++++++++++++++++++ drivers/usb/ip/stub_main.c | 300 +++++++++++++++++++++ drivers/usb/ip/stub_rx.c | 616 +++++++++++++++++++++++++++++++++++++++++++++ drivers/usb/ip/stub_tx.c | 371 +++++++++++++++++++++++++++ 7 files changed, 1878 insertions(+)
drivers/usb/ip/Kconfig +10 -0
@@ -22,3 +22,13 @@ config USB_IP_VHCI_HCD To compile this driver as a module, choose M here: the module will be called vhci_hcd. + +config USB_IP_HOST + tristate "USB IP host driver" + depends on USB_IP_COMMON + ---help--- + This enables the USB IP device driver which will run on the + host machine. + + To compile this driver as a module, choose M here: the + module will be called usbip.
drivers/usb/ip/Makefile +3 -0
@@ -4,6 +4,9 @@ usbip_common_mod-objs := usbip_common.o obj-$(CONFIG_USB_IP_VHCI_HCD) += vhci-hcd.o vhci-hcd-objs := vhci_sysfs.o vhci_tx.o vhci_rx.o vhci_hcd.o +obj-$(CONFIG_USB_IP_HOST) += usbip.o +usbip-objs := stub_dev.o stub_main.o stub_rx.o stub_tx.o + ifeq ($(CONFIG_USB_DEBUG),y) EXTRA_CFLAGS += -DDEBUG endif
drivers/usb/ip/stub_dev.c new file +483 -0
483 lines not on this page · raw message
drivers/usb/ip/stub.h new file +95 -0
95 lines not on this page · raw message
drivers/usb/ip/stub_main.c new file +300 -0
300 lines not on this page · raw message
drivers/usb/ip/stub_rx.c new file +616 -0
616 lines not on this page · raw message
drivers/usb/ip/stub_tx.c new file +371 -0
371 lines not on this page · raw message
Re: [patch 03/03] USB: USB/IP: add host driver
Quoted 3 lines · On Thu, Aug 28, 2008 at 04:00:38PM -0700, [email protected] wrote:
From: Takahiro Hirofuchi <[email protected]>
This adds the USB IP client driver
Seems this changelog is wrong because the help says it's the host :
drivers/usb/ip/Kconfig config USB_IP_VHCI_HCD · line 34
Quoted 9 lines
drivers/usb/ip/Kconfig +9
-0+config USB_IP_HOST + tristate "USB IP host driver" + depends on USB_IP_COMMON + ---help--- + This enables the USB IP device driver which will run on the + host machine. + + To compile this driver as a module, choose M here: the + module will be called usbip.
Very cool stuff anyway !
regards,
Willy
Em Thu, Aug 28, 2008 at 04:00:16PM -0700, [email protected] escreveu:
Quoted 17 lines
Here's 3 patches that adds USB-IP functionality code to the kernel tree.
It is against 2.6.27-rc4, and has been added to the -staging tree. If there are no major objections, I'll also queue it up in the usb tree for submission into 2.6.28.
The code is based on Takahiro's great work that has been sitting outside of the kernel for many many years now. Brian Merrell took the most recent version of the code, cleaned it up and sent it to me. I did more cleanup and split the patch into 3 pieces, making it a bit easier to work with.
There are still a number of checkpatch.pl warnings/errors emitted, and Brian said he would work on them in the upcoming weeks, but they don't distract from the basic functionality and a good review would be nice to have.
Quoted 5 lines
We do need some more documentation for how to use this code (you need the tools at usbip.sf.net), and how the sysfs files are exporting data to userspace. Brian, can you write up the sysfs interface in the format that
Documentation/ABI/details and also provide some kind of basic HOWTO to include in the kernel source tree?
Great stuff, I almost worked on udp_hcd or something along these lines, will definetely take a look! :-)
- Arnaldo
Quoted 12 lines · On Thu, Aug 28, 2008 at 04:00:16PM -0700, [email protected] wrote:
Here's 3 patches that adds USB-IP functionality code to the kernel tree.
It is against 2.6.27-rc4, and has been added to the -staging tree. If there are no major objections, I'll also queue it up in the usb tree for submission into 2.6.28.
The code is based on Takahiro's great work that has been sitting outside of the kernel for many many years now. Brian Merrell took the most recent version of the code, cleaned it up and sent it to me. I did more cleanup and split the patch into 3 pieces, making it a bit easier to work with.
Quoted 4 lines
There are still a number of checkpatch.pl warnings/errors emitted, and Brian said he would work on them in the upcoming weeks, but they don't distract from the basic functionality and a good review would be nice to have.
I will indeed continue to work on getting rid of the checkpatch.pl warnings/errors during the upcoming weeks. I already eliminated the ones I could figure out without too much effort; I am sure the remaining ones are trivial to many of you out there, so I welcome any suggestions.
Quoted 6 lines
We do need some more documentation for how to use this code (you need the tools at usbip.sf.net), and how the sysfs files are exporting data to userspace. Brian, can you write up the sysfs interface in the format that
Documentation/ABI/details and also provide some kind of basic HOWTO to include in the kernel source tree?
Yes, I would be happy to work on this.
Quoted 4 lines
thanks,
greg k-h
Thanks,
Brian G. Merrell
Quoted 18 lines · Brian G. Merrell
Quoted 12 lines · On Thu, Aug 28, 2008 at 04:00:16PM -0700, [email protected] wrote:
Here's 3 patches that adds USB-IP functionality code to the kernel tree.
It is against 2.6.27-rc4, and has been added to the -staging tree. If there are no major objections, I'll also queue it up in the usb tree for submission into 2.6.28.
The code is based on Takahiro's great work that has been sitting outside of the kernel for many many years now. Brian Merrell took the most recent version of the code, cleaned it up and sent it to me. I did more cleanup and split the patch into 3 pieces, making it a bit easier to work with.
Quoted 4 lines
There are still a number of checkpatch.pl warnings/errors emitted, and Brian said he would work on them in the upcoming weeks, but they don't distract from the basic functionality and a good review would be nice to have.
Quoted 5 lines
I will indeed continue to work on getting rid of the checkpatch.pl warnings/errors during the upcoming weeks. I already eliminated the ones I could figure out without too much effort; I am sure the remaining ones are trivial to many of you out there, so I welcome any suggestions.
The kthread one looks like you will have to change a bit of the code, all of the other remaining ones should be self-explanatory. If not, please let us know and we'll be glad to help out.
Can you also work to address all of the review comments made on the code so far as well? I don't know how much time you have to work on this, but for now I'll let you send me changes and not do anything on the code myself. Sound good?
thanks,
greg k-h
Quoted 25 lines · Greg KH
Quoted 18 lines · Brian G. Merrell
Quoted 12 lines · On Thu, Aug 28, 2008 at 04:00:16PM -0700, [email protected] wrote:
Here's 3 patches that adds USB-IP functionality code to the kernel tree.
It is against 2.6.27-rc4, and has been added to the -staging tree. If there are no major objections, I'll also queue it up in the usb tree for submission into 2.6.28.
The code is based on Takahiro's great work that has been sitting outside of the kernel for many many years now. Brian Merrell took the most recent version of the code, cleaned it up and sent it to me. I did more cleanup and split the patch into 3 pieces, making it a bit easier to work with.
Quoted 4 lines
There are still a number of checkpatch.pl warnings/errors emitted, and Brian said he would work on them in the upcoming weeks, but they don't distract from the basic functionality and a good review would be nice to have.
Quoted 5 lines
I will indeed continue to work on getting rid of the checkpatch.pl warnings/errors during the upcoming weeks. I already eliminated the ones I could figure out without too much effort; I am sure the remaining ones are trivial to many of you out there, so I welcome any suggestions.
Quoted 8 lines
The kthread one looks like you will have to change a bit of the code, all of the other remaining ones should be self-explanatory. If not, please let us know and we'll be glad to help out.
Can you also work to address all of the review comments made on the code so far as well? I don't know how much time you have to work on this, but for now I'll let you send me changes and not do anything on the code myself. Sound good?
Well, now that school is back in session I haven't had a lot of time to look at this. I was really hoping to make time but it just hasn't happened. I finish my degree in December, but until then it doesn't look like I will have a lot of time to look at this. I still want to contribute what I can, but I don't want to hold things up. So please don't not make changes on my account. Sorry.
Thanks,
Brian G. Merrell