Re: BUG in: Driver core: convert block from raw kobjects to coredevices

From: Alan Stern
Date: Sat Oct 20 2007 - 21:34:17 EST


On Sat, 20 Oct 2007, Kay Sievers wrote:

> Here is what I see, the error handler hangs without the final put and
> the kobject never gets cleaned up. Note the missing:
> kobject sdb: cleaning up
>
> What is your CONFIG_SYSFS_DEPRECATED option? I have it unset, and that
> may be the difference in the behavior if you have it set.

It's unset in my config also. No, the difference lies somewhere else.
The plug-in parts are the same, but we differ in the remove parts. On
your system, unlink_gendisk ends up dropping only one reference instead
of two. This suggests that something strange is happening to the
request_queue on your machine.

Can you try running the attached patch (without the previous patch)?
It traces the various release routines. The idea is that both the
scsi_disk and the scsi_device hold references to the request_queue,
and these references get dropped in their respective release routines.

Just for the record, here's what happens with this patch on my system,
without the put_device call in del_gendisk (the patch comments it out).
I plugged in a USB drive and let things settle down. Then unplugging
the drive gave this:

[ 457.916995] usb 6-4: USB disconnect, address 3
[ 457.918459] usb 6-4: unregistering device
[ 457.920570] usb 6-4: usb_disable_device nuking all URBs
[ 457.920859] usb 6-4: unregistering interface 6-4:1.0
[ 457.958990] disk_release: kobj cedcda50

The line above refers to the /dev/sda1 partition. Ignore it.

[ 458.012317] del_gendisk sda, kobj ce8be990, queue cd9b2000, refcount before put_device 2

2 references: one from the scsi_disk and one from the request_queue.

[ 458.013133] scsi_disk_release: disk sda, kobj ce8be990, refcount before put_disk 2
[ 458.032420] scsi_device_dev_release: rq cd9b2000

These lines show where the two references to the request_queue get
dropped. As a result the queue is released, causing the gendisk to be
released as well:

[ 458.032766] blk_release_queue: rq cd9b2000, parent ce8be990
[ 458.032973] disk_release: kobj ce8be990
[ 458.051641] usb 6-4:1.0: uevent
[ 458.052001] usb 6-4:1.0: uevent
[ 458.068665] usb 6-4: uevent

If you don't get a similar sequence of events, it must indicate that
something on your system continues to hold an outstanding reference.
Maybe an automounter program, or something like that.

Alan Stern
Index: 2.6.23/block/genhd.c
===================================================================
--- 2.6.23.orig/block/genhd.c
+++ 2.6.23/block/genhd.c
@@ -496,6 +496,7 @@ static void disk_release(struct device *
{
struct gendisk *disk = dev_to_disk(dev);

+ printk(KERN_INFO "disk_release: kobj %p\n", &disk->dev.kobj);
kfree(disk->random);
kfree(disk->part);
free_disk_stats(disk);
Index: 2.6.23/block/ll_rw_blk.c
===================================================================
--- 2.6.23.orig/block/ll_rw_blk.c
+++ 2.6.23/block/ll_rw_blk.c
@@ -1781,6 +1781,8 @@ static void blk_release_queue(struct kob
container_of(kobj, struct request_queue, kobj);
struct request_list *rl = &q->rq;

+ printk(KERN_INFO "blk_release_queue: rq %p, parent %p\n",
+ q, q->kobj.parent);
blk_sync_queue(q);

if (rl->rq_pool)
Index: 2.6.23/drivers/scsi/scsi_sysfs.c
===================================================================
--- 2.6.23.orig/drivers/scsi/scsi_sysfs.c
+++ 2.6.23/drivers/scsi/scsi_sysfs.c
@@ -238,6 +238,8 @@ static void scsi_device_dev_release_user
list_del(&sdev->starved_entry);
spin_unlock_irqrestore(sdev->host->host_lock, flags);

+ printk(KERN_INFO "scsi_device_dev_release: rq %p\n",
+ sdev->request_queue);
if (sdev->request_queue) {
sdev->request_queue->queuedata = NULL;
/* user context needed to free queue */
Index: 2.6.23/fs/partitions/check.c
===================================================================
--- 2.6.23.orig/fs/partitions/check.c
+++ 2.6.23/fs/partitions/check.c
@@ -516,5 +516,9 @@ void del_gendisk(struct gendisk *disk)
sysfs_remove_link(&block_depr, disk->dev.bus_id);
#endif
device_del(&disk->dev);
- put_device(&disk->dev);
+ printk(KERN_INFO "del_gendisk %s, kobj %p, queue %p, "
+ "refcount before put_device %d\n",
+ disk->dev.bus_id, &disk->dev.kobj, disk->queue,
+ atomic_read(&disk->dev.kobj.kref.refcount));
+// put_device(&disk->dev);
}
Index: 2.6.23/drivers/scsi/sd.c
===================================================================
--- 2.6.23.orig/drivers/scsi/sd.c
+++ 2.6.23/drivers/scsi/sd.c
@@ -1738,6 +1738,10 @@ static void scsi_disk_release(struct cla
spin_unlock(&sd_index_lock);

disk->private_data = NULL;
+ printk(KERN_INFO "scsi_disk_release: disk %s, kobj %p, "
+ "refcount before put_disk %d\n",
+ disk->dev.bus_id, &disk->dev.kobj,
+ atomic_read(&disk->dev.kobj.kref.refcount));
put_disk(disk);
put_device(&sdkp->device->sdev_gendev);