xref: /csrg-svn/usr.sbin/config.new/pack.c (revision 57493)
1*57493Storek /*
2*57493Storek  * Copyright (c) 1992 The Regents of the University of California.
3*57493Storek  * All rights reserved.
4*57493Storek  *
5*57493Storek  * This software was developed by the Computer Systems Engineering group
6*57493Storek  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
7*57493Storek  * contributed to Berkeley.
8*57493Storek  *
9*57493Storek  * All advertising materials mentioning features or use of this software
10*57493Storek  * must display the following acknowledgement:
11*57493Storek  *	This product includes software developed by the University of
12*57493Storek  *	California, Lawrence Berkeley Laboratories.
13*57493Storek  *
14*57493Storek  * %sccs.include.redist.c%
15*57493Storek  *
16*57493Storek  *	@(#)pack.c	5.1 (Berkeley) 01/12/93
17*57493Storek  *
18*57493Storek  * from: $Header: pack.c,v 1.2 92/10/10 09:01:35 torek Exp $
19*57493Storek  */
20*57493Storek 
21*57493Storek #include <sys/param.h>
22*57493Storek #include <stdlib.h>
23*57493Storek #include <string.h>
24*57493Storek #include "config.h"
25*57493Storek 
26*57493Storek /*
27*57493Storek  * Packing.  We have three separate kinds of packing here.
28*57493Storek  *
29*57493Storek  * First, we pack device instances, to collapse things like
30*57493Storek  *
31*57493Storek  *	uba0 at sbi0 nexus ?
32*57493Storek  *	uba0 at bi0 nexus ?
33*57493Storek  *
34*57493Storek  * into a single instance that is "at sbi0 or bi0".
35*57493Storek  *
36*57493Storek  * Second, we pack locators.  Given something like
37*57493Storek  *
38*57493Storek  *	hp0 at mba0 drive 0
39*57493Storek  *	hp* at mba* drive ?
40*57493Storek  *	ht0 at mba0 drive 0
41*57493Storek  *	tu0 at ht0 slave 0
42*57493Storek  *	ht* at mba* drive ?
43*57493Storek  *	tu* at ht* slave ?
44*57493Storek  *
45*57493Storek  * (where the default drive and slave numbers are -1), we have three
46*57493Storek  * locators whose value is 0 and three whose value is -1.  Rather than
47*57493Storek  * emitting six integers, we emit just two.
48*57493Storek  *
49*57493Storek  * Finally, we pack parent vectors.  This is very much like packing
50*57493Storek  * locators.  Unlike locators, however, parent vectors are always
51*57493Storek  * terminated by -1 (rather like the way C strings always end with
52*57493Storek  * a NUL).
53*57493Storek  *
54*57493Storek  * When packing locators, we would like to find sequences such as
55*57493Storek  *	{1 2 3} {2 3 4} {3} {4 5}
56*57493Storek  * and turn this into the flat sequence {1 2 3 4 5}, with each subsequence
57*57493Storek  * given by the appropriate offset (here 0, 1, 2, and 3 respectively).
58*57493Storek  * When we pack parent vectors, overlap of this sort is impossible.
59*57493Storek  * Non-overlapping packing is much easier, and so we use that here
60*57493Storek  * and miss out on the chance to squeeze the locator sequence optimally.
61*57493Storek  * (So it goes.)
62*57493Storek  */
63*57493Storek 
64*57493Storek typedef int (*vec_cmp_func) __P((const void *, int, int));
65*57493Storek 
66*57493Storek #define	TAILHSIZE	128
67*57493Storek #define	PVHASH(i)	((i) & (TAILHSIZE - 1))
68*57493Storek #define	LOCHASH(l)	(((int)(l) >> 2) & (TAILHSIZE - 1))
69*57493Storek struct tails {
70*57493Storek 	struct	tails *t_next;
71*57493Storek 	int	t_ends_at;
72*57493Storek };
73*57493Storek 
74*57493Storek static struct tails *tails[TAILHSIZE];
75*57493Storek static int locspace;
76*57493Storek static int pvecspace;
77*57493Storek static int longest_pvec;
78*57493Storek 
79*57493Storek static void packdevi __P((void));
80*57493Storek static void packlocs __P((void));
81*57493Storek static void packpvec __P((void));
82*57493Storek 
83*57493Storek static void addparents __P((struct devi *src, struct devi *dst));
84*57493Storek static int nparents __P((struct devi **, struct devbase *, int));
85*57493Storek static int sameas __P((struct devi *, struct devi *));
86*57493Storek static int findvec __P((const void *, int, int, vec_cmp_func, int));
87*57493Storek static int samelocs __P((const void *, int, int));
88*57493Storek static int addlocs __P((const char **, int));
89*57493Storek static int loclencmp __P((const void *, const void *));
90*57493Storek static int samepv __P((const void *, int, int));
91*57493Storek static int addpv __P((short *, int));
92*57493Storek static int pvlencmp __P((const void *, const void *));
93*57493Storek static void resettails __P((void));
94*57493Storek 
95*57493Storek void
96*57493Storek pack()
97*57493Storek {
98*57493Storek 	register struct devi *i;
99*57493Storek 	register int n;
100*57493Storek 
101*57493Storek 	/* Pack instances and make parent vectors. */
102*57493Storek 	packdevi();
103*57493Storek 
104*57493Storek 	/*
105*57493Storek 	 * Now that we know what we have, find upper limits on space
106*57493Storek 	 * needed for the loc[] and pv[] tables, and find the longest
107*57493Storek 	 * single pvec.  The loc and pv table sizes are bounded by
108*57493Storek 	 * what we would get if no packing occurred.
109*57493Storek 	 */
110*57493Storek 	locspace = pvecspace = 0;
111*57493Storek 	for (i = alldevi; i != NULL; i = i->i_next) {
112*57493Storek 		if (i->i_collapsed)
113*57493Storek 			continue;
114*57493Storek 		locspace += i->i_atattr->a_loclen;
115*57493Storek 		n = i->i_pvlen + 1;
116*57493Storek 		if (n > longest_pvec)
117*57493Storek 			longest_pvec = n;
118*57493Storek 		pvecspace += n;
119*57493Storek 	}
120*57493Storek 
121*57493Storek 	/* Allocate and pack loc[]. */
122*57493Storek 	locators.vec = emalloc(locspace * sizeof(*locators.vec));
123*57493Storek 	locators.used = 0;
124*57493Storek 	packlocs();
125*57493Storek 
126*57493Storek 	/* Allocate and pack pv[]. */
127*57493Storek 	parents.vec = emalloc(pvecspace * sizeof(*parents.vec));
128*57493Storek 	parents.used = 0;
129*57493Storek 	packpvec();
130*57493Storek }
131*57493Storek 
132*57493Storek /*
133*57493Storek  * Pack instances together wherever possible.  When everything is
134*57493Storek  * packed, go back and set up the parents for each.  We must do this
135*57493Storek  * on a second pass because during the first one, we do not know which,
136*57493Storek  * if any, of the parents will collapse during packing.
137*57493Storek  */
138*57493Storek void
139*57493Storek packdevi()
140*57493Storek {
141*57493Storek 	register struct devi *i, *l, *p;
142*57493Storek 	register struct devbase *d;
143*57493Storek 	register int j, m, n;
144*57493Storek 
145*57493Storek 	packed = emalloc((ndevi + 1) * sizeof *packed);
146*57493Storek 	n = 0;
147*57493Storek 	for (d = allbases; d != NULL; d = d->d_next) {
148*57493Storek 		/*
149*57493Storek 		 * For each instance of each device, add or collapse
150*57493Storek 		 * all its aliases.
151*57493Storek 		 */
152*57493Storek 		for (i = d->d_ihead; i != NULL; i = i->i_bsame) {
153*57493Storek 			m = n;
154*57493Storek 			for (l = i; l != NULL; l = l->i_alias) {
155*57493Storek 				l->i_pvlen = 0;
156*57493Storek 				l->i_pvoff = -1;
157*57493Storek 				l->i_locoff = -1;
158*57493Storek 				l->i_ivoff = -1;
159*57493Storek 				/* try to find an equivalent for l */
160*57493Storek 				for (j = m; j < n; j++) {
161*57493Storek 					p = packed[j];
162*57493Storek 					if (sameas(l, p)) {
163*57493Storek 						l->i_collapsed = 1;
164*57493Storek 						l->i_cfindex = p->i_cfindex;
165*57493Storek 						goto nextalias;
166*57493Storek 					}
167*57493Storek 				}
168*57493Storek 				/* could not find a suitable alias */
169*57493Storek 				l->i_collapsed = 0;
170*57493Storek 				l->i_cfindex = n;
171*57493Storek 				l->i_parents = emalloc(sizeof(*l->i_parents));
172*57493Storek 				l->i_parents[0] = NULL;
173*57493Storek 				packed[n++] = l;
174*57493Storek 			nextalias:;
175*57493Storek 			}
176*57493Storek 		}
177*57493Storek 	}
178*57493Storek 	npacked = n;
179*57493Storek 	packed[n] = NULL;
180*57493Storek 	for (i = alldevi; i != NULL; i = i->i_next)
181*57493Storek 		addparents(i, packed[i->i_cfindex]);
182*57493Storek }
183*57493Storek 
184*57493Storek /*
185*57493Storek  * Return true if two aliases are "the same".  In this case, they need
186*57493Storek  * to have the same config flags and the same locators.
187*57493Storek  */
188*57493Storek static int
189*57493Storek sameas(i1, i2)
190*57493Storek 	register struct devi *i1, *i2;
191*57493Storek {
192*57493Storek 	register const char **p1, **p2;
193*57493Storek 
194*57493Storek 	if (i1->i_cfflags != i2->i_cfflags)
195*57493Storek 		return (0);
196*57493Storek 	for (p1 = i1->i_locs, p2 = i2->i_locs; *p1 == *p2; p2++)
197*57493Storek 		if (*p1++ == 0)
198*57493Storek 			return (1);
199*57493Storek 	return 0;
200*57493Storek }
201*57493Storek 
202*57493Storek /*
203*57493Storek  * Add the parents associated with "src" to the (presumably uncollapsed)
204*57493Storek  * instance "dst".
205*57493Storek  */
206*57493Storek static void
207*57493Storek addparents(src, dst)
208*57493Storek 	register struct devi *src, *dst;
209*57493Storek {
210*57493Storek 	register struct nvlist *nv;
211*57493Storek 	register struct devi *i, **p, **q;
212*57493Storek 	register int j, n, old, new, ndup;
213*57493Storek 
214*57493Storek 	if (dst->i_collapsed)
215*57493Storek 		panic("addparents() i_collapsed");
216*57493Storek 
217*57493Storek 	/* Collect up list of parents to add. */
218*57493Storek 	if (src->i_at == NULL)	/* none, 'cuz "at root" */
219*57493Storek 		return;
220*57493Storek 	if (src->i_atdev != NULL) {
221*57493Storek 		n = nparents(NULL, src->i_atdev, src->i_atunit);
222*57493Storek 		p = emalloc(n * sizeof *p);
223*57493Storek 		if (n == 0)
224*57493Storek 			return;
225*57493Storek 		(void)nparents(p, src->i_atdev, src->i_atunit);
226*57493Storek 	} else {
227*57493Storek 		n = 0;
228*57493Storek 		for (nv = src->i_atattr->a_refs; nv != NULL; nv = nv->nv_next)
229*57493Storek 			n += nparents(NULL, nv->nv_ptr, src->i_atunit);
230*57493Storek 		if (n == 0)
231*57493Storek 			return;
232*57493Storek 		p = emalloc(n * sizeof *p);
233*57493Storek 		n = 0;
234*57493Storek 		for (nv = src->i_atattr->a_refs; nv != NULL; nv = nv->nv_next)
235*57493Storek 			n += nparents(p + n, nv->nv_ptr, src->i_atunit);
236*57493Storek 	}
237*57493Storek 	/* Now elide duplicates. */
238*57493Storek 	ndup = 0;
239*57493Storek 	for (j = 0; j < n; j++) {
240*57493Storek 		i = p[j];
241*57493Storek 		for (q = dst->i_parents; *q != NULL; q++) {
242*57493Storek 			if (*q == i) {
243*57493Storek 				ndup++;
244*57493Storek 				p[j] = NULL;
245*57493Storek 				break;
246*57493Storek 			}
247*57493Storek 		}
248*57493Storek 	}
249*57493Storek 	/* Finally, add all the non-duplicates. */
250*57493Storek 	old = dst->i_pvlen;
251*57493Storek 	new = old + (n - ndup);
252*57493Storek 	if (old > new)
253*57493Storek 		panic("addparents() old > new");
254*57493Storek 	if (old == new) {
255*57493Storek 		free(p);
256*57493Storek 		return;
257*57493Storek 	}
258*57493Storek 	dst->i_parents = q = erealloc(dst->i_parents, (new + 1) * sizeof(*q));
259*57493Storek 	dst->i_pvlen = new;
260*57493Storek 	q[new] = NULL;
261*57493Storek 	q += old;
262*57493Storek 	for (j = 0; j < n; j++)
263*57493Storek 		if (p[j] != NULL)
264*57493Storek 			*q++ = p[j];
265*57493Storek 	free(p);
266*57493Storek }
267*57493Storek 
268*57493Storek /*
269*57493Storek  * Count up parents, and optionally store pointers to each.
270*57493Storek  */
271*57493Storek static int
272*57493Storek nparents(p, dev, unit)
273*57493Storek 	register struct devi **p;
274*57493Storek 	register struct devbase *dev;
275*57493Storek 	register int unit;
276*57493Storek {
277*57493Storek 	register struct devi *i, *l;
278*57493Storek 	register int n;
279*57493Storek 
280*57493Storek 	n = 0;
281*57493Storek 	/* for each instance ... */
282*57493Storek 	for (i = dev->d_ihead; i != NULL; i = i->i_bsame) {
283*57493Storek 		/* ... take each un-collapsed alias */
284*57493Storek 		for (l = i; l != NULL; l = l->i_alias) {
285*57493Storek 			if (!l->i_collapsed &&
286*57493Storek 			    (unit == WILD || unit == l->i_unit)) {
287*57493Storek 				if (p != NULL)
288*57493Storek 					*p++ = l;
289*57493Storek 				n++;
290*57493Storek 			}
291*57493Storek 		}
292*57493Storek 	}
293*57493Storek 	return (n);
294*57493Storek }
295*57493Storek 
296*57493Storek static void
297*57493Storek packlocs()
298*57493Storek {
299*57493Storek 	register struct devi **p, *i;
300*57493Storek 	register int l, o;
301*57493Storek 
302*57493Storek 	qsort(packed, npacked, sizeof *packed, loclencmp);
303*57493Storek 	for (p = packed; (i = *p) != NULL; p++) {
304*57493Storek 		if ((l = i->i_atattr->a_loclen) > 0) {
305*57493Storek 			o = findvec(i->i_locs, LOCHASH(i->i_locs[l - 1]), l,
306*57493Storek 				    samelocs, locators.used);
307*57493Storek 			i->i_locoff = o < 0 ? addlocs(i->i_locs, l) : o;
308*57493Storek 		} else
309*57493Storek 			i->i_locoff = -1;
310*57493Storek 	}
311*57493Storek 	resettails();
312*57493Storek }
313*57493Storek 
314*57493Storek static void
315*57493Storek packpvec()
316*57493Storek {
317*57493Storek 	register struct devi **p, *i, **par;
318*57493Storek 	register int l, v, o;
319*57493Storek 	register short *vec;
320*57493Storek 
321*57493Storek 	vec = emalloc(longest_pvec * sizeof(*vec));
322*57493Storek 	qsort(packed, npacked, sizeof *packed, pvlencmp);
323*57493Storek 	for (p = packed; (i = *p) != NULL; p++) {
324*57493Storek 		l = i->i_pvlen;
325*57493Storek if (l > longest_pvec) panic("packpvec");
326*57493Storek 		par = i->i_parents;
327*57493Storek 		for (v = 0; v < l; v++)
328*57493Storek 			vec[v] = par[v]->i_cfindex;
329*57493Storek 		if (l == 0 ||
330*57493Storek 		    (o = findvec(vec, PVHASH(vec[l - 1]), l,
331*57493Storek 			    samepv, parents.used)) < 0)
332*57493Storek 		    	o = addpv(vec, l);
333*57493Storek 		i->i_pvoff = o;
334*57493Storek 	}
335*57493Storek 	free(vec);
336*57493Storek 	resettails();
337*57493Storek }
338*57493Storek 
339*57493Storek /*
340*57493Storek  * Return the index at which the given vector already exists, or -1
341*57493Storek  * if it is not anywhere in the current set.  If we return -1, we assume
342*57493Storek  * our caller will add it at the end of the current set, and we make
343*57493Storek  * sure that next time, we will find it there.
344*57493Storek  */
345*57493Storek static int
346*57493Storek findvec(ptr, hash, len, cmp, nextplace)
347*57493Storek 	const void *ptr;
348*57493Storek 	int hash, len;
349*57493Storek 	vec_cmp_func cmp;
350*57493Storek 	int nextplace;
351*57493Storek {
352*57493Storek 	register struct tails *t, **hp;
353*57493Storek 	register int off;
354*57493Storek 
355*57493Storek 	hp = &tails[hash];
356*57493Storek 	for (t = *hp; t != NULL; t = t->t_next) {
357*57493Storek 		off = t->t_ends_at - len;
358*57493Storek 		if (off >= 0 && (*cmp)(ptr, off, len))
359*57493Storek 			return (off);
360*57493Storek 	}
361*57493Storek 	t = emalloc(sizeof(*t));
362*57493Storek 	t->t_next = *hp;
363*57493Storek 	*hp = t;
364*57493Storek 	t->t_ends_at = nextplace + len;
365*57493Storek 	return (-1);
366*57493Storek }
367*57493Storek 
368*57493Storek /*
369*57493Storek  * Comparison function for locators.
370*57493Storek  */
371*57493Storek static int
372*57493Storek samelocs(ptr, off, len)
373*57493Storek 	const void *ptr;
374*57493Storek 	int off;
375*57493Storek 	register int len;
376*57493Storek {
377*57493Storek 	register const char **p, **q;
378*57493Storek 
379*57493Storek 	for (p = &locators.vec[off], q = (const char **)ptr; --len >= 0;)
380*57493Storek 		if (*p++ != *q++)
381*57493Storek 			return (0);	/* different */
382*57493Storek 	return (1);			/* same */
383*57493Storek }
384*57493Storek 
385*57493Storek /*
386*57493Storek  * Add the given locators at the end of the global loc[] table.
387*57493Storek  */
388*57493Storek static int
389*57493Storek addlocs(locs, len)
390*57493Storek 	register const char **locs;
391*57493Storek 	register int len;
392*57493Storek {
393*57493Storek 	register const char **p;
394*57493Storek 	register int ret;
395*57493Storek 
396*57493Storek 	ret = locators.used;
397*57493Storek 	if ((locators.used = ret + len) > locspace)
398*57493Storek 		panic("addlocs: overrun");
399*57493Storek 	for (p = &locators.vec[ret]; --len >= 0;)
400*57493Storek 		*p++ = *locs++;
401*57493Storek 	return (ret);
402*57493Storek }
403*57493Storek 
404*57493Storek /*
405*57493Storek  * Comparison function for qsort-by-locator-length, longest first.
406*57493Storek  * We rashly assume that subtraction of these lengths does not overflow.
407*57493Storek  */
408*57493Storek static int
409*57493Storek loclencmp(a, b)
410*57493Storek 	const void *a, *b;
411*57493Storek {
412*57493Storek 	register int l1, l2;
413*57493Storek 
414*57493Storek 	l1 = (*(struct devi **)a)->i_atattr->a_loclen;
415*57493Storek 	l2 = (*(struct devi **)b)->i_atattr->a_loclen;
416*57493Storek 	return (l2 - l1);
417*57493Storek }
418*57493Storek 
419*57493Storek /*
420*57493Storek  * Comparison function for parent vectors.
421*57493Storek  */
422*57493Storek static int
423*57493Storek samepv(ptr, off, len)
424*57493Storek 	const void *ptr;
425*57493Storek 	int off;
426*57493Storek 	register int len;
427*57493Storek {
428*57493Storek 	register short *p, *q;
429*57493Storek 
430*57493Storek 	for (p = &parents.vec[off], q = (short *)ptr; --len >= 0;)
431*57493Storek 		if (*p++ != *q++)
432*57493Storek 			return (0);	/* different */
433*57493Storek 	return (1);			/* same */
434*57493Storek }
435*57493Storek 
436*57493Storek /*
437*57493Storek  * Add the given parent vectors at the end of the global pv[] table.
438*57493Storek  */
439*57493Storek static int
440*57493Storek addpv(pv, len)
441*57493Storek 	register short *pv;
442*57493Storek 	register int len;
443*57493Storek {
444*57493Storek 	register short *p;
445*57493Storek 	register int ret;
446*57493Storek 	static int firstend = -1;
447*57493Storek 
448*57493Storek 	/*
449*57493Storek 	 * If the vector is empty, reuse the first -1.  It will be
450*57493Storek 	 * there if there are any nonempty vectors at all, since we
451*57493Storek 	 * do the longest first.  If there are no nonempty vectors,
452*57493Storek 	 * something is probably wrong, but we will ignore that here.
453*57493Storek 	 */
454*57493Storek 	if (len == 0 && firstend >= 0)
455*57493Storek 		return (firstend);
456*57493Storek 	len++;			/* account for trailing -1 */
457*57493Storek 	ret = parents.used;
458*57493Storek 	if ((parents.used = ret + len) > pvecspace)
459*57493Storek 		panic("addpv: overrun");
460*57493Storek 	for (p = &parents.vec[ret]; --len > 0;)
461*57493Storek 		*p++ = *pv++;
462*57493Storek 	*p = -1;
463*57493Storek 	if (firstend < 0)
464*57493Storek 		firstend = parents.used - 1;
465*57493Storek 	return (ret);
466*57493Storek }
467*57493Storek 
468*57493Storek /*
469*57493Storek  * Comparison function for qsort-by-parent-vector-length, longest first.
470*57493Storek  * We rashly assume that subtraction of these lengths does not overflow.
471*57493Storek  */
472*57493Storek static int
473*57493Storek pvlencmp(a, b)
474*57493Storek 	const void *a, *b;
475*57493Storek {
476*57493Storek 	register int l1, l2;
477*57493Storek 
478*57493Storek 	l1 = (*(struct devi **)a)->i_pvlen;
479*57493Storek 	l2 = (*(struct devi **)b)->i_pvlen;
480*57493Storek 	return (l2 - l1);
481*57493Storek }
482*57493Storek 
483*57493Storek static void
484*57493Storek resettails()
485*57493Storek {
486*57493Storek 	register struct tails **p, *t, *next;
487*57493Storek 	register int i;
488*57493Storek 
489*57493Storek 	for (p = tails, i = TAILHSIZE; --i >= 0; p++) {
490*57493Storek 		for (t = *p; t != NULL; t = next) {
491*57493Storek 			next = t->t_next;
492*57493Storek 			free(t);
493*57493Storek 		}
494*57493Storek 		*p = NULL;
495*57493Storek 	}
496*57493Storek }
497