From: Pete Zaitcev Date: Wed, 3 May 2006 07:16:00 +0000 (-0700) Subject: [PATCH] USB: ub oops in block_uevent X-Git-Tag: v2.6.16.28-rc1~84 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=572ae685ec6f034eedf34e9dc90fa8d904bcfc32;p=karo-tx-linux.git [PATCH] USB: ub oops in block_uevent In kernel 2.6.16, if a mounted storage device is removed, an oops happens because ub supplies an interface device (and kobject) to the block layer, but neglects to pin it. And apparently, the block layer expects its users to pin device structures. The code in ub was broken this way for years. But the bug was exposed only by 2.6.16 when it started to call block_uevent on close, which traverses device structures (kobjects actually). Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman Signed-off-by: Chris Wright --- diff --git a/drivers/block/ub.c b/drivers/block/ub.c index f04d864770ad..a9485e520372 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -704,6 +704,9 @@ static void ub_cleanup(struct ub_dev *sc) kfree(lun); } + usb_set_intfdata(sc->intf, NULL); + usb_put_intf(sc->intf); + usb_put_dev(sc->dev); kfree(sc); } @@ -2428,7 +2431,12 @@ static int ub_probe(struct usb_interface *intf, // sc->ifnum = intf->cur_altsetting->desc.bInterfaceNumber; usb_set_intfdata(intf, sc); usb_get_dev(sc->dev); - // usb_get_intf(sc->intf); /* Do we need this? */ + /* + * Since we give the interface struct to the block level through + * disk->driverfs_dev, we have to pin it. Otherwise, block_uevent + * oopses on close after a disconnect (kernels 2.6.16 and up). + */ + usb_get_intf(sc->intf); snprintf(sc->name, 12, DRV_NAME "(%d.%d)", sc->dev->bus->busnum, sc->dev->devnum); @@ -2509,7 +2517,7 @@ static int ub_probe(struct usb_interface *intf, err_diag: err_dev_desc: usb_set_intfdata(intf, NULL); - // usb_put_intf(sc->intf); + usb_put_intf(sc->intf); usb_put_dev(sc->dev); kfree(sc); err_core: @@ -2688,12 +2696,6 @@ static void ub_disconnect(struct usb_interface *intf) */ device_remove_file(&sc->intf->dev, &dev_attr_diag); - usb_set_intfdata(intf, NULL); - // usb_put_intf(sc->intf); - sc->intf = NULL; - usb_put_dev(sc->dev); - sc->dev = NULL; - ub_put(sc); }