1*b9fc9a72Sderaadt /* $OpenBSD: pack.c,v 1.18 2015/01/16 06:40:16 deraadt Exp $ */
26fd5fbd6Sniklas /* $NetBSD: pack.c,v 1.5 1996/08/31 21:15:11 mycroft Exp $ */
3608f9123Sniklas
4df930be7Sderaadt /*
5df930be7Sderaadt * Copyright (c) 1992, 1993
6df930be7Sderaadt * The Regents of the University of California. All rights reserved.
7df930be7Sderaadt *
8df930be7Sderaadt * This software was developed by the Computer Systems Engineering group
9df930be7Sderaadt * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
10df930be7Sderaadt * contributed to Berkeley.
11df930be7Sderaadt *
12df930be7Sderaadt * All advertising materials mentioning features or use of this software
13df930be7Sderaadt * must display the following acknowledgement:
14df930be7Sderaadt * This product includes software developed by the University of
15df930be7Sderaadt * California, Lawrence Berkeley Laboratories.
16df930be7Sderaadt *
17df930be7Sderaadt * Redistribution and use in source and binary forms, with or without
18df930be7Sderaadt * modification, are permitted provided that the following conditions
19df930be7Sderaadt * are met:
20df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright
21df930be7Sderaadt * notice, this list of conditions and the following disclaimer.
22df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright
23df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the
24df930be7Sderaadt * documentation and/or other materials provided with the distribution.
2529295d1cSmillert * 3. Neither the name of the University nor the names of its contributors
26df930be7Sderaadt * may be used to endorse or promote products derived from this software
27df930be7Sderaadt * without specific prior written permission.
28df930be7Sderaadt *
29df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39df930be7Sderaadt * SUCH DAMAGE.
40df930be7Sderaadt *
41df930be7Sderaadt * from: @(#)pack.c 8.1 (Berkeley) 6/6/93
42df930be7Sderaadt */
43df930be7Sderaadt
44df930be7Sderaadt #include <stdlib.h>
45df930be7Sderaadt #include <string.h>
46c6b62359Sedd
47df930be7Sderaadt #include "config.h"
48df930be7Sderaadt
49df930be7Sderaadt /*
50df930be7Sderaadt * Packing. We have three separate kinds of packing here.
51df930be7Sderaadt *
52df930be7Sderaadt * First, we pack device instances, to collapse things like
53df930be7Sderaadt *
54df930be7Sderaadt * uba0 at sbi0 nexus ?
55df930be7Sderaadt * uba0 at bi0 nexus ?
56df930be7Sderaadt *
57df930be7Sderaadt * into a single instance that is "at sbi0 or bi0".
58df930be7Sderaadt *
59df930be7Sderaadt * Second, we pack locators. Given something like
60df930be7Sderaadt *
61df930be7Sderaadt * hp0 at mba0 drive 0
62df930be7Sderaadt * hp* at mba* drive ?
63df930be7Sderaadt * ht0 at mba0 drive 0
64df930be7Sderaadt * tu0 at ht0 slave 0
65df930be7Sderaadt * ht* at mba* drive ?
66df930be7Sderaadt * tu* at ht* slave ?
67df930be7Sderaadt *
68df930be7Sderaadt * (where the default drive and slave numbers are -1), we have three
69df930be7Sderaadt * locators whose value is 0 and three whose value is -1. Rather than
70df930be7Sderaadt * emitting six integers, we emit just two.
71df930be7Sderaadt *
72df930be7Sderaadt * Finally, we pack parent vectors. This is very much like packing
73df930be7Sderaadt * locators. Unlike locators, however, parent vectors are always
74df930be7Sderaadt * terminated by -1 (rather like the way C strings always end with
75df930be7Sderaadt * a NUL).
76df930be7Sderaadt *
77df930be7Sderaadt * When packing locators, we would like to find sequences such as
78df930be7Sderaadt * {1 2 3} {2 3 4} {3} {4 5}
79df930be7Sderaadt * and turn this into the flat sequence {1 2 3 4 5}, with each subsequence
80df930be7Sderaadt * given by the appropriate offset (here 0, 1, 2, and 3 respectively).
81df930be7Sderaadt * When we pack parent vectors, overlap of this sort is impossible.
82df930be7Sderaadt * Non-overlapping packing is much easier, and so we use that here
83df930be7Sderaadt * and miss out on the chance to squeeze the locator sequence optimally.
84df930be7Sderaadt * (So it goes.)
85df930be7Sderaadt */
86df930be7Sderaadt
87c72b5b24Smillert typedef int (*vec_cmp_func)(const void *, int, int);
88df930be7Sderaadt
89df930be7Sderaadt #define TAILHSIZE 128
90df930be7Sderaadt #define PVHASH(i) ((i) & (TAILHSIZE - 1))
91df930be7Sderaadt #define LOCHASH(l) (((long)(l) >> 2) & (TAILHSIZE - 1))
92df930be7Sderaadt struct tails {
93df930be7Sderaadt struct tails *t_next;
94df930be7Sderaadt int t_ends_at;
95df930be7Sderaadt };
96df930be7Sderaadt
97df930be7Sderaadt static struct tails *tails[TAILHSIZE];
98df930be7Sderaadt static int locspace;
99df930be7Sderaadt static int pvecspace;
100df930be7Sderaadt static int longest_pvec;
101df930be7Sderaadt
102c72b5b24Smillert static void packdevi(void);
103c72b5b24Smillert static void packlocs(void);
104c72b5b24Smillert static void packpvec(void);
105df930be7Sderaadt
106c72b5b24Smillert static void addparents(struct devi *src, struct devi *dst);
107c72b5b24Smillert static int nparents(struct devi **, struct devbase *, int);
108c72b5b24Smillert static int sameas(struct devi *, struct devi *);
109c72b5b24Smillert static int findvec(const void *, int, int, vec_cmp_func, int);
110c72b5b24Smillert static int samelocs(const void *, int, int);
111c72b5b24Smillert static int addlocs(const char **, int);
112c72b5b24Smillert static int loclencmp(const void *, const void *);
113c72b5b24Smillert static int samepv(const void *, int, int);
114c72b5b24Smillert static int addpv(short *, int);
115c72b5b24Smillert static int pvlencmp(const void *, const void *);
116c72b5b24Smillert static void resettails(void);
117df930be7Sderaadt
118df930be7Sderaadt void
pack(void)119815b5809Sderaadt pack(void)
120df930be7Sderaadt {
1210ac0d02eSmpech struct devi *i;
1220ac0d02eSmpech int n;
123df930be7Sderaadt
124df930be7Sderaadt /* Pack instances and make parent vectors. */
125df930be7Sderaadt packdevi();
126df930be7Sderaadt
127df930be7Sderaadt /*
128df930be7Sderaadt * Now that we know what we have, find upper limits on space
129df930be7Sderaadt * needed for the loc[] and pv[] tables, and find the longest
130df930be7Sderaadt * single pvec. The loc and pv table sizes are bounded by
131df930be7Sderaadt * what we would get if no packing occurred.
132df930be7Sderaadt */
133df930be7Sderaadt locspace = pvecspace = 0;
134df930be7Sderaadt for (i = alldevi; i != NULL; i = i->i_next) {
135df930be7Sderaadt if (i->i_collapsed)
136df930be7Sderaadt continue;
137df930be7Sderaadt locspace += i->i_atattr->a_loclen;
138df930be7Sderaadt n = i->i_pvlen + 1;
139df930be7Sderaadt if (n > longest_pvec)
140df930be7Sderaadt longest_pvec = n;
141df930be7Sderaadt pvecspace += n;
142df930be7Sderaadt }
143df930be7Sderaadt
144df930be7Sderaadt /* Allocate and pack loc[]. */
145c811dcf3Sespie locators.vec = ereallocarray(NULL, locspace, sizeof(*locators.vec));
146df930be7Sderaadt locators.used = 0;
147df930be7Sderaadt packlocs();
148df930be7Sderaadt
149df930be7Sderaadt /* Allocate and pack pv[]. */
150c811dcf3Sespie parents.vec = ereallocarray(NULL, pvecspace, sizeof(*parents.vec));
151df930be7Sderaadt parents.used = 0;
152df930be7Sderaadt packpvec();
153df930be7Sderaadt }
154df930be7Sderaadt
155df930be7Sderaadt /*
156df930be7Sderaadt * Pack instances together wherever possible. When everything is
157df930be7Sderaadt * packed, go back and set up the parents for each. We must do this
158df930be7Sderaadt * on a second pass because during the first one, we do not know which,
159df930be7Sderaadt * if any, of the parents will collapse during packing.
160df930be7Sderaadt */
161df930be7Sderaadt void
packdevi(void)162815b5809Sderaadt packdevi(void)
163df930be7Sderaadt {
1640ac0d02eSmpech struct devi *i, *l, *p;
1650ac0d02eSmpech struct deva *d;
1660ac0d02eSmpech int j, m, n;
167df930be7Sderaadt
168c811dcf3Sespie packed = ereallocarray(NULL, ndevi + 1, sizeof *packed);
169df930be7Sderaadt n = 0;
170ddf1f9cbSniklas for (d = alldevas; d != NULL; d = d->d_next) {
171df930be7Sderaadt /*
172ddf1f9cbSniklas * For each instance of each attachment, add or collapse
173df930be7Sderaadt * all its aliases.
174df930be7Sderaadt */
175ddf1f9cbSniklas for (i = d->d_ihead; i != NULL; i = i->i_asame) {
176df930be7Sderaadt m = n;
177df930be7Sderaadt for (l = i; l != NULL; l = l->i_alias) {
178ddf1f9cbSniklas /* Skip if we already handled this one. */
179ddf1f9cbSniklas if (l->i_cfindex >= 0)
180ddf1f9cbSniklas continue;
181df930be7Sderaadt l->i_pvlen = 0;
182df930be7Sderaadt l->i_pvoff = -1;
183df930be7Sderaadt l->i_locoff = -1;
184df930be7Sderaadt /* try to find an equivalent for l */
185df930be7Sderaadt for (j = m; j < n; j++) {
186df930be7Sderaadt p = packed[j];
187df930be7Sderaadt if (sameas(l, p)) {
188df930be7Sderaadt l->i_collapsed = 1;
189df930be7Sderaadt l->i_cfindex = p->i_cfindex;
190df930be7Sderaadt goto nextalias;
191df930be7Sderaadt }
192df930be7Sderaadt }
193df930be7Sderaadt /* could not find a suitable alias */
194df930be7Sderaadt l->i_collapsed = 0;
195df930be7Sderaadt l->i_cfindex = n;
196df930be7Sderaadt l->i_parents = emalloc(sizeof(*l->i_parents));
197df930be7Sderaadt l->i_parents[0] = NULL;
198df930be7Sderaadt packed[n++] = l;
199df930be7Sderaadt nextalias:;
200df930be7Sderaadt }
201df930be7Sderaadt }
202df930be7Sderaadt }
203df930be7Sderaadt npacked = n;
204df930be7Sderaadt packed[n] = NULL;
205df930be7Sderaadt for (i = alldevi; i != NULL; i = i->i_next)
206df930be7Sderaadt addparents(i, packed[i->i_cfindex]);
207df930be7Sderaadt }
208df930be7Sderaadt
209df930be7Sderaadt /*
210df930be7Sderaadt * Return true if two aliases are "the same". In this case, they need
21162b6b48eSderaadt * to attach via the same attribute, have the same config flags, and
21262b6b48eSderaadt * have the same locators.
213df930be7Sderaadt */
214df930be7Sderaadt static int
sameas(struct devi * i1,struct devi * i2)215815b5809Sderaadt sameas(struct devi *i1, struct devi *i2)
216df930be7Sderaadt {
2170ac0d02eSmpech const char **p1, **p2;
218df930be7Sderaadt
21962b6b48eSderaadt if (i1->i_atattr != i2->i_atattr)
22062b6b48eSderaadt return (0);
221df930be7Sderaadt if (i1->i_cfflags != i2->i_cfflags)
222df930be7Sderaadt return (0);
223df930be7Sderaadt for (p1 = i1->i_locs, p2 = i2->i_locs; *p1 == *p2; p2++)
224df930be7Sderaadt if (*p1++ == 0)
225df930be7Sderaadt return (1);
226df930be7Sderaadt return 0;
227df930be7Sderaadt }
228df930be7Sderaadt
229df930be7Sderaadt /*
230df930be7Sderaadt * Add the parents associated with "src" to the (presumably uncollapsed)
231df930be7Sderaadt * instance "dst".
232df930be7Sderaadt */
233df930be7Sderaadt static void
addparents(struct devi * src,struct devi * dst)234815b5809Sderaadt addparents(struct devi *src, struct devi *dst)
235df930be7Sderaadt {
2360ac0d02eSmpech struct nvlist *nv;
2370ac0d02eSmpech struct devi *i, **p, **q;
2380ac0d02eSmpech int j, n, old, new, ndup;
239df930be7Sderaadt
240df930be7Sderaadt if (dst->i_collapsed)
241df930be7Sderaadt panic("addparents() i_collapsed");
242df930be7Sderaadt
243df930be7Sderaadt /* Collect up list of parents to add. */
244973a9374Sjsyn if (src->i_at == NULL) /* none, because we are "at root" */
245df930be7Sderaadt return;
246df930be7Sderaadt if (src->i_atdev != NULL) {
247df930be7Sderaadt n = nparents(NULL, src->i_atdev, src->i_atunit);
248c811dcf3Sespie p = ereallocarray(NULL, n, sizeof *p);
249df930be7Sderaadt if (n == 0)
250df930be7Sderaadt return;
251df930be7Sderaadt (void)nparents(p, src->i_atdev, src->i_atunit);
252df930be7Sderaadt } else {
253df930be7Sderaadt n = 0;
254df930be7Sderaadt for (nv = src->i_atattr->a_refs; nv != NULL; nv = nv->nv_next)
255df930be7Sderaadt n += nparents(NULL, nv->nv_ptr, src->i_atunit);
256df930be7Sderaadt if (n == 0)
257df930be7Sderaadt return;
258c811dcf3Sespie p = ereallocarray(NULL, n, sizeof *p);
259df930be7Sderaadt n = 0;
260df930be7Sderaadt for (nv = src->i_atattr->a_refs; nv != NULL; nv = nv->nv_next)
261df930be7Sderaadt n += nparents(p + n, nv->nv_ptr, src->i_atunit);
262df930be7Sderaadt }
263df930be7Sderaadt /* Now elide duplicates. */
264df930be7Sderaadt ndup = 0;
265df930be7Sderaadt for (j = 0; j < n; j++) {
266df930be7Sderaadt i = p[j];
267df930be7Sderaadt for (q = dst->i_parents; *q != NULL; q++) {
268df930be7Sderaadt if (*q == i) {
269df930be7Sderaadt ndup++;
270df930be7Sderaadt p[j] = NULL;
271df930be7Sderaadt break;
272df930be7Sderaadt }
273df930be7Sderaadt }
274df930be7Sderaadt }
275df930be7Sderaadt /* Finally, add all the non-duplicates. */
276df930be7Sderaadt old = dst->i_pvlen;
277df930be7Sderaadt new = old + (n - ndup);
278df930be7Sderaadt if (old > new)
279df930be7Sderaadt panic("addparents() old > new");
280df930be7Sderaadt if (old == new) {
281df930be7Sderaadt free(p);
282df930be7Sderaadt return;
283df930be7Sderaadt }
284c811dcf3Sespie dst->i_parents = q = ereallocarray(dst->i_parents, new + 1, sizeof(*q));
285df930be7Sderaadt dst->i_pvlen = new;
286df930be7Sderaadt q[new] = NULL;
287df930be7Sderaadt q += old;
288df930be7Sderaadt for (j = 0; j < n; j++)
289df930be7Sderaadt if (p[j] != NULL)
290df930be7Sderaadt *q++ = p[j];
291df930be7Sderaadt free(p);
292df930be7Sderaadt }
293df930be7Sderaadt
294df930be7Sderaadt /*
295df930be7Sderaadt * Count up parents, and optionally store pointers to each.
296df930be7Sderaadt */
297df930be7Sderaadt static int
nparents(struct devi ** p,struct devbase * dev,int unit)298815b5809Sderaadt nparents(struct devi **p, struct devbase *dev, int unit)
299df930be7Sderaadt {
3000ac0d02eSmpech struct devi *i, *l;
3010ac0d02eSmpech int n;
302df930be7Sderaadt
303df930be7Sderaadt n = 0;
304df930be7Sderaadt /* for each instance ... */
305df930be7Sderaadt for (i = dev->d_ihead; i != NULL; i = i->i_bsame) {
306df930be7Sderaadt /* ... take each un-collapsed alias */
307df930be7Sderaadt for (l = i; l != NULL; l = l->i_alias) {
308df930be7Sderaadt if (!l->i_collapsed &&
309df930be7Sderaadt (unit == WILD || unit == l->i_unit)) {
310df930be7Sderaadt if (p != NULL)
311df930be7Sderaadt *p++ = l;
312df930be7Sderaadt n++;
313df930be7Sderaadt }
314df930be7Sderaadt }
315df930be7Sderaadt }
316df930be7Sderaadt return (n);
317df930be7Sderaadt }
318df930be7Sderaadt
319df930be7Sderaadt static void
packlocs(void)320815b5809Sderaadt packlocs(void)
321df930be7Sderaadt {
3220ac0d02eSmpech struct devi **p, *i;
3230ac0d02eSmpech int l, o;
324df930be7Sderaadt
325df930be7Sderaadt qsort(packed, npacked, sizeof *packed, loclencmp);
326df930be7Sderaadt for (p = packed; (i = *p) != NULL; p++) {
327df930be7Sderaadt if ((l = i->i_atattr->a_loclen) > 0) {
328df930be7Sderaadt o = findvec(i->i_locs, LOCHASH(i->i_locs[l - 1]), l,
329df930be7Sderaadt samelocs, locators.used);
330df930be7Sderaadt i->i_locoff = o < 0 ? addlocs(i->i_locs, l) : o;
331df930be7Sderaadt } else
332df930be7Sderaadt i->i_locoff = -1;
333df930be7Sderaadt }
334df930be7Sderaadt resettails();
335df930be7Sderaadt }
336df930be7Sderaadt
337df930be7Sderaadt static void
packpvec(void)338815b5809Sderaadt packpvec(void)
339df930be7Sderaadt {
3400ac0d02eSmpech struct devi **p, *i, **par;
3410ac0d02eSmpech int l, v, o;
3420ac0d02eSmpech short *vec;
343df930be7Sderaadt
344c811dcf3Sespie vec = ereallocarray(NULL, longest_pvec, sizeof(*vec));
345df930be7Sderaadt qsort(packed, npacked, sizeof *packed, pvlencmp);
346df930be7Sderaadt for (p = packed; (i = *p) != NULL; p++) {
347df930be7Sderaadt l = i->i_pvlen;
348c1a0c9d6Sderaadt if (l > longest_pvec)
349c1a0c9d6Sderaadt panic("packpvec");
350df930be7Sderaadt par = i->i_parents;
351df930be7Sderaadt for (v = 0; v < l; v++)
352df930be7Sderaadt vec[v] = par[v]->i_cfindex;
353c1a0c9d6Sderaadt if (l == 0 || (o = findvec(vec, PVHASH(vec[l - 1]), l,
354df930be7Sderaadt samepv, parents.used)) < 0)
355df930be7Sderaadt o = addpv(vec, l);
356df930be7Sderaadt i->i_pvoff = o;
357df930be7Sderaadt }
358df930be7Sderaadt free(vec);
359df930be7Sderaadt resettails();
360df930be7Sderaadt }
361df930be7Sderaadt
362df930be7Sderaadt /*
363df930be7Sderaadt * Return the index at which the given vector already exists, or -1
364df930be7Sderaadt * if it is not anywhere in the current set. If we return -1, we assume
365df930be7Sderaadt * our caller will add it at the end of the current set, and we make
366df930be7Sderaadt * sure that next time, we will find it there.
367df930be7Sderaadt */
368df930be7Sderaadt static int
findvec(const void * ptr,int hash,int len,vec_cmp_func cmp,int nextplace)369815b5809Sderaadt findvec(const void *ptr, int hash, int len, vec_cmp_func cmp, int nextplace)
370df930be7Sderaadt {
3710ac0d02eSmpech struct tails *t, **hp;
3720ac0d02eSmpech int off;
373df930be7Sderaadt
374df930be7Sderaadt hp = &tails[hash];
375df930be7Sderaadt for (t = *hp; t != NULL; t = t->t_next) {
376df930be7Sderaadt off = t->t_ends_at - len;
377df930be7Sderaadt if (off >= 0 && (*cmp)(ptr, off, len))
378df930be7Sderaadt return (off);
379df930be7Sderaadt }
380df930be7Sderaadt t = emalloc(sizeof(*t));
381df930be7Sderaadt t->t_next = *hp;
382df930be7Sderaadt *hp = t;
383df930be7Sderaadt t->t_ends_at = nextplace + len;
384df930be7Sderaadt return (-1);
385df930be7Sderaadt }
386df930be7Sderaadt
387df930be7Sderaadt /*
388df930be7Sderaadt * Comparison function for locators.
389df930be7Sderaadt */
390df930be7Sderaadt static int
samelocs(const void * ptr,int off,int len)391815b5809Sderaadt samelocs(const void *ptr, int off, int len)
392df930be7Sderaadt {
3930ac0d02eSmpech const char **p, **q;
394df930be7Sderaadt
395df930be7Sderaadt for (p = &locators.vec[off], q = (const char **)ptr; --len >= 0;)
396df930be7Sderaadt if (*p++ != *q++)
397df930be7Sderaadt return (0); /* different */
398df930be7Sderaadt return (1); /* same */
399df930be7Sderaadt }
400df930be7Sderaadt
401df930be7Sderaadt /*
402df930be7Sderaadt * Add the given locators at the end of the global loc[] table.
403df930be7Sderaadt */
404df930be7Sderaadt static int
addlocs(const char ** locs,int len)405815b5809Sderaadt addlocs(const char **locs, int len)
406df930be7Sderaadt {
4070ac0d02eSmpech const char **p;
4080ac0d02eSmpech int ret;
409df930be7Sderaadt
410df930be7Sderaadt ret = locators.used;
411df930be7Sderaadt if ((locators.used = ret + len) > locspace)
412df930be7Sderaadt panic("addlocs: overrun");
413df930be7Sderaadt for (p = &locators.vec[ret]; --len >= 0;)
414df930be7Sderaadt *p++ = *locs++;
415df930be7Sderaadt return (ret);
416df930be7Sderaadt }
417df930be7Sderaadt
418df930be7Sderaadt /*
419df930be7Sderaadt * Comparison function for qsort-by-locator-length, longest first.
420df930be7Sderaadt * We rashly assume that subtraction of these lengths does not overflow.
421df930be7Sderaadt */
422df930be7Sderaadt static int
loclencmp(const void * a,const void * b)423815b5809Sderaadt loclencmp(const void *a, const void *b)
424df930be7Sderaadt {
4250ac0d02eSmpech int l1, l2;
426df930be7Sderaadt
427df930be7Sderaadt l1 = (*(struct devi **)a)->i_atattr->a_loclen;
428df930be7Sderaadt l2 = (*(struct devi **)b)->i_atattr->a_loclen;
429df930be7Sderaadt return (l2 - l1);
430df930be7Sderaadt }
431df930be7Sderaadt
432df930be7Sderaadt /*
433df930be7Sderaadt * Comparison function for parent vectors.
434df930be7Sderaadt */
435df930be7Sderaadt static int
samepv(const void * ptr,int off,int len)436815b5809Sderaadt samepv(const void *ptr, int off, int len)
437df930be7Sderaadt {
4380ac0d02eSmpech short *p, *q;
439df930be7Sderaadt
440df930be7Sderaadt for (p = &parents.vec[off], q = (short *)ptr; --len >= 0;)
441df930be7Sderaadt if (*p++ != *q++)
442df930be7Sderaadt return (0); /* different */
443df930be7Sderaadt return (1); /* same */
444df930be7Sderaadt }
445df930be7Sderaadt
446df930be7Sderaadt /*
447df930be7Sderaadt * Add the given parent vectors at the end of the global pv[] table.
448df930be7Sderaadt */
449df930be7Sderaadt static int
addpv(short * pv,int len)450815b5809Sderaadt addpv(short *pv, int len)
451df930be7Sderaadt {
4520ac0d02eSmpech short *p;
4530ac0d02eSmpech int ret;
454df930be7Sderaadt static int firstend = -1;
455df930be7Sderaadt
456df930be7Sderaadt /*
457df930be7Sderaadt * If the vector is empty, reuse the first -1. It will be
458df930be7Sderaadt * there if there are any nonempty vectors at all, since we
459df930be7Sderaadt * do the longest first. If there are no nonempty vectors,
460df930be7Sderaadt * something is probably wrong, but we will ignore that here.
461df930be7Sderaadt */
462df930be7Sderaadt if (len == 0 && firstend >= 0)
463df930be7Sderaadt return (firstend);
464df930be7Sderaadt len++; /* account for trailing -1 */
465df930be7Sderaadt ret = parents.used;
466df930be7Sderaadt if ((parents.used = ret + len) > pvecspace)
467df930be7Sderaadt panic("addpv: overrun");
468df930be7Sderaadt for (p = &parents.vec[ret]; --len > 0;)
469df930be7Sderaadt *p++ = *pv++;
470df930be7Sderaadt *p = -1;
471df930be7Sderaadt if (firstend < 0)
472df930be7Sderaadt firstend = parents.used - 1;
473df930be7Sderaadt return (ret);
474df930be7Sderaadt }
475df930be7Sderaadt
476df930be7Sderaadt /*
477df930be7Sderaadt * Comparison function for qsort-by-parent-vector-length, longest first.
478df930be7Sderaadt * We rashly assume that subtraction of these lengths does not overflow.
479df930be7Sderaadt */
480df930be7Sderaadt static int
pvlencmp(const void * a,const void * b)481815b5809Sderaadt pvlencmp(const void *a, const void *b)
482df930be7Sderaadt {
4830ac0d02eSmpech int l1, l2;
484df930be7Sderaadt
485df930be7Sderaadt l1 = (*(struct devi **)a)->i_pvlen;
486df930be7Sderaadt l2 = (*(struct devi **)b)->i_pvlen;
487df930be7Sderaadt return (l2 - l1);
488df930be7Sderaadt }
489df930be7Sderaadt
490df930be7Sderaadt static void
resettails(void)491815b5809Sderaadt resettails(void)
492df930be7Sderaadt {
4930ac0d02eSmpech struct tails **p, *t, *next;
4940ac0d02eSmpech int i;
495df930be7Sderaadt
496df930be7Sderaadt for (p = tails, i = TAILHSIZE; --i >= 0; p++) {
497df930be7Sderaadt for (t = *p; t != NULL; t = next) {
498df930be7Sderaadt next = t->t_next;
499df930be7Sderaadt free(t);
500df930be7Sderaadt }
501df930be7Sderaadt *p = NULL;
502df930be7Sderaadt }
503df930be7Sderaadt }
504