aboutsummaryrefslogtreecommitdiffstats
path: root/block/genhd.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2013-02-27 20:03:56 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-02-27 22:10:14 -0500
commitce23bba842aee98092225d9576dba47c82352521 (patch)
tree5642d356f830bc3987f65f6879249cf96bf24df2 /block/genhd.c
parentd5c7409f79e14db49d00785692334657592c07ff (diff)
block: fix synchronization and limit check in blk_alloc_devt()
idr allocation in blk_alloc_devt() wasn't synchronized against lookup and removal, and its limit check was off by one - 1 << MINORBITS is the number of minors allowed, not the maximum allowed minor. Add locking and rename MAX_EXT_DEVT to NR_EXT_DEVT and fix limit checking. Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: Jens Axboe <axboe@kernel.dk> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'block/genhd.c')
-rw-r--r--block/genhd.c13
1 files changed, 5 insertions, 8 deletions
diff --git a/block/genhd.c b/block/genhd.c
index cd65b97e84d4..841b3037d866 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -26,7 +26,7 @@ static DEFINE_MUTEX(block_class_lock);
26struct kobject *block_depr; 26struct kobject *block_depr;
27 27
28/* for extended dynamic devt allocation, currently only one major is used */ 28/* for extended dynamic devt allocation, currently only one major is used */
29#define MAX_EXT_DEVT (1 << MINORBITS) 29#define NR_EXT_DEVT (1 << MINORBITS)
30 30
31/* For extended devt allocation. ext_devt_mutex prevents look up 31/* For extended devt allocation. ext_devt_mutex prevents look up
32 * results from going away underneath its user. 32 * results from going away underneath its user.
@@ -425,19 +425,16 @@ int blk_alloc_devt(struct hd_struct *part, dev_t *devt)
425 return -ENOMEM; 425 return -ENOMEM;
426 mutex_lock(&ext_devt_mutex); 426 mutex_lock(&ext_devt_mutex);
427 rc = idr_get_new(&ext_devt_idr, part, &idx); 427 rc = idr_get_new(&ext_devt_idr, part, &idx);
428 if (!rc && idx >= NR_EXT_DEVT) {
429 idr_remove(&ext_devt_idr, idx);
430 rc = -EBUSY;
431 }
428 mutex_unlock(&ext_devt_mutex); 432 mutex_unlock(&ext_devt_mutex);
429 } while (rc == -EAGAIN); 433 } while (rc == -EAGAIN);
430 434
431 if (rc) 435 if (rc)
432 return rc; 436 return rc;
433 437
434 if (idx > MAX_EXT_DEVT) {
435 mutex_lock(&ext_devt_mutex);
436 idr_remove(&ext_devt_idr, idx);
437 mutex_unlock(&ext_devt_mutex);
438 return -EBUSY;
439 }
440
441 *devt = MKDEV(BLOCK_EXT_MAJOR, blk_mangle_minor(idx)); 438 *devt = MKDEV(BLOCK_EXT_MAJOR, blk_mangle_minor(idx));
442 return 0; 439 return 0;
443} 440}