Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2)  * Copyright (C) 2010-2012 by Dell Inc.  All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * Copyright (C) 2011-2013 Red Hat, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * This file is released under the GPL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  * dm-switch is a device-mapper target that maps IO to underlying block
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  * devices efficiently when there are a large number of fixed-sized
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  * address regions but there is no simple pattern to allow for a compact
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  * mapping representation such as dm-stripe.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) #include <linux/device-mapper.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) #include <linux/vmalloc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) #define DM_MSG_PREFIX "switch"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22)  * One region_table_slot_t holds <region_entries_per_slot> region table
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23)  * entries each of which is <region_table_entry_bits> in size.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) typedef unsigned long region_table_slot_t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28)  * A device with the offset to its start sector.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) struct switch_path {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) 	struct dm_dev *dmdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 	sector_t start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36)  * Context block for a dm switch device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) struct switch_ctx {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 	struct dm_target *ti;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 	unsigned nr_paths;		/* Number of paths in path_list. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 	unsigned region_size;		/* Region size in 512-byte sectors */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 	unsigned long nr_regions;	/* Number of regions making up the device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) 	signed char region_size_bits;	/* log2 of region_size or -1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 	unsigned char region_table_entry_bits;	/* Number of bits in one region table entry */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 	unsigned char region_entries_per_slot;	/* Number of entries in one region table slot */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 	signed char region_entries_per_slot_bits;	/* log2 of region_entries_per_slot or -1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 	region_table_slot_t *region_table;	/* Region table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	 * Array of dm devices to switch between.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 	struct switch_path path_list[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) static struct switch_ctx *alloc_switch_ctx(struct dm_target *ti, unsigned nr_paths,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 					   unsigned region_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 	struct switch_ctx *sctx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 	sctx = kzalloc(struct_size(sctx, path_list, nr_paths), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 	if (!sctx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 	sctx->ti = ti;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 	sctx->region_size = region_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 	ti->private = sctx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 	return sctx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) static int alloc_region_table(struct dm_target *ti, unsigned nr_paths)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 	struct switch_ctx *sctx = ti->private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 	sector_t nr_regions = ti->len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 	sector_t nr_slots;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 	if (!(sctx->region_size & (sctx->region_size - 1)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 		sctx->region_size_bits = __ffs(sctx->region_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 		sctx->region_size_bits = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 	sctx->region_table_entry_bits = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 	while (sctx->region_table_entry_bits < sizeof(region_table_slot_t) * 8 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 	       (region_table_slot_t)1 << sctx->region_table_entry_bits < nr_paths)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 		sctx->region_table_entry_bits++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 	sctx->region_entries_per_slot = (sizeof(region_table_slot_t) * 8) / sctx->region_table_entry_bits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 	if (!(sctx->region_entries_per_slot & (sctx->region_entries_per_slot - 1)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 		sctx->region_entries_per_slot_bits = __ffs(sctx->region_entries_per_slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 		sctx->region_entries_per_slot_bits = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 	if (sector_div(nr_regions, sctx->region_size))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 		nr_regions++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 	if (nr_regions >= ULONG_MAX) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 		ti->error = "Region table too large";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 	sctx->nr_regions = nr_regions;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 	nr_slots = nr_regions;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 	if (sector_div(nr_slots, sctx->region_entries_per_slot))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 		nr_slots++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 	if (nr_slots > ULONG_MAX / sizeof(region_table_slot_t)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 		ti->error = "Region table too large";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 	sctx->region_table = vmalloc(array_size(nr_slots,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 						sizeof(region_table_slot_t)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 	if (!sctx->region_table) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 		ti->error = "Cannot allocate region table";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) static void switch_get_position(struct switch_ctx *sctx, unsigned long region_nr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 				unsigned long *region_index, unsigned *bit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 	if (sctx->region_entries_per_slot_bits >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 		*region_index = region_nr >> sctx->region_entries_per_slot_bits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 		*bit = region_nr & (sctx->region_entries_per_slot - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 		*region_index = region_nr / sctx->region_entries_per_slot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 		*bit = region_nr % sctx->region_entries_per_slot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 	*bit *= sctx->region_table_entry_bits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) static unsigned switch_region_table_read(struct switch_ctx *sctx, unsigned long region_nr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 	unsigned long region_index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 	unsigned bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 	switch_get_position(sctx, region_nr, &region_index, &bit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 	return (READ_ONCE(sctx->region_table[region_index]) >> bit) &
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 		((1 << sctx->region_table_entry_bits) - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)  * Find which path to use at given offset.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) static unsigned switch_get_path_nr(struct switch_ctx *sctx, sector_t offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 	unsigned path_nr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 	sector_t p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 	p = offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 	if (sctx->region_size_bits >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 		p >>= sctx->region_size_bits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 		sector_div(p, sctx->region_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 	path_nr = switch_region_table_read(sctx, p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 	/* This can only happen if the processor uses non-atomic stores. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 	if (unlikely(path_nr >= sctx->nr_paths))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 		path_nr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 	return path_nr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) static void switch_region_table_write(struct switch_ctx *sctx, unsigned long region_nr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 				      unsigned value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 	unsigned long region_index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 	unsigned bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 	region_table_slot_t pte;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 	switch_get_position(sctx, region_nr, &region_index, &bit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 	pte = sctx->region_table[region_index];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 	pte &= ~((((region_table_slot_t)1 << sctx->region_table_entry_bits) - 1) << bit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 	pte |= (region_table_slot_t)value << bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 	sctx->region_table[region_index] = pte;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)  * Fill the region table with an initial round robin pattern.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) static void initialise_region_table(struct switch_ctx *sctx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 	unsigned path_nr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 	unsigned long region_nr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 	for (region_nr = 0; region_nr < sctx->nr_regions; region_nr++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 		switch_region_table_write(sctx, region_nr, path_nr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 		if (++path_nr >= sctx->nr_paths)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 			path_nr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) static int parse_path(struct dm_arg_set *as, struct dm_target *ti)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 	struct switch_ctx *sctx = ti->private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 	unsigned long long start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 	int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 	r = dm_get_device(ti, dm_shift_arg(as), dm_table_get_mode(ti->table),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 			  &sctx->path_list[sctx->nr_paths].dmdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 	if (r) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 		ti->error = "Device lookup failed";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 		return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 	if (kstrtoull(dm_shift_arg(as), 10, &start) || start != (sector_t)start) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 		ti->error = "Invalid device starting offset";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 		dm_put_device(ti, sctx->path_list[sctx->nr_paths].dmdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 	sctx->path_list[sctx->nr_paths].start = start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 	sctx->nr_paths++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)  * Destructor: Don't free the dm_target, just the ti->private data (if any).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) static void switch_dtr(struct dm_target *ti)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 	struct switch_ctx *sctx = ti->private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 	while (sctx->nr_paths--)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 		dm_put_device(ti, sctx->path_list[sctx->nr_paths].dmdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 	vfree(sctx->region_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 	kfree(sctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)  * Constructor arguments:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)  *   <num_paths> <region_size> <num_optional_args> [<optional_args>...]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)  *   [<dev_path> <offset>]+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)  * Optional args are to allow for future extension: currently this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)  * parameter must be 0.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) static int switch_ctr(struct dm_target *ti, unsigned argc, char **argv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 	static const struct dm_arg _args[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 		{1, (KMALLOC_MAX_SIZE - sizeof(struct switch_ctx)) / sizeof(struct switch_path), "Invalid number of paths"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 		{1, UINT_MAX, "Invalid region size"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 		{0, 0, "Invalid number of optional args"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 	};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 	struct switch_ctx *sctx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 	struct dm_arg_set as;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 	unsigned nr_paths, region_size, nr_optional_args;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 	int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 	as.argc = argc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 	as.argv = argv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 	r = dm_read_arg(_args, &as, &nr_paths, &ti->error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 	if (r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 	r = dm_read_arg(_args + 1, &as, &region_size, &ti->error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 	if (r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 		return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 	r = dm_read_arg_group(_args + 2, &as, &nr_optional_args, &ti->error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 	if (r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) 		return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 	/* parse optional arguments here, if we add any */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 	if (as.argc != nr_paths * 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 		ti->error = "Incorrect number of path arguments";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 	sctx = alloc_switch_ctx(ti, nr_paths, region_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 	if (!sctx) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 		ti->error = "Cannot allocate redirection context";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 	r = dm_set_target_max_io_len(ti, region_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 	if (r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 		goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) 	while (as.argc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 		r = parse_path(&as, ti);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 		if (r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 			goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 	r = alloc_region_table(ti, nr_paths);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 	if (r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 		goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 	initialise_region_table(sctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) 	/* For UNMAP, sending the request down any path is sufficient */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 	ti->num_discard_bios = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 	switch_dtr(ti);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) 	return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) static int switch_map(struct dm_target *ti, struct bio *bio)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) 	struct switch_ctx *sctx = ti->private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) 	sector_t offset = dm_target_offset(ti, bio->bi_iter.bi_sector);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 	unsigned path_nr = switch_get_path_nr(sctx, offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) 	bio_set_dev(bio, sctx->path_list[path_nr].dmdev->bdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) 	bio->bi_iter.bi_sector = sctx->path_list[path_nr].start + offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) 	return DM_MAPIO_REMAPPED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)  * We need to parse hex numbers in the message as quickly as possible.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334)  * This table-based hex parser improves performance.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)  * It improves a time to load 1000000 entries compared to the condition-based
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)  * parser.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)  *		table-based parser	condition-based parser
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)  * PA-RISC	0.29s			0.31s
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)  * Opteron	0.0495s			0.0498s
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) static const unsigned char hex_table[256] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) static __always_inline unsigned long parse_hex(const char **string)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) 	unsigned char d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) 	unsigned long r = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) 	while ((d = hex_table[(unsigned char)**string]) < 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) 		r = (r << 4) | d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) 		(*string)++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) 	return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) static int process_set_region_mappings(struct switch_ctx *sctx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) 				       unsigned argc, char **argv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) 	unsigned i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) 	unsigned long region_index = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) 	for (i = 1; i < argc; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) 		unsigned long path_nr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) 		const char *string = argv[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) 		if ((*string & 0xdf) == 'R') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) 			unsigned long cycle_length, num_write;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) 			string++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) 			if (unlikely(*string == ',')) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) 				DMWARN("invalid set_region_mappings argument: '%s'", argv[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) 				return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) 			cycle_length = parse_hex(&string);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) 			if (unlikely(*string != ',')) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) 				DMWARN("invalid set_region_mappings argument: '%s'", argv[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) 				return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) 			string++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) 			if (unlikely(!*string)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) 				DMWARN("invalid set_region_mappings argument: '%s'", argv[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) 				return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) 			num_write = parse_hex(&string);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) 			if (unlikely(*string)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) 				DMWARN("invalid set_region_mappings argument: '%s'", argv[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) 				return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) 			if (unlikely(!cycle_length) || unlikely(cycle_length - 1 > region_index)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) 				DMWARN("invalid set_region_mappings cycle length: %lu > %lu",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) 				       cycle_length - 1, region_index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) 				return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) 			if (unlikely(region_index + num_write < region_index) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) 			    unlikely(region_index + num_write >= sctx->nr_regions)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) 				DMWARN("invalid set_region_mappings region number: %lu + %lu >= %lu",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) 				       region_index, num_write, sctx->nr_regions);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) 				return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) 			while (num_write--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) 				region_index++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) 				path_nr = switch_region_table_read(sctx, region_index - cycle_length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) 				switch_region_table_write(sctx, region_index, path_nr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) 		if (*string == ':')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) 			region_index++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) 		else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) 			region_index = parse_hex(&string);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) 			if (unlikely(*string != ':')) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) 				DMWARN("invalid set_region_mappings argument: '%s'", argv[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) 				return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) 		string++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) 		if (unlikely(!*string)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) 			DMWARN("invalid set_region_mappings argument: '%s'", argv[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) 		path_nr = parse_hex(&string);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) 		if (unlikely(*string)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) 			DMWARN("invalid set_region_mappings argument: '%s'", argv[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) 		if (unlikely(region_index >= sctx->nr_regions)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) 			DMWARN("invalid set_region_mappings region number: %lu >= %lu", region_index, sctx->nr_regions);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) 		if (unlikely(path_nr >= sctx->nr_paths)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) 			DMWARN("invalid set_region_mappings device: %lu >= %u", path_nr, sctx->nr_paths);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) 		switch_region_table_write(sctx, region_index, path_nr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)  * Messages are processed one-at-a-time.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467)  * Only set_region_mappings is supported.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) static int switch_message(struct dm_target *ti, unsigned argc, char **argv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) 			  char *result, unsigned maxlen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) 	static DEFINE_MUTEX(message_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) 	struct switch_ctx *sctx = ti->private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) 	int r = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) 	mutex_lock(&message_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) 	if (!strcasecmp(argv[0], "set_region_mappings"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) 		r = process_set_region_mappings(sctx, argc, argv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) 		DMWARN("Unrecognised message received.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) 	mutex_unlock(&message_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) 	return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) static void switch_status(struct dm_target *ti, status_type_t type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) 			  unsigned status_flags, char *result, unsigned maxlen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) 	struct switch_ctx *sctx = ti->private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) 	unsigned sz = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) 	int path_nr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) 	switch (type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) 	case STATUSTYPE_INFO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) 		result[0] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) 	case STATUSTYPE_TABLE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) 		DMEMIT("%u %u 0", sctx->nr_paths, sctx->region_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) 		for (path_nr = 0; path_nr < sctx->nr_paths; path_nr++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) 			DMEMIT(" %s %llu", sctx->path_list[path_nr].dmdev->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) 			       (unsigned long long)sctx->path_list[path_nr].start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511)  * Switch ioctl:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513)  * Passthrough all ioctls to the path for sector 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) static int switch_prepare_ioctl(struct dm_target *ti, struct block_device **bdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) 	struct switch_ctx *sctx = ti->private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) 	unsigned path_nr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) 	path_nr = switch_get_path_nr(sctx, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) 	*bdev = sctx->path_list[path_nr].dmdev->bdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) 	 * Only pass ioctls through if the device sizes match exactly.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) 	if (ti->len + sctx->path_list[path_nr].start !=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) 	    i_size_read((*bdev)->bd_inode) >> SECTOR_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) 		return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) static int switch_iterate_devices(struct dm_target *ti,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) 				  iterate_devices_callout_fn fn, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) 	struct switch_ctx *sctx = ti->private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) 	int path_nr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) 	int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) 	for (path_nr = 0; path_nr < sctx->nr_paths; path_nr++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) 		r = fn(ti, sctx->path_list[path_nr].dmdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) 			 sctx->path_list[path_nr].start, ti->len, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) 		if (r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) 			return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) static struct target_type switch_target = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) 	.name = "switch",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) 	.version = {1, 1, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) 	.module = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) 	.ctr = switch_ctr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) 	.dtr = switch_dtr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) 	.map = switch_map,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) 	.message = switch_message,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) 	.status = switch_status,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) 	.prepare_ioctl = switch_prepare_ioctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) 	.iterate_devices = switch_iterate_devices,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) static int __init dm_switch_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) 	int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) 	r = dm_register_target(&switch_target);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) 	if (r < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) 		DMERR("dm_register_target() failed %d", r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) 	return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) static void __exit dm_switch_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) 	dm_unregister_target(&switch_target);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) module_init(dm_switch_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) module_exit(dm_switch_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) MODULE_DESCRIPTION(DM_NAME " dynamic path switching target");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) MODULE_AUTHOR("Kevin D. O'Kelley <Kevin_OKelley@dell.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) MODULE_AUTHOR("Narendran Ganapathy <Narendran_Ganapathy@dell.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) MODULE_AUTHOR("Jim Ramsay <Jim_Ramsay@dell.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) MODULE_AUTHOR("Mikulas Patocka <mpatocka@redhat.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) MODULE_LICENSE("GPL");