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