| Commit | Line | Data |
|---|---|---|
| ff56536e AH |
1 | /* |
| 2 | * Copyright (c) 2009 The NetBSD Foundation, Inc. | |
| 3 | * All rights reserved. | |
| 4 | * | |
| 5 | * This code is derived from software contributed to The NetBSD Foundation | |
| 6 | * by Adam Hamsik. | |
| 7 | * | |
| 1446934e MD |
8 | * This code is further derived from software contributed to the |
| 9 | * DragonFly project by Alex Hornung and Matthew Dillon | |
| 10 | * | |
| ff56536e AH |
11 | * Redistribution and use in source and binary forms, with or without |
| 12 | * modification, are permitted provided that the following conditions | |
| 13 | * are met: | |
| 14 | * 1. Redistributions of source code must retain the above copyright | |
| 15 | * notice, this list of conditions and the following disclaimer. | |
| 16 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 17 | * notice, this list of conditions and the following disclaimer in the | |
| 18 | * documentation and/or other materials provided with the distribution. | |
| 19 | * | |
| 20 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
| 21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
| 22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
| 23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
| 24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
| 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
| 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
| 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
| 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
| 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| 30 | * POSSIBILITY OF SUCH DAMAGE. | |
| 1446934e MD |
31 | * |
| 32 | * $NetBSD: dm_target_stripe.c,v 1.9 2010/01/04 00:14:41 haad Exp $ | |
| ff56536e AH |
33 | */ |
| 34 | ||
| 35 | /* | |
| 36 | * This file implements initial version of device-mapper stripe target. | |
| 1446934e MD |
37 | * |
| 38 | * DragonFly changes: Increase to an unlimited number of stripes | |
| ff56536e AH |
39 | */ |
| 40 | #include <sys/types.h> | |
| 41 | #include <sys/param.h> | |
| 42 | ||
| 43 | #include <sys/buf.h> | |
| 5b279a20 | 44 | #include <sys/malloc.h> |
| ff56536e AH |
45 | #include <sys/vnode.h> |
| 46 | ||
| a84e173e | 47 | #include <dev/disk/dm/dm.h> |
| 5b279a20 | 48 | MALLOC_DEFINE(M_DMSTRIPE, "dm_stripe", "Device Mapper Target Stripe"); |
| ff56536e | 49 | |
| 1446934e MD |
50 | static void dm_target_stripe_destroy_config(dm_target_stripe_config_t *tsc); |
| 51 | ||
| ff56536e AH |
52 | /* |
| 53 | * Init function called from dm_table_load_ioctl. | |
| 1446934e | 54 | * |
| ff56536e AH |
55 | * Example line sent to dm from lvm tools when using striped target. |
| 56 | * start length striped #stripes chunk_size device1 offset1 ... deviceN offsetN | |
| 57 | * 0 65536 striped 2 512 /dev/hda 0 /dev/hdb 0 | |
| 58 | */ | |
| 5c411e8e | 59 | static int |
| 1446934e | 60 | dm_target_stripe_init(dm_dev_t *dmv, void **target_config, char *params) |
| ff56536e AH |
61 | { |
| 62 | dm_target_stripe_config_t *tsc; | |
| 1446934e MD |
63 | int n; |
| 64 | char *ap; | |
| ff56536e AH |
65 | |
| 66 | if (params == NULL) | |
| 67 | return EINVAL; | |
| 68 | ||
| ff56536e | 69 | /* |
| 1446934e | 70 | * nstripes |
| ff56536e | 71 | */ |
| 1446934e MD |
72 | ap = strsep(¶ms, " \t"); |
| 73 | if (ap == NULL) | |
| 74 | return EINVAL; | |
| 75 | n = (int)atoi64(ap); | |
| 76 | if (n < 0 || n > MAX_STRIPES) { | |
| 77 | kprintf("dm: Error %d stripes not supported (%d max)\n", | |
| 78 | n, MAX_STRIPES); | |
| ff56536e | 79 | return ENOTSUP; |
| 1446934e | 80 | } |
| ff56536e | 81 | |
| 1446934e MD |
82 | tsc = kmalloc(sizeof(dm_target_stripe_config_t), |
| 83 | M_DMSTRIPE, M_WAITOK | M_ZERO); | |
| 84 | tsc->stripe_num = n; | |
| ff56536e | 85 | |
| 1446934e MD |
86 | ap = strsep(¶ms, " \t"); |
| 87 | if (ap == NULL) | |
| 88 | return EINVAL; | |
| 89 | tsc->stripe_chunksize = atoi64(ap); | |
| 90 | if (tsc->stripe_chunksize < 1 || | |
| 91 | tsc->stripe_chunksize * DEV_BSIZE > MAXPHYS) { | |
| 92 | kprintf("dm: Error unsupported chunk size %jdKB\n", | |
| 93 | (intmax_t)tsc->stripe_chunksize * DEV_BSIZE / 1024); | |
| 94 | dm_target_stripe_destroy_config(tsc); | |
| 95 | return EINVAL; | |
| 96 | } | |
| ff56536e | 97 | |
| 1446934e MD |
98 | /* |
| 99 | * Parse the devices | |
| 100 | */ | |
| ff56536e | 101 | |
| 1446934e MD |
102 | kprintf("dm: Stripe %d devices chunk size %dKB\n", |
| 103 | (int)tsc->stripe_num, | |
| 104 | (int)tsc->stripe_chunksize | |
| 105 | ); | |
| ff56536e | 106 | |
| 1446934e MD |
107 | for (n = 0; n < tsc->stripe_num; ++n) { |
| 108 | ap = strsep(¶ms, " \t"); | |
| 109 | if (ap == NULL) | |
| 110 | break; | |
| 111 | tsc->stripe_devs[n].pdev = dm_pdev_insert(ap); | |
| 112 | if (tsc->stripe_devs[n].pdev == NULL) | |
| 113 | break; | |
| 114 | ap = strsep(¶ms, " \t"); | |
| 115 | if (ap == NULL) | |
| 116 | break; | |
| 117 | tsc->stripe_devs[n].offset = atoi64(ap); | |
| 118 | } | |
| 119 | if (n != tsc->stripe_num) { | |
| 120 | dm_target_stripe_destroy_config(tsc); | |
| 121 | return (ENOENT); | |
| 122 | } | |
| ff56536e AH |
123 | |
| 124 | *target_config = tsc; | |
| 125 | ||
| 126 | dmv->dev_type = DM_STRIPE_DEV; | |
| 127 | ||
| 128 | return 0; | |
| 129 | } | |
| 1446934e MD |
130 | |
| 131 | /* | |
| 132 | * Status routine called to get params string. | |
| 133 | */ | |
| 5c411e8e | 134 | static char * |
| ff56536e AH |
135 | dm_target_stripe_status(void *target_config) |
| 136 | { | |
| 137 | dm_target_stripe_config_t *tsc; | |
| 138 | char *params; | |
| 1446934e MD |
139 | char *ptr; |
| 140 | size_t len; | |
| 141 | size_t nlen; | |
| 142 | int n; | |
| ff56536e AH |
143 | |
| 144 | tsc = target_config; | |
| 145 | ||
| 1446934e MD |
146 | /* caller expects use of M_DM for returned params */ |
| 147 | nlen = DM_MAX_PARAMS_SIZE; | |
| 148 | params = kmalloc(nlen, M_DM, M_WAITOK); | |
| 149 | ptr = params; | |
| 150 | ||
| 151 | ksnprintf(ptr, nlen, "%d %jd", | |
| 152 | tsc->stripe_num, (intmax_t)tsc->stripe_chunksize); | |
| 153 | len = strlen(params); | |
| 154 | ptr += len; | |
| 155 | nlen -= len; | |
| 156 | ||
| 157 | for (n = 0; n < tsc->stripe_num; ++n) { | |
| 158 | ksnprintf(ptr, nlen, " %s %jd", | |
| 159 | tsc->stripe_devs[n].pdev->name, | |
| 160 | (intmax_t)tsc->stripe_devs[n].offset); | |
| 161 | len = strlen(ptr); | |
| 162 | ptr += len; | |
| 163 | nlen -= len; | |
| 164 | } | |
| ff56536e AH |
165 | |
| 166 | return params; | |
| 167 | } | |
| 1446934e MD |
168 | |
| 169 | /* | |
| 170 | * Strategy routine called from dm_strategy. | |
| 171 | */ | |
| 5c411e8e | 172 | static int |
| 1446934e | 173 | dm_target_stripe_strategy(dm_table_entry_t *table_en, struct buf *bp) |
| ff56536e AH |
174 | { |
| 175 | dm_target_stripe_config_t *tsc; | |
| 5b279a20 | 176 | struct bio *bio = &bp->b_bio1; |
| ff56536e AH |
177 | struct buf *nestbuf; |
| 178 | uint64_t blkno, blkoff; | |
| 3adc52bc | 179 | uint64_t stripe, blknr; |
| ff56536e | 180 | uint32_t stripe_off, stripe_rest, num_blks, issue_blks; |
| 3adc52bc | 181 | int devnr; |
| ff56536e AH |
182 | |
| 183 | tsc = table_en->target_config; | |
| 184 | if (tsc == NULL) | |
| 185 | return 0; | |
| 186 | ||
| ff56536e | 187 | /* calculate extent of request */ |
| 5b279a20 | 188 | KKASSERT(bp->b_resid % DEV_BSIZE == 0); |
| ff56536e | 189 | |
| 3adc52bc MD |
190 | switch(bp->b_cmd) { |
| 191 | case BUF_CMD_READ: | |
| 192 | case BUF_CMD_WRITE: | |
| 193 | case BUF_CMD_FREEBLKS: | |
| 194 | /* | |
| 195 | * Loop through to individual operations | |
| 196 | */ | |
| 197 | blkno = bp->b_bio1.bio_offset / DEV_BSIZE; | |
| 198 | blkoff = 0; | |
| 199 | num_blks = bp->b_resid / DEV_BSIZE; | |
| 200 | nestiobuf_init(bio); | |
| 201 | ||
| 202 | while (num_blks > 0) { | |
| 203 | /* blockno to strip piece nr */ | |
| 204 | stripe = blkno / tsc->stripe_chunksize; | |
| 205 | stripe_off = blkno % tsc->stripe_chunksize; | |
| 206 | ||
| 207 | /* where we are inside the strip */ | |
| 208 | devnr = stripe % tsc->stripe_num; | |
| 209 | blknr = stripe / tsc->stripe_num; | |
| 210 | ||
| 211 | /* how much is left before we hit a boundary */ | |
| 212 | stripe_rest = tsc->stripe_chunksize - stripe_off; | |
| 213 | ||
| 214 | /* issue this piece on stripe `stripe' */ | |
| 215 | issue_blks = MIN(stripe_rest, num_blks); | |
| 216 | nestbuf = getpbuf(NULL); | |
| f6221ad1 | 217 | nestbuf->b_flags |= bio->bio_buf->b_flags & B_HASBOGUS; |
| 3adc52bc MD |
218 | |
| 219 | nestiobuf_add(bio, nestbuf, blkoff, | |
| 3b48c3c1 | 220 | issue_blks * DEV_BSIZE, NULL); |
| 3adc52bc MD |
221 | |
| 222 | /* I need number of bytes. */ | |
| 223 | nestbuf->b_bio1.bio_offset = | |
| 224 | blknr * tsc->stripe_chunksize + stripe_off; | |
| 225 | nestbuf->b_bio1.bio_offset += | |
| 226 | tsc->stripe_devs[devnr].offset; | |
| 227 | nestbuf->b_bio1.bio_offset *= DEV_BSIZE; | |
| 228 | ||
| 229 | vn_strategy(tsc->stripe_devs[devnr].pdev->pdev_vnode, | |
| 230 | &nestbuf->b_bio1); | |
| 231 | ||
| 232 | blkno += issue_blks; | |
| 233 | blkoff += issue_blks * DEV_BSIZE; | |
| 234 | num_blks -= issue_blks; | |
| 235 | } | |
| 236 | nestiobuf_start(bio); | |
| 237 | break; | |
| 238 | case BUF_CMD_FLUSH: | |
| 239 | nestiobuf_init(bio); | |
| 240 | for (devnr = 0; devnr < tsc->stripe_num; ++devnr) { | |
| 241 | nestbuf = getpbuf(NULL); | |
| f6221ad1 | 242 | nestbuf->b_flags |= bio->bio_buf->b_flags & B_HASBOGUS; |
| 3adc52bc | 243 | |
| 3b48c3c1 | 244 | nestiobuf_add(bio, nestbuf, 0, 0, NULL); |
| 3adc52bc MD |
245 | nestbuf->b_bio1.bio_offset = 0; |
| 246 | vn_strategy(tsc->stripe_devs[devnr].pdev->pdev_vnode, | |
| 247 | &nestbuf->b_bio1); | |
| 248 | } | |
| 249 | nestiobuf_start(bio); | |
| 250 | break; | |
| 251 | default: | |
| 252 | bp->b_flags |= B_ERROR; | |
| 253 | bp->b_error = EIO; | |
| 254 | biodone(bio); | |
| 255 | break; | |
| ff56536e | 256 | } |
| ff56536e AH |
257 | return 0; |
| 258 | } | |
| 1446934e | 259 | |
| 79b7159f | 260 | |
| 5c411e8e | 261 | static int |
| 79b7159f AH |
262 | dm_target_stripe_dump(dm_table_entry_t *table_en, void *data, size_t length, off_t offset) |
| 263 | { | |
| 264 | dm_target_stripe_config_t *tsc; | |
| 265 | uint64_t blkno, blkoff; | |
| 266 | uint64_t stripe, blknr; | |
| 267 | uint32_t stripe_off, stripe_rest, num_blks, issue_blks; | |
| 268 | uint64_t off2, len2; | |
| 269 | int devnr; | |
| 270 | ||
| 271 | tsc = table_en->target_config; | |
| 272 | if (tsc == NULL) | |
| 273 | return 0; | |
| 274 | ||
| 275 | /* calculate extent of request */ | |
| 276 | KKASSERT(length % DEV_BSIZE == 0); | |
| 277 | ||
| 278 | blkno = offset / DEV_BSIZE; | |
| 279 | blkoff = 0; | |
| 280 | num_blks = length / DEV_BSIZE; | |
| 281 | ||
| 282 | /* | |
| 283 | * 0 length means flush buffers and return | |
| 284 | */ | |
| 285 | if (length == 0) { | |
| 286 | for (devnr = 0; devnr < tsc->stripe_num; ++devnr) { | |
| 287 | if (tsc->stripe_devs[devnr].pdev->pdev_vnode->v_rdev == NULL) | |
| 288 | return ENXIO; | |
| 289 | ||
| 290 | dev_ddump(tsc->stripe_devs[devnr].pdev->pdev_vnode->v_rdev, | |
| 291 | data, 0, offset, 0); | |
| 292 | } | |
| 293 | return 0; | |
| 294 | } | |
| 295 | ||
| 296 | while (num_blks > 0) { | |
| 297 | /* blockno to strip piece nr */ | |
| 298 | stripe = blkno / tsc->stripe_chunksize; | |
| 299 | stripe_off = blkno % tsc->stripe_chunksize; | |
| 300 | ||
| 301 | /* where we are inside the strip */ | |
| 302 | devnr = stripe % tsc->stripe_num; | |
| 303 | blknr = stripe / tsc->stripe_num; | |
| 304 | ||
| 305 | /* how much is left before we hit a boundary */ | |
| 306 | stripe_rest = tsc->stripe_chunksize - stripe_off; | |
| 307 | ||
| 308 | /* issue this piece on stripe `stripe' */ | |
| 309 | issue_blks = MIN(stripe_rest, num_blks); | |
| 310 | ||
| 311 | #if 0 | |
| 312 | nestiobuf_add(bio, nestbuf, blkoff, | |
| 313 | issue_blks * DEV_BSIZE); | |
| 314 | #endif | |
| 315 | len2 = issue_blks * DEV_BSIZE; | |
| 316 | ||
| 317 | /* I need number of bytes. */ | |
| 318 | off2 = blknr * tsc->stripe_chunksize + stripe_off; | |
| 319 | off2 += tsc->stripe_devs[devnr].offset; | |
| 320 | off2 *= DEV_BSIZE; | |
| 321 | off2 = dm_pdev_correct_dump_offset(tsc->stripe_devs[devnr].pdev, | |
| 322 | off2); | |
| 323 | ||
| 324 | if (tsc->stripe_devs[devnr].pdev->pdev_vnode->v_rdev == NULL) | |
| 325 | return ENXIO; | |
| 326 | ||
| 327 | dev_ddump(tsc->stripe_devs[devnr].pdev->pdev_vnode->v_rdev, | |
| 328 | (char *)data + blkoff, 0, off2, len2); | |
| 329 | ||
| 330 | blkno += issue_blks; | |
| 331 | blkoff += issue_blks * DEV_BSIZE; | |
| 332 | num_blks -= issue_blks; | |
| 333 | } | |
| 334 | ||
| 335 | return 0; | |
| 336 | } | |
| 337 | ||
| 1446934e MD |
338 | /* |
| 339 | * Destroy a dm table entry for stripes. | |
| 340 | */ | |
| 5c411e8e | 341 | static int |
| 1446934e | 342 | dm_target_stripe_destroy(dm_table_entry_t *table_en) |
| ff56536e AH |
343 | { |
| 344 | dm_target_stripe_config_t *tsc; | |
| 345 | ||
| 1446934e MD |
346 | if ((tsc = table_en->target_config) != NULL) { |
| 347 | table_en->target_config = NULL; | |
| 348 | dm_target_stripe_destroy_config(tsc); | |
| 349 | } | |
| ff56536e AH |
350 | |
| 351 | /* Unbusy target so we can unload it */ | |
| 352 | dm_target_unbusy(table_en->target); | |
| 353 | ||
| 1446934e MD |
354 | return 0; |
| 355 | } | |
| ff56536e | 356 | |
| 1446934e MD |
357 | static void |
| 358 | dm_target_stripe_destroy_config(dm_target_stripe_config_t *tsc) | |
| 359 | { | |
| 360 | int n; | |
| ff56536e | 361 | |
| 1446934e MD |
362 | for (n = 0; n < tsc->stripe_num; ++n) { |
| 363 | if (tsc->stripe_devs[n].pdev) { | |
| 364 | dm_pdev_decr(tsc->stripe_devs[n].pdev); | |
| 365 | tsc->stripe_devs[n].pdev = NULL; | |
| 366 | } | |
| 367 | } | |
| 368 | kfree(tsc, M_DMSTRIPE); | |
| ff56536e | 369 | } |
| 1446934e MD |
370 | |
| 371 | /* | |
| 372 | * Generate properties from stripe table entry. | |
| 373 | */ | |
| 5c411e8e | 374 | static int |
| 1446934e | 375 | dm_target_stripe_deps(dm_table_entry_t *table_en, prop_array_t prop_array) |
| ff56536e AH |
376 | { |
| 377 | dm_target_stripe_config_t *tsc; | |
| 378 | struct vattr va; | |
| ff56536e | 379 | int error; |
| 1446934e | 380 | int n; |
| ff56536e AH |
381 | |
| 382 | if (table_en->target_config == NULL) | |
| 383 | return ENOENT; | |
| 384 | ||
| 385 | tsc = table_en->target_config; | |
| 1446934e MD |
386 | error = 0; |
| 387 | for (n = 0; n < tsc->stripe_num; ++n) { | |
| 388 | error = VOP_GETATTR(tsc->stripe_devs[n].pdev->pdev_vnode, &va); | |
| 389 | if (error) | |
| 390 | break; | |
| 391 | prop_array_add_uint64(prop_array, | |
| 392 | (uint64_t)makeudev(va.va_rmajor, va.va_rminor)); | |
| 393 | } | |
| 394 | return (error); | |
| ff56536e | 395 | } |
| 1446934e MD |
396 | |
| 397 | /* | |
| 398 | * Unsupported for this target. | |
| 399 | */ | |
| 5c411e8e | 400 | static int |
| ff56536e AH |
401 | dm_target_stripe_upcall(dm_table_entry_t * table_en, struct buf * bp) |
| 402 | { | |
| 403 | return 0; | |
| 404 | } | |
| 5c411e8e AH |
405 | |
| 406 | static int | |
| 407 | dmts_mod_handler(module_t mod, int type, void *unused) | |
| 408 | { | |
| 409 | dm_target_t *dmt = NULL; | |
| 410 | int err = 0; | |
| 411 | ||
| 412 | switch(type) { | |
| 413 | case MOD_LOAD: | |
| 414 | if ((dmt = dm_target_lookup("striped")) != NULL) { | |
| 415 | dm_target_unbusy(dmt); | |
| 416 | return EEXIST; | |
| 417 | } | |
| 418 | dmt = dm_target_alloc("striped"); | |
| 419 | dmt->version[0] = 1; | |
| 420 | dmt->version[1] = 0; | |
| 421 | dmt->version[2] = 3; | |
| 422 | strlcpy(dmt->name, "striped", DM_MAX_TYPE_NAME); | |
| 423 | dmt->init = &dm_target_stripe_init; | |
| 424 | dmt->status = &dm_target_stripe_status; | |
| 425 | dmt->strategy = &dm_target_stripe_strategy; | |
| 426 | dmt->deps = &dm_target_stripe_deps; | |
| 427 | dmt->destroy = &dm_target_stripe_destroy; | |
| 428 | dmt->upcall = &dm_target_stripe_upcall; | |
| 429 | dmt->dump = &dm_target_stripe_dump; | |
| 430 | ||
| 431 | err = dm_target_insert(dmt); | |
| 432 | if (err == 0) | |
| 433 | kprintf("dm_target_stripe: Successfully initialized\n"); | |
| 434 | break; | |
| 435 | ||
| 436 | case MOD_UNLOAD: | |
| 437 | err = dm_target_rem("striped"); | |
| 438 | if (err == 0) | |
| 439 | kprintf("dm_target_stripe: unloaded\n"); | |
| 440 | break; | |
| 441 | ||
| 442 | default: | |
| 443 | break; | |
| 444 | } | |
| 445 | ||
| 446 | return err; | |
| 447 | } | |
| 448 | ||
| 7115a22b | 449 | DM_TARGET_MODULE(dm_target_striped, dmts_mod_handler); |