xref: /titanic_41/usr/src/common/mdesc/mdesc_diff.c (revision 1ae0874509b6811fdde1dfd46f0d93fd09867a3f)
1*1ae08745Sheppo /*
2*1ae08745Sheppo  * CDDL HEADER START
3*1ae08745Sheppo  *
4*1ae08745Sheppo  * The contents of this file are subject to the terms of the
5*1ae08745Sheppo  * Common Development and Distribution License (the "License").
6*1ae08745Sheppo  * You may not use this file except in compliance with the License.
7*1ae08745Sheppo  *
8*1ae08745Sheppo  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*1ae08745Sheppo  * or http://www.opensolaris.org/os/licensing.
10*1ae08745Sheppo  * See the License for the specific language governing permissions
11*1ae08745Sheppo  * and limitations under the License.
12*1ae08745Sheppo  *
13*1ae08745Sheppo  * When distributing Covered Code, include this CDDL HEADER in each
14*1ae08745Sheppo  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*1ae08745Sheppo  * If applicable, add the following below this CDDL HEADER, with the
16*1ae08745Sheppo  * fields enclosed by brackets "[]" replaced with your own identifying
17*1ae08745Sheppo  * information: Portions Copyright [yyyy] [name of copyright owner]
18*1ae08745Sheppo  *
19*1ae08745Sheppo  * CDDL HEADER END
20*1ae08745Sheppo  */
21*1ae08745Sheppo 
22*1ae08745Sheppo /*
23*1ae08745Sheppo  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24*1ae08745Sheppo  * Use is subject to license terms.
25*1ae08745Sheppo  */
26*1ae08745Sheppo 
27*1ae08745Sheppo #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*1ae08745Sheppo 
29*1ae08745Sheppo #include <sys/types.h>
30*1ae08745Sheppo #ifdef _KERNEL
31*1ae08745Sheppo #include <sys/systm.h>
32*1ae08745Sheppo #else /* _KERNEL */
33*1ae08745Sheppo #include <string.h>
34*1ae08745Sheppo #include <strings.h>
35*1ae08745Sheppo #endif /* _KERNEL */
36*1ae08745Sheppo #include <sys/note.h>
37*1ae08745Sheppo #include <sys/mdesc.h>
38*1ae08745Sheppo #include <sys/mdesc_impl.h>
39*1ae08745Sheppo 
40*1ae08745Sheppo #define	MDD_FREE_CHECK(mdp, ptr, sz)		\
41*1ae08745Sheppo 	do {					\
42*1ae08745Sheppo 		if (ptr) mdp->freep(ptr, sz);	\
43*1ae08745Sheppo 	_NOTE(CONSTCOND) } while (0)
44*1ae08745Sheppo 
45*1ae08745Sheppo #define	MD_DIFF_MAGIC			0x4D445F4449464621ull	/* 'MD_DIFF!' */
46*1ae08745Sheppo #define	MD_DIFF_NOMATCH			(-1)
47*1ae08745Sheppo #define	MD_DIFF_MATCH			(1)
48*1ae08745Sheppo 
49*1ae08745Sheppo typedef struct {
50*1ae08745Sheppo 	mde_cookie_t	*mdep;
51*1ae08745Sheppo 	uint_t		nelem;
52*1ae08745Sheppo } md_diff_t;
53*1ae08745Sheppo 
54*1ae08745Sheppo typedef struct {
55*1ae08745Sheppo 	uint64_t	mdd_magic;
56*1ae08745Sheppo 	md_diff_t	added;
57*1ae08745Sheppo 	md_diff_t	removed;
58*1ae08745Sheppo 	md_diff_t	match1;
59*1ae08745Sheppo 	md_diff_t	match2;
60*1ae08745Sheppo 	void 		*(*allocp)(size_t);
61*1ae08745Sheppo 	void		(*freep)(void *, size_t);
62*1ae08745Sheppo } md_diff_impl_t;
63*1ae08745Sheppo 
64*1ae08745Sheppo /*
65*1ae08745Sheppo  * Internal utility functions
66*1ae08745Sheppo  */
67*1ae08745Sheppo static int mdd_scan_for_nodes(md_t *mdp, mde_cookie_t start,
68*1ae08745Sheppo     char *compnodep, int *countp, mde_cookie_t **nodespp);
69*1ae08745Sheppo 
70*1ae08745Sheppo static boolean_t mdd_any_dup_nodes(md_impl_t *mdp, md_prop_match_t *pmp,
71*1ae08745Sheppo     int count, mde_cookie_t *nodesp);
72*1ae08745Sheppo 
73*1ae08745Sheppo static int mdd_node_list_match(md_impl_t *md1, md_impl_t *md2,
74*1ae08745Sheppo     md_element_t *match_nodep, mde_cookie_t *match_listp,
75*1ae08745Sheppo     uint8_t *match_seenp, int start, int end, md_prop_match_t *match_elemsp);
76*1ae08745Sheppo 
77*1ae08745Sheppo static int mdd_node_compare(md_impl_t *mdap, md_impl_t *mdbp,
78*1ae08745Sheppo     md_element_t *nodeap, md_element_t *nodebp, md_prop_match_t *match_elemsp);
79*1ae08745Sheppo 
80*1ae08745Sheppo /*
81*1ae08745Sheppo  * Given two DAGs and information about how to uniquely identify
82*1ae08745Sheppo  * the nodes of interest, determine which nodes have been added
83*1ae08745Sheppo  * to the second MD, removed from the first MD, or exist in both
84*1ae08745Sheppo  * MDs. This information is recorded and can be accessed using the
85*1ae08745Sheppo  * opaque cookie returned to the caller.
86*1ae08745Sheppo  */
87*1ae08745Sheppo md_diff_cookie_t
md_diff_init(md_t * md1p,mde_cookie_t start1,md_t * md2p,mde_cookie_t start2,char * compnodep,md_prop_match_t * match_fieldsp)88*1ae08745Sheppo md_diff_init(md_t *md1p, mde_cookie_t start1, md_t *md2p, mde_cookie_t start2,
89*1ae08745Sheppo     char *compnodep, md_prop_match_t *match_fieldsp)
90*1ae08745Sheppo {
91*1ae08745Sheppo 	int		idx;
92*1ae08745Sheppo 	md_impl_t	*md1 = (md_impl_t *)md1p;
93*1ae08745Sheppo 	md_impl_t	*md2 = (md_impl_t *)md2p;
94*1ae08745Sheppo 	mde_cookie_t	*md1nodesp = NULL;
95*1ae08745Sheppo 	mde_cookie_t	*md2nodesp = NULL;
96*1ae08745Sheppo 	int		md1count = 0;
97*1ae08745Sheppo 	int		md2count = 0;
98*1ae08745Sheppo 	uint8_t		*seenp = NULL;
99*1ae08745Sheppo 
100*1ae08745Sheppo 	/* variables used to gather results */
101*1ae08745Sheppo 	md_diff_impl_t	*diff_res;
102*1ae08745Sheppo 	mde_cookie_t	*mde_add_scr;
103*1ae08745Sheppo 	mde_cookie_t	*mde_rem_scr;
104*1ae08745Sheppo 	mde_cookie_t	*mde_match1_scr;
105*1ae08745Sheppo 	mde_cookie_t	*mde_match2_scr;
106*1ae08745Sheppo 	int		nadd = 0;
107*1ae08745Sheppo 	int		nrem = 0;
108*1ae08745Sheppo 	int		nmatch = 0;
109*1ae08745Sheppo 
110*1ae08745Sheppo 	/* sanity check params */
111*1ae08745Sheppo 	if ((md1p == NULL) || (md2p == NULL))
112*1ae08745Sheppo 		return (MD_INVAL_DIFF_COOKIE);
113*1ae08745Sheppo 
114*1ae08745Sheppo 	if ((start1 == MDE_INVAL_ELEM_COOKIE) ||
115*1ae08745Sheppo 	    (start2 == MDE_INVAL_ELEM_COOKIE))
116*1ae08745Sheppo 		return (MD_INVAL_DIFF_COOKIE);
117*1ae08745Sheppo 
118*1ae08745Sheppo 	if ((compnodep == NULL) || (match_fieldsp == NULL))
119*1ae08745Sheppo 		return (MD_INVAL_DIFF_COOKIE);
120*1ae08745Sheppo 
121*1ae08745Sheppo 	/*
122*1ae08745Sheppo 	 * Prepare an array of the matching nodes from the first MD.
123*1ae08745Sheppo 	 */
124*1ae08745Sheppo 	if (mdd_scan_for_nodes(md1p,
125*1ae08745Sheppo 	    start1, compnodep, &md1count, &md1nodesp) == -1)
126*1ae08745Sheppo 		return (MD_INVAL_DIFF_COOKIE);
127*1ae08745Sheppo 
128*1ae08745Sheppo 	/* sanity check that all nodes are unique */
129*1ae08745Sheppo 	if (md1nodesp &&
130*1ae08745Sheppo 	    mdd_any_dup_nodes(md1, match_fieldsp, md1count, md1nodesp)) {
131*1ae08745Sheppo 		MDD_FREE_CHECK(md1, md1nodesp, sizeof (mde_cookie_t) *
132*1ae08745Sheppo 		    md1count);
133*1ae08745Sheppo 		return (MD_INVAL_DIFF_COOKIE);
134*1ae08745Sheppo 	}
135*1ae08745Sheppo 
136*1ae08745Sheppo 
137*1ae08745Sheppo 	/*
138*1ae08745Sheppo 	 * Prepare an array of the matching nodes from the second MD.
139*1ae08745Sheppo 	 */
140*1ae08745Sheppo 	if (mdd_scan_for_nodes(md2p,
141*1ae08745Sheppo 	    start2, compnodep, &md2count, &md2nodesp) == -1)
142*1ae08745Sheppo 		return (MD_INVAL_DIFF_COOKIE);
143*1ae08745Sheppo 
144*1ae08745Sheppo 	/* sanity check that all nodes are unique */
145*1ae08745Sheppo 	if (md2nodesp &&
146*1ae08745Sheppo 	    mdd_any_dup_nodes(md2, match_fieldsp, md2count, md2nodesp)) {
147*1ae08745Sheppo 		MDD_FREE_CHECK(md1, md1nodesp, sizeof (mde_cookie_t) *
148*1ae08745Sheppo 		    md1count);
149*1ae08745Sheppo 		MDD_FREE_CHECK(md2, md2nodesp, sizeof (mde_cookie_t) *
150*1ae08745Sheppo 		    md2count);
151*1ae08745Sheppo 		return (MD_INVAL_DIFF_COOKIE);
152*1ae08745Sheppo 	}
153*1ae08745Sheppo 
154*1ae08745Sheppo 	/* setup our result structure */
155*1ae08745Sheppo 	diff_res = md1->allocp(sizeof (md_diff_impl_t));
156*1ae08745Sheppo 	bzero(diff_res, sizeof (md_diff_impl_t));
157*1ae08745Sheppo 	diff_res->allocp = md1->allocp;
158*1ae08745Sheppo 	diff_res->freep = md1->freep;
159*1ae08745Sheppo 	diff_res->mdd_magic = MD_DIFF_MAGIC;
160*1ae08745Sheppo 
161*1ae08745Sheppo 	/*
162*1ae08745Sheppo 	 * Special cases for empty lists
163*1ae08745Sheppo 	 */
164*1ae08745Sheppo 	if ((md1count == 0) && (md2count != 0)) {
165*1ae08745Sheppo 		/* all the nodes found were added */
166*1ae08745Sheppo 		diff_res->added.mdep = md2nodesp;
167*1ae08745Sheppo 		diff_res->added.nelem = md2count;
168*1ae08745Sheppo 		return ((mde_cookie_t)diff_res);
169*1ae08745Sheppo 	}
170*1ae08745Sheppo 
171*1ae08745Sheppo 	if ((md1count != 0) && (md2count == 0)) {
172*1ae08745Sheppo 		/* all the nodes found were removed */
173*1ae08745Sheppo 		diff_res->removed.mdep = md1nodesp;
174*1ae08745Sheppo 		diff_res->removed.nelem = md1count;
175*1ae08745Sheppo 		return ((mde_cookie_t)diff_res);
176*1ae08745Sheppo 	}
177*1ae08745Sheppo 
178*1ae08745Sheppo 	if ((md1count == 0) && (md2count == 0))
179*1ae08745Sheppo 		/* no nodes found */
180*1ae08745Sheppo 		return ((mde_cookie_t)diff_res);
181*1ae08745Sheppo 
182*1ae08745Sheppo 	/*
183*1ae08745Sheppo 	 * Both lists have some elements. Allocate some scratch
184*1ae08745Sheppo 	 * buffers to sort them into our three categories, added,
185*1ae08745Sheppo 	 * removed, and matched pairs.
186*1ae08745Sheppo 	 */
187*1ae08745Sheppo 	mde_add_scr = diff_res->allocp(sizeof (mde_cookie_t) * md2count);
188*1ae08745Sheppo 	mde_rem_scr = diff_res->allocp(sizeof (mde_cookie_t) * md1count);
189*1ae08745Sheppo 	mde_match1_scr = diff_res->allocp(sizeof (mde_cookie_t) * md1count);
190*1ae08745Sheppo 	mde_match2_scr = diff_res->allocp(sizeof (mde_cookie_t) * md2count);
191*1ae08745Sheppo 
192*1ae08745Sheppo 	/* array of seen flags only needed for md2 */
193*1ae08745Sheppo 	seenp = (uint8_t *)diff_res->allocp(sizeof (uint8_t) * md2count);
194*1ae08745Sheppo 	bzero(seenp, sizeof (uint8_t) * md2count);
195*1ae08745Sheppo 
196*1ae08745Sheppo 	/*
197*1ae08745Sheppo 	 * Make a pass through the md1 node array. Make note of
198*1ae08745Sheppo 	 * any nodes not in the md2 array, indicating that they
199*1ae08745Sheppo 	 * have been removed. Also keep track of the nodes that
200*1ae08745Sheppo 	 * are present in both arrays for the matched pair results.
201*1ae08745Sheppo 	 */
202*1ae08745Sheppo 	for (idx = 0; idx < md1count; idx++) {
203*1ae08745Sheppo 
204*1ae08745Sheppo 		md_element_t *elem = &(md1->mdep[md1nodesp[idx]]);
205*1ae08745Sheppo 
206*1ae08745Sheppo 		int match = mdd_node_list_match(md1, md2, elem, md2nodesp,
207*1ae08745Sheppo 		    seenp, 0, md2count - 1, match_fieldsp);
208*1ae08745Sheppo 
209*1ae08745Sheppo 		if (match == MD_DIFF_NOMATCH)
210*1ae08745Sheppo 			/* record deleted node */
211*1ae08745Sheppo 			mde_rem_scr[nrem++] = md1nodesp[idx];
212*1ae08745Sheppo 		else {
213*1ae08745Sheppo 			/* record matched node pair */
214*1ae08745Sheppo 			mde_match1_scr[nmatch] = md1nodesp[idx];
215*1ae08745Sheppo 			mde_match2_scr[nmatch] = md2nodesp[match];
216*1ae08745Sheppo 			nmatch++;
217*1ae08745Sheppo 
218*1ae08745Sheppo 			/* mark that this match has been recorded */
219*1ae08745Sheppo 			seenp[match] = 1;
220*1ae08745Sheppo 		}
221*1ae08745Sheppo 	}
222*1ae08745Sheppo 
223*1ae08745Sheppo 	/*
224*1ae08745Sheppo 	 * Make a pass through the md2 array. Any nodes that have
225*1ae08745Sheppo 	 * not been marked as seen have been added.
226*1ae08745Sheppo 	 */
227*1ae08745Sheppo 	for (idx = 0; idx < md2count; idx++) {
228*1ae08745Sheppo 		if (!seenp[idx])
229*1ae08745Sheppo 			/* record added node */
230*1ae08745Sheppo 			mde_add_scr[nadd++] = md2nodesp[idx];
231*1ae08745Sheppo 	}
232*1ae08745Sheppo 
233*1ae08745Sheppo 	/* fill in the added node list */
234*1ae08745Sheppo 	if (nadd) {
235*1ae08745Sheppo 		int addsz = sizeof (mde_cookie_t) * nadd;
236*1ae08745Sheppo 		diff_res->added.mdep = (mde_cookie_t *)diff_res->allocp(addsz);
237*1ae08745Sheppo 
238*1ae08745Sheppo 		bcopy(mde_add_scr, diff_res->added.mdep, addsz);
239*1ae08745Sheppo 
240*1ae08745Sheppo 		diff_res->added.nelem = nadd;
241*1ae08745Sheppo 	}
242*1ae08745Sheppo 
243*1ae08745Sheppo 	/* fill in the removed node list */
244*1ae08745Sheppo 	if (nrem) {
245*1ae08745Sheppo 		int remsz = sizeof (mde_cookie_t) * nrem;
246*1ae08745Sheppo 		diff_res->removed.mdep =
247*1ae08745Sheppo 		    (mde_cookie_t *)diff_res->allocp(remsz);
248*1ae08745Sheppo 
249*1ae08745Sheppo 		bcopy(mde_rem_scr, diff_res->removed.mdep, remsz);
250*1ae08745Sheppo 		diff_res->removed.nelem = nrem;
251*1ae08745Sheppo 	}
252*1ae08745Sheppo 
253*1ae08745Sheppo 	/* fill in the matching node lists */
254*1ae08745Sheppo 	if (nmatch) {
255*1ae08745Sheppo 		int matchsz = sizeof (mde_cookie_t) * nmatch;
256*1ae08745Sheppo 		diff_res->match1.mdep =
257*1ae08745Sheppo 		    (mde_cookie_t *)diff_res->allocp(matchsz);
258*1ae08745Sheppo 		diff_res->match2.mdep =
259*1ae08745Sheppo 		    (mde_cookie_t *)diff_res->allocp(matchsz);
260*1ae08745Sheppo 
261*1ae08745Sheppo 		bcopy(mde_match1_scr, diff_res->match1.mdep, matchsz);
262*1ae08745Sheppo 		bcopy(mde_match2_scr, diff_res->match2.mdep, matchsz);
263*1ae08745Sheppo 		diff_res->match1.nelem = nmatch;
264*1ae08745Sheppo 		diff_res->match2.nelem = nmatch;
265*1ae08745Sheppo 	}
266*1ae08745Sheppo 
267*1ae08745Sheppo 	/* clean up */
268*1ae08745Sheppo 	md1->freep(md1nodesp, sizeof (mde_cookie_t) * md1count);
269*1ae08745Sheppo 	md2->freep(md2nodesp, sizeof (mde_cookie_t) * md2count);
270*1ae08745Sheppo 
271*1ae08745Sheppo 	diff_res->freep(mde_add_scr, sizeof (mde_cookie_t) * md2count);
272*1ae08745Sheppo 	diff_res->freep(mde_rem_scr, sizeof (mde_cookie_t) * md1count);
273*1ae08745Sheppo 	diff_res->freep(mde_match1_scr, sizeof (mde_cookie_t) * md1count);
274*1ae08745Sheppo 	diff_res->freep(mde_match2_scr, sizeof (mde_cookie_t) * md2count);
275*1ae08745Sheppo 
276*1ae08745Sheppo 	diff_res->freep(seenp, sizeof (uint8_t) * md2count);
277*1ae08745Sheppo 
278*1ae08745Sheppo 	return ((md_diff_cookie_t)diff_res);
279*1ae08745Sheppo }
280*1ae08745Sheppo 
281*1ae08745Sheppo /*
282*1ae08745Sheppo  * Returns an array of the nodes added to the second MD in a
283*1ae08745Sheppo  * previous md_diff_init() call. Returns the number of elements
284*1ae08745Sheppo  * in the returned array. If the value is zero, the pointer
285*1ae08745Sheppo  * passed back will be NULL.
286*1ae08745Sheppo  */
287*1ae08745Sheppo int
md_diff_added(md_diff_cookie_t mdd,mde_cookie_t ** mde_addedp)288*1ae08745Sheppo md_diff_added(md_diff_cookie_t mdd, mde_cookie_t **mde_addedp)
289*1ae08745Sheppo {
290*1ae08745Sheppo 	md_diff_impl_t	*mddp = (md_diff_impl_t *)mdd;
291*1ae08745Sheppo 
292*1ae08745Sheppo 	if ((mddp == NULL) || (mddp->mdd_magic != MD_DIFF_MAGIC))
293*1ae08745Sheppo 		return (-1);
294*1ae08745Sheppo 
295*1ae08745Sheppo 	*mde_addedp = mddp->added.mdep;
296*1ae08745Sheppo 
297*1ae08745Sheppo 	return (mddp->added.nelem);
298*1ae08745Sheppo }
299*1ae08745Sheppo 
300*1ae08745Sheppo /*
301*1ae08745Sheppo  * Returns an array of the nodes removed from the first MD in a
302*1ae08745Sheppo  * previous md_diff_init() call. Returns the number of elements
303*1ae08745Sheppo  * in the returned array. If the value is zero, the pointer
304*1ae08745Sheppo  * passed back will be NULL.
305*1ae08745Sheppo  */
306*1ae08745Sheppo int
md_diff_removed(md_diff_cookie_t mdd,mde_cookie_t ** mde_removedp)307*1ae08745Sheppo md_diff_removed(md_diff_cookie_t mdd, mde_cookie_t **mde_removedp)
308*1ae08745Sheppo {
309*1ae08745Sheppo 	md_diff_impl_t	*mddp = (md_diff_impl_t *)mdd;
310*1ae08745Sheppo 
311*1ae08745Sheppo 	if ((mddp == NULL) || (mddp->mdd_magic != MD_DIFF_MAGIC))
312*1ae08745Sheppo 		return (-1);
313*1ae08745Sheppo 
314*1ae08745Sheppo 	*mde_removedp = mddp->removed.mdep;
315*1ae08745Sheppo 
316*1ae08745Sheppo 	return (mddp->removed.nelem);
317*1ae08745Sheppo }
318*1ae08745Sheppo 
319*1ae08745Sheppo /*
320*1ae08745Sheppo  * Returns a pair of parallel arrays that contain nodes that were
321*1ae08745Sheppo  * considered matching based on the match criteria passed in to
322*1ae08745Sheppo  * a previous md_diff_init() call. Returns the number of elements
323*1ae08745Sheppo  * in the arrays. If the value is zero, both pointers passed back
324*1ae08745Sheppo  * will be NULL.
325*1ae08745Sheppo  */
326*1ae08745Sheppo int
md_diff_matched(md_diff_cookie_t mdd,mde_cookie_t ** mde_match1p,mde_cookie_t ** mde_match2p)327*1ae08745Sheppo md_diff_matched(md_diff_cookie_t mdd, mde_cookie_t **mde_match1p,
328*1ae08745Sheppo     mde_cookie_t **mde_match2p)
329*1ae08745Sheppo {
330*1ae08745Sheppo 	md_diff_impl_t	*mddp = (md_diff_impl_t *)mdd;
331*1ae08745Sheppo 
332*1ae08745Sheppo 	if ((mddp == NULL) || (mddp->mdd_magic != MD_DIFF_MAGIC))
333*1ae08745Sheppo 		return (-1);
334*1ae08745Sheppo 
335*1ae08745Sheppo 	*mde_match1p = mddp->match1.mdep;
336*1ae08745Sheppo 	*mde_match2p = mddp->match2.mdep;
337*1ae08745Sheppo 
338*1ae08745Sheppo 	return (mddp->match1.nelem);
339*1ae08745Sheppo }
340*1ae08745Sheppo 
341*1ae08745Sheppo /*
342*1ae08745Sheppo  * Deallocate any storage used to store results of a previous
343*1ae08745Sheppo  * md_diff_init() call. Returns 0 on success and -1 on failure.
344*1ae08745Sheppo  */
345*1ae08745Sheppo int
md_diff_fini(md_diff_cookie_t mdd)346*1ae08745Sheppo md_diff_fini(md_diff_cookie_t mdd)
347*1ae08745Sheppo {
348*1ae08745Sheppo 	md_diff_impl_t	*mddp = (md_diff_impl_t *)mdd;
349*1ae08745Sheppo 
350*1ae08745Sheppo 	if ((mddp == NULL) || (mddp->mdd_magic != MD_DIFF_MAGIC))
351*1ae08745Sheppo 		return (-1);
352*1ae08745Sheppo 
353*1ae08745Sheppo 	mddp->mdd_magic = 0;
354*1ae08745Sheppo 
355*1ae08745Sheppo 	MDD_FREE_CHECK(mddp, mddp->added.mdep, mddp->added.nelem *
356*1ae08745Sheppo 	    sizeof (mde_cookie_t));
357*1ae08745Sheppo 
358*1ae08745Sheppo 	MDD_FREE_CHECK(mddp, mddp->removed.mdep, mddp->removed.nelem *
359*1ae08745Sheppo 	    sizeof (mde_cookie_t));
360*1ae08745Sheppo 
361*1ae08745Sheppo 	MDD_FREE_CHECK(mddp, mddp->match1.mdep, mddp->match1.nelem *
362*1ae08745Sheppo 	    sizeof (mde_cookie_t));
363*1ae08745Sheppo 
364*1ae08745Sheppo 	MDD_FREE_CHECK(mddp, mddp->match2.mdep, mddp->match2.nelem *
365*1ae08745Sheppo 	    sizeof (mde_cookie_t));
366*1ae08745Sheppo 
367*1ae08745Sheppo 	mddp->freep(mddp, sizeof (md_diff_impl_t));
368*1ae08745Sheppo 
369*1ae08745Sheppo 	return (0);
370*1ae08745Sheppo }
371*1ae08745Sheppo 
372*1ae08745Sheppo /*
373*1ae08745Sheppo  * Walk the "fwd" DAG in an MD and return an array of nodes that are
374*1ae08745Sheppo  * of the specified type. The start param is used to start the walk
375*1ae08745Sheppo  * from an arbitrary location in the DAG. Returns an array of nodes
376*1ae08745Sheppo  * as well as a count of the number of nodes in the array.  If the
377*1ae08745Sheppo  * count is zero, the node pointer will be passed back as NULL.
378*1ae08745Sheppo  *
379*1ae08745Sheppo  * Returns: 0 success; -1 failure
380*1ae08745Sheppo  */
381*1ae08745Sheppo static int
mdd_scan_for_nodes(md_t * mdp,mde_cookie_t start,char * compnodep,int * countp,mde_cookie_t ** nodespp)382*1ae08745Sheppo mdd_scan_for_nodes(md_t *mdp,
383*1ae08745Sheppo     mde_cookie_t start, char *compnodep, int *countp, mde_cookie_t **nodespp)
384*1ae08745Sheppo {
385*1ae08745Sheppo 	mde_str_cookie_t	cname;
386*1ae08745Sheppo 	mde_str_cookie_t	aname;
387*1ae08745Sheppo 	md_impl_t		*mdip = (md_impl_t *)mdp;
388*1ae08745Sheppo 
389*1ae08745Sheppo 	if (mdip == NULL)
390*1ae08745Sheppo 		return (-1);
391*1ae08745Sheppo 
392*1ae08745Sheppo 	cname = md_find_name(mdp, compnodep);
393*1ae08745Sheppo 	aname = md_find_name(mdp, "fwd");
394*1ae08745Sheppo 
395*1ae08745Sheppo 	/* get the number of nodes of interest in the DAG */
396*1ae08745Sheppo 	*countp = md_scan_dag(mdp, start, cname, aname, NULL);
397*1ae08745Sheppo 	if (*countp == 0) {
398*1ae08745Sheppo 		*nodespp = NULL;
399*1ae08745Sheppo 		return (0);
400*1ae08745Sheppo 	}
401*1ae08745Sheppo 
402*1ae08745Sheppo 	/* allocate the storage */
403*1ae08745Sheppo 	*nodespp = mdip->allocp(sizeof (mde_cookie_t) * (*countp));
404*1ae08745Sheppo 
405*1ae08745Sheppo 	/* populate our array with the matching nodes */
406*1ae08745Sheppo 	(void) md_scan_dag(mdp, start, cname, aname, *nodespp);
407*1ae08745Sheppo 
408*1ae08745Sheppo 	return (0);
409*1ae08745Sheppo }
410*1ae08745Sheppo 
411*1ae08745Sheppo /*
412*1ae08745Sheppo  * Walk an array of nodes and check if there are any duplicate
413*1ae08745Sheppo  * nodes. A duplicate is determined based on the specified match
414*1ae08745Sheppo  * criteria. Returns B_TRUE if there are any duplicates and B_FALSE
415*1ae08745Sheppo  * otherwise.
416*1ae08745Sheppo  */
417*1ae08745Sheppo static boolean_t
mdd_any_dup_nodes(md_impl_t * mdp,md_prop_match_t * pmp,int count,mde_cookie_t * nodesp)418*1ae08745Sheppo mdd_any_dup_nodes(md_impl_t *mdp, md_prop_match_t *pmp, int count,
419*1ae08745Sheppo     mde_cookie_t *nodesp)
420*1ae08745Sheppo {
421*1ae08745Sheppo 	int		idx;
422*1ae08745Sheppo 	int		match;
423*1ae08745Sheppo 	md_element_t	*elem;
424*1ae08745Sheppo 
425*1ae08745Sheppo 	ASSERT(count > 0 || nodesp == NULL);
426*1ae08745Sheppo 
427*1ae08745Sheppo 	for (idx = 0; idx < count; idx++) {
428*1ae08745Sheppo 		elem = &(mdp->mdep[nodesp[idx]]);
429*1ae08745Sheppo 
430*1ae08745Sheppo 		match = mdd_node_list_match(mdp, mdp, elem, nodesp, NULL,
431*1ae08745Sheppo 		    idx + 1, count - 1, pmp);
432*1ae08745Sheppo 
433*1ae08745Sheppo 		if (match != MD_DIFF_NOMATCH)
434*1ae08745Sheppo 			return (B_TRUE);
435*1ae08745Sheppo 	}
436*1ae08745Sheppo 
437*1ae08745Sheppo 	return (B_FALSE);
438*1ae08745Sheppo }
439*1ae08745Sheppo 
440*1ae08745Sheppo /*
441*1ae08745Sheppo  * Given a node and a array of nodes, compare the node to all elements
442*1ae08745Sheppo  * in the specified start-end range of the array. If the node matches
443*1ae08745Sheppo  * one of the nodes in the array, return the index of that node. Otherwise
444*1ae08745Sheppo  * return MD_DIFF_NOMATCH.
445*1ae08745Sheppo  *
446*1ae08745Sheppo  * The optional seen array parameter can be used to optimize repeated
447*1ae08745Sheppo  * calls to this function. If the seen array indicates that an element
448*1ae08745Sheppo  * has already been matched, the full comparison is not necessary.
449*1ae08745Sheppo  */
450*1ae08745Sheppo static int
mdd_node_list_match(md_impl_t * md1,md_impl_t * md2,md_element_t * match_nodep,mde_cookie_t * match_listp,uint8_t * match_seenp,int start,int end,md_prop_match_t * match_elemsp)451*1ae08745Sheppo mdd_node_list_match(md_impl_t *md1, md_impl_t *md2, md_element_t *match_nodep,
452*1ae08745Sheppo     mde_cookie_t *match_listp, uint8_t *match_seenp, int start, int end,
453*1ae08745Sheppo     md_prop_match_t *match_elemsp)
454*1ae08745Sheppo {
455*1ae08745Sheppo 	int		match;
456*1ae08745Sheppo 	int		idx;
457*1ae08745Sheppo 	md_element_t	*elem;
458*1ae08745Sheppo 
459*1ae08745Sheppo 	for (idx = start; idx <= end; idx++) {
460*1ae08745Sheppo 
461*1ae08745Sheppo 		if ((match_seenp != NULL) && (match_seenp[idx]))
462*1ae08745Sheppo 			continue;
463*1ae08745Sheppo 
464*1ae08745Sheppo 		elem = &(md2->mdep[match_listp[idx]]);
465*1ae08745Sheppo 
466*1ae08745Sheppo 		match = mdd_node_compare(md1, md2, match_nodep, elem,
467*1ae08745Sheppo 		    match_elemsp);
468*1ae08745Sheppo 		if (match == MD_DIFF_MATCH)
469*1ae08745Sheppo 			return (idx);
470*1ae08745Sheppo 	}
471*1ae08745Sheppo 
472*1ae08745Sheppo 	return (MD_DIFF_NOMATCH);
473*1ae08745Sheppo }
474*1ae08745Sheppo 
475*1ae08745Sheppo /*
476*1ae08745Sheppo  * Given two nodes and a list of properties, compare the nodes.
477*1ae08745Sheppo  * A match is concluded if both nodes have all of the specified
478*1ae08745Sheppo  * properties and all the values of those properties are the
479*1ae08745Sheppo  * same. Returns MD_DIFF_NOMATCH if the nodes do not match and
480*1ae08745Sheppo  * MD_DIFF_MATCH otherwise.
481*1ae08745Sheppo  */
482*1ae08745Sheppo static int
mdd_node_compare(md_impl_t * mdap,md_impl_t * mdbp,md_element_t * nodeap,md_element_t * nodebp,md_prop_match_t * match_elemsp)483*1ae08745Sheppo mdd_node_compare(md_impl_t *mdap, md_impl_t *mdbp, md_element_t *nodeap,
484*1ae08745Sheppo     md_element_t *nodebp, md_prop_match_t *match_elemsp)
485*1ae08745Sheppo {
486*1ae08745Sheppo 	md_element_t	*ap;
487*1ae08745Sheppo 	md_element_t	*bp;
488*1ae08745Sheppo 	boolean_t	nodea_interest;
489*1ae08745Sheppo 	boolean_t	nodeb_interest;
490*1ae08745Sheppo 	int		idx;
491*1ae08745Sheppo 
492*1ae08745Sheppo 	/* make sure we are starting at the beginning of the nodes */
493*1ae08745Sheppo 	if ((MDE_TAG(nodeap) != MDET_NODE) || (MDE_TAG(nodebp) != MDET_NODE))
494*1ae08745Sheppo 		return (MD_DIFF_NOMATCH);
495*1ae08745Sheppo 
496*1ae08745Sheppo 	for (idx = 0; match_elemsp[idx].type != MDET_LIST_END; idx++) {
497*1ae08745Sheppo 
498*1ae08745Sheppo 		int type;
499*1ae08745Sheppo 
500*1ae08745Sheppo 		nodea_interest = B_FALSE;
501*1ae08745Sheppo 		nodeb_interest = B_FALSE;
502*1ae08745Sheppo 
503*1ae08745Sheppo 		type = match_elemsp[idx].type;
504*1ae08745Sheppo 
505*1ae08745Sheppo 		/*
506*1ae08745Sheppo 		 * Check node A for the property of interest
507*1ae08745Sheppo 		 */
508*1ae08745Sheppo 		for (ap = nodeap; MDE_TAG(ap) != MDET_NODE_END; ap++) {
509*1ae08745Sheppo 			char *elemname;
510*1ae08745Sheppo 
511*1ae08745Sheppo 			if (MDE_TAG(ap) != type)
512*1ae08745Sheppo 				continue;
513*1ae08745Sheppo 
514*1ae08745Sheppo 			elemname = mdap->namep + MDE_NAME(ap);
515*1ae08745Sheppo 
516*1ae08745Sheppo 			if (strcmp(elemname, match_elemsp[idx].namep) == 0) {
517*1ae08745Sheppo 				/* found the property of interest */
518*1ae08745Sheppo 				nodea_interest = B_TRUE;
519*1ae08745Sheppo 				break;
520*1ae08745Sheppo 			}
521*1ae08745Sheppo 		}
522*1ae08745Sheppo 
523*1ae08745Sheppo 		/* node A is not of interest */
524*1ae08745Sheppo 		if (!nodea_interest)
525*1ae08745Sheppo 			return (MD_DIFF_NOMATCH);
526*1ae08745Sheppo 
527*1ae08745Sheppo 		/*
528*1ae08745Sheppo 		 * Check node B for the property of interest
529*1ae08745Sheppo 		 */
530*1ae08745Sheppo 		for (bp = nodebp; MDE_TAG(bp) != MDET_NODE_END; bp++) {
531*1ae08745Sheppo 			char *elemname;
532*1ae08745Sheppo 
533*1ae08745Sheppo 			if (MDE_TAG(bp) != type)
534*1ae08745Sheppo 				continue;
535*1ae08745Sheppo 
536*1ae08745Sheppo 			elemname = mdbp->namep + MDE_NAME(bp);
537*1ae08745Sheppo 
538*1ae08745Sheppo 			if (strcmp(elemname, match_elemsp[idx].namep) == 0) {
539*1ae08745Sheppo 				nodeb_interest = B_TRUE;
540*1ae08745Sheppo 				break;
541*1ae08745Sheppo 			}
542*1ae08745Sheppo 		}
543*1ae08745Sheppo 
544*1ae08745Sheppo 		/* node B is not of interest */
545*1ae08745Sheppo 		if (!nodeb_interest)
546*1ae08745Sheppo 			return (MD_DIFF_NOMATCH);
547*1ae08745Sheppo 
548*1ae08745Sheppo 		/*
549*1ae08745Sheppo 		 * Both nodes have the property of interest. The
550*1ae08745Sheppo 		 * nodes are not a match unless the value of that
551*1ae08745Sheppo 		 * property match
552*1ae08745Sheppo 		 */
553*1ae08745Sheppo 		switch (type) {
554*1ae08745Sheppo 		case MDET_PROP_VAL:
555*1ae08745Sheppo 			if (MDE_PROP_VALUE(ap) != MDE_PROP_VALUE(bp))
556*1ae08745Sheppo 				return (MD_DIFF_NOMATCH);
557*1ae08745Sheppo 			break;
558*1ae08745Sheppo 
559*1ae08745Sheppo 		case MDET_PROP_STR: {
560*1ae08745Sheppo 			char *stra = (char *)(mdap->datap +
561*1ae08745Sheppo 			    MDE_PROP_DATA_OFFSET(ap));
562*1ae08745Sheppo 			char *strb = (char *)(mdbp->datap +
563*1ae08745Sheppo 			    MDE_PROP_DATA_OFFSET(bp));
564*1ae08745Sheppo 
565*1ae08745Sheppo 			if (strcmp(stra, strb) != 0)
566*1ae08745Sheppo 				return (MD_DIFF_NOMATCH);
567*1ae08745Sheppo 			break;
568*1ae08745Sheppo 		}
569*1ae08745Sheppo 
570*1ae08745Sheppo 		case MDET_PROP_DAT: {
571*1ae08745Sheppo 
572*1ae08745Sheppo 			caddr_t dataa;
573*1ae08745Sheppo 			caddr_t datab;
574*1ae08745Sheppo 
575*1ae08745Sheppo 			if (MDE_PROP_DATA_LEN(ap) != MDE_PROP_DATA_LEN(bp))
576*1ae08745Sheppo 				return (MD_DIFF_NOMATCH);
577*1ae08745Sheppo 
578*1ae08745Sheppo 			dataa = (caddr_t)(mdap->datap +
579*1ae08745Sheppo 			    MDE_PROP_DATA_OFFSET(ap));
580*1ae08745Sheppo 			datab = (caddr_t)(mdbp->datap +
581*1ae08745Sheppo 			    MDE_PROP_DATA_OFFSET(bp));
582*1ae08745Sheppo 
583*1ae08745Sheppo 			if (memcmp(dataa, datab, MDE_PROP_DATA_LEN(ap)) != 0)
584*1ae08745Sheppo 				return (MD_DIFF_NOMATCH);
585*1ae08745Sheppo 
586*1ae08745Sheppo 			break;
587*1ae08745Sheppo 		}
588*1ae08745Sheppo 
589*1ae08745Sheppo 		default:
590*1ae08745Sheppo 			/* unsupported prop type */
591*1ae08745Sheppo 			return (MD_DIFF_NOMATCH);
592*1ae08745Sheppo 		}
593*1ae08745Sheppo 	}
594*1ae08745Sheppo 
595*1ae08745Sheppo 	/*
596*1ae08745Sheppo 	 * All the specified properties exist in both
597*1ae08745Sheppo 	 * nodes and have the same value. The two nodes
598*1ae08745Sheppo 	 * match.
599*1ae08745Sheppo 	 */
600*1ae08745Sheppo 
601*1ae08745Sheppo 	return (MD_DIFF_MATCH);
602*1ae08745Sheppo }
603