xref: /onnv-gate/usr/src/uts/common/io/lvm/md/md_rename.c (revision 2077:ef90dc4e9399)
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
51623Stw21770  * Common Development and Distribution License (the "License").
61623Stw21770  * 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 /*
221623Stw21770  * 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 /*
300Sstevel@tonic-gate  * rename or exchange identities of virtual device nodes
310Sstevel@tonic-gate  */
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #include <sys/param.h>
340Sstevel@tonic-gate #include <sys/systm.h>
350Sstevel@tonic-gate #include <sys/debug.h>
360Sstevel@tonic-gate #include <sys/sysmacros.h>
370Sstevel@tonic-gate #include <sys/types.h>
380Sstevel@tonic-gate #include <sys/ddi.h>
390Sstevel@tonic-gate #include <sys/sunddi.h>
400Sstevel@tonic-gate 
410Sstevel@tonic-gate #include <sys/lvm/mdvar.h>
420Sstevel@tonic-gate #include <sys/lvm/md_rename.h>
430Sstevel@tonic-gate 
440Sstevel@tonic-gate #include <sys/sysevent/eventdefs.h>
450Sstevel@tonic-gate #include <sys/sysevent/svm.h>
460Sstevel@tonic-gate 
470Sstevel@tonic-gate extern	major_t		md_major;
480Sstevel@tonic-gate extern	unit_t		md_nunits;
490Sstevel@tonic-gate extern	set_t		md_nsets;
500Sstevel@tonic-gate extern	md_set_t	md_set[];
510Sstevel@tonic-gate 
520Sstevel@tonic-gate #define	ROLE(r)						\
530Sstevel@tonic-gate 	((r) == MDRR_PARENT?	"parent":		\
540Sstevel@tonic-gate 	(r) == MDRR_SELF?	"self":			\
550Sstevel@tonic-gate 	(r) == MDRR_CHILD?	"child":		\
560Sstevel@tonic-gate 	(r) == MDRR_UNK?	"<unknown>": "<garbage>")
570Sstevel@tonic-gate 
580Sstevel@tonic-gate #define	OP_STR(op)							\
590Sstevel@tonic-gate 		(((op) == MDRNOP_UNK)?		"<unknown>"	:	\
600Sstevel@tonic-gate 		    ((op) == MDRNOP_RENAME)?	"rename"	:	\
610Sstevel@tonic-gate 		    ((op) == MDRNOP_EXCHANGE)?	"exchange"	:	\
620Sstevel@tonic-gate 						"<garbage>")
630Sstevel@tonic-gate int md_rename_debug = 0;
640Sstevel@tonic-gate 
650Sstevel@tonic-gate /* delta guard rails */
660Sstevel@tonic-gate const unsigned long long	DELTA_BEG	= (0xDad08888a110beefull);
670Sstevel@tonic-gate const unsigned long long	DELTA_END	= (0xa110Beef88880Dadull);
680Sstevel@tonic-gate 
690Sstevel@tonic-gate const unsigned long long	DELTA_BEG_FREED	= (0xBad0c0ed0fed0dadull);
700Sstevel@tonic-gate const unsigned long long	DELTA_END_FREED	= (0x0Fed0dadbad0c0edull);
710Sstevel@tonic-gate 
720Sstevel@tonic-gate /* transaction guard rails */
730Sstevel@tonic-gate const unsigned long long	TXN_BEG		= (0xDad01eadc0ed2badull);
740Sstevel@tonic-gate const unsigned long long	TXN_END		= (0xc0ed2badDad01eadull);
750Sstevel@tonic-gate 
760Sstevel@tonic-gate const unsigned long long	TXNUN_BEG	= (0xcafe0fedbad0beefull);
770Sstevel@tonic-gate const unsigned long long	TXNUN_END	= (0xbad0beefcafe0fedull);
780Sstevel@tonic-gate 
790Sstevel@tonic-gate const unsigned int		guard_shift	= (sizeof (u_longlong_t) - 3);
800Sstevel@tonic-gate const md_stackcap_t		MD_CAN_DO_ANYTHING	= (md_stackcap_t)0;
810Sstevel@tonic-gate 
820Sstevel@tonic-gate typedef struct role_change_mapping_tab_t {
830Sstevel@tonic-gate 	const int			ord;
840Sstevel@tonic-gate 	const md_renrole_t		old_role;
850Sstevel@tonic-gate 	const md_renrole_t		new_role;
860Sstevel@tonic-gate 	const char			*svc_name;
870Sstevel@tonic-gate 	md_ren_roleswap_svc_t * const	default_svc;
880Sstevel@tonic-gate } role_change_tab_t;
890Sstevel@tonic-gate 
900Sstevel@tonic-gate /*
910Sstevel@tonic-gate  *  The actual table is at the end of the file, so we don't need
920Sstevel@tonic-gate  *  many forward references
930Sstevel@tonic-gate  */
940Sstevel@tonic-gate static	role_change_tab_t	role_swap_tab[];
950Sstevel@tonic-gate 
960Sstevel@tonic-gate #define	ILLEGAL_ROLESWAP_SVC	((md_ren_roleswap_svc_t *)(0xA1100BAD))
970Sstevel@tonic-gate #define	NO_DEFAULT_ROLESWAP_SVC	((md_ren_roleswap_svc_t *)(NULL))
980Sstevel@tonic-gate #define	ILLEGAL_SVC_NAME	(NULL)
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate /*
1010Sstevel@tonic-gate  *
1020Sstevel@tonic-gate  * Role swap rule table:
1030Sstevel@tonic-gate  *
1040Sstevel@tonic-gate  *                                New Role
1050Sstevel@tonic-gate  *      +---------------------------------------------------------------|
1060Sstevel@tonic-gate  *      |        |    Parent       |       Self     |      Child        |
1070Sstevel@tonic-gate  *      +--------+-----------------+----------------+-------------------+
1080Sstevel@tonic-gate  *      | Parent | no default      | ...no default  | illegal	        |
1090Sstevel@tonic-gate  *      |        | 1 (update kids) | 2  (update to) | 3	                |
1100Sstevel@tonic-gate  * Old  +--------+-----------------+----------------+-------------------+
1110Sstevel@tonic-gate  * Role | Self   | ...self update  | ...rename self | no default (down  |
1120Sstevel@tonic-gate  *      |        | 4   update up | 5	            | 6    update from) |
1130Sstevel@tonic-gate  *      +--------+-----------------+----------------+-------------------+
1140Sstevel@tonic-gate  *      | Child  | illegal         | ...child       | ...update         |
1150Sstevel@tonic-gate  *      |        | 7	           | 8   update to  | 9	parent          |
1160Sstevel@tonic-gate  *      +---------------------------------------------------------------+
1170Sstevel@tonic-gate  *
1180Sstevel@tonic-gate  * and notes:
1190Sstevel@tonic-gate  *
1200Sstevel@tonic-gate  * - Boxes 1, 4 and 6 are the most interesting. They are responsible
1210Sstevel@tonic-gate  *   for updating the from unit's data structures. These may involve
1220Sstevel@tonic-gate  *   finding (former or future) children, resetting name keys and the like.
1230Sstevel@tonic-gate  *
1240Sstevel@tonic-gate  * - The "rename" operation is boxes 1, 5 and 9. Most of the work
1250Sstevel@tonic-gate  *   is done in box 5, since that contains both the "from" and "to"
1260Sstevel@tonic-gate  *   unit struct for rename.
1270Sstevel@tonic-gate  *
1280Sstevel@tonic-gate  *  (There's got to be an eigen function for this; that diagonal
1290Sstevel@tonic-gate  *   axis is a role identity operation searching for an expression.)
1300Sstevel@tonic-gate  *
1310Sstevel@tonic-gate  * - Almost every transaction will call more than one of these.
1320Sstevel@tonic-gate  *   (Only a rename of a unit with no relatives will only call
1330Sstevel@tonic-gate  *   a single box.)
1340Sstevel@tonic-gate  *
1350Sstevel@tonic-gate  * - Box 4 "...update from" is the generic self->parent modifier.
1360Sstevel@tonic-gate  * - Box 8 "...update to" is the generic child->self modifier.
1370Sstevel@tonic-gate  *   These can be generic because all of the information which
1380Sstevel@tonic-gate  *   needs to be updated is in the common portion of the unit
1390Sstevel@tonic-gate  *   structure when changing from their respective roles.
1400Sstevel@tonic-gate  *
1410Sstevel@tonic-gate  * - Boxes 1, 2 and 6 ("no default") indicate that per-metadevice
1420Sstevel@tonic-gate  *   information must be updated. For example, in box 1, children
1430Sstevel@tonic-gate  *   identities must be updated. Since different metadevice types
1440Sstevel@tonic-gate  *   detect and manipulate their children differently, there can
1450Sstevel@tonic-gate  *   be no generic "md_rename" function in this box.
1460Sstevel@tonic-gate  *
1470Sstevel@tonic-gate  * In addition to the named services in the table above, there
1480Sstevel@tonic-gate  * are other named services used by rename/exchange.
1490Sstevel@tonic-gate  * MDRNM_LIST_URFOLKS, MDRNM_LIST_URSELF, MDRNM_LIST_URKIDS
1500Sstevel@tonic-gate  * list a device's parents, self and children, respectively.
1510Sstevel@tonic-gate  * In most cases the default functions can be used for parents
1520Sstevel@tonic-gate  * and self. Top-level devices, are not required to have a
1530Sstevel@tonic-gate  * "list folks" named service. Likewise, devices which can
1540Sstevel@tonic-gate  * not have metadevice children, are not required to have the
1550Sstevel@tonic-gate  * "list kids" named service. The LIST_UR* functions call back into
1560Sstevel@tonic-gate  * the base driver (md_build_rendelta()) to package the changes to
1570Sstevel@tonic-gate  * a device for addition onto the tree. The LIST_UR* named service
1580Sstevel@tonic-gate  * then adds this "rename delta" onto the delta tree itself.
1590Sstevel@tonic-gate  * This keeps private knowledge appropriately encapsulated.
1600Sstevel@tonic-gate  * They return the number of devices which will need to be changed,
1610Sstevel@tonic-gate  * and hence the number of elements they've added to the delta list
1620Sstevel@tonic-gate  * or -1 for error.
1630Sstevel@tonic-gate  *
1640Sstevel@tonic-gate  * Other named services used by rename/exchange are:
1650Sstevel@tonic-gate  * "lock" (MDRNM_LOCK), "unlock" (MDRNM_UNLOCK) and "check" (MDRNM_CHECK).
1660Sstevel@tonic-gate  * These (un) write-lock all of the relevant in-core structs,
1670Sstevel@tonic-gate  * including the unit structs for the device and quiesce i/o as necessary.
1680Sstevel@tonic-gate  * The "check" named service verifies that this device
1690Sstevel@tonic-gate  * is in a state where rename could and may occur at this time.
1700Sstevel@tonic-gate  * Since the role_swap functions themselves cannot be undone
1710Sstevel@tonic-gate  * (at least in this implementation), it is check()'s job to
1720Sstevel@tonic-gate  * verify that the device is renamable (sic) or, if not, abort.
1730Sstevel@tonic-gate  * The check function for the device participating in the role
1740Sstevel@tonic-gate  * of "self" is usually where rename or exchange validity is verified.
1750Sstevel@tonic-gate  *
1760Sstevel@tonic-gate  * All of these functions take two arguments which may be thought
1770Sstevel@tonic-gate  * of as the collective state changes of the tree of devices
1780Sstevel@tonic-gate  * (md_rendelta_t *family) and the rename transaction state
1790Sstevel@tonic-gate  * (md_rentxn_t rtxn or rtxnp).
1800Sstevel@tonic-gate  *
1810Sstevel@tonic-gate  */
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate /*
1850Sstevel@tonic-gate  * rename unit lock
1860Sstevel@tonic-gate  * (default name service routine MDRNM_LOCK)
1870Sstevel@tonic-gate  */
1880Sstevel@tonic-gate static intptr_t
md_rename_lock(md_rendelta_t * delta,md_rentxn_t * rtxnp)1890Sstevel@tonic-gate md_rename_lock(md_rendelta_t *delta, md_rentxn_t *rtxnp)
1900Sstevel@tonic-gate {
1910Sstevel@tonic-gate 	minor_t		 mnum;
1920Sstevel@tonic-gate 	md_renop_t	 op;
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate 	ASSERT(delta);
1950Sstevel@tonic-gate 	ASSERT(rtxnp);
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 	if (!delta || !rtxnp) {
1980Sstevel@tonic-gate 		(void) mdsyserror(&rtxnp->mde, EINVAL);
1990Sstevel@tonic-gate 		return (EINVAL);
2000Sstevel@tonic-gate 	}
2010Sstevel@tonic-gate 	mnum = md_getminor(delta->dev);
2020Sstevel@tonic-gate 	op = rtxnp->op;
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	/*
2050Sstevel@tonic-gate 	 * target doesn't exist if renaming (by definition),
2060Sstevel@tonic-gate 	 * so it need not be locked
2070Sstevel@tonic-gate 	 */
2080Sstevel@tonic-gate 	if (op == MDRNOP_RENAME && mnum == rtxnp->to.mnum) {
2090Sstevel@tonic-gate 		return (0);
2100Sstevel@tonic-gate 	}
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 	ASSERT(delta->uip);
2130Sstevel@tonic-gate 	if (!delta->uip) {
2140Sstevel@tonic-gate 		(void) mdmderror(&rtxnp->mde, MDE_UNIT_NOT_SETUP, mnum);
2150Sstevel@tonic-gate 		return (ENODEV);
2160Sstevel@tonic-gate 	}
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 	ASSERT(delta->unp);
2190Sstevel@tonic-gate 	if (!delta->unp) {
2200Sstevel@tonic-gate 		(void) mdmderror(&rtxnp->mde, MDE_UNIT_NOT_SETUP, mnum);
2210Sstevel@tonic-gate 		return (ENODEV);
2220Sstevel@tonic-gate 	}
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 	ASSERT(!UNIT_WRITER_HELD(delta->unp));
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 	(void) md_unit_writerlock(delta->uip);
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 	ASSERT(UNIT_WRITER_HELD(delta->unp));
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	return (0);
2310Sstevel@tonic-gate }
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate /*
2340Sstevel@tonic-gate  * (default name service routine MDRNM_UNLOCK)
2350Sstevel@tonic-gate  */
2360Sstevel@tonic-gate /* ARGSUSED */
2370Sstevel@tonic-gate static void
md_rename_unlock(md_rendelta_t * delta,md_rentxn_t * rtxnp)2380Sstevel@tonic-gate md_rename_unlock(
2390Sstevel@tonic-gate 	md_rendelta_t	*delta,
2400Sstevel@tonic-gate 	md_rentxn_t	*rtxnp)
2410Sstevel@tonic-gate {
2420Sstevel@tonic-gate 	ASSERT(delta);
2430Sstevel@tonic-gate 	ASSERT(delta->uip);
2440Sstevel@tonic-gate 	ASSERT(delta->unp);
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	ASSERT(UNIT_WRITER_HELD(delta->unp));
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 	(void) md_unit_writerexit(delta->uip);
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 	ASSERT(!UNIT_WRITER_HELD(delta->unp));
2510Sstevel@tonic-gate }
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate /*
2540Sstevel@tonic-gate  * This is used by the various MDRNM_LIST* named services.
2550Sstevel@tonic-gate  */
2560Sstevel@tonic-gate md_rendelta_t *
md_build_rendelta(md_renrole_t old_role,md_renrole_t new_role,md_dev64_t dev,md_rendelta_t * prev,md_unit_t * unp,mdi_unit_t * uip,md_error_t * ep)2570Sstevel@tonic-gate md_build_rendelta(
2580Sstevel@tonic-gate 	md_renrole_t	 old_role,
2590Sstevel@tonic-gate 	md_renrole_t	 new_role,
2600Sstevel@tonic-gate 	md_dev64_t	 dev,
2610Sstevel@tonic-gate 	md_rendelta_t	*prev,
2620Sstevel@tonic-gate 	md_unit_t	*unp,
2630Sstevel@tonic-gate 	mdi_unit_t	*uip,
2640Sstevel@tonic-gate 	md_error_t	*ep)
2650Sstevel@tonic-gate {
2660Sstevel@tonic-gate 	int		 err	= 0;
2670Sstevel@tonic-gate 	md_rendelta_t	*new;
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 	new = (md_rendelta_t *)kmem_alloc(sizeof (md_rendelta_t), KM_SLEEP);
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	new->beginning	= DELTA_BEG;
2720Sstevel@tonic-gate 	new->dev	= dev;
2730Sstevel@tonic-gate 	new->new_role	= new_role;
2740Sstevel@tonic-gate 	new->old_role	= old_role;
2750Sstevel@tonic-gate 	new->next	= NULL;
2760Sstevel@tonic-gate 	new->prev	= prev;
2770Sstevel@tonic-gate 	new->unp = unp;
2780Sstevel@tonic-gate 	new->uip = uip;
2790Sstevel@tonic-gate 	bzero((void *) &new->txn_stat, sizeof (md_rendstat_t));
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 	/*
2820Sstevel@tonic-gate 	 * For non-meta devices that are being renamed (in the future,
2830Sstevel@tonic-gate 	 * that is) we would need to pass in default functions to
2840Sstevel@tonic-gate 	 * accommodate them, provided the default function is
2850Sstevel@tonic-gate 	 * truly capable of performing the lock/check/unlock function
2860Sstevel@tonic-gate 	 * on opaque devices.
2870Sstevel@tonic-gate 	 */
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 	new->lock	= md_get_named_service(dev, /* modindex */ 0,
2900Sstevel@tonic-gate 						MDRNM_LOCK, md_rename_lock);
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 	new->unlock	= (md_ren_void_svc_t *)md_get_named_service(dev,
2930Sstevel@tonic-gate 					/* modindex */ 0, MDRNM_UNLOCK,
2940Sstevel@tonic-gate 					(intptr_t (*)()) md_rename_unlock);
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 	new->check	= md_get_named_service(dev, /* modindex */ 0,
2970Sstevel@tonic-gate 					    MDRNM_CHECK, /* Default */ NULL);
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 	new->role_swap	= NULL;	/* set this when the roles are determined */
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 	if (!new->lock || !new->unlock || !new->check) {
3020Sstevel@tonic-gate 		(void) mdmderror(ep, MDE_RENAME_CONFIG_ERROR, md_getminor(dev));
3030Sstevel@tonic-gate 		err = EINVAL;
3040Sstevel@tonic-gate 		goto out;
3050Sstevel@tonic-gate 	}
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	new->end = DELTA_END;
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate out:
3100Sstevel@tonic-gate 	if (err != 0) {
3110Sstevel@tonic-gate 		if (new) {
3120Sstevel@tonic-gate 			new->beginning	= DELTA_BEG_FREED;
3130Sstevel@tonic-gate 			new->end	= DELTA_END_FREED;
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 			kmem_free(new, sizeof (md_rendelta_t));
3160Sstevel@tonic-gate 			new = NULL;
3170Sstevel@tonic-gate 		}
3180Sstevel@tonic-gate 	}
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate 	if (prev) {
3210Sstevel@tonic-gate 		prev->next = new;
3220Sstevel@tonic-gate 	}
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 	return (new);
3250Sstevel@tonic-gate }
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate /*
3280Sstevel@tonic-gate  * md_store_recid()
3290Sstevel@tonic-gate  * used by role swap functions
3300Sstevel@tonic-gate  */
3310Sstevel@tonic-gate void
md_store_recid(int * prec_idx,mddb_recid_t * recid_list,md_unit_t * un)3320Sstevel@tonic-gate md_store_recid(
3330Sstevel@tonic-gate 	int		*prec_idx,
3340Sstevel@tonic-gate 	mddb_recid_t	*recid_list,
3350Sstevel@tonic-gate 	md_unit_t	*un)
3360Sstevel@tonic-gate {
3370Sstevel@tonic-gate 	mddb_recid_t	*rp;
3380Sstevel@tonic-gate 	bool_t		 add_recid;
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 	ASSERT(prec_idx);
3410Sstevel@tonic-gate 	ASSERT(recid_list);
3420Sstevel@tonic-gate 	ASSERT(recid_list[*prec_idx] == 0);
3430Sstevel@tonic-gate 	ASSERT(*prec_idx >= 0);
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 	for (add_recid = TRUE, rp = recid_list; add_recid && rp && *rp; rp++) {
3460Sstevel@tonic-gate 		if (MD_RECID(un) == *rp) {
3470Sstevel@tonic-gate 			add_recid = FALSE;
3480Sstevel@tonic-gate 		}
3490Sstevel@tonic-gate 	}
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 	if (add_recid) {
3520Sstevel@tonic-gate 		recid_list[(*prec_idx)++] = MD_RECID(un);
3530Sstevel@tonic-gate 	}
3540Sstevel@tonic-gate }
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate /*
3570Sstevel@tonic-gate  * MDRNM_LIST_URFOLKS: generic named svc entry point
3580Sstevel@tonic-gate  * add all parents onto the list pointed to by dlpp
3590Sstevel@tonic-gate  * (only weird multi-parented devices need to have their
3600Sstevel@tonic-gate  * own named svc  to do this.)
3610Sstevel@tonic-gate  */
3620Sstevel@tonic-gate static int
md_rename_listfolks(md_rendelta_t ** dlpp,md_rentxn_t * rtxnp)3630Sstevel@tonic-gate md_rename_listfolks(md_rendelta_t **dlpp, md_rentxn_t *rtxnp)
3640Sstevel@tonic-gate {
3650Sstevel@tonic-gate 	md_rendelta_t	*new;
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 	ASSERT(rtxnp);
3680Sstevel@tonic-gate 	ASSERT(dlpp);
3690Sstevel@tonic-gate 	ASSERT(*dlpp == NULL);
3700Sstevel@tonic-gate 	ASSERT((rtxnp->op == MDRNOP_EXCHANGE) || (rtxnp->op == MDRNOP_RENAME));
3710Sstevel@tonic-gate 	ASSERT(rtxnp->from.uip);
3720Sstevel@tonic-gate 	ASSERT(rtxnp->from.unp);
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 	if ((!rtxnp->from.uip) || (!rtxnp->from.unp)) {
3750Sstevel@tonic-gate 		(void) mdmderror(&rtxnp->mde, MDE_UNIT_NOT_SETUP,
3760Sstevel@tonic-gate 							rtxnp->from.mnum);
3770Sstevel@tonic-gate 		return (-1);
3780Sstevel@tonic-gate 	}
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	if (!MD_HAS_PARENT(MD_PARENT(rtxnp->from.unp))) {
3810Sstevel@tonic-gate 		return (0);
3820Sstevel@tonic-gate 	}
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 	/*
3850Sstevel@tonic-gate 	 * If supporting log renaming (and other multiparented devices)
3860Sstevel@tonic-gate 	 * callout to each misc module to claim this waif and return the
3870Sstevel@tonic-gate 	 * md_dev64_t of its parents.
3880Sstevel@tonic-gate 	 */
3890Sstevel@tonic-gate 	if (MD_PARENT(rtxnp->from.unp) == MD_MULTI_PARENT) {
3900Sstevel@tonic-gate 		(void) mdmderror(&rtxnp->mde, MDE_RENAME_SOURCE_BAD,
3910Sstevel@tonic-gate 							rtxnp->from.mnum);
3920Sstevel@tonic-gate 		return (2);
3930Sstevel@tonic-gate 	}
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 	if ((rtxnp->op == MDRNOP_RENAME) ||
3960Sstevel@tonic-gate 	    (MD_PARENT(rtxnp->from.unp) != MD_SID(rtxnp->to.unp))) {
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 		new = md_build_rendelta(
3990Sstevel@tonic-gate 			    MDRR_PARENT,
4000Sstevel@tonic-gate 			    MDRR_PARENT,
4010Sstevel@tonic-gate 			    md_makedevice(md_major, MD_PARENT(rtxnp->from.unp)),
4020Sstevel@tonic-gate 			    NULL,
4030Sstevel@tonic-gate 			    MD_UNIT(MD_PARENT(rtxnp->from.unp)),
4040Sstevel@tonic-gate 			    MDI_UNIT(MD_PARENT(rtxnp->from.unp)),
4050Sstevel@tonic-gate 			    &rtxnp->mde);
4060Sstevel@tonic-gate 	} else {
4070Sstevel@tonic-gate 		/* parent is swapping roles with self */
4080Sstevel@tonic-gate 		new = md_build_rendelta(
4090Sstevel@tonic-gate 			    MDRR_PARENT,
4100Sstevel@tonic-gate 			    MDRR_SELF,
4110Sstevel@tonic-gate 			    md_makedevice(md_major, MD_SID(rtxnp->to.unp)),
4120Sstevel@tonic-gate 			    NULL,
4130Sstevel@tonic-gate 			    rtxnp->to.unp,
4140Sstevel@tonic-gate 			    rtxnp->to.uip,
4150Sstevel@tonic-gate 			    &rtxnp->mde);
4160Sstevel@tonic-gate 	}
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate 	if (!new) {
4190Sstevel@tonic-gate 		if (mdisok(&rtxnp->mde)) {
4200Sstevel@tonic-gate 			(void) mdsyserror(&rtxnp->mde, ENOMEM);
4210Sstevel@tonic-gate 		}
4220Sstevel@tonic-gate 		return (-1);
4230Sstevel@tonic-gate 	}
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 	*dlpp = new;
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 	return (1);
4280Sstevel@tonic-gate }
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate /*
4310Sstevel@tonic-gate  * MDRNM_LIST_URSELF: named svc entry point
4320Sstevel@tonic-gate  * add all delta entries appropriate for ourselves onto the deltalist pointed
4330Sstevel@tonic-gate  * to by dlpp
4340Sstevel@tonic-gate  */
4350Sstevel@tonic-gate static int
md_rename_listself(md_rendelta_t ** dlpp,md_rentxn_t * rtxnp)4360Sstevel@tonic-gate md_rename_listself(md_rendelta_t **dlpp, md_rentxn_t *rtxnp)
4370Sstevel@tonic-gate {
4380Sstevel@tonic-gate 	md_rendelta_t	*new, *p;
4390Sstevel@tonic-gate 	bool_t		 exchange_up	= FALSE;
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	ASSERT(rtxnp);
4420Sstevel@tonic-gate 	ASSERT(dlpp);
4430Sstevel@tonic-gate 	ASSERT((rtxnp->op == MDRNOP_EXCHANGE) || (rtxnp->op == MDRNOP_RENAME));
4440Sstevel@tonic-gate 	ASSERT(rtxnp->from.unp);
4450Sstevel@tonic-gate 	ASSERT(rtxnp->from.uip);
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 	if ((!rtxnp->from.uip) || (!rtxnp->from.unp)) {
4480Sstevel@tonic-gate 		(void) mdmderror(&rtxnp->mde, MDE_UNIT_NOT_SETUP,
4490Sstevel@tonic-gate 							rtxnp->from.mnum);
4500Sstevel@tonic-gate 		return (-1);
4510Sstevel@tonic-gate 	}
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate 	for (p = *dlpp; p && p->next != NULL; p = p->next) {
4540Sstevel@tonic-gate 		/* NULL */
4550Sstevel@tonic-gate 	}
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 	/*
4580Sstevel@tonic-gate 	 * renaming or
4590Sstevel@tonic-gate 	 * from's parent is not to and to's parent is not from
4600Sstevel@tonic-gate 	 */
4610Sstevel@tonic-gate 	if (rtxnp->op == MDRNOP_RENAME) {
4620Sstevel@tonic-gate 		new = md_build_rendelta(
4630Sstevel@tonic-gate 				MDRR_SELF,
4640Sstevel@tonic-gate 				MDRR_SELF,
4650Sstevel@tonic-gate 				md_makedevice(md_major, rtxnp->from.mnum),
4660Sstevel@tonic-gate 				p,
4670Sstevel@tonic-gate 				rtxnp->from.unp,
4680Sstevel@tonic-gate 				rtxnp->from.uip,
4690Sstevel@tonic-gate 				&rtxnp->mde);
4700Sstevel@tonic-gate 	} else {
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 		if (MD_PARENT(rtxnp->from.unp) == MD_SID(rtxnp->to.unp)) {
4730Sstevel@tonic-gate 			exchange_up = TRUE;
4740Sstevel@tonic-gate 		}
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 		/* self and parent are flipping */
4770Sstevel@tonic-gate 		new = md_build_rendelta(
4780Sstevel@tonic-gate 				MDRR_SELF,
4790Sstevel@tonic-gate 				exchange_up? MDRR_PARENT: MDRR_CHILD,
4800Sstevel@tonic-gate 				md_makedevice(md_major, rtxnp->from.mnum),
4810Sstevel@tonic-gate 				p,
4820Sstevel@tonic-gate 				rtxnp->from.unp,
4830Sstevel@tonic-gate 				rtxnp->from.uip,
4840Sstevel@tonic-gate 				&rtxnp->mde);
4850Sstevel@tonic-gate 	}
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 	if (!new) {
4880Sstevel@tonic-gate 		if (mdisok(&rtxnp->mde)) {
4890Sstevel@tonic-gate 			(void) mdsyserror(&rtxnp->mde, ENOMEM);
4900Sstevel@tonic-gate 		}
4910Sstevel@tonic-gate 		return (-1);
4920Sstevel@tonic-gate 	}
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 	if (!*dlpp) {
4950Sstevel@tonic-gate 		*dlpp = new;
4960Sstevel@tonic-gate 	}
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 	return (1);
4990Sstevel@tonic-gate }
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate /*
5020Sstevel@tonic-gate  * free the tree of all deltas to devices involved in the rename transaction
5030Sstevel@tonic-gate  */
5040Sstevel@tonic-gate static void
free_dtree(md_rendelta_t * family)5050Sstevel@tonic-gate free_dtree(md_rendelta_t *family)
5060Sstevel@tonic-gate {
5070Sstevel@tonic-gate 	md_rendelta_t	*next		= NULL;
5080Sstevel@tonic-gate 	int		 i		= 0;
5090Sstevel@tonic-gate 	md_rendelta_t	*r;
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 	for (r = family; (NULL != r); r = next, i++) {
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 		next		= r->next;
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate 		/* shift << because it makes the resultant pattern readable */
5160Sstevel@tonic-gate 		r->beginning	= DELTA_BEG_FREED ^ (i << guard_shift);
5170Sstevel@tonic-gate 		r->end		= DELTA_END_FREED ^ (i << guard_shift);
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 		kmem_free(r, sizeof (md_rendelta_t));
5200Sstevel@tonic-gate 	}
5210Sstevel@tonic-gate }
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate /*
5240Sstevel@tonic-gate  * walk down family tree, calling lock service function
5250Sstevel@tonic-gate  */
5260Sstevel@tonic-gate static int
lock_dtree(md_rendelta_t * family,md_rentxn_t * rtxnp)5270Sstevel@tonic-gate lock_dtree(md_rendelta_t *family, md_rentxn_t *rtxnp)
5280Sstevel@tonic-gate {
5290Sstevel@tonic-gate 	md_rendelta_t	*r;
5300Sstevel@tonic-gate 	int		 rc;
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate 	ASSERT(family);
5330Sstevel@tonic-gate 	ASSERT(rtxnp);
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 	if (!family || !rtxnp) {
5360Sstevel@tonic-gate 		return (EINVAL);
5370Sstevel@tonic-gate 	}
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 	for (rc = 0, r = family; r; r = r->next) {
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate 		ASSERT(r->unp);
5420Sstevel@tonic-gate 		ASSERT(!UNIT_WRITER_HELD(r->unp));
5430Sstevel@tonic-gate 		ASSERT(r->lock);
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 		if ((rc = (int)(*r->lock) (r, rtxnp)) != 0) {
5460Sstevel@tonic-gate 			return (rc);
5470Sstevel@tonic-gate 		}
5480Sstevel@tonic-gate 		r->txn_stat.locked = TRUE;
5490Sstevel@tonic-gate 	}
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate 	return (0);
5520Sstevel@tonic-gate }
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate /*
5550Sstevel@tonic-gate  * We rely on check() (MDRNM_CHECK) to make exhaustive checks,
5560Sstevel@tonic-gate  * since we don't attempt to undo role_swap() failures.
5570Sstevel@tonic-gate  *
5580Sstevel@tonic-gate  * To implement an undo() function would require each role_swap()
5590Sstevel@tonic-gate  * to store a log of previous state of the structures it changes,
5600Sstevel@tonic-gate  * presumably anchored by the rendelta.
5610Sstevel@tonic-gate  *
5620Sstevel@tonic-gate  */
5630Sstevel@tonic-gate static int
check_dtree(md_rendelta_t * family,md_rentxn_t * rtxnp)5640Sstevel@tonic-gate check_dtree(md_rendelta_t *family, md_rentxn_t *rtxnp)
5650Sstevel@tonic-gate {
5660Sstevel@tonic-gate 	md_rendelta_t	*r;
5670Sstevel@tonic-gate 	int		 rc;
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 	ASSERT(family);
5700Sstevel@tonic-gate 	ASSERT(rtxnp);
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate 	if (!family || !rtxnp) {
5730Sstevel@tonic-gate 		/* no error packet to set? */
5740Sstevel@tonic-gate 		return (EINVAL);
5750Sstevel@tonic-gate 	}
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 	for (r = family, rc = 0; r; r = r->next) {
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate 		ASSERT(UNIT_WRITER_HELD(r->unp));
5800Sstevel@tonic-gate 		ASSERT(r->txn_stat.locked);
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 		/*
5830Sstevel@tonic-gate 		 * <to> doesn't exist for rename
5840Sstevel@tonic-gate 		 */
5850Sstevel@tonic-gate 		if (!(rtxnp->op == MDRNOP_RENAME &&
5860Sstevel@tonic-gate 		    md_getminor(r->dev) == rtxnp->to.mnum)) {
5870Sstevel@tonic-gate 			ASSERT(r->uip);
5880Sstevel@tonic-gate 			r->txn_stat.is_open = md_unit_isopen(r->uip);
5890Sstevel@tonic-gate 		}
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 		/*
5920Sstevel@tonic-gate 		 * if only allowing offline rename/exchanges, check
5930Sstevel@tonic-gate 		 * for top being trans because it opens its sub-devices
5940Sstevel@tonic-gate 		 */
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 		switch (rtxnp->revision) {
5970Sstevel@tonic-gate 		case MD_RENAME_VERSION_OFFLINE:
5980Sstevel@tonic-gate 			if ((r->txn_stat.is_open) &&
5990Sstevel@tonic-gate 				(!rtxnp->stat.trans_in_stack)) {
6000Sstevel@tonic-gate 				(void) mdmderror(&rtxnp->mde, MDE_RENAME_BUSY,
6010Sstevel@tonic-gate 							md_getminor(r->dev));
6020Sstevel@tonic-gate 				return (EBUSY);
6030Sstevel@tonic-gate 			}
6040Sstevel@tonic-gate 			break;
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate 		case MD_RENAME_VERSION_ONLINE:
6070Sstevel@tonic-gate 			break;
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 		default:
6100Sstevel@tonic-gate 			(void) mdmderror(&rtxnp->mde, MDE_RENAME_CONFIG_ERROR,
6110Sstevel@tonic-gate 						md_getminor(r->dev));
6120Sstevel@tonic-gate 			return (EINVAL);
6130Sstevel@tonic-gate 		}
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate 		/* MD_UN_MOD_INPROGRESS includes the MD_UN_RENAMING bit */
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate 		if (MD_STATUS(r->unp) & MD_UN_MOD_INPROGRESS) {
6180Sstevel@tonic-gate 			(void) mdmderror(&rtxnp->mde, MDE_RENAME_BUSY,
6190Sstevel@tonic-gate 							md_getminor(r->dev));
6200Sstevel@tonic-gate 			return (EBUSY);
6210Sstevel@tonic-gate 		}
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 		MD_STATUS(r->unp) |= MD_UN_RENAMING;
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 		if ((rc = (int)(*r->check)(r, rtxnp)) != 0) {
6260Sstevel@tonic-gate 			return (rc);
6270Sstevel@tonic-gate 		}
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 		/* and be sure we can proceed */
6300Sstevel@tonic-gate 		if (!(r->role_swap)) {
6310Sstevel@tonic-gate 			(void) mdmderror(&rtxnp->mde, MDE_RENAME_CONFIG_ERROR,
6320Sstevel@tonic-gate 							md_getminor(r->dev));
6330Sstevel@tonic-gate 			return (EINVAL);
6340Sstevel@tonic-gate 		}
6350Sstevel@tonic-gate 		r->txn_stat.checked = TRUE;
6360Sstevel@tonic-gate 	}
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 	return (0);
6390Sstevel@tonic-gate }
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate /*
6430Sstevel@tonic-gate  * rename role_swap() functions are responsible for updating their
6440Sstevel@tonic-gate  * own parent, self and children references in both on-disk
6450Sstevel@tonic-gate  * and in-core structures, as well as storing the changed
6460Sstevel@tonic-gate  * record ids into recids and incrementing rec_idx.
6470Sstevel@tonic-gate  */
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate static void
role_swap_dtree(md_rendelta_t * family,md_rentxn_t * rtxnp)6500Sstevel@tonic-gate role_swap_dtree(md_rendelta_t *family, md_rentxn_t *rtxnp)
6510Sstevel@tonic-gate {
6520Sstevel@tonic-gate 	md_rendelta_t	*r;
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 	ASSERT(family);
6550Sstevel@tonic-gate 	ASSERT(rtxnp);
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 	for (r = family; r; r = r->next) {
6580Sstevel@tonic-gate 		ASSERT(r->role_swap);
6590Sstevel@tonic-gate 		ASSERT(r->txn_stat.locked);
6600Sstevel@tonic-gate 		ASSERT(r->txn_stat.checked);
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate 		(*r->role_swap)(r, rtxnp);
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 		r->txn_stat.role_swapped = TRUE;
6650Sstevel@tonic-gate 	}
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate 	/*
6680Sstevel@tonic-gate 	 * there's some work to do, but not more than expected
6690Sstevel@tonic-gate 	 */
6700Sstevel@tonic-gate 	ASSERT(rtxnp->rec_idx > 0);
6710Sstevel@tonic-gate 	ASSERT(rtxnp->rec_idx < rtxnp->n_recids);
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	if (rtxnp->rec_idx >= rtxnp->n_recids || rtxnp->rec_idx <= 0) {
6740Sstevel@tonic-gate 		/*
6750Sstevel@tonic-gate 		 * There's no way to indicate error from here,
6760Sstevel@tonic-gate 		 * and even if we could, there's no undo mechanism.
6770Sstevel@tonic-gate 		 * We've already modified the in-core structs, so
6780Sstevel@tonic-gate 		 * We can't continue w/o committing, but we
6790Sstevel@tonic-gate 		 * don't appear to have anything to commit.
6800Sstevel@tonic-gate 		 */
6810Sstevel@tonic-gate 		cmn_err(CE_PANIC,
6820Sstevel@tonic-gate 			"md_rename: role_swap_dtree(family:%p, rtxnp:%p)",
6830Sstevel@tonic-gate 					(void *) family, (void *) rtxnp);
6840Sstevel@tonic-gate 		return;
6850Sstevel@tonic-gate 	}
6860Sstevel@tonic-gate 	rtxnp->recids[rtxnp->rec_idx] = 0;
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate 	mddb_commitrecs_wrapper(rtxnp->recids);
6890Sstevel@tonic-gate }
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate /*
6920Sstevel@tonic-gate  * walk down delta tree, calling the unlock service for each device,
6930Sstevel@tonic-gate  * provided any of the devices appear to have been locked
6940Sstevel@tonic-gate  */
6950Sstevel@tonic-gate static void
unlock_dtree(md_rendelta_t * family,md_rentxn_t * rtxnp)6960Sstevel@tonic-gate unlock_dtree(md_rendelta_t *family, md_rentxn_t *rtxnp)
6970Sstevel@tonic-gate {
6980Sstevel@tonic-gate 	md_rendelta_t	*r;
6990Sstevel@tonic-gate 	uint_t		 any_locked	= FALSE;
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 	ASSERT(family);
7020Sstevel@tonic-gate 	ASSERT(rtxnp);
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 	for (r = family; r; r = r->next) {
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 		ASSERT(!(r->txn_stat.unlocked)); /* "has been unlocked" */
7070Sstevel@tonic-gate 		any_locked |= r->txn_stat.locked;
7080Sstevel@tonic-gate 	}
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate 	if (any_locked) {
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate 		/* unwind in reverse order */
7130Sstevel@tonic-gate 		for (r = family; NULL != r->next; r = r->next) {
7140Sstevel@tonic-gate 			/* NULL */
7150Sstevel@tonic-gate 		}
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 		for (; NULL != r; r = r->prev) {
7180Sstevel@tonic-gate 			MD_STATUS(r->unp) &= ~MD_UN_RENAMING;
7190Sstevel@tonic-gate 			ASSERT(r->unlock);
7200Sstevel@tonic-gate 			r->unlock(r, rtxnp);
7210Sstevel@tonic-gate 			r->txn_stat.unlocked = TRUE;
7220Sstevel@tonic-gate 		}
7230Sstevel@tonic-gate 	}
7240Sstevel@tonic-gate }
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate /*
7270Sstevel@tonic-gate  * MDRNM_UPDATE_SELF
7280Sstevel@tonic-gate  * This role swap function is identical for all unit types,
7290Sstevel@tonic-gate  * so keep it here. It's also the best example because it
7300Sstevel@tonic-gate  * touches all the modified portions of the relevant
7310Sstevel@tonic-gate  * in-common structures.
7320Sstevel@tonic-gate  */
7330Sstevel@tonic-gate static void
md_rename_update_self(md_rendelta_t * delta,md_rentxn_t * rtxnp)7340Sstevel@tonic-gate md_rename_update_self(
7350Sstevel@tonic-gate 	md_rendelta_t	*delta,
7360Sstevel@tonic-gate 	md_rentxn_t	*rtxnp)
7370Sstevel@tonic-gate {
7380Sstevel@tonic-gate 	minor_t		from_min, to_min;
7390Sstevel@tonic-gate 	sv_dev_t	sv;
7401623Stw21770 	mddb_de_ic_t	*dep;
7411623Stw21770 	mddb_rb32_t	*rbp;
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate 	ASSERT(rtxnp);
7440Sstevel@tonic-gate 	ASSERT(rtxnp->op == MDRNOP_RENAME);
7450Sstevel@tonic-gate 	ASSERT(delta);
7460Sstevel@tonic-gate 	ASSERT(delta->unp);
7470Sstevel@tonic-gate 	ASSERT(delta->uip);
7480Sstevel@tonic-gate 	ASSERT(rtxnp->rec_idx >= 0);
7490Sstevel@tonic-gate 	ASSERT(rtxnp->recids);
7500Sstevel@tonic-gate 	ASSERT(delta->old_role == MDRR_SELF);
7510Sstevel@tonic-gate 	ASSERT(delta->new_role == MDRR_SELF);
7520Sstevel@tonic-gate 	ASSERT(md_getminor(delta->dev) == rtxnp->from.mnum);
7530Sstevel@tonic-gate 
7540Sstevel@tonic-gate 	from_min = rtxnp->from.mnum;
7550Sstevel@tonic-gate 	to_min = rtxnp->to.mnum;
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate 	/*
7580Sstevel@tonic-gate 	 * self id changes in our own unit struct
7590Sstevel@tonic-gate 	 */
7601623Stw21770 	MD_SID(delta->unp) = to_min;
7610Sstevel@tonic-gate 
7621623Stw21770 	/*
7631623Stw21770 	 * make sure that dest always has correct un_revision
7641623Stw21770 	 * and rb_revision
7651623Stw21770 	 */
7661623Stw21770 	delta->unp->c.un_revision |= MD_FN_META_DEV;
7671623Stw21770 	dep = mddb_getrecdep(MD_RECID(delta->unp));
7681623Stw21770 	ASSERT(dep);
7691623Stw21770 	rbp = dep->de_rb;
7701623Stw21770 	if (rbp->rb_revision & MDDB_REV_RB) {
7711623Stw21770 		rbp->rb_revision = MDDB_REV_RBFN;
7721623Stw21770 	} else if (rbp->rb_revision & MDDB_REV_RB64) {
7731623Stw21770 		rbp->rb_revision = MDDB_REV_RB64FN;
7741623Stw21770 	}
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 	/*
7770Sstevel@tonic-gate 	 * clear old array pointers to unit in-core and unit
7780Sstevel@tonic-gate 	 */
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate 	MDI_VOIDUNIT(from_min) = NULL;
7810Sstevel@tonic-gate 	MD_VOIDUNIT(from_min) = NULL;
7820Sstevel@tonic-gate 
7830Sstevel@tonic-gate 	/*
7840Sstevel@tonic-gate 	 * and point the new slots at the unit in-core and unit structs
7850Sstevel@tonic-gate 	 */
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 	MDI_VOIDUNIT(to_min) = delta->uip;
7880Sstevel@tonic-gate 	MD_VOIDUNIT(to_min) = delta->unp;
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 	/*
7910Sstevel@tonic-gate 	 * recreate kstats
7920Sstevel@tonic-gate 	 * - destroy the ones associated with our former identity
7930Sstevel@tonic-gate 	 * - reallocate and associate them with our new identity
7940Sstevel@tonic-gate 	 */
7950Sstevel@tonic-gate 	md_kstat_destroy_ui(delta->uip);
7960Sstevel@tonic-gate 	md_kstat_init_ui(to_min, delta->uip);
7970Sstevel@tonic-gate 
7980Sstevel@tonic-gate 	/*
7990Sstevel@tonic-gate 	 * the unit in-core reference to the get next link's id changes
8000Sstevel@tonic-gate 	 */
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate 	delta->uip->ui_link.ln_id = to_min;
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate 	/*
8050Sstevel@tonic-gate 	 * name space addition of new key was done from user-level
8060Sstevel@tonic-gate 	 * remove the old name's key here
8070Sstevel@tonic-gate 	 */
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 	sv.setno = MD_MIN2SET(from_min);
8100Sstevel@tonic-gate 	sv.key = rtxnp->from.key;
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 	md_rem_names(&sv, 1);
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate 	/*
8151623Stw21770 	 * Remove associated device node as well
8161623Stw21770 	 */
817*2077Stw21770 	md_remove_minor_node(from_min);
8181623Stw21770 
8191623Stw21770 	/*
8200Sstevel@tonic-gate 	 * and store the record id (from the unit struct) into recids
8210Sstevel@tonic-gate 	 * for later commitment by md_rename()
8220Sstevel@tonic-gate 	 */
8230Sstevel@tonic-gate 	md_store_recid(&rtxnp->rec_idx, rtxnp->recids, delta->unp);
8240Sstevel@tonic-gate }
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate /*
8270Sstevel@tonic-gate  * Either one of our siblings and/or our parent changed identities.
8280Sstevel@tonic-gate  */
8290Sstevel@tonic-gate static void
md_renexch_update_parent(md_rendelta_t * delta,md_rentxn_t * rtxnp)8300Sstevel@tonic-gate md_renexch_update_parent(
8310Sstevel@tonic-gate 	md_rendelta_t	*delta,
8320Sstevel@tonic-gate 	md_rentxn_t	*rtxnp)
8330Sstevel@tonic-gate {
8340Sstevel@tonic-gate 	ASSERT(rtxnp);
8350Sstevel@tonic-gate 	ASSERT((MDRNOP_RENAME == rtxnp->op) || (rtxnp->op == MDRNOP_EXCHANGE));
8360Sstevel@tonic-gate 	ASSERT(rtxnp->rec_idx >= 0);
8370Sstevel@tonic-gate 	ASSERT(rtxnp->recids);
8380Sstevel@tonic-gate 	ASSERT(delta);
8390Sstevel@tonic-gate 	ASSERT(delta->unp);
8400Sstevel@tonic-gate 	ASSERT(delta->old_role == MDRR_CHILD);
8410Sstevel@tonic-gate 	ASSERT(delta->new_role == MDRR_CHILD);
8420Sstevel@tonic-gate 	ASSERT((MD_PARENT(delta->unp) == rtxnp->from.mnum) ||
8430Sstevel@tonic-gate 		(MD_PARENT(delta->unp) == rtxnp->to.mnum));
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate 	if (MD_PARENT(delta->unp) == rtxnp->from.mnum) {
8460Sstevel@tonic-gate 		MD_PARENT(delta->unp) = rtxnp->to.mnum;
8470Sstevel@tonic-gate 	}
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 	md_store_recid(&rtxnp->rec_idx, rtxnp->recids, delta->unp);
8500Sstevel@tonic-gate }
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate /*
8530Sstevel@tonic-gate  * exchange up (child->self)
8540Sstevel@tonic-gate  */
8550Sstevel@tonic-gate static void
md_exchange_child_update_to(md_rendelta_t * delta,md_rentxn_t * rtxnp)8560Sstevel@tonic-gate md_exchange_child_update_to(
8570Sstevel@tonic-gate 	md_rendelta_t	*delta,
8580Sstevel@tonic-gate 	md_rentxn_t	*rtxnp)
8590Sstevel@tonic-gate {
8600Sstevel@tonic-gate 	minor_t from_min, to_min;
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate 	ASSERT(rtxnp);
8630Sstevel@tonic-gate 	ASSERT(rtxnp->op == MDRNOP_EXCHANGE);
8640Sstevel@tonic-gate 	ASSERT(rtxnp->rec_idx >= 0);
8650Sstevel@tonic-gate 	ASSERT(rtxnp->recids);
8660Sstevel@tonic-gate 	ASSERT(delta);
8670Sstevel@tonic-gate 	ASSERT(delta->unp);
8680Sstevel@tonic-gate 	ASSERT(delta->uip);
8690Sstevel@tonic-gate 	ASSERT(delta->old_role == MDRR_CHILD);
8700Sstevel@tonic-gate 	ASSERT(delta->new_role == MDRR_SELF);
8710Sstevel@tonic-gate 	ASSERT(md_getminor(delta->dev) == rtxnp->to.mnum);
8720Sstevel@tonic-gate 
8730Sstevel@tonic-gate 	from_min = rtxnp->from.mnum;
8740Sstevel@tonic-gate 	to_min = rtxnp->to.mnum;
8750Sstevel@tonic-gate 
8760Sstevel@tonic-gate 	/*
8770Sstevel@tonic-gate 	 * self id changes in our own unit struct
8780Sstevel@tonic-gate 	 * Note:
8790Sstevel@tonic-gate 	 * - Since we're assuming the identity of "from" we use its mnum even
8800Sstevel@tonic-gate 	 *   though we're updating the "to" structures.
8810Sstevel@tonic-gate 	 */
8820Sstevel@tonic-gate 
8830Sstevel@tonic-gate 	MD_SID(delta->unp) = from_min;
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 	/*
8860Sstevel@tonic-gate 	 * our parent identifier becomes the new self, who was "to"
8870Sstevel@tonic-gate 	 */
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate 	MD_PARENT(delta->unp) = to_min;
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 	/*
8920Sstevel@tonic-gate 	 * point the set array pointers at the "new" unit and unit in-cores
8930Sstevel@tonic-gate 	 * Note:
8940Sstevel@tonic-gate 	 * - The other half of this transfer is done in the "update from"
8950Sstevel@tonic-gate 	 *   rename/exchange named service.
8960Sstevel@tonic-gate 	 */
8970Sstevel@tonic-gate 
8980Sstevel@tonic-gate 	MD_VOIDUNIT(from_min) = delta->unp;
8990Sstevel@tonic-gate 	MDI_VOIDUNIT(from_min) = delta->uip;
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate 	/*
9020Sstevel@tonic-gate 	 * transfer kstats
9030Sstevel@tonic-gate 	 */
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate 	delta->uip->ui_kstat = rtxnp->from.kstatp;
9060Sstevel@tonic-gate 
9070Sstevel@tonic-gate 	/*
9080Sstevel@tonic-gate 	 * the unit in-core reference to the get next link's id changes
9090Sstevel@tonic-gate 	 */
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate 	delta->uip->ui_link.ln_id = from_min;
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 	/*
9140Sstevel@tonic-gate 	 * name space additions, if necessary, were done from user-level.
9150Sstevel@tonic-gate 	 * name space deletions, if necessary, were done in "exchange_from"
9160Sstevel@tonic-gate 	 */
9170Sstevel@tonic-gate 
9180Sstevel@tonic-gate 	/*
9190Sstevel@tonic-gate 	 * and store the record id (from the unit struct) into recids
9200Sstevel@tonic-gate 	 * for later comitment by md_rename()
9210Sstevel@tonic-gate 	 */
9220Sstevel@tonic-gate 
9230Sstevel@tonic-gate 	md_store_recid(&rtxnp->rec_idx, rtxnp->recids, delta->unp);
9240Sstevel@tonic-gate }
9250Sstevel@tonic-gate 
9260Sstevel@tonic-gate /*
9270Sstevel@tonic-gate  * exchange up (self->parent)
9280Sstevel@tonic-gate  */
9290Sstevel@tonic-gate static void
md_exchange_self_update_from_up(md_rendelta_t * delta,md_rentxn_t * rtxnp)9300Sstevel@tonic-gate md_exchange_self_update_from_up(
9310Sstevel@tonic-gate 	md_rendelta_t	*delta,
9320Sstevel@tonic-gate 	md_rentxn_t	*rtxnp)
9330Sstevel@tonic-gate {
9340Sstevel@tonic-gate 	minor_t from_min, to_min;
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate 	ASSERT(rtxnp);
9370Sstevel@tonic-gate 	ASSERT(rtxnp->op == MDRNOP_EXCHANGE);
9380Sstevel@tonic-gate 	ASSERT(rtxnp->rec_idx >= 0);
9390Sstevel@tonic-gate 	ASSERT(rtxnp->recids);
9400Sstevel@tonic-gate 	ASSERT(delta);
9410Sstevel@tonic-gate 	ASSERT(delta->unp);
9420Sstevel@tonic-gate 	ASSERT(delta->uip);
9430Sstevel@tonic-gate 	ASSERT(delta->old_role == MDRR_SELF);
9440Sstevel@tonic-gate 	ASSERT(delta->new_role == MDRR_PARENT);
9450Sstevel@tonic-gate 	ASSERT(md_getminor(delta->dev) == rtxnp->from.mnum);
9460Sstevel@tonic-gate 
9470Sstevel@tonic-gate 	from_min = rtxnp->from.mnum;
9480Sstevel@tonic-gate 	to_min = rtxnp->to.mnum;
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate 	/*
9510Sstevel@tonic-gate 	 * self id changes in our own unit struct
9520Sstevel@tonic-gate 	 * Note:
9530Sstevel@tonic-gate 	 * - Since we're assuming the identity of "to" we use its mnum
9540Sstevel@tonic-gate 	 *   while we're updating the "to" structures.
9550Sstevel@tonic-gate 	 */
9560Sstevel@tonic-gate 
9570Sstevel@tonic-gate 	MD_SID(delta->unp) = to_min;
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate 	/*
9600Sstevel@tonic-gate 	 * our parent identifier becomes the new parent, who was "from"
9610Sstevel@tonic-gate 	 */
9620Sstevel@tonic-gate 
9630Sstevel@tonic-gate 	MD_PARENT(delta->unp) = from_min;
9640Sstevel@tonic-gate 
9650Sstevel@tonic-gate 	/*
9660Sstevel@tonic-gate 	 * point the set array pointers at the "new" unit and unit in-cores
9670Sstevel@tonic-gate 	 * Note:
9680Sstevel@tonic-gate 	 * - The other half of this transfer is done in the "update from"
9690Sstevel@tonic-gate 	 *   rename/exchange named service.
9700Sstevel@tonic-gate 	 */
9710Sstevel@tonic-gate 
9720Sstevel@tonic-gate 	MD_VOIDUNIT(to_min) = delta->unp;
9730Sstevel@tonic-gate 	MDI_VOIDUNIT(to_min) = delta->uip;
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate 	/*
9760Sstevel@tonic-gate 	 * transfer kstats
9770Sstevel@tonic-gate 	 */
9780Sstevel@tonic-gate 
9790Sstevel@tonic-gate 	delta->uip->ui_kstat = rtxnp->to.kstatp;
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate 	/*
9820Sstevel@tonic-gate 	 * the unit in-core reference to the get next link's id changes
9830Sstevel@tonic-gate 	 */
9840Sstevel@tonic-gate 
9850Sstevel@tonic-gate 	delta->uip->ui_link.ln_id = to_min;
9860Sstevel@tonic-gate 
9870Sstevel@tonic-gate 	/*
9880Sstevel@tonic-gate 	 * name space additions, if necessary, were done from user-level.
9890Sstevel@tonic-gate 	 * name space deletions, if necessary, were done in "exchange_from"
9900Sstevel@tonic-gate 	 */
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate 	/*
9930Sstevel@tonic-gate 	 * and store the record id (from the unit struct) into recids
9940Sstevel@tonic-gate 	 * for later comitment by md_rename()
9950Sstevel@tonic-gate 	 */
9960Sstevel@tonic-gate 
9970Sstevel@tonic-gate 	md_store_recid(&rtxnp->rec_idx, rtxnp->recids, delta->unp);
9980Sstevel@tonic-gate }
9990Sstevel@tonic-gate 
10000Sstevel@tonic-gate /*
10010Sstevel@tonic-gate  * The order of the called role swap functions is critical.
10020Sstevel@tonic-gate  * If they're not ordered as "all parents", then "all self"
10030Sstevel@tonic-gate  * then "all child" transitions, we will almost certainly
10040Sstevel@tonic-gate  * corrupt the data base and the in-core linkages. So,
10050Sstevel@tonic-gate  * verify that the list built by the individual drivers is
10060Sstevel@tonic-gate  * ok here.
10070Sstevel@tonic-gate  *
10080Sstevel@tonic-gate  * We could have done fancy bit encodings of the roles so
10090Sstevel@tonic-gate  * it all fit into a single word and we wouldn't need the
10100Sstevel@tonic-gate  * prev_ord field. But, since cpu power is cheaper than
10110Sstevel@tonic-gate  * than people power, they're all separate for easier
10120Sstevel@tonic-gate  * debugging and maintaining. (In the unlikely event that
10130Sstevel@tonic-gate  * rename/exchange ever becomes cpu-limited, and this
10140Sstevel@tonic-gate  * algorithm is the bottleneck, we should revisit this.)
10150Sstevel@tonic-gate  */
10160Sstevel@tonic-gate 
10170Sstevel@tonic-gate static bool_t
role_swap_is_valid(int previous,int current,md_rendelta_t * delta,md_rentxn_t * rtxnp)10180Sstevel@tonic-gate role_swap_is_valid(
10190Sstevel@tonic-gate 	int		 previous,
10200Sstevel@tonic-gate 	int		 current,
10210Sstevel@tonic-gate 	md_rendelta_t	*delta,
10220Sstevel@tonic-gate 	md_rentxn_t	*rtxnp)
10230Sstevel@tonic-gate {
10240Sstevel@tonic-gate 	bool_t	valid	= FALSE;
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate 	/*
10270Sstevel@tonic-gate 	 * we've backed up in processing the role table
10280Sstevel@tonic-gate 	 */
10290Sstevel@tonic-gate 	if ((previous > current) &&
10300Sstevel@tonic-gate 	    (delta->prev && (delta->old_role != delta->prev->old_role))) {
10310Sstevel@tonic-gate 		goto out;
10320Sstevel@tonic-gate 	}
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 	/*
10350Sstevel@tonic-gate 	 * we're repeating the same role transition
10360Sstevel@tonic-gate 	 */
10370Sstevel@tonic-gate 	if (previous == current) {
10380Sstevel@tonic-gate 		switch (delta->old_role) {
10390Sstevel@tonic-gate 		case MDRR_PARENT:
10400Sstevel@tonic-gate 			/*
10410Sstevel@tonic-gate 			 * require at least one of the devices to
10420Sstevel@tonic-gate 			 * be multiparented for us to allow another
10430Sstevel@tonic-gate 			 * parent transition
10440Sstevel@tonic-gate 			 */
10450Sstevel@tonic-gate 			if ((MD_MULTI_PARENT != MD_PARENT(rtxnp->from.unp)) &&
10460Sstevel@tonic-gate 			    (MD_MULTI_PARENT != MD_PARENT(rtxnp->to.unp))) {
10470Sstevel@tonic-gate 				goto out;
10480Sstevel@tonic-gate 			}
10490Sstevel@tonic-gate 			break;
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate 		case MDRR_CHILD:
10520Sstevel@tonic-gate 			/* it's ok to have multiple children */
10530Sstevel@tonic-gate 			break;
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate 		case MDRR_SELF:
10560Sstevel@tonic-gate 			/* it's never ok to have multiple self transitions */
10570Sstevel@tonic-gate 			/* FALLTHROUGH */
10580Sstevel@tonic-gate 		default:
10590Sstevel@tonic-gate 			goto out;
10600Sstevel@tonic-gate 		}
10610Sstevel@tonic-gate 	}
10620Sstevel@tonic-gate 
10630Sstevel@tonic-gate 	valid = TRUE;
10640Sstevel@tonic-gate out:
10650Sstevel@tonic-gate 	if (!valid) {
10660Sstevel@tonic-gate 		if (md_rename_debug != 0) {
10670Sstevel@tonic-gate 			cmn_err(CE_NOTE, "previous: %d, current: %d, role: %s",
10680Sstevel@tonic-gate 					previous, current,
10690Sstevel@tonic-gate 					ROLE(delta->old_role));
10700Sstevel@tonic-gate 			delay(3*drv_usectohz(1000000));
10710Sstevel@tonic-gate 			ASSERT(FALSE);
10720Sstevel@tonic-gate 		}
10730Sstevel@tonic-gate 	}
10740Sstevel@tonic-gate 
10750Sstevel@tonic-gate 	return (valid);
10760Sstevel@tonic-gate }
10770Sstevel@tonic-gate 
10780Sstevel@tonic-gate static role_change_tab_t *
lookup_role(md_renrole_t old_role,md_renrole_t new_role)10790Sstevel@tonic-gate lookup_role(md_renrole_t old_role, md_renrole_t new_role)
10800Sstevel@tonic-gate {
10810Sstevel@tonic-gate 	role_change_tab_t	*rp;
10820Sstevel@tonic-gate 	role_change_tab_t	*found = NULL;
10830Sstevel@tonic-gate 
10840Sstevel@tonic-gate 	for (rp = role_swap_tab; !found && (rp->old_role != MDRR_UNK); rp++) {
10850Sstevel@tonic-gate 
10860Sstevel@tonic-gate 		if (rp->old_role == old_role && rp->new_role == new_role) {
10870Sstevel@tonic-gate 			found = rp;
10880Sstevel@tonic-gate 		}
10890Sstevel@tonic-gate 	}
10900Sstevel@tonic-gate 	/*
10910Sstevel@tonic-gate 	 * we require a named svc if we've got two devices
10920Sstevel@tonic-gate 	 * claiming to be changing roles in this manner
10930Sstevel@tonic-gate 	 */
10940Sstevel@tonic-gate 	ASSERT(found);
10950Sstevel@tonic-gate 	ASSERT(found->default_svc != ILLEGAL_ROLESWAP_SVC);
10960Sstevel@tonic-gate 	ASSERT(found->svc_name != ILLEGAL_SVC_NAME);
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate 	if (!found ||
10990Sstevel@tonic-gate 	    (found->default_svc == ILLEGAL_ROLESWAP_SVC) ||
11000Sstevel@tonic-gate 	    (found->svc_name == ILLEGAL_SVC_NAME)) {
11010Sstevel@tonic-gate 		return (NULL);
11020Sstevel@tonic-gate 	}
11030Sstevel@tonic-gate 
11040Sstevel@tonic-gate 	return (found);
11050Sstevel@tonic-gate }
11060Sstevel@tonic-gate 
11070Sstevel@tonic-gate /*
11080Sstevel@tonic-gate  * fill in the role swap named svc., now that we know each device
11090Sstevel@tonic-gate  * and its changing role
11100Sstevel@tonic-gate  */
11110Sstevel@tonic-gate static int
valid_roleswap_dtree(md_rendelta_t * family,md_rentxn_t * rtxnp)11120Sstevel@tonic-gate valid_roleswap_dtree(
11130Sstevel@tonic-gate 	md_rendelta_t	*family,
11140Sstevel@tonic-gate 	md_rentxn_t	*rtxnp
11150Sstevel@tonic-gate )
11160Sstevel@tonic-gate {
11170Sstevel@tonic-gate 	md_rendelta_t		*r;
11180Sstevel@tonic-gate 	role_change_tab_t	*rolep;
11190Sstevel@tonic-gate 	minor_t			 from_min, to_min;
11200Sstevel@tonic-gate 	int			 prev_ord	= -1;
11210Sstevel@tonic-gate 	bool_t			found_self	= FALSE;
11220Sstevel@tonic-gate 	int			 err		= 0;
11230Sstevel@tonic-gate 
11240Sstevel@tonic-gate 	ASSERT(family);
11250Sstevel@tonic-gate 	ASSERT(rtxnp);
11260Sstevel@tonic-gate 
11270Sstevel@tonic-gate 	from_min = rtxnp->from.mnum;
11280Sstevel@tonic-gate 	to_min = rtxnp->to.mnum;
11290Sstevel@tonic-gate 
11300Sstevel@tonic-gate 	for (r = family; r; r = r->next, prev_ord = rolep->ord) {
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 		if (!(rolep = lookup_role(r->old_role, r->new_role))) {
11330Sstevel@tonic-gate 			(void) mdmderror(&rtxnp->mde,
11340Sstevel@tonic-gate 					MDE_RENAME_CONFIG_ERROR, from_min);
11350Sstevel@tonic-gate 			err = EOPNOTSUPP;
11360Sstevel@tonic-gate 			goto out;
11370Sstevel@tonic-gate 		}
11380Sstevel@tonic-gate 		r->role_swap = (md_ren_roleswap_svc_t *)md_get_named_service(
11390Sstevel@tonic-gate 					r->dev, /* modindex */ 0,
11400Sstevel@tonic-gate 					(char *)rolep->svc_name,
11410Sstevel@tonic-gate 					(intptr_t (*)()) rolep->default_svc);
11420Sstevel@tonic-gate 
11430Sstevel@tonic-gate 		/*
11440Sstevel@tonic-gate 		 * someone probably called the ioctl directly and
11450Sstevel@tonic-gate 		 * incorrectly, rather than via the libmeta wrappers
11460Sstevel@tonic-gate 		 */
11470Sstevel@tonic-gate 		if (!(r->role_swap)) {
11480Sstevel@tonic-gate 			(void) mdmderror(&rtxnp->mde,
11490Sstevel@tonic-gate 					MDE_RENAME_TARGET_UNRELATED, to_min);
11500Sstevel@tonic-gate 			err = EOPNOTSUPP;
11510Sstevel@tonic-gate 			goto out;
11520Sstevel@tonic-gate 		}
11530Sstevel@tonic-gate 
11540Sstevel@tonic-gate 		if (!role_swap_is_valid(prev_ord, rolep->ord, r, rtxnp)) {
11550Sstevel@tonic-gate 			(void) mdmderror(&rtxnp->mde,
11560Sstevel@tonic-gate 					MDE_RENAME_CONFIG_ERROR, from_min);
11570Sstevel@tonic-gate 			err = EINVAL;
11580Sstevel@tonic-gate 			goto out;
11590Sstevel@tonic-gate 		}
11600Sstevel@tonic-gate 
11610Sstevel@tonic-gate 		if (rolep->old_role == MDRR_SELF) {
11620Sstevel@tonic-gate 			found_self = TRUE;
11630Sstevel@tonic-gate 		}
11640Sstevel@tonic-gate 
11650Sstevel@tonic-gate 		if (MD_PARENT(r->unp) == MD_MULTI_PARENT) {
11660Sstevel@tonic-gate 			(void) mdmderror(&rtxnp->mde, MDE_RENAME_TARGET_BAD,
11670Sstevel@tonic-gate 							md_getminor(r->dev));
11680Sstevel@tonic-gate 			err = EINVAL;
11690Sstevel@tonic-gate 			goto out;
11700Sstevel@tonic-gate 		}
11710Sstevel@tonic-gate 	}
11720Sstevel@tonic-gate 
11730Sstevel@tonic-gate 	/*
11740Sstevel@tonic-gate 	 * must be at least one selfish device
11750Sstevel@tonic-gate 	 */
11760Sstevel@tonic-gate 	ASSERT(found_self);
11770Sstevel@tonic-gate 	if (!found_self) {
11780Sstevel@tonic-gate 		(void) mdmderror(&rtxnp->mde,
11790Sstevel@tonic-gate 					MDE_RENAME_CONFIG_ERROR, from_min);
11800Sstevel@tonic-gate 		err = EINVAL;
11810Sstevel@tonic-gate 		goto out;
11820Sstevel@tonic-gate 	}
11830Sstevel@tonic-gate 
11840Sstevel@tonic-gate out:
11850Sstevel@tonic-gate 	return (err);
11860Sstevel@tonic-gate }
11870Sstevel@tonic-gate 
11880Sstevel@tonic-gate /*
11890Sstevel@tonic-gate  * dump contents of rename transaction
11900Sstevel@tonic-gate  */
11910Sstevel@tonic-gate static void
dump_txn(md_rentxn_t * rtxnp)11920Sstevel@tonic-gate dump_txn(md_rentxn_t *rtxnp) {
11930Sstevel@tonic-gate 
11940Sstevel@tonic-gate 	if (md_rename_debug == 0) {
11950Sstevel@tonic-gate 		return;
11960Sstevel@tonic-gate 	}
11970Sstevel@tonic-gate 
11980Sstevel@tonic-gate 	cmn_err(CE_NOTE, "rtxnp: %p", (void *) rtxnp);
11990Sstevel@tonic-gate 	if (rtxnp) {
12000Sstevel@tonic-gate 		cmn_err(CE_NOTE, "beginning: %llx, op: %s",
12010Sstevel@tonic-gate 			rtxnp->beginning, OP_STR(rtxnp->op));
12020Sstevel@tonic-gate 
12030Sstevel@tonic-gate 		cmn_err(CE_NOTE,
12040Sstevel@tonic-gate 	"revision: %d, uflags: %d, rec_idx: %d, n_recids: %d, rec_ids: %p%s",
12050Sstevel@tonic-gate 			rtxnp->revision, rtxnp->uflags,
12060Sstevel@tonic-gate 			rtxnp->rec_idx, rtxnp->n_recids, (void *) rtxnp->recids,
12070Sstevel@tonic-gate 			rtxnp->stat.trans_in_stack? " (trans in stack)": "");
12080Sstevel@tonic-gate 		cmn_err(CE_NOTE, " from: beginning: %llx",
12090Sstevel@tonic-gate 							rtxnp->from.beginning);
12100Sstevel@tonic-gate 		cmn_err(CE_NOTE, "    minor: %lX, key: %lX",
12110Sstevel@tonic-gate 			(ulong_t)rtxnp->from.mnum, (ulong_t)rtxnp->from.key);
12120Sstevel@tonic-gate 		cmn_err(CE_NOTE, "    unp: %lX, uip: %lX",
12130Sstevel@tonic-gate 			(ulong_t)rtxnp->from.unp, (ulong_t)rtxnp->from.uip);
12140Sstevel@tonic-gate 		cmn_err(CE_NOTE, "    end: %llx", rtxnp->from.end);
12150Sstevel@tonic-gate 		cmn_err(CE_NOTE, "  to: beginning: %llx", rtxnp->to.beginning);
12160Sstevel@tonic-gate 		cmn_err(CE_NOTE, "    minor: %lX, key: %lX",
12170Sstevel@tonic-gate 			(ulong_t)rtxnp->to.mnum, (ulong_t)rtxnp->to.key);
12180Sstevel@tonic-gate 		cmn_err(CE_NOTE, "    unp: %lX, uip: %lX",
12190Sstevel@tonic-gate 			(ulong_t)rtxnp->to.unp, (ulong_t)rtxnp->to.uip);
12200Sstevel@tonic-gate 		cmn_err(CE_NOTE, "    end: %llx", rtxnp->to.end);
12210Sstevel@tonic-gate 		cmn_err(CE_NOTE, "end: %llx\n", rtxnp->end);
12220Sstevel@tonic-gate 	}
12230Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
12240Sstevel@tonic-gate }
12250Sstevel@tonic-gate 
12260Sstevel@tonic-gate /*
12270Sstevel@tonic-gate  * dump contents of all deltas
12280Sstevel@tonic-gate  */
12290Sstevel@tonic-gate static void
dump_dtree(md_rendelta_t * family)12300Sstevel@tonic-gate dump_dtree(md_rendelta_t *family)
12310Sstevel@tonic-gate {
12320Sstevel@tonic-gate 	md_rendelta_t	*r;
12330Sstevel@tonic-gate 	int		i;
12340Sstevel@tonic-gate 
12350Sstevel@tonic-gate 	if (md_rename_debug == 0) {
12360Sstevel@tonic-gate 		return;
12370Sstevel@tonic-gate 	}
12380Sstevel@tonic-gate 
12390Sstevel@tonic-gate 	for (r = family, i = 0; r; r = r->next, i++) {
12400Sstevel@tonic-gate 		cmn_err(CE_NOTE, "%d.  beginning: %llx", i, r->beginning);
12410Sstevel@tonic-gate 		cmn_err(CE_NOTE, "  r: %lX, dev: %lX, next: %lx, prev: %lx",
12420Sstevel@tonic-gate 					(ulong_t)r, (ulong_t)r->dev,
12430Sstevel@tonic-gate 					(ulong_t)r->next, (ulong_t)r->prev);
12440Sstevel@tonic-gate 
12450Sstevel@tonic-gate 		cmn_err(CE_NOTE, "  role: %s -> %s, unp: %lx, uip: %lx",
12460Sstevel@tonic-gate 			ROLE(r->old_role), ROLE(r->new_role),
12470Sstevel@tonic-gate 			(ulong_t)r->unp, (ulong_t)r->uip);
12480Sstevel@tonic-gate 		cmn_err(CE_NOTE,
12490Sstevel@tonic-gate 		"  lock: %lx, unlock: %lx\n\t  check: %lx, role_swap: %lx",
12500Sstevel@tonic-gate 			(ulong_t)r->lock, (ulong_t)r->unlock,
12510Sstevel@tonic-gate 			(ulong_t)r->check, (ulong_t)r->role_swap);
12520Sstevel@tonic-gate 		if (*((uint_t *)(&r->txn_stat)) != 0) {
12530Sstevel@tonic-gate 			cmn_err(CE_NOTE, "status: (0x%x) %s%s%s%s%s",
12540Sstevel@tonic-gate 			*((uint_t *)(&r->txn_stat)),
12550Sstevel@tonic-gate 			r->txn_stat.is_open?		"is_open "	: "",
12560Sstevel@tonic-gate 			r->txn_stat.locked?		"locked "	: "",
12570Sstevel@tonic-gate 			r->txn_stat.checked?		"checked "	: "",
12580Sstevel@tonic-gate 			r->txn_stat.role_swapped?	"role_swapped "	: "",
12590Sstevel@tonic-gate 			r->txn_stat.unlocked?		"unlocked"	: "");
12600Sstevel@tonic-gate 		}
12610Sstevel@tonic-gate 		cmn_err(CE_NOTE, "end: %llx\n", r->end);
12620Sstevel@tonic-gate 	}
12630Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
12640Sstevel@tonic-gate }
12650Sstevel@tonic-gate 
12660Sstevel@tonic-gate /*
12670Sstevel@tonic-gate  * validate the rename request parameters
12680Sstevel@tonic-gate  */
12690Sstevel@tonic-gate static int
validate_txn_parms(md_rentxn_t * rtxnp)12700Sstevel@tonic-gate validate_txn_parms(md_rentxn_t *rtxnp)
12710Sstevel@tonic-gate {
12720Sstevel@tonic-gate 	minor_t	to_min, from_min;
12730Sstevel@tonic-gate 
12740Sstevel@tonic-gate 	ASSERT(rtxnp);
12750Sstevel@tonic-gate 
12760Sstevel@tonic-gate 	from_min = rtxnp->from.mnum;
12770Sstevel@tonic-gate 	to_min = rtxnp->to.mnum;
12780Sstevel@tonic-gate 
12790Sstevel@tonic-gate 	switch (rtxnp->revision) {
12800Sstevel@tonic-gate 	case MD_RENAME_VERSION_OFFLINE:
12810Sstevel@tonic-gate 		if (rtxnp->uflags != 0) {
12820Sstevel@tonic-gate 			(void) mdmderror(&rtxnp->mde, MDE_RENAME_CONFIG_ERROR,
12830Sstevel@tonic-gate 								from_min);
12840Sstevel@tonic-gate 			return (ENOTSUP);
12850Sstevel@tonic-gate 		}
12860Sstevel@tonic-gate 		break;
12870Sstevel@tonic-gate 
12880Sstevel@tonic-gate 	case MD_RENAME_VERSION_ONLINE:
12890Sstevel@tonic-gate 		/* not supported until 5.0 */
12900Sstevel@tonic-gate 		/* FALLTHROUGH */
12910Sstevel@tonic-gate 
12920Sstevel@tonic-gate 	default:
12930Sstevel@tonic-gate 		(void) mdmderror(&rtxnp->mde, MDE_RENAME_CONFIG_ERROR,
12940Sstevel@tonic-gate 								from_min);
12950Sstevel@tonic-gate 		return (EPROTONOSUPPORT);
12960Sstevel@tonic-gate 	}
12970Sstevel@tonic-gate 
12980Sstevel@tonic-gate 	if ((rtxnp->from.uip = MDI_UNIT(from_min)) == NULL) {
12990Sstevel@tonic-gate 		(void) mdmderror(&rtxnp->mde, MDE_UNIT_NOT_SETUP, from_min);
13000Sstevel@tonic-gate 		return (ENODEV);
13010Sstevel@tonic-gate 	}
13020Sstevel@tonic-gate 
13030Sstevel@tonic-gate 	if (!md_dev_exists(md_makedevice(md_major, from_min))) {
13040Sstevel@tonic-gate 		(void) mdmderror(&rtxnp->mde, MDE_UNIT_NOT_SETUP, from_min);
13050Sstevel@tonic-gate 		return (ENODEV);
13060Sstevel@tonic-gate 	}
13070Sstevel@tonic-gate 
13080Sstevel@tonic-gate 	if ((rtxnp->from.key == MD_KEYBAD) || (rtxnp->from.key == MD_KEYWILD)) {
13090Sstevel@tonic-gate 		(void) mdmderror(&rtxnp->mde, MDE_INVAL_UNIT, from_min);
13100Sstevel@tonic-gate 		return (EINVAL);
13110Sstevel@tonic-gate 	}
13120Sstevel@tonic-gate 
13130Sstevel@tonic-gate 	rtxnp->from.kstatp = rtxnp->from.uip->ui_kstat;
13140Sstevel@tonic-gate 	rtxnp->from.unp = MD_UNIT(from_min);
13150Sstevel@tonic-gate 
13160Sstevel@tonic-gate 	if (MD_MIN2SET(to_min) != MD_MIN2SET(from_min)) {
13170Sstevel@tonic-gate 		(void) mdmderror(&rtxnp->mde, MDE_INVAL_UNIT, to_min);
13180Sstevel@tonic-gate 		return (EINVAL);
13190Sstevel@tonic-gate 	}
13200Sstevel@tonic-gate 
13210Sstevel@tonic-gate 	switch (rtxnp->op) {
13220Sstevel@tonic-gate 	case MDRNOP_EXCHANGE:
13230Sstevel@tonic-gate 		rtxnp->to.unp = MD_UNIT(to_min);
13240Sstevel@tonic-gate 		rtxnp->to.uip = MDI_UNIT(to_min);
13250Sstevel@tonic-gate 
13260Sstevel@tonic-gate 		/*
13270Sstevel@tonic-gate 		 * exchange requires target to exist
13280Sstevel@tonic-gate 		 */
13290Sstevel@tonic-gate 
13300Sstevel@tonic-gate 		if ((rtxnp->to.uip == NULL) ||
13310Sstevel@tonic-gate 		    (md_dev_exists(md_makedevice(md_major, to_min)) == NULL)) {
13320Sstevel@tonic-gate 			(void) mdmderror(&rtxnp->mde, MDE_UNIT_NOT_SETUP,
13330Sstevel@tonic-gate 									to_min);
13340Sstevel@tonic-gate 			return (ENODEV);
13350Sstevel@tonic-gate 		}
13360Sstevel@tonic-gate 
13370Sstevel@tonic-gate 		if ((rtxnp->to.key == MD_KEYBAD) ||
13380Sstevel@tonic-gate 		    (rtxnp->to.key == MD_KEYWILD)) {
13390Sstevel@tonic-gate 			(void) mdmderror(&rtxnp->mde, MDE_INVAL_UNIT, to_min);
13400Sstevel@tonic-gate 			return (EINVAL);
13410Sstevel@tonic-gate 		}
13420Sstevel@tonic-gate 
13430Sstevel@tonic-gate 		/*
13440Sstevel@tonic-gate 		 * <from> is not in the role of <self>,
13450Sstevel@tonic-gate 		 * that is,
13460Sstevel@tonic-gate 		 * <from> has a parent, which is <to> and <to> has a parent too
13470Sstevel@tonic-gate 		 * or
13480Sstevel@tonic-gate 		 * <to> has a parent, which is <from> and <to> can have a child
13490Sstevel@tonic-gate 		 */
13500Sstevel@tonic-gate 		if ((MD_HAS_PARENT(MD_PARENT(rtxnp->from.unp))) &&
13510Sstevel@tonic-gate 		    (MD_PARENT(rtxnp->from.unp) == to_min) &&
13520Sstevel@tonic-gate 		    MD_HAS_PARENT(MD_PARENT(rtxnp->to.unp))) {
13530Sstevel@tonic-gate 			(void) mdmderror(&rtxnp->mde, MDE_RENAME_ORDER,
13540Sstevel@tonic-gate 								from_min);
13550Sstevel@tonic-gate 			return (EINVAL);
13560Sstevel@tonic-gate 		}
13570Sstevel@tonic-gate 
13580Sstevel@tonic-gate 		if ((MD_HAS_PARENT(MD_PARENT(rtxnp->to.unp))) &&
13590Sstevel@tonic-gate 		    (MD_PARENT(rtxnp->to.unp) == from_min) &&
13600Sstevel@tonic-gate 		    (MD_CAPAB(rtxnp->to.unp) & MD_CAN_META_CHILD)) {
13610Sstevel@tonic-gate 			(void) mdmderror(&rtxnp->mde, MDE_RENAME_ORDER,
13620Sstevel@tonic-gate 								from_min);
13630Sstevel@tonic-gate 			return (EINVAL);
13640Sstevel@tonic-gate 		}
13650Sstevel@tonic-gate 
13660Sstevel@tonic-gate 		rtxnp->to.kstatp = rtxnp->to.uip->ui_kstat;
13670Sstevel@tonic-gate 		break;
13680Sstevel@tonic-gate 
13690Sstevel@tonic-gate 	case MDRNOP_RENAME:
13700Sstevel@tonic-gate 
13710Sstevel@tonic-gate 		/*
13720Sstevel@tonic-gate 		 * rename requires <to> not to exist
13730Sstevel@tonic-gate 		 */
13740Sstevel@tonic-gate 
13750Sstevel@tonic-gate 		if (MDI_UNIT(to_min) ||
13760Sstevel@tonic-gate 		    md_dev_exists(md_makedevice(md_major, to_min))) {
13770Sstevel@tonic-gate 
13780Sstevel@tonic-gate 			(void) mdmderror(&rtxnp->mde, MDE_UNIT_ALREADY_SETUP,
13790Sstevel@tonic-gate 									to_min);
13800Sstevel@tonic-gate 			return (EEXIST);
13810Sstevel@tonic-gate 		}
13820Sstevel@tonic-gate 
13830Sstevel@tonic-gate 		/*
13840Sstevel@tonic-gate 		 * and to be within valid ranges for the current
13850Sstevel@tonic-gate 		 * limits on number of sets and metadevices
13860Sstevel@tonic-gate 		 */
13870Sstevel@tonic-gate 		if ((MD_MIN2SET(to_min) >= md_nsets) ||
13880Sstevel@tonic-gate 		    (MD_MIN2UNIT(to_min) >= md_nunits)) {
13890Sstevel@tonic-gate 			(void) mdmderror(&rtxnp->mde, MDE_INVAL_UNIT, to_min);
13900Sstevel@tonic-gate 			return (EINVAL);
13910Sstevel@tonic-gate 		}
13920Sstevel@tonic-gate 
13930Sstevel@tonic-gate 		rtxnp->to.unp = NULL;
13940Sstevel@tonic-gate 		rtxnp->to.uip = NULL;
13950Sstevel@tonic-gate 		rtxnp->to.kstatp = NULL;
13960Sstevel@tonic-gate 		break;
13970Sstevel@tonic-gate 
13980Sstevel@tonic-gate 	default:
13990Sstevel@tonic-gate 		(void) mdmderror(&rtxnp->mde, MDE_RENAME_CONFIG_ERROR,
14000Sstevel@tonic-gate 								from_min);
14010Sstevel@tonic-gate 		return (EINVAL);
14020Sstevel@tonic-gate 	}
14030Sstevel@tonic-gate 
14040Sstevel@tonic-gate 	/*
14050Sstevel@tonic-gate 	 * install guard rails
14060Sstevel@tonic-gate 	 */
14070Sstevel@tonic-gate 	rtxnp->beginning = TXN_BEG;
14080Sstevel@tonic-gate 
14090Sstevel@tonic-gate 	rtxnp->from.beginning	= TXNUN_BEG;
14100Sstevel@tonic-gate 	rtxnp->from.end		= TXNUN_END;
14110Sstevel@tonic-gate 
14120Sstevel@tonic-gate 	rtxnp->to.beginning	= TXNUN_BEG;
14130Sstevel@tonic-gate 	rtxnp->to.end		= TXNUN_END;
14140Sstevel@tonic-gate 
14150Sstevel@tonic-gate 	rtxnp->end = TXN_END;
14160Sstevel@tonic-gate 
14170Sstevel@tonic-gate 	return (0);
14180Sstevel@tonic-gate }
14190Sstevel@tonic-gate 
14200Sstevel@tonic-gate /*
14210Sstevel@tonic-gate  * If the device being changed exhibits this capability, set the list
14220Sstevel@tonic-gate  * relatives function pointer to the named service that lists the
14230Sstevel@tonic-gate  * appropriate relatives for this capability.
14240Sstevel@tonic-gate  */
14250Sstevel@tonic-gate static int
set_list_rels_funcp(md_rentxn_t * rtxnp,md_stackcap_t capability,char * svc_name,md_ren_list_svc_t default_svc_func,md_ren_list_svc_t ** list_relatives_funcp)14260Sstevel@tonic-gate set_list_rels_funcp(
14270Sstevel@tonic-gate 	md_rentxn_t		 *rtxnp,
14280Sstevel@tonic-gate 	md_stackcap_t		 capability,
14290Sstevel@tonic-gate 	char			 *svc_name,
14300Sstevel@tonic-gate 	md_ren_list_svc_t	 default_svc_func,
14310Sstevel@tonic-gate 	md_ren_list_svc_t	 **list_relatives_funcp
14320Sstevel@tonic-gate )
14330Sstevel@tonic-gate {
14340Sstevel@tonic-gate 	int		 err;
14350Sstevel@tonic-gate 	minor_t		 from_min;
14360Sstevel@tonic-gate 	md_dev64_t	 from_dev;
14370Sstevel@tonic-gate 	md_unit_t	*from_un;
14380Sstevel@tonic-gate 	mdi_unit_t	*from_ui;
14390Sstevel@tonic-gate 
14400Sstevel@tonic-gate 	ASSERT(rtxnp);
14410Sstevel@tonic-gate 	ASSERT((rtxnp->op == MDRNOP_RENAME) || (rtxnp->op == MDRNOP_EXCHANGE));
14420Sstevel@tonic-gate 	ASSERT(list_relatives_funcp);
14430Sstevel@tonic-gate 
14440Sstevel@tonic-gate 	from_min	= rtxnp->from.mnum;
14450Sstevel@tonic-gate 	from_dev	= md_makedevice(md_major, from_min);
14460Sstevel@tonic-gate 	from_un		= MD_UNIT(from_min);
14470Sstevel@tonic-gate 	from_ui		= MDI_UNIT(from_min);
14480Sstevel@tonic-gate 	err		= 0;
14490Sstevel@tonic-gate 
14500Sstevel@tonic-gate 	if (!from_ui || !from_un) {
14510Sstevel@tonic-gate 		(void) mdmderror(&rtxnp->mde, MDE_UNIT_NOT_SETUP, from_min);
14520Sstevel@tonic-gate 		err = EINVAL;
14530Sstevel@tonic-gate 		goto out;
14540Sstevel@tonic-gate 	}
14550Sstevel@tonic-gate 
14560Sstevel@tonic-gate 	if ((capability == MD_CAN_DO_ANYTHING) ||
14570Sstevel@tonic-gate 	    ((MD_CAPAB(from_un) & capability) == capability)) {
14580Sstevel@tonic-gate 
14590Sstevel@tonic-gate 			*list_relatives_funcp = (md_ren_list_svc_t *)
14600Sstevel@tonic-gate 					md_get_named_service(from_dev,
14610Sstevel@tonic-gate 					/* modindex */ 0, svc_name,
14620Sstevel@tonic-gate 					(intptr_t (*)()) default_svc_func);
14630Sstevel@tonic-gate 
14640Sstevel@tonic-gate 			ASSERT(*list_relatives_funcp);
14650Sstevel@tonic-gate 			if (!(*list_relatives_funcp)) {
14660Sstevel@tonic-gate 				(void) mdmderror(&rtxnp->mde,
14670Sstevel@tonic-gate 					MDE_RENAME_CONFIG_ERROR, from_min);
14680Sstevel@tonic-gate 				err = EINVAL;
14690Sstevel@tonic-gate 				goto out;
14700Sstevel@tonic-gate 			}
14710Sstevel@tonic-gate 	} else {
14720Sstevel@tonic-gate 		*list_relatives_funcp = (md_ren_list_svc_t *)NULL;
14730Sstevel@tonic-gate 	}
14740Sstevel@tonic-gate 
14750Sstevel@tonic-gate out:
14760Sstevel@tonic-gate 	return (err);
14770Sstevel@tonic-gate }
14780Sstevel@tonic-gate 
14790Sstevel@tonic-gate /*
14800Sstevel@tonic-gate  * call list relations function, bump recid counter
14810Sstevel@tonic-gate  * by number of members added to the delta list.
14820Sstevel@tonic-gate  * Validate that the number of members added is within bounds.
14830Sstevel@tonic-gate  */
14840Sstevel@tonic-gate static int
list_relations(md_rendelta_t ** family,md_rentxn_t * rtxnp,md_ren_list_svc_t * add_relatives_funcp,int valid_min,int valid_max)14850Sstevel@tonic-gate list_relations(
14860Sstevel@tonic-gate 		md_rendelta_t		**family,
14870Sstevel@tonic-gate 		md_rentxn_t		 *rtxnp,
14880Sstevel@tonic-gate 		md_ren_list_svc_t	 *add_relatives_funcp,
14890Sstevel@tonic-gate 		int			  valid_min,
14900Sstevel@tonic-gate 		int			  valid_max
14910Sstevel@tonic-gate )
14920Sstevel@tonic-gate {
14930Sstevel@tonic-gate 	int	n_added;
14940Sstevel@tonic-gate 	int	err = 0;
14950Sstevel@tonic-gate 
14960Sstevel@tonic-gate 	ASSERT(family);
14970Sstevel@tonic-gate 	ASSERT(rtxnp);
14980Sstevel@tonic-gate 
14990Sstevel@tonic-gate 	if (!family || !rtxnp) {
15000Sstevel@tonic-gate 		err = EINVAL;
15010Sstevel@tonic-gate 		goto out;
15020Sstevel@tonic-gate 	}
15030Sstevel@tonic-gate 
15040Sstevel@tonic-gate 	n_added = 0;
15050Sstevel@tonic-gate 
15060Sstevel@tonic-gate 	/* no relations of this type */
15070Sstevel@tonic-gate 	if (!add_relatives_funcp) {
15080Sstevel@tonic-gate 		goto out;
15090Sstevel@tonic-gate 	}
15100Sstevel@tonic-gate 
15110Sstevel@tonic-gate 	n_added = (*add_relatives_funcp) (family, rtxnp);
15120Sstevel@tonic-gate 
15130Sstevel@tonic-gate 	if ((n_added < valid_min) || (n_added > valid_max)) {
15140Sstevel@tonic-gate 		if (mdisok(&rtxnp->mde)) {
15150Sstevel@tonic-gate 			(void) mdmderror(&rtxnp->mde, MDE_RENAME_CONFIG_ERROR,
15160Sstevel@tonic-gate 							rtxnp->from.mnum);
15170Sstevel@tonic-gate 		}
15180Sstevel@tonic-gate 		err = EINVAL;
15190Sstevel@tonic-gate 		goto out;
15200Sstevel@tonic-gate 	}
15210Sstevel@tonic-gate 
15220Sstevel@tonic-gate 	rtxnp->n_recids += n_added;
15230Sstevel@tonic-gate 
15240Sstevel@tonic-gate out:
15250Sstevel@tonic-gate 	return (err);
15260Sstevel@tonic-gate }
15270Sstevel@tonic-gate 
15280Sstevel@tonic-gate /*
15290Sstevel@tonic-gate  * build recid array
15300Sstevel@tonic-gate  */
15310Sstevel@tonic-gate static int
alloc_recids(md_rendelta_t * family,md_rentxn_t * rtxnp)15320Sstevel@tonic-gate alloc_recids(md_rendelta_t *family, md_rentxn_t *rtxnp)
15330Sstevel@tonic-gate {
15340Sstevel@tonic-gate 	int	err	= 0;
15350Sstevel@tonic-gate 
15360Sstevel@tonic-gate 	if (!family || !rtxnp) {
15370Sstevel@tonic-gate 		err = ENOMEM;
15380Sstevel@tonic-gate 		goto out;
15390Sstevel@tonic-gate 	}
15400Sstevel@tonic-gate 
15410Sstevel@tonic-gate 	rtxnp->rec_idx = 0;
15420Sstevel@tonic-gate 
15430Sstevel@tonic-gate 	if (rtxnp->n_recids == 0) {
15440Sstevel@tonic-gate 		err = EINVAL;
15450Sstevel@tonic-gate 		goto out;
15460Sstevel@tonic-gate 	}
15470Sstevel@tonic-gate 
15480Sstevel@tonic-gate 	rtxnp->n_recids += 1;	/* terminator */
15490Sstevel@tonic-gate 
15500Sstevel@tonic-gate 	rtxnp->recids = kmem_alloc(sizeof (mddb_recid_t) * rtxnp->n_recids,
15510Sstevel@tonic-gate 	    KM_SLEEP);
15520Sstevel@tonic-gate 	if (!(rtxnp->recids)) {
15530Sstevel@tonic-gate 		err = ENOMEM;
15540Sstevel@tonic-gate 		goto out;
15550Sstevel@tonic-gate 	}
15560Sstevel@tonic-gate 
15570Sstevel@tonic-gate 	bzero((void *) rtxnp->recids,
15580Sstevel@tonic-gate 				(sizeof (mddb_recid_t) * rtxnp->n_recids));
15590Sstevel@tonic-gate out:
15600Sstevel@tonic-gate 	if (err != 0) {
15610Sstevel@tonic-gate 		(void) mdsyserror(&rtxnp->mde, err);
15620Sstevel@tonic-gate 	}
15630Sstevel@tonic-gate 
15640Sstevel@tonic-gate 	return (err);
15650Sstevel@tonic-gate }
15660Sstevel@tonic-gate 
15670Sstevel@tonic-gate /*
15680Sstevel@tonic-gate  * build family tree (parent(s), self, children)
15690Sstevel@tonic-gate  * The order of the resultant list is important, as it governs
15700Sstevel@tonic-gate  * the order of locking, checking and changing the unit structures.
15710Sstevel@tonic-gate  * Since we'll be changing them, we may not use the MD_UNIT, MDI_UNIT,
15720Sstevel@tonic-gate  * and other pointer which depend on the array being correct.
15730Sstevel@tonic-gate  * Use only the cached pointers (in rtxnp.)
15740Sstevel@tonic-gate  */
15750Sstevel@tonic-gate static md_rendelta_t *
build_dtree(md_rentxn_t * rtxnp)15760Sstevel@tonic-gate build_dtree(md_rentxn_t *rtxnp)
15770Sstevel@tonic-gate {
15780Sstevel@tonic-gate 	md_ren_list_svc_t	*add_folks, *add_self, *add_kids;
15790Sstevel@tonic-gate 	int			 err;
15800Sstevel@tonic-gate 	md_rendelta_t		*family	= NULL;
15810Sstevel@tonic-gate 
15820Sstevel@tonic-gate 	ASSERT(rtxnp);
15830Sstevel@tonic-gate 	ASSERT((rtxnp->op == MDRNOP_RENAME) || (rtxnp->op == MDRNOP_EXCHANGE));
15840Sstevel@tonic-gate 
15850Sstevel@tonic-gate 	err = set_list_rels_funcp(rtxnp, MD_CAN_PARENT, MDRNM_LIST_URFOLKS,
15860Sstevel@tonic-gate 					md_rename_listfolks, &add_folks);
15870Sstevel@tonic-gate 
15880Sstevel@tonic-gate 	if (err) {
15890Sstevel@tonic-gate 		goto out;
15900Sstevel@tonic-gate 	}
15910Sstevel@tonic-gate 
15920Sstevel@tonic-gate 	err = set_list_rels_funcp(rtxnp, MD_CAN_DO_ANYTHING, MDRNM_LIST_URSELF,
15930Sstevel@tonic-gate 						md_rename_listself, &add_self);
15940Sstevel@tonic-gate 	if (err) {
15950Sstevel@tonic-gate 		goto out;
15960Sstevel@tonic-gate 	}
15970Sstevel@tonic-gate 
15980Sstevel@tonic-gate 	err = set_list_rels_funcp(rtxnp, MD_CAN_META_CHILD, MDRNM_LIST_URKIDS,
15990Sstevel@tonic-gate 				/* no default list func */ ((int (*)()) NULL),
16000Sstevel@tonic-gate 								&add_kids);
16010Sstevel@tonic-gate 	if (err) {
16020Sstevel@tonic-gate 		goto out;
16030Sstevel@tonic-gate 	}
16040Sstevel@tonic-gate 
16050Sstevel@tonic-gate 	rtxnp->n_recids = 0;	/* accumulated by list_relations() */
16060Sstevel@tonic-gate 
16070Sstevel@tonic-gate 	if ((err = list_relations(&family, rtxnp, add_folks, 0, 1)) != 0) {
16080Sstevel@tonic-gate 		goto out;
16090Sstevel@tonic-gate 	}
16100Sstevel@tonic-gate 
16110Sstevel@tonic-gate 	if ((err = list_relations(&family, rtxnp, add_self, 1, 1)) != 0) {
16120Sstevel@tonic-gate 		goto out;
16130Sstevel@tonic-gate 	}
16140Sstevel@tonic-gate 
16150Sstevel@tonic-gate 	err = list_relations(&family, rtxnp, add_kids, 0, md_nunits);
16160Sstevel@tonic-gate 	if (err != 0) {
16170Sstevel@tonic-gate 		goto out;
16180Sstevel@tonic-gate 	}
16190Sstevel@tonic-gate 
16200Sstevel@tonic-gate 	/*
16210Sstevel@tonic-gate 	 * delta tree is still empty?
16220Sstevel@tonic-gate 	 */
16230Sstevel@tonic-gate 	if ((!family) || (rtxnp->n_recids == 0)) {
16240Sstevel@tonic-gate 		(void) mdmderror(&rtxnp->mde, MDE_RENAME_CONFIG_ERROR,
16250Sstevel@tonic-gate 							rtxnp->from.mnum);
16260Sstevel@tonic-gate 		err = EINVAL;
16270Sstevel@tonic-gate 		goto out;
16280Sstevel@tonic-gate 	}
16290Sstevel@tonic-gate 
16300Sstevel@tonic-gate 	/*
16310Sstevel@tonic-gate 	 * verify role change interactions
16320Sstevel@tonic-gate 	 */
16330Sstevel@tonic-gate 	if ((err = valid_roleswap_dtree(family, rtxnp)) != 0) {
16340Sstevel@tonic-gate 		goto out;
16350Sstevel@tonic-gate 	}
16360Sstevel@tonic-gate 
16370Sstevel@tonic-gate 	if ((err = alloc_recids(family, rtxnp)) != 0) {
16380Sstevel@tonic-gate 		goto out;
16390Sstevel@tonic-gate 	}
16400Sstevel@tonic-gate 
16410Sstevel@tonic-gate out:
16420Sstevel@tonic-gate 	if (err != 0) {
16430Sstevel@tonic-gate 		free_dtree(family);
16440Sstevel@tonic-gate 		dump_dtree(family);	/* yes, after freeing it */
16450Sstevel@tonic-gate 		family = NULL;
16460Sstevel@tonic-gate 	}
16470Sstevel@tonic-gate 
16480Sstevel@tonic-gate 	return (family);
16490Sstevel@tonic-gate }
16500Sstevel@tonic-gate 
16510Sstevel@tonic-gate 
16520Sstevel@tonic-gate /*
16530Sstevel@tonic-gate  * (MD_IOCRENAME) rename/exchange ioctl entry point
16540Sstevel@tonic-gate  * calls individual driver named service entry points
16550Sstevel@tonic-gate  * to build a list of devices which need state changed,
16560Sstevel@tonic-gate  * to verify that they're in a state where renames may occur,
16570Sstevel@tonic-gate  * and to modify themselves into their new identities
16580Sstevel@tonic-gate  */
16590Sstevel@tonic-gate 
16600Sstevel@tonic-gate int
md_rename(md_rename_t * mrp,IOLOCK * iolockp)16610Sstevel@tonic-gate md_rename(
16620Sstevel@tonic-gate 	md_rename_t	*mrp,
16630Sstevel@tonic-gate 	IOLOCK		*iolockp)
16640Sstevel@tonic-gate {
16650Sstevel@tonic-gate 	md_rendelta_t	*family		= NULL;
16661623Stw21770 	md_rentxn_t	rtxn;
16671623Stw21770 	int		err		= 0;
16681623Stw21770 	set_t		setno;
16691623Stw21770 	mdc_unit_t	*mdc;
16700Sstevel@tonic-gate 
16710Sstevel@tonic-gate 	ASSERT(iolockp);
16720Sstevel@tonic-gate 	if (mrp == NULL)
16730Sstevel@tonic-gate 		return (EINVAL);
16740Sstevel@tonic-gate 
16751623Stw21770 	setno = MD_MIN2SET(mrp->from.mnum);
16761623Stw21770 	if (setno >= md_nsets) {
16771623Stw21770 		return (EINVAL);
16781623Stw21770 	}
16791623Stw21770 
16801623Stw21770 	/*
16811623Stw21770 	 * Early exit if top is eof trans
16821623Stw21770 	 */
16831623Stw21770 	mdc = (mdc_unit_t *)md_set[setno].s_un[MD_MIN2UNIT(mrp->from.mnum)];
16841623Stw21770 	while (mdc != NULL) {
16851623Stw21770 	    if (!MD_HAS_PARENT(mdc->un_parent)) {
16861623Stw21770 		break;
16871623Stw21770 	    } else {
16881623Stw21770 		mdc = (mdc_unit_t *)md_set[setno].s_un[MD_MIN2UNIT
16891623Stw21770 		    (mdc->un_parent)];
16901623Stw21770 	    }
16911623Stw21770 	}
16921623Stw21770 
16931623Stw21770 	if (mdc && mdc->un_type == MD_METATRANS) {
16941623Stw21770 		return (EINVAL);
16951623Stw21770 	}
16961623Stw21770 
16971623Stw21770 
16980Sstevel@tonic-gate 	mdclrerror(&mrp->mde);
16990Sstevel@tonic-gate 
17000Sstevel@tonic-gate 	bzero((void *) &rtxn, sizeof (md_rentxn_t));
17010Sstevel@tonic-gate 	mdclrerror(&rtxn.mde);
17020Sstevel@tonic-gate 
17030Sstevel@tonic-gate 	/*
17040Sstevel@tonic-gate 	 * encapsulate user parameters
17050Sstevel@tonic-gate 	 */
17060Sstevel@tonic-gate 	rtxn.from.key	= mrp->from.key;
17070Sstevel@tonic-gate 	rtxn.to.key	= mrp->to.key;
17080Sstevel@tonic-gate 	rtxn.from.mnum	= mrp->from.mnum;
17090Sstevel@tonic-gate 	rtxn.to.mnum	= mrp->to.mnum;
17100Sstevel@tonic-gate 	rtxn.op		= mrp->op;
17110Sstevel@tonic-gate 	rtxn.uflags	= mrp->flags;
17120Sstevel@tonic-gate 	rtxn.revision	= mrp->revision;
17130Sstevel@tonic-gate 
17140Sstevel@tonic-gate 	if (MD_MIN2UNIT(mrp->to.mnum) >= md_nunits) {
17150Sstevel@tonic-gate 		err = EINVAL;
17160Sstevel@tonic-gate 		goto cleanup;
17170Sstevel@tonic-gate 	}
17180Sstevel@tonic-gate 
17190Sstevel@tonic-gate 	/*
17200Sstevel@tonic-gate 	 * catch this early, before taking any locks
17210Sstevel@tonic-gate 	 */
17220Sstevel@tonic-gate 	if (md_get_setstatus(setno) & MD_SET_STALE) {
17230Sstevel@tonic-gate 		(void) (mdmddberror(&rtxn.mde, MDE_DB_STALE, rtxn.from.mnum,
17240Sstevel@tonic-gate 						MD_MIN2SET(rtxn.from.mnum)));
17250Sstevel@tonic-gate 		err = EROFS;
17260Sstevel@tonic-gate 		goto cleanup;
17270Sstevel@tonic-gate 	}
17280Sstevel@tonic-gate 
17290Sstevel@tonic-gate 	/*
17300Sstevel@tonic-gate 	 * Locking and re-validation (of the per-unit state) is
17310Sstevel@tonic-gate 	 * done by the rename lock/unlock service, for now only take
17320Sstevel@tonic-gate 	 * the array lock.
17330Sstevel@tonic-gate 	 */
17340Sstevel@tonic-gate 	md_array_writer(iolockp);
17350Sstevel@tonic-gate 
17360Sstevel@tonic-gate 	/*
17370Sstevel@tonic-gate 	 * validate the rename/exchange parameters
17380Sstevel@tonic-gate 	 * rtxn is filled in on succesful completion of validate_txn_parms()
17390Sstevel@tonic-gate 	 */
17400Sstevel@tonic-gate 	if ((err = validate_txn_parms(&rtxn)) != 0) {
17410Sstevel@tonic-gate 		goto cleanup;
17420Sstevel@tonic-gate 	}
17430Sstevel@tonic-gate 
17440Sstevel@tonic-gate 	/*
17450Sstevel@tonic-gate 	 * build list of work to do, the "delta tree" for related devices
17460Sstevel@tonic-gate 	 */
17470Sstevel@tonic-gate 	if (!(family = build_dtree(&rtxn))) {
17480Sstevel@tonic-gate 		err = ENOMEM;
17490Sstevel@tonic-gate 		goto cleanup;
17500Sstevel@tonic-gate 	}
17510Sstevel@tonic-gate 	dump_txn(&rtxn);
17520Sstevel@tonic-gate 	dump_dtree(family);
17530Sstevel@tonic-gate 
17540Sstevel@tonic-gate 	if ((err = lock_dtree(family, &rtxn)) != 0) {
17550Sstevel@tonic-gate 		goto cleanup;
17560Sstevel@tonic-gate 	}
17570Sstevel@tonic-gate 
17580Sstevel@tonic-gate 	if ((err = check_dtree(family, &rtxn)) != 0) {
17590Sstevel@tonic-gate 		goto cleanup;
17600Sstevel@tonic-gate 	}
17610Sstevel@tonic-gate 	dump_txn(&rtxn);
17620Sstevel@tonic-gate 
17630Sstevel@tonic-gate 	role_swap_dtree(family, &rtxn);	/* commits the recids */
17640Sstevel@tonic-gate 
17650Sstevel@tonic-gate 	/*
17660Sstevel@tonic-gate 	 * let folks know
17670Sstevel@tonic-gate 	 */
17680Sstevel@tonic-gate 	SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_RENAME_SRC, SVM_TAG_METADEVICE,
17690Sstevel@tonic-gate 	    MD_MIN2SET(rtxn.from.mnum), rtxn.from.mnum);
17700Sstevel@tonic-gate 	SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_RENAME_DST, SVM_TAG_METADEVICE,
17710Sstevel@tonic-gate 	    MD_MIN2SET(rtxn.from.mnum), rtxn.from.mnum);
17720Sstevel@tonic-gate 
17730Sstevel@tonic-gate cleanup:
17740Sstevel@tonic-gate 
17750Sstevel@tonic-gate 	if (err != 0 && mdisok(&rtxn.mde)) {
17760Sstevel@tonic-gate 		(void) mdsyserror(&rtxn.mde, EINVAL);
17770Sstevel@tonic-gate 	}
17780Sstevel@tonic-gate 
17790Sstevel@tonic-gate 	if (family) {
17800Sstevel@tonic-gate 		unlock_dtree(family, &rtxn);
17810Sstevel@tonic-gate 		free_dtree(family);
17820Sstevel@tonic-gate 		dump_dtree(family);
17830Sstevel@tonic-gate 		family = NULL;
17840Sstevel@tonic-gate 	}
17850Sstevel@tonic-gate 
17860Sstevel@tonic-gate 	if (rtxn.recids && (rtxn.n_recids > 0)) {
17870Sstevel@tonic-gate 		kmem_free(rtxn.recids, sizeof (mddb_recid_t) * rtxn.n_recids);
17880Sstevel@tonic-gate 	}
17890Sstevel@tonic-gate 
17900Sstevel@tonic-gate 	if (!mdisok(&rtxn.mde)) {
17910Sstevel@tonic-gate 		(void) mdstealerror(&mrp->mde, &rtxn.mde);
17920Sstevel@tonic-gate 	}
17930Sstevel@tonic-gate 
17940Sstevel@tonic-gate 	return (0);	/* success/failure will be communicated via rtxn.mde */
17950Sstevel@tonic-gate }
17960Sstevel@tonic-gate 
17970Sstevel@tonic-gate static role_change_tab_t
17980Sstevel@tonic-gate role_swap_tab[] =
17990Sstevel@tonic-gate {
18000Sstevel@tonic-gate 	{
18010Sstevel@tonic-gate 		1,			/* ordinal */
18020Sstevel@tonic-gate 		MDRR_PARENT,		/* old role */
18030Sstevel@tonic-gate 		MDRR_PARENT,		/* new role */
18040Sstevel@tonic-gate 		MDRNM_UPDATE_KIDS,	/* named service */
18050Sstevel@tonic-gate 		NO_DEFAULT_ROLESWAP_SVC	/* default role swap function */
18060Sstevel@tonic-gate 	},
18070Sstevel@tonic-gate 	{
18080Sstevel@tonic-gate 		2,
18090Sstevel@tonic-gate 		MDRR_PARENT,
18100Sstevel@tonic-gate 		MDRR_SELF,
18110Sstevel@tonic-gate 		MDRNM_PARENT_UPDATE_TO,
18120Sstevel@tonic-gate 		NO_DEFAULT_ROLESWAP_SVC
18130Sstevel@tonic-gate 	},
18140Sstevel@tonic-gate 	{
18150Sstevel@tonic-gate 		3,
18160Sstevel@tonic-gate 		MDRR_PARENT,
18170Sstevel@tonic-gate 		MDRR_CHILD,
18180Sstevel@tonic-gate 		ILLEGAL_SVC_NAME,
18190Sstevel@tonic-gate 		ILLEGAL_ROLESWAP_SVC
18200Sstevel@tonic-gate 	},
18210Sstevel@tonic-gate 	{
18220Sstevel@tonic-gate 		4,
18230Sstevel@tonic-gate 		MDRR_SELF,
18240Sstevel@tonic-gate 		MDRR_PARENT,
18250Sstevel@tonic-gate 		MDRNM_SELF_UPDATE_FROM_UP,
18260Sstevel@tonic-gate 		md_exchange_self_update_from_up
18270Sstevel@tonic-gate 	},
18280Sstevel@tonic-gate 	{
18290Sstevel@tonic-gate 		5,
18300Sstevel@tonic-gate 		MDRR_SELF,
18310Sstevel@tonic-gate 		MDRR_SELF,
18320Sstevel@tonic-gate 		MDRNM_UPDATE_SELF,
18330Sstevel@tonic-gate 		md_rename_update_self
18340Sstevel@tonic-gate 	},
18350Sstevel@tonic-gate 	{
18360Sstevel@tonic-gate 		6,
18370Sstevel@tonic-gate 		MDRR_SELF,
18380Sstevel@tonic-gate 		MDRR_CHILD,
18390Sstevel@tonic-gate 		MDRNM_SELF_UPDATE_FROM_DOWN,
18400Sstevel@tonic-gate 		NO_DEFAULT_ROLESWAP_SVC
18410Sstevel@tonic-gate 	},
18420Sstevel@tonic-gate 	{
18430Sstevel@tonic-gate 		7,
18440Sstevel@tonic-gate 		MDRR_CHILD,
18450Sstevel@tonic-gate 		MDRR_PARENT,
18460Sstevel@tonic-gate 		ILLEGAL_SVC_NAME,
18470Sstevel@tonic-gate 		ILLEGAL_ROLESWAP_SVC
18480Sstevel@tonic-gate 	},
18490Sstevel@tonic-gate 	{
18500Sstevel@tonic-gate 		8,
18510Sstevel@tonic-gate 		MDRR_CHILD,
18520Sstevel@tonic-gate 		MDRR_SELF,
18530Sstevel@tonic-gate 		MDRNM_CHILD_UPDATE_TO,
18540Sstevel@tonic-gate 		md_exchange_child_update_to
18550Sstevel@tonic-gate 	},
18560Sstevel@tonic-gate 	{
18570Sstevel@tonic-gate 		9,
18580Sstevel@tonic-gate 		MDRR_CHILD,
18590Sstevel@tonic-gate 		MDRR_CHILD,
18600Sstevel@tonic-gate 		MDRNM_UPDATE_FOLKS,
18610Sstevel@tonic-gate 		md_renexch_update_parent
18620Sstevel@tonic-gate 	},
18630Sstevel@tonic-gate 
18640Sstevel@tonic-gate 	/* terminator is old_role == MDRR_UNK */
18650Sstevel@tonic-gate 	{
18660Sstevel@tonic-gate 		0,
18670Sstevel@tonic-gate 		MDRR_UNK,
18680Sstevel@tonic-gate 		MDRR_UNK,
18690Sstevel@tonic-gate 		ILLEGAL_SVC_NAME,
18700Sstevel@tonic-gate 		NO_DEFAULT_ROLESWAP_SVC
18710Sstevel@tonic-gate 	}
18720Sstevel@tonic-gate };
1873