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