| Commit | Line | Data |
|---|---|---|
| ff56536e AH |
1 | /* $NetBSD: dm_target_linear.c,v 1.9 2010/01/04 00:14:41 haad Exp $ */ |
| 2 | ||
| 3 | /* | |
| 4 | * Copyright (c) 2008 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 | /* | |
| 34 | * This file implements initial version of device-mapper dklinear target. | |
| 35 | */ | |
| 36 | ||
| 37 | #include <sys/types.h> | |
| 38 | #include <sys/param.h> | |
| 5b279a20 | 39 | #include <sys/ctype.h> |
| ff56536e AH |
40 | |
| 41 | #include <sys/buf.h> | |
| 5b279a20 | 42 | #include <sys/malloc.h> |
| ff56536e AH |
43 | #include <sys/vnode.h> |
| 44 | ||
| a84e173e | 45 | #include <dev/disk/dm/dm.h> |
| 5b279a20 | 46 | MALLOC_DEFINE(M_DMLINEAR, "dm_linear", "Device Mapper Target Linear"); |
| ff56536e AH |
47 | |
| 48 | /* | |
| 49 | * Allocate target specific config data, and link them to table. | |
| 50 | * This function is called only when, flags is not READONLY and | |
| 51 | * therefore we can add things to pdev list. This should not a | |
| 52 | * problem because this routine is called only from dm_table_load_ioctl. | |
| 53 | * @argv[0] is name, | |
| 54 | * @argv[1] is physical data offset. | |
| 55 | */ | |
| 5c411e8e | 56 | static int |
| ff56536e AH |
57 | dm_target_linear_init(dm_dev_t * dmv, void **target_config, char *params) |
| 58 | { | |
| 59 | dm_target_linear_config_t *tlc; | |
| 60 | dm_pdev_t *dmp; | |
| 61 | ||
| 62 | char **ap, *argv[3]; | |
| 63 | ||
| 64 | if (params == NULL) | |
| 65 | return EINVAL; | |
| 66 | ||
| 67 | /* | |
| 68 | * Parse a string, containing tokens delimited by white space, | |
| 69 | * into an argument vector | |
| 70 | */ | |
| 71 | for (ap = argv; ap < &argv[2] && | |
| 72 | (*ap = strsep(¶ms, " \t")) != NULL;) { | |
| 73 | if (**ap != '\0') | |
| 74 | ap++; | |
| 75 | } | |
| 76 | ||
| 77 | aprint_debug("Linear target init function called %s--%s!!\n", | |
| 78 | argv[0], argv[1]); | |
| 79 | ||
| 5b279a20 AH |
80 | /* XXX: temp hack */ |
| 81 | if (argv[0] == NULL) | |
| 82 | return EINVAL; | |
| 83 | ||
| ff56536e AH |
84 | /* Insert dmp to global pdev list */ |
| 85 | if ((dmp = dm_pdev_insert(argv[0])) == NULL) | |
| 86 | return ENOENT; | |
| 87 | ||
| 5b279a20 | 88 | if ((tlc = kmalloc(sizeof(dm_target_linear_config_t), M_DMLINEAR, M_WAITOK)) |
| ff56536e AH |
89 | == NULL) |
| 90 | return ENOMEM; | |
| 91 | ||
| 92 | tlc->pdev = dmp; | |
| 93 | tlc->offset = 0; /* default settings */ | |
| 94 | ||
| 95 | /* Check user input if it is not leave offset as 0. */ | |
| 1446934e | 96 | tlc->offset = atoi64(argv[1]); |
| ff56536e AH |
97 | |
| 98 | *target_config = tlc; | |
| 99 | ||
| 100 | dmv->dev_type = DM_LINEAR_DEV; | |
| 101 | ||
| 102 | return 0; | |
| 103 | } | |
| 104 | /* | |
| 105 | * Status routine is called to get params string, which is target | |
| 106 | * specific. When dm_table_status_ioctl is called with flag | |
| 107 | * DM_STATUS_TABLE_FLAG I have to sent params string back. | |
| 108 | */ | |
| 5c411e8e | 109 | static char * |
| ff56536e AH |
110 | dm_target_linear_status(void *target_config) |
| 111 | { | |
| 112 | dm_target_linear_config_t *tlc; | |
| 113 | char *params; | |
| 114 | tlc = target_config; | |
| 115 | ||
| 116 | aprint_debug("Linear target status function called\n"); | |
| 117 | ||
| 1446934e MD |
118 | /* target expects use of M_DM */ |
| 119 | params = kmalloc(DM_MAX_PARAMS_SIZE, M_DM, M_WAITOK); | |
| ff56536e AH |
120 | |
| 121 | aprint_normal("%s %" PRIu64, tlc->pdev->name, tlc->offset); | |
| 5b279a20 | 122 | ksnprintf(params, DM_MAX_PARAMS_SIZE, "%s %" PRIu64, |
| ff56536e AH |
123 | tlc->pdev->name, tlc->offset); |
| 124 | ||
| 125 | return params; | |
| 126 | } | |
| 127 | /* | |
| 128 | * Do IO operation, called from dmstrategy routine. | |
| 129 | */ | |
| 5c411e8e | 130 | static int |
| ff56536e AH |
131 | dm_target_linear_strategy(dm_table_entry_t * table_en, struct buf * bp) |
| 132 | { | |
| 133 | dm_target_linear_config_t *tlc; | |
| 134 | ||
| 135 | tlc = table_en->target_config; | |
| 136 | ||
| 137 | /* printf("Linear target read function called %" PRIu64 "!!\n", | |
| 138 | tlc->offset);*/ | |
| 139 | ||
| 5b279a20 | 140 | #if 0 |
| ff56536e | 141 | bp->b_blkno += tlc->offset; |
| 5b279a20 AH |
142 | #endif |
| 143 | bp->b_bio1.bio_offset += tlc->offset * DEV_BSIZE; | |
| ff56536e | 144 | |
| 5b279a20 | 145 | vn_strategy(tlc->pdev->pdev_vnode, &bp->b_bio1); |
| ff56536e AH |
146 | |
| 147 | return 0; | |
| 148 | ||
| 149 | } | |
| 79b7159f | 150 | |
| 5c411e8e | 151 | static int |
| 79b7159f AH |
152 | dm_target_linear_dump(dm_table_entry_t *table_en, void *data, size_t length, off_t offset) |
| 153 | { | |
| 154 | dm_target_linear_config_t *tlc; | |
| 155 | ||
| 156 | tlc = table_en->target_config; | |
| 157 | ||
| 158 | offset += tlc->offset * DEV_BSIZE; | |
| 159 | offset = dm_pdev_correct_dump_offset(tlc->pdev, offset); | |
| 160 | ||
| 161 | if (tlc->pdev->pdev_vnode->v_rdev == NULL) | |
| 162 | return ENXIO; | |
| 163 | ||
| 164 | return dev_ddump(tlc->pdev->pdev_vnode->v_rdev, data, 0, offset, length); | |
| 165 | } | |
| 166 | ||
| ff56536e AH |
167 | /* |
| 168 | * Destroy target specific data. Decrement table pdevs. | |
| 169 | */ | |
| 5c411e8e | 170 | static int |
| ff56536e AH |
171 | dm_target_linear_destroy(dm_table_entry_t * table_en) |
| 172 | { | |
| 173 | dm_target_linear_config_t *tlc; | |
| 174 | ||
| 175 | /* | |
| 176 | * Destroy function is called for every target even if it | |
| 177 | * doesn't have target_config. | |
| 178 | */ | |
| 179 | ||
| 180 | if (table_en->target_config == NULL) | |
| 181 | return 0; | |
| 182 | ||
| 183 | tlc = table_en->target_config; | |
| 184 | ||
| 185 | /* Decrement pdev ref counter if 0 remove it */ | |
| 186 | dm_pdev_decr(tlc->pdev); | |
| 187 | ||
| 188 | /* Unbusy target so we can unload it */ | |
| 189 | dm_target_unbusy(table_en->target); | |
| 190 | ||
| 5b279a20 | 191 | kfree(table_en->target_config, M_DMLINEAR); |
| ff56536e AH |
192 | |
| 193 | table_en->target_config = NULL; | |
| 194 | ||
| 195 | return 0; | |
| 196 | } | |
| 197 | /* Add this target pdev dependiences to prop_array_t */ | |
| 5c411e8e | 198 | static int |
| ff56536e AH |
199 | dm_target_linear_deps(dm_table_entry_t * table_en, prop_array_t prop_array) |
| 200 | { | |
| 201 | dm_target_linear_config_t *tlc; | |
| 202 | struct vattr va; | |
| 203 | ||
| 204 | int error; | |
| 205 | ||
| 206 | if (table_en->target_config == NULL) | |
| 207 | return ENOENT; | |
| 208 | ||
| 209 | tlc = table_en->target_config; | |
| 210 | ||
| 5b279a20 | 211 | if ((error = VOP_GETATTR(tlc->pdev->pdev_vnode, &va)) != 0) |
| ff56536e AH |
212 | return error; |
| 213 | ||
| 5b279a20 AH |
214 | prop_array_add_uint64(prop_array, |
| 215 | (uint64_t) makeudev(va.va_rmajor, va.va_rminor)); | |
| ff56536e AH |
216 | |
| 217 | return 0; | |
| 218 | } | |
| 219 | /* | |
| 220 | * Register upcall device. | |
| 221 | * Linear target doesn't need any upcall devices but other targets like | |
| 222 | * mirror, snapshot, multipath, stripe will use this functionality. | |
| 223 | */ | |
| 5c411e8e | 224 | static int |
| ff56536e AH |
225 | dm_target_linear_upcall(dm_table_entry_t * table_en, struct buf * bp) |
| 226 | { | |
| 227 | return 0; | |
| 228 | } | |
| 229 | /* | |
| 230 | * Transform char s to uint64_t offset number. | |
| 231 | */ | |
| 232 | uint64_t | |
| 1446934e | 233 | atoi64(const char *s) |
| ff56536e AH |
234 | { |
| 235 | uint64_t n; | |
| 236 | n = 0; | |
| 237 | ||
| 238 | while (*s != '\0') { | |
| 239 | if (!isdigit(*s)) | |
| 240 | break; | |
| 241 | ||
| 242 | n = (10 * n) + (*s - '0'); | |
| 243 | s++; | |
| 244 | } | |
| 245 | ||
| 246 | return n; | |
| 247 | } | |
| 5c411e8e AH |
248 | |
| 249 | static int | |
| 250 | dmtl_mod_handler(module_t mod, int type, void *unused) | |
| 251 | { | |
| 252 | dm_target_t *dmt = NULL; | |
| 253 | int err = 0; | |
| 254 | ||
| 255 | switch(type) { | |
| 256 | case MOD_LOAD: | |
| 257 | if ((dmt = dm_target_lookup("linear")) != NULL) { | |
| 258 | dm_target_unbusy(dmt); | |
| 259 | return EEXIST; | |
| 260 | } | |
| 261 | dmt = dm_target_alloc("linear"); | |
| 262 | dmt->version[0] = 1; | |
| 263 | dmt->version[1] = 0; | |
| 264 | dmt->version[2] = 2; | |
| 265 | strlcpy(dmt->name, "linear", DM_MAX_TYPE_NAME); | |
| 266 | dmt->init = &dm_target_linear_init; | |
| 267 | dmt->status = &dm_target_linear_status; | |
| 268 | dmt->strategy = &dm_target_linear_strategy; | |
| 269 | dmt->deps = &dm_target_linear_deps; | |
| 270 | dmt->destroy = &dm_target_linear_destroy; | |
| 271 | dmt->upcall = &dm_target_linear_upcall; | |
| 272 | dmt->dump = &dm_target_linear_dump; | |
| 273 | ||
| 274 | err = dm_target_insert(dmt); | |
| 275 | if (err == 0) | |
| 276 | kprintf("dm_target_linear: Successfully initialized\n"); | |
| 277 | break; | |
| 278 | ||
| 279 | case MOD_UNLOAD: | |
| 280 | err = dm_target_rem("linear"); | |
| 281 | if (err == 0) | |
| 282 | kprintf("dm_target_linear: unloaded\n"); | |
| 283 | break; | |
| 284 | ||
| 285 | default: | |
| 286 | break; | |
| 287 | } | |
| 288 | ||
| 289 | return err; | |
| 290 | } | |
| 291 | ||
| 292 | DM_TARGET_MODULE(dm_target_linear, dmtl_mod_handler); |