diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2021-11-09 22:24:08 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2021-11-09 22:24:08 +0300 |
commit | cb690f5238d71f543f4ce874aa59237cf53a877c (patch) | |
tree | 9cffbe44fb9eca3e70297b45cfeacc2c2ef93e0f /drivers/block | |
parent | 3e28850cbd359bed841b832200f9fc208a9ef040 (diff) | |
parent | 2878feaed543c35f9dbbe6d8ce36fb67ac803eef (diff) | |
download | linux-cb690f5238d71f543f4ce874aa59237cf53a877c.tar.xz |
Merge tag 'for-5.16/drivers-2021-11-09' of git://git.kernel.dk/linux-block
Pull more block driver updates from Jens Axboe:
- Last series adding error handling support for add_disk() in drivers.
After this one, and once the SCSI side has been merged, we can
finally annotate add_disk() as must_check. (Luis)
- bcache fixes (Coly)
- zram fixes (Ming)
- ataflop locking fix (Tetsuo)
- nbd fixes (Ye, Yu)
- MD merge via Song
- Cleanup (Yang)
- sysfs fix (Guoqing)
- Misc fixes (Geert, Wu, luo)
* tag 'for-5.16/drivers-2021-11-09' of git://git.kernel.dk/linux-block: (34 commits)
bcache: Revert "bcache: use bvec_virt"
ataflop: Add missing semicolon to return statement
floppy: address add_disk() error handling on probe
ataflop: address add_disk() error handling on probe
block: update __register_blkdev() probe documentation
ataflop: remove ataflop_probe_lock mutex
mtd/ubi/block: add error handling support for add_disk()
block/sunvdc: add error handling support for add_disk()
z2ram: add error handling support for add_disk()
nvdimm/pmem: use add_disk() error handling
nvdimm/pmem: cleanup the disk if pmem_release_disk() is yet assigned
nvdimm/blk: add error handling support for add_disk()
nvdimm/blk: avoid calling del_gendisk() on early failures
nvdimm/btt: add error handling support for add_disk()
nvdimm/btt: use goto error labels on btt_blk_init()
loop: Remove duplicate assignments
drbd: Fix double free problem in drbd_create_device
nvdimm/btt: do not call del_gendisk() if not needed
bcache: fix use-after-free problem in bcache_device_free()
zram: replace fsync_bdev with sync_blockdev
...
Diffstat (limited to 'drivers/block')
-rw-r--r-- | drivers/block/ataflop.c | 61 | ||||
-rw-r--r-- | drivers/block/brd.c | 9 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_main.c | 4 | ||||
-rw-r--r-- | drivers/block/floppy.c | 17 | ||||
-rw-r--r-- | drivers/block/loop.c | 1 | ||||
-rw-r--r-- | drivers/block/nbd.c | 44 | ||||
-rw-r--r-- | drivers/block/ps3disk.c | 8 | ||||
-rw-r--r-- | drivers/block/ps3vram.c | 7 | ||||
-rw-r--r-- | drivers/block/sunvdc.c | 14 | ||||
-rw-r--r-- | drivers/block/z2ram.c | 7 | ||||
-rw-r--r-- | drivers/block/zram/zram_drv.c | 45 |
11 files changed, 143 insertions, 74 deletions
diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index d14bdc3589b2..bf769e6e32fe 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -2008,8 +2008,6 @@ static int ataflop_alloc_disk(unsigned int drive, unsigned int type) return 0; } -static DEFINE_MUTEX(ataflop_probe_lock); - static void ataflop_probe(dev_t dev) { int drive = MINOR(dev) & 3; @@ -2020,14 +2018,38 @@ static void ataflop_probe(dev_t dev) if (drive >= FD_MAX_UNITS || type >= NUM_DISK_MINORS) return; - mutex_lock(&ataflop_probe_lock); - if (!unit[drive].disk[type]) { - if (ataflop_alloc_disk(drive, type) == 0) { - add_disk(unit[drive].disk[type]); - unit[drive].registered[type] = true; + if (unit[drive].disk[type]) + return; + if (ataflop_alloc_disk(drive, type)) + return; + if (add_disk(unit[drive].disk[type])) + goto cleanup_disk; + unit[drive].registered[type] = true; + return; + +cleanup_disk: + blk_cleanup_disk(unit[drive].disk[type]); + unit[drive].disk[type] = NULL; +} + +static void atari_floppy_cleanup(void) +{ + int i; + int type; + + for (i = 0; i < FD_MAX_UNITS; i++) { + for (type = 0; type < NUM_DISK_MINORS; type++) { + if (!unit[i].disk[type]) + continue; + del_gendisk(unit[i].disk[type]); + blk_cleanup_queue(unit[i].disk[type]->queue); + put_disk(unit[i].disk[type]); } + blk_mq_free_tag_set(&unit[i].tag_set); } - mutex_unlock(&ataflop_probe_lock); + + del_timer_sync(&fd_timer); + atari_stram_free(DMABuffer); } static void atari_cleanup_floppy_disk(struct atari_floppy_struct *fs) @@ -2053,11 +2075,6 @@ static int __init atari_floppy_init (void) /* Amiga, Mac, ... don't have Atari-compatible floppy :-) */ return -ENODEV; - mutex_lock(&ataflop_probe_lock); - ret = __register_blkdev(FLOPPY_MAJOR, "fd", ataflop_probe); - if (ret) - goto out_unlock; - for (i = 0; i < FD_MAX_UNITS; i++) { memset(&unit[i].tag_set, 0, sizeof(unit[i].tag_set)); unit[i].tag_set.ops = &ataflop_mq_ops; @@ -2113,7 +2130,12 @@ static int __init atari_floppy_init (void) UseTrackbuffer ? "" : "no "); config_types(); - return 0; + ret = __register_blkdev(FLOPPY_MAJOR, "fd", ataflop_probe); + if (ret) { + printk(KERN_ERR "atari_floppy_init: cannot register block device\n"); + atari_floppy_cleanup(); + } + return ret; err_out_dma: atari_stram_free(DMABuffer); @@ -2121,9 +2143,6 @@ err: while (--i >= 0) atari_cleanup_floppy_disk(&unit[i]); - unregister_blkdev(FLOPPY_MAJOR, "fd"); -out_unlock: - mutex_unlock(&ataflop_probe_lock); return ret; } @@ -2168,14 +2187,8 @@ __setup("floppy=", atari_floppy_setup); static void __exit atari_floppy_exit(void) { - int i; - - for (i = 0; i < FD_MAX_UNITS; i++) - atari_cleanup_floppy_disk(&unit[i]); unregister_blkdev(FLOPPY_MAJOR, "fd"); - - del_timer_sync(&fd_timer); - atari_stram_free( DMABuffer ); + atari_floppy_cleanup(); } module_init(atari_floppy_init) diff --git a/drivers/block/brd.c b/drivers/block/brd.c index aa0472718dce..a896ee175d86 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -370,6 +370,7 @@ static int brd_alloc(int i) struct brd_device *brd; struct gendisk *disk; char buf[DISK_NAME_LEN]; + int err = -ENOMEM; mutex_lock(&brd_devices_mutex); list_for_each_entry(brd, &brd_devices, brd_list) { @@ -420,16 +421,20 @@ static int brd_alloc(int i) /* Tell the block layer that this is not a rotational device */ blk_queue_flag_set(QUEUE_FLAG_NONROT, disk->queue); blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, disk->queue); - add_disk(disk); + err = add_disk(disk); + if (err) + goto out_cleanup_disk; return 0; +out_cleanup_disk: + blk_cleanup_disk(disk); out_free_dev: mutex_lock(&brd_devices_mutex); list_del(&brd->brd_list); mutex_unlock(&brd_devices_mutex); kfree(brd); - return -ENOMEM; + return err; } static void brd_probe(dev_t dev) diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 19db80a1e409..53ba2dddba6e 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2796,7 +2796,7 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig err = add_disk(disk); if (err) - goto out_cleanup_disk; + goto out_idr_remove_vol; /* inherit the connection state */ device->state.conn = first_connection(resource)->cstate; @@ -2810,8 +2810,6 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig drbd_debugfs_device_add(device); return NO_ERROR; -out_cleanup_disk: - blk_cleanup_disk(disk); out_idr_remove_vol: idr_remove(&connection->peer_devices, vnr); out_idr_remove_from_resource: diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 3873e789478e..c4267da716fe 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -4528,10 +4528,19 @@ static void floppy_probe(dev_t dev) return; mutex_lock(&floppy_probe_lock); - if (!disks[drive][type]) { - if (floppy_alloc_disk(drive, type) == 0) - add_disk(disks[drive][type]); - } + if (disks[drive][type]) + goto out; + if (floppy_alloc_disk(drive, type)) + goto out; + if (add_disk(disks[drive][type])) + goto cleanup_disk; +out: + mutex_unlock(&floppy_probe_lock); + return; + +cleanup_disk: + blk_cleanup_disk(disks[drive][type]); + disks[drive][type] = NULL; mutex_unlock(&floppy_probe_lock); } diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 3c09a33fa1c7..a154cab6cd98 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1983,7 +1983,6 @@ static int loop_add(int i) goto out_free_dev; i = err; - err = -ENOMEM; lo->tag_set.ops = &loop_mq_ops; lo->tag_set.nr_hw_queues = 1; lo->tag_set.queue_depth = 128; diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index b47b2a87ae8f..5a1f98494ddd 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -260,7 +260,7 @@ static void nbd_dev_remove(struct nbd_device *nbd) mutex_lock(&nbd_index_mutex); idr_remove(&nbd_index_idr, nbd->index); mutex_unlock(&nbd_index_mutex); - + destroy_workqueue(nbd->recv_workq); kfree(nbd); } @@ -755,6 +755,8 @@ static struct nbd_cmd *nbd_handle_reply(struct nbd_device *nbd, int index, if (cmd->index != index) { dev_err(disk_to_dev(nbd->disk), "Unexpected reply %d from different sock %d (expected %d)", tag, index, cmd->index); + ret = -ENOENT; + goto out; } if (cmd->cmd_cookie != nbd_handle_to_cookie(handle)) { dev_err(disk_to_dev(nbd->disk), "Double reply on req %p, cmd_cookie %u, handle cookie %u\n", @@ -1314,10 +1316,6 @@ static void nbd_config_put(struct nbd_device *nbd) kfree(nbd->config); nbd->config = NULL; - if (nbd->recv_workq) - destroy_workqueue(nbd->recv_workq); - nbd->recv_workq = NULL; - nbd->tag_set.timeout = 0; nbd->disk->queue->limits.discard_granularity = 0; nbd->disk->queue->limits.discard_alignment = 0; @@ -1346,14 +1344,6 @@ static int nbd_start_device(struct nbd_device *nbd) return -EINVAL; } - nbd->recv_workq = alloc_workqueue("knbd%d-recv", - WQ_MEM_RECLAIM | WQ_HIGHPRI | - WQ_UNBOUND, 0, nbd->index); - if (!nbd->recv_workq) { - dev_err(disk_to_dev(nbd->disk), "Could not allocate knbd recv work queue.\n"); - return -ENOMEM; - } - blk_mq_update_nr_hw_queues(&nbd->tag_set, config->num_connections); nbd->pid = task_pid_nr(current); @@ -1779,6 +1769,15 @@ static struct nbd_device *nbd_dev_add(int index, unsigned int refs) } nbd->disk = disk; + nbd->recv_workq = alloc_workqueue("nbd%d-recv", + WQ_MEM_RECLAIM | WQ_HIGHPRI | + WQ_UNBOUND, 0, nbd->index); + if (!nbd->recv_workq) { + dev_err(disk_to_dev(nbd->disk), "Could not allocate knbd recv work queue.\n"); + err = -ENOMEM; + goto out_err_disk; + } + /* * Tell the block layer that we are not a rotational device */ @@ -1803,13 +1802,13 @@ static struct nbd_device *nbd_dev_add(int index, unsigned int refs) disk->major = NBD_MAJOR; /* Too big first_minor can cause duplicate creation of - * sysfs files/links, since first_minor will be truncated to - * byte in __device_add_disk(). + * sysfs files/links, since index << part_shift might overflow, or + * MKDEV() expect that the max bits of first_minor is 20. */ disk->first_minor = index << part_shift; - if (disk->first_minor > 0xff) { + if (disk->first_minor < index || disk->first_minor > MINORMASK) { err = -EINVAL; - goto out_free_idr; + goto out_free_work; } disk->minors = 1 << part_shift; @@ -1818,7 +1817,7 @@ static struct nbd_device *nbd_dev_add(int index, unsigned int refs) sprintf(disk->disk_name, "nbd%d", index); err = add_disk(disk); if (err) - goto out_err_disk; + goto out_free_work; /* * Now publish the device. @@ -1827,6 +1826,8 @@ static struct nbd_device *nbd_dev_add(int index, unsigned int refs) nbd_total_devices++; return nbd; +out_free_work: + destroy_workqueue(nbd->recv_workq); out_err_disk: blk_cleanup_disk(disk); out_free_idr: @@ -2082,13 +2083,10 @@ static void nbd_disconnect_and_put(struct nbd_device *nbd) nbd_disconnect(nbd); sock_shutdown(nbd); /* - * Make sure recv thread has finished, so it does not drop the last - * config ref and try to destroy the workqueue from inside the work - * queue. And this also ensure that we can safely call nbd_clear_que() + * Make sure recv thread has finished, we can safely call nbd_clear_que() * to cancel the inflight I/Os. */ - if (nbd->recv_workq) - flush_workqueue(nbd->recv_workq); + flush_workqueue(nbd->recv_workq); nbd_clear_que(nbd); nbd->task_setup = NULL; mutex_unlock(&nbd->config_lock); diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index 8d51efbe045d..3054adf77460 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -467,9 +467,13 @@ static int ps3disk_probe(struct ps3_system_bus_device *_dev) gendisk->disk_name, priv->model, priv->raw_capacity >> 11, get_capacity(gendisk) >> 11); - device_add_disk(&dev->sbd.core, gendisk, NULL); - return 0; + error = device_add_disk(&dev->sbd.core, gendisk, NULL); + if (error) + goto fail_cleanup_disk; + return 0; +fail_cleanup_disk: + blk_cleanup_disk(gendisk); fail_free_tag_set: blk_mq_free_tag_set(&priv->tag_set); fail_teardown: diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c index d1ebf193cb9a..c1876646a4cb 100644 --- a/drivers/block/ps3vram.c +++ b/drivers/block/ps3vram.c @@ -753,9 +753,14 @@ static int ps3vram_probe(struct ps3_system_bus_device *dev) dev_info(&dev->core, "%s: Using %llu MiB of GPU memory\n", gendisk->disk_name, get_capacity(gendisk) >> 11); - device_add_disk(&dev->core, gendisk, NULL); + error = device_add_disk(&dev->core, gendisk, NULL); + if (error) + goto out_cleanup_disk; + return 0; +out_cleanup_disk: + blk_cleanup_disk(gendisk); out_cache_cleanup: remove_proc_entry(DEVICE_NAME, NULL); ps3vram_cache_cleanup(dev); diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c index 4d4bb810c2ae..6f45a53f7cbf 100644 --- a/drivers/block/sunvdc.c +++ b/drivers/block/sunvdc.c @@ -826,8 +826,8 @@ static int probe_disk(struct vdc_port *port) if (IS_ERR(g)) { printk(KERN_ERR PFX "%s: Could not allocate gendisk.\n", port->vio.name); - blk_mq_free_tag_set(&port->tag_set); - return PTR_ERR(g); + err = PTR_ERR(g); + goto out_free_tag; } port->disk = g; @@ -879,9 +879,17 @@ static int probe_disk(struct vdc_port *port) port->vdisk_size, (port->vdisk_size >> (20 - 9)), port->vio.ver.major, port->vio.ver.minor); - device_add_disk(&port->vio.vdev->dev, g, NULL); + err = device_add_disk(&port->vio.vdev->dev, g, NULL); + if (err) + goto out_cleanup_disk; return 0; + +out_cleanup_disk: + blk_cleanup_disk(g); +out_free_tag: + blk_mq_free_tag_set(&port->tag_set); + return err; } static struct ldc_channel_config vdc_ldc_cfg = { diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c index 4eef218108c6..ccc52c935faf 100644 --- a/drivers/block/z2ram.c +++ b/drivers/block/z2ram.c @@ -318,6 +318,7 @@ static const struct blk_mq_ops z2_mq_ops = { static int z2ram_register_disk(int minor) { struct gendisk *disk; + int err; disk = blk_mq_alloc_disk(&tag_set, NULL); if (IS_ERR(disk)) @@ -333,8 +334,10 @@ static int z2ram_register_disk(int minor) sprintf(disk->disk_name, "z2ram"); z2ram_gendisk[minor] = disk; - add_disk(disk); - return 0; + err = add_disk(disk); + if (err) + blk_cleanup_disk(disk); + return err; } static int __init z2_init(void) diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index c8931ba91b57..08d7953ec5f1 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -1734,12 +1734,13 @@ static void zram_reset_device(struct zram *zram) set_capacity_and_notify(zram->disk, 0); part_stat_set_all(zram->disk->part0, 0); - up_write(&zram->init_lock); /* I/O operation under all of CPU are done so let's free */ zram_meta_free(zram, disksize); memset(&zram->stats, 0, sizeof(zram->stats)); zcomp_destroy(comp); reset_bdev(zram); + + up_write(&zram->init_lock); } static ssize_t disksize_store(struct device *dev, @@ -1819,7 +1820,7 @@ static ssize_t reset_store(struct device *dev, mutex_unlock(&bdev->bd_disk->open_mutex); /* Make sure all the pending I/O are finished */ - fsync_bdev(bdev); + sync_blockdev(bdev); zram_reset_device(zram); mutex_lock(&bdev->bd_disk->open_mutex); @@ -1979,7 +1980,9 @@ static int zram_add(void) blk_queue_max_write_zeroes_sectors(zram->disk->queue, UINT_MAX); blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, zram->disk->queue); - device_add_disk(NULL, zram->disk, zram_disk_attr_groups); + ret = device_add_disk(NULL, zram->disk, zram_disk_attr_groups); + if (ret) + goto out_cleanup_disk; strlcpy(zram->compressor, default_compressor, sizeof(zram->compressor)); @@ -1987,6 +1990,8 @@ static int zram_add(void) pr_info("Added device: %s\n", zram->disk->disk_name); return device_id; +out_cleanup_disk: + blk_cleanup_disk(zram->disk); out_free_idr: idr_remove(&zram_index_idr, device_id); out_free_dev: @@ -1997,25 +2002,47 @@ out_free_dev: static int zram_remove(struct zram *zram) { struct block_device *bdev = zram->disk->part0; + bool claimed; mutex_lock(&bdev->bd_disk->open_mutex); - if (bdev->bd_openers || zram->claim) { + if (bdev->bd_openers) { mutex_unlock(&bdev->bd_disk->open_mutex); return -EBUSY; } - zram->claim = true; + claimed = zram->claim; + if (!claimed) + zram->claim = true; mutex_unlock(&bdev->bd_disk->open_mutex); zram_debugfs_unregister(zram); - /* Make sure all the pending I/O are finished */ - fsync_bdev(bdev); - zram_reset_device(zram); + if (claimed) { + /* + * If we were claimed by reset_store(), del_gendisk() will + * wait until reset_store() is done, so nothing need to do. + */ + ; + } else { + /* Make sure all the pending I/O are finished */ + sync_blockdev(bdev); + zram_reset_device(zram); + } pr_info("Removed device: %s\n", zram->disk->disk_name); del_gendisk(zram->disk); + + /* del_gendisk drains pending reset_store */ + WARN_ON_ONCE(claimed && zram->claim); + + /* + * disksize_store() may be called in between zram_reset_device() + * and del_gendisk(), so run the last reset to avoid leaking + * anything allocated with disksize_store() + */ + zram_reset_device(zram); + blk_cleanup_disk(zram->disk); kfree(zram); return 0; @@ -2092,7 +2119,7 @@ static struct class zram_control_class = { static int zram_remove_cb(int id, void *ptr, void *data) { - zram_remove(ptr); + WARN_ON_ONCE(zram_remove(ptr)); return 0; } |