10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 23*253Sstevep * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * Just in case we're not in a build environment, make sure that 310Sstevel@tonic-gate * TEXT_DOMAIN gets set to something. 320Sstevel@tonic-gate */ 330Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 340Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 350Sstevel@tonic-gate #endif 360Sstevel@tonic-gate 370Sstevel@tonic-gate /* 380Sstevel@tonic-gate * change the identity of a metadevice 390Sstevel@tonic-gate * These are the "do it" functions for the metarename command. 400Sstevel@tonic-gate */ 410Sstevel@tonic-gate 420Sstevel@tonic-gate #include <string.h> 430Sstevel@tonic-gate #include <meta.h> 440Sstevel@tonic-gate #include <sys/lvm/md_rename.h> 450Sstevel@tonic-gate 460Sstevel@tonic-gate /* private */ 470Sstevel@tonic-gate #define FORCE (0x00000001) 480Sstevel@tonic-gate #define NOISY (0x00000010) 490Sstevel@tonic-gate #define NOFLIP (0x00000020) 500Sstevel@tonic-gate #define DRYRUN (0x00000040) 510Sstevel@tonic-gate 520Sstevel@tonic-gate #define OP_STR(op) \ 530Sstevel@tonic-gate ((op) == MDRNOP_EXCHANGE? "exchange": \ 540Sstevel@tonic-gate (op) == MDRNOP_RENAME? "rename": \ 550Sstevel@tonic-gate (op) == MDRNOP_UNK? "<unknown>": "garbage") 560Sstevel@tonic-gate 570Sstevel@tonic-gate 580Sstevel@tonic-gate /* 590Sstevel@tonic-gate * Check if from_np is open 600Sstevel@tonic-gate * Return 0 if not open, -1 if open 610Sstevel@tonic-gate */ 620Sstevel@tonic-gate static int 630Sstevel@tonic-gate check_open( 640Sstevel@tonic-gate mdsetname_t *sp, 650Sstevel@tonic-gate mdname_t *from_np, 660Sstevel@tonic-gate md_error_t *ep) 670Sstevel@tonic-gate { 680Sstevel@tonic-gate int rc; 690Sstevel@tonic-gate 700Sstevel@tonic-gate if ((rc = meta_isopen(sp, from_np, ep, (mdcmdopts_t)0)) < 0) { 710Sstevel@tonic-gate assert(!mdisok(ep)); 720Sstevel@tonic-gate return (-1); 730Sstevel@tonic-gate 740Sstevel@tonic-gate } else if (rc > 0) { 750Sstevel@tonic-gate if (mdisok(ep)) { 760Sstevel@tonic-gate (void) mdmderror(ep, MDE_RENAME_BUSY, 770Sstevel@tonic-gate meta_getminor(from_np->dev), 780Sstevel@tonic-gate from_np->cname); 790Sstevel@tonic-gate } 800Sstevel@tonic-gate return (-1); 810Sstevel@tonic-gate } 820Sstevel@tonic-gate return (0); 830Sstevel@tonic-gate } 840Sstevel@tonic-gate 850Sstevel@tonic-gate /* 860Sstevel@tonic-gate * meta_swap is the common code used by the 870Sstevel@tonic-gate * meta_rename() and meta_exchange() entry points 880Sstevel@tonic-gate */ 890Sstevel@tonic-gate 900Sstevel@tonic-gate static int 910Sstevel@tonic-gate meta_swap( 920Sstevel@tonic-gate mdsetname_t *sp, 930Sstevel@tonic-gate mdname_t *from_np, 94*253Sstevep md_common_t *from_mdp, 950Sstevel@tonic-gate mdname_t *to_np, 96*253Sstevep md_common_t *to_mdp, 970Sstevel@tonic-gate md_renop_t op, 980Sstevel@tonic-gate int flags, 990Sstevel@tonic-gate md_error_t *ep) 1000Sstevel@tonic-gate { 1010Sstevel@tonic-gate md_rename_t txn; 102*253Sstevep int from_add_flag = 0; 103*253Sstevep int to_add_flag = 0; 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate /* 1060Sstevel@tonic-gate * If the device exists a key may already exist so need to find it 1070Sstevel@tonic-gate * otherwise we'll end up adding the key in again which will lead 1080Sstevel@tonic-gate * to an inconsistent n_count for the namespace record. 1090Sstevel@tonic-gate */ 1100Sstevel@tonic-gate if (from_np->dev != NODEV) { 1110Sstevel@tonic-gate (void) meta_getnmentbydev(sp->setno, MD_SIDEWILD, from_np->dev, 1120Sstevel@tonic-gate NULL, NULL, &from_np->key, ep); 1130Sstevel@tonic-gate } 1140Sstevel@tonic-gate 115*253Sstevep if (to_np->dev != NODEV) { 116*253Sstevep (void) meta_getnmentbydev(sp->setno, MD_SIDEWILD, to_np->dev, 117*253Sstevep NULL, NULL, &to_np->key, ep); 118*253Sstevep } 119*253Sstevep 1200Sstevel@tonic-gate if ((from_np->key == MD_KEYWILD) || (from_np->key == MD_KEYBAD)) { 121*253Sstevep /* 122*253Sstevep * If from does not have key and it is a component device 123*253Sstevep * then something really goes wrong 124*253Sstevep */ 125*253Sstevep assert(!MD_HAS_PARENT(from_mdp->parent)); 126*253Sstevep 127*253Sstevep /* 128*253Sstevep * So only add the entry if from is a top device 129*253Sstevep */ 1300Sstevel@tonic-gate if (add_key_name(sp, from_np, NULL, ep) != 0) { 1310Sstevel@tonic-gate assert(!mdisok(ep)); 1320Sstevel@tonic-gate return (-1); 133*253Sstevep } else { 134*253Sstevep from_add_flag = 1; 1350Sstevel@tonic-gate } 1360Sstevel@tonic-gate } 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate (void) memset(&txn, 0, sizeof (txn)); 1390Sstevel@tonic-gate 1400Sstevel@tonic-gate txn.op = op; 1410Sstevel@tonic-gate txn.revision = MD_RENAME_VERSION; 1420Sstevel@tonic-gate txn.flags = 0; 1430Sstevel@tonic-gate txn.from.mnum = meta_getminor(from_np->dev); 1440Sstevel@tonic-gate txn.from.key = from_np->key; 1450Sstevel@tonic-gate 146*253Sstevep if ((to_np->key == MD_KEYWILD) || (to_np->key == MD_KEYBAD)) { 147*253Sstevep /* 148*253Sstevep * If to does not have key and is not a top device 149*253Sstevep * then something really goes wrong 150*253Sstevep */ 151*253Sstevep assert(!MD_HAS_PARENT(to_mdp->parent)); 1520Sstevel@tonic-gate 153*253Sstevep /* 154*253Sstevep * Add entry 155*253Sstevep */ 1560Sstevel@tonic-gate if (add_key_name(sp, to_np, NULL, ep) != 0) { 1570Sstevel@tonic-gate assert(!mdisok(ep)); 158*253Sstevep if (from_add_flag) 159*253Sstevep (void) del_key_name(sp, from_np, ep); 1600Sstevel@tonic-gate return (-1); 161*253Sstevep } else { 162*253Sstevep to_add_flag = 1; 1630Sstevel@tonic-gate } 1640Sstevel@tonic-gate } 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate txn.to.mnum = meta_getminor(to_np->dev); 1670Sstevel@tonic-gate txn.to.key = to_np->key; 1680Sstevel@tonic-gate 1690Sstevel@tonic-gate if (flags & NOISY) { 1700Sstevel@tonic-gate (void) fprintf(stderr, "\top: %s\n", OP_STR(txn.op)); 1710Sstevel@tonic-gate (void) fprintf(stderr, "\trevision: %d, flags: %d\n", 1720Sstevel@tonic-gate txn.revision, txn.flags); 1730Sstevel@tonic-gate (void) fprintf(stderr, 1740Sstevel@tonic-gate "\tfrom(mnum,key): %ld, %d\tto: %ld, %d\n", 1750Sstevel@tonic-gate txn.from.mnum, txn.from.key, 1760Sstevel@tonic-gate txn.to.mnum, txn.to.key); 1770Sstevel@tonic-gate } 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate mdclrerror(ep); 1800Sstevel@tonic-gate if (metaioctl(MD_IOCRENAME, &txn, &txn.mde, from_np->cname) != 0) { 181*253Sstevep if (from_add_flag) { 182*253Sstevep (void) del_key_name(sp, from_np, ep); 183*253Sstevep } 184*253Sstevep 185*253Sstevep if (op == MDRNOP_RENAME || to_add_flag) { 186*253Sstevep (void) del_key_name(sp, to_np, ep); 187*253Sstevep } 188*253Sstevep return (mdstealerror(ep, &txn.mde)); 189*253Sstevep } 190*253Sstevep 191*253Sstevep /* 192*253Sstevep * If top device 193*253Sstevep */ 194*253Sstevep if (op == MDRNOP_RENAME && !MD_HAS_PARENT(from_mdp->parent)) { 1950Sstevel@tonic-gate (void) del_key_name(sp, to_np, ep); 1960Sstevel@tonic-gate } 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate /* force the name cache to re-read device state */ 1990Sstevel@tonic-gate meta_invalidate_name(from_np); 2000Sstevel@tonic-gate meta_invalidate_name(to_np); 2010Sstevel@tonic-gate 2020Sstevel@tonic-gate return (0); 2030Sstevel@tonic-gate } 2040Sstevel@tonic-gate 2050Sstevel@tonic-gate /* 2060Sstevel@tonic-gate * rename a metadevice 2070Sstevel@tonic-gate */ 2080Sstevel@tonic-gate int 2090Sstevel@tonic-gate meta_rename( 2100Sstevel@tonic-gate mdsetname_t *sp, 2110Sstevel@tonic-gate mdname_t *from_np, 2120Sstevel@tonic-gate mdname_t *to_np, 2130Sstevel@tonic-gate mdcmdopts_t options, 2140Sstevel@tonic-gate md_error_t *ep 2150Sstevel@tonic-gate ) 2160Sstevel@tonic-gate { 2170Sstevel@tonic-gate int flags = (options & MDCMD_FORCE)? FORCE: 0; 2180Sstevel@tonic-gate int rc = 0; 2190Sstevel@tonic-gate mdcinfo_t *cinfop; 2200Sstevel@tonic-gate char *p; 2210Sstevel@tonic-gate md_set_desc *sd; 2220Sstevel@tonic-gate mdkey_t side_key = MD_KEYWILD; 2230Sstevel@tonic-gate md_error_t dummy_ep = mdnullerror; 2240Sstevel@tonic-gate int i, j; 2250Sstevel@tonic-gate md_mnnode_desc *nd, *nd_del; 226*253Sstevep md_common_t *from_mdp; 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate /* must have a set */ 2290Sstevel@tonic-gate assert(sp != NULL); 2300Sstevel@tonic-gate assert(sp->setno == MD_MIN2SET(meta_getminor(from_np->dev))); 2310Sstevel@tonic-gate 2320Sstevel@tonic-gate mdclrerror(ep); 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate if (((p = getenv("MD_DEBUG")) != NULL) && 2350Sstevel@tonic-gate (strstr(p, "RENAME") != NULL)) { 2360Sstevel@tonic-gate flags |= NOISY; 2370Sstevel@tonic-gate } 2380Sstevel@tonic-gate /* if DOIT is not set, we are in dryrun mode */ 2390Sstevel@tonic-gate if ((options & MDCMD_DOIT) == 0) { 2400Sstevel@tonic-gate flags |= DRYRUN; 2410Sstevel@tonic-gate } 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate 2440Sstevel@tonic-gate if (metachkmeta(from_np, ep) != 0) { 2450Sstevel@tonic-gate assert(!mdisok(ep)); 2460Sstevel@tonic-gate return (-1); 2470Sstevel@tonic-gate } 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate mdclrerror(ep); 2500Sstevel@tonic-gate 251*253Sstevep if ((from_mdp = meta_get_unit(sp, from_np, ep)) == NULL) { 2520Sstevel@tonic-gate assert(!mdisok(ep)); 2530Sstevel@tonic-gate return (-1); 2540Sstevel@tonic-gate } 2550Sstevel@tonic-gate 256*253Sstevep if (meta_get_unit(sp, to_np, ep) != NULL) { 2570Sstevel@tonic-gate if (mdisok(ep)) { 2580Sstevel@tonic-gate (void) mdmderror(ep, MDE_UNIT_ALREADY_SETUP, 2590Sstevel@tonic-gate meta_getminor(to_np->dev), 2600Sstevel@tonic-gate to_np->cname); 2610Sstevel@tonic-gate } 2620Sstevel@tonic-gate return (-1); 2630Sstevel@tonic-gate } 2640Sstevel@tonic-gate mdclrerror(ep); 2650Sstevel@tonic-gate 2660Sstevel@tonic-gate /* If FORCE is not set, check if metadevice is open */ 2670Sstevel@tonic-gate if (!(flags & FORCE)) { 2680Sstevel@tonic-gate if (check_open(sp, from_np, ep) != 0) { 2690Sstevel@tonic-gate return (-1); 2700Sstevel@tonic-gate } 2710Sstevel@tonic-gate } 2720Sstevel@tonic-gate 2730Sstevel@tonic-gate /* 2740Sstevel@tonic-gate * All checks are done, now we do the real work. 2750Sstevel@tonic-gate * If we are in dryrun mode, we're done. 2760Sstevel@tonic-gate */ 2770Sstevel@tonic-gate if (flags & DRYRUN) { 2780Sstevel@tonic-gate return (0); /* success */ 2790Sstevel@tonic-gate } 2800Sstevel@tonic-gate 2810Sstevel@tonic-gate /* 2820Sstevel@tonic-gate * add key for new name to the namespace 2830Sstevel@tonic-gate */ 2840Sstevel@tonic-gate if ((cinfop = metagetcinfo(from_np, ep)) == NULL) { 2850Sstevel@tonic-gate assert(!mdisok(ep)); 2860Sstevel@tonic-gate return (-1); 2870Sstevel@tonic-gate } 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate if (metaislocalset(sp)) { 2900Sstevel@tonic-gate to_np->key = add_name(sp, MD_SIDEWILD, MD_KEYWILD, 2910Sstevel@tonic-gate cinfop->dname, meta_getminor(to_np->dev), to_np->bname, ep); 2920Sstevel@tonic-gate } else { 2930Sstevel@tonic-gate /* 2940Sstevel@tonic-gate * As this is not the local set we have to create a namespace 2950Sstevel@tonic-gate * record for each side (host) in the set. We cannot use 2960Sstevel@tonic-gate * add_key_names() because the destination device (to_np) 2970Sstevel@tonic-gate * should not exist and so the subsequent metagetcinfo() 2980Sstevel@tonic-gate * call will fail when it tries to open the device, so we 2990Sstevel@tonic-gate * have to use the information from the source device (from_np) 3000Sstevel@tonic-gate */ 3010Sstevel@tonic-gate if ((sd = metaget_setdesc(sp, ep)) == (md_set_desc *)NULL) { 3020Sstevel@tonic-gate return (-1); 3030Sstevel@tonic-gate } 3040Sstevel@tonic-gate to_np->key = MD_KEYWILD; 3050Sstevel@tonic-gate 3060Sstevel@tonic-gate if (MD_MNSET_DESC(sd)) { 3070Sstevel@tonic-gate nd = sd->sd_nodelist; 3080Sstevel@tonic-gate while (nd) { 3090Sstevel@tonic-gate side_key = add_name(sp, (side_t)nd->nd_nodeid, 3100Sstevel@tonic-gate to_np->key, cinfop->dname, 3110Sstevel@tonic-gate meta_getminor(to_np->dev), 3120Sstevel@tonic-gate to_np->bname, ep); 3130Sstevel@tonic-gate /* 3140Sstevel@tonic-gate * Break out if failed to add the key, 3150Sstevel@tonic-gate * but delete any name space records that 3160Sstevel@tonic-gate * were added. 3170Sstevel@tonic-gate */ 3180Sstevel@tonic-gate if (side_key == MD_KEYBAD || 3190Sstevel@tonic-gate side_key == MD_KEYWILD) { 3200Sstevel@tonic-gate /* 3210Sstevel@tonic-gate * If we have a valid to_np->key then 3220Sstevel@tonic-gate * a record was added correctly but 3230Sstevel@tonic-gate * we do not know for which side, so 3240Sstevel@tonic-gate * we need to try to delete all of them. 3250Sstevel@tonic-gate */ 3260Sstevel@tonic-gate 3270Sstevel@tonic-gate if (to_np->key != MD_KEYBAD && 3280Sstevel@tonic-gate to_np->key != MD_KEYWILD) { 3290Sstevel@tonic-gate nd_del = sd->sd_nodelist; 3300Sstevel@tonic-gate while ((nd_del != nd) && 3310Sstevel@tonic-gate (nd_del != NULL)) { 3320Sstevel@tonic-gate (void) del_name(sp, 3330Sstevel@tonic-gate (side_t)nd_del->nd_nodeid, 3340Sstevel@tonic-gate to_np->key, &dummy_ep); 3350Sstevel@tonic-gate nd_del = nd_del->nd_next; 3360Sstevel@tonic-gate } 3370Sstevel@tonic-gate /* preserve error key state */ 3380Sstevel@tonic-gate to_np->key = side_key; 3390Sstevel@tonic-gate } 3400Sstevel@tonic-gate break; 3410Sstevel@tonic-gate } 3420Sstevel@tonic-gate to_np->key = side_key; 3430Sstevel@tonic-gate nd = nd->nd_next; 3440Sstevel@tonic-gate } 3450Sstevel@tonic-gate } else { 3460Sstevel@tonic-gate for (i = 0; i < MD_MAXSIDES; i++) { 3470Sstevel@tonic-gate if (sd->sd_nodes[i][0] != '\0') { 3480Sstevel@tonic-gate side_key = add_name(sp, (side_t)i, 3490Sstevel@tonic-gate to_np->key, cinfop->dname, 3500Sstevel@tonic-gate meta_getminor(to_np->dev), 3510Sstevel@tonic-gate to_np->bname, ep); 3520Sstevel@tonic-gate /* 3530Sstevel@tonic-gate * Break out if failed to add the key, 3540Sstevel@tonic-gate * but delete any name space records 3550Sstevel@tonic-gate * that were added. 3560Sstevel@tonic-gate */ 3570Sstevel@tonic-gate if (side_key == MD_KEYBAD || 3580Sstevel@tonic-gate side_key == MD_KEYWILD) { 3590Sstevel@tonic-gate /* 3600Sstevel@tonic-gate * If we have a valid 3610Sstevel@tonic-gate * to_np->key then a record was 3620Sstevel@tonic-gate * added correctly but we do 3630Sstevel@tonic-gate * not know for which side, so 3640Sstevel@tonic-gate * we need to try to delete 3650Sstevel@tonic-gate * all of them. 3660Sstevel@tonic-gate */ 3670Sstevel@tonic-gate if (to_np->key != MD_KEYBAD && 3680Sstevel@tonic-gate to_np->key != MD_KEYWILD) { 3690Sstevel@tonic-gate for (j = 0; j < i; 3700Sstevel@tonic-gate j++) { 3710Sstevel@tonic-gate (void) del_name(sp, 3720Sstevel@tonic-gate (side_t)j, 3730Sstevel@tonic-gate to_np->key, 3740Sstevel@tonic-gate &dummy_ep); 3750Sstevel@tonic-gate } 3760Sstevel@tonic-gate /* 3770Sstevel@tonic-gate * preserve err 3780Sstevel@tonic-gate * key state 3790Sstevel@tonic-gate */ 3800Sstevel@tonic-gate to_np->key = side_key; 3810Sstevel@tonic-gate } 3820Sstevel@tonic-gate break; 3830Sstevel@tonic-gate } 3840Sstevel@tonic-gate to_np->key = side_key; 3850Sstevel@tonic-gate } 3860Sstevel@tonic-gate } 3870Sstevel@tonic-gate } 3880Sstevel@tonic-gate } 3890Sstevel@tonic-gate 3900Sstevel@tonic-gate if (to_np->key == MD_KEYBAD || to_np->key == MD_KEYWILD) { 3910Sstevel@tonic-gate assert(!mdisok(ep)); 3920Sstevel@tonic-gate return (-1); 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate 395*253Sstevep rc = meta_swap(sp, from_np, from_mdp, to_np, NULL, MDRNOP_RENAME, 396*253Sstevep flags, ep); 3970Sstevel@tonic-gate 3980Sstevel@tonic-gate if (rc == 0) { 3990Sstevel@tonic-gate if (options & MDCMD_PRINT) { 4000Sstevel@tonic-gate (void) fprintf(stdout, dgettext(TEXT_DOMAIN, 4010Sstevel@tonic-gate "%s: has been renamed to %s\n"), 4020Sstevel@tonic-gate from_np->cname, to_np->cname); 4030Sstevel@tonic-gate } 4040Sstevel@tonic-gate } 4050Sstevel@tonic-gate 4060Sstevel@tonic-gate return (rc); 4070Sstevel@tonic-gate } 4080Sstevel@tonic-gate 4090Sstevel@tonic-gate /* 4100Sstevel@tonic-gate * return TRUE if current <from>, <to> ordering would 4110Sstevel@tonic-gate * prevent <from> from being in the role of <self> 4120Sstevel@tonic-gate */ 4130Sstevel@tonic-gate static bool_t 4140Sstevel@tonic-gate meta_exchange_need_to_flip( 4150Sstevel@tonic-gate md_common_t *from_mdp, 4160Sstevel@tonic-gate md_common_t *to_mdp 4170Sstevel@tonic-gate ) 4180Sstevel@tonic-gate { 4190Sstevel@tonic-gate assert(from_mdp); 4200Sstevel@tonic-gate assert(to_mdp); 4210Sstevel@tonic-gate 4220Sstevel@tonic-gate /* 4230Sstevel@tonic-gate * ? 4240Sstevel@tonic-gate * \ 4250Sstevel@tonic-gate * <to> 4260Sstevel@tonic-gate * \ 4270Sstevel@tonic-gate * <from> 4280Sstevel@tonic-gate */ 4290Sstevel@tonic-gate 4300Sstevel@tonic-gate if (MD_HAS_PARENT(from_mdp->parent)) { 4310Sstevel@tonic-gate if (MD_HAS_PARENT(to_mdp->parent)) { 4320Sstevel@tonic-gate if (from_mdp->parent == 4330Sstevel@tonic-gate meta_getminor(to_mdp->namep->dev)) { 4340Sstevel@tonic-gate return (TRUE); 4350Sstevel@tonic-gate } 4360Sstevel@tonic-gate } 4370Sstevel@tonic-gate } 4380Sstevel@tonic-gate 4390Sstevel@tonic-gate /* 4400Sstevel@tonic-gate * <from> 4410Sstevel@tonic-gate * \ 4420Sstevel@tonic-gate * <to> 4430Sstevel@tonic-gate * \ 4440Sstevel@tonic-gate * ? 4450Sstevel@tonic-gate */ 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate if (MD_HAS_PARENT(to_mdp->parent)) { 4480Sstevel@tonic-gate if (to_mdp->capabilities & MD_CAN_META_CHILD) { 4490Sstevel@tonic-gate return (TRUE); 4500Sstevel@tonic-gate } 4510Sstevel@tonic-gate } 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate /* 4540Sstevel@tonic-gate * <to> 4550Sstevel@tonic-gate * \ 4560Sstevel@tonic-gate * <from> 4570Sstevel@tonic-gate */ 4580Sstevel@tonic-gate 4590Sstevel@tonic-gate if (MD_HAS_PARENT(from_mdp->parent)) { 4600Sstevel@tonic-gate if (from_mdp->parent == meta_getminor(to_mdp->namep->dev)) { 4610Sstevel@tonic-gate if (!(from_mdp->capabilities & MD_CAN_META_CHILD)) { 4620Sstevel@tonic-gate return (TRUE); 4630Sstevel@tonic-gate } 4640Sstevel@tonic-gate } 4650Sstevel@tonic-gate } 4660Sstevel@tonic-gate 4670Sstevel@tonic-gate /* 4680Sstevel@tonic-gate * <from> or <to> 4690Sstevel@tonic-gate * \ \ 4700Sstevel@tonic-gate * <to> <from> 4710Sstevel@tonic-gate * \ 4720Sstevel@tonic-gate * ? 4730Sstevel@tonic-gate */ 4740Sstevel@tonic-gate 4750Sstevel@tonic-gate return (FALSE); 4760Sstevel@tonic-gate } 4770Sstevel@tonic-gate 4780Sstevel@tonic-gate /* 4790Sstevel@tonic-gate * exchange the names of two metadevices 4800Sstevel@tonic-gate */ 4810Sstevel@tonic-gate int 4820Sstevel@tonic-gate meta_exchange( 4830Sstevel@tonic-gate mdsetname_t *sp, 4840Sstevel@tonic-gate mdname_t *from_np, 4850Sstevel@tonic-gate mdname_t *to_np, 4860Sstevel@tonic-gate mdcmdopts_t options, 4870Sstevel@tonic-gate md_error_t *ep 4880Sstevel@tonic-gate ) 4890Sstevel@tonic-gate { 4900Sstevel@tonic-gate int flags = (options & MDCMD_FORCE)? FORCE: 0; 4910Sstevel@tonic-gate md_common_t *from_mdp, *to_mdp; 4920Sstevel@tonic-gate int rc; 4930Sstevel@tonic-gate char *p, *p2; 4940Sstevel@tonic-gate 4950Sstevel@tonic-gate /* must have a set */ 4960Sstevel@tonic-gate assert(sp != NULL); 4970Sstevel@tonic-gate assert(sp->setno == MD_MIN2SET(meta_getminor(from_np->dev))); 4980Sstevel@tonic-gate assert(sp->setno == MD_MIN2SET(meta_getminor(to_np->dev))); 4990Sstevel@tonic-gate 5000Sstevel@tonic-gate if (metachkmeta(from_np, ep) != 0) { 5010Sstevel@tonic-gate assert(!mdisok(ep)); 5020Sstevel@tonic-gate return (-1); 5030Sstevel@tonic-gate } 5040Sstevel@tonic-gate 5050Sstevel@tonic-gate if (metachkmeta(to_np, ep) != 0) { 5060Sstevel@tonic-gate assert(!mdisok(ep)); 5070Sstevel@tonic-gate return (-1); 5080Sstevel@tonic-gate } 5090Sstevel@tonic-gate 5100Sstevel@tonic-gate if ((options & MDCMD_DOIT) == 0) { 5110Sstevel@tonic-gate flags |= DRYRUN; 5120Sstevel@tonic-gate } 5130Sstevel@tonic-gate 5140Sstevel@tonic-gate if ((p = getenv("MD_DEBUG")) != NULL) { 5150Sstevel@tonic-gate if ((p2 = strstr(p, "EXCHANGE=")) != NULL) { 5160Sstevel@tonic-gate flags |= NOISY; 5170Sstevel@tonic-gate if ((p2 = strchr(p2, '=')) != NULL) { 5180Sstevel@tonic-gate if (strcmp((p2+1), "NOFLIP") == 0) { 5190Sstevel@tonic-gate flags |= NOFLIP; 5200Sstevel@tonic-gate } 5210Sstevel@tonic-gate } 5220Sstevel@tonic-gate } else if (strstr(p, "EXCHANGE") != NULL) { 5230Sstevel@tonic-gate flags |= NOISY; 5240Sstevel@tonic-gate } 5250Sstevel@tonic-gate } 5260Sstevel@tonic-gate 5270Sstevel@tonic-gate if ((from_mdp = meta_get_unit(sp, from_np, ep)) == NULL) { 5280Sstevel@tonic-gate assert(!mdisok(ep)); 5290Sstevel@tonic-gate return (-1); 5300Sstevel@tonic-gate } 5310Sstevel@tonic-gate 5320Sstevel@tonic-gate if ((to_mdp = meta_get_unit(sp, to_np, ep)) == NULL) { 5330Sstevel@tonic-gate assert(!mdisok(ep)); 5340Sstevel@tonic-gate return (-1); 5350Sstevel@tonic-gate } 5360Sstevel@tonic-gate assert(mdisok(ep)); 5370Sstevel@tonic-gate 538*253Sstevep 5390Sstevel@tonic-gate /* If FORCE is not set, check if metadevice is open */ 5400Sstevel@tonic-gate if (!(flags & FORCE)) { 5410Sstevel@tonic-gate if (check_open(sp, from_np, ep) != 0) { 5420Sstevel@tonic-gate return (-1); 5430Sstevel@tonic-gate } 5440Sstevel@tonic-gate } 5450Sstevel@tonic-gate 5460Sstevel@tonic-gate /* 5470Sstevel@tonic-gate * All checks are done, now we do the real work. 5480Sstevel@tonic-gate * If we are in dryrun mode, we're done. 5490Sstevel@tonic-gate */ 5500Sstevel@tonic-gate if (flags & DRYRUN) { 5510Sstevel@tonic-gate return (0); /* success */ 5520Sstevel@tonic-gate } 5530Sstevel@tonic-gate 5540Sstevel@tonic-gate /* 5550Sstevel@tonic-gate * NOFLIP is used only for debugging; the driver 5560Sstevel@tonic-gate * will catch this and return MDE_RENAME_ORDER, if necessary 5570Sstevel@tonic-gate */ 5580Sstevel@tonic-gate if (((flags & NOFLIP) == 0) && 5590Sstevel@tonic-gate meta_exchange_need_to_flip(from_mdp, to_mdp)) { 560*253Sstevep rc = meta_swap(sp, to_np, to_mdp, from_np, from_mdp, 561*253Sstevep MDRNOP_EXCHANGE, flags, ep); 5620Sstevel@tonic-gate 5630Sstevel@tonic-gate } else { 564*253Sstevep rc = meta_swap(sp, from_np, from_mdp, to_np, to_mdp, 565*253Sstevep MDRNOP_EXCHANGE, flags, ep); 5660Sstevel@tonic-gate } 5670Sstevel@tonic-gate 5680Sstevel@tonic-gate if (rc == 0) { 5690Sstevel@tonic-gate if (options & MDCMD_PRINT) { 5700Sstevel@tonic-gate (void) fprintf(stdout, dgettext(TEXT_DOMAIN, 5710Sstevel@tonic-gate "%s and %s have exchanged identities\n"), 5720Sstevel@tonic-gate from_np->cname, to_np->cname); 5730Sstevel@tonic-gate } 5740Sstevel@tonic-gate } 5750Sstevel@tonic-gate 5760Sstevel@tonic-gate return (rc); 5770Sstevel@tonic-gate } 578