Commit 2b5bebccd282f2527d17ac90cf3ad0d486dd89d8
Committed by
James Bottomley
1 parent
95c9f4d4da
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
[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
drivers/scsi/st.c
... | ... | @@ -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); |