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