1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2017 Intel Corporation. 4 * 5 * This file is released under the GPL. 6 */ 7 8 #include "dm.h" 9 10 #include <linux/module.h> 11 12 struct unstripe_c { 13 struct dm_dev *dev; 14 sector_t physical_start; 15 16 uint32_t stripes; 17 18 uint32_t unstripe; 19 sector_t unstripe_width; 20 sector_t unstripe_offset; 21 22 uint32_t chunk_size; 23 u8 chunk_shift; 24 }; 25 26 #define DM_MSG_PREFIX "unstriped" 27 28 static void cleanup_unstripe(struct unstripe_c *uc, struct dm_target *ti) 29 { 30 if (uc->dev) 31 dm_put_device(ti, uc->dev); 32 kfree(uc); 33 } 34 35 /* 36 * Contruct an unstriped mapping. 37 * <number of stripes> <chunk size> <stripe #> <dev_path> <offset> 38 */ 39 static int unstripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) 40 { 41 struct unstripe_c *uc; 42 sector_t tmp_len; 43 unsigned long long start; 44 char dummy; 45 46 if (argc != 5) { 47 ti->error = "Invalid number of arguments"; 48 return -EINVAL; 49 } 50 51 uc = kzalloc(sizeof(*uc), GFP_KERNEL); 52 if (!uc) { 53 ti->error = "Memory allocation for unstriped context failed"; 54 return -ENOMEM; 55 } 56 57 if (kstrtouint(argv[0], 10, &uc->stripes) || !uc->stripes) { 58 ti->error = "Invalid stripe count"; 59 goto err; 60 } 61 62 if (kstrtouint(argv[1], 10, &uc->chunk_size) || !uc->chunk_size) { 63 ti->error = "Invalid chunk_size"; 64 goto err; 65 } 66 67 if (kstrtouint(argv[2], 10, &uc->unstripe)) { 68 ti->error = "Invalid stripe number"; 69 goto err; 70 } 71 72 if (uc->unstripe > uc->stripes && uc->stripes > 1) { 73 ti->error = "Please provide stripe between [0, # of stripes]"; 74 goto err; 75 } 76 77 if (dm_get_device(ti, argv[3], dm_table_get_mode(ti->table), &uc->dev)) { 78 ti->error = "Couldn't get striped device"; 79 goto err; 80 } 81 82 if (sscanf(argv[4], "%llu%c", &start, &dummy) != 1 || start != (sector_t)start) { 83 ti->error = "Invalid striped device offset"; 84 goto err; 85 } 86 uc->physical_start = start; 87 88 uc->unstripe_offset = (sector_t)uc->unstripe * uc->chunk_size; 89 uc->unstripe_width = (sector_t)(uc->stripes - 1) * uc->chunk_size; 90 uc->chunk_shift = is_power_of_2(uc->chunk_size) ? fls(uc->chunk_size) - 1 : 0; 91 92 tmp_len = ti->len; 93 if (sector_div(tmp_len, uc->chunk_size)) { 94 ti->error = "Target length not divisible by chunk size"; 95 goto err; 96 } 97 98 if (dm_set_target_max_io_len(ti, uc->chunk_size)) { 99 ti->error = "Failed to set max io len"; 100 goto err; 101 } 102 103 ti->private = uc; 104 return 0; 105 err: 106 cleanup_unstripe(uc, ti); 107 return -EINVAL; 108 } 109 110 static void unstripe_dtr(struct dm_target *ti) 111 { 112 struct unstripe_c *uc = ti->private; 113 114 cleanup_unstripe(uc, ti); 115 } 116 117 static sector_t map_to_core(struct dm_target *ti, struct bio *bio) 118 { 119 struct unstripe_c *uc = ti->private; 120 sector_t sector = bio->bi_iter.bi_sector; 121 sector_t tmp_sector = sector; 122 123 /* Shift us up to the right "row" on the stripe */ 124 if (uc->chunk_shift) 125 tmp_sector >>= uc->chunk_shift; 126 else 127 sector_div(tmp_sector, uc->chunk_size); 128 129 sector += uc->unstripe_width * tmp_sector; 130 131 /* Account for what stripe we're operating on */ 132 return sector + uc->unstripe_offset; 133 } 134 135 static int unstripe_map(struct dm_target *ti, struct bio *bio) 136 { 137 struct unstripe_c *uc = ti->private; 138 139 bio_set_dev(bio, uc->dev->bdev); 140 bio->bi_iter.bi_sector = map_to_core(ti, bio) + uc->physical_start; 141 142 return DM_MAPIO_REMAPPED; 143 } 144 145 static void unstripe_status(struct dm_target *ti, status_type_t type, 146 unsigned int status_flags, char *result, unsigned int maxlen) 147 { 148 struct unstripe_c *uc = ti->private; 149 unsigned int sz = 0; 150 151 switch (type) { 152 case STATUSTYPE_INFO: 153 break; 154 155 case STATUSTYPE_TABLE: 156 DMEMIT("%d %llu %d %s %llu", 157 uc->stripes, (unsigned long long)uc->chunk_size, uc->unstripe, 158 uc->dev->name, (unsigned long long)uc->physical_start); 159 break; 160 161 case STATUSTYPE_IMA: 162 *result = '\0'; 163 break; 164 } 165 } 166 167 static int unstripe_iterate_devices(struct dm_target *ti, 168 iterate_devices_callout_fn fn, void *data) 169 { 170 struct unstripe_c *uc = ti->private; 171 172 return fn(ti, uc->dev, uc->physical_start, ti->len, data); 173 } 174 175 static void unstripe_io_hints(struct dm_target *ti, 176 struct queue_limits *limits) 177 { 178 struct unstripe_c *uc = ti->private; 179 180 limits->chunk_sectors = uc->chunk_size; 181 } 182 183 static struct target_type unstripe_target = { 184 .name = "unstriped", 185 .version = {1, 1, 0}, 186 .features = DM_TARGET_NOWAIT, 187 .module = THIS_MODULE, 188 .ctr = unstripe_ctr, 189 .dtr = unstripe_dtr, 190 .map = unstripe_map, 191 .status = unstripe_status, 192 .iterate_devices = unstripe_iterate_devices, 193 .io_hints = unstripe_io_hints, 194 }; 195 module_dm(unstripe); 196 197 MODULE_DESCRIPTION(DM_NAME " unstriped target"); 198 MODULE_ALIAS("dm-unstriped"); 199 MODULE_AUTHOR("Scott Bauer <scott.bauer@intel.com>"); 200 MODULE_LICENSE("GPL"); 201