Skip to content

Commit

Permalink
block: fix synchronization and limit check in blk_alloc_devt()
Browse files Browse the repository at this point in the history
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 <[email protected]>
Acked-by: Jens Axboe <[email protected]>
Cc: <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
htejun authored and torvalds committed Feb 28, 2013
1 parent d5c7409 commit ce23bba
Showing 1 changed file with 5 additions and 8 deletions.
13 changes: 5 additions & 8 deletions block/genhd.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ static DEFINE_MUTEX(block_class_lock);
struct kobject *block_depr;

/* for extended dynamic devt allocation, currently only one major is used */
#define MAX_EXT_DEVT (1 << MINORBITS)
#define NR_EXT_DEVT (1 << MINORBITS)

/* For extended devt allocation. ext_devt_mutex prevents look up
* results from going away underneath its user.
Expand Down Expand Up @@ -425,19 +425,16 @@ int blk_alloc_devt(struct hd_struct *part, dev_t *devt)
return -ENOMEM;
mutex_lock(&ext_devt_mutex);
rc = idr_get_new(&ext_devt_idr, part, &idx);
if (!rc && idx >= NR_EXT_DEVT) {
idr_remove(&ext_devt_idr, idx);
rc = -EBUSY;
}
mutex_unlock(&ext_devt_mutex);
} while (rc == -EAGAIN);

if (rc)
return rc;

if (idx > MAX_EXT_DEVT) {
mutex_lock(&ext_devt_mutex);
idr_remove(&ext_devt_idr, idx);
mutex_unlock(&ext_devt_mutex);
return -EBUSY;
}

*devt = MKDEV(BLOCK_EXT_MAJOR, blk_mangle_minor(idx));
return 0;
}
Expand Down

0 comments on commit ce23bba

Please sign in to comment.