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 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 /*
29 * attach submirrors
30 */
31
32 #include <meta.h>
33
34 #include <sdssc.h>
35
36 /*
37 * print usage message
38 */
39 static void
usage(mdsetname_t * sp,int eval)40 usage(
41 mdsetname_t *sp,
42 int eval
43 )
44 {
45 (void) fprintf(stderr, gettext("\
46 usage: %s [-s setname] mirror [metadevice]\n\
47 %s [-s setname] [-i interlace] concat/stripe component...\n\
48 %s [-s setname] RAID component...\n\
49 %s [-s setname] [-A alignment] softpart size|all\n"),
50 myname, myname, myname, myname);
51 md_exit(sp, eval);
52 }
53
54 /*
55 * attach more space to a soft partition
56 */
57 static int
sp_attach(mdsetname_t ** spp,mdname_t * spnp,int argc,char * argv[],mdcmdopts_t options,md_error_t * ep)58 sp_attach(
59 mdsetname_t **spp,
60 mdname_t *spnp,
61 int argc,
62 char *argv[],
63 mdcmdopts_t options,
64 md_error_t *ep
65 )
66 {
67 int c;
68 sp_ext_offset_t alignment = 0;
69
70 /* reset and parse args */
71 optind = 1;
72 opterr = 1;
73 while ((c = getopt(argc, argv, "ns:A:")) != -1) {
74 switch (c) {
75 case 'n':
76 case 's':
77 break;
78 case 'A':
79 if (meta_sp_parsesize(optarg, &alignment) == -1) {
80 usage(*spp, 1);
81 /* NOTREACHED */
82 }
83 break;
84 default:
85 usage(*spp, 1);
86 /* NOTREACHED */
87 break;
88 }
89 }
90 argc -= optind + 1;
91 argv += optind + 1;
92
93 if (argc != 1)
94 usage(*spp, 1);
95
96 if (meta_sp_attach(*spp, spnp, argv[0], options, alignment, ep) != 0) {
97 return (-1);
98 }
99
100 /* update md.cf file */
101 if (meta_update_md_cf(*spp, ep) != 0)
102 return (-1);
103
104 return (0);
105 }
106 /*
107 * attach components to stripe
108 */
109 static int
stripe_attach(mdsetname_t ** spp,mdname_t * stripenp,int argc,char * argv[],mdcmdopts_t options,md_error_t * ep)110 stripe_attach(
111 mdsetname_t **spp,
112 mdname_t *stripenp,
113 int argc,
114 char *argv[],
115 mdcmdopts_t options,
116 md_error_t *ep
117 )
118 {
119 diskaddr_t interlace = 0;
120 int c;
121 mdnamelist_t *compnlp = NULL;
122 mdnamelist_t *p;
123 mdname_t *currootnp;
124 md_stripe_t *stripep;
125 md_row_t *rp;
126 md_comp_t *cp;
127
128
129 /* reset and parse args */
130 optind = 1;
131 opterr = 1;
132 while ((c = getopt(argc, argv, "s:ani:")) != -1) {
133 switch (c) {
134 case 'n':
135 case 's':
136 break;
137
138 case 'a':
139 break; /* obsolete */
140
141 case 'i':
142 if (parse_interlace(stripenp->cname, optarg,
143 &interlace, ep) != 0) {
144 return (-1);
145 }
146 if (meta_stripe_check_interlace(interlace,
147 stripenp->cname, ep))
148 return (-1);
149 break;
150
151 default:
152 usage(*spp, 1);
153 /*NOTREACHED*/
154 break;
155 }
156 }
157
158 argc -= optind + 1;
159 argv += optind + 1;
160
161 if (argc <= 0)
162 usage(*spp, 1);
163
164 /* get list of components */
165 if (metanamelist(spp, &compnlp, argc, argv,
166 UNKNOWN, ep) < 0)
167 return (-1);
168 assert(compnlp != NULL);
169 for (p = compnlp; (p != NULL); p = p->next) {
170 mdname_t *compnp = p->namep;
171
172 /* see if we are a soft partition */
173 if (meta_sp_issp(*spp, compnp, ep) != 0) {
174 /* nope, check component */
175 if (metachkcomp(compnp, ep) != 0)
176 return (-1);
177 }
178 }
179
180 /* get root device */
181 if ((currootnp = meta_get_current_root_dev(*spp, ep)) != NULL) {
182 /*
183 * Root is either a stripe or a slice
184 * If root device is the 1st component of the stripe
185 * Then fail as root cannot be expanded
186 */
187 if ((stripep = meta_get_stripe(*spp, stripenp, ep)) == NULL)
188 return (-1);
189
190 rp = &stripep->rows.rows_val[0];
191 cp = &rp->comps.comps_val[0];
192 if (metachkcomp(cp->compnamep, ep) == 0) {
193 /* Component is a disk */
194 if (strcmp(currootnp->cname,
195 cp->compnamep->cname) == 0) {
196 md_eprintf(gettext(
197 "%s: volume mounted as root cannot be "
198 "expanded\n"), stripenp->cname);
199 md_exit(*spp, 1);
200 }
201 }
202 }
203
204 /* attach components */
205 if (meta_stripe_attach(*spp, stripenp, compnlp, interlace, options,
206 ep) != 0) {
207 return (-1);
208 }
209
210 /* update md.cf file */
211 if (meta_update_md_cf(*spp, ep) != 0)
212 return (-1);
213
214 /* return success */
215 return (0);
216 }
217
218 /*
219 * attach components to raid
220 */
221 static int
raid_attach(mdsetname_t ** spp,mdname_t * raidnp,int argc,char * argv[],mdcmdopts_t options,md_error_t * ep)222 raid_attach(
223 mdsetname_t **spp,
224 mdname_t *raidnp,
225 int argc,
226 char *argv[],
227 mdcmdopts_t options,
228 md_error_t *ep
229 )
230 {
231 int c;
232 mdnamelist_t *compnlp = NULL;
233 mdnamelist_t *p;
234
235 /* reset and parse args */
236 optind = 1;
237 opterr = 1;
238 while ((c = getopt(argc, argv, "s:ai:")) != -1) {
239 switch (c) {
240 case 'n':
241 case 's':
242 break;
243
244 case 'a':
245 break; /* obsolete */
246
247 default:
248 usage(*spp, 1);
249 /*NOTREACHED*/
250 break;
251 }
252 }
253 argc -= optind + 1;
254 argv += optind + 1;
255 if (argc <= 0)
256 usage(*spp, 1);
257
258 /* get list of components */
259 if (metanamelist(spp, &compnlp, argc, argv,
260 UNKNOWN, ep) < 0)
261 return (-1);
262 assert(compnlp != NULL);
263 for (p = compnlp; (p != NULL); p = p->next) {
264 mdname_t *compnp = p->namep;
265
266 /* check for soft partitions */
267 if (meta_sp_issp(*spp, compnp, ep) != 0) {
268 /* check disk */
269 if (metachkcomp(compnp, ep) != 0)
270 return (-1);
271 }
272 }
273
274 /* attach components */
275 if (meta_raid_attach(*spp, raidnp, compnlp, options, ep) != 0)
276 return (-1);
277
278 /* update md.cf file */
279 if (meta_update_md_cf(*spp, ep) != 0)
280 return (-1);
281
282 /* return success */
283 return (0);
284 }
285
286 /*
287 * attach submirror to mirror
288 */
289 static int
mirror_attach(mdsetname_t ** spp,mdname_t * mirnp,int argc,char * argv[],mdcmdopts_t options,md_error_t * ep)290 mirror_attach(
291 mdsetname_t **spp,
292 mdname_t *mirnp,
293 int argc,
294 char *argv[],
295 mdcmdopts_t options,
296 md_error_t *ep
297 )
298 {
299 int c;
300 mdname_t *submirnp;
301
302 /* reset and parse args */
303 optind = 1;
304 opterr = 1;
305 while ((c = getopt(argc, argv, "ns:")) != -1) {
306 switch (c) {
307 case 'n':
308 case 's':
309 break;
310
311 default:
312 usage(*spp, 1);
313 /*NOTREACHED*/
314 break;
315 }
316 }
317 argc -= optind + 1;
318 argv += optind + 1;
319
320 /* get submirror */
321 if (argc == 1) {
322 if (((submirnp = metaname(spp, argv[0], META_DEVICE,
323 ep)) == NULL) ||
324 (metachkmeta(submirnp, ep) != 0)) {
325 return (-1);
326 }
327 } else if (argc == 0) {
328 submirnp = NULL;
329 } else {
330 usage(*spp, 1);
331 }
332
333 /* attach submirror */
334 if (meta_mirror_attach(*spp, mirnp, submirnp, options, ep) != 0)
335 return (-1);
336
337 /* update md.cf file */
338 if (meta_update_md_cf(*spp, ep) != 0)
339 return (-1);
340
341 /* return success */
342 return (0);
343 }
344
345 /*
346 * attach devices
347 */
348 int
main(int argc,char * argv[])349 main(
350 int argc,
351 char *argv[]
352 )
353 {
354 char *sname = NULL;
355 mdsetname_t *sp = NULL;
356 mdcmdopts_t options = (MDCMD_PRINT|MDCMD_DOIT);
357 mdname_t *np;
358 char *miscname;
359 int c;
360 md_error_t status = mdnullerror;
361 md_error_t *ep = &status;
362 int error;
363 bool_t called_thru_rpc = FALSE;
364 char *cp;
365
366 /*
367 * Get the locale set up before calling any other routines
368 * with messages to ouput. Just in case we're not in a build
369 * environment, make sure that TEXT_DOMAIN gets set to
370 * something.
371 */
372 #if !defined(TEXT_DOMAIN)
373 #define TEXT_DOMAIN "SYS_TEST"
374 #endif
375 (void) setlocale(LC_ALL, "");
376 (void) textdomain(TEXT_DOMAIN);
377
378 /* initialize */
379 if ((cp = strstr(argv[0], ".rpc_call")) == NULL) {
380 if (sdssc_bind_library() == SDSSC_OKAY)
381 if (sdssc_cmd_proxy(argc, argv, SDSSC_PROXY_PRIMARY,
382 &error) == SDSSC_PROXY_DONE)
383 exit(error);
384 } else {
385 *cp = '\0'; /* cut off ".rpc_call" */
386 called_thru_rpc = TRUE;
387 }
388
389 if (md_init(argc, argv, 0, 1, ep) != 0 ||
390 meta_check_root(ep) != 0) {
391 mde_perror(ep, "");
392 md_exit(sp, 1);
393 }
394
395 /* find set and metadevice first */
396 optind = 1;
397 opterr = 1;
398 while ((c = getopt(argc, argv, "hns:A:ai:?")) != -1) {
399 switch (c) {
400 case 'h':
401 usage(sp, 0);
402 break;
403
404 case 'n':
405 if (called_thru_rpc == TRUE) {
406 options &= ~MDCMD_DOIT;
407 } else {
408 usage(sp, 1);
409 }
410 break;
411
412 case 's':
413 sname = optarg;
414 break;
415
416 case '?':
417 if (optopt == '?')
418 usage(sp, 0);
419 break;
420 }
421 }
422 if ((argc - optind) <= 0)
423 usage(sp, 1);
424
425 if (sname != NULL) {
426 if ((sp = metasetname(sname, ep)) == NULL) {
427 mde_perror(ep, "");
428 md_exit(sp, 1);
429 }
430 }
431
432 if (((np = metaname(&sp, argv[optind], META_DEVICE, ep)) == NULL) ||
433 (metachkmeta(np, ep) != 0)) {
434 mde_perror(ep, "");
435 md_exit(sp, 1);
436 }
437 assert(sp != NULL);
438
439 if ((called_thru_rpc == FALSE) &&
440 meta_is_mn_name(&sp, argv[optind], ep)) {
441 /*
442 * If we are dealing with a MN set and we were not
443 * called thru an rpc call, we are just to send this
444 * command string to the master of the set and let it
445 * deal with it.
446 * Note that if sp is NULL, meta_is_mn_name() derives sp
447 * from argv[optind] which is the metadevice arg
448 */
449 int i;
450 int newargc;
451 int result;
452 char **newargv;
453
454 if ((miscname = metagetmiscname(np, ep)) == NULL) {
455 mde_perror(ep, "");
456 md_exit(sp, 1);
457 }
458
459 newargv = calloc(argc+1, sizeof (char *));
460 newargv[0] = "metattach";
461 newargv[1] = "-n"; /* always do "-n" first */
462 newargc = 2;
463 for (i = 1; i < argc; i++, newargc++)
464 newargv[newargc] = argv[i];
465
466 result = meta_mn_send_command(sp, newargc, newargv,
467 MD_DISP_STDERR | MD_DRYRUN, NO_CONTEXT_STRING, ep);
468
469 /* If we found a problem don't do it for real */
470 if (result != 0) {
471 md_exit(sp, result);
472 }
473
474 /*
475 * Do it for real now. Remove "-n" from the arguments and
476 * MD_DRYRUN from the flags. If we fail now, the master must
477 * panic as the mddbs may be inconsistent.
478 */
479 newargv[1] = ""; /* this was "-n" before */
480 result = meta_mn_send_command(sp, newargc, newargv,
481 MD_DISP_STDERR | MD_RETRY_BUSY | MD_PANIC_WHEN_INCONSISTENT,
482 NO_CONTEXT_STRING, ep);
483
484 free(newargv);
485
486 /*
487 * If the metattach command succeeds, for a mirror, send a
488 * resync starting message for the metadevice
489 */
490 if ((result == 0) && (strcmp(miscname, MD_MIRROR) == 0))
491 if ((result = meta_mn_send_resync_starting(np, ep))
492 != 0)
493 mde_perror(ep, "Unable to start resync");
494 md_exit(sp, result);
495 }
496
497 if (meta_lock(sp, TRUE, ep)) {
498 mde_perror(ep, "");
499 md_exit(sp, 1);
500 }
501
502 if (meta_check_ownership(sp, ep) != 0) {
503 mde_perror(ep, "");
504 md_exit(sp, 1);
505 }
506 if ((miscname = metagetmiscname(np, ep)) == NULL) {
507 mde_perror(ep, "");
508 md_exit(sp, 1);
509 }
510
511 /* dispatch based on device type */
512 if (strcmp(miscname, MD_STRIPE) == 0) {
513 if (stripe_attach(&sp, np, argc, argv, options, ep) != 0) {
514 mde_perror(ep, "");
515 md_exit(sp, 1);
516 }
517 } else if (strcmp(miscname, MD_RAID) == 0) {
518 if (raid_attach(&sp, np, argc, argv, options, ep) != 0) {
519 mde_perror(ep, "");
520 md_exit(sp, 1);
521 }
522 } else if (strcmp(miscname, MD_MIRROR) == 0) {
523 if (mirror_attach(&sp, np, argc, argv, options, ep) != 0) {
524 mde_perror(ep, "");
525 md_exit(sp, 1);
526 }
527 } else if (strcmp(miscname, MD_TRANS) == 0) {
528 md_eprintf(gettext(MD_EOF_TRANS_MSG));
529 md_exit(sp, 1);
530 } else if (strcmp(miscname, MD_SP) == 0) {
531 if (sp_attach(&sp, np, argc, argv, options, ep) != 0) {
532 mde_perror(ep, "");
533 md_exit(sp, 1);
534 }
535 } else {
536 md_eprintf(gettext(
537 "%s: invalid metadevice type %s\n"),
538 np->cname, miscname);
539 md_exit(sp, 1);
540 }
541
542 /* return success */
543 md_exit(sp, 0);
544 /*NOTREACHED*/
545 return (0);
546 }
547