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