xref: /titanic_41/usr/src/cmd/lvm/util/metahs.c (revision 70025d765b044c6d8594bb965a2247a61e991a99)
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 2004 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  * hotspare maintenance
31  */
32 
33 #include <meta.h>
34 #include <sdssc.h>
35 
36 /*
37  * possible actions
38  */
39 enum metahs_op {
40 	NONE,
41 	ADD_A_HS,
42 	DELETE_A_HS,
43 	ENABLE_A_HS,
44 	REPLACE_A_HS,
45 	STATUS_A_HSP
46 };
47 
48 /*
49  * report status of a hotspare pool
50  */
51 static int
52 status_hsp(
53 	mdsetname_t	*sp,
54 	mdhspname_t	*hspnp,
55 	md_error_t	*ep
56 )
57 {
58 	mdprtopts_t	options = (PRINT_HEADER | PRINT_SUBDEVS | PRINT_DEVID);
59 	mdnamelist_t	*nlp = NULL;
60 
61 	/* must have set */
62 	assert(sp != NULL);
63 	assert(sp->setno == HSP_SET(hspnp->hsp));
64 
65 	/* print status */
66 	if (meta_hsp_print(sp, hspnp, &nlp, NULL, stdout, options, ep) != 0)
67 		return (-1);
68 
69 	/* return success */
70 	return (0);
71 }
72 
73 /*
74  * print usage message
75  */
76 static void
77 usage(
78 	mdsetname_t	*sp,
79 	int		eval
80 )
81 {
82 	(void) fprintf(stderr, gettext("\
83 usage:	%s [-s setname] -a hot_spare_pool [component...]\n\
84 	%s [-s setname] -a \"all\" component...\n\
85 	%s [-s setname] -d hot_spare_pool [component...]\n\
86 	%s [-s setname] -d \"all\" component...\n\
87 	%s [-s setname] -e component...\n\
88 	%s [-s setname] -r hot_spare_pool component_old component_new\n\
89 	%s [-s setname] -r \"all\" component_old component_new\n\
90 	%s [-s setname] -i [hot_spare_pool...]\n"),
91 	    myname, myname, myname, myname, myname, myname, myname, myname);
92 	md_exit(sp, eval);
93 }
94 
95 /*
96  * check for "all"
97  */
98 static int
99 is_all(char *s)
100 {
101 	if ((strcoll(s, gettext("all")) == 0) ||
102 	    (strcoll(s, gettext("ALL")) == 0))
103 		return (1);
104 	return (0);
105 }
106 
107 /*
108  * parse args and add hotspares
109  */
110 static int
111 add_hotspares(
112 	mdsetname_t	**spp,
113 	int		argc,
114 	char		*argv[],
115 	mdcmdopts_t	options,
116 	md_error_t	*ep
117 )
118 {
119 	mdhspnamelist_t	*hspnlp = NULL;
120 	mdnamelist_t	*nlp = NULL;
121 	int		cnt;
122 	mdhspnamelist_t	*p;
123 	int		rval = -1;
124 
125 	/* get hotspare pool name(s) */
126 	if (argc < 1)
127 		usage(*spp, 1);
128 	if ((argc > 1) && is_all(argv[0])) {
129 		if ((*spp == NULL) &&
130 		    ((*spp = metasetname(MD_LOCAL_NAME, ep)) == NULL)) {
131 			return (-1);
132 		}
133 		/* check for ownership */
134 		assert(*spp != NULL);
135 		if (meta_check_ownership(*spp, ep) != 0)
136 			return (-1);
137 
138 		if ((cnt = meta_get_hsp_names(*spp, &hspnlp, 0, ep)) < 0) {
139 			return (-1);
140 		} else if (cnt == 0) {
141 			return (mderror(ep, MDE_NO_HSPS, NULL));
142 		}
143 	} else if ((cnt = metahspnamelist(spp, &hspnlp, 1, &argv[0],
144 	    ep)) < 0) {
145 		return (-1);
146 	}
147 	assert(cnt > 0);
148 	--argc, ++argv;
149 
150 	assert(*spp != NULL);
151 
152 	/* grab set lock */
153 	if (meta_lock(*spp, TRUE, ep))
154 		return (-1);
155 
156 	/* check for ownership */
157 	if (meta_check_ownership(*spp, ep) != 0)
158 		return (-1);
159 
160 	/* get hotspares */
161 	if (metanamelist(spp, &nlp, argc, argv, ep) < 0) {
162 		goto out;
163 	}
164 
165 	/* add hotspares */
166 	for (p = hspnlp; (p != NULL); p = p->next) {
167 		mdhspname_t	*hspnp = p->hspnamep;
168 
169 		if (meta_hs_add(*spp, hspnp, nlp, options, ep) != 0)
170 			goto out;
171 	}
172 	rval = 0;
173 
174 	/* cleanup, return success */
175 out:
176 	if (hspnlp != NULL)
177 		metafreehspnamelist(hspnlp);
178 	if (nlp != NULL)
179 		metafreenamelist(nlp);
180 	return (rval);
181 }
182 
183 /*
184  * parse args and delete hotspares
185  */
186 static int
187 delete_hotspares(
188 	mdsetname_t	**spp,
189 	int		argc,
190 	char		*argv[],
191 	mdcmdopts_t	options,
192 	md_error_t	*ep
193 )
194 {
195 	mdhspnamelist_t	*hspnlp = NULL;
196 	mdnamelist_t	*nlp = NULL;
197 	int		cnt;
198 	mdhspnamelist_t	*p;
199 	int		rval = -1;
200 
201 	/* get hotspare pool name(s) */
202 	if (argc < 1)
203 		usage(*spp, 1);
204 	if ((argc > 1) && is_all(argv[0])) {
205 		if ((*spp == NULL) &&
206 		    ((*spp = metasetname(MD_LOCAL_NAME, ep)) == NULL)) {
207 			return (-1);
208 		}
209 		/* check for ownership */
210 		assert(*spp != NULL);
211 		if (meta_check_ownership(*spp, ep) != 0)
212 			return (-1);
213 
214 		if ((cnt = meta_get_hsp_names(*spp, &hspnlp, 0, ep)) < 0) {
215 			return (-1);
216 		} else if (cnt == 0) {
217 			return (mderror(ep, MDE_NO_HSPS, NULL));
218 		}
219 	} else if ((cnt = metahspnamelist(spp, &hspnlp, 1, &argv[0],
220 	    ep)) < 0) {
221 		return (-1);
222 	}
223 	assert(cnt > 0);
224 	--argc, ++argv;
225 
226 	assert(*spp != NULL);
227 
228 	/* grab set lock */
229 	if (meta_lock(*spp, TRUE, ep))
230 		return (-1);
231 
232 	/* check for ownership */
233 	if (meta_check_ownership(*spp, ep) != 0)
234 		return (-1);
235 
236 	/* get hotspares */
237 	if (metanamelist(spp, &nlp, argc, argv, ep) < 0) {
238 		goto out;
239 	}
240 
241 	/* delete hotspares */
242 	cnt = 0;
243 	for (p = hspnlp; (p != NULL); p = p->next) {
244 		mdhspname_t	*hspnp = p->hspnamep;
245 
246 		if (meta_hs_delete(*spp, hspnp, nlp, options, ep) != 0) {
247 			if (mdisdeverror(ep, MDE_INVAL_HS))
248 				mdclrerror(ep);
249 			else
250 				goto out;
251 		} else {
252 			++cnt;
253 		}
254 	}
255 
256 	/* make sure we got some */
257 	if ((nlp != NULL) && (cnt == 0)) {
258 		(void) mddeverror(ep, MDE_INVAL_HS, nlp->namep->dev,
259 		    nlp->namep->cname);
260 		goto out;
261 	}
262 
263 	/* success */
264 	rval = 0;
265 
266 	/* cleanup, return success */
267 out:
268 	if (hspnlp != NULL)
269 		metafreehspnamelist(hspnlp);
270 	if (nlp != NULL)
271 		metafreenamelist(nlp);
272 	return (rval);
273 }
274 
275 /*
276  * parse args and enable hotspares
277  */
278 static int
279 enable_hotspares(
280 	mdsetname_t	**spp,
281 	int		argc,
282 	char		*argv[],
283 	mdcmdopts_t	options,
284 	md_error_t	*ep
285 )
286 {
287 	mdnamelist_t	*nlp = NULL;
288 	int		rval = -1;
289 
290 	/* enable hotspares */
291 	if (argc < 1)
292 		usage(*spp, 1);
293 
294 	/* get list of hotspares */
295 	if (metanamelist(spp, &nlp, argc, argv, ep) < 0)
296 		goto out;
297 	assert(nlp != NULL);
298 
299 	assert(*spp != NULL);
300 
301 	/* grab set lock */
302 	if (meta_lock(*spp, TRUE, ep))
303 		return (-1);
304 
305 	/* check for ownership */
306 	if (meta_check_ownership(*spp, ep) != 0)
307 		return (-1);
308 
309 	/* enable hotspares */
310 	rval = meta_hs_enable(*spp, nlp, options, ep);
311 
312 	/* cleanup, return success */
313 out:
314 	metafreenamelist(nlp);
315 	return (rval);
316 }
317 
318 /*
319  * parse args and replace hotspares
320  */
321 static int
322 replace_hotspares(
323 	mdsetname_t	**spp,
324 	int		argc,
325 	char		*argv[],
326 	mdcmdopts_t	options,
327 	md_error_t	*ep
328 )
329 {
330 	mdhspnamelist_t	*hspnlp = NULL;
331 	int		cnt;
332 	mdname_t	*oldnp;
333 	mdname_t	*newnp;
334 	mdhspnamelist_t	*p;
335 	int		rval = -1;
336 
337 	/* get hotspare pool name(s) */
338 	if (argc != 3)
339 		usage(*spp, 1);
340 	if (is_all(argv[0])) {
341 		if ((*spp == NULL) &&
342 		    ((*spp = metasetname(MD_LOCAL_NAME, ep)) == NULL)) {
343 			return (-1);
344 		}
345 		/* check for ownership */
346 		assert(*spp != NULL);
347 		if (meta_check_ownership(*spp, ep) != 0)
348 			return (-1);
349 
350 		if ((cnt = meta_get_hsp_names(*spp, &hspnlp, 0, ep)) < 0) {
351 			return (-1);
352 		} else if (cnt == 0) {
353 			return (mderror(ep, MDE_NO_HSPS, NULL));
354 		}
355 	} else if ((cnt = metahspnamelist(spp, &hspnlp, 1, &argv[0],
356 	    ep)) < 0) {
357 		return (-1);
358 	}
359 	assert(cnt > 0);
360 
361 	assert(*spp != NULL);
362 
363 	/* grab set lock */
364 	if (meta_lock(*spp, TRUE, ep))
365 		return (-1);
366 
367 	/* check for ownership */
368 	if (meta_check_ownership(*spp, ep) != 0)
369 		return (-1);
370 
371 	/* get old component */
372 	if ((oldnp = metaname(spp, argv[1], ep)) == NULL)
373 		goto out;
374 
375 	/* get new component */
376 	if ((newnp = metaname(spp, argv[2], ep)) == NULL)
377 		goto out;
378 
379 	/* replace hotspares */
380 	cnt = 0;
381 	for (p = hspnlp; (p != NULL); p = p->next) {
382 		mdhspname_t	*hspnp = p->hspnamep;
383 
384 		if (meta_hs_replace(*spp, hspnp, oldnp, newnp, options, ep)
385 		    != 0) {
386 			if (mdisdeverror(ep, MDE_INVAL_HS))
387 				mdclrerror(ep);
388 			else
389 				goto out;
390 		} else {
391 			++cnt;
392 		}
393 	}
394 
395 	/* make sure we got some */
396 	if (cnt == 0) {
397 		(void) mddeverror(ep, MDE_INVAL_HS, oldnp->dev, oldnp->cname);
398 		goto out;
399 	}
400 
401 	/* success */
402 	rval = 0;
403 
404 	/* cleanup, return success */
405 out:
406 	if (hspnlp != NULL)
407 		metafreehspnamelist(hspnlp);
408 	return (rval);
409 }
410 
411 /*
412  * print_hsp_devid will collect the information for each underlying
413  * physical device for all the hotspare pools and print out the
414  * device relocation information
415  * INPUT:
416  *	mdsetname_t *sp			set the hsp is in
417  *	mdhspnamelist_t *hspnlp		list of hsp
418  *	FILE	*fp			where to print to
419  *	md_error_t	*ep		errors
420  * RETURN:
421  *	0 	SUCCESS
422  *	-1	ERROR
423  */
424 static int
425 print_hsp_devid(
426 	mdsetname_t	*sp,
427 	mdhspnamelist_t *hspnlp,
428 	FILE		*fp,
429 	md_error_t	*ep
430 )
431 {
432 	mddevid_t	*ldevidp = NULL;
433 	int		retval = 0;
434 	mdhspnamelist_t	*p;
435 	mddevid_t	*nextp;
436 
437 	/* for all hotspare pools */
438 	for (p = hspnlp; (p != NULL); p = p->next) {
439 		mdhspname_t	*hspnp = p->hspnamep;
440 		uint_t		hsi;
441 
442 		/* for all hotspares within a pool */
443 		for (hsi = 0;
444 		    hsi < hspnp->unitp->hotspares.hotspares_len; hsi++) {
445 			mdname_t	*hsname;
446 
447 			hsname =
448 			    hspnp->unitp->hotspares.hotspares_val[hsi].hsnamep;
449 
450 			meta_create_non_dup_list(hsname, &ldevidp);
451 		}
452 	}
453 
454 	retval = meta_print_devid(sp, fp, ldevidp, ep);
455 
456 	/* cleanup */
457 	for (nextp = ldevidp; nextp != NULL; ldevidp = nextp) {
458 		Free(ldevidp->ctdname);
459 		nextp = ldevidp->next;
460 		Free(ldevidp);
461 	}
462 	return (retval);
463 }
464 
465 /*
466  * parse args and status hotspares
467  */
468 static int
469 status_hotspares(
470 	mdsetname_t	**spp,
471 	int		argc,
472 	char		*argv[],
473 	md_error_t	*ep
474 )
475 {
476 	mdhspnamelist_t	*hspnlp = NULL;
477 	int		cnt;
478 	mdhspnamelist_t	*p;
479 	int		rval = -1;
480 
481 	/* get hotspare pool name(s) */
482 	if (argc == 0) {
483 		if ((*spp == NULL) &&
484 		    ((*spp = metasetname(MD_LOCAL_NAME, ep)) == NULL)) {
485 			return (-1);
486 		}
487 		/* check for ownership */
488 		assert(*spp != NULL);
489 		if (meta_check_ownership(*spp, ep) != 0)
490 			return (-1);
491 
492 		if ((cnt = meta_get_hsp_names(*spp, &hspnlp, 0, ep)) < 0) {
493 			return (-1);
494 		} else if (cnt == 0) {
495 			return (mderror(ep, MDE_NO_HSPS, NULL));
496 		}
497 	} else if ((cnt = metahspnamelist(spp, &hspnlp, argc, argv, ep)) < 0) {
498 		return (-1);
499 	}
500 	assert(cnt > 0);
501 
502 	/* check for ownership */
503 	assert(*spp != NULL);
504 	if (meta_check_ownership(*spp, ep) != 0)
505 		return (-1);
506 
507 	/* status hotspare pools */
508 	for (p = hspnlp; (p != NULL); p = p->next) {
509 		mdhspname_t	*hspnp = p->hspnamep;
510 
511 		if (status_hsp(*spp, hspnp, ep) != 0)
512 			goto out;
513 	}
514 
515 	if (print_hsp_devid(*spp, hspnlp, stdout, ep) == 0) {
516 		rval = 0;
517 	}
518 
519 	/* cleanup, return success */
520 out:
521 	if (hspnlp != NULL)
522 		metafreehspnamelist(hspnlp);
523 	return (rval);
524 }
525 
526 /*
527  * parse args and doit
528  */
529 int
530 main(
531 	int		argc,
532 	char		**argv
533 )
534 {
535 	char		*sname = MD_LOCAL_NAME;
536 	mdsetname_t	*sp = NULL;
537 	enum metahs_op	which_op = NONE;
538 	mdcmdopts_t	options = (MDCMD_PRINT | MDCMD_DOIT);
539 	int		c;
540 	md_error_t	status = mdnullerror;
541 	md_error_t	*ep = &status;
542 	int		error;
543 	bool_t		called_thru_rpc = FALSE;
544 	char		*cp;
545 
546 	/*
547 	 * Get the locale set up before calling any other routines
548 	 * with messages to ouput.  Just in case we're not in a build
549 	 * environment, make sure that TEXT_DOMAIN gets set to
550 	 * something.
551 	 */
552 #if !defined(TEXT_DOMAIN)
553 #define	TEXT_DOMAIN "SYS_TEST"
554 #endif
555 	(void) setlocale(LC_ALL, "");
556 	(void) textdomain(TEXT_DOMAIN);
557 
558 
559 	if ((cp = strstr(argv[0], ".rpc_call")) == NULL) {
560 		if (sdssc_bind_library() == SDSSC_OKAY)
561 			if (sdssc_cmd_proxy(argc, argv, SDSSC_PROXY_PRIMARY,
562 						&error) == SDSSC_PROXY_DONE)
563 				exit(error);
564 	} else {
565 		*cp = '\0'; /* cut off ".rpc_call" */
566 		called_thru_rpc = TRUE;
567 	}
568 
569 	/* initialize */
570 	if (md_init(argc, argv, 0, 1, ep) != 0) {
571 		mde_perror(ep, "");
572 		md_exit(sp, 1);
573 	}
574 
575 	/* parse args */
576 	optind = 1;
577 	opterr = 1;
578 	while ((c = getopt(argc, argv, "hs:aderin?")) != -1) {
579 		switch (c) {
580 		case 'h':
581 			usage(sp, 0);
582 			break;
583 
584 		case 's':
585 			sname = optarg;
586 			break;
587 
588 		case 'a':
589 			if (which_op != NONE)
590 				usage(sp, 1);
591 			which_op = ADD_A_HS;
592 			break;
593 
594 		case 'd':
595 			if (which_op != NONE)
596 				usage(sp, 1);
597 			which_op = DELETE_A_HS;
598 			break;
599 
600 		case 'e':
601 			if (which_op != NONE)
602 				usage(sp, 1);
603 			which_op = ENABLE_A_HS;
604 			break;
605 
606 		case 'r':
607 			if (which_op != NONE)
608 				usage(sp, 1);
609 			which_op = REPLACE_A_HS;
610 			break;
611 
612 		case 'i':
613 			if (which_op != NONE)
614 				usage(sp, 1);
615 			which_op = STATUS_A_HSP;
616 			break;
617 
618 		case 'n':
619 			if (called_thru_rpc == TRUE) {
620 				options &= ~MDCMD_DOIT;
621 			} else {
622 				usage(sp, 1);
623 			}
624 			break;
625 
626 
627 		case '?':
628 			if (optopt == '?')
629 				usage(sp, 0);
630 			/*FALLTHROUGH*/
631 		default:
632 			usage(sp, 1);
633 			break;
634 		}
635 	}
636 
637 	/* get set context */
638 	if ((sp = metasetname(sname, ep)) == NULL) {
639 		mde_perror(ep, "");
640 		md_exit(sp, 1);
641 	}
642 
643 	/*
644 	 * Send the command to all nodes if the -s argument refers to a MN
645 	 * set or the next argument refers to MN set hotspare name ( argc
646 	 * greater than optind if there is a next argument)
647 	 */
648 	if ((called_thru_rpc == FALSE) &&
649 	    (meta_is_mn_set(sp, ep) || ((argc > optind) &&
650 	    meta_is_mn_name(&sp, argv[optind], ep)))) {
651 		int	i;
652 		int	newargc;
653 		int	result;
654 		char	**newargv;
655 
656 		/*
657 		 * If we are dealing with a MN set and we were not
658 		 * called thru an rpc call, we are just to send this
659 		 * command string to the master of the set and let it
660 		 * deal with it.
661 		 * First we send out a dryrun version of this command.
662 		 * If that returns success, we know it succeeded on all
663 		 * nodes and it is safe to do the real command now.
664 		 */
665 		newargv = calloc(argc+1, sizeof (char *));
666 		newargv[0] = "metahs";
667 		newargv[1] = "-n"; /* always do "-n" first */
668 		newargc = 2;
669 		for (i = 1; i < argc; i++, newargc++)
670 			newargv[newargc] = argv[i];
671 		result = meta_mn_send_command(sp, newargc, newargv,
672 		    MD_DISP_STDERR | MD_DRYRUN, NO_CONTEXT_STRING, ep);
673 
674 		/* If we found a problem don't do it for real */
675 		if (result != 0) {
676 			md_exit(sp, result);
677 		}
678 
679 		/*
680 		 * Do it for real now. Remove "-n" from the arguments and
681 		 * MD_DRYRUN from the flags. If this fails the master must panic
682 		 * as the mddbs may be inconsistent.
683 		 */
684 		newargv[1] = ""; /* this was "-n" before */
685 		result = meta_mn_send_command(sp, newargc, newargv,
686 		    MD_DISP_STDERR | MD_RETRY_BUSY | MD_PANIC_WHEN_INCONSISTENT,
687 		    NO_CONTEXT_STRING, ep);
688 		free(newargv);
689 
690 		/* No further action required */
691 		md_exit(sp, result);
692 	}
693 
694 	argc -= optind;
695 	argv += optind;
696 	if (which_op == NONE)
697 		usage(sp, 1);
698 
699 	if (which_op == STATUS_A_HSP) {
700 		if (status_hotspares(&sp, argc, argv, ep) != 0) {
701 			mde_perror(ep, "");
702 			md_exit(sp, 1);
703 		}
704 		md_exit(sp, 0);
705 	}
706 
707 	if (meta_check_root(ep) != 0) {
708 		mde_perror(ep, "");
709 		md_exit(sp, 1);
710 	}
711 
712 
713 	/* dispatch */
714 	switch (which_op) {
715 
716 	case ADD_A_HS:
717 		if (add_hotspares(&sp, argc, argv, options, ep) != 0) {
718 			mde_perror(ep, "");
719 			md_exit(sp, 1);
720 		}
721 		break;
722 
723 	case DELETE_A_HS:
724 		if (delete_hotspares(&sp, argc, argv, options, ep) != 0) {
725 			mde_perror(ep, "");
726 			md_exit(sp, 1);
727 		}
728 		break;
729 
730 	case ENABLE_A_HS:
731 		if (enable_hotspares(&sp, argc, argv, options, ep) != 0) {
732 			mde_perror(ep, "");
733 			md_exit(sp, 1);
734 		}
735 		break;
736 
737 	case REPLACE_A_HS:
738 		if (replace_hotspares(&sp, argc, argv, options, ep) != 0) {
739 			mde_perror(ep, "");
740 			md_exit(sp, 1);
741 		}
742 		break;
743 
744 	default:
745 		assert(0);
746 		break;
747 	}
748 
749 	/* update md.cf */
750 out:
751 	if (meta_update_md_cf(sp, ep) != 0) {
752 		mde_perror(ep, "");
753 		md_exit(sp, 1);
754 	}
755 	md_exit(sp, 0);
756 	/*NOTREACHED*/
757 	return (0);
758 }
759