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