[SCSI] sd: revive sd_index_lock
Commit f27bac2761
which converted sd to
use ida instead of idr incorrectly removed sd_index_lock around id
allocation and free. idr/ida do have internal locks but they protect
their free object lists not the allocation itself. The caller is
responsible for that. This missing synchronization led to the same id
being assigned to multiple devices leading to oops.
Reported and tracked down by Stuart Hayes of Dell.
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Stable Tree <stable@kernel.org>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
This commit is contained in:
parent
b7e7bd3446
commit
4034cc6815
|
@ -107,6 +107,7 @@ static void scsi_disk_release(struct device *cdev);
|
||||||
static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *);
|
static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *);
|
||||||
static void sd_print_result(struct scsi_disk *, int);
|
static void sd_print_result(struct scsi_disk *, int);
|
||||||
|
|
||||||
|
static DEFINE_SPINLOCK(sd_index_lock);
|
||||||
static DEFINE_IDA(sd_index_ida);
|
static DEFINE_IDA(sd_index_ida);
|
||||||
|
|
||||||
/* This semaphore is used to mediate the 0->1 reference get in the
|
/* This semaphore is used to mediate the 0->1 reference get in the
|
||||||
|
@ -1914,7 +1915,9 @@ static int sd_probe(struct device *dev)
|
||||||
if (!ida_pre_get(&sd_index_ida, GFP_KERNEL))
|
if (!ida_pre_get(&sd_index_ida, GFP_KERNEL))
|
||||||
goto out_put;
|
goto out_put;
|
||||||
|
|
||||||
|
spin_lock(&sd_index_lock);
|
||||||
error = ida_get_new(&sd_index_ida, &index);
|
error = ida_get_new(&sd_index_ida, &index);
|
||||||
|
spin_unlock(&sd_index_lock);
|
||||||
} while (error == -EAGAIN);
|
} while (error == -EAGAIN);
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
|
@ -1936,7 +1939,9 @@ static int sd_probe(struct device *dev)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_free_index:
|
out_free_index:
|
||||||
|
spin_lock(&sd_index_lock);
|
||||||
ida_remove(&sd_index_ida, index);
|
ida_remove(&sd_index_ida, index);
|
||||||
|
spin_unlock(&sd_index_lock);
|
||||||
out_put:
|
out_put:
|
||||||
put_disk(gd);
|
put_disk(gd);
|
||||||
out_free:
|
out_free:
|
||||||
|
@ -1986,7 +1991,9 @@ static void scsi_disk_release(struct device *dev)
|
||||||
struct scsi_disk *sdkp = to_scsi_disk(dev);
|
struct scsi_disk *sdkp = to_scsi_disk(dev);
|
||||||
struct gendisk *disk = sdkp->disk;
|
struct gendisk *disk = sdkp->disk;
|
||||||
|
|
||||||
|
spin_lock(&sd_index_lock);
|
||||||
ida_remove(&sd_index_ida, sdkp->index);
|
ida_remove(&sd_index_ida, sdkp->index);
|
||||||
|
spin_unlock(&sd_index_lock);
|
||||||
|
|
||||||
disk->private_data = NULL;
|
disk->private_data = NULL;
|
||||||
put_disk(disk);
|
put_disk(disk);
|
||||||
|
|
Loading…
Reference in New Issue