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