xref: /titanic_41/usr/src/cmd/lvm/util/metattach.c (revision d58fda4376e4bf67072ce2e69f6f47036f9dbb68)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 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  * attach submirrors
31  */
32 
33 #include <meta.h>
34 
35 #include <sdssc.h>
36 
37 /*
38  * print usage message
39  */
40 static void
41 usage(
42 	mdsetname_t	*sp,
43 	int		eval
44 )
45 {
46 	(void) fprintf(stderr, gettext("\
47 usage:	%s [-s setname] mirror [metadevice]\n\
48 	%s [-s setname] [-i interlace] concat/stripe component...\n\
49 	%s [-s setname] RAID component...\n\
50 	%s [-s setname] [-A alignment] softpart size|all\n"),
51 	    myname, myname, myname, myname);
52 	md_exit(sp, eval);
53 }
54 
55 /*
56  * attach more space to a soft partition
57  */
58 static int
59 sp_attach(
60 	mdsetname_t	**spp,
61 	mdname_t	*spnp,
62 	int		argc,
63 	char		*argv[],
64 	mdcmdopts_t	options,
65 	md_error_t	*ep
66 )
67 {
68 	int		c;
69 	sp_ext_offset_t	alignment = 0;
70 
71 	/* reset and parse args */
72 	optind = 1;
73 	opterr = 1;
74 	while ((c = getopt(argc, argv, "ns:A:")) != -1) {
75 		switch (c) {
76 		case 'n':
77 		case 's':
78 			break;
79 		case 'A':
80 			if (meta_sp_parsesize(optarg, &alignment) == -1) {
81 			    usage(*spp, 1);
82 			    /* NOTREACHED */
83 			}
84 			break;
85 		default:
86 			usage(*spp, 1);
87 			/* NOTREACHED */
88 			break;
89 		}
90 	}
91 	argc -= optind + 1;
92 	argv += optind + 1;
93 
94 	if (argc != 1)
95 		usage(*spp, 1);
96 
97 	if (meta_sp_attach(*spp, spnp, argv[0], options, alignment, ep) != 0) {
98 		return (-1);
99 	}
100 
101 	/* update md.cf file */
102 	if (meta_update_md_cf(*spp, ep) != 0)
103 		return (-1);
104 
105 	return (0);
106 }
107 /*
108  * attach components to stripe
109  */
110 static int
111 stripe_attach(
112 	mdsetname_t	**spp,
113 	mdname_t	*stripenp,
114 	int		argc,
115 	char		*argv[],
116 	mdcmdopts_t	options,
117 	md_error_t	*ep
118 )
119 {
120 	diskaddr_t	interlace = 0;
121 	int		c;
122 	mdnamelist_t	*compnlp = NULL;
123 	mdnamelist_t	*p;
124 	mdname_t	*currootnp;
125 	md_stripe_t	*stripep;
126 	md_row_t	*rp;
127 	md_comp_t	*cp;
128 
129 
130 	/* reset and parse args */
131 	optind = 1;
132 	opterr = 1;
133 	while ((c = getopt(argc, argv, "s:ani:")) != -1) {
134 		switch (c) {
135 		case 'n':
136 		case 's':
137 			break;
138 
139 		case 'a':
140 			break;	/* obsolete */
141 
142 		case 'i':
143 			if (parse_interlace(stripenp->cname, optarg,
144 			    &interlace, ep) != 0) {
145 				return (-1);
146 			}
147 			if (meta_stripe_check_interlace(interlace,
148 			    stripenp->cname, ep))
149 				return (-1);
150 			break;
151 
152 		default:
153 			usage(*spp, 1);
154 			/*NOTREACHED*/
155 			break;
156 		}
157 	}
158 
159 	argc -= optind + 1;
160 	argv += optind + 1;
161 
162 	if (argc <= 0)
163 		usage(*spp, 1);
164 
165 	/* get list of components */
166 	if (metanamelist(spp, &compnlp, argc, argv, 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, ep) < 0)
260 		return (-1);
261 	assert(compnlp != NULL);
262 	for (p = compnlp; (p != NULL); p = p->next) {
263 		mdname_t	*compnp = p->namep;
264 
265 		/* check for soft partitions */
266 		if (meta_sp_issp(*spp, compnp, ep) != 0) {
267 			/* check disk */
268 			if (metachkcomp(compnp, ep) != 0)
269 				return (-1);
270 		}
271 	}
272 
273 	/* attach components */
274 	if (meta_raid_attach(*spp, raidnp, compnlp, options, ep) != 0)
275 		return (-1);
276 
277 	/* update md.cf file */
278 	if (meta_update_md_cf(*spp, ep) != 0)
279 		return (-1);
280 
281 	/* return success */
282 	return (0);
283 }
284 
285 /*
286  * attach submirror to mirror
287  */
288 static int
289 mirror_attach(
290 	mdsetname_t	**spp,
291 	mdname_t	*mirnp,
292 	int		argc,
293 	char		*argv[],
294 	mdcmdopts_t	options,
295 	md_error_t	*ep
296 )
297 {
298 	int		c;
299 	mdname_t	*submirnp;
300 
301 	/* reset and parse args */
302 	optind = 1;
303 	opterr = 1;
304 	while ((c = getopt(argc, argv, "ns:")) != -1) {
305 		switch (c) {
306 		case 'n':
307 		case 's':
308 			break;
309 
310 		default:
311 			usage(*spp, 1);
312 			/*NOTREACHED*/
313 			break;
314 		}
315 	}
316 	argc -= optind + 1;
317 	argv += optind + 1;
318 
319 	/* get submirror */
320 	if (argc == 1) {
321 		if (((submirnp = metaname(spp, argv[0], ep)) == NULL) ||
322 		    (metachkmeta(submirnp, ep) != 0)) {
323 			return (-1);
324 		}
325 	} else if (argc == 0) {
326 		submirnp = NULL;
327 	} else {
328 		usage(*spp, 1);
329 	}
330 
331 	/* attach submirror */
332 	if (meta_mirror_attach(*spp, mirnp, submirnp, options, ep) != 0)
333 		return (-1);
334 
335 	/* update md.cf file */
336 	if (meta_update_md_cf(*spp, ep) != 0)
337 		return (-1);
338 
339 	/* return success */
340 	return (0);
341 }
342 
343 /*
344  * attach devices
345  */
346 int
347 main(
348 	int		argc,
349 	char		*argv[]
350 )
351 {
352 	char		*sname = NULL;
353 	mdsetname_t	*sp = NULL;
354 	mdcmdopts_t	options = (MDCMD_PRINT|MDCMD_DOIT);
355 	mdname_t	*np;
356 	char		*miscname;
357 	int		c;
358 	md_error_t	status = mdnullerror;
359 	md_error_t	*ep = &status;
360 	int		error;
361 	bool_t		called_thru_rpc = FALSE;
362 	char		*cp;
363 
364 	/*
365 	 * Get the locale set up before calling any other routines
366 	 * with messages to ouput.  Just in case we're not in a build
367 	 * environment, make sure that TEXT_DOMAIN gets set to
368 	 * something.
369 	 */
370 #if !defined(TEXT_DOMAIN)
371 #define	TEXT_DOMAIN "SYS_TEST"
372 #endif
373 	(void) setlocale(LC_ALL, "");
374 	(void) textdomain(TEXT_DOMAIN);
375 
376 	/* initialize */
377 	if ((cp = strstr(argv[0], ".rpc_call")) == NULL) {
378 		if (sdssc_bind_library() == SDSSC_OKAY)
379 			if (sdssc_cmd_proxy(argc, argv, SDSSC_PROXY_PRIMARY,
380 						&error) == SDSSC_PROXY_DONE)
381 				exit(error);
382 	} else {
383 		*cp = '\0'; /* cut off ".rpc_call" */
384 		called_thru_rpc = TRUE;
385 	}
386 
387 	if (md_init(argc, argv, 0, 1, ep) != 0 ||
388 			meta_check_root(ep) != 0) {
389 		mde_perror(ep, "");
390 		md_exit(sp, 1);
391 	}
392 
393 	/* find set and metadevice first */
394 	optind = 1;
395 	opterr = 1;
396 	while ((c = getopt(argc, argv, "hns:A:ai:?")) != -1) {
397 		switch (c) {
398 		case 'h':
399 			usage(sp, 0);
400 			break;
401 
402 		case 'n':
403 			if (called_thru_rpc == TRUE) {
404 				options &= ~MDCMD_DOIT;
405 			} else {
406 				usage(sp, 1);
407 			}
408 			break;
409 
410 		case 's':
411 			sname = optarg;
412 			break;
413 
414 		case '?':
415 			if (optopt == '?')
416 				usage(sp, 0);
417 			break;
418 		}
419 	}
420 	if ((argc - optind) <= 0)
421 		usage(sp, 1);
422 
423 	if (sname != NULL) {
424 		if ((sp = metasetname(sname, ep)) == NULL) {
425 			mde_perror(ep, "");
426 			md_exit(sp, 1);
427 		}
428 	}
429 
430 	if (((np = metaname(&sp, argv[optind], ep)) == NULL) ||
431 	    (metachkmeta(np, ep) != 0)) {
432 		mde_perror(ep, "");
433 		md_exit(sp, 1);
434 	}
435 	assert(sp != NULL);
436 
437 	if ((called_thru_rpc == FALSE) &&
438 	    meta_is_mn_name(&sp, argv[optind], ep)) {
439 		/*
440 		 * If we are dealing with a MN set and we were not
441 		 * called thru an rpc call, we are just to send this
442 		 * command string to the master of the set and let it
443 		 * deal with it.
444 		 * Note that if sp is NULL, meta_is_mn_name() derives sp
445 		 * from argv[optind] which is the metadevice arg
446 		 */
447 		int	i;
448 		int	newargc;
449 		int	result;
450 		char	**newargv;
451 
452 		if ((miscname = metagetmiscname(np, ep)) == NULL) {
453 			mde_perror(ep, "");
454 			md_exit(sp, 1);
455 		}
456 
457 		newargv = calloc(argc+1, sizeof (char *));
458 		newargv[0] = "metattach";
459 		newargv[1] = "-n"; /* always do "-n" first */
460 		newargc = 2;
461 		for (i = 1; i < argc; i++, newargc++)
462 			newargv[newargc] = argv[i];
463 
464 		result = meta_mn_send_command(sp, newargc, newargv,
465 		    MD_DISP_STDERR | MD_DRYRUN, NO_CONTEXT_STRING, ep);
466 
467 		/* If we found a problem don't do it for real */
468 		if (result != 0) {
469 			md_exit(sp, result);
470 		}
471 
472 		/*
473 		 * Do it for real now. Remove "-n" from the arguments and
474 		 * MD_DRYRUN from the flags. If we fail now, the master must
475 		 * panic as the mddbs may be inconsistent.
476 		 */
477 		newargv[1] = ""; /* this was "-n" before */
478 		result = meta_mn_send_command(sp, newargc, newargv,
479 		    MD_DISP_STDERR | MD_RETRY_BUSY | MD_PANIC_WHEN_INCONSISTENT,
480 		    NO_CONTEXT_STRING, ep);
481 
482 		free(newargv);
483 
484 		/*
485 		 * If the metattach command succeeds, for a mirror, send a
486 		 * resync starting message for the metadevice
487 		 */
488 		if ((result == 0) && (strcmp(miscname, MD_MIRROR) == 0))
489 			if ((result = meta_mn_send_resync_starting(np, ep))
490 			    != 0)
491 				mde_perror(ep, "Unable to start resync");
492 		md_exit(sp, result);
493 	}
494 
495 	if (meta_lock(sp, TRUE, ep)) {
496 		mde_perror(ep, "");
497 		md_exit(sp, 1);
498 	}
499 
500 	if (meta_check_ownership(sp, ep) != 0) {
501 		mde_perror(ep, "");
502 		md_exit(sp, 1);
503 	}
504 	if ((miscname = metagetmiscname(np, ep)) == NULL) {
505 		mde_perror(ep, "");
506 		md_exit(sp, 1);
507 	}
508 
509 	/* dispatch based on device type */
510 	if (strcmp(miscname, MD_STRIPE) == 0) {
511 		if (stripe_attach(&sp, np, argc, argv, options, ep) != 0) {
512 			mde_perror(ep, "");
513 			md_exit(sp, 1);
514 		}
515 	} else if (strcmp(miscname, MD_RAID) == 0) {
516 		if (raid_attach(&sp, np, argc, argv, options, ep) != 0) {
517 			mde_perror(ep, "");
518 			md_exit(sp, 1);
519 		}
520 	} else if (strcmp(miscname, MD_MIRROR) == 0) {
521 		if (mirror_attach(&sp, np, argc, argv, options, ep) != 0) {
522 			mde_perror(ep, "");
523 			md_exit(sp, 1);
524 		}
525 	} else if (strcmp(miscname, MD_TRANS) == 0) {
526 		md_eprintf(gettext(MD_EOF_TRANS_MSG));
527 		md_exit(sp, 1);
528 	} else if (strcmp(miscname, MD_SP) == 0) {
529 		if (sp_attach(&sp, np, argc, argv, options, ep) != 0) {
530 			mde_perror(ep, "");
531 			md_exit(sp, 1);
532 		}
533 	} else {
534 		md_eprintf(gettext(
535 		    "%s: invalid metadevice type %s\n"),
536 		    np->cname, miscname);
537 		md_exit(sp, 1);
538 	}
539 
540 	/* return success */
541 	md_exit(sp, 0);
542 	/*NOTREACHED*/
543 	return (0);
544 }
545