[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>
			
			
This commit is contained in:
		
							parent
							
								
									95c9f4d4da
								
							
						
					
					
						commit
						2b5bebccd2
					
				| @ -4112,6 +4112,10 @@ static int st_probe(struct device *dev) | ||||
| 	tpnt->disk = disk; | ||||
| 	disk->private_data = &tpnt->driver; | ||||
| 	disk->queue = SDp->request_queue; | ||||
| 	/* SCSI tape doesn't register this gendisk via add_disk().  Manually
 | ||||
| 	 * take queue reference that release_disk() expects. */ | ||||
| 	if (!blk_get_queue(disk->queue)) | ||||
| 		goto out_put_disk; | ||||
| 	tpnt->driver = &st_template; | ||||
| 
 | ||||
| 	tpnt->device = SDp; | ||||
| @ -4185,7 +4189,7 @@ static int st_probe(struct device *dev) | ||||
| 	idr_preload_end(); | ||||
| 	if (error < 0) { | ||||
| 		pr_warn("st: idr allocation failed: %d\n", error); | ||||
| 		goto out_put_disk; | ||||
| 		goto out_put_queue; | ||||
| 	} | ||||
| 	tpnt->index = error; | ||||
| 	sprintf(disk->disk_name, "st%d", tpnt->index); | ||||
| @ -4211,6 +4215,8 @@ out_remove_devs: | ||||
| 	spin_lock(&st_index_lock); | ||||
| 	idr_remove(&st_index_idr, tpnt->index); | ||||
| 	spin_unlock(&st_index_lock); | ||||
| out_put_queue: | ||||
| 	blk_put_queue(disk->queue); | ||||
| out_put_disk: | ||||
| 	put_disk(disk); | ||||
| 	kfree(tpnt); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user