1*57493Storek /* 2*57493Storek * Copyright (c) 1992 The Regents of the University of California. 3*57493Storek * All rights reserved. 4*57493Storek * 5*57493Storek * This software was developed by the Computer Systems Engineering group 6*57493Storek * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 7*57493Storek * contributed to Berkeley. 8*57493Storek * 9*57493Storek * All advertising materials mentioning features or use of this software 10*57493Storek * must display the following acknowledgement: 11*57493Storek * This product includes software developed by the University of 12*57493Storek * California, Lawrence Berkeley Laboratories. 13*57493Storek * 14*57493Storek * %sccs.include.redist.c% 15*57493Storek * 16*57493Storek * @(#)pack.c 5.1 (Berkeley) 01/12/93 17*57493Storek * 18*57493Storek * from: $Header: pack.c,v 1.2 92/10/10 09:01:35 torek Exp $ 19*57493Storek */ 20*57493Storek 21*57493Storek #include <sys/param.h> 22*57493Storek #include <stdlib.h> 23*57493Storek #include <string.h> 24*57493Storek #include "config.h" 25*57493Storek 26*57493Storek /* 27*57493Storek * Packing. We have three separate kinds of packing here. 28*57493Storek * 29*57493Storek * First, we pack device instances, to collapse things like 30*57493Storek * 31*57493Storek * uba0 at sbi0 nexus ? 32*57493Storek * uba0 at bi0 nexus ? 33*57493Storek * 34*57493Storek * into a single instance that is "at sbi0 or bi0". 35*57493Storek * 36*57493Storek * Second, we pack locators. Given something like 37*57493Storek * 38*57493Storek * hp0 at mba0 drive 0 39*57493Storek * hp* at mba* drive ? 40*57493Storek * ht0 at mba0 drive 0 41*57493Storek * tu0 at ht0 slave 0 42*57493Storek * ht* at mba* drive ? 43*57493Storek * tu* at ht* slave ? 44*57493Storek * 45*57493Storek * (where the default drive and slave numbers are -1), we have three 46*57493Storek * locators whose value is 0 and three whose value is -1. Rather than 47*57493Storek * emitting six integers, we emit just two. 48*57493Storek * 49*57493Storek * Finally, we pack parent vectors. This is very much like packing 50*57493Storek * locators. Unlike locators, however, parent vectors are always 51*57493Storek * terminated by -1 (rather like the way C strings always end with 52*57493Storek * a NUL). 53*57493Storek * 54*57493Storek * When packing locators, we would like to find sequences such as 55*57493Storek * {1 2 3} {2 3 4} {3} {4 5} 56*57493Storek * and turn this into the flat sequence {1 2 3 4 5}, with each subsequence 57*57493Storek * given by the appropriate offset (here 0, 1, 2, and 3 respectively). 58*57493Storek * When we pack parent vectors, overlap of this sort is impossible. 59*57493Storek * Non-overlapping packing is much easier, and so we use that here 60*57493Storek * and miss out on the chance to squeeze the locator sequence optimally. 61*57493Storek * (So it goes.) 62*57493Storek */ 63*57493Storek 64*57493Storek typedef int (*vec_cmp_func) __P((const void *, int, int)); 65*57493Storek 66*57493Storek #define TAILHSIZE 128 67*57493Storek #define PVHASH(i) ((i) & (TAILHSIZE - 1)) 68*57493Storek #define LOCHASH(l) (((int)(l) >> 2) & (TAILHSIZE - 1)) 69*57493Storek struct tails { 70*57493Storek struct tails *t_next; 71*57493Storek int t_ends_at; 72*57493Storek }; 73*57493Storek 74*57493Storek static struct tails *tails[TAILHSIZE]; 75*57493Storek static int locspace; 76*57493Storek static int pvecspace; 77*57493Storek static int longest_pvec; 78*57493Storek 79*57493Storek static void packdevi __P((void)); 80*57493Storek static void packlocs __P((void)); 81*57493Storek static void packpvec __P((void)); 82*57493Storek 83*57493Storek static void addparents __P((struct devi *src, struct devi *dst)); 84*57493Storek static int nparents __P((struct devi **, struct devbase *, int)); 85*57493Storek static int sameas __P((struct devi *, struct devi *)); 86*57493Storek static int findvec __P((const void *, int, int, vec_cmp_func, int)); 87*57493Storek static int samelocs __P((const void *, int, int)); 88*57493Storek static int addlocs __P((const char **, int)); 89*57493Storek static int loclencmp __P((const void *, const void *)); 90*57493Storek static int samepv __P((const void *, int, int)); 91*57493Storek static int addpv __P((short *, int)); 92*57493Storek static int pvlencmp __P((const void *, const void *)); 93*57493Storek static void resettails __P((void)); 94*57493Storek 95*57493Storek void 96*57493Storek pack() 97*57493Storek { 98*57493Storek register struct devi *i; 99*57493Storek register int n; 100*57493Storek 101*57493Storek /* Pack instances and make parent vectors. */ 102*57493Storek packdevi(); 103*57493Storek 104*57493Storek /* 105*57493Storek * Now that we know what we have, find upper limits on space 106*57493Storek * needed for the loc[] and pv[] tables, and find the longest 107*57493Storek * single pvec. The loc and pv table sizes are bounded by 108*57493Storek * what we would get if no packing occurred. 109*57493Storek */ 110*57493Storek locspace = pvecspace = 0; 111*57493Storek for (i = alldevi; i != NULL; i = i->i_next) { 112*57493Storek if (i->i_collapsed) 113*57493Storek continue; 114*57493Storek locspace += i->i_atattr->a_loclen; 115*57493Storek n = i->i_pvlen + 1; 116*57493Storek if (n > longest_pvec) 117*57493Storek longest_pvec = n; 118*57493Storek pvecspace += n; 119*57493Storek } 120*57493Storek 121*57493Storek /* Allocate and pack loc[]. */ 122*57493Storek locators.vec = emalloc(locspace * sizeof(*locators.vec)); 123*57493Storek locators.used = 0; 124*57493Storek packlocs(); 125*57493Storek 126*57493Storek /* Allocate and pack pv[]. */ 127*57493Storek parents.vec = emalloc(pvecspace * sizeof(*parents.vec)); 128*57493Storek parents.used = 0; 129*57493Storek packpvec(); 130*57493Storek } 131*57493Storek 132*57493Storek /* 133*57493Storek * Pack instances together wherever possible. When everything is 134*57493Storek * packed, go back and set up the parents for each. We must do this 135*57493Storek * on a second pass because during the first one, we do not know which, 136*57493Storek * if any, of the parents will collapse during packing. 137*57493Storek */ 138*57493Storek void 139*57493Storek packdevi() 140*57493Storek { 141*57493Storek register struct devi *i, *l, *p; 142*57493Storek register struct devbase *d; 143*57493Storek register int j, m, n; 144*57493Storek 145*57493Storek packed = emalloc((ndevi + 1) * sizeof *packed); 146*57493Storek n = 0; 147*57493Storek for (d = allbases; d != NULL; d = d->d_next) { 148*57493Storek /* 149*57493Storek * For each instance of each device, add or collapse 150*57493Storek * all its aliases. 151*57493Storek */ 152*57493Storek for (i = d->d_ihead; i != NULL; i = i->i_bsame) { 153*57493Storek m = n; 154*57493Storek for (l = i; l != NULL; l = l->i_alias) { 155*57493Storek l->i_pvlen = 0; 156*57493Storek l->i_pvoff = -1; 157*57493Storek l->i_locoff = -1; 158*57493Storek l->i_ivoff = -1; 159*57493Storek /* try to find an equivalent for l */ 160*57493Storek for (j = m; j < n; j++) { 161*57493Storek p = packed[j]; 162*57493Storek if (sameas(l, p)) { 163*57493Storek l->i_collapsed = 1; 164*57493Storek l->i_cfindex = p->i_cfindex; 165*57493Storek goto nextalias; 166*57493Storek } 167*57493Storek } 168*57493Storek /* could not find a suitable alias */ 169*57493Storek l->i_collapsed = 0; 170*57493Storek l->i_cfindex = n; 171*57493Storek l->i_parents = emalloc(sizeof(*l->i_parents)); 172*57493Storek l->i_parents[0] = NULL; 173*57493Storek packed[n++] = l; 174*57493Storek nextalias:; 175*57493Storek } 176*57493Storek } 177*57493Storek } 178*57493Storek npacked = n; 179*57493Storek packed[n] = NULL; 180*57493Storek for (i = alldevi; i != NULL; i = i->i_next) 181*57493Storek addparents(i, packed[i->i_cfindex]); 182*57493Storek } 183*57493Storek 184*57493Storek /* 185*57493Storek * Return true if two aliases are "the same". In this case, they need 186*57493Storek * to have the same config flags and the same locators. 187*57493Storek */ 188*57493Storek static int 189*57493Storek sameas(i1, i2) 190*57493Storek register struct devi *i1, *i2; 191*57493Storek { 192*57493Storek register const char **p1, **p2; 193*57493Storek 194*57493Storek if (i1->i_cfflags != i2->i_cfflags) 195*57493Storek return (0); 196*57493Storek for (p1 = i1->i_locs, p2 = i2->i_locs; *p1 == *p2; p2++) 197*57493Storek if (*p1++ == 0) 198*57493Storek return (1); 199*57493Storek return 0; 200*57493Storek } 201*57493Storek 202*57493Storek /* 203*57493Storek * Add the parents associated with "src" to the (presumably uncollapsed) 204*57493Storek * instance "dst". 205*57493Storek */ 206*57493Storek static void 207*57493Storek addparents(src, dst) 208*57493Storek register struct devi *src, *dst; 209*57493Storek { 210*57493Storek register struct nvlist *nv; 211*57493Storek register struct devi *i, **p, **q; 212*57493Storek register int j, n, old, new, ndup; 213*57493Storek 214*57493Storek if (dst->i_collapsed) 215*57493Storek panic("addparents() i_collapsed"); 216*57493Storek 217*57493Storek /* Collect up list of parents to add. */ 218*57493Storek if (src->i_at == NULL) /* none, 'cuz "at root" */ 219*57493Storek return; 220*57493Storek if (src->i_atdev != NULL) { 221*57493Storek n = nparents(NULL, src->i_atdev, src->i_atunit); 222*57493Storek p = emalloc(n * sizeof *p); 223*57493Storek if (n == 0) 224*57493Storek return; 225*57493Storek (void)nparents(p, src->i_atdev, src->i_atunit); 226*57493Storek } else { 227*57493Storek n = 0; 228*57493Storek for (nv = src->i_atattr->a_refs; nv != NULL; nv = nv->nv_next) 229*57493Storek n += nparents(NULL, nv->nv_ptr, src->i_atunit); 230*57493Storek if (n == 0) 231*57493Storek return; 232*57493Storek p = emalloc(n * sizeof *p); 233*57493Storek n = 0; 234*57493Storek for (nv = src->i_atattr->a_refs; nv != NULL; nv = nv->nv_next) 235*57493Storek n += nparents(p + n, nv->nv_ptr, src->i_atunit); 236*57493Storek } 237*57493Storek /* Now elide duplicates. */ 238*57493Storek ndup = 0; 239*57493Storek for (j = 0; j < n; j++) { 240*57493Storek i = p[j]; 241*57493Storek for (q = dst->i_parents; *q != NULL; q++) { 242*57493Storek if (*q == i) { 243*57493Storek ndup++; 244*57493Storek p[j] = NULL; 245*57493Storek break; 246*57493Storek } 247*57493Storek } 248*57493Storek } 249*57493Storek /* Finally, add all the non-duplicates. */ 250*57493Storek old = dst->i_pvlen; 251*57493Storek new = old + (n - ndup); 252*57493Storek if (old > new) 253*57493Storek panic("addparents() old > new"); 254*57493Storek if (old == new) { 255*57493Storek free(p); 256*57493Storek return; 257*57493Storek } 258*57493Storek dst->i_parents = q = erealloc(dst->i_parents, (new + 1) * sizeof(*q)); 259*57493Storek dst->i_pvlen = new; 260*57493Storek q[new] = NULL; 261*57493Storek q += old; 262*57493Storek for (j = 0; j < n; j++) 263*57493Storek if (p[j] != NULL) 264*57493Storek *q++ = p[j]; 265*57493Storek free(p); 266*57493Storek } 267*57493Storek 268*57493Storek /* 269*57493Storek * Count up parents, and optionally store pointers to each. 270*57493Storek */ 271*57493Storek static int 272*57493Storek nparents(p, dev, unit) 273*57493Storek register struct devi **p; 274*57493Storek register struct devbase *dev; 275*57493Storek register int unit; 276*57493Storek { 277*57493Storek register struct devi *i, *l; 278*57493Storek register int n; 279*57493Storek 280*57493Storek n = 0; 281*57493Storek /* for each instance ... */ 282*57493Storek for (i = dev->d_ihead; i != NULL; i = i->i_bsame) { 283*57493Storek /* ... take each un-collapsed alias */ 284*57493Storek for (l = i; l != NULL; l = l->i_alias) { 285*57493Storek if (!l->i_collapsed && 286*57493Storek (unit == WILD || unit == l->i_unit)) { 287*57493Storek if (p != NULL) 288*57493Storek *p++ = l; 289*57493Storek n++; 290*57493Storek } 291*57493Storek } 292*57493Storek } 293*57493Storek return (n); 294*57493Storek } 295*57493Storek 296*57493Storek static void 297*57493Storek packlocs() 298*57493Storek { 299*57493Storek register struct devi **p, *i; 300*57493Storek register int l, o; 301*57493Storek 302*57493Storek qsort(packed, npacked, sizeof *packed, loclencmp); 303*57493Storek for (p = packed; (i = *p) != NULL; p++) { 304*57493Storek if ((l = i->i_atattr->a_loclen) > 0) { 305*57493Storek o = findvec(i->i_locs, LOCHASH(i->i_locs[l - 1]), l, 306*57493Storek samelocs, locators.used); 307*57493Storek i->i_locoff = o < 0 ? addlocs(i->i_locs, l) : o; 308*57493Storek } else 309*57493Storek i->i_locoff = -1; 310*57493Storek } 311*57493Storek resettails(); 312*57493Storek } 313*57493Storek 314*57493Storek static void 315*57493Storek packpvec() 316*57493Storek { 317*57493Storek register struct devi **p, *i, **par; 318*57493Storek register int l, v, o; 319*57493Storek register short *vec; 320*57493Storek 321*57493Storek vec = emalloc(longest_pvec * sizeof(*vec)); 322*57493Storek qsort(packed, npacked, sizeof *packed, pvlencmp); 323*57493Storek for (p = packed; (i = *p) != NULL; p++) { 324*57493Storek l = i->i_pvlen; 325*57493Storek if (l > longest_pvec) panic("packpvec"); 326*57493Storek par = i->i_parents; 327*57493Storek for (v = 0; v < l; v++) 328*57493Storek vec[v] = par[v]->i_cfindex; 329*57493Storek if (l == 0 || 330*57493Storek (o = findvec(vec, PVHASH(vec[l - 1]), l, 331*57493Storek samepv, parents.used)) < 0) 332*57493Storek o = addpv(vec, l); 333*57493Storek i->i_pvoff = o; 334*57493Storek } 335*57493Storek free(vec); 336*57493Storek resettails(); 337*57493Storek } 338*57493Storek 339*57493Storek /* 340*57493Storek * Return the index at which the given vector already exists, or -1 341*57493Storek * if it is not anywhere in the current set. If we return -1, we assume 342*57493Storek * our caller will add it at the end of the current set, and we make 343*57493Storek * sure that next time, we will find it there. 344*57493Storek */ 345*57493Storek static int 346*57493Storek findvec(ptr, hash, len, cmp, nextplace) 347*57493Storek const void *ptr; 348*57493Storek int hash, len; 349*57493Storek vec_cmp_func cmp; 350*57493Storek int nextplace; 351*57493Storek { 352*57493Storek register struct tails *t, **hp; 353*57493Storek register int off; 354*57493Storek 355*57493Storek hp = &tails[hash]; 356*57493Storek for (t = *hp; t != NULL; t = t->t_next) { 357*57493Storek off = t->t_ends_at - len; 358*57493Storek if (off >= 0 && (*cmp)(ptr, off, len)) 359*57493Storek return (off); 360*57493Storek } 361*57493Storek t = emalloc(sizeof(*t)); 362*57493Storek t->t_next = *hp; 363*57493Storek *hp = t; 364*57493Storek t->t_ends_at = nextplace + len; 365*57493Storek return (-1); 366*57493Storek } 367*57493Storek 368*57493Storek /* 369*57493Storek * Comparison function for locators. 370*57493Storek */ 371*57493Storek static int 372*57493Storek samelocs(ptr, off, len) 373*57493Storek const void *ptr; 374*57493Storek int off; 375*57493Storek register int len; 376*57493Storek { 377*57493Storek register const char **p, **q; 378*57493Storek 379*57493Storek for (p = &locators.vec[off], q = (const char **)ptr; --len >= 0;) 380*57493Storek if (*p++ != *q++) 381*57493Storek return (0); /* different */ 382*57493Storek return (1); /* same */ 383*57493Storek } 384*57493Storek 385*57493Storek /* 386*57493Storek * Add the given locators at the end of the global loc[] table. 387*57493Storek */ 388*57493Storek static int 389*57493Storek addlocs(locs, len) 390*57493Storek register const char **locs; 391*57493Storek register int len; 392*57493Storek { 393*57493Storek register const char **p; 394*57493Storek register int ret; 395*57493Storek 396*57493Storek ret = locators.used; 397*57493Storek if ((locators.used = ret + len) > locspace) 398*57493Storek panic("addlocs: overrun"); 399*57493Storek for (p = &locators.vec[ret]; --len >= 0;) 400*57493Storek *p++ = *locs++; 401*57493Storek return (ret); 402*57493Storek } 403*57493Storek 404*57493Storek /* 405*57493Storek * Comparison function for qsort-by-locator-length, longest first. 406*57493Storek * We rashly assume that subtraction of these lengths does not overflow. 407*57493Storek */ 408*57493Storek static int 409*57493Storek loclencmp(a, b) 410*57493Storek const void *a, *b; 411*57493Storek { 412*57493Storek register int l1, l2; 413*57493Storek 414*57493Storek l1 = (*(struct devi **)a)->i_atattr->a_loclen; 415*57493Storek l2 = (*(struct devi **)b)->i_atattr->a_loclen; 416*57493Storek return (l2 - l1); 417*57493Storek } 418*57493Storek 419*57493Storek /* 420*57493Storek * Comparison function for parent vectors. 421*57493Storek */ 422*57493Storek static int 423*57493Storek samepv(ptr, off, len) 424*57493Storek const void *ptr; 425*57493Storek int off; 426*57493Storek register int len; 427*57493Storek { 428*57493Storek register short *p, *q; 429*57493Storek 430*57493Storek for (p = &parents.vec[off], q = (short *)ptr; --len >= 0;) 431*57493Storek if (*p++ != *q++) 432*57493Storek return (0); /* different */ 433*57493Storek return (1); /* same */ 434*57493Storek } 435*57493Storek 436*57493Storek /* 437*57493Storek * Add the given parent vectors at the end of the global pv[] table. 438*57493Storek */ 439*57493Storek static int 440*57493Storek addpv(pv, len) 441*57493Storek register short *pv; 442*57493Storek register int len; 443*57493Storek { 444*57493Storek register short *p; 445*57493Storek register int ret; 446*57493Storek static int firstend = -1; 447*57493Storek 448*57493Storek /* 449*57493Storek * If the vector is empty, reuse the first -1. It will be 450*57493Storek * there if there are any nonempty vectors at all, since we 451*57493Storek * do the longest first. If there are no nonempty vectors, 452*57493Storek * something is probably wrong, but we will ignore that here. 453*57493Storek */ 454*57493Storek if (len == 0 && firstend >= 0) 455*57493Storek return (firstend); 456*57493Storek len++; /* account for trailing -1 */ 457*57493Storek ret = parents.used; 458*57493Storek if ((parents.used = ret + len) > pvecspace) 459*57493Storek panic("addpv: overrun"); 460*57493Storek for (p = &parents.vec[ret]; --len > 0;) 461*57493Storek *p++ = *pv++; 462*57493Storek *p = -1; 463*57493Storek if (firstend < 0) 464*57493Storek firstend = parents.used - 1; 465*57493Storek return (ret); 466*57493Storek } 467*57493Storek 468*57493Storek /* 469*57493Storek * Comparison function for qsort-by-parent-vector-length, longest first. 470*57493Storek * We rashly assume that subtraction of these lengths does not overflow. 471*57493Storek */ 472*57493Storek static int 473*57493Storek pvlencmp(a, b) 474*57493Storek const void *a, *b; 475*57493Storek { 476*57493Storek register int l1, l2; 477*57493Storek 478*57493Storek l1 = (*(struct devi **)a)->i_pvlen; 479*57493Storek l2 = (*(struct devi **)b)->i_pvlen; 480*57493Storek return (l2 - l1); 481*57493Storek } 482*57493Storek 483*57493Storek static void 484*57493Storek resettails() 485*57493Storek { 486*57493Storek register struct tails **p, *t, *next; 487*57493Storek register int i; 488*57493Storek 489*57493Storek for (p = tails, i = TAILHSIZE; --i >= 0; p++) { 490*57493Storek for (t = *p; t != NULL; t = next) { 491*57493Storek next = t->t_next; 492*57493Storek free(t); 493*57493Storek } 494*57493Storek *p = NULL; 495*57493Storek } 496*57493Storek } 497