1 /* 2 * Copyright (c) 1992 The Regents of the University of California. 3 * 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 5.2 (Berkeley) 04/18/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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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