On Sun, Mar 21, David Brownell wrote:

> Olaf Hering wrote:
> >
> >the mouse will not disappear from /proc/bus/usb/devices, even if I
> >unplug the mouse. Same for the keyspan device, it seems the ports are
> >dead for some reason.
> 
> Sounds more like "khubd" is wedged.  It's annoying, but that's
> a single-point-of-failure for the entire USB stack.  Alt-SysRq-t
> is often informative at such times.

Please revert of improve the attached patch. It is the culprit.


-- 
USB is for mice, FireWire is for men!

sUse lINUX ag, nÃRNBERG
Return-Path: <[EMAIL PROTECTED]>
Received: from hermes.suse.de (hermes.suse.de [10.0.0.1])
        by wotan.suse.de (Postfix) with ESMTP id 7E7BA6D1B
        for <[EMAIL PROTECTED]>; Wed, 17 Mar 2004 06:46:06 +0100 (CET)
Received: by hermes.suse.de (Postfix)
        id 799D98C50; Wed, 17 Mar 2004 06:46:06 +0100 (CET)
Received: from mandarine.suse.de (mandarine.suse.de [10.10.3.21])
        by hermes.suse.de (Postfix) with ESMTP
        id 6C4B13F25; Wed, 17 Mar 2004 06:46:06 +0100 (CET)
Received: by mandarine.suse.de (Postfix, from userid 90)
        id 4B575468E5; Wed, 17 Mar 2004 06:46:06 +0100 (CET)
To: [EMAIL PROTECTED], [EMAIL PROTECTED]
Subject: Incoming changes to linux-2.5 cset 1.1608.24.34  
mandarine.suse.de:/olaf/sources/tree/linux-2.5 
Message-Id: <[EMAIL PROTECTED]>
Date: Wed, 17 Mar 2004 06:46:06 +0100 (CET)
From: [EMAIL PROTECTED] (Olaf Hering)
X-Spam-Checker-Version: SpamAssassin 2.63 (2004-01-11) on wotan.suse.de
X-Spam-Level: 
X-Spam-Status: No, hits=-4.8 required=5.0 tests=AWL,BAYES_00 autolearn=ham 
        version=2.63
Content-Length: 12130

old status OK
ChangeSet
  1.1608.24.34 04/03/03 11:16:57 [EMAIL PROTECTED] +3 -0
  [PATCH] USB: Don't add/del interfaces, register/unregister them
  
  On Fri, 27 Feb 2004, Greg KH wrote:
  
  > On Wed, Feb 25, 2004 at 10:05:37AM -0500, Alan Stern wrote:
  >
  > > Why would anyone want to do this, you ask?  Well the USB subsystem does it
  > > already.  Each USB device can have several configurations, only one of
  > > which is active at any time.  Corresponding to each configuration is a set
  > > of struct devices, and they (together with their embedded kobjects) are
  > > allocated and initialized when the USB device is first detected.  The
  > > struct devices are add()'ed and del()'ed as configurations are activated
  > > and deactivated, leading to just the sort of call sequence shown above.
  >
  > Then we need to fix this.
  
  The driver model does not support repeated device_add(), device_del(),
  device_add(), device_del(), ... calls for the same device.  But that's
  what happens to an interface's embedded struct device when we change
  configurations.
  
  Accordingly, this patch changes the device_add()/device_del() calls for
  interfaces to device_register()/device_unregister().  When the interface
  is unregistered the new code waits for the release method to run, so that
  it will be safe to re-register the interface should the former
  configuration be reinstated.
  
  Greg, please check this out to make sure I haven't made some dumb mistake.
  It works on my system and it fixes a memory leak in the USB system.

  include/linux/usb.h
    1.96 04/02/27 08:46:19 [EMAIL PROTECTED] +3 -0
    USB: Don't add/del interfaces, register/unregister them

  drivers/usb/core/message.c
    1.42 04/02/27 08:46:19 [EMAIL PROTECTED] +14 -2
    USB: Don't add/del interfaces, register/unregister them

  drivers/usb/core/config.c
    1.17 04/02/27 08:46:19 [EMAIL PROTECTED] +2 -7
    USB: Don't add/del interfaces, register/unregister them

