Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 870d6656 authored by Tejun Heo's avatar Tejun Heo Committed by Jens Axboe
Browse files

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: default avatarTejun Heo <tj@kernel.org>
Signed-off-by: default avatarJens Axboe <jens.axboe@oracle.com>
parent f615b48c
Loading
Loading
Loading
Loading
+35 −3
Original line number Diff line number Diff line
@@ -298,6 +298,38 @@ EXPORT_SYMBOL(unregister_blkdev);

static struct kobj_map *bdev_map;

/**
 * blk_mangle_minor - scatter minor numbers apart
 * @minor: minor number to mangle
 *
 * Scatter consecutively allocated @minor number apart if MANGLE_DEVT
 * is enabled.  Mangling twice gives the original value.
 *
 * RETURNS:
 * Mangled value.
 *
 * CONTEXT:
 * Don't care.
 */
static int blk_mangle_minor(int minor)
{
#ifdef CONFIG_DEBUG_BLOCK_EXT_DEVT
	int i;

	for (i = 0; i < MINORBITS / 2; i++) {
		int low = minor & (1 << i);
		int high = minor & (1 << (MINORBITS - 1 - i));
		int distance = MINORBITS - 1 - 2 * i;

		minor ^= low | high;	/* clear both bits */
		low <<= distance;	/* swap the positions */
		high >>= distance;
		minor |= low | high;	/* and set */
	}
#endif
	return minor;
}

/**
 * blk_alloc_devt - allocate a dev_t for a partition
 * @part: partition to allocate dev_t for
@@ -339,7 +371,7 @@ int blk_alloc_devt(struct hd_struct *part, dev_t *devt)
		return -EBUSY;
	}

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

@@ -361,7 +393,7 @@ void blk_free_devt(dev_t devt)

	if (MAJOR(devt) == BLOCK_EXT_MAJOR) {
		mutex_lock(&ext_devt_mutex);
		idr_remove(&ext_devt_idr, MINOR(devt));
		idr_remove(&ext_devt_idr, blk_mangle_minor(MINOR(devt)));
		mutex_unlock(&ext_devt_mutex);
	}
}
@@ -473,7 +505,7 @@ struct gendisk *get_gendisk(dev_t devt, int *partno)
		struct hd_struct *part;

		mutex_lock(&ext_devt_mutex);
		part = idr_find(&ext_devt_idr, MINOR(devt));
		part = idr_find(&ext_devt_idr, blk_mangle_minor(MINOR(devt)));
		if (part && get_disk(part_to_disk(part))) {
			*partno = part->partno;
			disk = part_to_disk(part);
+6 −0
Original line number Diff line number Diff line
@@ -42,7 +42,13 @@
#include <asm/div64.h>

#define IDE_DISK_PARTS		(1 << PARTN_BITS)

#if !defined(CONFIG_DEBUG_BLOCK_EXT_DEVT)
#define IDE_DISK_MINORS		IDE_DISK_PARTS
#else
#define IDE_DISK_MINORS		1
#endif

#define IDE_DISK_EXT_MINORS	(IDE_DISK_PARTS - IDE_DISK_MINORS)

struct ide_disk_obj {
+6 −0
Original line number Diff line number Diff line
@@ -87,7 +87,13 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_MOD);
MODULE_ALIAS_SCSI_DEVICE(TYPE_RBC);

#define SD_PARTS	64

#if !defined(CONFIG_DEBUG_BLOCK_EXT_DEVT)
#define SD_MINORS	16
#else
#define SD_MINORS	1
#endif

#define SD_EXT_MINORS	(SD_PARTS - SD_MINORS)

static int  sd_revalidate_disk(struct gendisk *);
+16 −0
Original line number Diff line number Diff line
@@ -624,6 +624,22 @@ config BACKTRACE_SELF_TEST

	  Say N if you are unsure.

config DEBUG_BLOCK_EXT_DEVT
        bool "Force extended block device numbers and spread them"
	depends on DEBUG_KERNEL
	depends on BLOCK
	default y
	help
	  Conventionally, block device numbers are allocated from
	  predetermined contiguous area.  However, extended block area
	  may introduce non-contiguous block device numbers.  This
	  option forces most block device numbers to be allocated from
	  the extended space and spreads them to discover kernel or
	  userland code paths which assume predetermined contiguous
	  device number allocation.

	  Say N if you are unsure.

config LKDTM
	tristate "Linux Kernel Dump Test Tool Module"
	depends on DEBUG_KERNEL