xref: /titanic_41/usr/src/cmd/lvm/util/metadb.c (revision 03494a9880d80f834bec10a1e8f0a2f8f7c97bf4)
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  * Metadevice database utility.
30  */
31 
32 #include <meta.h>
33 #define	MDDB
34 #include <sys/lvm/md_mddb.h>
35 #include <sdssc.h>
36 
37 enum mddb_cmd {none, attach, detach, patch, infolong, infoshort};
38 
39 extern int	procsigs(int block, sigset_t *oldsigs, md_error_t *ep);
40 
41 static void
42 usage(
43 	mdsetname_t	*sp,
44 	char		*string
45 )
46 {
47 	if ((string != NULL) && (*string != '\0'))
48 		md_eprintf("%s\n", string);
49 
50 	(void) fprintf(stderr, gettext(
51 "usage:  %s [-s setname] -a [options] mddbnnn\n"
52 "	%s [-s setname] -a [options] device ...\n"
53 "	%s [-s setname] -d [options] mddbnnn\n"
54 "	%s [-s setname] -d [options] device ...\n"
55 "	%s [-s setname] -i \n"
56 "	%s -p [options] [ mddb.cf-file ]\n"
57 "options:\n"
58 "-c count	number of replicas (for use with -a only)\n"
59 "-f		force adding or deleting of replicas\n"
60 "-k filename	alternate /etc/system file\n"
61 "-l length	specify size of replica (for use with -a only)\n"),
62 	    myname, myname, myname, myname, myname, myname);
63 
64 	md_exit(sp, (string == NULL) ? 0 : 1);
65 }
66 
67 static mdname_t *
68 make_dbname(
69 	mdsetname_t	*sp,
70 	mdnamelist_t	**nlp,
71 	char		*name,
72 	md_error_t	*ep
73 )
74 {
75 	mdname_t	*np;
76 
77 	if ((np = metaname(&sp, name, LOGICAL_DEVICE, ep)) == NULL)
78 		return (NULL);
79 
80 	return (metanamelist_append(nlp, np));
81 }
82 
83 static mdnamelist_t *
84 get_dbnames_fromfile(
85 	mdsetname_t	*sp,
86 	mdnamelist_t	**nlp,
87 	char		*tabname,
88 	int		*dbsize,
89 	int		*dbcnt,
90 	int		*default_size,
91 	md_error_t	*ep
92 )
93 {
94 	md_tab_t	*tabp = NULL;
95 	md_tab_line_t	*linep = NULL;
96 	int		argc;
97 	char		**argv;
98 	char		*context;
99 	int		save = optind;
100 	int		c;
101 
102 	/* look in md.tab */
103 	if ((tabp = meta_tab_parse(NULL, ep)) == NULL) {
104 		if (! mdissyserror(ep, ENOENT))
105 			mde_perror(ep, "");
106 		mdclrerror(ep);
107 		return (NULL);
108 	}
109 
110 	if ((linep = meta_tab_find(sp, tabp, tabname, TAB_MDDB)) == NULL) {
111 		(void) mdsyserror(ep, ENOENT, tabname);
112 		goto out;
113 	}
114 	argc = linep->argc;
115 	argv = linep->argv;
116 	context = linep->context;
117 
118 	/* parse up entry */
119 	optind = 1;
120 	opterr = 1;
121 	while ((c = getopt(argc, argv, "c:l:")) != -1) {
122 		switch (c) {
123 		case 'c':
124 			if (sscanf(optarg, "%d", dbcnt) != 1) {
125 				md_eprintf("%s: %s\n",
126 				    context, gettext("bad format"));
127 				usage(sp, "");
128 			}
129 			break;
130 
131 		case 'l':
132 			if (sscanf(optarg, "%d", dbsize) != 1) {
133 				md_eprintf("%s: %s\n",
134 				    context, gettext("bad format"));
135 				usage(sp, "");
136 			}
137 			*default_size = FALSE;
138 			break;
139 
140 		default:
141 			usage(sp, "");
142 		}
143 	}
144 	argc -= optind;
145 	argv += optind;
146 	for (; (argc > 0); --argc, ++argv) {
147 		char	*token = argv[0];
148 
149 		if (make_dbname(sp, nlp, token, ep) == NULL) {
150 			metafreenamelist(*nlp);
151 			*nlp = NULL;
152 			goto out;
153 		}
154 	}
155 
156 	/* cleanup, return list */
157 out:
158 	if (tabp != NULL)
159 		meta_tab_free(tabp);
160 	optind = save;
161 	return (*nlp);
162 }
163 
164 /*
165  * built list of all devices which are to be detached
166  */
167 static mdnamelist_t *
168 build_a_namelist(
169 	mdsetname_t	*sp,
170 	int		argc,
171 	char		**argv,
172 	md_error_t	*ep
173 )
174 {
175 	int		i;
176 	int		dbsize, dbcnt, default_size;
177 	mdnamelist_t	*dbnlp = NULL;
178 
179 	for (i = 0; i < argc; i++) {
180 		if (strncmp(argv[i], "mddb", 4) == 0) {
181 			if (get_dbnames_fromfile(sp, &dbnlp, argv[i],
182 			    &dbsize, &dbcnt, &default_size, ep) == NULL) {
183 				/* don't freelist here - already been done */
184 				return (NULL);
185 			}
186 			continue;
187 		}
188 		if (make_dbname(sp, &dbnlp, argv[i], ep) == NULL) {
189 			metafreenamelist(dbnlp);
190 			return (NULL);
191 		}
192 	}
193 
194 	return (dbnlp);
195 }
196 
197 
198 /*
199  * built the next list of devices which are to be attached
200  * that have the same size and count of replicas.
201  */
202 static mdnamelist_t *
203 build_next_namelist(
204 	mdsetname_t	*sp,
205 	int		argc,
206 	char		**argv,
207 	int		*arg_index,
208 	int		*dbsize,
209 	int		*dbcnt,
210 	int		*default_size,
211 	md_error_t	*ep
212 )
213 {
214 	int		i;
215 	mdnamelist_t	*dbnlp = NULL;
216 
217 	for (i = *arg_index; i < argc; i++) {
218 		if (strncmp(argv[i], "mddb", 4) == 0) {
219 			/*
220 			 * If we have stuff in the namelist
221 			 * return it before processing the mddb entry.
222 			 */
223 			if (dbnlp) {
224 				*arg_index = i;
225 				return (dbnlp);
226 			}
227 			if (get_dbnames_fromfile(sp, &dbnlp, argv[i],
228 			    dbsize, dbcnt, default_size, ep) == NULL) {
229 				/* don't freelist here - already been done */
230 				return (NULL);
231 			}
232 			*arg_index = i + 1;
233 			return (dbnlp);
234 		}
235 		if (make_dbname(sp, &dbnlp, argv[i], ep) == NULL) {
236 			metafreenamelist(dbnlp);
237 			return (NULL);
238 		}
239 	}
240 	*arg_index = argc;
241 	return (dbnlp);
242 }
243 
244 
245 static int
246 chngdb(
247 	mdsetname_t	*sp,
248 	enum mddb_cmd	cmd,
249 	int		argc,
250 	char		*argv[],
251 	uint_t		options,
252 	md_error_t	*ep
253 )
254 {
255 	int		c;
256 	int		i;
257 	md_error_t	xep = mdnullerror;
258 	mdnamelist_t	*dbnlp = NULL;
259 	int		dbsize = MD_DBSIZE;
260 	int		maxblks = MDDB_MAXBLKS;
261 	int		minblks = MDDB_MINBLKS;
262 	int		dbcnt = 1;
263 	mdforceopts_t	force = MDFORCE_NONE;
264 	int		rval = 0;
265 	char		*sysfilename = NULL;
266 	int		default_size = TRUE;
267 	md_set_desc	*sd;
268 	md_setkey_t	*cl_sk;
269 	md_mnnode_desc	*nd;
270 	int		suspend1_flag = 0;
271 
272 	/* reset and parse args */
273 	optind = 1;
274 	opterr = 1;
275 	while ((c = getopt(argc, argv, "ac:dfk:pl:s:")) != -1) {
276 		switch (c) {
277 		case 'a':
278 			break;
279 		case 'c':
280 			if (sscanf(optarg, "%d", &dbcnt) != 1) {
281 				md_eprintf("%s: %s\n",
282 				    optarg, gettext("bad format"));
283 				usage(sp, "");
284 			}
285 			break;
286 		case 'd':
287 			break;
288 		case 'f':
289 			force = MDFORCE_LOCAL;
290 			break;
291 		case 'k':
292 			sysfilename = optarg;
293 			break;
294 		case 'l':
295 			if (sscanf(optarg, "%d", &dbsize) != 1) {
296 				md_eprintf("%s: %s\n",
297 				    optarg, gettext("bad format"));
298 				usage(sp, "");
299 			}
300 			default_size = FALSE;
301 			break;
302 		case 'p':
303 			break;
304 		case 's':
305 			break;
306 		default:
307 			usage(sp, "");
308 		}
309 	}
310 
311 	/*
312 	 * If it is a multinode diskset, use appropriate metadb size.
313 	 */
314 	if (! metaislocalset(sp)) {
315 		if ((sd = metaget_setdesc(sp, ep)) == NULL)
316 			return (-1);
317 
318 		if (MD_MNSET_DESC(sd)) {
319 			maxblks = MDDB_MN_MAXBLKS;
320 			minblks = MDDB_MN_MINBLKS;
321 			if (default_size)
322 				dbsize = MD_MN_DBSIZE;
323 		}
324 	}
325 
326 	if (dbsize > maxblks)
327 		usage(sp, gettext("size (-l) is too big"));
328 
329 
330 	if (dbsize < minblks)
331 		usage(sp, gettext("size (-l) is too small"));
332 
333 	if (dbcnt < 1)
334 		usage(sp, gettext(
335 		    "count (-c) must be 1 or more"));
336 
337 
338 	argc -= optind;
339 	argv += optind;
340 	if (argc <= 0) {
341 		usage(sp, gettext(
342 		    "no devices specified to attach or detach"));
343 	}
344 
345 	if (! metaislocalset(sp)) {
346 
347 		if (MD_MNSET_DESC(sd)) {
348 			md_error_t xep = mdnullerror;
349 			sigset_t sigs;
350 
351 			/* Make sure we are blocking all signals */
352 			if (procsigs(TRUE, &sigs, &xep) < 0)
353 				mdclrerror(&xep);
354 
355 			/*
356 			 * Lock out other metaset or metadb commands
357 			 * across the diskset.
358 			 */
359 			nd = sd->sd_nodelist;
360 			while (nd) {
361 				if ((force & MDFORCE_LOCAL) &&
362 				    strcmp(nd->nd_nodename, mynode()) != 0) {
363 					nd = nd->nd_next;
364 					continue;
365 				}
366 
367 				if (!(nd->nd_flags & MD_MN_NODE_ALIVE)) {
368 					nd = nd->nd_next;
369 					continue;
370 				}
371 
372 				if (clnt_lock_set(nd->nd_nodename, sp, ep)) {
373 					rval = -1;
374 					goto done;
375 				}
376 				nd = nd->nd_next;
377 			}
378 			/*
379 			 * Lock out other meta* commands by suspending
380 			 * class 1 messages across the diskset.
381 			 */
382 			nd = sd->sd_nodelist;
383 			while (nd) {
384 				if (!(nd->nd_flags & MD_MN_NODE_ALIVE)) {
385 					nd = nd->nd_next;
386 					continue;
387 				}
388 
389 				if (clnt_mdcommdctl(nd->nd_nodename,
390 				    COMMDCTL_SUSPEND, sp, MD_MSG_CLASS1,
391 				    MD_MSCF_NO_FLAGS, ep)) {
392 					rval = -1;
393 					goto done;
394 				}
395 				suspend1_flag = 1;
396 				nd = nd->nd_next;
397 			}
398 		} else {
399 			/* Lock the set on current set members */
400 			for (i = 0; i < MD_MAXSIDES; i++) {
401 				/* Skip empty slots */
402 				if (sd->sd_nodes[i][0] == '\0')
403 					continue;
404 
405 				if ((force & MDFORCE_LOCAL) &&
406 				    strcmp(sd->sd_nodes[i], mynode()) != 0)
407 					continue;
408 
409 				if (clnt_lock_set(sd->sd_nodes[i], sp, ep)) {
410 					rval = -1;
411 					goto done;
412 				}
413 			}
414 		}
415 
416 		force |= MDFORCE_SET_LOCKED;
417 		options |= MDCHK_SET_LOCKED;
418 	}
419 
420 	if (cmd == detach) {
421 		if ((dbnlp = build_a_namelist(sp, argc, argv, ep)) == NULL) {
422 			rval = -1;
423 			goto done;
424 		}
425 
426 		rval = meta_db_detach(sp, dbnlp, force, sysfilename, ep);
427 
428 		metafreenamelist(dbnlp);
429 	}
430 
431 	if (cmd == attach) {
432 		daddr_t	nblks = 0;
433 		int	arg_index = 0;
434 		int	saved_dbsize = dbsize;
435 		int	saved_dbcnt = dbcnt;
436 		int	saved_default_size = default_size;
437 
438 		if (force & MDFORCE_LOCAL)
439 			options |= MDCHK_SET_FORCE;
440 
441 		if (default_size)
442 			if ((nblks = meta_db_minreplica(sp, ep)) < 0)
443 				mdclrerror(ep);
444 		/*
445 		 * Loop through build a new namelist
446 		 * for each "mddb" entry or the devices list
447 		 * on the command line.  This allows each "mddb"
448 		 * entry to have unique dbsize and dbcnt.
449 		 */
450 		while (arg_index < argc) {
451 
452 			dbnlp = build_next_namelist(sp, argc, argv,
453 			    &arg_index, &dbsize, &dbcnt, &default_size, ep);
454 			if (dbnlp == NULL) {
455 				rval = -1;
456 				goto done;
457 			}
458 			/*
459 			 * If using the default size,
460 			 *   then let's adjust the default to the minimum
461 			 *   size currently in use.
462 			 */
463 			if (default_size && (nblks > 0))
464 				dbsize = nblks;	/* adjust replica size */
465 
466 			if (dbsize > maxblks)
467 				usage(sp, gettext("size (-l) is too big"));
468 
469 			rval = meta_db_attach(sp, dbnlp, options, NULL, dbcnt,
470 			    dbsize, sysfilename, ep);
471 			if (rval) {
472 				metafreenamelist(dbnlp);
473 				break;
474 			}
475 			dbsize = saved_dbsize;
476 			dbcnt = saved_dbcnt;
477 			default_size = saved_default_size;
478 
479 			metafreenamelist(dbnlp);
480 		}
481 	}
482 
483 done:
484 	if (! metaislocalset(sp)) {
485 		cl_sk = cl_get_setkey(sp->setno, sp->setname);
486 		if (MD_MNSET_DESC(sd)) {
487 			/*
488 			 * Unlock diskset by resuming
489 			 * class 1 messages across the diskset.
490 			 */
491 			if (suspend1_flag) {
492 				nd = sd->sd_nodelist;
493 				while (nd) {
494 					if (!(nd->nd_flags &
495 					    MD_MN_NODE_ALIVE)) {
496 						nd = nd->nd_next;
497 						continue;
498 					}
499 
500 					if (clnt_mdcommdctl(nd->nd_nodename,
501 					    COMMDCTL_RESUME, sp,
502 					    MD_MSG_CLASS1,
503 					    MD_MSCF_NO_FLAGS, &xep)) {
504 						mde_perror(&xep, "");
505 						mdclrerror(&xep);
506 					}
507 					nd = nd->nd_next;
508 				}
509 			}
510 			nd = sd->sd_nodelist;
511 			while (nd) {
512 				if ((force & MDFORCE_LOCAL) &&
513 				    strcmp(nd->nd_nodename, mynode()) != 0) {
514 					nd = nd->nd_next;
515 					continue;
516 				}
517 				if (!(nd->nd_flags & MD_MN_NODE_ALIVE)) {
518 					nd = nd->nd_next;
519 					continue;
520 				}
521 
522 				if (clnt_unlock_set(nd->nd_nodename, cl_sk,
523 				    &xep))
524 					mdclrerror(&xep);
525 				nd = nd->nd_next;
526 			}
527 		} else {
528 			for (i = 0; i < MD_MAXSIDES; i++) {
529 				/* Skip empty slots */
530 				if (sd->sd_nodes[i][0] == '\0')
531 					continue;
532 
533 				if ((force & MDFORCE_LOCAL) &&
534 				    strcmp(sd->sd_nodes[i], mynode()) != 0)
535 					continue;
536 
537 				if (clnt_unlock_set(sd->sd_nodes[i], cl_sk,
538 				    &xep))
539 					mdclrerror(&xep);
540 			}
541 		}
542 		cl_set_setkey(NULL);
543 	}
544 
545 	return (rval);
546 }
547 
548 static int
549 info(
550 	mdsetname_t	*sp,
551 	enum mddb_cmd	cmd,
552 	int		print_headers,
553 	int		print_footers,
554 	md_error_t	*ep
555 )
556 {
557 	md_replicalist_t	*rlp = NULL;
558 	md_replicalist_t	*rl;
559 	md_replica_t		*r;
560 	int			i;
561 	char			*unk_str = NULL;
562 
563 	/* get list of replicas, quit if none */
564 	if (metareplicalist(sp, (MD_BASICNAME_OK | PRINT_FAST), &rlp, ep) < 0)
565 		return (-1);
566 	else if (rlp == NULL)
567 		return (0);
568 
569 	if (print_headers) {
570 		(void) printf("\t%5.5s\t\t%9.9s\t%11.11s\n", gettext("flags"),
571 		    gettext("first blk"), gettext("block count"));
572 	}
573 
574 	unk_str = gettext("unknown");
575 	for (rl = rlp; rl != NULL; rl = rl->rl_next) {
576 		r = rl->rl_repp;
577 
578 		for (i = 0; i < MDDB_FLAGS_LEN; i++) {
579 			if (r->r_flags & (1 << i))
580 				(void) putchar(MDDB_FLAGS_STRING[i]);
581 			else
582 				(void) putchar(' ');
583 		}
584 
585 		if ((r->r_blkno == -1) && (r->r_nblk == -1)) {
586 			(void) printf("\t%7.7s\t\t%7.7s\t", unk_str, unk_str);
587 		} else if (r->r_nblk == -1) {
588 			(void) printf("\t%ld\t\t%7.7s\t", r->r_blkno, unk_str);
589 		} else {
590 			(void) printf("\t%ld\t\t%ld\t", r->r_blkno, r->r_nblk);
591 		}
592 
593 		(void) printf("\t%s\n", r->r_namep->bname);
594 
595 	}
596 
597 	metafreereplicalist(rlp);
598 
599 	if (cmd == infoshort)
600 		return (0);
601 
602 	if (!print_footers)
603 		return (0);
604 
605 	(void) printf(gettext(
606 	    " r - replica does not have device relocation information\n"
607 	    " o - replica active prior to last mddb configuration change\n"
608 	    " u - replica is up to date\n"
609 	    " l - locator for this replica was read successfully\n"
610 	    " c - replica's location was in %s\n"
611 	    " p - replica's location was patched in kernel\n"
612 	    " m - replica is master, this is replica selected as input\n"
613 	    " t - tagged data is associated with the replica\n"
614 	    " W - replica has device write errors\n"
615 	    " a - replica is active, commits are occurring to this replica\n"
616 	    " M - replica had problem with master blocks\n"
617 	    " D - replica had problem with data blocks\n"
618 	    " F - replica had format problems\n"
619 	    " S - replica is too small to hold current data base\n"
620 	    " R - replica had device read errors\n"
621 	    " B - tagged data associated with the replica is not valid\n"),
622 	    META_DBCONF);
623 	return (0);
624 }
625 
626 int
627 main(int argc, char **argv)
628 {
629 	mdsetname_t	*sp = NULL;
630 	int		c;
631 	enum mddb_cmd	cmd = none;
632 	char		*sname = MD_LOCAL_NAME;
633 	char		*cffilename = NULL;
634 	char		*sysfilename = NULL;
635 	int		forceflg = FALSE;
636 	mdchkopts_t	options = 0;
637 	md_error_t	status = mdnullerror;
638 	md_error_t	*ep = &status;
639 	int		error;
640 	md_set_desc	*sd;
641 	int		multi_node = 0;
642 
643 	/*
644 	 * Get the locale set up before calling any other routines
645 	 * with messages to ouput.  Just in case we're not in a build
646 	 * environment, make sure that TEXT_DOMAIN gets set to
647 	 * something.
648 	 */
649 #if !defined(TEXT_DOMAIN)
650 #define	TEXT_DOMAIN "SYS_TEST"
651 #endif
652 	(void) setlocale(LC_ALL, "");
653 	(void) textdomain(TEXT_DOMAIN);
654 
655 	if (sdssc_bind_library() == SDSSC_OKAY)
656 		if (sdssc_cmd_proxy(argc, argv, SDSSC_PROXY_PRIMARY,
657 		    &error) == SDSSC_PROXY_DONE)
658 			exit(error);
659 
660 	/* parse args */
661 	optind = 1;
662 	opterr = 1;
663 
664 	/* initialize */
665 	if (md_init(argc, argv, 0, 1, ep) != 0) {
666 		mde_perror(ep, "");
667 		md_exit(sp, 1);
668 	}
669 
670 	/* parse args */
671 	optind = 1;
672 	opterr = 1;
673 	while ((c = getopt(argc, argv, "ac:dfhik:l:ps:?")) != -1) {
674 		switch (c) {
675 		case 'a':
676 			cmd = attach;
677 			break;
678 		case 'c':
679 			break;
680 		case 'd':
681 			cmd = detach;
682 			break;
683 		case 'f':
684 			forceflg = TRUE;
685 			break;
686 		case 'h':
687 			usage(sp, (char *)0);
688 			break;
689 		case 'i':
690 			cmd = infolong;
691 			break;
692 		case 'k':
693 			sysfilename = optarg;
694 			break;
695 		case 'l':
696 			break;
697 		case 'p':
698 			cmd = patch;
699 			break;
700 		case 's':
701 			sname = optarg;
702 			break;
703 
704 		case '?':
705 			if (optopt == '?')
706 				usage(sp, NULL);
707 			/*FALLTHROUGH*/
708 		default:
709 			usage(sp, gettext("unknown command"));
710 		}
711 	}
712 	if (cmd == none)
713 		cmd = infoshort;
714 
715 	/* get set context */
716 	if ((sp = metasetname(sname, ep)) == NULL) {
717 		mde_perror(ep, "");
718 		md_exit(sp, 1);
719 	}
720 
721 	/* print status */
722 	if (cmd == infoshort || cmd == infolong) {
723 		if (optind != argc)
724 			usage(sp, gettext(
725 				"too many arguments"));
726 
727 		if (info(sp, cmd, 1, 1, ep)) {
728 			mde_perror(ep, "");
729 			md_exit(sp, 1);
730 		}
731 
732 		if (meta_smf_isonline(meta_smf_getmask(), ep) == 0) {
733 			mde_perror(ep, "");
734 			md_exit(sp, 1);
735 		}
736 
737 		md_exit(sp, 0);
738 	}
739 
740 	if (meta_check_root(ep) != 0) {
741 		mde_perror(ep, "");
742 		md_exit(sp, 1);
743 	}
744 
745 	if (! metaislocalset(sp)) {
746 		if ((sd = metaget_setdesc(sp, ep)) == NULL) {
747 			mde_perror(ep, "");
748 			md_exit(sp, 1);
749 		}
750 		if (MD_MNSET_DESC(sd)) {
751 			multi_node = 1;
752 		}
753 	}
754 
755 	/*
756 	 * Adjust lock for traditional and local diskset.
757 	 *
758 	 * A MN diskset does not use the set meta_lock but instead
759 	 * uses the clnt_lock of rpc.metad and the suspend/resume
760 	 * feature of the rpc.mdcommd.  Can't use set meta_lock since
761 	 * class 1 messages are grabbing this lock and if this thread
762 	 * is holding the set meta_lock then no rpc.mdcommd suspend
763 	 * can occur.
764 	 */
765 	if ((!multi_node) && (meta_lock(sp, TRUE, ep) != 0)) {
766 		mde_perror(ep, "");
767 		md_exit(sp, 1);
768 	}
769 
770 	/* check for ownership */
771 	if (meta_check_ownership(sp, ep) != 0) {
772 		mde_perror(ep, "");
773 		md_exit(sp, 1);
774 	}
775 
776 	/* snarf MDDB locations */
777 	if (cmd != patch) {
778 		if (meta_setup_db_locations(ep) != 0) {
779 			if (! mdismddberror(ep, MDE_DB_STALE)) {
780 				if (forceflg == FALSE) {
781 					mde_perror(ep, "");
782 					md_exit(sp, 1);
783 				}
784 				options = MDCHK_ALLOW_NODBS;
785 			}
786 			mdclrerror(ep);
787 		}
788 	}
789 
790 	/* patch MDDB locations */
791 	if (cmd == patch) {
792 		if (optind < (argc - 1)) {
793 			usage(sp, gettext(
794 			    "too many arguments to -p"));
795 		}
796 
797 		if (optind == (argc - 1))
798 			cffilename = argv[optind];
799 
800 		if (metaislocalset(sp)) {
801 			if (meta_db_patch(sysfilename, cffilename, 1, ep)) {
802 				mde_perror(ep, "");
803 				md_exit(sp, 1);
804 			}
805 		}
806 	}
807 
808 	/* add/delete replicas */
809 	if (cmd == attach || cmd == detach) {
810 		if (chngdb(sp, cmd, argc, argv, options, ep)) {
811 			mde_perror(ep, "");
812 			md_exit(sp, 1);
813 		}
814 	}
815 
816 	md_exit(sp, 0);
817 	/*NOTREACHED*/
818 	return (0);
819 }
820