1 /* $OpenBSD: pack.c,v 1.9 1999/01/19 01:11:25 niklas Exp $ */
2 /* $NetBSD: pack.c,v 1.5 1996/08/31 21:15:11 mycroft Exp $ */
5 * Copyright (c) 1992, 1993
6 * The Regents of the University of California. All rights reserved.
8 * This software was developed by the Computer Systems Engineering group
9 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
10 * contributed to Berkeley.
12 * All advertising materials mentioning features or use of this software
13 * must display the following acknowledgement:
14 * This product includes software developed by the University of
15 * California, Lawrence Berkeley Laboratories.
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
20 * 1. Redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution.
25 * 3. All advertising materials mentioning features or use of this software
26 * must display the following acknowledgement:
27 * This product includes software developed by the University of
28 * California, Berkeley and its contributors.
29 * 4. Neither the name of the University nor the names of its contributors
30 * may be used to endorse or promote products derived from this software
31 * without specific prior written permission.
33 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
34 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
37 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45 * from: @(#)pack.c 8.1 (Berkeley) 6/6/93
48 #include <sys/param.h>
54 * Packing. We have three separate kinds of packing here.
56 * First, we pack device instances, to collapse things like
58 * uba0 at sbi0 nexus ?
61 * into a single instance that is "at sbi0 or bi0".
63 * Second, we pack locators. Given something like
72 * (where the default drive and slave numbers are -1), we have three
73 * locators whose value is 0 and three whose value is -1. Rather than
74 * emitting six integers, we emit just two.
76 * Finally, we pack parent vectors. This is very much like packing
77 * locators. Unlike locators, however, parent vectors are always
78 * terminated by -1 (rather like the way C strings always end with
81 * When packing locators, we would like to find sequences such as
82 * {1 2 3} {2 3 4} {3} {4 5}
83 * and turn this into the flat sequence {1 2 3 4 5}, with each subsequence
84 * given by the appropriate offset (here 0, 1, 2, and 3 respectively).
85 * When we pack parent vectors, overlap of this sort is impossible.
86 * Non-overlapping packing is much easier, and so we use that here
87 * and miss out on the chance to squeeze the locator sequence optimally.
91 typedef int (*vec_cmp_func
) (const void *, int, int);
94 #define PVHASH(i) ((i) & (TAILHSIZE - 1))
95 #define LOCHASH(l) (((long)(l) >> 2) & (TAILHSIZE - 1))
101 static struct tails
*tails
[TAILHSIZE
];
103 static int pvecspace
;
104 static int longest_pvec
;
106 static void packdevi(void);
107 static void packlocs(void);
108 static void packpvec(void);
110 static void addparents(struct devi
*src
, struct devi
*dst
);
111 static int nparents(struct devi
**, struct devbase
*, int);
112 static int sameas(struct devi
*, struct devi
*);
113 static int findvec(const void *, int, int, vec_cmp_func
, int);
114 static int samelocs(const void *, int, int);
115 static int addlocs(const char **, int);
116 static int loclencmp(const void *, const void *);
117 static int samepv(const void *, int, int);
118 static int addpv(short *, int);
119 static int pvlencmp(const void *, const void *);
120 static void resettails(void);
125 register struct devi
*i
;
128 /* Pack instances and make parent vectors. */
132 * Now that we know what we have, find upper limits on space
133 * needed for the loc[] and pv[] tables, and find the longest
134 * single pvec. The loc and pv table sizes are bounded by
135 * what we would get if no packing occurred.
137 locspace
= pvecspace
= 0;
138 for (i
= alldevi
; i
!= NULL
; i
= i
->i_next
) {
141 locspace
+= i
->i_atattr
->a_loclen
;
143 if (n
> longest_pvec
)
148 /* Allocate and pack loc[]. */
149 locators
.vec
= emalloc(locspace
* sizeof(*locators
.vec
));
153 /* Allocate and pack pv[]. */
154 parents
.vec
= emalloc(pvecspace
* sizeof(*parents
.vec
));
160 * Pack instances together wherever possible. When everything is
161 * packed, go back and set up the parents for each. We must do this
162 * on a second pass because during the first one, we do not know which,
163 * if any, of the parents will collapse during packing.
168 register struct devi
*i
, *l
, *p
;
169 register struct deva
*d
;
170 register int j
, m
, n
;
172 packed
= emalloc((ndevi
+ 1) * sizeof *packed
);
174 for (d
= alldevas
; d
!= NULL
; d
= d
->d_next
) {
176 * For each instance of each attachment, add or collapse
179 for (i
= d
->d_ihead
; i
!= NULL
; i
= i
->i_asame
) {
181 for (l
= i
; l
!= NULL
; l
= l
->i_alias
) {
182 /* Skip if we already handled this one. */
183 if (l
->i_cfindex
>= 0)
188 /* try to find an equivalent for l */
189 for (j
= m
; j
< n
; j
++) {
193 l
->i_cfindex
= p
->i_cfindex
;
197 /* could not find a suitable alias */
200 l
->i_parents
= emalloc(sizeof(*l
->i_parents
));
201 l
->i_parents
[0] = NULL
;
209 for (i
= alldevi
; i
!= NULL
; i
= i
->i_next
)
210 addparents(i
, packed
[i
->i_cfindex
]);
214 * Return true if two aliases are "the same". In this case, they need
215 * to attach via the same attribute, have the same config flags, and
216 * have the same locators.
220 register struct devi
*i1
, *i2
;
222 register const char **p1
, **p2
;
224 if (i1
->i_atattr
!= i2
->i_atattr
)
226 if (i1
->i_cfflags
!= i2
->i_cfflags
)
228 for (p1
= i1
->i_locs
, p2
= i2
->i_locs
; *p1
== *p2
; p2
++)
235 * Add the parents associated with "src" to the (presumably uncollapsed)
240 register struct devi
*src
, *dst
;
242 register struct nvlist
*nv
;
243 register struct devi
*i
, **p
, **q
;
244 register int j
, n
, old
, new, ndup
;
246 if (dst
->i_collapsed
)
247 panic("addparents() i_collapsed");
249 /* Collect up list of parents to add. */
250 if (src
->i_at
== NULL
) /* none, 'cuz "at root" */
252 if (src
->i_atdev
!= NULL
) {
253 n
= nparents(NULL
, src
->i_atdev
, src
->i_atunit
);
254 p
= emalloc(n
* sizeof *p
);
257 (void)nparents(p
, src
->i_atdev
, src
->i_atunit
);
260 for (nv
= src
->i_atattr
->a_refs
; nv
!= NULL
; nv
= nv
->nv_next
)
261 n
+= nparents(NULL
, nv
->nv_ptr
, src
->i_atunit
);
264 p
= emalloc(n
* sizeof *p
);
266 for (nv
= src
->i_atattr
->a_refs
; nv
!= NULL
; nv
= nv
->nv_next
)
267 n
+= nparents(p
+ n
, nv
->nv_ptr
, src
->i_atunit
);
269 /* Now elide duplicates. */
271 for (j
= 0; j
< n
; j
++) {
273 for (q
= dst
->i_parents
; *q
!= NULL
; q
++) {
281 /* Finally, add all the non-duplicates. */
283 new = old
+ (n
- ndup
);
285 panic("addparents() old > new");
290 dst
->i_parents
= q
= erealloc(dst
->i_parents
, (new + 1) * sizeof(*q
));
294 for (j
= 0; j
< n
; j
++)
301 * Count up parents, and optionally store pointers to each.
304 nparents(p
, dev
, unit
)
305 register struct devi
**p
;
306 register struct devbase
*dev
;
309 register struct devi
*i
, *l
;
313 /* for each instance ... */
314 for (i
= dev
->d_ihead
; i
!= NULL
; i
= i
->i_bsame
) {
315 /* ... take each un-collapsed alias */
316 for (l
= i
; l
!= NULL
; l
= l
->i_alias
) {
317 if (!l
->i_collapsed
&&
318 (unit
== WILD
|| unit
== l
->i_unit
)) {
331 register struct devi
**p
, *i
;
334 qsort(packed
, npacked
, sizeof *packed
, loclencmp
);
335 for (p
= packed
; (i
= *p
) != NULL
; p
++) {
336 if ((l
= i
->i_atattr
->a_loclen
) > 0) {
337 o
= findvec(i
->i_locs
, LOCHASH(i
->i_locs
[l
- 1]), l
,
338 samelocs
, locators
.used
);
339 i
->i_locoff
= o
< 0 ? addlocs(i
->i_locs
, l
) : o
;
349 register struct devi
**p
, *i
, **par
;
350 register int l
, v
, o
;
353 vec
= emalloc(longest_pvec
* sizeof(*vec
));
354 qsort(packed
, npacked
, sizeof *packed
, pvlencmp
);
355 for (p
= packed
; (i
= *p
) != NULL
; p
++) {
357 if (l
> longest_pvec
) panic("packpvec");
359 for (v
= 0; v
< l
; v
++)
360 vec
[v
] = par
[v
]->i_cfindex
;
362 (o
= findvec(vec
, PVHASH(vec
[l
- 1]), l
,
363 samepv
, parents
.used
)) < 0)
372 * Return the index at which the given vector already exists, or -1
373 * if it is not anywhere in the current set. If we return -1, we assume
374 * our caller will add it at the end of the current set, and we make
375 * sure that next time, we will find it there.
378 findvec(ptr
, hash
, len
, cmp
, nextplace
)
384 register struct tails
*t
, **hp
;
388 for (t
= *hp
; t
!= NULL
; t
= t
->t_next
) {
389 off
= t
->t_ends_at
- len
;
390 if (off
>= 0 && (*cmp
)(ptr
, off
, len
))
393 t
= emalloc(sizeof(*t
));
396 t
->t_ends_at
= nextplace
+ len
;
401 * Comparison function for locators.
404 samelocs(ptr
, off
, len
)
409 register const char **p
, **q
;
411 for (p
= &locators
.vec
[off
], q
= (const char **)ptr
; --len
>= 0;)
413 return (0); /* different */
414 return (1); /* same */
418 * Add the given locators at the end of the global loc[] table.
422 register const char **locs
;
425 register const char **p
;
429 if ((locators
.used
= ret
+ len
) > locspace
)
430 panic("addlocs: overrun");
431 for (p
= &locators
.vec
[ret
]; --len
>= 0;)
437 * Comparison function for qsort-by-locator-length, longest first.
438 * We rashly assume that subtraction of these lengths does not overflow.
446 l1
= (*(struct devi
**)a
)->i_atattr
->a_loclen
;
447 l2
= (*(struct devi
**)b
)->i_atattr
->a_loclen
;
452 * Comparison function for parent vectors.
455 samepv(ptr
, off
, len
)
460 register short *p
, *q
;
462 for (p
= &parents
.vec
[off
], q
= (short *)ptr
; --len
>= 0;)
464 return (0); /* different */
465 return (1); /* same */
469 * Add the given parent vectors at the end of the global pv[] table.
478 static int firstend
= -1;
481 * If the vector is empty, reuse the first -1. It will be
482 * there if there are any nonempty vectors at all, since we
483 * do the longest first. If there are no nonempty vectors,
484 * something is probably wrong, but we will ignore that here.
486 if (len
== 0 && firstend
>= 0)
488 len
++; /* account for trailing -1 */
490 if ((parents
.used
= ret
+ len
) > pvecspace
)
491 panic("addpv: overrun");
492 for (p
= &parents
.vec
[ret
]; --len
> 0;)
496 firstend
= parents
.used
- 1;
501 * Comparison function for qsort-by-parent-vector-length, longest first.
502 * We rashly assume that subtraction of these lengths does not overflow.
510 l1
= (*(struct devi
**)a
)->i_pvlen
;
511 l2
= (*(struct devi
**)b
)->i_pvlen
;
518 register struct tails
**p
, *t
, *next
;
521 for (p
= tails
, i
= TAILHSIZE
; --i
>= 0; p
++) {
522 for (t
= *p
; t
!= NULL
; t
= next
) {