aboutsummaryrefslogtreecommitdiffstats
path: root/block/genhd.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2008-08-25 06:47:25 -0400
committerJens Axboe <jens.axboe@oracle.com>2008-10-09 02:56:06 -0400
commit870d6656126add8e383645732b03df2b7ccd4f94 (patch)
tree9c33dd91350ea163b160d9f5cb40d913c5caf268 /block/genhd.c
parentf615b48cc7df7cac3865ec76ac1a5bb04d3e07f4 (diff)
block: implement CONFIG_DEBUG_BLOCK_EXT_DEVT
Extended devt introduces non-contiguos device numbers. This patch implements a debug option which forces most devt allocations to be from the extended area and spreads them out. This is enabled by default if DEBUG_KERNEL is set and achieves... 1. Detects code paths in kernel or userland which expect predetermined consecutive device numbers. 2. When something goes wrong, avoid corruption as adding to the minor of earlier partition won't lead to the wrong but valid device. Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'block/genhd.c')
-rw-r--r--block/genhd.c38
1 files changed, 35 insertions, 3 deletions
diff --git a/block/genhd.c b/block/genhd.c
index ee4b13520e59..67e5a59ced2a 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -299,6 +299,38 @@ EXPORT_SYMBOL(unregister_blkdev);
299static struct kobj_map *bdev_map; 299static struct kobj_map *bdev_map;
300 300
301/** 301/**
302 * blk_mangle_minor - scatter minor numbers apart
303 * @minor: minor number to mangle
304 *
305 * Scatter consecutively allocated @minor number apart if MANGLE_DEVT
306 * is enabled. Mangling twice gives the original value.
307 *
308 * RETURNS:
309 * Mangled value.
310 *
311 * CONTEXT:
312 * Don't care.
313 */
314static int blk_mangle_minor(int minor)
315{
316#ifdef CONFIG_DEBUG_BLOCK_EXT_DEVT
317 int i;
318
319 for (i = 0; i < MINORBITS / 2; i++) {
320 int low = minor & (1 << i);
321 int high = minor & (1 << (MINORBITS - 1 - i));
322 int distance = MINORBITS - 1 - 2 * i;
323
324 minor ^= low | high; /* clear both bits */
325 low <<= distance; /* swap the positions */
326 high >>= distance;
327 minor |= low | high; /* and set */
328 }
329#endif
330 return minor;
331}
332
333/**
302 * blk_alloc_devt - allocate a dev_t for a partition 334 * blk_alloc_devt - allocate a dev_t for a partition
303 * @part: partition to allocate dev_t for 335 * @part: partition to allocate dev_t for
304 * @gfp_mask: memory allocation flag 336 * @gfp_mask: memory allocation flag
@@ -339,7 +371,7 @@ int blk_alloc_devt(struct hd_struct *part, dev_t *devt)
339 return -EBUSY; 371 return -EBUSY;
340 } 372 }
341 373
342 *devt = MKDEV(BLOCK_EXT_MAJOR, idx); 374 *devt = MKDEV(BLOCK_EXT_MAJOR, blk_mangle_minor(idx));
343 return 0; 375 return 0;
344} 376}
345 377
@@ -361,7 +393,7 @@ void blk_free_devt(dev_t devt)
361 393
362 if (MAJOR(devt) == BLOCK_EXT_MAJOR) { 394 if (MAJOR(devt) == BLOCK_EXT_MAJOR) {
363 mutex_lock(&ext_devt_mutex); 395 mutex_lock(&ext_devt_mutex);
364 idr_remove(&ext_devt_idr, MINOR(devt)); 396 idr_remove(&ext_devt_idr, blk_mangle_minor(MINOR(devt)));
365 mutex_unlock(&ext_devt_mutex); 397 mutex_unlock(&ext_devt_mutex);
366 } 398 }
367} 399}
@@ -473,7 +505,7 @@ struct gendisk *get_gendisk(dev_t devt, int *partno)
473 struct hd_struct *part; 505 struct hd_struct *part;
474 506
475 mutex_lock(&ext_devt_mutex); 507 mutex_lock(&ext_devt_mutex);
476 part = idr_find(&ext_devt_idr, MINOR(devt)); 508 part = idr_find(&ext_devt_idr, blk_mangle_minor(MINOR(devt)));
477 if (part && get_disk(part_to_disk(part))) { 509 if (part && get_disk(part_to_disk(part))) {
478 *partno = part->partno; 510 *partno = part->partno;
479 disk = part_to_disk(part); 511 disk = part_to_disk(part);