xref: /csrg-svn/usr.sbin/config.new/pack.c (revision 61818)
157493Storek /*
2*61818Sbostic  * Copyright (c) 1992, 1993
3*61818Sbostic  *	The Regents of the University of California.  All rights reserved.
457493Storek  *
557493Storek  * This software was developed by the Computer Systems Engineering group
657493Storek  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
757493Storek  * contributed to Berkeley.
857493Storek  *
957493Storek  * All advertising materials mentioning features or use of this software
1057493Storek  * must display the following acknowledgement:
1157493Storek  *	This product includes software developed by the University of
1257493Storek  *	California, Lawrence Berkeley Laboratories.
1357493Storek  *
1457493Storek  * %sccs.include.redist.c%
1557493Storek  *
16*61818Sbostic  *	@(#)pack.c	8.1 (Berkeley) 06/06/93
1757493Storek  */
1857493Storek 
1957493Storek #include <sys/param.h>
2057493Storek #include <stdlib.h>
2157493Storek #include <string.h>
2257493Storek #include "config.h"
2357493Storek 
2457493Storek /*
2557493Storek  * Packing.  We have three separate kinds of packing here.
2657493Storek  *
2757493Storek  * First, we pack device instances, to collapse things like
2857493Storek  *
2957493Storek  *	uba0 at sbi0 nexus ?
3057493Storek  *	uba0 at bi0 nexus ?
3157493Storek  *
3257493Storek  * into a single instance that is "at sbi0 or bi0".
3357493Storek  *
3457493Storek  * Second, we pack locators.  Given something like
3557493Storek  *
3657493Storek  *	hp0 at mba0 drive 0
3757493Storek  *	hp* at mba* drive ?
3857493Storek  *	ht0 at mba0 drive 0
3957493Storek  *	tu0 at ht0 slave 0
4057493Storek  *	ht* at mba* drive ?
4157493Storek  *	tu* at ht* slave ?
4257493Storek  *
4357493Storek  * (where the default drive and slave numbers are -1), we have three
4457493Storek  * locators whose value is 0 and three whose value is -1.  Rather than
4557493Storek  * emitting six integers, we emit just two.
4657493Storek  *
4757493Storek  * Finally, we pack parent vectors.  This is very much like packing
4857493Storek  * locators.  Unlike locators, however, parent vectors are always
4957493Storek  * terminated by -1 (rather like the way C strings always end with
5057493Storek  * a NUL).
5157493Storek  *
5257493Storek  * When packing locators, we would like to find sequences such as
5357493Storek  *	{1 2 3} {2 3 4} {3} {4 5}
5457493Storek  * and turn this into the flat sequence {1 2 3 4 5}, with each subsequence
5557493Storek  * given by the appropriate offset (here 0, 1, 2, and 3 respectively).
5657493Storek  * When we pack parent vectors, overlap of this sort is impossible.
5757493Storek  * Non-overlapping packing is much easier, and so we use that here
5857493Storek  * and miss out on the chance to squeeze the locator sequence optimally.
5957493Storek  * (So it goes.)
6057493Storek  */
6157493Storek 
6257493Storek typedef int (*vec_cmp_func) __P((const void *, int, int));
6357493Storek 
6457493Storek #define	TAILHSIZE	128
6557493Storek #define	PVHASH(i)	((i) & (TAILHSIZE - 1))
6657493Storek #define	LOCHASH(l)	(((int)(l) >> 2) & (TAILHSIZE - 1))
6757493Storek struct tails {
6857493Storek 	struct	tails *t_next;
6957493Storek 	int	t_ends_at;
7057493Storek };
7157493Storek 
7257493Storek static struct tails *tails[TAILHSIZE];
7357493Storek static int locspace;
7457493Storek static int pvecspace;
7557493Storek static int longest_pvec;
7657493Storek 
7757493Storek static void packdevi __P((void));
7857493Storek static void packlocs __P((void));
7957493Storek static void packpvec __P((void));
8057493Storek 
8157493Storek static void addparents __P((struct devi *src, struct devi *dst));
8257493Storek static int nparents __P((struct devi **, struct devbase *, int));
8357493Storek static int sameas __P((struct devi *, struct devi *));
8457493Storek static int findvec __P((const void *, int, int, vec_cmp_func, int));
8557493Storek static int samelocs __P((const void *, int, int));
8657493Storek static int addlocs __P((const char **, int));
8757493Storek static int loclencmp __P((const void *, const void *));
8857493Storek static int samepv __P((const void *, int, int));
8957493Storek static int addpv __P((short *, int));
9057493Storek static int pvlencmp __P((const void *, const void *));
9157493Storek static void resettails __P((void));
9257493Storek 
9357493Storek void
pack()9457493Storek pack()
9557493Storek {
9657493Storek 	register struct devi *i;
9757493Storek 	register int n;
9857493Storek 
9957493Storek 	/* Pack instances and make parent vectors. */
10057493Storek 	packdevi();
10157493Storek 
10257493Storek 	/*
10357493Storek 	 * Now that we know what we have, find upper limits on space
10457493Storek 	 * needed for the loc[] and pv[] tables, and find the longest
10557493Storek 	 * single pvec.  The loc and pv table sizes are bounded by
10657493Storek 	 * what we would get if no packing occurred.
10757493Storek 	 */
10857493Storek 	locspace = pvecspace = 0;
10957493Storek 	for (i = alldevi; i != NULL; i = i->i_next) {
11057493Storek 		if (i->i_collapsed)
11157493Storek 			continue;
11257493Storek 		locspace += i->i_atattr->a_loclen;
11357493Storek 		n = i->i_pvlen + 1;
11457493Storek 		if (n > longest_pvec)
11557493Storek 			longest_pvec = n;
11657493Storek 		pvecspace += n;
11757493Storek 	}
11857493Storek 
11957493Storek 	/* Allocate and pack loc[]. */
12057493Storek 	locators.vec = emalloc(locspace * sizeof(*locators.vec));
12157493Storek 	locators.used = 0;
12257493Storek 	packlocs();
12357493Storek 
12457493Storek 	/* Allocate and pack pv[]. */
12557493Storek 	parents.vec = emalloc(pvecspace * sizeof(*parents.vec));
12657493Storek 	parents.used = 0;
12757493Storek 	packpvec();
12857493Storek }
12957493Storek 
13057493Storek /*
13157493Storek  * Pack instances together wherever possible.  When everything is
13257493Storek  * packed, go back and set up the parents for each.  We must do this
13357493Storek  * on a second pass because during the first one, we do not know which,
13457493Storek  * if any, of the parents will collapse during packing.
13557493Storek  */
13657493Storek void
packdevi()13757493Storek packdevi()
13857493Storek {
13957493Storek 	register struct devi *i, *l, *p;
14057493Storek 	register struct devbase *d;
14157493Storek 	register int j, m, n;
14257493Storek 
14357493Storek 	packed = emalloc((ndevi + 1) * sizeof *packed);
14457493Storek 	n = 0;
14557493Storek 	for (d = allbases; d != NULL; d = d->d_next) {
14657493Storek 		/*
14757493Storek 		 * For each instance of each device, add or collapse
14857493Storek 		 * all its aliases.
14957493Storek 		 */
15057493Storek 		for (i = d->d_ihead; i != NULL; i = i->i_bsame) {
15157493Storek 			m = n;
15257493Storek 			for (l = i; l != NULL; l = l->i_alias) {
15357493Storek 				l->i_pvlen = 0;
15457493Storek 				l->i_pvoff = -1;
15557493Storek 				l->i_locoff = -1;
15657493Storek 				l->i_ivoff = -1;
15757493Storek 				/* try to find an equivalent for l */
15857493Storek 				for (j = m; j < n; j++) {
15957493Storek 					p = packed[j];
16057493Storek 					if (sameas(l, p)) {
16157493Storek 						l->i_collapsed = 1;
16257493Storek 						l->i_cfindex = p->i_cfindex;
16357493Storek 						goto nextalias;
16457493Storek 					}
16557493Storek 				}
16657493Storek 				/* could not find a suitable alias */
16757493Storek 				l->i_collapsed = 0;
16857493Storek 				l->i_cfindex = n;
16957493Storek 				l->i_parents = emalloc(sizeof(*l->i_parents));
17057493Storek 				l->i_parents[0] = NULL;
17157493Storek 				packed[n++] = l;
17257493Storek 			nextalias:;
17357493Storek 			}
17457493Storek 		}
17557493Storek 	}
17657493Storek 	npacked = n;
17757493Storek 	packed[n] = NULL;
17857493Storek 	for (i = alldevi; i != NULL; i = i->i_next)
17957493Storek 		addparents(i, packed[i->i_cfindex]);
18057493Storek }
18157493Storek 
18257493Storek /*
18357493Storek  * Return true if two aliases are "the same".  In this case, they need
18457493Storek  * to have the same config flags and the same locators.
18557493Storek  */
18657493Storek static int
sameas(i1,i2)18757493Storek sameas(i1, i2)
18857493Storek 	register struct devi *i1, *i2;
18957493Storek {
19057493Storek 	register const char **p1, **p2;
19157493Storek 
19257493Storek 	if (i1->i_cfflags != i2->i_cfflags)
19357493Storek 		return (0);
19457493Storek 	for (p1 = i1->i_locs, p2 = i2->i_locs; *p1 == *p2; p2++)
19557493Storek 		if (*p1++ == 0)
19657493Storek 			return (1);
19757493Storek 	return 0;
19857493Storek }
19957493Storek 
20057493Storek /*
20157493Storek  * Add the parents associated with "src" to the (presumably uncollapsed)
20257493Storek  * instance "dst".
20357493Storek  */
20457493Storek static void
addparents(src,dst)20557493Storek addparents(src, dst)
20657493Storek 	register struct devi *src, *dst;
20757493Storek {
20857493Storek 	register struct nvlist *nv;
20957493Storek 	register struct devi *i, **p, **q;
21057493Storek 	register int j, n, old, new, ndup;
21157493Storek 
21257493Storek 	if (dst->i_collapsed)
21357493Storek 		panic("addparents() i_collapsed");
21457493Storek 
21557493Storek 	/* Collect up list of parents to add. */
21657493Storek 	if (src->i_at == NULL)	/* none, 'cuz "at root" */
21757493Storek 		return;
21857493Storek 	if (src->i_atdev != NULL) {
21957493Storek 		n = nparents(NULL, src->i_atdev, src->i_atunit);
22057493Storek 		p = emalloc(n * sizeof *p);
22157493Storek 		if (n == 0)
22257493Storek 			return;
22357493Storek 		(void)nparents(p, src->i_atdev, src->i_atunit);
22457493Storek 	} else {
22557493Storek 		n = 0;
22657493Storek 		for (nv = src->i_atattr->a_refs; nv != NULL; nv = nv->nv_next)
22757493Storek 			n += nparents(NULL, nv->nv_ptr, src->i_atunit);
22857493Storek 		if (n == 0)
22957493Storek 			return;
23057493Storek 		p = emalloc(n * sizeof *p);
23157493Storek 		n = 0;
23257493Storek 		for (nv = src->i_atattr->a_refs; nv != NULL; nv = nv->nv_next)
23357493Storek 			n += nparents(p + n, nv->nv_ptr, src->i_atunit);
23457493Storek 	}
23557493Storek 	/* Now elide duplicates. */
23657493Storek 	ndup = 0;
23757493Storek 	for (j = 0; j < n; j++) {
23857493Storek 		i = p[j];
23957493Storek 		for (q = dst->i_parents; *q != NULL; q++) {
24057493Storek 			if (*q == i) {
24157493Storek 				ndup++;
24257493Storek 				p[j] = NULL;
24357493Storek 				break;
24457493Storek 			}
24557493Storek 		}
24657493Storek 	}
24757493Storek 	/* Finally, add all the non-duplicates. */
24857493Storek 	old = dst->i_pvlen;
24957493Storek 	new = old + (n - ndup);
25057493Storek 	if (old > new)
25157493Storek 		panic("addparents() old > new");
25257493Storek 	if (old == new) {
25357493Storek 		free(p);
25457493Storek 		return;
25557493Storek 	}
25657493Storek 	dst->i_parents = q = erealloc(dst->i_parents, (new + 1) * sizeof(*q));
25757493Storek 	dst->i_pvlen = new;
25857493Storek 	q[new] = NULL;
25957493Storek 	q += old;
26057493Storek 	for (j = 0; j < n; j++)
26157493Storek 		if (p[j] != NULL)
26257493Storek 			*q++ = p[j];
26357493Storek 	free(p);
26457493Storek }
26557493Storek 
26657493Storek /*
26757493Storek  * Count up parents, and optionally store pointers to each.
26857493Storek  */
26957493Storek static int
nparents(p,dev,unit)27057493Storek nparents(p, dev, unit)
27157493Storek 	register struct devi **p;
27257493Storek 	register struct devbase *dev;
27357493Storek 	register int unit;
27457493Storek {
27557493Storek 	register struct devi *i, *l;
27657493Storek 	register int n;
27757493Storek 
27857493Storek 	n = 0;
27957493Storek 	/* for each instance ... */
28057493Storek 	for (i = dev->d_ihead; i != NULL; i = i->i_bsame) {
28157493Storek 		/* ... take each un-collapsed alias */
28257493Storek 		for (l = i; l != NULL; l = l->i_alias) {
28357493Storek 			if (!l->i_collapsed &&
28457493Storek 			    (unit == WILD || unit == l->i_unit)) {
28557493Storek 				if (p != NULL)
28657493Storek 					*p++ = l;
28757493Storek 				n++;
28857493Storek 			}
28957493Storek 		}
29057493Storek 	}
29157493Storek 	return (n);
29257493Storek }
29357493Storek 
29457493Storek static void
packlocs()29557493Storek packlocs()
29657493Storek {
29757493Storek 	register struct devi **p, *i;
29857493Storek 	register int l, o;
29957493Storek 
30057493Storek 	qsort(packed, npacked, sizeof *packed, loclencmp);
30157493Storek 	for (p = packed; (i = *p) != NULL; p++) {
30257493Storek 		if ((l = i->i_atattr->a_loclen) > 0) {
30357493Storek 			o = findvec(i->i_locs, LOCHASH(i->i_locs[l - 1]), l,
30457493Storek 				    samelocs, locators.used);
30557493Storek 			i->i_locoff = o < 0 ? addlocs(i->i_locs, l) : o;
30657493Storek 		} else
30757493Storek 			i->i_locoff = -1;
30857493Storek 	}
30957493Storek 	resettails();
31057493Storek }
31157493Storek 
31257493Storek static void
packpvec()31357493Storek packpvec()
31457493Storek {
31557493Storek 	register struct devi **p, *i, **par;
31657493Storek 	register int l, v, o;
31757493Storek 	register short *vec;
31857493Storek 
31957493Storek 	vec = emalloc(longest_pvec * sizeof(*vec));
32057493Storek 	qsort(packed, npacked, sizeof *packed, pvlencmp);
32157493Storek 	for (p = packed; (i = *p) != NULL; p++) {
32257493Storek 		l = i->i_pvlen;
32357493Storek if (l > longest_pvec) panic("packpvec");
32457493Storek 		par = i->i_parents;
32557493Storek 		for (v = 0; v < l; v++)
32657493Storek 			vec[v] = par[v]->i_cfindex;
32757493Storek 		if (l == 0 ||
32857493Storek 		    (o = findvec(vec, PVHASH(vec[l - 1]), l,
32957493Storek 			    samepv, parents.used)) < 0)
33057493Storek 		    	o = addpv(vec, l);
33157493Storek 		i->i_pvoff = o;
33257493Storek 	}
33357493Storek 	free(vec);
33457493Storek 	resettails();
33557493Storek }
33657493Storek 
33757493Storek /*
33857493Storek  * Return the index at which the given vector already exists, or -1
33957493Storek  * if it is not anywhere in the current set.  If we return -1, we assume
34057493Storek  * our caller will add it at the end of the current set, and we make
34157493Storek  * sure that next time, we will find it there.
34257493Storek  */
34357493Storek static int
findvec(ptr,hash,len,cmp,nextplace)34457493Storek findvec(ptr, hash, len, cmp, nextplace)
34557493Storek 	const void *ptr;
34657493Storek 	int hash, len;
34757493Storek 	vec_cmp_func cmp;
34857493Storek 	int nextplace;
34957493Storek {
35057493Storek 	register struct tails *t, **hp;
35157493Storek 	register int off;
35257493Storek 
35357493Storek 	hp = &tails[hash];
35457493Storek 	for (t = *hp; t != NULL; t = t->t_next) {
35557493Storek 		off = t->t_ends_at - len;
35657493Storek 		if (off >= 0 && (*cmp)(ptr, off, len))
35757493Storek 			return (off);
35857493Storek 	}
35957493Storek 	t = emalloc(sizeof(*t));
36057493Storek 	t->t_next = *hp;
36157493Storek 	*hp = t;
36257493Storek 	t->t_ends_at = nextplace + len;
36357493Storek 	return (-1);
36457493Storek }
36557493Storek 
36657493Storek /*
36757493Storek  * Comparison function for locators.
36857493Storek  */
36957493Storek static int
samelocs(ptr,off,len)37057493Storek samelocs(ptr, off, len)
37157493Storek 	const void *ptr;
37257493Storek 	int off;
37357493Storek 	register int len;
37457493Storek {
37557493Storek 	register const char **p, **q;
37657493Storek 
37757493Storek 	for (p = &locators.vec[off], q = (const char **)ptr; --len >= 0;)
37857493Storek 		if (*p++ != *q++)
37957493Storek 			return (0);	/* different */
38057493Storek 	return (1);			/* same */
38157493Storek }
38257493Storek 
38357493Storek /*
38457493Storek  * Add the given locators at the end of the global loc[] table.
38557493Storek  */
38657493Storek static int
addlocs(locs,len)38757493Storek addlocs(locs, len)
38857493Storek 	register const char **locs;
38957493Storek 	register int len;
39057493Storek {
39157493Storek 	register const char **p;
39257493Storek 	register int ret;
39357493Storek 
39457493Storek 	ret = locators.used;
39557493Storek 	if ((locators.used = ret + len) > locspace)
39657493Storek 		panic("addlocs: overrun");
39757493Storek 	for (p = &locators.vec[ret]; --len >= 0;)
39857493Storek 		*p++ = *locs++;
39957493Storek 	return (ret);
40057493Storek }
40157493Storek 
40257493Storek /*
40357493Storek  * Comparison function for qsort-by-locator-length, longest first.
40457493Storek  * We rashly assume that subtraction of these lengths does not overflow.
40557493Storek  */
40657493Storek static int
loclencmp(a,b)40757493Storek loclencmp(a, b)
40857493Storek 	const void *a, *b;
40957493Storek {
41057493Storek 	register int l1, l2;
41157493Storek 
41257493Storek 	l1 = (*(struct devi **)a)->i_atattr->a_loclen;
41357493Storek 	l2 = (*(struct devi **)b)->i_atattr->a_loclen;
41457493Storek 	return (l2 - l1);
41557493Storek }
41657493Storek 
41757493Storek /*
41857493Storek  * Comparison function for parent vectors.
41957493Storek  */
42057493Storek static int
samepv(ptr,off,len)42157493Storek samepv(ptr, off, len)
42257493Storek 	const void *ptr;
42357493Storek 	int off;
42457493Storek 	register int len;
42557493Storek {
42657493Storek 	register short *p, *q;
42757493Storek 
42857493Storek 	for (p = &parents.vec[off], q = (short *)ptr; --len >= 0;)
42957493Storek 		if (*p++ != *q++)
43057493Storek 			return (0);	/* different */
43157493Storek 	return (1);			/* same */
43257493Storek }
43357493Storek 
43457493Storek /*
43557493Storek  * Add the given parent vectors at the end of the global pv[] table.
43657493Storek  */
43757493Storek static int
addpv(pv,len)43857493Storek addpv(pv, len)
43957493Storek 	register short *pv;
44057493Storek 	register int len;
44157493Storek {
44257493Storek 	register short *p;
44357493Storek 	register int ret;
44457493Storek 	static int firstend = -1;
44557493Storek 
44657493Storek 	/*
44757493Storek 	 * If the vector is empty, reuse the first -1.  It will be
44857493Storek 	 * there if there are any nonempty vectors at all, since we
44957493Storek 	 * do the longest first.  If there are no nonempty vectors,
45057493Storek 	 * something is probably wrong, but we will ignore that here.
45157493Storek 	 */
45257493Storek 	if (len == 0 && firstend >= 0)
45357493Storek 		return (firstend);
45457493Storek 	len++;			/* account for trailing -1 */
45557493Storek 	ret = parents.used;
45657493Storek 	if ((parents.used = ret + len) > pvecspace)
45757493Storek 		panic("addpv: overrun");
45857493Storek 	for (p = &parents.vec[ret]; --len > 0;)
45957493Storek 		*p++ = *pv++;
46057493Storek 	*p = -1;
46157493Storek 	if (firstend < 0)
46257493Storek 		firstend = parents.used - 1;
46357493Storek 	return (ret);
46457493Storek }
46557493Storek 
46657493Storek /*
46757493Storek  * Comparison function for qsort-by-parent-vector-length, longest first.
46857493Storek  * We rashly assume that subtraction of these lengths does not overflow.
46957493Storek  */
47057493Storek static int
pvlencmp(a,b)47157493Storek pvlencmp(a, b)
47257493Storek 	const void *a, *b;
47357493Storek {
47457493Storek 	register int l1, l2;
47557493Storek 
47657493Storek 	l1 = (*(struct devi **)a)->i_pvlen;
47757493Storek 	l2 = (*(struct devi **)b)->i_pvlen;
47857493Storek 	return (l2 - l1);
47957493Storek }
48057493Storek 
48157493Storek static void
resettails()48257493Storek resettails()
48357493Storek {
48457493Storek 	register struct tails **p, *t, *next;
48557493Storek 	register int i;
48657493Storek 
48757493Storek 	for (p = tails, i = TAILHSIZE; --i >= 0; p++) {
48857493Storek 		for (t = *p; t != NULL; t = next) {
48957493Storek 			next = t->t_next;
49057493Storek 			free(t);
49157493Storek 		}
49257493Storek 		*p = NULL;
49357493Storek 	}
49457493Storek }
495