.........................................................................
# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#                  ChangeSet    1.1608.24.33 -> 1.1608.24.34
#       drivers/usb/core/config.c       1.16    -> 1.17   
#       drivers/usb/core/message.c      1.41    -> 1.42   
#        include/linux/usb.h    1.95    -> 1.96   
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 04/03/03      [EMAIL PROTECTED]       1.1608.58.1
# Merge nuts.davemloft.net:/disk1/BK/sparcwork-2.6
# into nuts.davemloft.net:/disk1/BK/sparc-2.6
# --------------------------------------------
# 04/03/03      [EMAIL PROTECTED]       1.1608.58.2
# [SPARC64]: Update defconfig.
# --------------------------------------------
# 04/03/03      [EMAIL PROTECTED]       1.1608.59.1
# [PATCH] parport: move exports to where they are defined
# 
#       Exports moved from parport/init.c to files where functions are
# actually defined.
# --------------------------------------------
# 04/03/03      [EMAIL PROTECTED]       1.1608.59.2
# [PATCH] parport: use module_init()
# 
#       Init of low-level drivers (except parport_pc) turned into module_init().
# --------------------------------------------
# 04/03/03      [EMAIL PROTECTED]       1.1608.59.3
# [PATCH] parport: sysctl registration
# 
#       Registration of sysctls turned into module_init().
# --------------------------------------------
# 04/03/03      [EMAIL PROTECTED]       1.1608.59.4
# [PATCH] parport: option parsing cleanup
# 
#       parport_pc options parsing moved to parport_pc.c; parport/init.c is
# gone.
#       Warning fixes from -mm added.
# --------------------------------------------
# 04/03/03      [EMAIL PROTECTED]       1.1608.59.5
# [PATCH] parport: fix probe leaks
# 
#       parport_pc_probe_port() sanitized; leaks fixed.
# --------------------------------------------
# 04/03/03      [EMAIL PROTECTED]       1.1608.59.6
# [PATCH] parport: slave port cleanups
# 
#       references to slave ports of mux added to struct parport.
# parport_daisy_init() doesn't go through parport_announce_port() for mux
# slaves anymore; parport_annouce_port() deals with found ones itself.
# Error handling sanitized, races on unregistration fixed.
# --------------------------------------------
# 04/03/03      [EMAIL PROTECTED]       1.1608.59.7
# [PATCH] parport: fix parport_unregister_port
# 
#       parport_unregister_port() is split; parport_remove_port() does
# what parport_unregister_port() used to do sans the final parport_put_port()
# call.
#       Callers updated; many of them needed only parport_put_port() (failure
# exit paths where we never had the port announced to drivers).
#       Fixed multiple races on port removal by shifting parport_remove_port()
# in front of the code that releases irq/io ports/etc.
# --------------------------------------------
# 04/03/03      [EMAIL PROTECTED]       1.1608.59.8
# [PATCH] parport: clean up parport_announce_port and friends
# 
#       parport_announce_port() was always called right after
# parport_proc_register().  Call shifted into parport_announce_port().
# Similar for parport_remove_port() and parport_proc_unregister().
# --------------------------------------------
# 04/03/03      [EMAIL PROTECTED]       1.1608.59.9
# [PATCH] parport: keep track of parport_pc ports
# 
#       parport_pc switched to keeping track of the ports it had
# created; in module_exit it uses the private list instead of messing
# with parport_enumerate().
#       Added compile fix for configs that have CONFIG_PARPORT_PC_FIFO turned
# off (from -mm).
# --------------------------------------------
# 04/03/03      [EMAIL PROTECTED]       1.1608.59.10
# [PATCH] parport: keep track of parport_sunbpp ports
# 
#       parport_sunbpp switched to keeping track of the ports it had
# created; in module_exit it uses the private list instead of messing
# with parport_enumerate().  Added check for sbus_ioremap() failure in
# port initialization.
# --------------------------------------------
# 04/03/03      [EMAIL PROTECTED]       1.1608.59.11
# [PATCH] parport: get rid of parport_enumerate
# 
#       parport_enumerate() is gone.  The last caller was under ifdef that
# never had been true.  Function itself is removed, port list handling
# cleaned up (now we can do that, since drivers don't mess with the list
# directly), tons of racy crap removed from parport/share.c
# --------------------------------------------
# 04/03/03      [EMAIL PROTECTED]       1.1608.59.12
# [PATCH] parport: list cleanups
# 
#       parport driver list turned into list.h one; parport/share.c code that
# works with that list got cleaned up.
# --------------------------------------------
# 04/03/03      [EMAIL PROTECTED]       1.1608.1.24
# Merge bk://gkernel.bkbits.net/libata-2.5
# into ppc970.osdl.org:/home/torvalds/v2.5/linux
# --------------------------------------------
# 04/03/03      [EMAIL PROTECTED]       1.1608.24.34
# [PATCH] USB: Don't add/del interfaces, register/unregister them
# 
# On Fri, 27 Feb 2004, Greg KH wrote:
# 
# > On Wed, Feb 25, 2004 at 10:05:37AM -0500, Alan Stern wrote:
# >
# > > Why would anyone want to do this, you ask?  Well the USB subsystem does it
# > > already.  Each USB device can have several configurations, only one of
# > > which is active at any time.  Corresponding to each configuration is a set
# > > of struct devices, and they (together with their embedded kobjects) are
# > > allocated and initialized when the USB device is first detected.  The
# > > struct devices are add()'ed and del()'ed as configurations are activated
# > > and deactivated, leading to just the sort of call sequence shown above.
# >
# > Then we need to fix this.
# 
# The driver model does not support repeated device_add(), device_del(),
# device_add(), device_del(), ... calls for the same device.  But that's
# what happens to an interface's embedded struct device when we change
# configurations.
# 
# Accordingly, this patch changes the device_add()/device_del() calls for
# interfaces to device_register()/device_unregister().  When the interface
# is unregistered the new code waits for the release method to run, so that
# it will be safe to re-register the interface should the former
# configuration be reinstated.
# 
# Greg, please check this out to make sure I haven't made some dumb mistake.
# It works on my system and it fixes a memory leak in the USB system.
# --------------------------------------------
#
diff -Nru a/drivers/usb/core/config.c b/drivers/usb/core/config.c
--- a/drivers/usb/core/config.c Wed Mar 17 06:46:04 2004
+++ b/drivers/usb/core/config.c Wed Mar 17 06:46:04 2004
@@ -72,13 +72,10 @@
        return buffer - buffer0;
 }
 
