1 /*$NetBSD: dm_target_stripe.c,v 1.9 2010/01/04 00:14:41 haad Exp $*/ 2 3 /* 4 * Copyright (c) 2009 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Adam Hamsik. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * This file implements initial version of device-mapper stripe target. 34 */ 35 #include <sys/types.h> 36 #include <sys/param.h> 37 38 #include <sys/buf.h> 39 #include <sys/kmem.h> 40 #include <sys/vnode.h> 41 42 #include "dm.h" 43 44 #ifdef DM_TARGET_MODULE 45 /* 46 * Every target can be compiled directly to dm driver or as a 47 * separate module this part of target is used for loading targets 48 * to dm driver. 49 * Target can be unloaded from kernel only if there are no users of 50 * it e.g. there are no devices which uses that target. 51 */ 52 #include <sys/kernel.h> 53 #include <sys/module.h> 54 55 MODULE(MODULE_CLASS_MISC, dm_target_stripe, NULL); 56 57 static int 58 dm_target_stripe_modcmd(modcmd_t cmd, void *arg) 59 { 60 dm_target_t *dmt; 61 int r; 62 dmt = NULL; 63 64 switch (cmd) { 65 case MODULE_CMD_INIT: 66 if ((dmt = dm_target_lookup("stripe")) != NULL) { 67 dm_target_unbusy(dmt); 68 return EEXIST; 69 } 70 dmt = dm_target_alloc("stripe"); 71 72 dmt->version[0] = 1; 73 dmt->version[1] = 0; 74 dmt->version[2] = 0; 75 strlcpy(dmt->name, "stripe", DM_MAX_TYPE_NAME); 76 dmt->init = &dm_target_stripe_init; 77 dmt->status = &dm_target_stripe_status; 78 dmt->strategy = &dm_target_stripe_strategy; 79 dmt->deps = &dm_target_stripe_deps; 80 dmt->destroy = &dm_target_stripe_destroy; 81 dmt->upcall = &dm_target_stripe_upcall; 82 83 r = dm_target_insert(dmt); 84 85 break; 86 87 case MODULE_CMD_FINI: 88 r = dm_target_rem("stripe"); 89 break; 90 91 case MODULE_CMD_STAT: 92 return ENOTTY; 93 94 default: 95 return ENOTTY; 96 } 97 98 return r; 99 } 100 #endif 101 102 /* 103 * Init function called from dm_table_load_ioctl. 104 * Example line sent to dm from lvm tools when using striped target. 105 * start length striped #stripes chunk_size device1 offset1 ... deviceN offsetN 106 * 0 65536 striped 2 512 /dev/hda 0 /dev/hdb 0 107 */ 108 int 109 dm_target_stripe_init(dm_dev_t * dmv, void **target_config, char *params) 110 { 111 dm_target_stripe_config_t *tsc; 112 size_t len; 113 char **ap, *argv[10]; 114 115 if (params == NULL) 116 return EINVAL; 117 118 len = strlen(params) + 1; 119 120 /* 121 * Parse a string, containing tokens delimited by white space, 122 * into an argument vector 123 */ 124 for (ap = argv; ap < &argv[9] && 125 (*ap = strsep(¶ms, " \t")) != NULL;) { 126 if (**ap != '\0') 127 ap++; 128 } 129 130 printf("Stripe target init function called!!\n"); 131 132 printf("Stripe target chunk size %s number of stripes %s\n", argv[1], argv[0]); 133 printf("Stripe target device name %s -- offset %s\n", argv[2], argv[3]); 134 printf("Stripe target device name %s -- offset %s\n", argv[4], argv[5]); 135 136 if (atoi(argv[0]) > MAX_STRIPES) 137 return ENOTSUP; 138 139 if ((tsc = kmem_alloc(sizeof(dm_target_stripe_config_t), KM_NOSLEEP)) 140 == NULL) 141 return ENOMEM; 142 143 /* Insert dmp to global pdev list */ 144 if ((tsc->stripe_devs[0].pdev = dm_pdev_insert(argv[2])) == NULL) 145 return ENOENT; 146 147 /* Insert dmp to global pdev list */ 148 if ((tsc->stripe_devs[1].pdev = dm_pdev_insert(argv[4])) == NULL) 149 return ENOENT; 150 151 tsc->stripe_devs[0].offset = atoi(argv[3]); 152 tsc->stripe_devs[1].offset = atoi(argv[5]); 153 154 /* Save length of param string */ 155 tsc->params_len = len; 156 tsc->stripe_chunksize = atoi(argv[1]); 157 tsc->stripe_num = (uint8_t) atoi(argv[0]); 158 159 *target_config = tsc; 160 161 dmv->dev_type = DM_STRIPE_DEV; 162 163 return 0; 164 } 165 /* Status routine called to get params string. */ 166 char * 167 dm_target_stripe_status(void *target_config) 168 { 169 dm_target_stripe_config_t *tsc; 170 char *params; 171 172 tsc = target_config; 173 174 if ((params = kmem_alloc(DM_MAX_PARAMS_SIZE, KM_SLEEP)) == NULL) 175 return NULL; 176 177 snprintf(params, DM_MAX_PARAMS_SIZE, "%d %" PRIu64 " %s %" PRIu64 " %s %" PRIu64, 178 tsc->stripe_num, tsc->stripe_chunksize, 179 tsc->stripe_devs[0].pdev->name, tsc->stripe_devs[0].offset, 180 tsc->stripe_devs[1].pdev->name, tsc->stripe_devs[1].offset); 181 182 return params; 183 } 184 /* Strategy routine called from dm_strategy. */ 185 int 186 dm_target_stripe_strategy(dm_table_entry_t * table_en, struct buf * bp) 187 { 188 dm_target_stripe_config_t *tsc; 189 struct buf *nestbuf; 190 uint64_t blkno, blkoff; 191 uint64_t stripe, stripe_blknr; 192 uint32_t stripe_off, stripe_rest, num_blks, issue_blks; 193 int stripe_devnr; 194 195 tsc = table_en->target_config; 196 if (tsc == NULL) 197 return 0; 198 199 /* printf("Stripe target read function called %" PRIu64 "!!\n", 200 tlc->offset);*/ 201 202 /* calculate extent of request */ 203 KASSERT(bp->b_resid % DEV_BSIZE == 0); 204 205 blkno = bp->b_blkno; 206 blkoff = 0; 207 num_blks = bp->b_resid / DEV_BSIZE; 208 for (;;) { 209 /* blockno to strip piece nr */ 210 stripe = blkno / tsc->stripe_chunksize; 211 stripe_off = blkno % tsc->stripe_chunksize; 212 213 /* where we are inside the strip */ 214 stripe_devnr = stripe % tsc->stripe_num; 215 stripe_blknr = stripe / tsc->stripe_num; 216 217 /* how much is left before we hit a boundary */ 218 stripe_rest = tsc->stripe_chunksize - stripe_off; 219 220 /* issue this piece on stripe `stripe' */ 221 issue_blks = MIN(stripe_rest, num_blks); 222 nestbuf = getiobuf(NULL, true); 223 224 nestiobuf_setup(bp, nestbuf, blkoff, issue_blks * DEV_BSIZE); 225 nestbuf->b_blkno = stripe_blknr * tsc->stripe_chunksize + stripe_off; 226 nestbuf->b_blkno += tsc->stripe_devs[stripe_devnr].offset; 227 228 VOP_STRATEGY(tsc->stripe_devs[stripe_devnr].pdev->pdev_vnode, nestbuf); 229 230 blkno += issue_blks; 231 blkoff += issue_blks * DEV_BSIZE; 232 num_blks -= issue_blks; 233 234 if (num_blks <= 0) 235 break; 236 } 237 238 return 0; 239 } 240 /* Doesn't do anything here. */ 241 int 242 dm_target_stripe_destroy(dm_table_entry_t * table_en) 243 { 244 dm_target_stripe_config_t *tsc; 245 246 tsc = table_en->target_config; 247 248 if (tsc == NULL) 249 return 0; 250 251 dm_pdev_decr(tsc->stripe_devs[0].pdev); 252 dm_pdev_decr(tsc->stripe_devs[1].pdev); 253 254 /* Unbusy target so we can unload it */ 255 dm_target_unbusy(table_en->target); 256 257 kmem_free(tsc, sizeof(dm_target_stripe_config_t)); 258 259 table_en->target_config = NULL; 260 261 return 0; 262 } 263 /* Doesn't not need to do anything here. */ 264 int 265 dm_target_stripe_deps(dm_table_entry_t * table_en, prop_array_t prop_array) 266 { 267 dm_target_stripe_config_t *tsc; 268 struct vattr va; 269 270 int error; 271 272 if (table_en->target_config == NULL) 273 return ENOENT; 274 275 tsc = table_en->target_config; 276 277 if ((error = VOP_GETATTR(tsc->stripe_devs[0].pdev->pdev_vnode, &va, curlwp->l_cred)) != 0) 278 return error; 279 280 prop_array_add_uint64(prop_array, (uint64_t) va.va_rdev); 281 282 if ((error = VOP_GETATTR(tsc->stripe_devs[1].pdev->pdev_vnode, &va, curlwp->l_cred)) != 0) 283 return error; 284 285 prop_array_add_uint64(prop_array, (uint64_t) va.va_rdev); 286 287 return 0; 288 } 289 /* Unsupported for this target. */ 290 int 291 dm_target_stripe_upcall(dm_table_entry_t * table_en, struct buf * bp) 292 { 293 return 0; 294 } 295