1 /*$NetBSD: dm_target_stripe.c,v 1.8 2009/12/01 23:12:10 haad Exp $*/
4 * Copyright (c) 2009 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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.
33 * This file implements initial version of device-mapper stripe target.
35 #include <sys/types.h>
36 #include <sys/param.h>
40 #include <sys/vnode.h>
44 #ifdef DM_TARGET_MODULE
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
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.
52 #include <sys/kernel.h>
53 #include <sys/module.h>
55 MODULE(MODULE_CLASS_MISC
, dm_target_stripe
, NULL
);
58 dm_target_stripe_modcmd(modcmd_t cmd
, void *arg
)
66 if ((dmt
= dm_target_lookup("stripe")) != NULL
) {
67 dm_target_unbusy(dmt
);
70 dmt
= dm_target_alloc("stripe");
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
;
83 r
= dm_target_insert(dmt
);
88 r
= dm_target_rem("stripe");
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
109 dm_target_stripe_init(dm_dev_t
* dmv
, void **target_config
, char *params
)
111 dm_target_stripe_config_t
*tsc
;
113 char **ap
, *argv
[10];
118 len
= strlen(params
) + 1;
121 * Parse a string, containing tokens delimited by white space,
122 * into an argument vector
124 for (ap
= argv
; ap
< &argv
[9] &&
125 (*ap
= strsep(¶ms
, " \t")) != NULL
;) {
130 printf("Stripe target init function called!!\n");
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]);
136 if (atoi(argv
[0]) > MAX_STRIPES
)
139 if ((tsc
= kmem_alloc(sizeof(dm_target_stripe_config_t
), KM_NOSLEEP
))
143 /* Insert dmp to global pdev list */
144 if ((tsc
->stripe_devs
[0].pdev
= dm_pdev_insert(argv
[2])) == NULL
)
147 /* Insert dmp to global pdev list */
148 if ((tsc
->stripe_devs
[1].pdev
= dm_pdev_insert(argv
[4])) == NULL
)
151 tsc
->stripe_devs
[0].offset
= atoi(argv
[3]);
152 tsc
->stripe_devs
[1].offset
= atoi(argv
[5]);
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]);
159 *target_config
= tsc
;
161 dmv
->dev_type
= DM_STRIPE_DEV
;
165 /* Status routine called to get params string. */
167 dm_target_stripe_status(void *target_config
)
169 dm_target_stripe_config_t
*tsc
;
174 if ((params
= kmem_alloc(DM_MAX_PARAMS_SIZE
, KM_SLEEP
)) == NULL
)
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
);
184 /* Strategy routine called from dm_strategy. */
186 dm_target_stripe_strategy(dm_table_entry_t
* table_en
, struct buf
* bp
)
188 dm_target_stripe_config_t
*tsc
;
190 uint64_t blkno
, blkoff
;
191 uint64_t stripe
, stripe_blknr
;
192 uint32_t stripe_off
, stripe_rest
, num_blks
, issue_blks
;
195 tsc
= table_en
->target_config
;
199 /* printf("Stripe target read function called %" PRIu64 "!!\n",
202 /* calculate extent of request */
203 KASSERT(bp
->b_resid
% DEV_BSIZE
== 0);
207 num_blks
= bp
->b_resid
/ DEV_BSIZE
;
209 /* blockno to strip piece nr */
210 stripe
= blkno
/ tsc
->stripe_chunksize
;
211 stripe_off
= blkno
% tsc
->stripe_chunksize
;
213 /* where we are inside the strip */
214 stripe_devnr
= stripe
% tsc
->stripe_num
;
215 stripe_blknr
= stripe
/ tsc
->stripe_num
;
217 /* how much is left before we hit a boundary */
218 stripe_rest
= tsc
->stripe_chunksize
- stripe_off
;
220 /* issue this piece on stripe `stripe' */
221 issue_blks
= MIN(stripe_rest
, num_blks
);
222 nestbuf
= getiobuf(NULL
, true);
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
;
228 VOP_STRATEGY(tsc
->stripe_devs
[stripe_devnr
].pdev
->pdev_vnode
, nestbuf
);
231 blkoff
+= issue_blks
* DEV_BSIZE
;
232 num_blks
-= issue_blks
;
240 /* Doesn't do anything here. */
242 dm_target_stripe_destroy(dm_table_entry_t
* table_en
)
244 dm_target_stripe_config_t
*tsc
;
246 tsc
= table_en
->target_config
;
251 dm_pdev_decr(tsc
->stripe_devs
[0].pdev
);
252 dm_pdev_decr(tsc
->stripe_devs
[1].pdev
);
254 /* Unbusy target so we can unload it */
255 dm_target_unbusy(table_en
->target
);
257 kmem_free(tsc
, sizeof(dm_target_stripe_config_t
));
259 table_en
->target_config
= NULL
;
263 /* Doesn't not need to do anything here. */
265 dm_target_stripe_deps(dm_table_entry_t
* table_en
, prop_array_t prop_array
)
267 dm_target_stripe_config_t
*tsc
;
272 if (table_en
->target_config
== NULL
)
275 tsc
= table_en
->target_config
;
277 if ((error
= VOP_GETATTR(tsc
->stripe_devs
[0].pdev
->pdev_vnode
, &va
, curlwp
->l_cred
)) != 0)
280 prop_array_add_uint64(prop_array
, (uint64_t) va
.va_rdev
);
282 if ((error
= VOP_GETATTR(tsc
->stripe_devs
[1].pdev
->pdev_vnode
, &va
, curlwp
->l_cred
)) != 0)
285 prop_array_add_uint64(prop_array
, (uint64_t) va
.va_rdev
);
289 /* Unsupported for this target. */
291 dm_target_stripe_upcall(dm_table_entry_t
* table_en
, struct buf
* bp
)