aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--block/blk-core.c1
-rw-r--r--block/genhd.c21
-rw-r--r--drivers/scsi/sd.c41
-rw-r--r--include/linux/blkdev.h1
-rw-r--r--include/linux/genhd.h8
5 files changed, 64 insertions, 8 deletions
diff --git a/block/blk-core.c b/block/blk-core.c
index a3c29270807e..a5726e01f839 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -572,6 +572,7 @@ void blk_cleanup_queue(struct request_queue *q)
572 spin_unlock_irq(lock); 572 spin_unlock_irq(lock);
573 573
574 bdi_unregister(q->backing_dev_info); 574 bdi_unregister(q->backing_dev_info);
575 put_disk_devt(q->disk_devt);
575 576
576 /* @q is and will stay empty, shutdown and put */ 577 /* @q is and will stay empty, shutdown and put */
577 blk_put_queue(q); 578 blk_put_queue(q);
diff --git a/block/genhd.c b/block/genhd.c
index d9ccd42f3675..3631cd480295 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -572,6 +572,20 @@ exit:
572 disk_part_iter_exit(&piter); 572 disk_part_iter_exit(&piter);
573} 573}
574 574
575void put_disk_devt(struct disk_devt *disk_devt)
576{
577 if (disk_devt && atomic_dec_and_test(&disk_devt->count))
578 disk_devt->release(disk_devt);
579}
580EXPORT_SYMBOL(put_disk_devt);
581
582void get_disk_devt(struct disk_devt *disk_devt)
583{
584 if (disk_devt)
585 atomic_inc(&disk_devt->count);
586}
587EXPORT_SYMBOL(get_disk_devt);
588
575/** 589/**
576 * device_add_disk - add partitioning information to kernel list 590 * device_add_disk - add partitioning information to kernel list
577 * @parent: parent device for the disk 591 * @parent: parent device for the disk
@@ -612,6 +626,13 @@ void device_add_disk(struct device *parent, struct gendisk *disk)
612 626
613 disk_alloc_events(disk); 627 disk_alloc_events(disk);
614 628
629 /*
630 * Take a reference on the devt and assign it to queue since it
631 * must not be reallocated while the bdi is registered
632 */
633 disk->queue->disk_devt = disk->disk_devt;
634 get_disk_devt(disk->disk_devt);
635
615 /* Register BDI before referencing it from bdev */ 636 /* Register BDI before referencing it from bdev */
616 bdi = disk->queue->backing_dev_info; 637 bdi = disk->queue->backing_dev_info;
617 bdi_register_owner(bdi, disk_to_dev(disk)); 638 bdi_register_owner(bdi, disk_to_dev(disk));
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index bd2fb4d52efa..dff709e22370 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -3064,6 +3064,23 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
3064 put_device(&sdkp->dev); 3064 put_device(&sdkp->dev);
3065} 3065}
3066 3066
3067struct sd_devt {
3068 int idx;
3069 struct disk_devt disk_devt;
3070};
3071
3072void sd_devt_release(struct disk_devt *disk_devt)
3073{
3074 struct sd_devt *sd_devt = container_of(disk_devt, struct sd_devt,
3075 disk_devt);
3076
3077 spin_lock(&sd_index_lock);
3078 ida_remove(&sd_index_ida, sd_devt->idx);
3079 spin_unlock(&sd_index_lock);
3080
3081 kfree(sd_devt);
3082}
3083
3067/** 3084/**
3068 * sd_probe - called during driver initialization and whenever a 3085 * sd_probe - called during driver initialization and whenever a
3069 * new scsi device is attached to the system. It is called once 3086 * new scsi device is attached to the system. It is called once
@@ -3085,6 +3102,7 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
3085static int sd_probe(struct device *dev) 3102static int sd_probe(struct device *dev)
3086{ 3103{
3087 struct scsi_device *sdp = to_scsi_device(dev); 3104 struct scsi_device *sdp = to_scsi_device(dev);
3105 struct sd_devt *sd_devt;
3088 struct scsi_disk *sdkp; 3106 struct scsi_disk *sdkp;
3089 struct gendisk *gd; 3107 struct gendisk *gd;
3090 int index; 3108 int index;
@@ -3110,9 +3128,13 @@ static int sd_probe(struct device *dev)
3110 if (!sdkp) 3128 if (!sdkp)
3111 goto out; 3129 goto out;
3112 3130
3131 sd_devt = kzalloc(sizeof(*sd_devt), GFP_KERNEL);
3132 if (!sd_devt)
3133 goto out_free;
3134
3113 gd = alloc_disk(SD_MINORS); 3135 gd = alloc_disk(SD_MINORS);
3114 if (!gd) 3136 if (!gd)
3115 goto out_free; 3137 goto out_free_devt;
3116 3138
3117 do { 3139 do {
3118 if (!ida_pre_get(&sd_index_ida, GFP_KERNEL)) 3140 if (!ida_pre_get(&sd_index_ida, GFP_KERNEL))
@@ -3128,6 +3150,11 @@ static int sd_probe(struct device *dev)
3128 goto out_put; 3150 goto out_put;
3129 } 3151 }
3130 3152
3153 atomic_set(&sd_devt->disk_devt.count, 1);
3154 sd_devt->disk_devt.release = sd_devt_release;
3155 sd_devt->idx = index;
3156 gd->disk_devt = &sd_devt->disk_devt;
3157
3131 error = sd_format_disk_name("sd", index, gd->disk_name, DISK_NAME_LEN); 3158 error = sd_format_disk_name("sd", index, gd->disk_name, DISK_NAME_LEN);
3132 if (error) { 3159 if (error) {
3133 sdev_printk(KERN_WARNING, sdp, "SCSI disk (sd) name length exceeded.\n"); 3160 sdev_printk(KERN_WARNING, sdp, "SCSI disk (sd) name length exceeded.\n");
@@ -3167,13 +3194,14 @@ static int sd_probe(struct device *dev)
3167 return 0; 3194 return 0;
3168 3195
3169 out_free_index: 3196 out_free_index:
3170 spin_lock(&sd_index_lock); 3197 put_disk_devt(&sd_devt->disk_devt);
3171 ida_remove(&sd_index_ida, index); 3198 sd_devt = NULL;
3172 spin_unlock(&sd_index_lock);
3173 out_put: 3199 out_put:
3174 put_disk(gd); 3200 put_disk(gd);
3175 out_free: 3201 out_free:
3176 kfree(sdkp); 3202 kfree(sdkp);
3203 out_free_devt:
3204 kfree(sd_devt);
3177 out: 3205 out:
3178 scsi_autopm_put_device(sdp); 3206 scsi_autopm_put_device(sdp);
3179 return error; 3207 return error;
@@ -3232,10 +3260,7 @@ static void scsi_disk_release(struct device *dev)
3232 struct scsi_disk *sdkp = to_scsi_disk(dev); 3260 struct scsi_disk *sdkp = to_scsi_disk(dev);
3233 struct gendisk *disk = sdkp->disk; 3261 struct gendisk *disk = sdkp->disk;
3234 3262
3235 spin_lock(&sd_index_lock); 3263 put_disk_devt(disk->disk_devt);
3236 ida_remove(&sd_index_ida, sdkp->index);
3237 spin_unlock(&sd_index_lock);
3238
3239 disk->private_data = NULL; 3264 disk->private_data = NULL;
3240 put_disk(disk); 3265 put_disk(disk);
3241 put_device(&sdkp->device->sdev_gendev); 3266 put_device(&sdkp->device->sdev_gendev);
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index b31137e2afd0..f84fbe55d3b3 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -433,6 +433,7 @@ struct request_queue {
433 struct delayed_work delay_work; 433 struct delayed_work delay_work;
434 434
435 struct backing_dev_info *backing_dev_info; 435 struct backing_dev_info *backing_dev_info;
436 struct disk_devt *disk_devt;
436 437
437 /* 438 /*
438 * The queue owner gets to use this for whatever they like. 439 * The queue owner gets to use this for whatever they like.
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index 76f39754e7b0..a999d281a2f1 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -167,6 +167,13 @@ struct blk_integrity {
167}; 167};
168 168
169#endif /* CONFIG_BLK_DEV_INTEGRITY */ 169#endif /* CONFIG_BLK_DEV_INTEGRITY */
170struct disk_devt {
171 atomic_t count;
172 void (*release)(struct disk_devt *disk_devt);
173};
174
175void put_disk_devt(struct disk_devt *disk_devt);
176void get_disk_devt(struct disk_devt *disk_devt);
170 177
171struct gendisk { 178struct gendisk {
172 /* major, first_minor and minors are input parameters only, 179 /* major, first_minor and minors are input parameters only,
@@ -176,6 +183,7 @@ struct gendisk {
176 int first_minor; 183 int first_minor;
177 int minors; /* maximum number of minors, =1 for 184 int minors; /* maximum number of minors, =1 for
178 * disks that can't be partitioned. */ 185 * disks that can't be partitioned. */
186 struct disk_devt *disk_devt;
179 187
180 char disk_name[DISK_NAME_LEN]; /* name of major driver */ 188 char disk_name[DISK_NAME_LEN]; /* name of major driver */
181 char *(*devnode)(struct gendisk *gd, umode_t *mode); 189 char *(*devnode)(struct gendisk *gd, umode_t *mode);