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