xref: /onnv-gate/usr/src/lib/lvm/libmeta/common/meta_rename.c (revision 2291:e439a051d5af)
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
5*1623Stw21770  * Common Development and Distribution License (the "License").
6*1623Stw21770  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*1623Stw21770  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * Just in case we're not in a build environment, make sure that
300Sstevel@tonic-gate  * TEXT_DOMAIN gets set to something.
310Sstevel@tonic-gate  */
320Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
330Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
340Sstevel@tonic-gate #endif
350Sstevel@tonic-gate 
360Sstevel@tonic-gate /*
370Sstevel@tonic-gate  * change the identity of a metadevice
380Sstevel@tonic-gate  * These are the "do it" functions for the metarename command.
390Sstevel@tonic-gate  */
400Sstevel@tonic-gate 
410Sstevel@tonic-gate #include <string.h>
420Sstevel@tonic-gate #include <meta.h>
430Sstevel@tonic-gate #include <sys/lvm/md_rename.h>
440Sstevel@tonic-gate 
450Sstevel@tonic-gate /* private */
460Sstevel@tonic-gate #define	FORCE	(0x00000001)
470Sstevel@tonic-gate #define	NOISY	(0x00000010)
480Sstevel@tonic-gate #define	NOFLIP	(0x00000020)
490Sstevel@tonic-gate #define	DRYRUN	(0x00000040)
500Sstevel@tonic-gate 
510Sstevel@tonic-gate #define	OP_STR(op)						\
520Sstevel@tonic-gate 	((op) == MDRNOP_EXCHANGE?	"exchange":		\
530Sstevel@tonic-gate 	    (op) == MDRNOP_RENAME?	"rename":		\
540Sstevel@tonic-gate 	    (op) == MDRNOP_UNK?		"<unknown>": "garbage")
550Sstevel@tonic-gate 
560Sstevel@tonic-gate 
570Sstevel@tonic-gate /*
580Sstevel@tonic-gate  * Check if from_np is open
590Sstevel@tonic-gate  * Return 0 if not open, -1 if open
600Sstevel@tonic-gate  */
610Sstevel@tonic-gate static int
check_open(mdsetname_t * sp,mdname_t * from_np,md_error_t * ep)620Sstevel@tonic-gate check_open(
630Sstevel@tonic-gate 	mdsetname_t	*sp,
640Sstevel@tonic-gate 	mdname_t	*from_np,
650Sstevel@tonic-gate 	md_error_t	*ep)
660Sstevel@tonic-gate {
670Sstevel@tonic-gate 	int		rc;
680Sstevel@tonic-gate 
690Sstevel@tonic-gate 	if ((rc = meta_isopen(sp, from_np, ep, (mdcmdopts_t)0)) < 0) {
700Sstevel@tonic-gate 		assert(!mdisok(ep));
710Sstevel@tonic-gate 		return (-1);
720Sstevel@tonic-gate 
730Sstevel@tonic-gate 	} else if (rc > 0) {
740Sstevel@tonic-gate 		if (mdisok(ep)) {
750Sstevel@tonic-gate 			(void) mdmderror(ep, MDE_RENAME_BUSY,
760Sstevel@tonic-gate 				meta_getminor(from_np->dev),
770Sstevel@tonic-gate 				from_np->cname);
780Sstevel@tonic-gate 		}
790Sstevel@tonic-gate 		return (-1);
800Sstevel@tonic-gate 	}
810Sstevel@tonic-gate 	return (0);
820Sstevel@tonic-gate }
830Sstevel@tonic-gate 
840Sstevel@tonic-gate /*
850Sstevel@tonic-gate  * meta_swap is the common code used by the
860Sstevel@tonic-gate  * meta_rename() and meta_exchange() entry points
870Sstevel@tonic-gate  */
880Sstevel@tonic-gate 
890Sstevel@tonic-gate static int
meta_swap(mdsetname_t * sp,mdname_t * from_np,md_common_t * from_mdp,mdname_t * to_np,md_common_t * to_mdp,md_renop_t op,int flags,md_error_t * ep)900Sstevel@tonic-gate meta_swap(
910Sstevel@tonic-gate 	mdsetname_t	*sp,
920Sstevel@tonic-gate 	mdname_t	*from_np,
93253Sstevep 	md_common_t	*from_mdp,
940Sstevel@tonic-gate 	mdname_t	*to_np,
95253Sstevep 	md_common_t	*to_mdp,
960Sstevel@tonic-gate 	md_renop_t	op,
970Sstevel@tonic-gate 	int		flags,
980Sstevel@tonic-gate 	md_error_t	*ep)
990Sstevel@tonic-gate {
1000Sstevel@tonic-gate 	md_rename_t	txn;
101253Sstevep 	int		from_add_flag = 0;
102253Sstevep 	int		to_add_flag = 0;
103*1623Stw21770 	int		from_is_fn, to_is_fn;
104*1623Stw21770 	bool_t		from_has_parent, to_has_parent;
105*1623Stw21770 
106*1623Stw21770 	/*
107*1623Stw21770 	 * What types of devices we have here?
108*1623Stw21770 	 * For MDRNOP_RENAME to_mdp is NULL
109*1623Stw21770 	 */
110*1623Stw21770 	from_is_fn = (from_mdp->revision & MD_FN_META_DEV);
111*1623Stw21770 	from_has_parent = MD_HAS_PARENT(from_mdp->parent);
112*1623Stw21770 	if (to_mdp) {
113*1623Stw21770 		to_is_fn = (to_mdp->revision & MD_FN_META_DEV);
114*1623Stw21770 		to_has_parent = MD_HAS_PARENT(to_mdp->parent);
115*1623Stw21770 	}
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate 	/*
1180Sstevel@tonic-gate 	 * If the device exists a key may already exist so need to find it
1190Sstevel@tonic-gate 	 * otherwise we'll end up adding the key in again which will lead
1200Sstevel@tonic-gate 	 * to an inconsistent n_count for the namespace record.
1210Sstevel@tonic-gate 	 */
1220Sstevel@tonic-gate 	if (from_np->dev != NODEV) {
1230Sstevel@tonic-gate 		(void) meta_getnmentbydev(sp->setno, MD_SIDEWILD, from_np->dev,
1240Sstevel@tonic-gate 		    NULL, NULL, &from_np->key, ep);
1250Sstevel@tonic-gate 	}
1260Sstevel@tonic-gate 
127253Sstevep 	if (to_np->dev != NODEV) {
128253Sstevep 		(void) meta_getnmentbydev(sp->setno, MD_SIDEWILD, to_np->dev,
129253Sstevep 		    NULL, NULL, &to_np->key, ep);
130253Sstevep 	}
131253Sstevep 
1320Sstevel@tonic-gate 	if ((from_np->key == MD_KEYWILD) || (from_np->key == MD_KEYBAD)) {
133253Sstevep 		/*
134*1623Stw21770 		 * If we are top and revision indicates that we
135*1623Stw21770 		 * should have key but we don't then something
136*1623Stw21770 		 * really goes wrong
137253Sstevep 		 */
138*1623Stw21770 		assert(!from_has_parent && !from_is_fn);
139*1623Stw21770 
140*1623Stw21770 		if (from_has_parent || from_is_fn) {
141*1623Stw21770 			return (-1);
142*1623Stw21770 		}
143253Sstevep 
144253Sstevep 		/*
145*1623Stw21770 		 * So only add the entry if necessary
146253Sstevep 		 */
1470Sstevel@tonic-gate 		if (add_key_name(sp, from_np, NULL, ep) != 0) {
1480Sstevel@tonic-gate 			assert(!mdisok(ep));
1490Sstevel@tonic-gate 			return (-1);
150253Sstevep 		} else {
151253Sstevep 			from_add_flag = 1;
1520Sstevel@tonic-gate 		}
1530Sstevel@tonic-gate 	}
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	(void) memset(&txn, 0, sizeof (txn));
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate 	txn.op		= op;
1580Sstevel@tonic-gate 	txn.revision	= MD_RENAME_VERSION;
1590Sstevel@tonic-gate 	txn.flags	= 0;
1600Sstevel@tonic-gate 	txn.from.mnum	= meta_getminor(from_np->dev);
1610Sstevel@tonic-gate 	txn.from.key	= from_np->key;
1620Sstevel@tonic-gate 
163253Sstevep 	if ((to_np->key == MD_KEYWILD) || (to_np->key == MD_KEYBAD)) {
164253Sstevep 		/*
165*1623Stw21770 		 * If we are top and revision indicates that we
166*1623Stw21770 		 * should have key but we don't then something
167*1623Stw21770 		 * really goes wrong
168253Sstevep 		 */
169*1623Stw21770 		assert(!to_has_parent && !to_is_fn);
170*1623Stw21770 
171*1623Stw21770 		if (to_has_parent || to_is_fn) {
172*1623Stw21770 			return (-1);
173*1623Stw21770 		}
1740Sstevel@tonic-gate 
175253Sstevep 		/*
176*1623Stw21770 		 * So only add the entry if necessary
177253Sstevep 		 */
1780Sstevel@tonic-gate 		if (add_key_name(sp, to_np, NULL, ep) != 0) {
1790Sstevel@tonic-gate 			assert(!mdisok(ep));
180253Sstevep 			if (from_add_flag)
181253Sstevep 				(void) del_key_name(sp, from_np, ep);
1820Sstevel@tonic-gate 			return (-1);
183253Sstevep 		} else {
184253Sstevep 			to_add_flag = 1;
1850Sstevel@tonic-gate 		}
1860Sstevel@tonic-gate 	}
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate 	txn.to.mnum	= meta_getminor(to_np->dev);
1890Sstevel@tonic-gate 	txn.to.key	= to_np->key;
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 	if (flags & NOISY) {
1920Sstevel@tonic-gate 		(void) fprintf(stderr, "\top: %s\n", OP_STR(txn.op));
1930Sstevel@tonic-gate 		(void) fprintf(stderr, "\trevision: %d, flags: %d\n",
1940Sstevel@tonic-gate 				txn.revision, txn.flags);
1950Sstevel@tonic-gate 		(void) fprintf(stderr,
1960Sstevel@tonic-gate 				"\tfrom(mnum,key): %ld, %d\tto: %ld, %d\n",
1970Sstevel@tonic-gate 				txn.from.mnum, txn.from.key,
1980Sstevel@tonic-gate 				txn.to.mnum, txn.to.key);
1990Sstevel@tonic-gate 	}
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	mdclrerror(ep);
2020Sstevel@tonic-gate 	if (metaioctl(MD_IOCRENAME, &txn, &txn.mde, from_np->cname) != 0) {
203253Sstevep 		if (from_add_flag) {
204253Sstevep 			(void) del_key_name(sp, from_np, ep);
205*1623Stw21770 			/*
206*1623Stw21770 			 * Attempt removal of device node
207*1623Stw21770 			 */
208*1623Stw21770 			(void) metaioctl(MD_IOCREM_DEV, &txn.from.mnum,
209*1623Stw21770 				ep, NULL);
210253Sstevep 		}
211253Sstevep 
212253Sstevep 		if (op == MDRNOP_RENAME || to_add_flag) {
213253Sstevep 			(void) del_key_name(sp, to_np, ep);
214*1623Stw21770 			/*
215*1623Stw21770 			 * Attempt removal of device node
216*1623Stw21770 			 */
217*1623Stw21770 			(void) metaioctl(MD_IOCREM_DEV, &txn.to.mnum,
218*1623Stw21770 				ep, NULL);
219253Sstevep 		}
220*1623Stw21770 
221253Sstevep 		return (mdstealerror(ep, &txn.mde));
222253Sstevep 	}
223253Sstevep 
224253Sstevep 	/*
225*1623Stw21770 	 * Since now the metadevice can be ref'd in the namespace
226*1623Stw21770 	 * by self and by the top device so upon the successful
227*1623Stw21770 	 * rename/xchange, we need to check the type and make
228*1623Stw21770 	 * necessary adjustment for the device's n_cnt in the namespace
229*1623Stw21770 	 * by calling add_key_name/del_key_name to do the tricks
230253Sstevep 	 */
231*1623Stw21770 	if (op == MDRNOP_RENAME && from_has_parent) {
232*1623Stw21770 		(void) add_key_name(sp, to_np, NULL, ep);
233*1623Stw21770 		if (from_is_fn)
234*1623Stw21770 			(void) del_self_name(sp, from_np->key, ep);
235*1623Stw21770 	}
236*1623Stw21770 
237*1623Stw21770 	if (op == MDRNOP_EXCHANGE && from_is_fn) {
238*1623Stw21770 		(void) add_key_name(sp, from_np, NULL, ep);
2390Sstevel@tonic-gate 	}
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 	/* force the name cache to re-read device state */
2420Sstevel@tonic-gate 	meta_invalidate_name(from_np);
2430Sstevel@tonic-gate 	meta_invalidate_name(to_np);
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	return (0);
2460Sstevel@tonic-gate }
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate /*
2490Sstevel@tonic-gate  * rename a metadevice
2500Sstevel@tonic-gate  */
2510Sstevel@tonic-gate int
meta_rename(mdsetname_t * sp,mdname_t * from_np,mdname_t * to_np,mdcmdopts_t options,md_error_t * ep)2520Sstevel@tonic-gate meta_rename(
2530Sstevel@tonic-gate 	mdsetname_t	*sp,
2540Sstevel@tonic-gate 	mdname_t	*from_np,
2550Sstevel@tonic-gate 	mdname_t	*to_np,
2560Sstevel@tonic-gate 	mdcmdopts_t	 options,
2570Sstevel@tonic-gate 	md_error_t	*ep
2580Sstevel@tonic-gate )
2590Sstevel@tonic-gate {
2600Sstevel@tonic-gate 	int		 flags		= (options & MDCMD_FORCE)? FORCE: 0;
2610Sstevel@tonic-gate 	int		 rc		= 0;
2620Sstevel@tonic-gate 	char		*p;
263253Sstevep 	md_common_t	*from_mdp;
264*1623Stw21770 	minor_t		to_minor = meta_getminor(to_np->dev);
265*1623Stw21770 	md_error_t	status = mdnullerror;
266*1623Stw21770 	md_error_t	*t_ep = &status;
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 	/* must have a set */
2690Sstevel@tonic-gate 	assert(sp != NULL);
2700Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(from_np->dev)));
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 	mdclrerror(ep);
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	if (((p = getenv("MD_DEBUG")) != NULL) &&
2750Sstevel@tonic-gate 	    (strstr(p, "RENAME") != NULL)) {
2760Sstevel@tonic-gate 		flags |= NOISY;
2770Sstevel@tonic-gate 	}
2780Sstevel@tonic-gate 	/* if DOIT is not set, we are in dryrun mode */
2790Sstevel@tonic-gate 	if ((options & MDCMD_DOIT) == 0) {
2800Sstevel@tonic-gate 		flags |= DRYRUN;
2810Sstevel@tonic-gate 	}
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 	if (metachkmeta(from_np, ep) != 0) {
2850Sstevel@tonic-gate 		assert(!mdisok(ep));
2860Sstevel@tonic-gate 		return (-1);
2870Sstevel@tonic-gate 	}
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 	mdclrerror(ep);
2900Sstevel@tonic-gate 
291253Sstevep 	if ((from_mdp = meta_get_unit(sp, from_np, ep)) == NULL) {
2920Sstevel@tonic-gate 		assert(!mdisok(ep));
2930Sstevel@tonic-gate 		return (-1);
2940Sstevel@tonic-gate 	}
2950Sstevel@tonic-gate 
296253Sstevep 	if (meta_get_unit(sp, to_np, ep) != NULL) {
2970Sstevel@tonic-gate 		if (mdisok(ep)) {
2980Sstevel@tonic-gate 			(void) mdmderror(ep, MDE_UNIT_ALREADY_SETUP,
2990Sstevel@tonic-gate 					meta_getminor(to_np->dev),
3000Sstevel@tonic-gate 					to_np->cname);
3010Sstevel@tonic-gate 		}
3020Sstevel@tonic-gate 		return (-1);
3030Sstevel@tonic-gate 	}
3040Sstevel@tonic-gate 	mdclrerror(ep);
3050Sstevel@tonic-gate 
306*1623Stw21770 	/*
307*1623Stw21770 	 * The dest device name has been added early on
308*1623Stw21770 	 * by meta_init_make_device call so get the entry from
309*1623Stw21770 	 * the namespace
310*1623Stw21770 	 */
311*1623Stw21770 	if (meta_getnmentbydev(sp->setno, MD_SIDEWILD, to_np->dev,
312*1623Stw21770 	    NULL, NULL, &to_np->key, ep) == NULL) {
313*1623Stw21770 		return (-1);
314*1623Stw21770 	}
315*1623Stw21770 
3160Sstevel@tonic-gate 	/* If FORCE is not set, check if metadevice is open */
3170Sstevel@tonic-gate 	if (!(flags & FORCE)) {
318*1623Stw21770 	    if (check_open(sp, from_np, ep) != 0) {
319*1623Stw21770 		(void) del_key_name(sp, to_np, t_ep);
320*1623Stw21770 		(void) metaioctl(MD_IOCREM_DEV, &to_minor, t_ep, NULL);
321*1623Stw21770 		return (-1);
322*1623Stw21770 	    }
3230Sstevel@tonic-gate 	}
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 	/*
3260Sstevel@tonic-gate 	 * All checks are done, now we do the real work.
327*1623Stw21770 	 * If we are in dryrun mode, clear the deivce node
328*1623Stw21770 	 * and we are done.
3290Sstevel@tonic-gate 	 */
3300Sstevel@tonic-gate 	if (flags & DRYRUN) {
331*1623Stw21770 		(void) del_key_name(sp, to_np, t_ep);
332*1623Stw21770 		(void) metaioctl(MD_IOCREM_DEV, &to_minor, t_ep, NULL);
3330Sstevel@tonic-gate 		return (0); /* success */
3340Sstevel@tonic-gate 	}
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 	if (to_np->key == MD_KEYBAD || to_np->key == MD_KEYWILD) {
3370Sstevel@tonic-gate 		assert(!mdisok(ep));
3380Sstevel@tonic-gate 		return (-1);
3390Sstevel@tonic-gate 	}
3400Sstevel@tonic-gate 
341253Sstevep 	rc = meta_swap(sp, from_np, from_mdp, to_np, NULL, MDRNOP_RENAME,
342253Sstevep 		flags, ep);
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	if (rc == 0) {
3450Sstevel@tonic-gate 		if (options & MDCMD_PRINT) {
3460Sstevel@tonic-gate 			(void) fprintf(stdout, dgettext(TEXT_DOMAIN,
3470Sstevel@tonic-gate 				"%s: has been renamed to %s\n"),
3480Sstevel@tonic-gate 				from_np->cname, to_np->cname);
3490Sstevel@tonic-gate 		}
3500Sstevel@tonic-gate 	}
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	return (rc);
3530Sstevel@tonic-gate }
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate /*
3560Sstevel@tonic-gate  * return TRUE if current <from>, <to> ordering would
3570Sstevel@tonic-gate  * prevent <from> from being in the role of <self>
3580Sstevel@tonic-gate  */
3590Sstevel@tonic-gate static bool_t
meta_exchange_need_to_flip(md_common_t * from_mdp,md_common_t * to_mdp)3600Sstevel@tonic-gate meta_exchange_need_to_flip(
3610Sstevel@tonic-gate 	md_common_t	*from_mdp,
3620Sstevel@tonic-gate 	md_common_t	*to_mdp
3630Sstevel@tonic-gate )
3640Sstevel@tonic-gate {
3650Sstevel@tonic-gate 	assert(from_mdp);
3660Sstevel@tonic-gate 	assert(to_mdp);
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate 	/*
3690Sstevel@tonic-gate 	 * ?
3700Sstevel@tonic-gate 	 *  \
3710Sstevel@tonic-gate 	 * <to>
3720Sstevel@tonic-gate 	 *    \
3730Sstevel@tonic-gate 	 *    <from>
3740Sstevel@tonic-gate 	 */
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 	if (MD_HAS_PARENT(from_mdp->parent)) {
3770Sstevel@tonic-gate 		if (MD_HAS_PARENT(to_mdp->parent)) {
3780Sstevel@tonic-gate 			if (from_mdp->parent ==
3790Sstevel@tonic-gate 				meta_getminor(to_mdp->namep->dev)) {
3800Sstevel@tonic-gate 				return (TRUE);
3810Sstevel@tonic-gate 			}
3820Sstevel@tonic-gate 		}
3830Sstevel@tonic-gate 	}
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 	/*
3860Sstevel@tonic-gate 	 * <from>
3870Sstevel@tonic-gate 	 *    \
3880Sstevel@tonic-gate 	 *    <to>
3890Sstevel@tonic-gate 	 *      \
3900Sstevel@tonic-gate 	 *	 ?
3910Sstevel@tonic-gate 	 */
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 	if (MD_HAS_PARENT(to_mdp->parent)) {
3940Sstevel@tonic-gate 		if (to_mdp->capabilities & MD_CAN_META_CHILD) {
3950Sstevel@tonic-gate 			return (TRUE);
3960Sstevel@tonic-gate 		}
3970Sstevel@tonic-gate 	}
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	/*
4000Sstevel@tonic-gate 	 * <to>
4010Sstevel@tonic-gate 	 *   \
4020Sstevel@tonic-gate 	 *  <from>
4030Sstevel@tonic-gate 	 */
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate 	if (MD_HAS_PARENT(from_mdp->parent)) {
4060Sstevel@tonic-gate 		if (from_mdp->parent == meta_getminor(to_mdp->namep->dev)) {
4070Sstevel@tonic-gate 			if (!(from_mdp->capabilities & MD_CAN_META_CHILD)) {
4080Sstevel@tonic-gate 				return (TRUE);
4090Sstevel@tonic-gate 			}
4100Sstevel@tonic-gate 		}
4110Sstevel@tonic-gate 	}
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 	/*
4140Sstevel@tonic-gate 	 * <from>	or	<to>
4150Sstevel@tonic-gate 	 *   \			  \
4160Sstevel@tonic-gate 	 *  <to>		<from>
4170Sstevel@tonic-gate 	 *			    \
4180Sstevel@tonic-gate 	 *			    ?
4190Sstevel@tonic-gate 	 */
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 	return (FALSE);
4220Sstevel@tonic-gate }
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate /*
4250Sstevel@tonic-gate  * exchange the names of two metadevices
4260Sstevel@tonic-gate  */
4270Sstevel@tonic-gate int
meta_exchange(mdsetname_t * sp,mdname_t * from_np,mdname_t * to_np,mdcmdopts_t options,md_error_t * ep)4280Sstevel@tonic-gate meta_exchange(
4290Sstevel@tonic-gate 	mdsetname_t	*sp,
4300Sstevel@tonic-gate 	mdname_t	*from_np,
4310Sstevel@tonic-gate 	mdname_t	*to_np,
4320Sstevel@tonic-gate 	mdcmdopts_t	 options,
4330Sstevel@tonic-gate 	md_error_t	*ep
4340Sstevel@tonic-gate )
4350Sstevel@tonic-gate {
4360Sstevel@tonic-gate 	int		 flags	= (options & MDCMD_FORCE)? FORCE: 0;
4370Sstevel@tonic-gate 	md_common_t	*from_mdp, *to_mdp;
4380Sstevel@tonic-gate 	int		 rc;
4390Sstevel@tonic-gate 	char		*p, *p2;
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	/* must have a set */
4420Sstevel@tonic-gate 	assert(sp != NULL);
4430Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(from_np->dev)));
4440Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(to_np->dev)));
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 	if (metachkmeta(from_np, ep) != 0) {
4470Sstevel@tonic-gate 		assert(!mdisok(ep));
4480Sstevel@tonic-gate 		return (-1);
4490Sstevel@tonic-gate 	}
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 	if (metachkmeta(to_np, ep) != 0) {
4520Sstevel@tonic-gate 		assert(!mdisok(ep));
4530Sstevel@tonic-gate 		return (-1);
4540Sstevel@tonic-gate 	}
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 	if ((options & MDCMD_DOIT) == 0) {
4570Sstevel@tonic-gate 		flags |= DRYRUN;
4580Sstevel@tonic-gate 	}
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 	if ((p = getenv("MD_DEBUG")) != NULL) {
4610Sstevel@tonic-gate 		if ((p2 = strstr(p, "EXCHANGE=")) != NULL) {
4620Sstevel@tonic-gate 			flags |= NOISY;
4630Sstevel@tonic-gate 			if ((p2 = strchr(p2, '=')) != NULL) {
4640Sstevel@tonic-gate 				if (strcmp((p2+1), "NOFLIP") == 0) {
4650Sstevel@tonic-gate 					flags |= NOFLIP;
4660Sstevel@tonic-gate 				}
4670Sstevel@tonic-gate 			}
4680Sstevel@tonic-gate 		} else if (strstr(p, "EXCHANGE") != NULL) {
4690Sstevel@tonic-gate 			flags |= NOISY;
4700Sstevel@tonic-gate 		}
4710Sstevel@tonic-gate 	}
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 	if ((from_mdp = meta_get_unit(sp, from_np, ep)) == NULL) {
4740Sstevel@tonic-gate 		assert(!mdisok(ep));
4750Sstevel@tonic-gate 		return (-1);
4760Sstevel@tonic-gate 	}
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 	if ((to_mdp = meta_get_unit(sp, to_np, ep)) == NULL) {
4790Sstevel@tonic-gate 		assert(!mdisok(ep));
4800Sstevel@tonic-gate 		return (-1);
4810Sstevel@tonic-gate 	}
4820Sstevel@tonic-gate 	assert(mdisok(ep));
4830Sstevel@tonic-gate 
484253Sstevep 
4850Sstevel@tonic-gate 	/* If FORCE is not set, check if metadevice is open */
4860Sstevel@tonic-gate 	if (!(flags & FORCE)) {
4870Sstevel@tonic-gate 		if (check_open(sp, from_np, ep) != 0) {
4880Sstevel@tonic-gate 			return (-1);
4890Sstevel@tonic-gate 		}
4900Sstevel@tonic-gate 	}
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 	/*
4930Sstevel@tonic-gate 	 * All checks are done, now we do the real work.
4940Sstevel@tonic-gate 	 * If we are in dryrun mode, we're done.
4950Sstevel@tonic-gate 	 */
4960Sstevel@tonic-gate 	if (flags & DRYRUN) {
4970Sstevel@tonic-gate 		return (0); /* success */
4980Sstevel@tonic-gate 	}
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate 	/*
5010Sstevel@tonic-gate 	 * NOFLIP is used only for debugging; the driver
5020Sstevel@tonic-gate 	 * will catch this and return MDE_RENAME_ORDER, if necessary
5030Sstevel@tonic-gate 	 */
5040Sstevel@tonic-gate 	if (((flags & NOFLIP) == 0) &&
5050Sstevel@tonic-gate 	    meta_exchange_need_to_flip(from_mdp, to_mdp)) {
506253Sstevep 		rc = meta_swap(sp, to_np, to_mdp, from_np, from_mdp,
507253Sstevep 			MDRNOP_EXCHANGE, flags, ep);
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 	} else {
510253Sstevep 		rc = meta_swap(sp, from_np, from_mdp, to_np, to_mdp,
511253Sstevep 			MDRNOP_EXCHANGE, flags, ep);
5120Sstevel@tonic-gate 	}
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 	if (rc == 0) {
5150Sstevel@tonic-gate 		if (options & MDCMD_PRINT) {
5160Sstevel@tonic-gate 			(void) fprintf(stdout, dgettext(TEXT_DOMAIN,
5170Sstevel@tonic-gate 				"%s and %s have exchanged identities\n"),
5180Sstevel@tonic-gate 				from_np->cname, to_np->cname);
5190Sstevel@tonic-gate 		}
5200Sstevel@tonic-gate 	}
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate 	return (rc);
5230Sstevel@tonic-gate }
524