aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBradley Bolen <bradleybolen@gmail.com>2018-01-18 08:55:20 -0500
committerRichard Weinberger <richard@nod.at>2018-01-18 10:48:31 -0500
commit7f29ae9f977bcdc3654e68bc36d170223c52fd48 (patch)
tree914eb7de318c02c1481533b70e67b2b5ffff8080
parent7233982ade15eeac05c6f351e8d347406e6bcd2f (diff)
ubi: block: Fix locking for idr_alloc/idr_remove
This fixes a race with idr_alloc where gd->first_minor can be set to the same value for two simultaneous calls to ubiblock_create. Each instance calls device_add_disk with the same first_minor. device_add_disk calls bdi_register_owner which generates several warnings. WARNING: CPU: 1 PID: 179 at kernel-source/fs/sysfs/dir.c:31 sysfs_warn_dup+0x68/0x88 sysfs: cannot create duplicate filename '/devices/virtual/bdi/252:2' WARNING: CPU: 1 PID: 179 at kernel-source/lib/kobject.c:240 kobject_add_internal+0x1ec/0x2f8 kobject_add_internal failed for 252:2 with -EEXIST, don't try to register things with the same name in the same directory WARNING: CPU: 1 PID: 179 at kernel-source/fs/sysfs/dir.c:31 sysfs_warn_dup+0x68/0x88 sysfs: cannot create duplicate filename '/dev/block/252:2' However, device_add_disk does not error out when bdi_register_owner returns an error. Control continues until reaching blk_register_queue. It then BUGs. kernel BUG at kernel-source/fs/sysfs/group.c:113! [<c01e26cc>] (internal_create_group) from [<c01e2950>] (sysfs_create_group+0x20/0x24) [<c01e2950>] (sysfs_create_group) from [<c00e3d38>] (blk_trace_init_sysfs+0x18/0x20) [<c00e3d38>] (blk_trace_init_sysfs) from [<c02bdfbc>] (blk_register_queue+0xd8/0x154) [<c02bdfbc>] (blk_register_queue) from [<c02cec84>] (device_add_disk+0x194/0x44c) [<c02cec84>] (device_add_disk) from [<c0436ec8>] (ubiblock_create+0x284/0x2e0) [<c0436ec8>] (ubiblock_create) from [<c0427bb8>] (vol_cdev_ioctl+0x450/0x554) [<c0427bb8>] (vol_cdev_ioctl) from [<c0189110>] (vfs_ioctl+0x30/0x44) [<c0189110>] (vfs_ioctl) from [<c01892e0>] (do_vfs_ioctl+0xa0/0x790) [<c01892e0>] (do_vfs_ioctl) from [<c0189a14>] (SyS_ioctl+0x44/0x68) [<c0189a14>] (SyS_ioctl) from [<c0010640>] (ret_fast_syscall+0x0/0x34) Locking idr_alloc/idr_remove removes the race and keeps gd->first_minor unique. Fixes: 2bf50d42f3a4 ("UBI: block: Dynamically allocate minor numbers") Cc: stable@vger.kernel.org Signed-off-by: Bradley Bolen <bradleybolen@gmail.com> Reviewed-by: Boris Brezillon <boris.brezillon@free-electrons.com> Signed-off-by: Richard Weinberger <richard@nod.at>
-rw-r--r--drivers/mtd/ubi/block.c42
1 files changed, 26 insertions, 16 deletions
diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
index b210fdb31c98..b1fc28f63882 100644
--- a/drivers/mtd/ubi/block.c
+++ b/drivers/mtd/ubi/block.c
@@ -99,6 +99,8 @@ struct ubiblock {
99 99
100/* Linked list of all ubiblock instances */ 100/* Linked list of all ubiblock instances */
101static LIST_HEAD(ubiblock_devices); 101static LIST_HEAD(ubiblock_devices);
102static DEFINE_IDR(ubiblock_minor_idr);
103/* Protects ubiblock_devices and ubiblock_minor_idr */
102static DEFINE_MUTEX(devices_mutex); 104static DEFINE_MUTEX(devices_mutex);
103static int ubiblock_major; 105static int ubiblock_major;
104 106
@@ -351,8 +353,6 @@ static const struct blk_mq_ops ubiblock_mq_ops = {
351 .init_request = ubiblock_init_request, 353 .init_request = ubiblock_init_request,
352}; 354};
353 355
354static DEFINE_IDR(ubiblock_minor_idr);
355
356int ubiblock_create(struct ubi_volume_info *vi) 356int ubiblock_create(struct ubi_volume_info *vi)
357{ 357{
358 struct ubiblock *dev; 358 struct ubiblock *dev;
@@ -365,14 +365,15 @@ int ubiblock_create(struct ubi_volume_info *vi)
365 /* Check that the volume isn't already handled */ 365 /* Check that the volume isn't already handled */
366 mutex_lock(&devices_mutex); 366 mutex_lock(&devices_mutex);
367 if (find_dev_nolock(vi->ubi_num, vi->vol_id)) { 367 if (find_dev_nolock(vi->ubi_num, vi->vol_id)) {
368 mutex_unlock(&devices_mutex); 368 ret = -EEXIST;
369 return -EEXIST; 369 goto out_unlock;
370 } 370 }
371 mutex_unlock(&devices_mutex);
372 371
373 dev = kzalloc(sizeof(struct ubiblock), GFP_KERNEL); 372 dev = kzalloc(sizeof(struct ubiblock), GFP_KERNEL);
374 if (!dev) 373 if (!dev) {
375 return -ENOMEM; 374 ret = -ENOMEM;
375 goto out_unlock;
376 }
376 377
377 mutex_init(&dev->dev_mutex); 378 mutex_init(&dev->dev_mutex);
378 379
@@ -437,14 +438,13 @@ int ubiblock_create(struct ubi_volume_info *vi)
437 goto out_free_queue; 438 goto out_free_queue;
438 } 439 }
439 440
440 mutex_lock(&devices_mutex);
441 list_add_tail(&dev->list, &ubiblock_devices); 441 list_add_tail(&dev->list, &ubiblock_devices);
442 mutex_unlock(&devices_mutex);
443 442
444 /* Must be the last step: anyone can call file ops from now on */ 443 /* Must be the last step: anyone can call file ops from now on */
445 add_disk(dev->gd); 444 add_disk(dev->gd);
446 dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)", 445 dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)",
447 dev->ubi_num, dev->vol_id, vi->name); 446 dev->ubi_num, dev->vol_id, vi->name);
447 mutex_unlock(&devices_mutex);
448 return 0; 448 return 0;
449 449
450out_free_queue: 450out_free_queue:
@@ -457,6 +457,8 @@ out_put_disk:
457 put_disk(dev->gd); 457 put_disk(dev->gd);
458out_free_dev: 458out_free_dev:
459 kfree(dev); 459 kfree(dev);
460out_unlock:
461 mutex_unlock(&devices_mutex);
460 462
461 return ret; 463 return ret;
462} 464}
@@ -478,30 +480,36 @@ static void ubiblock_cleanup(struct ubiblock *dev)
478int ubiblock_remove(struct ubi_volume_info *vi) 480int ubiblock_remove(struct ubi_volume_info *vi)
479{ 481{
480 struct ubiblock *dev; 482 struct ubiblock *dev;
483 int ret;
481 484
482 mutex_lock(&devices_mutex); 485 mutex_lock(&devices_mutex);
483 dev = find_dev_nolock(vi->ubi_num, vi->vol_id); 486 dev = find_dev_nolock(vi->ubi_num, vi->vol_id);
484 if (!dev) { 487 if (!dev) {
485 mutex_unlock(&devices_mutex); 488 ret = -ENODEV;
486 return -ENODEV; 489 goto out_unlock;
487 } 490 }
488 491
489 /* Found a device, let's lock it so we can check if it's busy */ 492 /* Found a device, let's lock it so we can check if it's busy */
490 mutex_lock(&dev->dev_mutex); 493 mutex_lock(&dev->dev_mutex);
491 if (dev->refcnt > 0) { 494 if (dev->refcnt > 0) {
492 mutex_unlock(&dev->dev_mutex); 495 ret = -EBUSY;
493 mutex_unlock(&devices_mutex); 496 goto out_unlock_dev;
494 return -EBUSY;
495 } 497 }
496 498
497 /* Remove from device list */ 499 /* Remove from device list */
498 list_del(&dev->list); 500 list_del(&dev->list);
499 mutex_unlock(&devices_mutex);
500
501 ubiblock_cleanup(dev); 501 ubiblock_cleanup(dev);
502 mutex_unlock(&dev->dev_mutex); 502 mutex_unlock(&dev->dev_mutex);
503 mutex_unlock(&devices_mutex);
504
503 kfree(dev); 505 kfree(dev);
504 return 0; 506 return 0;
507
508out_unlock_dev:
509 mutex_unlock(&dev->dev_mutex);
510out_unlock:
511 mutex_unlock(&devices_mutex);
512 return ret;
505} 513}
506 514
507static int ubiblock_resize(struct ubi_volume_info *vi) 515static int ubiblock_resize(struct ubi_volume_info *vi)
@@ -630,6 +638,7 @@ static void ubiblock_remove_all(void)
630 struct ubiblock *next; 638 struct ubiblock *next;
631 struct ubiblock *dev; 639 struct ubiblock *dev;
632 640
641 mutex_lock(&devices_mutex);
633 list_for_each_entry_safe(dev, next, &ubiblock_devices, list) { 642 list_for_each_entry_safe(dev, next, &ubiblock_devices, list) {
634 /* The module is being forcefully removed */ 643 /* The module is being forcefully removed */
635 WARN_ON(dev->desc); 644 WARN_ON(dev->desc);
@@ -638,6 +647,7 @@ static void ubiblock_remove_all(void)
638 ubiblock_cleanup(dev); 647 ubiblock_cleanup(dev);
639 kfree(dev); 648 kfree(dev);
640 } 649 }
650 mutex_unlock(&devices_mutex);
641} 651}
642 652
643int __init ubiblock_init(void) 653int __init ubiblock_init(void)