Commit 2b5bebccd282f2527d17ac90cf3ad0d486dd89d8

Authored by Joe Lawrence
Committed by James Bottomley
1 parent 95c9f4d4da

[SCSI] st: Take additional queue ref in st_probe

This patch fixes a reference count bug in the SCSI tape driver which can be
reproduced with the following:

* Boot with slub_debug=FZPU, tape drive attached
* echo 1 > /sys/devices/... tape device pci path .../remove
* Wait for device removal
* echo 1 > /sys/kernel/slab/blkdev_queue/validate
* Slub debug complains about corrupted poison pattern

In commit 523e1d39 (block: make gendisk hold a reference to its queue)
add_disk() and disk_release() were modified to get/put an additional
reference on a disk queue to fix a reference counting discrepency
between bdev release and SCSI device removal.  The ST driver never
calls add_disk(), so this commit introduced an extra kref put when the
ST driver frees its struct gendisk.

Attempts were made to fix this bug at the block level [1] but later
abandoned due to floppy driver issues [2].

[1] https://lkml.org/lkml/2012/8/27/354
[2] https://lkml.org/lkml/2012/9/22/113

Signed-off-by: Joe Lawrence <joe.lawrence@stratus.com>
Tested-by: Ewan D. Milne <emilne@redhat.com>
Acked-by: Kai Mäkisara <Kai.Makisara@kolumbus.fi>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>

Showing 1 changed file with 7 additions and 1 deletions Side-by-side Diff

... ... @@ -4112,6 +4112,10 @@
4112 4112 tpnt->disk = disk;
4113 4113 disk->private_data = &tpnt->driver;
4114 4114 disk->queue = SDp->request_queue;
  4115 + /* SCSI tape doesn't register this gendisk via add_disk(). Manually
  4116 + * take queue reference that release_disk() expects. */
  4117 + if (!blk_get_queue(disk->queue))
  4118 + goto out_put_disk;
4115 4119 tpnt->driver = &st_template;
4116 4120  
4117 4121 tpnt->device = SDp;
... ... @@ -4185,7 +4189,7 @@
4185 4189 idr_preload_end();
4186 4190 if (error < 0) {
4187 4191 pr_warn("st: idr allocation failed: %d\n", error);
4188   - goto out_put_disk;
  4192 + goto out_put_queue;
4189 4193 }
4190 4194 tpnt->index = error;
4191 4195 sprintf(disk->disk_name, "st%d", tpnt->index);
... ... @@ -4211,6 +4215,8 @@
4211 4215 spin_lock(&st_index_lock);
4212 4216 idr_remove(&st_index_idr, tpnt->index);
4213 4217 spin_unlock(&st_index_lock);
  4218 +out_put_queue:
  4219 + blk_put_queue(disk->queue);
4214 4220 out_put_disk:
4215 4221 put_disk(disk);
4216 4222 kfree(tpnt);