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 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 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 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 * 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 * 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 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 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 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 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 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 * 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 * 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 * 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 * 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 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 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 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 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 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 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 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 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 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 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