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 /*
27 * Just in case we're not in a build environment, make sure that
28 * TEXT_DOMAIN gets set to something.
29 */
30 #if !defined(TEXT_DOMAIN)
31 #define TEXT_DOMAIN "SYS_TEST"
32 #endif
33
34 /*
35 * trans operations
36 */
37
38 #include <meta.h>
39 #include <meta_basic.h>
40 #include <sys/lvm/md_trans.h>
41 #include <sys/wait.h>
42 #include <sys/mnttab.h>
43 #include <stddef.h>
44
45 extern char *getfullblkname();
46
47 /*
48 * replace trans
49 */
50
51 int
meta_trans_replace(mdsetname_t * sp,mdname_t * transnp,mdname_t * oldnp,mdname_t * newnp,mdcmdopts_t options,md_error_t * ep)52 meta_trans_replace(mdsetname_t *sp, mdname_t *transnp, mdname_t *oldnp,
53 mdname_t *newnp, mdcmdopts_t options, md_error_t *ep)
54 {
55 replace_params_t params;
56 md_dev64_t old_dev, new_dev;
57 daddr_t new_start_blk, new_end_blk;
58
59 /* should have same set */
60 assert(sp != NULL);
61 assert(sp->setno == MD_MIN2SET(meta_getminor(transnp->dev)));
62
63 new_dev = newnp->dev;
64 new_start_blk = newnp->start_blk;
65 new_end_blk = newnp->end_blk;
66
67 meta_invalidate_name(transnp);
68 /* the old device binding is now established */
69 if ((old_dev = oldnp->dev) == NODEV64)
70 return (mdsyserror(ep, ENODEV, oldnp->cname));
71
72 if (((strcmp(oldnp->rname, newnp->rname) == 0) &&
73 (old_dev != new_dev))) {
74 newnp->dev = new_dev;
75 newnp->start_blk = new_start_blk;
76 newnp->end_blk = new_end_blk;
77 }
78
79 if (add_key_name(sp, newnp, NULL, ep) != 0)
80 return (-1);
81
82 (void) memset(¶ms, 0, sizeof (params));
83 params.mnum = meta_getminor(transnp->dev);
84 MD_SETDRIVERNAME(¶ms, MD_TRANS, sp->setno);
85
86 params.cmd = REPLACE_COMP;
87 params.old_dev = old_dev;
88 params.new_dev = new_dev;
89 params.new_key = newnp->key;
90 if (metaioctl(MD_IOCREPLACE, ¶ms, ¶ms.mde, NULL) != 0) {
91 (void) del_key_name(sp, newnp, ep);
92 return (mdstealerror(ep, ¶ms.mde));
93 }
94 meta_invalidate_name(oldnp);
95 meta_invalidate_name(newnp);
96 meta_invalidate_name(transnp);
97
98 if (options & MDCMD_PRINT) {
99 (void) printf(dgettext(TEXT_DOMAIN,
100 "%s: device %s is replaced with %s\n"),
101 transnp->cname, oldnp->cname, newnp->cname);
102 }
103 return (0);
104 }
105
106
107
108 /*
109 * FUNCTION: meta_get_trans_names()
110 * INPUT: sp - the set name to get trans from
111 * options - options from the command line
112 * OUTPUT: nlpp - list of all trans names
113 * ep - return error pointer
114 * RETURNS: int - -1 if error, 0 success
115 * PURPOSE: returns a list of all trans in the metadb
116 * for all devices in the specified set
117 */
118 int
meta_get_trans_names(mdsetname_t * sp,mdnamelist_t ** nlpp,int options,md_error_t * ep)119 meta_get_trans_names(
120 mdsetname_t *sp,
121 mdnamelist_t **nlpp,
122 int options,
123 md_error_t *ep
124 )
125 {
126 return (meta_get_names(MD_TRANS, sp, nlpp, options, ep));
127 }
128
129 /*
130 * free trans unit
131 */
132 void
meta_free_trans(md_trans_t * transp)133 meta_free_trans(
134 md_trans_t *transp
135 )
136 {
137 Free(transp);
138 }
139
140 /*
141 * get trans (common)
142 */
143 md_trans_t *
meta_get_trans_common(mdsetname_t * sp,mdname_t * transnp,int fast,md_error_t * ep)144 meta_get_trans_common(
145 mdsetname_t *sp,
146 mdname_t *transnp,
147 int fast,
148 md_error_t *ep
149 )
150 {
151 mddrivename_t *dnp = transnp->drivenamep;
152 char *miscname;
153 mt_unit_t *mt;
154 md_trans_t *transp;
155 int gotlog;
156
157 /* must have set */
158 assert(sp != NULL);
159 assert(sp->setno == MD_MIN2SET(meta_getminor(transnp->dev)));
160
161 /* short circuit */
162 if (dnp->unitp != NULL) {
163 assert(dnp->unitp->type == MD_METATRANS);
164 return ((md_trans_t *)dnp->unitp);
165 }
166
167 /* get miscname and unit */
168 if ((miscname = metagetmiscname(transnp, ep)) == NULL)
169 return (NULL);
170 if (strcmp(miscname, MD_TRANS) != 0) {
171 (void) mdmderror(ep, MDE_NOT_MT,
172 meta_getminor(transnp->dev), transnp->cname);
173 return (NULL);
174 }
175 if ((mt = (mt_unit_t *)meta_get_mdunit(sp, transnp, ep)) == NULL)
176 return (NULL);
177 assert(mt->c.un_type == MD_METATRANS);
178
179 /* allocate trans */
180 transp = Zalloc(sizeof (*transp));
181
182 /* get common info */
183 transp->common.namep = transnp;
184 transp->common.type = mt->c.un_type;
185 transp->common.state = mt->c.un_status;
186 transp->common.capabilities = mt->c.un_capabilities;
187 transp->common.parent = mt->c.un_parent;
188 transp->common.size = mt->c.un_total_blocks;
189 transp->common.user_flags = mt->c.un_user_flags;
190 transp->common.revision = mt->c.un_revision;
191
192 /* get master */
193 transp->masternamep = metakeyname(&sp, mt->un_m_key, fast, ep);
194 if (transp->masternamep == NULL)
195 goto out;
196
197 /* get log */
198 gotlog = ((mt->un_flags & TRANS_DETACHED) == 0);
199 if (gotlog) {
200 daddr_t sblk;
201
202 transp->lognamep = metakeyname(&sp, mt->un_l_key, fast, ep);
203 if (transp->lognamep == NULL)
204 goto out;
205
206 /* calculate the kernels start block */
207 sblk = mt->un_l_pwsblk + mt->un_l_maxtransfer;
208
209 if (getenv("META_DEBUG_START_BLK") != NULL) {
210 if (metagetstart(sp, transp->lognamep, ep) ==
211 MD_DISKADDR_ERROR)
212 mdclrerror(ep);
213
214 if (transp->lognamep->start_blk > sblk)
215 md_eprintf(dgettext(TEXT_DOMAIN,
216 "%s: suspected bad start block [trans]\n"),
217 transp->lognamep->cname);
218 }
219
220 /* override any start_blk */
221 transp->lognamep->start_blk = sblk;
222 }
223
224 /* get flags, etc. */
225 transp->flags = mt->un_flags;
226 transp->timestamp = mt->un_timestamp;
227 transp->log_error = mt->un_l_error;
228 transp->log_timestamp = mt->un_l_timestamp;
229 transp->log_size = mt->un_l_nblks;
230 transp->debug = mt->un_debug;
231
232 /* cleanup, return success */
233 Free(mt);
234 dnp->unitp = (md_common_t *)transp;
235 return (transp);
236
237 /* cleanup, return error */
238 out:
239 Free(mt);
240 meta_free_trans(transp);
241 return (NULL);
242 }
243
244 /*
245 * get trans
246 */
247 md_trans_t *
meta_get_trans(mdsetname_t * sp,mdname_t * transnp,md_error_t * ep)248 meta_get_trans(
249 mdsetname_t *sp,
250 mdname_t *transnp,
251 md_error_t *ep
252 )
253 {
254 return (meta_get_trans_common(sp, transnp, 0, ep));
255 }
256
257 /*
258 * check trans for dev
259 */
260 static int
in_trans(mdsetname_t * sp,mdname_t * transnp,mdname_t * np,mdchkopts_t options,diskaddr_t slblk,diskaddr_t nblks,md_error_t * ep)261 in_trans(
262 mdsetname_t *sp,
263 mdname_t *transnp,
264 mdname_t *np,
265 mdchkopts_t options,
266 diskaddr_t slblk,
267 diskaddr_t nblks,
268 md_error_t *ep
269 )
270 {
271 md_trans_t *transp;
272 mdname_t *masternp;
273 mdname_t *lognp;
274
275 /* should be in the same set */
276 assert(sp != NULL);
277 assert(sp->setno == MD_MIN2SET(meta_getminor(transnp->dev)));
278
279 /* get unit */
280 if ((transp = meta_get_trans(sp, transnp, ep)) == NULL)
281 return (-1);
282
283 /* check master */
284 masternp = transp->masternamep;
285 if ((! metaismeta(masternp)) &&
286 (meta_check_overlap(transnp->cname, np, slblk, nblks,
287 masternp, 0, -1, ep) != 0)) {
288 return (-1);
289 }
290
291 /* check log */
292 if (((lognp = transp->lognamep) != NULL) &&
293 (! (options & MDCHK_ALLOW_LOG)) &&
294 (! metaismeta(lognp))) {
295 daddr_t log_start;
296 int err;
297
298 /* check same drive since metagetstart() can fail */
299 if ((err = meta_check_samedrive(np, lognp, ep)) < 0)
300 return (-1);
301
302 /* check overlap */
303 if (err != 0) {
304 if ((log_start = metagetstart(sp, lognp, ep)) ==
305 MD_DISKADDR_ERROR)
306 return (-1);
307 if (meta_check_overlap(transnp->cname, np, slblk,
308 nblks, lognp, log_start, -1, ep) != 0) {
309 return (-1);
310 }
311 }
312 }
313
314 /* return success */
315 return (0);
316 }
317
318 /*
319 * check to see if we're in a trans
320 */
321 int
meta_check_intrans(mdsetname_t * sp,mdname_t * np,mdchkopts_t options,diskaddr_t slblk,diskaddr_t nblks,md_error_t * ep)322 meta_check_intrans(
323 mdsetname_t *sp,
324 mdname_t *np,
325 mdchkopts_t options,
326 diskaddr_t slblk,
327 diskaddr_t nblks,
328 md_error_t *ep
329 )
330 {
331 mdnamelist_t *transnlp = NULL;
332 mdnamelist_t *p;
333 int rval = 0;
334
335 /* should have a set */
336 assert(sp != NULL);
337
338 /* for each trans */
339 if (meta_get_trans_names(sp, &transnlp, 0, ep) < 0)
340 return (-1);
341 for (p = transnlp; (p != NULL); p = p->next) {
342 mdname_t *transnp = p->namep;
343
344 /* check trans */
345 if (in_trans(sp, transnp, np, options, slblk, nblks, ep) != 0) {
346 rval = -1;
347 break;
348 }
349 }
350
351 /* cleanup, return success */
352 metafreenamelist(transnlp);
353 return (rval);
354 }
355
356 /*
357 * check master
358 */
359 int
meta_check_master(mdsetname_t * sp,mdname_t * np,int force,md_error_t * ep)360 meta_check_master(
361 mdsetname_t *sp,
362 mdname_t *np,
363 int force,
364 md_error_t *ep
365 )
366 {
367 mdchkopts_t options = 0;
368 md_common_t *mdp;
369
370 /* make sure we have a disk */
371 if (metachkdisk(np, ep) != 0)
372 return (-1);
373
374 /* check to ensure that it is not already in use */
375 if ((!force) && meta_check_inuse(sp, np, MDCHK_INUSE, ep) != 0) {
376 return (-1);
377 }
378
379 /* make sure it is in the set */
380 if (meta_check_inset(sp, np, ep) != 0)
381 return (-1);
382
383 /* make sure its not in a metadevice */
384 if (! metaismeta(np)) { /* Non-metadevices */
385 if (meta_check_inmeta(sp, np, options, 0, -1, ep) != 0)
386 return (-1);
387 } else { /* Metadevices only! */
388 if ((mdp = meta_get_unit(sp, np, ep)) == NULL)
389 return (-1);
390
391 /*
392 * Since soft partitions may appear at the top or bottom
393 * of the metadevice stack, we check them separately.
394 * A trans may be built on top of a soft partition if
395 * the soft partition has no parent (can't rely on the
396 * MD_CAN_PARENT flag in this case since a soft partition
397 * built on a metadevice clears this flag to prevent nested
398 * configurations).
399 */
400 if ((meta_sp_issp(sp, np, ep) == 0) &&
401 (mdp->parent == MD_NO_PARENT))
402 return (0);
403
404 if ((! (mdp->capabilities & MD_CAN_PARENT)) ||
405 (mdp->parent != MD_NO_PARENT)) {
406 return (mdmderror(ep, MDE_INVAL_UNIT,
407 meta_getminor(np->dev), np->cname));
408 }
409 }
410
411 /* return success */
412 return (0);
413 }
414
415 /*
416 * check log
417 */
418 int
meta_check_log(mdsetname_t * sp,mdname_t * np,md_error_t * ep)419 meta_check_log(
420 mdsetname_t *sp,
421 mdname_t *np,
422 md_error_t *ep
423 )
424 {
425 mdchkopts_t options = (MDCHK_ALLOW_MDDB | MDCHK_ALLOW_LOG);
426 md_common_t *mdp;
427
428 /* make sure we have a disk */
429 if (metachkdisk(np, ep) != 0)
430 return (-1);
431
432 /* check to ensure that it is not already in use */
433 if (meta_check_inuse(sp, np, MDCHK_INUSE, ep) != 0) {
434 return (-1);
435 }
436
437 /* make sure it is in the set */
438 if (meta_check_inset(sp, np, ep) != 0)
439 return (-1);
440
441 /* make sure its not in a metadevice */
442 if (! metaismeta(np)) { /* Non-metadevices */
443 if (meta_check_inmeta(sp, np, options, 0, -1, ep) != 0)
444 return (-1);
445 } else { /* Metadevices only! */
446 if ((mdp = meta_get_unit(sp, np, ep)) == NULL)
447 return (-1);
448
449 /*
450 * Since soft partitions may appear at the top or bottom
451 * of the metadevice stack, we check them separately.
452 * A trans may be built on top of a soft partition if
453 * the soft partition has no parent (can't rely on the
454 * MD_CAN_PARENT flag in this case since a soft partition
455 * built on a metadevice clears this flag to prevent nested
456 * configurations).
457 *
458 */
459 if ((meta_sp_issp(sp, np, ep) == 0) &&
460 (mdp->parent == MD_NO_PARENT))
461 return (0);
462
463 if ((! (mdp->capabilities & MD_CAN_PARENT)) ||
464 ((mdp->parent != MD_NO_PARENT) &&
465 (mdp->parent != MD_MULTI_PARENT))) {
466 return (mdmderror(ep, MDE_INVAL_UNIT,
467 meta_getminor(np->dev), np->cname));
468 }
469 }
470
471 /* return success */
472 return (0);
473 }
474
475 /*
476 * print trans
477 */
478 static int
trans_print(md_trans_t * transp,char * fname,FILE * fp,md_error_t * ep)479 trans_print(
480 md_trans_t *transp,
481 char *fname,
482 FILE *fp,
483 md_error_t *ep
484 )
485 {
486 int rval = -1;
487
488 /* print name and -t */
489 if (fprintf(fp, "%s -t", transp->common.namep->cname) == EOF)
490 goto out;
491
492 /* print master */
493 /*
494 * If the path is our standard /dev/rdsk or /dev/md/rdsk
495 * then just print out the cxtxdxsx or the dx, metainit
496 * will assume the default, otherwise we need the full
497 * pathname to make sure this works as we intend.
498 */
499 if ((strstr(transp->masternamep->rname, "/dev/rdsk") == NULL) &&
500 (strstr(transp->masternamep->rname, "/dev/md/rdsk") == NULL) &&
501 (strstr(transp->masternamep->rname, "/dev/td/") == NULL)) {
502 /* not standard path, print full pathname */
503 if (fprintf(fp, " %s", transp->masternamep->rname) == EOF)
504 goto out;
505 } else {
506 /* standard path, print ctds or d number */
507 if (fprintf(fp, " %s", transp->masternamep->cname) == EOF)
508 goto out;
509 }
510
511
512 /* print log */
513 if (transp->lognamep != NULL) {
514 /*
515 * If the path is our standard /dev/rdsk or /dev/md/rdsk
516 * then just print out the cxtxdxsx or the dx, metainit
517 * will assume the default, otherwise we need the full
518 * pathname to make sure this works as we intend.
519 */
520 if ((strstr(transp->lognamep->rname, "/dev/rdsk") == NULL) &&
521 (strstr(transp->lognamep->rname, "/dev/md/rdsk") == NULL) &&
522 (strstr(transp->lognamep->rname, "/dev/td/") == NULL)) {
523 /* not standard path, print full pathname */
524 if (fprintf(fp, " %s", transp->lognamep->rname) == EOF)
525 goto out;
526 } else {
527 /* standard path */
528 if (fprintf(fp, " %s", transp->lognamep->cname) == EOF)
529 goto out;
530 }
531 }
532
533 /* print terminating newline */
534 if (fprintf(fp, "\n") == EOF)
535 goto out;
536
537 /* success */
538 rval = 0;
539
540 /* cleanup, return error */
541 out:
542 if (rval != 0)
543 (void) mdsyserror(ep, errno, fname);
544 return (rval);
545 }
546
547 /*
548 * convert flags to repair action
549 */
550
551 char *
mt_flags_to_action(md_trans_t * transp)552 mt_flags_to_action(
553 md_trans_t *transp
554 )
555 {
556 int len;
557 char *actionp = NULL;
558 int err = -1;
559
560 if (!transp) {
561 goto out;
562 }
563
564 /*
565 * if in any of these states, the log_error word is not (yet) meaningful
566 */
567 if (transp->flags & (TRANS_DETACHED|TRANS_DETACHING|TRANS_ATTACHING)) {
568 goto out;
569 }
570
571 if (transp->log_error & LDL_ANYERROR) {
572 char *fix_msg = dgettext(TEXT_DOMAIN,
573 " To Fix: Please refer to the log device's status.\n");
574
575 if ((len = strlen(fix_msg)) <= 0) {
576 goto out;
577 }
578 if (!(actionp = Zalloc(len+1))) {
579 goto out;
580 }
581 if (strncpy(actionp, fix_msg, len + 1) != actionp) {
582 goto out;
583 }
584 }
585 err = 0;
586 out:
587 if (err != 0) {
588 if (actionp) {
589 Free(actionp);
590 actionp = NULL;
591 }
592 }
593 return (actionp);
594 }
595
596 /*
597 * convert log state to repair action
598 */
599 char *
mt_l_error_to_action(mdsetname_t * sp,mdnamelist_t * transnlp,mdname_t * lognamep,md_error_t * ep)600 mt_l_error_to_action(
601 mdsetname_t *sp,
602 mdnamelist_t *transnlp,
603 mdname_t *lognamep,
604 md_error_t *ep
605 )
606 {
607 char umnt_msg[1024];
608 char fsck_msg[1024];
609 char mnt_msg[1024];
610 mdnamelist_t *p;
611 md_trans_t *tp;
612 int rc;
613 int len = 0;
614 char *rmsg = NULL;
615 char *mp = NULL;
616 bool_t is_mounted = FALSE;
617 bool_t any_in_error = FALSE;
618 int only_fsck = TRUE;
619
620 (void) memset(umnt_msg, 0, sizeof (umnt_msg));
621 (void) memset(fsck_msg, 0, sizeof (fsck_msg));
622 (void) memset(mnt_msg, 0, sizeof (mnt_msg));
623
624 /*
625 * If a the trans devices listed in transnlp contain
626 * devices which are in error and are sub-mount points
627 * of each other, than it would need to be reverse sorted.
628 * When this actually occurs, and customers find the usage
629 * message insufficiently clear, then we should take the
630 * hit to sort it.
631 */
632
633 /*
634 * this preliminary loop is necessary to keep the
635 * fsck message greppable, if possible
636 */
637 for (p = transnlp; ((p != NULL) && (only_fsck == TRUE)); p = p->next) {
638
639 if ((tp = meta_get_trans(sp, p->namep, ep)) == NULL) {
640 goto out;
641 }
642
643 if (!(tp->log_error & LDL_ANYERROR)) {
644 continue;
645 }
646
647 if ((tp->lognamep == NULL) ||
648 (strcmp(lognamep->bname, tp->lognamep->bname) != 0)) {
649 continue;
650 }
651
652 mdclrerror(ep);
653 is_mounted = (meta_check_inuse(sp,
654 p->namep, MDCHK_MOUNTED, ep) != 0);
655
656 if (!mdisok(ep) && mdisuseerror(ep, MDE_IS_MOUNTED)) {
657 goto out;
658 }
659
660 mdclrerror(ep);
661 mp = meta_get_mountp(sp, p->namep, ep);
662
663 if (!mdisok(ep)) {
664 goto out;
665 }
666
667 if (is_mounted) {
668 if (!mp) {
669 goto out;
670 }
671 only_fsck = FALSE;
672
673 /*
674 * not greppable; there must be multiple commands, so
675 * add preliminary newline so the formatting is uniform
676 */
677 if (sprintf(umnt_msg, "\n") == EOF) {
678 goto out;
679 }
680
681 }
682
683 if (mp) {
684 Free(mp);
685 mp = NULL;
686 }
687 }
688
689 /*
690 * although the log may either be in error or hard-error
691 * states, the action is the same; unmount, fsck and remount
692 * all fs associated with this log
693 */
694 for (p = transnlp; (p != NULL); p = p->next) {
695
696 if ((tp = meta_get_trans(sp, p->namep, ep)) == NULL) {
697 goto out;
698 }
699
700 if (!(tp->log_error & LDL_ANYERROR)) {
701 continue;
702 }
703
704 if ((tp->lognamep == NULL) ||
705 (strcmp(lognamep->bname, tp->lognamep->bname) != 0)) {
706 continue;
707 }
708
709 mdclrerror(ep);
710 is_mounted = (meta_check_inuse(sp,
711 p->namep, MDCHK_MOUNTED, ep) != 0);
712
713 if (!mdisok(ep) && mdisuseerror(ep, MDE_IS_MOUNTED)) {
714 goto out;
715 }
716
717 mdclrerror(ep);
718 mp = meta_get_mountp(sp, p->namep, ep);
719
720 if (!mdisok(ep)) {
721 goto out;
722 }
723
724 if (is_mounted) {
725 if (!mp) {
726 goto out;
727 }
728 }
729
730 if (is_mounted) {
731 rc = snprintf(umnt_msg, sizeof (umnt_msg),
732 "%s umount %s\n", umnt_msg, mp);
733
734 if (rc < 0) {
735 goto out;
736 }
737 }
738
739 rc = snprintf(fsck_msg, sizeof (fsck_msg), "%s %s",
740 (any_in_error) ? fsck_msg :
741 ((only_fsck) ? "fsck" : " fsck"),
742 p->namep->rname);
743 if (rc < 0) {
744 goto out;
745 }
746
747 if (is_mounted) {
748 rc = snprintf(mnt_msg, sizeof (mnt_msg),
749 "%s mount %s %s\n",
750 mnt_msg, p->namep->bname, mp);
751
752 if (rc < 0) {
753 goto out;
754 }
755 }
756
757 if (mp) {
758 Free(mp);
759 mp = NULL;
760 }
761
762 any_in_error |= TRUE;
763 }
764
765 if (!any_in_error) {
766 goto out;
767 }
768
769 len = strlen(umnt_msg) + strlen(fsck_msg) + strlen(mnt_msg) +
770 (only_fsck? 1: 0) + 1;
771 if (!(rmsg = Zalloc(len))) {
772 len = 0;
773 goto out;
774 }
775 rc = snprintf(rmsg, len, "%s%s%s%s", umnt_msg, fsck_msg,
776 !only_fsck? "\n": "", mnt_msg);
777 if (rc == EOF) {
778 goto out;
779 }
780
781 out:
782 if (mp) {
783 Free(mp);
784 mp = NULL;
785 }
786 if (len == 0 && rmsg) {
787 Free(rmsg);
788 rmsg = NULL;
789 }
790
791 return (rmsg);
792 }
793
794 /*
795 * printable log state
796 */
797 char *
mt_l_error_to_name(md_trans_t * transp,md_timeval32_t * tvp,uint_t tstate)798 mt_l_error_to_name(
799 md_trans_t *transp,
800 md_timeval32_t *tvp,
801 uint_t tstate /* Errored tstate flags */
802 )
803 {
804 mt_l_error_t log_error = transp->log_error;
805
806 /* grab time */
807 if (tvp != NULL)
808 *tvp = transp->log_timestamp;
809
810 if (tstate != 0) {
811 return (dgettext(TEXT_DOMAIN, "Unavailable"));
812 }
813
814 /* return state */
815 if (log_error & LDL_ERROR) {
816 return (dgettext(TEXT_DOMAIN, "Error"));
817 } else if (log_error & LDL_HERROR) {
818 return (dgettext(TEXT_DOMAIN, "Hard Error"));
819 } else {
820 return (dgettext(TEXT_DOMAIN, "Okay"));
821 }
822 }
823
824 /*
825 * printable trans state
826 */
827 char *
mt_flags_to_name(md_trans_t * transp,md_timeval32_t * tvp,uint_t tstate)828 mt_flags_to_name(
829 md_trans_t *transp,
830 md_timeval32_t *tvp,
831 uint_t tstate /* Errored tstate flags */
832 )
833 {
834 /* grab time */
835 if (tvp != NULL)
836 *tvp = transp->timestamp;
837
838 if (tstate != 0) {
839 return (dgettext(TEXT_DOMAIN, "Unavailable"));
840 }
841
842 /* return state */
843 if (transp->flags & TRANS_DETACHED)
844 return (dgettext(TEXT_DOMAIN, "Detached"));
845 else if (transp->flags & TRANS_DETACHING)
846 return (dgettext(TEXT_DOMAIN, "Detaching"));
847 else if (transp->flags & TRANS_ATTACHING)
848 return (dgettext(TEXT_DOMAIN, "Attaching"));
849 return (mt_l_error_to_name(transp, tvp, tstate));
850 }
851
852 /*
853 * report trans
854 */
855 static int
trans_report(mdsetname_t * sp,md_trans_t * transp,char * fname,FILE * fp,mdprtopts_t options,md_error_t * ep)856 trans_report(
857 mdsetname_t *sp,
858 md_trans_t *transp,
859 char *fname,
860 FILE *fp,
861 mdprtopts_t options,
862 md_error_t *ep
863 )
864 {
865 char *mt_state;
866 md_timeval32_t tv;
867 char *timep;
868 int rval = -1;
869 char *actionp = NULL;
870 char *devid = "";
871 mdname_t *didnp = NULL;
872 ddi_devid_t dtp;
873 uint_t tstate = 0;
874
875 /* print header */
876 if (options & PRINT_HEADER) {
877 if (fprintf(fp, dgettext(TEXT_DOMAIN, "%s: Trans"
878 " (Feature replaced see message below)\n"),
879 transp->common.namep->cname) == EOF) {
880 goto out;
881 }
882 }
883
884 /* print state */
885 if (metaismeta(transp->common.namep)) {
886 if (meta_get_tstate(transp->common.namep->dev, &tstate, ep)
887 != 0)
888 goto out;
889 }
890 mt_state = mt_flags_to_name(transp, &tv, tstate & MD_DEV_ERRORED);
891 if (options & PRINT_TIMES) {
892 timep = meta_print_time(&tv);
893 } else {
894 timep = "";
895 }
896 if (fprintf(fp, dgettext(TEXT_DOMAIN, " State: %-12s %s\n"),
897 mt_state, timep) == EOF) {
898 goto out;
899 }
900
901 if ((tstate & MD_DEV_ERRORED) == 0) {
902 actionp = mt_flags_to_action(transp);
903 if (actionp) {
904 if (fprintf(fp, "%s", actionp) == EOF) {
905 goto out;
906 }
907 Free(actionp);
908 actionp = NULL;
909 }
910 }
911
912 /* debug stuff */
913 if (transp->debug) {
914 if (fprintf(fp,
915 " Debug Modes:%s%s%s%s%s%s%s%s%s%s%s\n",
916 (transp->debug & MT_TRANSACT) ? " TRANSACT" : "",
917 (transp->debug & MT_MATAMAP) ? " METADATA" : "",
918 (transp->debug & MT_WRITE_CHECK) ? " WRITES" : "",
919 (transp->debug & MT_LOG_WRITE_CHECK) ? " LOGWRITES" : "",
920 (transp->debug & MT_CHECK_MAP) ? " MAP" : "",
921 (transp->debug & MT_TRACE) ? " TRACE" : "",
922 (transp->debug & MT_SIZE) ? " SIZE" : "",
923 (transp->debug & MT_NOASYNC) ? " NOASYNC" : "",
924 (transp->debug & MT_FORCEROLL) ? " FORCEROLL" : "",
925 (transp->debug & MT_SCAN) ? " SCAN" : "",
926 (transp->debug & MT_PREWRITE) ? " PREWRITE" : "")
927 == EOF) {
928 goto out;
929 }
930 }
931
932 /* print size */
933 if (fprintf(fp, dgettext(TEXT_DOMAIN, " Size: %lld blocks (%s)\n"),
934 transp->common.size,
935 meta_number_to_string(transp->common.size, DEV_BSIZE)) == EOF) {
936 goto out;
937 }
938
939
940 /* print master */
941 if (fprintf(fp, dgettext(TEXT_DOMAIN, " Master Device: %s\n"),
942 transp->masternamep->cname) == EOF) {
943 goto out;
944 }
945
946 /* print log */
947 if (transp->lognamep != NULL) {
948 if (fprintf(fp, dgettext(TEXT_DOMAIN,
949 " Logging Device: %s\n"),
950 transp->lognamep->cname) == EOF) {
951 goto out;
952 }
953 }
954
955 /* add extra line */
956 if (fprintf(fp, "\n") == EOF)
957 goto out;
958
959 /* print master details if regular device */
960 if (! metaismeta(transp->masternamep)) {
961 daddr_t start_blk = 0;
962 char *has_mddb_str = dgettext(TEXT_DOMAIN, "No");
963 int len;
964
965 /*
966 * Building a format string on the fly that will
967 * be used in (f)printf. This allows the length
968 * of the ctd to vary from small to large without
969 * looking horrible.
970 */
971 len = strlen(transp->masternamep->cname) + 2;
972 len = max(len, strlen(dgettext(TEXT_DOMAIN, "Master Device")));
973
974 /* print header */
975 if (fprintf(fp,
976 "\t%-*.*s %-12.12s %-5.5s %s\n",
977 len, len,
978 dgettext(TEXT_DOMAIN, "Master Device"),
979 dgettext(TEXT_DOMAIN, "Start Block"),
980 dgettext(TEXT_DOMAIN, "Dbase"),
981 dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
982 goto out;
983 }
984
985 /* populate the key in the name_p structure */
986 if ((didnp = metadevname(&sp,
987 transp->masternamep->dev, ep)) == NULL) {
988 return (-1);
989 }
990
991 /* determine if devid does NOT exist */
992 if (options & PRINT_DEVID)
993 if ((dtp = meta_getdidbykey(sp->setno,
994 getmyside(sp, ep), didnp->key, ep)) == NULL) {
995 devid = dgettext(TEXT_DOMAIN, "No ");
996 } else {
997 devid = dgettext(TEXT_DOMAIN, "Yes");
998 free(dtp);
999 }
1000
1001 /* print info */
1002 /*
1003 * This allows the length
1004 * of the ctd to vary from small to large without
1005 * looking horrible.
1006 */
1007 if (fprintf(fp, "\t%-*s %8ld %-5.5s %s\n", len,
1008 transp->masternamep->cname,
1009 start_blk, has_mddb_str, devid) == EOF) {
1010 goto out;
1011 }
1012 /* add extra line */
1013 if (fprintf(fp, "\n") == EOF)
1014 goto out;
1015 }
1016
1017 /* success */
1018 rval = 0;
1019
1020 /* cleanup, return error */
1021 out:
1022 if (rval != 0)
1023 (void) mdsyserror(ep, errno, fname);
1024 return (rval);
1025 }
1026
1027 /*
1028 * print/report trans
1029 */
1030 int
meta_trans_print(mdsetname_t * sp,mdname_t * transnp,mdnamelist_t ** nlistpp,char * fname,FILE * fp,mdprtopts_t options,int * meta_print_trans_msgp,mdnamelist_t ** lognlpp,md_error_t * ep)1031 meta_trans_print(
1032 mdsetname_t *sp,
1033 mdname_t *transnp,
1034 mdnamelist_t **nlistpp,
1035 char *fname,
1036 FILE *fp,
1037 mdprtopts_t options,
1038 int *meta_print_trans_msgp, /* NULL if transnp != NULL */
1039 mdnamelist_t **lognlpp,
1040 md_error_t *ep
1041 )
1042 {
1043 md_trans_t *transp;
1044 mdname_t *lognamep;
1045
1046 /* should have same set */
1047 assert(sp != NULL);
1048
1049 /* print all transs */
1050 if (transnp == NULL) {
1051 mdnamelist_t *nlp = NULL;
1052 mdnamelist_t *p;
1053 int cnt;
1054 int rval = 0;
1055
1056 /* get list */
1057 if ((cnt = meta_get_trans_names(sp, &nlp, options, ep)) < 0)
1058 return (-1);
1059 else if (cnt == 0)
1060 return (0);
1061
1062 /* recurse */
1063 for (p = nlp; (p != NULL); p = p->next) {
1064 mdname_t *np = p->namep;
1065
1066 if (meta_trans_print(sp, np, nlistpp, fname, fp,
1067 options, meta_print_trans_msgp, lognlpp, ep) != 0)
1068 rval = -1;
1069 }
1070
1071 if (meta_print_trans_msgp)
1072 *meta_print_trans_msgp = 1;
1073
1074 /* cleanup, return success */
1075 metafreenamelist(nlp);
1076 return (rval);
1077 }
1078
1079
1080 /* get unit structure */
1081 if ((transp = meta_get_trans_common(sp, transnp,
1082 ((options & PRINT_FAST) ? 1 : 0), ep)) == NULL)
1083 return (-1);
1084
1085 /* save unique log */
1086 if ((lognlpp != NULL) &&
1087 ((lognamep = transp->lognamep) != NULL)) {
1088 mdnamelist_t *p;
1089
1090 for (p = *lognlpp; (p != NULL); p = p->next) {
1091 if (strcmp(lognamep->bname, p->namep->bname) == 0)
1092 break;
1093 }
1094 if (p == NULL)
1095 (void) metanamelist_append(lognlpp, lognamep);
1096 }
1097
1098 /* check for parented */
1099 if ((! (options & PRINT_SUBDEVS)) &&
1100 (MD_HAS_PARENT(transp->common.parent))) {
1101 return (0);
1102 }
1103
1104 /* can't have a large trans or descriptive name trans */
1105 if (!(options & (PRINT_LARGEDEVICES | PRINT_FN))) {
1106 /* print appropriate detail */
1107 if (options & PRINT_SHORT) {
1108 if (trans_print(transp, fname, fp, ep) != 0)
1109 return (-1);
1110 } else {
1111 if (trans_report(sp, transp, fname, fp, options, ep)
1112 != 0)
1113 return (-1);
1114 }
1115 }
1116
1117 /* print underlying metadevices, log is later */
1118 if (metaismeta(transp->masternamep)) {
1119 if (meta_print_name(sp, transp->masternamep, nlistpp, fname,
1120 fp, (options | PRINT_HEADER | PRINT_SUBDEVS), NULL, ep)
1121 != 0) {
1122 return (-1);
1123 }
1124 }
1125
1126 /* return success */
1127 return (0);
1128 }
1129
1130 /*
1131 * print log
1132 */
1133 static int
log_print(mdsetname_t * sp,mdname_t * lognamep,char * fname,FILE * fp,mdprtopts_t options,md_error_t * ep)1134 log_print(
1135 mdsetname_t *sp,
1136 mdname_t *lognamep,
1137 char *fname,
1138 FILE *fp,
1139 mdprtopts_t options,
1140 md_error_t *ep
1141 )
1142 {
1143 mdnamelist_t *nlp = NULL;
1144
1145 /* metadevice info */
1146 if (metaismeta(lognamep)) {
1147 return (meta_print_name(sp, lognamep, &nlp, fname, fp,
1148 options, NULL, ep));
1149 }
1150
1151 /* regular device info */
1152 return (0);
1153 }
1154
1155 /*
1156 * report log
1157 */
1158 static int
log_report(mdsetname_t * sp,mdname_t * lognamep,mdnamelist_t ** nlistpp,char * fname,FILE * fp,mdprtopts_t options,mdnamelist_t * transnlp,md_error_t * ep)1159 log_report(
1160 mdsetname_t *sp,
1161 mdname_t *lognamep,
1162 mdnamelist_t **nlistpp,
1163 char *fname,
1164 FILE *fp,
1165 mdprtopts_t options,
1166 mdnamelist_t *transnlp,
1167 md_error_t *ep
1168 )
1169 {
1170 md_trans_t *transp = NULL;
1171 mdnamelist_t *p;
1172 char *ml_state;
1173 md_timeval32_t tv;
1174 char *timep;
1175 char *actionp = NULL;
1176 int rval = -1;
1177 char *devid = " ";
1178 mdname_t *didnp = NULL;
1179 ddi_devid_t dtp;
1180 uint_t tstate = 0;
1181
1182 for (p = transnlp; (p != NULL); p = p->next) {
1183 md_trans_t *tp;
1184
1185 if ((tp = meta_get_trans(sp, p->namep, ep)) == NULL)
1186 return (-1);
1187 if ((tp->lognamep != NULL) &&
1188 (strcmp(lognamep->bname, tp->lognamep->bname) == 0)) {
1189 transp = tp; /* save any parent trans */
1190 }
1191 }
1192
1193 /* we must have at least one trans */
1194 assert(transp != NULL);
1195 if (transp == NULL) {
1196 rval = 0;
1197 goto out;
1198 }
1199
1200 if ((options & PRINT_LARGEDEVICES) &&
1201 (transp->log_size <= MD_MAX_BLKS_FOR_SMALL_DEVS)) {
1202 rval = 0;
1203 goto out;
1204 }
1205
1206 /* print header and trans devices, collect log_error and size */
1207 if (fprintf(fp, dgettext(TEXT_DOMAIN, "%s: Logging device for"),
1208 lognamep->cname) == EOF) {
1209 goto out;
1210 }
1211
1212 if ((transp->lognamep != NULL) &&
1213 (strcmp(lognamep->bname, transp->lognamep->bname) == 0)) {
1214 if (fprintf(fp, " %s", transp->common.namep->cname)
1215 == EOF) {
1216 goto out;
1217 }
1218 }
1219 if (fprintf(fp, "\n") == EOF)
1220 goto out;
1221
1222 /* print state */
1223 if (metaismeta(transp->lognamep)) {
1224 if (meta_get_tstate(transp->lognamep->dev, &tstate, ep) != 0)
1225 return (-1);
1226 }
1227 ml_state = mt_l_error_to_name(transp, &tv, tstate & MD_DEV_ERRORED);
1228 if (options & PRINT_TIMES) {
1229 timep = meta_print_time(&tv);
1230 } else {
1231 timep = "";
1232 }
1233 if (fprintf(fp, dgettext(TEXT_DOMAIN, " State: %-12s %s\n"),
1234 ml_state, timep) == EOF) {
1235 goto out;
1236 }
1237
1238 if ((tstate & MD_DEV_ERRORED) == 0) {
1239 actionp = mt_l_error_to_action(sp, transnlp, lognamep, ep);
1240 if (actionp) {
1241 if (fprintf(fp, dgettext(TEXT_DOMAIN,
1242 " Invoke: %s\n"), actionp) == EOF) {
1243 goto out;
1244 }
1245 Free(actionp);
1246 actionp = NULL;
1247 }
1248 }
1249
1250 /* print size */
1251 if (fprintf(fp, dgettext(TEXT_DOMAIN, " Size: %ld blocks (%s)\n"),
1252 transp->log_size,
1253 meta_number_to_string(transp->log_size, DEV_BSIZE)) == EOF) {
1254 goto out;
1255 }
1256
1257 /* MD_DEBUG stuff */
1258 if (options & PRINT_DEBUG) {
1259 mdname_t *transnp = transp->common.namep;
1260 mt_unit_t *mt;
1261 daddr_t blksinuse, head, tail, nblks, eblk, sblk;
1262 int percent;
1263
1264 if ((mt = (mt_unit_t *)meta_get_mdunit(sp, transnp, ep))
1265 == NULL) {
1266 return (-1);
1267 }
1268 assert(mt->c.un_type == MD_METATRANS);
1269
1270 if (fprintf(fp, dgettext(TEXT_DOMAIN,
1271 " Transfer Size: %d blocks\n"),
1272 mt->un_l_maxtransfer) == EOF) {
1273 Free(mt);
1274 goto out;
1275 }
1276
1277 head = mt->un_l_head;
1278 tail = mt->un_l_tail;
1279 sblk = mt->un_l_sblk;
1280 nblks = mt->un_l_nblks;
1281 eblk = sblk + nblks;
1282 if (head <= tail)
1283 blksinuse = tail - head;
1284 else
1285 blksinuse = (eblk - head) + (tail - sblk);
1286
1287 percent = ((u_longlong_t)blksinuse * 100) / nblks;
1288 if (fprintf(fp, dgettext(TEXT_DOMAIN,
1289 " Full: %d%% (%ld of %ld blocks)\n"),
1290 percent, blksinuse, nblks) == EOF) {
1291 Free(mt);
1292 goto out;
1293 }
1294
1295 percent = ((u_longlong_t)mt->un_l_resv * 100) /
1296 mt->un_l_maxresv;
1297 if (fprintf(fp, dgettext(TEXT_DOMAIN,
1298 " Reserved: %d%% (%ud of %ud bytes)\n"),
1299 percent, mt->un_l_resv, mt->un_l_maxresv) == EOF) {
1300 Free(mt);
1301 goto out;
1302 }
1303 Free(mt);
1304 }
1305
1306 /* add extra line */
1307 if (fprintf(fp, "\n") == EOF)
1308 goto out;
1309
1310 /* print log details */
1311 if (metaismeta(lognamep)) {
1312 if (meta_print_name(sp, lognamep, nlistpp, fname, fp,
1313 options, NULL, ep) != 0) {
1314 return (-1);
1315 }
1316 } else {
1317 daddr_t start_blk;
1318 int has_mddb;
1319 char *has_mddb_str;
1320 int len;
1321
1322 /*
1323 * Building a format string on the fly that will
1324 * be used in (f)printf. This allows the length
1325 * of the ctd to vary from small to large without
1326 * looking horrible.
1327 */
1328 len = strlen(lognamep->cname) + 2;
1329 len = max(len, strlen(dgettext(TEXT_DOMAIN, "Logging Device")));
1330 /* print header */
1331 if (fprintf(fp,
1332 "\t%-*.*s %-12.12s %-5.5s %s\n",
1333 len, len,
1334 dgettext(TEXT_DOMAIN, "Logging Device"),
1335 dgettext(TEXT_DOMAIN, "Start Block"),
1336 dgettext(TEXT_DOMAIN, "Dbase"),
1337 dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
1338 goto out;
1339 }
1340 /* get info */
1341 if ((start_blk = metagetstart(sp, lognamep, ep)) ==
1342 MD_DISKADDR_ERROR) {
1343 return (-1);
1344 }
1345 if ((has_mddb = metahasmddb(sp, lognamep, ep)) < 0) {
1346 return (-1);
1347 }
1348 if (has_mddb)
1349 has_mddb_str = dgettext(TEXT_DOMAIN, "Yes");
1350 else
1351 has_mddb_str = dgettext(TEXT_DOMAIN, "No");
1352
1353 /* populate the key in the name_p structure */
1354 if ((didnp = metadevname(&sp, lognamep->dev, ep)) == NULL) {
1355 return (-1);
1356 }
1357
1358 /* determine if devid does NOT exist */
1359 if (options & PRINT_DEVID)
1360 if ((dtp = meta_getdidbykey(sp->setno,
1361 getmyside(sp, ep), didnp->key, ep)) == NULL) {
1362 devid = dgettext(TEXT_DOMAIN, "No ");
1363 } else {
1364 devid = dgettext(TEXT_DOMAIN, "Yes");
1365 free(dtp);
1366 }
1367
1368 /* print info */
1369 /*
1370 * This allows the length
1371 * of the ctd to vary from small to large without
1372 * looking horrible.
1373 */
1374 if (fprintf(fp, "\t%-*s %8ld %-5.5s %s\n",
1375 len, lognamep->cname, start_blk,
1376 has_mddb_str, devid) == EOF) {
1377 goto out;
1378 }
1379 }
1380
1381 /* add extra line */
1382 if (fprintf(fp, "\n") == EOF)
1383 goto out;
1384
1385 /* success */
1386 rval = 0;
1387
1388 /* cleanup, return error */
1389 out:
1390 if (rval != 0)
1391 (void) mdsyserror(ep, errno, fname);
1392 return (rval);
1393 }
1394
1395 /*
1396 * print/report logs
1397 */
1398 int
meta_logs_print(mdsetname_t * sp,mdnamelist_t * lognlp,mdnamelist_t ** nlistpp,char * fname,FILE * fp,mdprtopts_t options,md_error_t * ep)1399 meta_logs_print(
1400 mdsetname_t *sp,
1401 mdnamelist_t *lognlp,
1402 mdnamelist_t **nlistpp,
1403 char *fname,
1404 FILE *fp,
1405 mdprtopts_t options,
1406 md_error_t *ep
1407 )
1408 {
1409 mdnamelist_t *transnlp = NULL;
1410 mdnamelist_t *p;
1411 int rval = 0;
1412
1413 /* must have a set */
1414 assert(sp != NULL);
1415
1416 /* get trans devices */
1417 if (lognlp == NULL)
1418 return (0);
1419
1420 if (! (options & PRINT_SHORT))
1421 if (meta_get_trans_names(sp, &transnlp, options, ep) < 0)
1422 return (-1);
1423
1424 /* print all logs */
1425 options |= PRINT_SUBDEVS;
1426 for (p = lognlp; (p != NULL); p = p->next) {
1427 mdname_t *lognamep = p->namep;
1428
1429 /* print appropriate detail */
1430 if (options & PRINT_SHORT) {
1431 if (log_print(sp, lognamep, fname, fp, options,
1432 ep) != 0) {
1433 rval = -1;
1434 }
1435 } else {
1436 if (log_report(sp, lognamep, nlistpp, fname, fp,
1437 options, transnlp, ep) != 0) {
1438 rval = -1;
1439 }
1440 }
1441 }
1442
1443 /* cleanup, return success */
1444 out:
1445 metafreenamelist(transnlp);
1446 return (rval);
1447 }
1448
1449 /*
1450 * meta_lockfs_common -- common lock and unlock code
1451 *
1452 * Normally this routine will return a 0 for success. Even if
1453 * lockfs wasn't able to lock down the filesystem. The reason
1454 * for this is that the master device can be in an errored state
1455 * and the lock can't be obtained. We don't want to prevent
1456 * possible recovery in this case and it's not likely any activity
1457 * will be occurring. If the filesystem is healthy with activity
1458 * lockfs will successfully lock the filesystem and return an
1459 * error code of 0.
1460 *
1461 * The one case where this routine returns a non-zero value would
1462 * be if we can't determine the outcome of the lockfs. This should
1463 * never occur because we don't catch signals that could cause
1464 * waitpid() to prematurely return.
1465 */
1466 static int
meta_lockfs_common(mdname_t * fs,void ** cookie,int lockit)1467 meta_lockfs_common(mdname_t *fs, void **cookie, int lockit)
1468 {
1469 char *blkname;
1470 FILE *m;
1471 struct mnttab tab_wildcard, tab_match;
1472 pid_t pid;
1473 int lock_exit;
1474
1475 (void) memset(&tab_wildcard, 0, sizeof (tab_wildcard));
1476 (void) memset(&tab_match, 0, sizeof (tab_match));
1477
1478 if ((blkname = fs->bname) == NULL)
1479 blkname = getfullblkname(fs->cname);
1480
1481 tab_wildcard.mnt_special = blkname;
1482
1483 if ((m = fopen(MNTTAB, "r")) == NULL) {
1484 /*
1485 * No mnttab means nothing is mounted
1486 */
1487 *cookie = 0;
1488 return (0);
1489 }
1490
1491 if (getmntany(m, &tab_match, &tab_wildcard)) {
1492 /*
1493 * No match in mnttab so we're not mounted ... at least
1494 * nothing better be mounted.
1495 */
1496 *cookie = 0;
1497 return (0);
1498 }
1499
1500 (void) fclose(m);
1501
1502 switch (pid = fork()) {
1503 case -1:
1504 /*
1505 * We've got some major trouble here and shouldn't
1506 * continue. The user needs to clear up the problems
1507 * that the system currently has before proceeding
1508 * to detach the log.
1509 */
1510 (void) printf(dgettext(TEXT_DOMAIN, "failed to fork lockfs\n"));
1511 *cookie = 0;
1512 return (1);
1513
1514 case 0:
1515 (void) execl("/usr/sbin/lockfs", "lockfs", lockit ? "-w" : "-u",
1516 "-c", "Solaris Volume Manager detach lock",
1517 tab_match.mnt_mountp, 0);
1518 /*
1519 * Shouldn't reach here, but if this code is run on
1520 * a release that doesn't have lockfs return an error
1521 * code so that the -f (force) option could be used
1522 * by metadetach.
1523 */
1524 exit(1);
1525
1526 default:
1527 if (waitpid(pid, &lock_exit, 0) != pid) {
1528 /*
1529 * We couldn't get status regarding the
1530 * outcome of the lockfs command. We should
1531 * attempt to unlock the filesystem though.
1532 * Return an error code so that if the user
1533 * is trying to force the detach make them
1534 * clear up this problem first.
1535 */
1536 *cookie = (void *)1;
1537 return (1);
1538 }
1539
1540 *cookie = (void *)1;
1541 return (0);
1542 }
1543 }
1544
1545 /*
1546 * meta_lockfs - if mounted, lock a given device against writes
1547 *
1548 * See comment section for meta_lockfs_common
1549 */
1550 static int
meta_lockfs(mdname_t * fs,void ** cookie)1551 meta_lockfs(mdname_t *fs, void **cookie)
1552 {
1553 return (meta_lockfs_common(fs, cookie, 1));
1554 }
1555
1556 /*
1557 * meta_unlockfs - if mounted, unlock the filesystem if previously locked
1558 *
1559 * See comment section for meta_lockfs_common
1560 */
1561 static void
meta_unlockfs(mdname_t * fs,void ** cookie)1562 meta_unlockfs(mdname_t *fs, void **cookie)
1563 {
1564 /*
1565 * Simple time saver. We could always try to unlock
1566 * the filesystem, that takes time a resources.
1567 */
1568 if (*cookie == (void *)1)
1569 (void) meta_lockfs_common(fs, cookie, 0);
1570 }
1571
1572 /*
1573 * meta_trans_detach -- detach log from trans device
1574 */
1575 int
meta_trans_detach(mdsetname_t * sp,mdname_t * transnp,mdcmdopts_t options,int * delayed,md_error_t * ep)1576 meta_trans_detach(
1577 mdsetname_t *sp,
1578 mdname_t *transnp,
1579 mdcmdopts_t options,
1580 int *delayed,
1581 md_error_t *ep
1582 )
1583 {
1584 int force = ((options & MDCMD_FORCE) ? 1 : 0);
1585 md_i_get_t detach;
1586 md_trans_t *transp;
1587 mdname_t *lognp;
1588 void *lock_cookie;
1589
1590 /* should have a set */
1591 assert(sp != NULL);
1592 assert(sp->setno == MD_MIN2SET(meta_getminor(transnp->dev)));
1593
1594 /* check name */
1595 if (metachkmeta(transnp, ep) != 0)
1596 return (-1);
1597
1598 /* save log name */
1599 if ((transp = meta_get_trans(sp, transnp, ep)) == NULL)
1600 return (-1);
1601 if ((lognp = transp->lognamep) == NULL)
1602 return (mdmderror(ep, MDE_NO_LOG, meta_getminor(transnp->dev),
1603 transnp->cname));
1604
1605 /*
1606 * If trans device is mounted lock the filesystem
1607 * against writes and mod time updates.
1608 */
1609 if (force && meta_lockfs(transnp, &lock_cookie)) {
1610 /*
1611 * This device is mounted and we were unable
1612 * lock the device. Data corruption can occur
1613 * if we don't lock the device before removing
1614 * the log so bail out here.
1615 * NOTE: There's one case were the exist status
1616 * of lockfs could have been lost yet the command
1617 * could have run. We should try to unlock the filesystem
1618 * before returning.
1619 */
1620 meta_unlockfs(transnp, &lock_cookie);
1621 return (mdmderror(ep, MDE_UNKNOWN_TYPE,
1622 meta_getminor(transnp->dev), transnp->cname));
1623 }
1624
1625 /* detach log */
1626 *delayed = 0;
1627 (void) memset(&detach, 0, sizeof (detach));
1628 detach.id = meta_getminor(transnp->dev);
1629 MD_SETDRIVERNAME(&detach, MD_TRANS, sp->setno);
1630 detach.size = force;
1631 if (metaioctl(MD_IOC_TRANS_DETACH, &detach, &detach.mde, NULL) != 0) {
1632 /* delayed detach */
1633 if ((force) && (mdissyserror(&detach.mde, EBUSY))) {
1634 *delayed = 1;
1635 mdclrerror(&detach.mde);
1636 } else {
1637 meta_unlockfs(transnp, &lock_cookie);
1638 return (mdstealerror(ep, &detach.mde));
1639 }
1640 }
1641
1642 /*
1643 * Unlock the filesystem
1644 */
1645 meta_unlockfs(transnp, &lock_cookie);
1646
1647 /* clear cache */
1648 meta_invalidate_name(lognp);
1649 meta_invalidate_name(transnp);
1650
1651 /* let em know */
1652 if (options & MDCMD_PRINT) {
1653 if (*delayed) {
1654 (void) printf(dgettext(TEXT_DOMAIN,
1655 "%s: logging device %s will be detached at unmount or reboot\n"),
1656 transnp->cname, lognp->cname);
1657 } else {
1658 (void) printf(dgettext(TEXT_DOMAIN,
1659 "%s: logging device %s is detached\n"),
1660 transnp->cname, lognp->cname);
1661 }
1662 (void) fflush(stdout);
1663 }
1664
1665 /* return success */
1666 return (0);
1667 }
1668
1669 /*
1670 * reset trans
1671 */
1672 int
meta_trans_reset(mdsetname_t * sp,mdname_t * transnp,mdcmdopts_t options,md_error_t * ep)1673 meta_trans_reset(
1674 mdsetname_t *sp,
1675 mdname_t *transnp,
1676 mdcmdopts_t options,
1677 md_error_t *ep
1678 )
1679 {
1680 md_trans_t *transp;
1681 int rval = -1;
1682
1683 /* should have a set */
1684 assert(sp != NULL);
1685 assert((transnp == NULL) ||
1686 (sp->setno == MD_MIN2SET(meta_getminor(transnp->dev))));
1687
1688 /* reset all trans */
1689 if (transnp == NULL) {
1690 mdnamelist_t *transnlp = NULL;
1691 mdnamelist_t *p;
1692
1693 /* for each trans */
1694 rval = 0;
1695 if (meta_get_trans_names(sp, &transnlp, 0, ep) < 0)
1696 return (-1);
1697 for (p = transnlp; (p != NULL); p = p->next) {
1698 /* reset trans */
1699 transnp = p->namep;
1700 if (meta_trans_reset(sp, transnp, options, ep) != 0) {
1701 rval = -1;
1702 break;
1703 }
1704 }
1705
1706 /* cleanup, return success */
1707 metafreenamelist(transnlp);
1708 return (rval);
1709 }
1710
1711 /* check name */
1712 if (metachkmeta(transnp, ep) != 0)
1713 return (-1);
1714 /* get unit structure */
1715 if ((transp = meta_get_trans(sp, transnp, ep)) == NULL)
1716 return (-1);
1717
1718 /* make sure nobody owns us */
1719 if (MD_HAS_PARENT(transp->common.parent)) {
1720 return (mdmderror(ep, MDE_IN_USE, meta_getminor(transnp->dev),
1721 transnp->cname));
1722 }
1723
1724 /* clear subdevices cache */
1725 meta_invalidate_name(transp->masternamep);
1726 if (transp->lognamep)
1727 meta_invalidate_name(transp->lognamep);
1728
1729 /* clear metadevice */
1730 if (meta_reset(sp, transnp, options, ep) != 0)
1731 goto out;
1732 rval = 0; /* success */
1733
1734 /* let em know */
1735 if (options & MDCMD_PRINT) {
1736 (void) printf(dgettext(TEXT_DOMAIN, "%s: Trans is cleared\n"),
1737 transnp->cname);
1738 (void) fflush(stdout);
1739 }
1740
1741 /* clear subdevices */
1742 if (! (options & MDCMD_RECURSE))
1743 goto out;
1744 if (metaismeta(transp->masternamep)) {
1745 mdname_t *masternp = transp->masternamep;
1746
1747 if (meta_reset_by_name(sp, masternp, options, ep) != 0)
1748 rval = -1;
1749 }
1750 /* (multi-parented) log will be cleared later */
1751
1752 /* cleanup, return success */
1753 out:
1754 meta_invalidate_name(transnp);
1755 return (rval);
1756 }
1757