1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 /*
30 * initialize metadevices
31 */
32
33 #include <meta.h>
34 #include <sys/lvm/mdio.h>
35 #include <libdevinfo.h>
36
37
38 int
parse_interlace(char * uname,char * str,diskaddr_t * interlacep,md_error_t * ep)39 parse_interlace(
40 char *uname, /* Meta Device name (eg d0) */
41 char *str, /* String to Parse */
42 diskaddr_t *interlacep,
43 md_error_t *ep
44 )
45 {
46 diskaddr_t num;
47 char c;
48 int cnt;
49
50 /* parse interlace */
51 if ((cnt = sscanf(str, "%llu%c", &num, &c)) < 1) {
52 return (meta_cook_syntax(ep, MDE_BAD_INTERLACE,
53 uname, 1, &str));
54 } else if (cnt == 1) {
55 if (num & (DEV_BSIZE - 1)) {
56 return (meta_cook_syntax(ep, MDE_BAD_INTERLACE,
57 uname, 1, &str));
58 }
59 num = lbtodb(num);
60 } else switch (c) {
61 case 'b':
62 case 'B':
63 num *= DEV_BSIZE / DEV_BSIZE;
64 break;
65 case 'k':
66 case 'K':
67 num *= 1024 / DEV_BSIZE;
68 break;
69 case 'm':
70 case 'M':
71 num *= 1024 * 1024 / DEV_BSIZE;
72 break;
73 default:
74 return (meta_cook_syntax(ep, MDE_BAD_INTERLACE,
75 NULL, 1, &str));
76 }
77
78 /* return success */
79 *interlacep = num;
80 return (0);
81 }
82
83 /*
84 * cook up syntax error
85 */
86 int
meta_cook_syntax(md_error_t * ep,md_void_errno_t errcode,char * uname,int argc,char * argv[])87 meta_cook_syntax(
88 md_error_t *ep,
89 md_void_errno_t errcode,
90 char *uname,
91 int argc,
92 char *argv[]
93 )
94 {
95 int rval;
96
97 /* if we have a token, concat it to uname */
98 if ((argc > 0) && (argv[0] != NULL) && (argv[0][0] != '\0')) {
99 char *p;
100
101 if ((uname != NULL) && (uname[0] != '\0')) {
102 p = Malloc(strlen(uname) + 2
103 + 1 + strlen(argv[0]) + 1 + 1);
104 (void) strcpy(p, uname);
105 (void) strcat(p, ": ");
106 } else {
107 p = Malloc(1 + strlen(argv[0]) + 1 + 1);
108 p[0] = '\0';
109 }
110 (void) strcat(p, "\"");
111 (void) strcat(p, argv[0]);
112 (void) strcat(p, "\"");
113 rval = mderror(ep, errcode, p);
114 Free(p);
115 } else {
116 rval = mderror(ep, errcode, uname);
117 }
118
119 return (rval);
120 }
121
122 int
meta_check_devicesize(diskaddr_t total_blocks)123 meta_check_devicesize(
124 diskaddr_t total_blocks
125 )
126 {
127 int rval = MD_CRO_32BIT;
128
129
130 if (total_blocks > MD_MAX_BLKS_FOR_SMALL_DEVS) {
131 rval = MD_CRO_64BIT;
132 }
133 return (rval);
134 }
135
136
137 /*
138 * setup metadevice geometry
139 */
140 /*ARGSUSED*/
141 int
meta_setup_geom(md_unit_t * md,mdname_t * np,mdgeom_t * geomp,uint_t write_reinstruct,uint_t read_reinstruct,uint_t round_cyl,md_error_t * ep)142 meta_setup_geom(
143 md_unit_t *md,
144 mdname_t *np,
145 mdgeom_t *geomp,
146 uint_t write_reinstruct,
147 uint_t read_reinstruct,
148 uint_t round_cyl,
149 md_error_t *ep
150 )
151 {
152 diskaddr_t cylsize = geomp->nhead * geomp->nsect;
153 diskaddr_t total_blocks;
154
155 if (round_cyl) {
156 total_blocks = rounddown(md->c.un_actual_tb, cylsize);
157 } else {
158 total_blocks = md->c.un_actual_tb;
159 }
160
161 md->c.un_total_blocks = total_blocks;
162 md->c.un_nhead = geomp->nhead;
163 md->c.un_nsect = geomp->nsect;
164 md->c.un_rpm = geomp->rpm;
165 md->c.un_wr_reinstruct = write_reinstruct;
166 md->c.un_rd_reinstruct = read_reinstruct;
167 return (0);
168 }
169
170 /*
171 * adjust metadevice geometry
172 */
173 /*ARGSUSED*/
174 int
meta_adjust_geom(md_unit_t * md,mdname_t * np,uint_t write_reinstruct,uint_t read_reinstruct,uint_t round_cyl,md_error_t * ep)175 meta_adjust_geom(
176 md_unit_t *md,
177 mdname_t *np,
178 uint_t write_reinstruct,
179 uint_t read_reinstruct,
180 uint_t round_cyl,
181 md_error_t *ep
182 )
183 {
184 diskaddr_t cylsize = md->c.un_nhead * md->c.un_nsect;
185 diskaddr_t total_blocks;
186
187 if (round_cyl) {
188 total_blocks = rounddown(md->c.un_actual_tb, cylsize);
189 } else {
190 total_blocks = md->c.un_actual_tb;
191 }
192
193 md->c.un_total_blocks = total_blocks;
194 if (write_reinstruct > md->c.un_wr_reinstruct)
195 md->c.un_wr_reinstruct = write_reinstruct;
196 if (read_reinstruct > md->c.un_rd_reinstruct)
197 md->c.un_rd_reinstruct = read_reinstruct;
198 return (0);
199 }
200
201 /*
202 * Function: meta_init_make_device
203 * Purpose:
204 * Create the device node <uname> by constructing the necessary
205 * md_mkdev_params_t structure. We have to handle relative names
206 * (e.g. "d80") and fully-qualified names (e.g. "/dev/md/red/dsk/d80").
207 * The field that we need is the unit number of the metadevice (80 in
208 * the above examples).
209 * Input: spp set structure
210 * uname unit-name (fully qualified or relative)
211 * Output: ep error return structure
212 * Returns: > 0 success and return 'key'
213 * -1 Error. <ep> contains error reason
214 */
215 mdkey_t
meta_init_make_device(mdsetname_t ** spp,char * uname,md_error_t * ep)216 meta_init_make_device(
217 mdsetname_t **spp,
218 char *uname,
219 md_error_t *ep
220 )
221 {
222 md_mkdev_params_t params;
223 mdkey_t rval = 0;
224 char *p;
225 int len = strlen(uname);
226
227 (void) memset(¶ms, 0, sizeof (params));
228 MD_SETDRIVERNAME(¶ms, "md", (*spp)->setno);
229
230 /*
231 * This ioctl call causes kernel to allocate a unit number
232 * and populate /devices for the named metadevice
233 */
234 if (metaioctl(MD_IOCMAKE_DEV, ¶ms, ¶ms.mde, NULL) != 0) {
235 return (mdstealerror(ep, ¶ms.mde));
236 }
237
238 /*
239 * Now we have minor number so add it to the namespace
240 * and return the key
241 */
242 if ((rval = add_self_name(*spp, uname, ¶ms, ep)) <= 0) {
243 if (mdisok(ep))
244 (void) mderror(ep, MDE_UNIT_NOT_FOUND, NULL);
245
246 return (-1);
247 }
248
249 /* Make sure the /dev link is created */
250 if (meta_update_devtree(MD_MKMIN((*spp)->setno, params.un)) != 0) {
251 /*
252 * Delete name entry we just created
253 */
254 (void) del_self_name(*spp, rval, ep);
255 p = Malloc(len + 3);
256 (void) snprintf(p, len + 3, "\"%s\"", uname);
257 rval = mderror(ep, MDE_UNIT_NOT_FOUND, p);
258 Free(p);
259 }
260 return (rval);
261 }
262
263 /*
264 * FUNCTION: is_metadb_cmd()
265 * INPUT: argc - number of command line arguments
266 * argv - pointer to array of command line arguments
267 * OUTPUT: none
268 * RETURNS: TRUE if a metadb is to be created, FALSE otherwise
269 * PURPOSE: parses enough of the command line to determine if a metadb
270 * create is being attempted
271 */
272 static boolean_t
is_metadb_cmd(int argc,char * argv[])273 is_metadb_cmd(
274 int argc,
275 char *argv[]
276 )
277 {
278 ulong_t num;
279 int len;
280
281 /* look for match */
282 if (argc > 0 && (sscanf(argv[0], "mddb%lu%n", &num, &len) == 1) &&
283 (strlen(argv[0]) == len) && ((long)num >= 0)) {
284 return (B_TRUE);
285 }
286
287 return (B_FALSE);
288 }
289
290 /*
291 * FUNCTION: is_stripe_cmd()
292 * INPUT: argc - number of command line arguments
293 * argv - pointer to array of command line arguments
294 * OUTPUT: none
295 * RETURNS: TRUE if a stripe is to be created, FALSE otherwise
296 * PURPOSE: parses enough of the command line to determine if a stripe
297 * create is being attempted
298 */
299 static boolean_t
is_stripe_cmd(int argc,char * argv[])300 is_stripe_cmd(
301 int argc,
302 char *argv[]
303 )
304 {
305 uint_t nrow;
306
307 if (argc > 1 && (sscanf(argv[1], "%u", &nrow) != 1) || ((int)nrow < 0))
308 return (B_FALSE);
309
310 return (B_TRUE);
311 }
312
313 /*
314 * FUNCTION: meta_get_init_type()
315 * INPUT: argc - number of command line arguments
316 * argv - pointer to array of command line arguments
317 * OUTPUT: none
318 * RETURNS: type of metadevice or hot spare pools being initialized
319 * PURPOSE: parses enough of the command line to determine what type
320 * of metainit is being attempted
321 */
322 mdinittypes_t
meta_get_init_type(int argc,char * argv[])323 meta_get_init_type(
324 int argc,
325 char *argv[]
326 )
327 {
328 char *arg = argv[1];
329 mdinittypes_t init_type;
330
331 if (argc == 1) /* must be a hot spare pool w/o devices */
332 return (TAB_HSP);
333
334 init_type = TAB_UNKNOWN;
335 if (arg != NULL) {
336 if (strcmp(arg, "-m") == 0) {
337 init_type = TAB_MIRROR;
338 } else if (strcmp(arg, "-r") == 0) {
339 init_type = TAB_RAID;
340 } else if (strcmp(arg, "-p") == 0) {
341 init_type = TAB_SP;
342 } else if (strcmp(arg, "-t") == 0) {
343 init_type = TAB_TRANS;
344 } else if (is_metadb_cmd(argc, argv)) {
345 init_type = TAB_MDDB;
346 } else if (is_stripe_cmd(argc, argv)) {
347 init_type = TAB_STRIPE;
348 } else { /* assume that it is a hsp */
349 init_type = TAB_HSP;
350 }
351 }
352 return (init_type);
353 }
354
355 /*
356 * initialize named device or hotspare pool
357 */
358 int
meta_init_name(mdsetname_t ** spp,int argc,char * argv[],char * cname,mdcmdopts_t options,md_error_t * ep)359 meta_init_name(
360 mdsetname_t **spp,
361 int argc,
362 char *argv[],
363 char *cname, /* canonical name */
364 mdcmdopts_t options,
365 md_error_t *ep
366 )
367 {
368 mdinittypes_t init_type;
369 char *p;
370 int rval;
371 char *uname = argv[0];
372 mdkey_t key = MD_KEYWILD;
373 minor_t mnum;
374 md_error_t t_e = mdnullerror;
375
376 assert(argc > 0);
377 assert(*spp != NULL);
378
379 /* determine type of metadevice or hot spare pool being created */
380 init_type = meta_get_init_type(argc, argv);
381
382 /*
383 * Metatrans is eof
384 */
385 if (init_type == TAB_TRANS)
386 return (mderror(ep, MDE_EOF_TRANS, NULL));
387
388 /* hotspare pool */
389 if (init_type == TAB_HSP)
390 return (meta_init_hsp(spp, argc, argv, options, ep));
391
392 /*
393 * We are creating metadevice so make sure the name
394 * has not been used
395 */
396 if (is_existing_meta_hsp(*spp, cname)) {
397 /*
398 * The name has been used by hsp
399 */
400 if (is_existing_hsp(*spp, cname)) {
401 return (mderror(ep, MDE_NAME_IN_USE, cname));
402 }
403
404 /*
405 * If path exists but unit is not created
406 * then meta_init_make_device will correct
407 * that. If unit also exists then it
408 * will return a conflict error
409 */
410 if (init_type != TAB_UNKNOWN) {
411 /* Create device node */
412 if ((key = meta_init_make_device(spp, uname,
413 &t_e)) <= 0) {
414 return (mdstealerror(ep, &t_e));
415 }
416 }
417 }
418
419 /* metadevice */
420 if (argc >= 2 && init_type != TAB_UNKNOWN) {
421 /*
422 * We need to create the device node if the specified metadevice
423 * does not already exist in the database. The actual creation
424 * is undertaken by the md driver and the links propagated by
425 * devfsadm.
426 */
427 if (key == MD_KEYWILD) {
428 if ((key = meta_init_make_device(spp, uname,
429 &t_e)) <= 0)
430 return (mdstealerror(ep, &t_e));
431 }
432
433 switch (init_type) {
434 case TAB_MIRROR:
435 rval = meta_init_mirror(spp, argc, argv, options, ep);
436 break;
437 case TAB_RAID:
438 rval = meta_init_raid(spp, argc, argv, options, ep);
439 break;
440 case TAB_SP:
441 rval = meta_init_sp(spp, argc, argv, options, ep);
442 break;
443 case TAB_STRIPE:
444 rval = meta_init_stripe(spp, argc, argv, options, ep);
445 break;
446 }
447
448 if (rval == -1 || !(options & MDCMD_DOIT)) {
449 /*
450 * Remove the device node created before
451 */
452 if ((meta_getnmentbykey((*spp)->setno, MD_SIDEWILD,
453 key, NULL, &mnum, NULL, ep) != NULL) &&
454 MD_MIN2UNIT(mnum) < MD_MAXUNITS) {
455 (void) metaioctl(MD_IOCREM_DEV, &mnum, &t_e, NULL);
456 }
457
458 /*
459 * Del what we added before
460 */
461 (void) del_self_name(*spp, key, &t_e);
462 }
463 return (rval);
464 }
465
466 /* unknown type */
467 p = Malloc(1 + strlen(uname) + 1 + 1);
468 (void) strcpy(p, "\"");
469 (void) strcat(p, uname);
470 (void) strcat(p, "\"");
471 rval = mderror(ep, MDE_SYNTAX, p);
472 Free(p);
473 return (rval);
474 }
475