hotplug remove vs. device driver close

linas at austin.ibm.com linas at austin.ibm.com
Fri Jun 4 08:25:03 EST 2004


Greg,

My apologies, I think I needed to read the source before posting to the
mailing list.  (yes, my middle name really is 'Luke', no kidding). I might have
been on a wild goose chase.  See below.

On Thu, Jun 03, 2004 at 01:02:27PM -0700, Don Fry wrote:
> > >
> > > The pcnet32 driver tries to do the 'right thing' when it reads 0xffff,
> > > but that does not include doing a 'close' prior to being removed.  The
> > > driver could keep some state around so that if its remove routine was
> > > called without close first, it would cleanup, but I don't know of any
> > > network driver that does this.
> >
> > What I get out of this thread is that pcnet32, and in fact, all drivers,
> > should keep sufficient state around so that close() can be called either
> > after or before remove().
>
> Today in 2.6.6 if I try and do a rmmod pcnet32 and something is still using
> the device, the rmmod will wait until the device is closed, and then it
> goes away.

Where?  pcnet32_cleanup_module() doesn't seem to wait for anything.

However, I'm reading the source, tracing through a power-off, and I don't
see any device driver memory leaks, at least not in the 'typical' pcnet32
driver.  What I do see is that the the device driver close() routine is
called before the device driver memory is released.

Anatomy of a device remove,
---------------------------
starting with an

echo 1 > /sysfs/bus/ .. power file ...

I trace this through the ppc64 rpaphp hotplug code, and the pcnet32 code.
I did this manually, I hope there aren't any mistakes.

power_write_file () // in /drivers/pci/hotplug/pci_hotplug_core.c
{
  calls
  slot->ops->disable_slot() which is just
  struct hotplug_slot_ops ->disable_slot() which is just
  disable_slot (struct hotplug_slot *) // in /drivers/pci/hotplug/rpaphp_core.c
  {
    which calls
    rpa_php_unconfig_pci_adapter (struct slot *)  // in rpaphp_pci.c
    {
      calls
      pci_remove_bus_device (struct pci_dev *) // in /drivers/pci/remove.c
      {
        calls
        pci_destroy_dev (struct pci_dev *)
        {
          calls
          device_unregister (&dev->dev) // in /drivers/base/core.c
          {
            calls
            device_del (struct device *)
            {
              calls
              bus_remove_device() // in /drivers/base/bus.c
              {
                calls
                device_release_driver()
                {
                  calls
                  struct device_driver->remove() which is just
                  pci_device_remove()  // in /drivers/pci/pci_driver.c
                  {
                    calls
                    struct pci_driver->remove() which is just
                    pcnet32_remove_one() // in /drivers/net/pcnet32.c
                    {
                      calls
                      unregister_netdev() // in /net/core/dev.c
                      {
                        calls
                        dev_close()  // in /net/core/dev.c
                        {
                           calls dev->stop();
                           which is just pcnet32_close() // in pcnet32.c
                           {
                             which does what you wanted
                             to stop the device
                           }
                        }
                     }
                   which
                   frees pcnet32 device driver memory
                }
     }}}}}}


** Sent via the linuxppc64-dev mail list. See http://lists.linuxppc.org/





More information about the Linuxppc64-dev mailing list