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