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