xref: /titanic_44/usr/src/uts/sun4v/io/mdeg.c (revision 4e4761498aa6990539820cfc2ee7b1c7c53b6bc3)
11ae08745Sheppo /*
21ae08745Sheppo  * CDDL HEADER START
31ae08745Sheppo  *
41ae08745Sheppo  * The contents of this file are subject to the terms of the
51ae08745Sheppo  * Common Development and Distribution License (the "License").
61ae08745Sheppo  * You may not use this file except in compliance with the License.
71ae08745Sheppo  *
81ae08745Sheppo  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91ae08745Sheppo  * or http://www.opensolaris.org/os/licensing.
101ae08745Sheppo  * See the License for the specific language governing permissions
111ae08745Sheppo  * and limitations under the License.
121ae08745Sheppo  *
131ae08745Sheppo  * When distributing Covered Code, include this CDDL HEADER in each
141ae08745Sheppo  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151ae08745Sheppo  * If applicable, add the following below this CDDL HEADER, with the
161ae08745Sheppo  * fields enclosed by brackets "[]" replaced with your own identifying
171ae08745Sheppo  * information: Portions Copyright [yyyy] [name of copyright owner]
181ae08745Sheppo  *
191ae08745Sheppo  * CDDL HEADER END
201ae08745Sheppo  */
211ae08745Sheppo 
221ae08745Sheppo /*
23*4e476149Srsmaeda  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
241ae08745Sheppo  * Use is subject to license terms.
251ae08745Sheppo  */
261ae08745Sheppo 
271ae08745Sheppo #pragma ident	"%Z%%M%	%I%	%E% SMI"
281ae08745Sheppo 
291ae08745Sheppo /*
301ae08745Sheppo  * MD Event Generator (MDEG) Module
311ae08745Sheppo  */
321ae08745Sheppo 
331ae08745Sheppo #include <sys/machsystm.h>
341ae08745Sheppo #include <sys/taskq.h>
351ae08745Sheppo #include <sys/disp.h>
361ae08745Sheppo #include <sys/cmn_err.h>
371ae08745Sheppo #include <sys/note.h>
381ae08745Sheppo 
391ae08745Sheppo #include <sys/mdeg.h>
401ae08745Sheppo #include <sys/mach_descrip.h>
411ae08745Sheppo #include <sys/mdesc.h>
421ae08745Sheppo 
431ae08745Sheppo /*
441ae08745Sheppo  * A single client registration
451ae08745Sheppo  */
461ae08745Sheppo typedef struct mdeg_clnt {
471ae08745Sheppo 	boolean_t		valid;		/* structure is in active use */
481ae08745Sheppo 	mdeg_node_match_t	*nmatch;	/* node match filter */
491ae08745Sheppo 	mdeg_node_spec_t	*pspec;		/* parent match filter */
501ae08745Sheppo 	mdeg_cb_t		cb;		/* the client callback */
511ae08745Sheppo 	caddr_t			cb_arg;		/* argument to the callback */
521ae08745Sheppo 	uint64_t		magic;		/* sanity checking magic */
531ae08745Sheppo 	mdeg_handle_t		hdl;		/* handle assigned by MDEG */
541ae08745Sheppo } mdeg_clnt_t;
551ae08745Sheppo 
561ae08745Sheppo /*
571ae08745Sheppo  * Global MDEG data
581ae08745Sheppo  *
591ae08745Sheppo  * Locking Strategy:
601ae08745Sheppo  *
61*4e476149Srsmaeda  *   mdeg.lock - lock used to synchronize system-wide MD updates. An
621ae08745Sheppo  *	MD update must be treated as an atomic event. The lock is
631ae08745Sheppo  *	taken when notification that a new MD is available and held
641ae08745Sheppo  *	until all clients have been notified.
651ae08745Sheppo  *
66*4e476149Srsmaeda  *   mdeg.rwlock - lock used to synchronize access to the table of
671ae08745Sheppo  *	registered clients. The reader lock must be held when looking
681ae08745Sheppo  *	up client information in the table. The writer lock must be
691ae08745Sheppo  *	held when modifying any client information.
701ae08745Sheppo  */
711ae08745Sheppo static struct mdeg {
721ae08745Sheppo 	taskq_t 	*taskq;		/* for internal processing */
731ae08745Sheppo 	boolean_t	enabled;	/* enable/disable taskq processing */
741ae08745Sheppo 	kmutex_t	lock;		/* synchronize MD updates */
751ae08745Sheppo 	md_t		*md_prev;	/* previous MD */
761ae08745Sheppo 	md_t		*md_curr;	/* current MD */
771ae08745Sheppo 	mdeg_clnt_t	*tbl;		/* table of registered clients */
781ae08745Sheppo 	krwlock_t	rwlock;		/* client table lock */
791ae08745Sheppo 	uint_t		maxclnts;	/* client table size */
801ae08745Sheppo 	uint_t		nclnts;		/* current number of clients */
811ae08745Sheppo } mdeg;
821ae08745Sheppo 
831ae08745Sheppo /*
841ae08745Sheppo  * Debugging routines
851ae08745Sheppo  */
861ae08745Sheppo #ifdef DEBUG
871ae08745Sheppo uint_t mdeg_debug = 0x0;
881ae08745Sheppo 
891ae08745Sheppo static void mdeg_dump_clnt(mdeg_clnt_t *clnt);
901ae08745Sheppo static void mdeg_dump_table(void);
911ae08745Sheppo 
921ae08745Sheppo #define	MDEG_DBG		if (mdeg_debug) printf
931ae08745Sheppo #define	MDEG_DUMP_CLNT		mdeg_dump_clnt
941ae08745Sheppo #define	MDEG_DUMP_TABLE		mdeg_dump_table
951ae08745Sheppo 
961ae08745Sheppo #else /* DEBUG */
971ae08745Sheppo 
981ae08745Sheppo #define	MDEG_DBG		_NOTE(CONSTCOND) if (0) printf
991ae08745Sheppo #define	MDEG_DUMP_CLNT
1001ae08745Sheppo #define	MDEG_DUMP_TABLE()
1011ae08745Sheppo 
1021ae08745Sheppo #endif /* DEBUG */
1031ae08745Sheppo 
1041ae08745Sheppo /*
1051ae08745Sheppo  * Global constants
1061ae08745Sheppo  */
1071ae08745Sheppo #define	MDEG_MAX_TASKQ_THR	512	/* maximum number of taskq threads */
1081ae08745Sheppo #define	MDEG_MAX_CLNTS_INIT	64	/* initial client table size */
1091ae08745Sheppo 
1101ae08745Sheppo #define	MDEG_MAGIC		0x4D4445475F48444Cull	/* 'MDEG_HDL' */
1111ae08745Sheppo 
1121ae08745Sheppo /*
1131ae08745Sheppo  * A client handle is a 64 bit value with two pieces of
1141ae08745Sheppo  * information encoded in it. The upper 32 bits are the
1151ae08745Sheppo  * index into the table of a particular client structure.
1161ae08745Sheppo  * The lower 32 bits are a counter that is incremented
1171ae08745Sheppo  * each time a client structure is reused.
1181ae08745Sheppo  */
1191ae08745Sheppo #define	MDEG_IDX_SHIFT			32
1201ae08745Sheppo #define	MDEG_COUNT_MASK			0xfffffffful
1211ae08745Sheppo 
1221ae08745Sheppo #define	MDEG_ALLOC_HDL(_idx, _count)	(((uint64_t)_idx << MDEG_IDX_SHIFT) | \
1231ae08745Sheppo 					((uint64_t)(_count + 1) &	      \
1241ae08745Sheppo 					MDEG_COUNT_MASK))
1251ae08745Sheppo #define	MDEG_HDL2IDX(hdl)		(hdl >> MDEG_IDX_SHIFT)
1261ae08745Sheppo #define	MDEG_HDL2COUNT(hdl)		(hdl & MDEG_COUNT_MASK)
1271ae08745Sheppo 
1281ae08745Sheppo static const char trunc_str[] = " ... }";
1291ae08745Sheppo 
1301ae08745Sheppo /*
1311ae08745Sheppo  * Utility routines
1321ae08745Sheppo  */
1331ae08745Sheppo static mdeg_clnt_t *mdeg_alloc_clnt(void);
1341ae08745Sheppo static void mdeg_notify_client(void *);
1351ae08745Sheppo static mde_cookie_t mdeg_find_start_node(md_t *, mdeg_node_spec_t *);
1361ae08745Sheppo static boolean_t mdeg_node_spec_match(md_t *, mde_cookie_t, mdeg_node_spec_t *);
1371ae08745Sheppo static void mdeg_get_diff_results(md_diff_cookie_t, mdeg_result_t *);
1381ae08745Sheppo 
1391ae08745Sheppo int
1401ae08745Sheppo mdeg_init(void)
1411ae08745Sheppo {
1421ae08745Sheppo 	int	tblsz;
1431ae08745Sheppo 
1441ae08745Sheppo 	/*
1451ae08745Sheppo 	 * Grab the current MD
1461ae08745Sheppo 	 */
1471ae08745Sheppo 	if ((mdeg.md_curr = md_get_handle()) == NULL) {
1481ae08745Sheppo 		cmn_err(CE_WARN, "unable to cache snapshot of MD");
1491ae08745Sheppo 		return (-1);
1501ae08745Sheppo 	}
1511ae08745Sheppo 
1521ae08745Sheppo 	/*
1531ae08745Sheppo 	 * Initialize table of registered clients
1541ae08745Sheppo 	 */
1551ae08745Sheppo 	mdeg.maxclnts = MDEG_MAX_CLNTS_INIT;
1561ae08745Sheppo 
1571ae08745Sheppo 	tblsz = mdeg.maxclnts * sizeof (mdeg_clnt_t);
1581ae08745Sheppo 	mdeg.tbl = kmem_zalloc(tblsz, KM_SLEEP);
1591ae08745Sheppo 
1601ae08745Sheppo 	rw_init(&mdeg.rwlock, NULL, RW_DRIVER, NULL);
1611ae08745Sheppo 
1621ae08745Sheppo 	mdeg.nclnts = 0;
1631ae08745Sheppo 
1641ae08745Sheppo 	/*
1651ae08745Sheppo 	 * Initialize global lock
1661ae08745Sheppo 	 */
1671ae08745Sheppo 	mutex_init(&mdeg.lock, NULL, MUTEX_DRIVER, NULL);
1681ae08745Sheppo 
1691ae08745Sheppo 	/*
1701ae08745Sheppo 	 * Initialize the task queue
1711ae08745Sheppo 	 */
1721ae08745Sheppo 	mdeg.taskq = taskq_create("mdeg_taskq", 1, minclsyspri, 1,
1731ae08745Sheppo 	    MDEG_MAX_TASKQ_THR, TASKQ_PREPOPULATE | TASKQ_DYNAMIC);
1741ae08745Sheppo 
1751ae08745Sheppo 	/* ready to begin handling clients */
1761ae08745Sheppo 	mdeg.enabled = B_TRUE;
1771ae08745Sheppo 
1781ae08745Sheppo 	return (0);
1791ae08745Sheppo }
1801ae08745Sheppo 
1811ae08745Sheppo void
1821ae08745Sheppo mdeg_fini(void)
1831ae08745Sheppo {
1841ae08745Sheppo 	/*
1851ae08745Sheppo 	 * Flip the enabled switch off to make sure that
1861ae08745Sheppo 	 * no events get dispatched while things are being
1871ae08745Sheppo 	 * torn down.
1881ae08745Sheppo 	 */
1891ae08745Sheppo 	mdeg.enabled = B_FALSE;
1901ae08745Sheppo 
1911ae08745Sheppo 	/* destroy the task queue */
1921ae08745Sheppo 	taskq_destroy(mdeg.taskq);
1931ae08745Sheppo 
1941ae08745Sheppo 	/*
1951ae08745Sheppo 	 * Deallocate the table of registered clients
1961ae08745Sheppo 	 */
1971ae08745Sheppo 	kmem_free(mdeg.tbl, mdeg.maxclnts * sizeof (mdeg_clnt_t));
1981ae08745Sheppo 	rw_destroy(&mdeg.rwlock);
1991ae08745Sheppo 
2001ae08745Sheppo 	/*
2011ae08745Sheppo 	 * Free up the cached MDs.
2021ae08745Sheppo 	 */
2031ae08745Sheppo 	if (mdeg.md_curr)
2041ae08745Sheppo 		(void) md_fini_handle(mdeg.md_curr);
2051ae08745Sheppo 
2061ae08745Sheppo 	if (mdeg.md_prev)
2071ae08745Sheppo 		(void) md_fini_handle(mdeg.md_prev);
2081ae08745Sheppo 
2091ae08745Sheppo 	mutex_destroy(&mdeg.lock);
2101ae08745Sheppo }
2111ae08745Sheppo 
2121ae08745Sheppo static mdeg_clnt_t *
2131ae08745Sheppo mdeg_alloc_clnt(void)
2141ae08745Sheppo {
2151ae08745Sheppo 	mdeg_clnt_t	*clnt;
2161ae08745Sheppo 	int		idx;
2171ae08745Sheppo 	mdeg_clnt_t	*newtbl;
2181ae08745Sheppo 	uint_t		newmaxclnts;
2191ae08745Sheppo 	uint_t		newtblsz;
2201ae08745Sheppo 	uint_t		oldtblsz;
2211ae08745Sheppo 
2221ae08745Sheppo 	ASSERT(RW_WRITE_HELD(&mdeg.rwlock));
2231ae08745Sheppo 
2241ae08745Sheppo 	/* search for an unused slot in the table */
2251ae08745Sheppo 	for (idx = 0; idx < mdeg.maxclnts; idx++) {
2261ae08745Sheppo 		clnt = &mdeg.tbl[idx];
2271ae08745Sheppo 		if (!clnt->valid) {
2281ae08745Sheppo 			break;
2291ae08745Sheppo 		}
2301ae08745Sheppo 	}
2311ae08745Sheppo 
2321ae08745Sheppo 	/* found any empty slot */
2331ae08745Sheppo 	if (idx != mdeg.maxclnts) {
2341ae08745Sheppo 		goto found;
2351ae08745Sheppo 	}
2361ae08745Sheppo 
2371ae08745Sheppo 	/*
2381ae08745Sheppo 	 * There was no free space in the table. Grow
2391ae08745Sheppo 	 * the table to double its current size.
2401ae08745Sheppo 	 */
2411ae08745Sheppo 
2421ae08745Sheppo 	MDEG_DBG("client table full:\n");
2431ae08745Sheppo 	MDEG_DUMP_TABLE();
2441ae08745Sheppo 
2451ae08745Sheppo 	newmaxclnts = mdeg.maxclnts * 2;
2461ae08745Sheppo 	newtblsz = newmaxclnts * sizeof (mdeg_clnt_t);
2471ae08745Sheppo 
2481ae08745Sheppo 	newtbl = kmem_zalloc(newtblsz, KM_SLEEP);
2491ae08745Sheppo 
2501ae08745Sheppo 	/* copy old table data to the new table */
2511ae08745Sheppo 	oldtblsz = mdeg.maxclnts * sizeof (mdeg_clnt_t);
2521ae08745Sheppo 	bcopy(mdeg.tbl, newtbl, oldtblsz);
2531ae08745Sheppo 
2541ae08745Sheppo 	/*
2551ae08745Sheppo 	 * Since the old table was full, the first free entry
256*4e476149Srsmaeda 	 * will be just past the end of the old table data in
257*4e476149Srsmaeda 	 * the new table.
2581ae08745Sheppo 	 */
259*4e476149Srsmaeda 	clnt = &newtbl[mdeg.maxclnts];
2601ae08745Sheppo 
2611ae08745Sheppo 	/* clean up the old table */
2621ae08745Sheppo 	kmem_free(mdeg.tbl, oldtblsz);
2631ae08745Sheppo 	mdeg.tbl = newtbl;
2641ae08745Sheppo 	mdeg.maxclnts = newmaxclnts;
2651ae08745Sheppo 
2661ae08745Sheppo found:
2671ae08745Sheppo 	ASSERT(clnt->valid == 0);
2681ae08745Sheppo 
2691ae08745Sheppo 	clnt->hdl = MDEG_ALLOC_HDL(idx, MDEG_HDL2COUNT(clnt->hdl));
2701ae08745Sheppo 
2711ae08745Sheppo 	return (clnt);
2721ae08745Sheppo }
2731ae08745Sheppo 
2741ae08745Sheppo static mdeg_clnt_t *
2751ae08745Sheppo mdeg_get_client(mdeg_handle_t hdl)
2761ae08745Sheppo {
2771ae08745Sheppo 	int		idx;
2781ae08745Sheppo 	mdeg_clnt_t	*clnt;
2791ae08745Sheppo 
2801ae08745Sheppo 	idx = MDEG_HDL2IDX(hdl);
2811ae08745Sheppo 
2821ae08745Sheppo 	/* check if index is out of bounds */
2831ae08745Sheppo 	if ((idx < 0) || (idx >= mdeg.maxclnts)) {
2841ae08745Sheppo 		MDEG_DBG("mdeg_get_client: index out of bounds\n");
2851ae08745Sheppo 		return (NULL);
2861ae08745Sheppo 	}
2871ae08745Sheppo 
2881ae08745Sheppo 	clnt = &mdeg.tbl[idx];
2891ae08745Sheppo 
2901ae08745Sheppo 	/* check for a valid client */
2911ae08745Sheppo 	if (!clnt->valid) {
2921ae08745Sheppo 		MDEG_DBG("mdeg_get_client: client is not valid\n");
2931ae08745Sheppo 		return (NULL);
2941ae08745Sheppo 	}
2951ae08745Sheppo 
2961ae08745Sheppo 	/* make sure the handle is an exact match */
2971ae08745Sheppo 	if (clnt->hdl != hdl) {
2981ae08745Sheppo 		MDEG_DBG("mdeg_get_client: bad handle\n");
2991ae08745Sheppo 		return (NULL);
3001ae08745Sheppo 	}
3011ae08745Sheppo 
3021ae08745Sheppo 	if (clnt->magic != MDEG_MAGIC) {
3031ae08745Sheppo 		MDEG_DBG("mdeg_get_client: bad magic\n");
3041ae08745Sheppo 		return (NULL);
3051ae08745Sheppo 	}
3061ae08745Sheppo 
3071ae08745Sheppo 	return (clnt);
3081ae08745Sheppo }
3091ae08745Sheppo 
3101ae08745Sheppo /*
3111ae08745Sheppo  * Send a notification to a client immediately after it registers.
3121ae08745Sheppo  * The result_t is a list of all the nodes that match their specified
3131ae08745Sheppo  * nodes of interest, all returned on the added list. This serves
3141ae08745Sheppo  * as a base of reference to the client. All future MD updates are
3151ae08745Sheppo  * relative to this list.
3161ae08745Sheppo  */
3171ae08745Sheppo static int
3181ae08745Sheppo mdeg_notify_client_reg(mdeg_clnt_t *clnt)
3191ae08745Sheppo {
3201ae08745Sheppo 	md_t			*mdp = NULL;
3211ae08745Sheppo 	mde_str_cookie_t	nname;
3221ae08745Sheppo 	mde_str_cookie_t	aname;
3231ae08745Sheppo 	mde_cookie_t		startnode;
3241ae08745Sheppo 	int			nnodes;
3251ae08745Sheppo 	int			nodechk;
3261ae08745Sheppo 	mde_cookie_t		*listp = NULL;
3271ae08745Sheppo 	mdeg_result_t		*mdeg_res = NULL;
3281ae08745Sheppo 	int			rv = MDEG_SUCCESS;
3291ae08745Sheppo 
3301ae08745Sheppo 	mutex_enter(&mdeg.lock);
3311ae08745Sheppo 
3321ae08745Sheppo 	/*
3331ae08745Sheppo 	 * Handle the special case where the node specification
3341ae08745Sheppo 	 * is NULL. In this case, call the client callback without
3351ae08745Sheppo 	 * any results. All processing is left to the client.
3361ae08745Sheppo 	 */
3371ae08745Sheppo 	if (clnt->pspec == NULL) {
3381ae08745Sheppo 		/* call the client callback */
3391ae08745Sheppo 		(*clnt->cb)(clnt->cb_arg, NULL);
3401ae08745Sheppo 		goto done;
3411ae08745Sheppo 	}
3421ae08745Sheppo 
3431ae08745Sheppo 	if ((mdp = md_get_handle()) == NULL) {
3441ae08745Sheppo 		cmn_err(CE_WARN, "unable to retrieve current MD");
3451ae08745Sheppo 		rv = MDEG_FAILURE;
3461ae08745Sheppo 		goto done;
3471ae08745Sheppo 	}
3481ae08745Sheppo 
3491ae08745Sheppo 	startnode = mdeg_find_start_node(mdp, clnt->pspec);
3501ae08745Sheppo 	if (startnode == MDE_INVAL_ELEM_COOKIE) {
3511ae08745Sheppo 		/* not much we can do */
3521ae08745Sheppo 		cmn_err(CE_WARN, "unable to match node specifier");
3531ae08745Sheppo 		rv = MDEG_FAILURE;
3541ae08745Sheppo 		goto done;
3551ae08745Sheppo 	}
3561ae08745Sheppo 
3571ae08745Sheppo 	/*
3581ae08745Sheppo 	 * Use zalloc to provide correct default values for the
3591ae08745Sheppo 	 * unused removed, match_prev, and match_curr lists.
3601ae08745Sheppo 	 */
3611ae08745Sheppo 	mdeg_res = kmem_zalloc(sizeof (mdeg_result_t), KM_SLEEP);
3621ae08745Sheppo 
3631ae08745Sheppo 	nname = md_find_name(mdp, clnt->nmatch->namep);
3641ae08745Sheppo 	aname = md_find_name(mdp, "fwd");
3651ae08745Sheppo 
3661ae08745Sheppo 	nnodes = md_scan_dag(mdp, startnode, nname, aname, NULL);
3671ae08745Sheppo 
3681ae08745Sheppo 	if (nnodes == 0) {
3691ae08745Sheppo 		MDEG_DBG("mdeg_notify_client_reg: no nodes of interest\n");
3701ae08745Sheppo 		rv = MDEG_SUCCESS;
3711ae08745Sheppo 		goto done;
3721ae08745Sheppo 	} else if (nnodes == -1) {
3731ae08745Sheppo 		MDEG_DBG("error scanning DAG\n");
3741ae08745Sheppo 		rv = MDEG_FAILURE;
3751ae08745Sheppo 		goto done;
3761ae08745Sheppo 	}
3771ae08745Sheppo 
3781ae08745Sheppo 	MDEG_DBG("mdeg_notify_client_reg: %d node%s of interest\n",
3791ae08745Sheppo 	    nnodes, (nnodes == 1) ? "" : "s");
3801ae08745Sheppo 
3811ae08745Sheppo 	/* get the list of nodes of interest */
3821ae08745Sheppo 	listp = kmem_alloc(sizeof (mde_cookie_t) * nnodes, KM_SLEEP);
3831ae08745Sheppo 	nodechk = md_scan_dag(mdp, startnode, nname, aname, listp);
3841ae08745Sheppo 
3851ae08745Sheppo 	ASSERT(nodechk == nnodes);
3861ae08745Sheppo 
3871ae08745Sheppo 	mdeg_res->added.mdp = mdp;
3881ae08745Sheppo 	mdeg_res->added.mdep = listp;
3891ae08745Sheppo 	mdeg_res->added.nelem = nnodes;
3901ae08745Sheppo 
3911ae08745Sheppo 	/* call the client callback */
3921ae08745Sheppo 	(*clnt->cb)(clnt->cb_arg, mdeg_res);
3931ae08745Sheppo 
3941ae08745Sheppo done:
3951ae08745Sheppo 	mutex_exit(&mdeg.lock);
3961ae08745Sheppo 
3971ae08745Sheppo 	if (mdp)
3981ae08745Sheppo 		(void) md_fini_handle(mdp);
3991ae08745Sheppo 
4001ae08745Sheppo 	if (listp)
4011ae08745Sheppo 		kmem_free(listp, sizeof (mde_cookie_t) * nnodes);
4021ae08745Sheppo 
4031ae08745Sheppo 	if (mdeg_res)
4041ae08745Sheppo 		kmem_free(mdeg_res, sizeof (mdeg_result_t));
4051ae08745Sheppo 
4061ae08745Sheppo 	return (rv);
4071ae08745Sheppo }
4081ae08745Sheppo 
4091ae08745Sheppo /*
4101ae08745Sheppo  * Register to receive an event notification when the system
4111ae08745Sheppo  * machine description is updated.
4121ae08745Sheppo  *
4131ae08745Sheppo  * Passing NULL for the node specification parameter is valid
4141ae08745Sheppo  * as long as the match specification is also NULL. In this
4151ae08745Sheppo  * case, the client will receive a notification when the MD
4161ae08745Sheppo  * has been updated, but the callback will not include any
4171ae08745Sheppo  * information. The client is then responsible for obtaining
4181ae08745Sheppo  * its own copy of the system MD and performing any processing
4191ae08745Sheppo  * manually.
4201ae08745Sheppo  */
4211ae08745Sheppo int
4221ae08745Sheppo mdeg_register(mdeg_node_spec_t *pspecp, mdeg_node_match_t *nmatchp,
4231ae08745Sheppo     mdeg_cb_t cb, void *cb_arg, mdeg_handle_t *hdlp)
4241ae08745Sheppo {
4251ae08745Sheppo 	mdeg_clnt_t	*clnt;
4261ae08745Sheppo 
4271ae08745Sheppo 	/*
4281ae08745Sheppo 	 * If the RW lock is held, a client is calling
4291ae08745Sheppo 	 * register from its own callback.
4301ae08745Sheppo 	 */
4311ae08745Sheppo 	if (RW_LOCK_HELD(&mdeg.rwlock)) {
4321ae08745Sheppo 		MDEG_DBG("mdeg_register: rwlock already held\n");
4331ae08745Sheppo 		return (MDEG_FAILURE);
4341ae08745Sheppo 	}
4351ae08745Sheppo 
4361ae08745Sheppo 	/* node spec and node match must both be valid, or both NULL */
4371ae08745Sheppo 	if (((pspecp != NULL) && (nmatchp == NULL)) ||
4381ae08745Sheppo 	    ((pspecp == NULL) && (nmatchp != NULL))) {
4391ae08745Sheppo 		MDEG_DBG("mdeg_register: invalid parameters\n");
4401ae08745Sheppo 		return (MDEG_FAILURE);
4411ae08745Sheppo 	}
4421ae08745Sheppo 
4431ae08745Sheppo 	rw_enter(&mdeg.rwlock, RW_WRITER);
4441ae08745Sheppo 
4451ae08745Sheppo 	clnt = mdeg_alloc_clnt();
4461ae08745Sheppo 
4471ae08745Sheppo 	ASSERT(clnt);
4481ae08745Sheppo 
4491ae08745Sheppo 	/*
4501ae08745Sheppo 	 * Fill in the rest of the data
4511ae08745Sheppo 	 */
4521ae08745Sheppo 	clnt->nmatch = nmatchp;
4531ae08745Sheppo 	clnt->pspec = pspecp;
4541ae08745Sheppo 	clnt->cb = cb;
4551ae08745Sheppo 	clnt->cb_arg = cb_arg;
4561ae08745Sheppo 	clnt->magic = MDEG_MAGIC;
4571ae08745Sheppo 
4581ae08745Sheppo 	/* do this last */
4591ae08745Sheppo 	clnt->valid = B_TRUE;
4601ae08745Sheppo 
4611ae08745Sheppo 	MDEG_DBG("client registered (0x%lx):\n", clnt->hdl);
4621ae08745Sheppo 	MDEG_DUMP_CLNT(clnt);
4631ae08745Sheppo 
4641ae08745Sheppo 	mdeg.nclnts++;
4651ae08745Sheppo 
4661ae08745Sheppo 	if (mdeg_notify_client_reg(clnt) != MDEG_SUCCESS) {
4671ae08745Sheppo 		bzero(clnt, sizeof (mdeg_clnt_t));
4681ae08745Sheppo 		rw_exit(&mdeg.rwlock);
4691ae08745Sheppo 		return (MDEG_FAILURE);
4701ae08745Sheppo 	}
4711ae08745Sheppo 
4721ae08745Sheppo 	rw_exit(&mdeg.rwlock);
4731ae08745Sheppo 
4741ae08745Sheppo 	*hdlp = clnt->hdl;
4751ae08745Sheppo 
4761ae08745Sheppo 	return (MDEG_SUCCESS);
4771ae08745Sheppo }
4781ae08745Sheppo 
4791ae08745Sheppo int
4801ae08745Sheppo mdeg_unregister(mdeg_handle_t hdl)
4811ae08745Sheppo {
4821ae08745Sheppo 	mdeg_clnt_t	*clnt;
4831ae08745Sheppo 	mdeg_handle_t	mdh;
4841ae08745Sheppo 
4851ae08745Sheppo 	/*
4861ae08745Sheppo 	 * If the RW lock is held, a client is calling
4871ae08745Sheppo 	 * unregister from its own callback.
4881ae08745Sheppo 	 */
4891ae08745Sheppo 	if (RW_LOCK_HELD(&mdeg.rwlock)) {
4901ae08745Sheppo 		MDEG_DBG("mdeg_unregister: rwlock already held\n");
4911ae08745Sheppo 		return (MDEG_FAILURE);
4921ae08745Sheppo 	}
4931ae08745Sheppo 
4941ae08745Sheppo 	/* lookup the client */
4951ae08745Sheppo 	if ((clnt = mdeg_get_client(hdl)) == NULL) {
4961ae08745Sheppo 		return (MDEG_FAILURE);
4971ae08745Sheppo 	}
4981ae08745Sheppo 
4991ae08745Sheppo 	rw_enter(&mdeg.rwlock, RW_WRITER);
5001ae08745Sheppo 
5011ae08745Sheppo 	MDEG_DBG("client unregistered (0x%lx):\n", hdl);
5021ae08745Sheppo 	MDEG_DUMP_CLNT(clnt);
5031ae08745Sheppo 
5041ae08745Sheppo 	/* save the handle to prevent reuse */
5051ae08745Sheppo 	mdh = clnt->hdl;
5061ae08745Sheppo 	bzero(clnt, sizeof (mdeg_clnt_t));
5071ae08745Sheppo 
5081ae08745Sheppo 	clnt->hdl = mdh;
5091ae08745Sheppo 
5101ae08745Sheppo 	mdeg.nclnts--;
5111ae08745Sheppo 
5121ae08745Sheppo 	rw_exit(&mdeg.rwlock);
5131ae08745Sheppo 
5141ae08745Sheppo 	return (MDEG_SUCCESS);
5151ae08745Sheppo }
5161ae08745Sheppo 
5171ae08745Sheppo /*
5181ae08745Sheppo  * Simple algorithm for now, grab the global lock and let all
5191ae08745Sheppo  * the clients update themselves in parallel. There is a lot of
5201ae08745Sheppo  * room for improvement here. We could eliminate some scans of
521*4e476149Srsmaeda  * the DAG by incrementally scanning at lower levels of the DAG
5221ae08745Sheppo  * rather than having each client start its own scan from the root.
5231ae08745Sheppo  */
5241ae08745Sheppo void
5251ae08745Sheppo mdeg_notify_clients(void)
5261ae08745Sheppo {
5271ae08745Sheppo 	md_t		*md_new;
5281ae08745Sheppo 	mdeg_clnt_t	*clnt;
5291ae08745Sheppo 	int		idx;
5301ae08745Sheppo 	int		nclnt;
5311ae08745Sheppo 
5321ae08745Sheppo 	rw_enter(&mdeg.rwlock, RW_READER);
5331ae08745Sheppo 	mutex_enter(&mdeg.lock);
5341ae08745Sheppo 
5351ae08745Sheppo 	/*
5361ae08745Sheppo 	 * Rotate the MDs
5371ae08745Sheppo 	 */
5381ae08745Sheppo 	if ((md_new = md_get_handle()) == NULL) {
5391ae08745Sheppo 		cmn_err(CE_WARN, "unable to retrieve new MD");
5401ae08745Sheppo 		goto done;
5411ae08745Sheppo 	}
5421ae08745Sheppo 
5431ae08745Sheppo 	if (mdeg.md_prev) {
5441ae08745Sheppo 		(void) md_fini_handle(mdeg.md_prev);
5451ae08745Sheppo 	}
5461ae08745Sheppo 
5471ae08745Sheppo 	mdeg.md_prev = mdeg.md_curr;
5481ae08745Sheppo 	mdeg.md_curr = md_new;
5491ae08745Sheppo 
5501ae08745Sheppo 	if (mdeg.nclnts == 0) {
5511ae08745Sheppo 		MDEG_DBG("mdeg_notify_clients: no clients registered\n");
5521ae08745Sheppo 		goto done;
5531ae08745Sheppo 	}
5541ae08745Sheppo 
5551ae08745Sheppo 	/* dispatch the update notification to all clients */
5561ae08745Sheppo 	for (idx = 0, nclnt = 0; idx < mdeg.maxclnts; idx++) {
5571ae08745Sheppo 		clnt = &mdeg.tbl[idx];
5581ae08745Sheppo 
5591ae08745Sheppo 		if (!clnt->valid)
5601ae08745Sheppo 			continue;
5611ae08745Sheppo 
5621ae08745Sheppo 		MDEG_DBG("notifying client 0x%lx (%d/%d)\n", clnt->hdl,
5631ae08745Sheppo 		    ++nclnt, mdeg.nclnts);
5641ae08745Sheppo 
5651ae08745Sheppo 		(void) taskq_dispatch(mdeg.taskq, mdeg_notify_client,
5661ae08745Sheppo 		    (void *)clnt, TQ_SLEEP);
5671ae08745Sheppo 	}
5681ae08745Sheppo 
5691ae08745Sheppo 	taskq_wait(mdeg.taskq);
5701ae08745Sheppo 
5711ae08745Sheppo done:
5721ae08745Sheppo 	mutex_exit(&mdeg.lock);
5731ae08745Sheppo 	rw_exit(&mdeg.rwlock);
5741ae08745Sheppo }
5751ae08745Sheppo 
5761ae08745Sheppo static void
5771ae08745Sheppo mdeg_notify_client(void *arg)
5781ae08745Sheppo {
5791ae08745Sheppo 	mdeg_clnt_t		*clnt = (mdeg_clnt_t *)arg;
5801ae08745Sheppo 	md_diff_cookie_t	mdd = MD_INVAL_DIFF_COOKIE;
5811ae08745Sheppo 	mdeg_result_t		mdeg_res;
5821ae08745Sheppo 	mde_cookie_t		md_prev_start;
5831ae08745Sheppo 	mde_cookie_t		md_curr_start;
5841ae08745Sheppo 
5851ae08745Sheppo 	rw_enter(&mdeg.rwlock, RW_READER);
5861ae08745Sheppo 
5871ae08745Sheppo 	if (!mdeg.enabled) {
5881ae08745Sheppo 		/* trying to shutdown */
5891ae08745Sheppo 		MDEG_DBG("mdeg_notify_client: mdeg disabled, aborting\n");
5901ae08745Sheppo 		goto cleanup;
5911ae08745Sheppo 	}
5921ae08745Sheppo 
5931ae08745Sheppo 	/*
5941ae08745Sheppo 	 * Handle the special case where the node specification
5951ae08745Sheppo 	 * is NULL. In this case, call the client callback without
5961ae08745Sheppo 	 * any results. All processing is left to the client.
5971ae08745Sheppo 	 */
5981ae08745Sheppo 	if (clnt->pspec == NULL) {
5991ae08745Sheppo 		/* call the client callback */
6001ae08745Sheppo 		(*clnt->cb)(clnt->cb_arg, NULL);
6011ae08745Sheppo 
6021ae08745Sheppo 		MDEG_DBG("MDEG client callback done\n");
6031ae08745Sheppo 		goto cleanup;
6041ae08745Sheppo 	}
6051ae08745Sheppo 
6061ae08745Sheppo 	/* find our start nodes */
6071ae08745Sheppo 	md_prev_start = mdeg_find_start_node(mdeg.md_prev, clnt->pspec);
6081ae08745Sheppo 	if (md_prev_start == MDE_INVAL_ELEM_COOKIE) {
6091ae08745Sheppo 		goto cleanup;
6101ae08745Sheppo 	}
6111ae08745Sheppo 
6121ae08745Sheppo 	md_curr_start = mdeg_find_start_node(mdeg.md_curr, clnt->pspec);
6131ae08745Sheppo 	if (md_curr_start == MDE_INVAL_ELEM_COOKIE) {
6141ae08745Sheppo 		goto cleanup;
6151ae08745Sheppo 	}
6161ae08745Sheppo 
6171ae08745Sheppo 	/* diff the MDs */
6181ae08745Sheppo 	mdd = md_diff_init(mdeg.md_prev, md_prev_start, mdeg.md_curr,
6191ae08745Sheppo 	    md_curr_start, clnt->nmatch->namep, clnt->nmatch->matchp);
6201ae08745Sheppo 
6211ae08745Sheppo 	if (mdd == MD_INVAL_DIFF_COOKIE) {
6221ae08745Sheppo 		MDEG_DBG("unable to diff MDs\n");
6231ae08745Sheppo 		goto cleanup;
6241ae08745Sheppo 	}
6251ae08745Sheppo 
6261ae08745Sheppo 	/*
6271ae08745Sheppo 	 * Cache the results of the diff
6281ae08745Sheppo 	 */
6291ae08745Sheppo 	mdeg_get_diff_results(mdd, &mdeg_res);
6301ae08745Sheppo 
6311ae08745Sheppo 	/* call the client callback */
6321ae08745Sheppo 	(*clnt->cb)(clnt->cb_arg, &mdeg_res);
6331ae08745Sheppo 
6341ae08745Sheppo 	MDEG_DBG("MDEG client callback done\n");
6351ae08745Sheppo 
6361ae08745Sheppo cleanup:
6371ae08745Sheppo 	rw_exit(&mdeg.rwlock);
6381ae08745Sheppo 
6391ae08745Sheppo 	if (mdd != MD_INVAL_DIFF_COOKIE)
6401ae08745Sheppo 		(void) md_diff_fini(mdd);
6411ae08745Sheppo }
6421ae08745Sheppo 
6431ae08745Sheppo static mde_cookie_t
6441ae08745Sheppo mdeg_find_start_node(md_t *md, mdeg_node_spec_t *nspec)
6451ae08745Sheppo {
6461ae08745Sheppo 	mde_cookie_t		*nodesp;
6471ae08745Sheppo 	mde_str_cookie_t	nname;
6481ae08745Sheppo 	mde_str_cookie_t	aname;
6491ae08745Sheppo 	int			nnodes;
6501ae08745Sheppo 	int			idx;
6511ae08745Sheppo 
6521ae08745Sheppo 	if ((md == NULL) || (nspec == NULL))
6531ae08745Sheppo 		return (MDE_INVAL_ELEM_COOKIE);
6541ae08745Sheppo 
6551ae08745Sheppo 	nname = md_find_name(md, nspec->namep);
6561ae08745Sheppo 	aname = md_find_name(md, "fwd");
6571ae08745Sheppo 
6581ae08745Sheppo 	nnodes = md_scan_dag(md, NULL, nname, aname, NULL);
6591ae08745Sheppo 	if (nnodes == 0)
6601ae08745Sheppo 		return (MDE_INVAL_ELEM_COOKIE);
6611ae08745Sheppo 
6621ae08745Sheppo 	nodesp = kmem_alloc(sizeof (mde_cookie_t) * nnodes, KM_SLEEP);
6631ae08745Sheppo 
6641ae08745Sheppo 	(void) md_scan_dag(md, NULL, nname, aname, nodesp);
6651ae08745Sheppo 
6661ae08745Sheppo 	for (idx = 0; idx < nnodes; idx++) {
6671ae08745Sheppo 
6681ae08745Sheppo 		if (mdeg_node_spec_match(md, nodesp[idx], nspec)) {
6691ae08745Sheppo 			mde_cookie_t res = nodesp[idx];
6701ae08745Sheppo 
6711ae08745Sheppo 			kmem_free(nodesp, sizeof (mde_cookie_t) * nnodes);
6721ae08745Sheppo 			return (res);
6731ae08745Sheppo 		}
6741ae08745Sheppo 	}
6751ae08745Sheppo 
6761ae08745Sheppo 	kmem_free(nodesp, sizeof (mde_cookie_t) * nnodes);
6771ae08745Sheppo 	return (MDE_INVAL_ELEM_COOKIE);
6781ae08745Sheppo }
6791ae08745Sheppo 
6801ae08745Sheppo static boolean_t
6811ae08745Sheppo mdeg_node_spec_match(md_t *md, mde_cookie_t node, mdeg_node_spec_t *nspec)
6821ae08745Sheppo {
6831ae08745Sheppo 	mdeg_prop_spec_t	*prop;
6841ae08745Sheppo 
6851ae08745Sheppo 	ASSERT(md && nspec);
6861ae08745Sheppo 	ASSERT(node != MDE_INVAL_ELEM_COOKIE);
6871ae08745Sheppo 
6881ae08745Sheppo 	prop = nspec->specp;
6891ae08745Sheppo 
6901ae08745Sheppo 	while (prop->type != MDET_LIST_END) {
6911ae08745Sheppo 
6921ae08745Sheppo 		switch (prop->type) {
6931ae08745Sheppo 		case MDET_PROP_VAL: {
6941ae08745Sheppo 			uint64_t val;
6951ae08745Sheppo 
6961ae08745Sheppo 			if (md_get_prop_val(md, node, prop->namep, &val) != 0)
6971ae08745Sheppo 				return (B_FALSE);
6981ae08745Sheppo 
6991ae08745Sheppo 			if (prop->ps_val != val)
7001ae08745Sheppo 				return (B_FALSE);
7011ae08745Sheppo 
7021ae08745Sheppo 			break;
7031ae08745Sheppo 		}
7041ae08745Sheppo 		case MDET_PROP_STR: {
7051ae08745Sheppo 			char	*str;
7061ae08745Sheppo 
7071ae08745Sheppo 			if (md_get_prop_str(md, node, prop->namep, &str) != 0)
7081ae08745Sheppo 				return (B_FALSE);
7091ae08745Sheppo 
7101ae08745Sheppo 			if (strcmp(prop->ps_str, str) != 0)
7111ae08745Sheppo 				return (B_FALSE);
7121ae08745Sheppo 
7131ae08745Sheppo 			break;
7141ae08745Sheppo 		}
7151ae08745Sheppo 
7161ae08745Sheppo 		default:
7171ae08745Sheppo 			return (B_FALSE);
7181ae08745Sheppo 		}
7191ae08745Sheppo 
7201ae08745Sheppo 		prop++;
7211ae08745Sheppo 	}
7221ae08745Sheppo 
7231ae08745Sheppo 	return (B_TRUE);
7241ae08745Sheppo }
7251ae08745Sheppo 
7261ae08745Sheppo static void
7271ae08745Sheppo mdeg_get_diff_results(md_diff_cookie_t mdd, mdeg_result_t *res)
7281ae08745Sheppo {
7291ae08745Sheppo 	/*
7301ae08745Sheppo 	 * Cache added nodes.
7311ae08745Sheppo 	 */
7321ae08745Sheppo 	res->added.mdp = mdeg.md_curr;
7331ae08745Sheppo 	res->added.nelem = md_diff_added(mdd, &(res->added.mdep));
7341ae08745Sheppo 
7351ae08745Sheppo 	if (res->added.nelem == -1) {
7361ae08745Sheppo 		bzero(&(res->added), sizeof (mdeg_diff_t));
7371ae08745Sheppo 	}
7381ae08745Sheppo 
7391ae08745Sheppo 	/*
7401ae08745Sheppo 	 * Cache removed nodes.
7411ae08745Sheppo 	 */
7421ae08745Sheppo 	res->removed.mdp = mdeg.md_prev;
7431ae08745Sheppo 	res->removed.nelem = md_diff_removed(mdd, &(res->removed.mdep));
7441ae08745Sheppo 
7451ae08745Sheppo 	if (res->removed.nelem == -1) {
7461ae08745Sheppo 		bzero(&(res->removed), sizeof (mdeg_diff_t));
7471ae08745Sheppo 	}
7481ae08745Sheppo 
7491ae08745Sheppo 	/*
7501ae08745Sheppo 	 * Cache matching node pairs.
7511ae08745Sheppo 	 */
7521ae08745Sheppo 	res->match_curr.mdp = mdeg.md_curr;
7531ae08745Sheppo 	res->match_prev.mdp = mdeg.md_prev;
7541ae08745Sheppo 	res->match_curr.nelem = md_diff_matched(mdd, &(res->match_prev.mdep),
7551ae08745Sheppo 	    &(res->match_curr.mdep));
7561ae08745Sheppo 	res->match_prev.nelem = res->match_curr.nelem;
7571ae08745Sheppo 
7581ae08745Sheppo 	if (res->match_prev.nelem == -1) {
7591ae08745Sheppo 		bzero(&(res->match_prev), sizeof (mdeg_diff_t));
7601ae08745Sheppo 		bzero(&(res->match_curr), sizeof (mdeg_diff_t));
7611ae08745Sheppo 	}
7621ae08745Sheppo }
7631ae08745Sheppo 
7641ae08745Sheppo #ifdef DEBUG
7651ae08745Sheppo /*
7661ae08745Sheppo  * Generate a string that represents the node specifier
7671ae08745Sheppo  * structure. Clamp the string length if the specifier
7681ae08745Sheppo  * structure contains too much information.
7691ae08745Sheppo  *
7701ae08745Sheppo  *	General form:
7711ae08745Sheppo  *
7721ae08745Sheppo  *		<nodename>:{<propname>=<propval>,...}
7731ae08745Sheppo  *	e.g.
7741ae08745Sheppo  *		vdevice:{name=vsw,reg=0x0}
7751ae08745Sheppo  */
7761ae08745Sheppo static void
7771ae08745Sheppo mdeg_spec_str(mdeg_node_spec_t *spec, char *buf, int len)
7781ae08745Sheppo {
7791ae08745Sheppo 	mdeg_prop_spec_t	*prop;
7801ae08745Sheppo 	int			offset;
7811ae08745Sheppo 	boolean_t		first = B_TRUE;
7821ae08745Sheppo 	char			*end = buf + len;
7831ae08745Sheppo 
7841ae08745Sheppo 	offset = snprintf(buf, len, "%s:{", spec->namep);
7851ae08745Sheppo 
7861ae08745Sheppo 	buf += offset;
7871ae08745Sheppo 	len -= offset;
7881ae08745Sheppo 	if (len <= 0)
7891ae08745Sheppo 		goto trunc;
7901ae08745Sheppo 
7911ae08745Sheppo 	prop = spec->specp;
7921ae08745Sheppo 
7931ae08745Sheppo 	while (prop->type != MDET_LIST_END) {
7941ae08745Sheppo 
7951ae08745Sheppo 		switch (prop->type) {
7961ae08745Sheppo 		case MDET_PROP_VAL:
7971ae08745Sheppo 			offset = snprintf(buf, len, "%s%s=0x%lx",
7981ae08745Sheppo 			    (first) ? "" : ",", prop->namep, prop->ps_val);
7991ae08745Sheppo 			buf += offset;
8001ae08745Sheppo 			len -= offset;
8011ae08745Sheppo 			if (len <= 0)
8021ae08745Sheppo 				goto trunc;
8031ae08745Sheppo 			break;
8041ae08745Sheppo 
8051ae08745Sheppo 		case MDET_PROP_STR:
8061ae08745Sheppo 			offset = snprintf(buf, len, "%s%s=%s",
8071ae08745Sheppo 			    (first) ? "" : ",", prop->namep, prop->ps_str);
8081ae08745Sheppo 			buf += offset;
8091ae08745Sheppo 			len -= offset;
8101ae08745Sheppo 			if (len <= 0)
8111ae08745Sheppo 				goto trunc;
8121ae08745Sheppo 			break;
8131ae08745Sheppo 
8141ae08745Sheppo 		default:
8151ae08745Sheppo 			(void) snprintf(buf, len, "}");
8161ae08745Sheppo 			return;
8171ae08745Sheppo 		}
8181ae08745Sheppo 
8191ae08745Sheppo 		if (first)
8201ae08745Sheppo 			first = B_FALSE;
8211ae08745Sheppo 		prop++;
8221ae08745Sheppo 	}
8231ae08745Sheppo 
8241ae08745Sheppo 	(void) snprintf(buf, len, "}");
8251ae08745Sheppo 	return;
8261ae08745Sheppo 
8271ae08745Sheppo trunc:
8281ae08745Sheppo 	/* string too long, truncate it */
8291ae08745Sheppo 	buf = end - (strlen(trunc_str) + 1);
8301ae08745Sheppo 	(void) sprintf(buf, trunc_str);
8311ae08745Sheppo }
8321ae08745Sheppo 
8331ae08745Sheppo /*
8341ae08745Sheppo  * Generate a string that represents the match structure.
8351ae08745Sheppo  * Clamp the string length if the match structure contains
8361ae08745Sheppo  * too much information.
8371ae08745Sheppo  *
8381ae08745Sheppo  *	General form:
8391ae08745Sheppo  *
8401ae08745Sheppo  *		<nodename>:{<propname>,...}
8411ae08745Sheppo  *	e.g.
8421ae08745Sheppo  *		nmatch=vport:{reg}
8431ae08745Sheppo  */
8441ae08745Sheppo static void
8451ae08745Sheppo mdeg_match_str(mdeg_node_match_t *match, char *buf, int len)
8461ae08745Sheppo {
8471ae08745Sheppo 	md_prop_match_t	*prop;
8481ae08745Sheppo 	int		offset;
8491ae08745Sheppo 	boolean_t	first = B_TRUE;
8501ae08745Sheppo 	char		*end = buf + len;
8511ae08745Sheppo 
8521ae08745Sheppo 	offset = snprintf(buf, len, "%s:{", match->namep);
8531ae08745Sheppo 
8541ae08745Sheppo 	buf += offset;
8551ae08745Sheppo 	len -= offset;
8561ae08745Sheppo 	if (len <= 0)
8571ae08745Sheppo 		goto trunc;
8581ae08745Sheppo 
8591ae08745Sheppo 	prop = match->matchp;
8601ae08745Sheppo 
8611ae08745Sheppo 	while (prop->type != MDET_LIST_END) {
8621ae08745Sheppo 		offset = snprintf(buf, len, "%s%s", (first) ? "" : ",",
8631ae08745Sheppo 		    prop->namep);
8641ae08745Sheppo 		buf += offset;
8651ae08745Sheppo 		len -= offset;
8661ae08745Sheppo 		if (len <= 0)
8671ae08745Sheppo 			goto trunc;
8681ae08745Sheppo 
8691ae08745Sheppo 		if (first)
8701ae08745Sheppo 			first = B_FALSE;
8711ae08745Sheppo 		prop++;
8721ae08745Sheppo 	}
8731ae08745Sheppo 
8741ae08745Sheppo 	(void) snprintf(buf, len, "}");
8751ae08745Sheppo 	return;
8761ae08745Sheppo 
8771ae08745Sheppo trunc:
8781ae08745Sheppo 	/* string too long, truncate it */
8791ae08745Sheppo 	buf = end - (strlen(trunc_str) + 1);
8801ae08745Sheppo 	(void) sprintf(buf, trunc_str);
8811ae08745Sheppo }
8821ae08745Sheppo 
8831ae08745Sheppo #define	MAX_FIELD_STR	80
8841ae08745Sheppo 
8851ae08745Sheppo static void
8861ae08745Sheppo mdeg_dump_clnt(mdeg_clnt_t *clnt)
8871ae08745Sheppo {
8881ae08745Sheppo 	char	str[MAX_FIELD_STR];
8891ae08745Sheppo 
8901ae08745Sheppo 	if (!clnt->valid) {
8911ae08745Sheppo 		MDEG_DBG("  valid=B_FALSE\n");
8921ae08745Sheppo 		return;
8931ae08745Sheppo 	}
8941ae08745Sheppo 
8951ae08745Sheppo 	mdeg_spec_str(clnt->pspec, str, MAX_FIELD_STR);
8961ae08745Sheppo 	MDEG_DBG("  pspecp=%s\n", str);
8971ae08745Sheppo 
8981ae08745Sheppo 	mdeg_match_str(clnt->nmatch, str, MAX_FIELD_STR);
8991ae08745Sheppo 	MDEG_DBG("  nmatch=%s\n", str);
9001ae08745Sheppo }
9011ae08745Sheppo 
9021ae08745Sheppo static void
9031ae08745Sheppo mdeg_dump_table(void)
9041ae08745Sheppo {
9051ae08745Sheppo 	int		idx;
9061ae08745Sheppo 	mdeg_clnt_t	*clnt;
9071ae08745Sheppo 
9081ae08745Sheppo 	for (idx = 0; idx < mdeg.maxclnts; idx++) {
9091ae08745Sheppo 		clnt = &(mdeg.tbl[idx]);
9101ae08745Sheppo 
9111ae08745Sheppo 		MDEG_DBG("client %d (0x%lx):\n", idx, clnt->hdl);
9121ae08745Sheppo 		mdeg_dump_clnt(clnt);
9131ae08745Sheppo 	}
9141ae08745Sheppo }
9151ae08745Sheppo #endif /* DEBUG */
916