^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, ®ion_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, ®ion_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, ®ion_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");