Commit 870d6656126add8e383645732b03df2b7ccd4f94

Authored by Tejun Heo
Committed by Jens Axboe
1 parent f615b48cc7

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>

Showing 4 changed files with 63 additions and 3 deletions Side-by-side Diff

... ... @@ -299,6 +299,38 @@
299 299 static 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 + */
  314 +static 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 334 * blk_alloc_devt - allocate a dev_t for a partition
303 335 * @part: partition to allocate dev_t for
304 336 * @gfp_mask: memory allocation flag
... ... @@ -339,7 +371,7 @@
339 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 375 return 0;
344 376 }
345 377  
... ... @@ -361,7 +393,7 @@
361 393  
362 394 if (MAJOR(devt) == BLOCK_EXT_MAJOR) {
363 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 397 mutex_unlock(&ext_devt_mutex);
366 398 }
367 399 }
... ... @@ -473,7 +505,7 @@
473 505 struct hd_struct *part;
474 506  
475 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 509 if (part && get_disk(part_to_disk(part))) {
478 510 *partno = part->partno;
479 511 disk = part_to_disk(part);
drivers/ide/ide-disk.c
... ... @@ -42,7 +42,13 @@
42 42 #include <asm/div64.h>
43 43  
44 44 #define IDE_DISK_PARTS (1 << PARTN_BITS)
  45 +
  46 +#if !defined(CONFIG_DEBUG_BLOCK_EXT_DEVT)
45 47 #define IDE_DISK_MINORS IDE_DISK_PARTS
  48 +#else
  49 +#define IDE_DISK_MINORS 1
  50 +#endif
  51 +
46 52 #define IDE_DISK_EXT_MINORS (IDE_DISK_PARTS - IDE_DISK_MINORS)
47 53  
48 54 struct ide_disk_obj {
... ... @@ -87,7 +87,13 @@
87 87 MODULE_ALIAS_SCSI_DEVICE(TYPE_RBC);
88 88  
89 89 #define SD_PARTS 64
  90 +
  91 +#if !defined(CONFIG_DEBUG_BLOCK_EXT_DEVT)
90 92 #define SD_MINORS 16
  93 +#else
  94 +#define SD_MINORS 1
  95 +#endif
  96 +
91 97 #define SD_EXT_MINORS (SD_PARTS - SD_MINORS)
92 98  
93 99 static int sd_revalidate_disk(struct gendisk *);
... ... @@ -624,6 +624,22 @@
624 624  
625 625 Say N if you are unsure.
626 626  
  627 +config DEBUG_BLOCK_EXT_DEVT
  628 + bool "Force extended block device numbers and spread them"
  629 + depends on DEBUG_KERNEL
  630 + depends on BLOCK
  631 + default y
  632 + help
  633 + Conventionally, block device numbers are allocated from
  634 + predetermined contiguous area. However, extended block area
  635 + may introduce non-contiguous block device numbers. This
  636 + option forces most block device numbers to be allocated from
  637 + the extended space and spreads them to discover kernel or
  638 + userland code paths which assume predetermined contiguous
  639 + device number allocation.
  640 +
  641 + Say N if you are unsure.
  642 +
627 643 config LKDTM
628 644 tristate "Linux Kernel Dump Test Tool Module"
629 645 depends on DEBUG_KERNEL