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 2005 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 * change the identity of a metadevice 39 * These are the "do it" functions for the metarename command. 40 */ 41 42 #include <string.h> 43 #include <meta.h> 44 #include <sys/lvm/md_rename.h> 45 46 /* private */ 47 #define FORCE (0x00000001) 48 #define NOISY (0x00000010) 49 #define NOFLIP (0x00000020) 50 #define DRYRUN (0x00000040) 51 52 #define OP_STR(op) \ 53 ((op) == MDRNOP_EXCHANGE? "exchange": \ 54 (op) == MDRNOP_RENAME? "rename": \ 55 (op) == MDRNOP_UNK? "<unknown>": "garbage") 56 57 58 /* 59 * Check if from_np is open 60 * Return 0 if not open, -1 if open 61 */ 62 static int 63 check_open( 64 mdsetname_t *sp, 65 mdname_t *from_np, 66 md_error_t *ep) 67 { 68 int rc; 69 70 if ((rc = meta_isopen(sp, from_np, ep, (mdcmdopts_t)0)) < 0) { 71 assert(!mdisok(ep)); 72 return (-1); 73 74 } else if (rc > 0) { 75 if (mdisok(ep)) { 76 (void) mdmderror(ep, MDE_RENAME_BUSY, 77 meta_getminor(from_np->dev), 78 from_np->cname); 79 } 80 return (-1); 81 } 82 return (0); 83 } 84 85 /* 86 * meta_swap is the common code used by the 87 * meta_rename() and meta_exchange() entry points 88 */ 89 90 static int 91 meta_swap( 92 mdsetname_t *sp, 93 mdname_t *from_np, 94 md_common_t *from_mdp, 95 mdname_t *to_np, 96 md_common_t *to_mdp, 97 md_renop_t op, 98 int flags, 99 md_error_t *ep) 100 { 101 md_rename_t txn; 102 int from_add_flag = 0; 103 int to_add_flag = 0; 104 105 /* 106 * If the device exists a key may already exist so need to find it 107 * otherwise we'll end up adding the key in again which will lead 108 * to an inconsistent n_count for the namespace record. 109 */ 110 if (from_np->dev != NODEV) { 111 (void) meta_getnmentbydev(sp->setno, MD_SIDEWILD, from_np->dev, 112 NULL, NULL, &from_np->key, ep); 113 } 114 115 if (to_np->dev != NODEV) { 116 (void) meta_getnmentbydev(sp->setno, MD_SIDEWILD, to_np->dev, 117 NULL, NULL, &to_np->key, ep); 118 } 119 120 if ((from_np->key == MD_KEYWILD) || (from_np->key == MD_KEYBAD)) { 121 /* 122 * If from does not have key and it is a component device 123 * then something really goes wrong 124 */ 125 assert(!MD_HAS_PARENT(from_mdp->parent)); 126 127 /* 128 * So only add the entry if from is a top device 129 */ 130 if (add_key_name(sp, from_np, NULL, ep) != 0) { 131 assert(!mdisok(ep)); 132 return (-1); 133 } else { 134 from_add_flag = 1; 135 } 136 } 137 138 (void) memset(&txn, 0, sizeof (txn)); 139 140 txn.op = op; 141 txn.revision = MD_RENAME_VERSION; 142 txn.flags = 0; 143 txn.from.mnum = meta_getminor(from_np->dev); 144 txn.from.key = from_np->key; 145 146 if ((to_np->key == MD_KEYWILD) || (to_np->key == MD_KEYBAD)) { 147 /* 148 * If to does not have key and is not a top device 149 * then something really goes wrong 150 */ 151 assert(!MD_HAS_PARENT(to_mdp->parent)); 152 153 /* 154 * Add entry 155 */ 156 if (add_key_name(sp, to_np, NULL, ep) != 0) { 157 assert(!mdisok(ep)); 158 if (from_add_flag) 159 (void) del_key_name(sp, from_np, ep); 160 return (-1); 161 } else { 162 to_add_flag = 1; 163 } 164 } 165 166 txn.to.mnum = meta_getminor(to_np->dev); 167 txn.to.key = to_np->key; 168 169 if (flags & NOISY) { 170 (void) fprintf(stderr, "\top: %s\n", OP_STR(txn.op)); 171 (void) fprintf(stderr, "\trevision: %d, flags: %d\n", 172 txn.revision, txn.flags); 173 (void) fprintf(stderr, 174 "\tfrom(mnum,key): %ld, %d\tto: %ld, %d\n", 175 txn.from.mnum, txn.from.key, 176 txn.to.mnum, txn.to.key); 177 } 178 179 mdclrerror(ep); 180 if (metaioctl(MD_IOCRENAME, &txn, &txn.mde, from_np->cname) != 0) { 181 if (from_add_flag) { 182 (void) del_key_name(sp, from_np, ep); 183 } 184 185 if (op == MDRNOP_RENAME || to_add_flag) { 186 (void) del_key_name(sp, to_np, ep); 187 } 188 return (mdstealerror(ep, &txn.mde)); 189 } 190 191 /* 192 * If top device 193 */ 194 if (op == MDRNOP_RENAME && !MD_HAS_PARENT(from_mdp->parent)) { 195 (void) del_key_name(sp, to_np, ep); 196 } 197 198 /* force the name cache to re-read device state */ 199 meta_invalidate_name(from_np); 200 meta_invalidate_name(to_np); 201 202 return (0); 203 } 204 205 /* 206 * rename a metadevice 207 */ 208 int 209 meta_rename( 210 mdsetname_t *sp, 211 mdname_t *from_np, 212 mdname_t *to_np, 213 mdcmdopts_t options, 214 md_error_t *ep 215 ) 216 { 217 int flags = (options & MDCMD_FORCE)? FORCE: 0; 218 int rc = 0; 219 mdcinfo_t *cinfop; 220 char *p; 221 md_set_desc *sd; 222 mdkey_t side_key = MD_KEYWILD; 223 md_error_t dummy_ep = mdnullerror; 224 int i, j; 225 md_mnnode_desc *nd, *nd_del; 226 md_common_t *from_mdp; 227 228 /* must have a set */ 229 assert(sp != NULL); 230 assert(sp->setno == MD_MIN2SET(meta_getminor(from_np->dev))); 231 232 mdclrerror(ep); 233 234 if (((p = getenv("MD_DEBUG")) != NULL) && 235 (strstr(p, "RENAME") != NULL)) { 236 flags |= NOISY; 237 } 238 /* if DOIT is not set, we are in dryrun mode */ 239 if ((options & MDCMD_DOIT) == 0) { 240 flags |= DRYRUN; 241 } 242 243 244 if (metachkmeta(from_np, ep) != 0) { 245 assert(!mdisok(ep)); 246 return (-1); 247 } 248 249 mdclrerror(ep); 250 251 if ((from_mdp = meta_get_unit(sp, from_np, ep)) == NULL) { 252 assert(!mdisok(ep)); 253 return (-1); 254 } 255 256 if (meta_get_unit(sp, to_np, ep) != NULL) { 257 if (mdisok(ep)) { 258 (void) mdmderror(ep, MDE_UNIT_ALREADY_SETUP, 259 meta_getminor(to_np->dev), 260 to_np->cname); 261 } 262 return (-1); 263 } 264 mdclrerror(ep); 265 266 /* If FORCE is not set, check if metadevice is open */ 267 if (!(flags & FORCE)) { 268 if (check_open(sp, from_np, ep) != 0) { 269 return (-1); 270 } 271 } 272 273 /* 274 * All checks are done, now we do the real work. 275 * If we are in dryrun mode, we're done. 276 */ 277 if (flags & DRYRUN) { 278 return (0); /* success */ 279 } 280 281 /* 282 * add key for new name to the namespace 283 */ 284 if ((cinfop = metagetcinfo(from_np, ep)) == NULL) { 285 assert(!mdisok(ep)); 286 return (-1); 287 } 288 289 if (metaislocalset(sp)) { 290 to_np->key = add_name(sp, MD_SIDEWILD, MD_KEYWILD, 291 cinfop->dname, meta_getminor(to_np->dev), to_np->bname, ep); 292 } else { 293 /* 294 * As this is not the local set we have to create a namespace 295 * record for each side (host) in the set. We cannot use 296 * add_key_names() because the destination device (to_np) 297 * should not exist and so the subsequent metagetcinfo() 298 * call will fail when it tries to open the device, so we 299 * have to use the information from the source device (from_np) 300 */ 301 if ((sd = metaget_setdesc(sp, ep)) == (md_set_desc *)NULL) { 302 return (-1); 303 } 304 to_np->key = MD_KEYWILD; 305 306 if (MD_MNSET_DESC(sd)) { 307 nd = sd->sd_nodelist; 308 while (nd) { 309 side_key = add_name(sp, (side_t)nd->nd_nodeid, 310 to_np->key, cinfop->dname, 311 meta_getminor(to_np->dev), 312 to_np->bname, ep); 313 /* 314 * Break out if failed to add the key, 315 * but delete any name space records that 316 * were added. 317 */ 318 if (side_key == MD_KEYBAD || 319 side_key == MD_KEYWILD) { 320 /* 321 * If we have a valid to_np->key then 322 * a record was added correctly but 323 * we do not know for which side, so 324 * we need to try to delete all of them. 325 */ 326 327 if (to_np->key != MD_KEYBAD && 328 to_np->key != MD_KEYWILD) { 329 nd_del = sd->sd_nodelist; 330 while ((nd_del != nd) && 331 (nd_del != NULL)) { 332 (void) del_name(sp, 333 (side_t)nd_del->nd_nodeid, 334 to_np->key, &dummy_ep); 335 nd_del = nd_del->nd_next; 336 } 337 /* preserve error key state */ 338 to_np->key = side_key; 339 } 340 break; 341 } 342 to_np->key = side_key; 343 nd = nd->nd_next; 344 } 345 } else { 346 for (i = 0; i < MD_MAXSIDES; i++) { 347 if (sd->sd_nodes[i][0] != '\0') { 348 side_key = add_name(sp, (side_t)i, 349 to_np->key, cinfop->dname, 350 meta_getminor(to_np->dev), 351 to_np->bname, ep); 352 /* 353 * Break out if failed to add the key, 354 * but delete any name space records 355 * that were added. 356 */ 357 if (side_key == MD_KEYBAD || 358 side_key == MD_KEYWILD) { 359 /* 360 * If we have a valid 361 * to_np->key then a record was 362 * added correctly but we do 363 * not know for which side, so 364 * we need to try to delete 365 * all of them. 366 */ 367 if (to_np->key != MD_KEYBAD && 368 to_np->key != MD_KEYWILD) { 369 for (j = 0; j < i; 370 j++) { 371 (void) del_name(sp, 372 (side_t)j, 373 to_np->key, 374 &dummy_ep); 375 } 376 /* 377 * preserve err 378 * key state 379 */ 380 to_np->key = side_key; 381 } 382 break; 383 } 384 to_np->key = side_key; 385 } 386 } 387 } 388 } 389 390 if (to_np->key == MD_KEYBAD || to_np->key == MD_KEYWILD) { 391 assert(!mdisok(ep)); 392 return (-1); 393 } 394 395 rc = meta_swap(sp, from_np, from_mdp, to_np, NULL, MDRNOP_RENAME, 396 flags, ep); 397 398 if (rc == 0) { 399 if (options & MDCMD_PRINT) { 400 (void) fprintf(stdout, dgettext(TEXT_DOMAIN, 401 "%s: has been renamed to %s\n"), 402 from_np->cname, to_np->cname); 403 } 404 } 405 406 return (rc); 407 } 408 409 /* 410 * return TRUE if current <from>, <to> ordering would 411 * prevent <from> from being in the role of <self> 412 */ 413 static bool_t 414 meta_exchange_need_to_flip( 415 md_common_t *from_mdp, 416 md_common_t *to_mdp 417 ) 418 { 419 assert(from_mdp); 420 assert(to_mdp); 421 422 /* 423 * ? 424 * \ 425 * <to> 426 * \ 427 * <from> 428 */ 429 430 if (MD_HAS_PARENT(from_mdp->parent)) { 431 if (MD_HAS_PARENT(to_mdp->parent)) { 432 if (from_mdp->parent == 433 meta_getminor(to_mdp->namep->dev)) { 434 return (TRUE); 435 } 436 } 437 } 438 439 /* 440 * <from> 441 * \ 442 * <to> 443 * \ 444 * ? 445 */ 446 447 if (MD_HAS_PARENT(to_mdp->parent)) { 448 if (to_mdp->capabilities & MD_CAN_META_CHILD) { 449 return (TRUE); 450 } 451 } 452 453 /* 454 * <to> 455 * \ 456 * <from> 457 */ 458 459 if (MD_HAS_PARENT(from_mdp->parent)) { 460 if (from_mdp->parent == meta_getminor(to_mdp->namep->dev)) { 461 if (!(from_mdp->capabilities & MD_CAN_META_CHILD)) { 462 return (TRUE); 463 } 464 } 465 } 466 467 /* 468 * <from> or <to> 469 * \ \ 470 * <to> <from> 471 * \ 472 * ? 473 */ 474 475 return (FALSE); 476 } 477 478 /* 479 * exchange the names of two metadevices 480 */ 481 int 482 meta_exchange( 483 mdsetname_t *sp, 484 mdname_t *from_np, 485 mdname_t *to_np, 486 mdcmdopts_t options, 487 md_error_t *ep 488 ) 489 { 490 int flags = (options & MDCMD_FORCE)? FORCE: 0; 491 md_common_t *from_mdp, *to_mdp; 492 int rc; 493 char *p, *p2; 494 495 /* must have a set */ 496 assert(sp != NULL); 497 assert(sp->setno == MD_MIN2SET(meta_getminor(from_np->dev))); 498 assert(sp->setno == MD_MIN2SET(meta_getminor(to_np->dev))); 499 500 if (metachkmeta(from_np, ep) != 0) { 501 assert(!mdisok(ep)); 502 return (-1); 503 } 504 505 if (metachkmeta(to_np, ep) != 0) { 506 assert(!mdisok(ep)); 507 return (-1); 508 } 509 510 if ((options & MDCMD_DOIT) == 0) { 511 flags |= DRYRUN; 512 } 513 514 if ((p = getenv("MD_DEBUG")) != NULL) { 515 if ((p2 = strstr(p, "EXCHANGE=")) != NULL) { 516 flags |= NOISY; 517 if ((p2 = strchr(p2, '=')) != NULL) { 518 if (strcmp((p2+1), "NOFLIP") == 0) { 519 flags |= NOFLIP; 520 } 521 } 522 } else if (strstr(p, "EXCHANGE") != NULL) { 523 flags |= NOISY; 524 } 525 } 526 527 if ((from_mdp = meta_get_unit(sp, from_np, ep)) == NULL) { 528 assert(!mdisok(ep)); 529 return (-1); 530 } 531 532 if ((to_mdp = meta_get_unit(sp, to_np, ep)) == NULL) { 533 assert(!mdisok(ep)); 534 return (-1); 535 } 536 assert(mdisok(ep)); 537 538 539 /* If FORCE is not set, check if metadevice is open */ 540 if (!(flags & FORCE)) { 541 if (check_open(sp, from_np, ep) != 0) { 542 return (-1); 543 } 544 } 545 546 /* 547 * All checks are done, now we do the real work. 548 * If we are in dryrun mode, we're done. 549 */ 550 if (flags & DRYRUN) { 551 return (0); /* success */ 552 } 553 554 /* 555 * NOFLIP is used only for debugging; the driver 556 * will catch this and return MDE_RENAME_ORDER, if necessary 557 */ 558 if (((flags & NOFLIP) == 0) && 559 meta_exchange_need_to_flip(from_mdp, to_mdp)) { 560 rc = meta_swap(sp, to_np, to_mdp, from_np, from_mdp, 561 MDRNOP_EXCHANGE, flags, ep); 562 563 } else { 564 rc = meta_swap(sp, from_np, from_mdp, to_np, to_mdp, 565 MDRNOP_EXCHANGE, flags, ep); 566 } 567 568 if (rc == 0) { 569 if (options & MDCMD_PRINT) { 570 (void) fprintf(stdout, dgettext(TEXT_DOMAIN, 571 "%s and %s have exchanged identities\n"), 572 from_np->cname, to_np->cname); 573 } 574 } 575 576 return (rc); 577 } 578