| From zaitcev@redhat.com Wed May 3 00:16:11 2006 |
| Date: Wed, 3 May 2006 00:16:00 -0700 |
| From: Pete Zaitcev <zaitcev@redhat.com> |
| To: greg@kroah.com |
| Cc: zaitcev@redhat.com, linux-usb-devel@lists.sourceforge.net |
| Subject: USB: ub oops in block_uevent |
| Message-Id: <20060503001600.c9012512.zaitcev@redhat.com> |
| |
| 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 <zaitcev@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| Signed-off-by: Chris Wright <chrisw@sous-sol.org> |
| |
| --- |
| drivers/block/ub.c | 18 ++++++++++-------- |
| 1 file changed, 10 insertions(+), 8 deletions(-) |
| |
| --- linux-2.6.16.16.orig/drivers/block/ub.c |
| +++ linux-2.6.16.16/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 |
| // 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 |
| 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_int |
| */ |
| |
| 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); |
| } |
| |