Diff below fixes two non trivial memory leaks related to closing usbd
pipes.

The first one is related to the wrongly designed refcounting for these
pipes.  The usbd_pipe structure includes a reference counter which is
always set to one when initialized but never incremented.  Useful?

Then when a driver calls usbd_close_pipe(), it starts by decrementing
this value then check for pending requests.  In this case if the driver
forgot to call usbd_abort_pipe() (go check your code!) the abort stop
here.  But now the reference counter is 0 and the pipe will never be
freed in case you properly check for error condition in your driver!

The second one is related to the fact that some of the drivers in-tree
assume the call to usbd_close_pipe() cannot fail, even if they don't
call usbd_abort_pipe() previously! In this case the function returns
without closing nor freeing the pipe.

So the diff below remove the reference counter from the usbd_pipe
structure and abort the pipe if some request are pending when we
try to close it.  Because generally we close a pipe when detaching 
a USB device and we don't care about pending transfers.  

Then we can clean all the code checking for errors that never
happen when calling usbd_abort_pipe() and simply call usbd_close_pipe()
instead of abort + close.

ok?

Index: usb_subr.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/usb_subr.c,v
retrieving revision 1.91
diff -u -p -r1.91 usb_subr.c
--- usb_subr.c  8 Aug 2013 09:44:22 -0000       1.91
+++ usb_subr.c  10 Aug 2013 08:18:18 -0000
@@ -803,7 +803,6 @@ usbd_setup_pipe(struct usbd_device *dev,
        p->iface = iface;
        p->endpoint = ep;
        ep->refcnt++;
-       p->refcnt = 1;
        p->intrxfer = 0;
        p->running = 0;
        p->aborting = 0;
Index: usbdi.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/usbdi.c,v
retrieving revision 1.56
diff -u -p -r1.56 usbdi.c
--- usbdi.c     8 Aug 2013 09:37:02 -0000       1.56
+++ usbdi.c     10 Aug 2013 10:01:54 -0000
@@ -273,10 +273,9 @@ usbd_close_pipe(struct usbd_pipe *pipe)
        }
 #endif
 
-       if (--pipe->refcnt != 0)
-               return (USBD_NORMAL_COMPLETION);
-       if (! SIMPLEQ_EMPTY(&pipe->queue))
-               return (USBD_PENDING_REQUESTS);
+       if (!SIMPLEQ_EMPTY(&pipe->queue))
+               usbd_abort_pipe(pipe);
+
        /* Default pipes are never linked */
        if (pipe->iface != NULL)
                LIST_REMOVE(pipe, next);
Index: usbdivar.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/usbdivar.h,v
retrieving revision 1.50
diff -u -p -r1.50 usbdivar.h
--- usbdivar.h  8 Aug 2013 09:44:22 -0000       1.50
+++ usbdivar.h  10 Aug 2013 08:17:05 -0000
@@ -159,7 +159,6 @@ struct usbd_pipe {
        struct usbd_interface  *iface;
        struct usbd_device     *device;
        struct usbd_endpoint   *endpoint;
-       int                     refcnt;
        char                    running;
        char                    aborting;
        SIMPLEQ_HEAD(, usbd_xfer) queue;

Reply via email to