-static void usb_release_intf(struct device *dev)
+static void usb_free_intf(struct usb_interface *intf)
 {
-       struct usb_interface *intf;
        int j;
 
-       intf = to_usb_interface(dev);
-
        if (intf->altsetting) {
                for (j = 0; j < intf->num_altsetting; j++) {
                        struct usb_host_interface *as = &intf->altsetting[j];
@@ -235,8 +232,6 @@
                        return -ENOMEM;
                }
                memset(interface, 0, sizeof(struct usb_interface));
-               interface->dev.release = usb_release_intf;
-               device_initialize(&interface->dev);
        }
 
        /* Go through the descriptors, checking their length and counting the
@@ -374,7 +369,7 @@
                        struct usb_interface *ifp = cf->interface[i];
 
                        if (ifp)
-                               put_device(&ifp->dev);
+                               usb_free_intf(ifp);
                }
        }
        kfree(dev->config);
diff -Nru a/drivers/usb/core/message.c b/drivers/usb/core/message.c
--- a/drivers/usb/core/message.c        Wed Mar 17 06:46:04 2004
+++ b/drivers/usb/core/message.c        Wed Mar 17 06:46:04 2004
@@ -793,6 +793,13 @@
        }
 }
 
+static void release_interface(struct device *dev)
+{
+       struct usb_interface *interface = to_usb_interface(dev);
+
+       complete(interface->released);
+}
+
 /*
  * usb_disable_device - Disable all the endpoints for a USB device
  * @dev: the device whose endpoints are being disabled
@@ -822,12 +829,16 @@
        if (dev->actconfig) {
                for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
                        struct usb_interface    *interface;
+                       struct completion       intf_completion;
 
                        /* remove this interface */
                        interface = dev->actconfig->interface[i];
                        dev_dbg (&dev->dev, "unregistering interface %s\n",
                                interface->dev.bus_id);
-                       device_del(&interface->dev);
+                       init_completion (&intf_completion);
+                       interface->released = &intf_completion;
+                       device_unregister (&interface->dev);
+                       wait_for_completion (&intf_completion);
                }
                dev->actconfig = 0;
                if (dev->state == USB_STATE_CONFIGURED)
@@ -1145,6 +1156,7 @@
                        intf->dev.driver = NULL;
                        intf->dev.bus = &usb_bus_type;
                        intf->dev.dma_mask = dev->dev.dma_mask;
+                       intf->dev.release = release_interface;
                        sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d",
                                 dev->bus->busnum, dev->devpath,
                                 configuration,
@@ -1153,7 +1165,7 @@
                                "registering %s (config #%d, interface %d)\n",
                                intf->dev.bus_id, configuration,
                                desc->bInterfaceNumber);
-                       device_add (&intf->dev);
+                       device_register (&intf->dev);
                        usb_create_driverfs_intf_files (intf);
                }
        }
diff -Nru a/include/linux/usb.h b/include/linux/usb.h
--- a/include/linux/usb.h       Wed Mar 17 06:46:04 2004
+++ b/include/linux/usb.h       Wed Mar 17 06:46:04 2004
@@ -89,6 +89,8 @@
  *     number from the USB core by calling usb_register_dev().
  * @dev: driver model's view of this device
  * @class_dev: driver model's class view of this device.
+ * @released: wait for the interface to be released when changing
+ *     configurations.
  *
  * USB device drivers attach to interfaces on a physical device.  Each
  * interface encapsulates a single high level function, such as feeding
@@ -122,6 +124,7 @@
        int minor;                      /* minor number this interface is bound to */
        struct device dev;              /* interface specific device info */
        struct class_device *class_dev;
+       struct completion *released;    /* wait for release */
 };
 #define        to_usb_interface(d) container_of(d, struct usb_interface, dev)
 #define        interface_to_usbdev(intf) \
.........................................................................
# vim: syntax=diff

Reply via email to