pack.c revision 1.8.24.1 1 /* $NetBSD: pack.c,v 1.8.24.1 2015/03/06 21:00:23 snj Exp $ */
2
3 /*
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This software was developed by the Computer Systems Engineering group
8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9 * contributed to Berkeley.
10 *
11 * All advertising materials mentioning features or use of this software
12 * must display the following acknowledgement:
13 * This product includes software developed by the University of
14 * California, Lawrence Berkeley Laboratories.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 * 3. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 * from: @(#)pack.c 8.1 (Berkeley) 6/6/93
41 */
42
43 #if HAVE_NBTOOL_CONFIG_H
44 #include "nbtool_config.h"
45 #endif
46
47 #include <sys/cdefs.h>
48 __RCSID("$NetBSD: pack.c,v 1.8.24.1 2015/03/06 21:00:23 snj Exp $");
49
50 #include <sys/param.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <util.h>
54 #include "defs.h"
55
56 /*
57 * Packing. We have three separate kinds of packing here.
58 *
59 * First, we pack device instances which have identical parent specs.
60 *
61 * Second, we pack locators. Given something like
62 *
63 * hp0 at mba0 drive 0
64 * hp* at mba* drive ?
65 * ht0 at mba0 drive 0
66 * tu0 at ht0 slave 0
67 * ht* at mba* drive ?
68 * tu* at ht* slave ?
69 *
70 * (where the default drive and slave numbers are -1), we have three
71 * locators whose value is 0 and three whose value is -1. Rather than
72 * emitting six integers, we emit just two.
73 *
74 * When packing locators, we would like to find sequences such as
75 * {1 2 3} {2 3 4} {3} {4 5}
76 * and turn this into the flat sequence {1 2 3 4 5}, with each subsequence
77 * given by the appropriate offset (here 0, 1, 2, and 3 respectively).
78 * Non-overlapping packing is much easier, and so we use that here
79 * and miss out on the chance to squeeze the locator sequence optimally.
80 * (So it goes.)
81 */
82
83 typedef int (*vec_cmp_func)(const void *, int, int);
84
85 #define TAILHSIZE 128
86 #define PVHASH(i) ((i) & (TAILHSIZE - 1))
87 #define LOCHASH(l) (((long)(l) >> 2) & (TAILHSIZE - 1))
88 struct tails {
89 struct tails *t_next;
90 int t_ends_at;
91 };
92
93 static struct tails *tails[TAILHSIZE];
94 static int locspace;
95
96 static void packdevi(void);
97 static void packlocs(void);
98
99 static int sameas(struct devi *, struct devi *);
100 static int findvec(const void *, int, int, vec_cmp_func, int);
101 static int samelocs(const void *, int, int);
102 static int addlocs(const char **, int);
103 static int loclencmp(const void *, const void *);
104 static void resettails(void);
105
106 void
107 pack(void)
108 {
109 struct pspec *p;
110 struct devi *i;
111
112 /* Pack instances and make parent vectors. */
113 packdevi();
114
115 /*
116 * Now that we know what we have, find upper limits on space
117 * needed for the loc[] table. The loc table size is bounded by
118 * what we would get if no packing occurred.
119 */
120 locspace = 0;
121 TAILQ_FOREACH(i, &alldevi, i_next) {
122 if (!i->i_active == DEVI_ACTIVE || i->i_collapsed)
123 continue;
124 if ((p = i->i_pspec) == NULL)
125 continue;
126 locspace += p->p_iattr->a_loclen;
127 }
128
129 /* Allocate and pack loc[]. */
130 locators.vec = ecalloc((size_t)locspace, sizeof(*locators.vec));
131 locators.used = 0;
132 packlocs();
133 }
134
135 /*
136 * Pack device instances together wherever possible.
137 */
138 static void
139 packdevi(void)
140 {
141 struct devi *firststar, *i, **ip, *l, *p;
142 struct devbase *d;
143 u_short j, m, n;
144
145 /*
146 * Sort all the cloning units to after the non-cloning units,
147 * preserving order of cloning and non-cloning units with
148 * respect to other units of the same type.
149 *
150 * Algorithm: Walk down the list until the first cloning unit is
151 * seen for the second time (or until the end of the list, if there
152 * are no cloning units on the list), moving starred units to the
153 * end of the list.
154 */
155 TAILQ_FOREACH(d, &allbases, d_next) {
156 ip = &d->d_ihead;
157 firststar = NULL;
158
159 for (i = *ip; i != firststar; i = *ip) {
160 if (i->i_unit != STAR) {
161 /* try i->i_bsame next */
162 ip = &i->i_bsame;
163 } else {
164 if (firststar == NULL)
165 firststar = i;
166
167 *d->d_ipp = i;
168 d->d_ipp = &i->i_bsame;
169
170 *ip = i->i_bsame;
171 i->i_bsame = NULL;
172
173 /* leave ip alone; try (old) i->i_bsame next */
174 }
175 }
176 }
177
178 packed = ecalloc((size_t)ndevi + 1, sizeof *packed);
179 n = 0;
180 TAILQ_FOREACH(d, &allbases, d_next) {
181 /*
182 * For each instance of each device, add or collapse
183 * all its aliases.
184 *
185 * Pseudo-devices have a non-empty d_ihead for convenience.
186 * Ignore them.
187 */
188 if (d->d_ispseudo)
189 continue;
190 for (i = d->d_ihead; i != NULL; i = i->i_bsame) {
191 m = n;
192 for (l = i; l != NULL; l = l->i_alias) {
193 if (l->i_active != DEVI_ACTIVE
194 || i->i_pseudoroot)
195 continue;
196 l->i_locoff = -1;
197 /* try to find an equivalent for l */
198 for (j = m; j < n; j++) {
199 p = packed[j];
200 if (sameas(l, p)) {
201 l->i_collapsed = 1;
202 l->i_cfindex = p->i_cfindex;
203 goto nextalias;
204 }
205 }
206 /* could not find a suitable alias */
207 l->i_collapsed = 0;
208 l->i_cfindex = n;
209 packed[n++] = l;
210 nextalias:;
211 }
212 }
213 }
214 npacked = n;
215 packed[n] = NULL;
216 }
217
218 /*
219 * Return true if two aliases are "the same". In this case, they need
220 * to have the same parent spec, have the same config flags, and have
221 * the same locators.
222 */
223 static int
224 sameas(struct devi *i1, struct devi *i2)
225 {
226 const char **p1, **p2;
227
228 if (i1->i_pspec != i2->i_pspec)
229 return (0);
230 if (i1->i_cfflags != i2->i_cfflags)
231 return (0);
232 for (p1 = i1->i_locs, p2 = i2->i_locs; *p1 == *p2; p2++)
233 if (*p1++ == 0)
234 return (1);
235 return (0);
236 }
237
238 static void
239 packlocs(void)
240 {
241 struct pspec *ps;
242 struct devi **p, *i;
243 int l,o;
244 extern int Pflag;
245
246 qsort(packed, npacked, sizeof *packed, loclencmp);
247 for (p = packed; (i = *p) != NULL; p++) {
248 if ((ps = i->i_pspec) != NULL &&
249 (l = ps->p_iattr->a_loclen) > 0) {
250 if (Pflag) {
251 o = findvec(i->i_locs,
252 LOCHASH(i->i_locs[l - 1]), l,
253 samelocs, locators.used);
254 i->i_locoff = o < 0 ?
255 addlocs(i->i_locs, l) : o;
256 } else
257 i->i_locoff = addlocs(i->i_locs, l);
258 } else
259 i->i_locoff = -1;
260 }
261 resettails();
262 }
263
264 /*
265 * Return the index at which the given vector already exists, or -1
266 * if it is not anywhere in the current set. If we return -1, we assume
267 * our caller will add it at the end of the current set, and we make
268 * sure that next time, we will find it there.
269 */
270 static int
271 findvec(const void *ptr, int hash, int len, vec_cmp_func cmp, int nextplace)
272 {
273 struct tails *t, **hp;
274 int off;
275
276 hp = &tails[hash];
277 for (t = *hp; t != NULL; t = t->t_next) {
278 off = t->t_ends_at - len;
279 if (off >= 0 && (*cmp)(ptr, off, len))
280 return (off);
281 }
282 t = ecalloc(1, sizeof(*t));
283 t->t_next = *hp;
284 *hp = t;
285 t->t_ends_at = nextplace + len;
286 return (-1);
287 }
288
289 /*
290 * Comparison function for locators.
291 */
292 static int
293 samelocs(const void *ptr, int off, int len)
294 {
295 const char * const *p, * const *q;
296
297 for (p = &locators.vec[off], q = (const char * const *)ptr; --len >= 0;)
298 if (*p++ != *q++)
299 return (0); /* different */
300 return (1); /* same */
301 }
302
303 /*
304 * Add the given locators at the end of the global loc[] table.
305 */
306 static int
307 addlocs(const char **locs, int len)
308 {
309 const char **p;
310 int ret;
311
312 ret = locators.used;
313 if ((locators.used = ret + len) > locspace)
314 panic("addlocs: overrun");
315 for (p = &locators.vec[ret]; --len >= 0;)
316 *p++ = *locs++;
317 return (ret);
318 }
319
320 /*
321 * Comparison function for qsort-by-locator-length, longest first.
322 * We rashly assume that subtraction of these lengths does not overflow.
323 */
324 static int
325 loclencmp(const void *a, const void *b)
326 {
327 const struct pspec *p1, *p2;
328 int l1, l2;
329
330 p1 = (*(const struct devi * const *)a)->i_pspec;
331 l1 = p1 != NULL ? p1->p_iattr->a_loclen : 0;
332
333 p2 = (*(const struct devi * const *)b)->i_pspec;
334 l2 = p2 != NULL ? p2->p_iattr->a_loclen : 0;
335
336 return (l2 - l1);
337 }
338
339 static void
340 resettails(void)
341 {
342 struct tails **p, *t, *next;
343 int i;
344
345 for (p = tails, i = TAILHSIZE; --i >= 0; p++) {
346 for (t = *p; t != NULL; t = next) {
347 next = t->t_next;
348 free(t);
349 }
350 *p = NULL;
351 }
352 }
353