xref: /titanic_41/usr/src/cmd/lvm/util/metattach.c (revision 4eaa471005973e11a6110b69fe990530b3b95a38)
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
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
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
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
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
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
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