diff options
-rw-r--r-- | block/blk-core.c | 1 | ||||
-rw-r--r-- | block/genhd.c | 21 | ||||
-rw-r--r-- | drivers/scsi/sd.c | 41 | ||||
-rw-r--r-- | include/linux/blkdev.h | 1 | ||||
-rw-r--r-- | include/linux/genhd.h | 8 |
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 | ||
575 | void 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 | } | ||
580 | EXPORT_SYMBOL(put_disk_devt); | ||
581 | |||
582 | void get_disk_devt(struct disk_devt *disk_devt) | ||
583 | { | ||
584 | if (disk_devt) | ||
585 | atomic_inc(&disk_devt->count); | ||
586 | } | ||
587 | EXPORT_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 | ||
3067 | struct sd_devt { | ||
3068 | int idx; | ||
3069 | struct disk_devt disk_devt; | ||
3070 | }; | ||
3071 | |||
3072 | void 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) | |||
3085 | static int sd_probe(struct device *dev) | 3102 | static 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 */ |
170 | struct disk_devt { | ||
171 | atomic_t count; | ||
172 | void (*release)(struct disk_devt *disk_devt); | ||
173 | }; | ||
174 | |||
175 | void put_disk_devt(struct disk_devt *disk_devt); | ||
176 | void get_disk_devt(struct disk_devt *disk_devt); | ||
170 | 177 | ||
171 | struct gendisk { | 178 | struct 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); |