drivers/md/dm-switch.c

Source file repositories/reference/linux-study-clean/drivers/md/dm-switch.c

File Facts

System
Linux kernel
Corpus path
drivers/md/dm-switch.c
Extension
.c
Size
15600 bytes
Lines
578
Domain
Driver Families
Bucket
drivers/md
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct switch_path {
	struct dm_dev *dmdev;
	sector_t start;
};

/*
 * Context block for a dm switch device.
 */
struct switch_ctx {
	struct dm_target *ti;

	unsigned int nr_paths;		/* Number of paths in path_list. */

	unsigned int region_size;		/* Region size in 512-byte sectors */
	unsigned long nr_regions;	/* Number of regions making up the device */
	signed char region_size_bits;	/* log2 of region_size or -1 */

	unsigned char region_table_entry_bits;	/* Number of bits in one region table entry */
	unsigned char region_entries_per_slot;	/* Number of entries in one region table slot */
	signed char region_entries_per_slot_bits;	/* log2 of region_entries_per_slot or -1 */

	region_table_slot_t *region_table;	/* Region table */

	/*
	 * Array of dm devices to switch between.
	 */
	struct switch_path path_list[];
};

static struct switch_ctx *alloc_switch_ctx(struct dm_target *ti, unsigned int nr_paths,
					   unsigned int region_size)
{
	struct switch_ctx *sctx;

	sctx = kzalloc_flex(*sctx, path_list, nr_paths);
	if (!sctx)
		return NULL;

	sctx->ti = ti;
	sctx->region_size = region_size;

	ti->private = sctx;

	return sctx;
}

static int alloc_region_table(struct dm_target *ti, unsigned int nr_paths)
{
	struct switch_ctx *sctx = ti->private;
	sector_t nr_regions = ti->len;
	sector_t nr_slots;

	if (!(sctx->region_size & (sctx->region_size - 1)))
		sctx->region_size_bits = __ffs(sctx->region_size);
	else
		sctx->region_size_bits = -1;

	sctx->region_table_entry_bits = 1;
	while (sctx->region_table_entry_bits < sizeof(region_table_slot_t) * 8 &&
	       (region_table_slot_t)1 << sctx->region_table_entry_bits < nr_paths)
		sctx->region_table_entry_bits++;

	sctx->region_entries_per_slot = (sizeof(region_table_slot_t) * 8) / sctx->region_table_entry_bits;
	if (!(sctx->region_entries_per_slot & (sctx->region_entries_per_slot - 1)))
		sctx->region_entries_per_slot_bits = __ffs(sctx->region_entries_per_slot);
	else
		sctx->region_entries_per_slot_bits = -1;

	if (sector_div(nr_regions, sctx->region_size))
		nr_regions++;

	if (nr_regions >= ULONG_MAX) {
		ti->error = "Region table too large";
		return -EINVAL;
	}
	sctx->nr_regions = nr_regions;

	nr_slots = nr_regions;
	if (sector_div(nr_slots, sctx->region_entries_per_slot))
		nr_slots++;

	if (nr_slots > ULONG_MAX / sizeof(region_table_slot_t)) {
		ti->error = "Region table too large";
		return -EINVAL;
	}

	sctx->region_table = vmalloc_array(nr_slots,
					   sizeof(region_table_slot_t));
	if (!sctx->region_table) {
		ti->error = "Cannot allocate region table";

Annotation

Implementation Notes