Blob
1 #include <u.h>2 #include <libc.h>3 #include <venti.h>4 #include <libsec.h>6 typedef struct Mem Mem;7 typedef struct Frag Frag;9 enum {10 BigMemSize = MaxFragSize,11 SmallMemSize = BigMemSize/8,12 NLocalFrag = 2,13 };15 /* position to carve out of a Mem */16 enum {17 PFront,18 PMiddle,19 PEnd,20 };22 struct Mem23 {24 Lock lk;25 int ref;26 uchar *bp;27 uchar *ep;28 uchar *rp;29 uchar *wp;30 Mem *next;31 };33 enum {34 FragLocalFree,35 FragLocalAlloc,36 FragGlobal,37 };39 struct Frag40 {41 int state;42 Mem *mem;43 uchar *rp;44 uchar *wp;45 Frag *next;46 void (*free)(void*);47 void *a;48 };50 struct Packet51 {52 int size;53 int asize; /* allocated memory - greater than size unless foreign frags */55 Packet *next;57 Frag *first;58 Frag *last;60 Frag local[NLocalFrag];61 };63 static Frag *fragalloc(Packet*, int n, int pos, Frag *next);64 static Frag *fragdup(Packet*, Frag*);65 static void fragfree(Frag*);67 static Mem *memalloc(int, int);68 static void memfree(Mem*);69 static int memhead(Mem *m, uchar *rp, int n);70 static int memtail(Mem *m, uchar *wp, int n);72 static char EPacketSize[] = "bad packet size";73 static char EPacketOffset[] = "bad packet offset";74 static char EBadSize[] = "bad size";76 static struct {77 Lock lk;78 Packet *packet;79 int npacket;80 Frag *frag;81 int nfrag;82 Mem *bigmem;83 int nbigmem;84 Mem *smallmem;85 int nsmallmem;86 } freelist;88 #define FRAGSIZE(f) ((f)->wp - (f)->rp)89 #define FRAGASIZE(f) ((f)->mem ? (f)->mem->ep - (f)->mem->bp : 0)91 #define NOTFREE(p) assert((p)->size>=0)93 Packet *94 packetalloc(void)95 {96 Packet *p;98 lock(&freelist.lk);99 p = freelist.packet;100 if(p != nil)101 freelist.packet = p->next;102 else103 freelist.npacket++;104 unlock(&freelist.lk);106 if(p == nil)107 p = vtbrk(sizeof(Packet));108 else109 assert(p->size == -1);110 p->size = 0;111 p->asize = 0;112 p->first = nil;113 p->last = nil;114 p->next = nil;116 if(1)fprint(2, "packetalloc %p from %08lux %08lux %08lux\n", p, *((uint*)&p+2), *((uint*)&p+3), *((uint*)&p+4));118 return p;119 }121 void122 packetfree(Packet *p)123 {124 Frag *f, *ff;126 if(1)fprint(2, "packetfree %p from %08lux\n", p, getcallerpc(&p));128 if(p == nil)129 return;131 NOTFREE(p);132 p->size = -1;134 for(f=p->first; f!=nil; f=ff) {135 ff = f->next;136 fragfree(f);137 }138 p->first = nil;139 p->last = nil;141 lock(&freelist.lk);142 p->next = freelist.packet;143 freelist.packet = p;144 unlock(&freelist.lk);145 }147 Packet *148 packetdup(Packet *p, int offset, int n)149 {150 Frag *f, *ff;151 Packet *pp;153 NOTFREE(p);154 if(offset < 0 || n < 0 || offset+n > p->size) {155 werrstr(EBadSize);156 return nil;157 }159 pp = packetalloc();160 if(n == 0)161 return pp;163 pp->size = n;165 /* skip offset */166 for(f=p->first; offset >= FRAGSIZE(f); f=f->next)167 offset -= FRAGSIZE(f);169 /* first frag */170 ff = fragdup(pp, f);171 ff->rp += offset;172 pp->first = ff;173 n -= FRAGSIZE(ff);174 pp->asize += FRAGASIZE(ff);176 /* the remaining */177 while(n > 0) {178 f = f->next;179 ff->next = fragdup(pp, f);180 ff = ff->next;181 n -= FRAGSIZE(ff);182 pp->asize += FRAGASIZE(ff);183 }185 /* fix up last frag: note n <= 0 */186 ff->wp += n;187 ff->next = nil;188 pp->last = ff;190 return pp;191 }193 Packet *194 packetsplit(Packet *p, int n)195 {196 Packet *pp;197 Frag *f, *ff;199 NOTFREE(p);200 if(n < 0 || n > p->size) {201 werrstr(EPacketSize);202 return nil;203 }205 pp = packetalloc();206 if(n == 0)207 return pp;209 pp->size = n;210 p->size -= n;211 ff = nil;212 for(f=p->first; n > 0 && n >= FRAGSIZE(f); f=f->next) {213 n -= FRAGSIZE(f);214 p->asize -= FRAGASIZE(f);215 pp->asize += FRAGASIZE(f);216 ff = f;217 }219 /* split shared frag */220 if(n > 0) {221 ff = f;222 f = fragdup(pp, ff);223 pp->asize += FRAGASIZE(ff);224 ff->next = nil;225 ff->wp = ff->rp + n;226 f->rp += n;227 }229 pp->first = p->first;230 pp->last = ff;231 p->first = f;232 return pp;233 }235 int236 packetconsume(Packet *p, uchar *buf, int n)237 {238 NOTFREE(p);239 if(buf && packetcopy(p, buf, 0, n) < 0)240 return 0;241 return packettrim(p, n, p->size-n);242 }244 int245 packettrim(Packet *p, int offset, int n)246 {247 Frag *f, *ff;249 NOTFREE(p);250 if(offset < 0 || offset > p->size) {251 werrstr(EPacketOffset);252 return -1;253 }255 if(n < 0 || offset + n > p->size) {256 werrstr(EPacketOffset);257 return -1;258 }260 p->size = n;262 /* easy case */263 if(n == 0) {264 for(f=p->first; f != nil; f=ff) {265 ff = f->next;266 fragfree(f);267 }268 p->first = p->last = nil;269 p->asize = 0;270 return 0;271 }273 /* free before offset */274 for(f=p->first; offset >= FRAGSIZE(f); f=ff) {275 p->asize -= FRAGASIZE(f);276 offset -= FRAGSIZE(f);277 ff = f->next;278 fragfree(f);279 }281 /* adjust frag */282 f->rp += offset;283 p->first = f;285 /* skip middle */286 for(; n > 0 && n > FRAGSIZE(f); f=f->next)287 n -= FRAGSIZE(f);289 /* adjust end */290 f->wp = f->rp + n;291 p->last = f;292 ff = f->next;293 f->next = nil;295 /* free after */296 for(f=ff; f != nil; f=ff) {297 p->asize -= FRAGASIZE(f);298 ff = f->next;299 fragfree(f);300 }301 return 0;302 }304 uchar *305 packetheader(Packet *p, int n)306 {307 Frag *f;308 Mem *m;310 NOTFREE(p);311 if(n <= 0 || n > MaxFragSize) {312 werrstr(EPacketSize);313 return nil;314 }316 p->size += n;318 /* try and fix in current frag */319 f = p->first;320 if(f != nil) {321 m = f->mem;322 if(n <= f->rp - m->bp)323 if(m->ref == 1 || memhead(m, f->rp, n) >= 0) {324 f->rp -= n;325 return f->rp;326 }327 }329 /* add frag to front */330 f = fragalloc(p, n, PEnd, p->first);331 p->asize += FRAGASIZE(f);332 if(p->first == nil)333 p->last = f;334 p->first = f;335 return f->rp;336 }338 uchar *339 packettrailer(Packet *p, int n)340 {341 Mem *m;342 Frag *f;344 NOTFREE(p);345 if(n <= 0 || n > MaxFragSize) {346 werrstr(EPacketSize);347 return nil;348 }350 p->size += n;352 /* try and fix in current frag */353 if(p->first != nil) {354 f = p->last;355 m = f->mem;356 if(n <= m->ep - f->wp)357 if(m->ref == 1 || memtail(m, f->wp, n) >= 0) {358 f->wp += n;359 return f->wp - n;360 }361 }363 /* add frag to end */364 f = fragalloc(p, n, (p->first == nil)?PMiddle:PFront, nil);365 p->asize += FRAGASIZE(f);366 if(p->first == nil)367 p->first = f;368 else369 p->last->next = f;370 p->last = f;371 return f->rp;372 }374 int375 packetprefix(Packet *p, uchar *buf, int n)376 {377 Frag *f;378 int nn;379 Mem *m;381 NOTFREE(p);382 if(n <= 0)383 return 0;385 p->size += n;387 /* try and fix in current frag */388 f = p->first;389 if(f != nil) {390 m = f->mem;391 nn = f->rp - m->bp;392 if(nn > n)393 nn = n;394 if(m->ref == 1 || memhead(m, f->rp, nn) >= 0) {395 f->rp -= nn;396 n -= nn;397 memmove(f->rp, buf+n, nn);398 }399 }401 while(n > 0) {402 nn = n;403 if(nn > MaxFragSize)404 nn = MaxFragSize;405 f = fragalloc(p, nn, PEnd, p->first);406 p->asize += FRAGASIZE(f);407 if(p->first == nil)408 p->last = f;409 p->first = f;410 n -= nn;411 memmove(f->rp, buf+n, nn);412 }413 return 0;414 }416 int417 packetappend(Packet *p, uchar *buf, int n)418 {419 Frag *f;420 int nn;421 Mem *m;423 NOTFREE(p);424 if(n <= 0)425 return 0;427 p->size += n;428 /* try and fix in current frag */429 if(p->first != nil) {430 f = p->last;431 m = f->mem;432 nn = m->ep - f->wp;433 if(nn > n)434 nn = n;435 if(m->ref == 1 || memtail(m, f->wp, nn) >= 0) {436 memmove(f->wp, buf, nn);437 f->wp += nn;438 buf += nn;439 n -= nn;440 }441 }443 while(n > 0) {444 nn = n;445 if(nn > MaxFragSize)446 nn = MaxFragSize;447 f = fragalloc(p, nn, (p->first == nil)?PMiddle:PFront, nil);448 p->asize += FRAGASIZE(f);449 if(p->first == nil)450 p->first = f;451 else452 p->last->next = f;453 p->last = f;454 memmove(f->rp, buf, nn);455 buf += nn;456 n -= nn;457 }458 return 0;459 }461 int462 packetconcat(Packet *p, Packet *pp)463 {464 NOTFREE(p);465 NOTFREE(pp);466 if(pp->size == 0)467 return 0;468 p->size += pp->size;469 p->asize += pp->asize;471 if(p->first != nil)472 p->last->next = pp->first;473 else474 p->first = pp->first;475 p->last = pp->last;476 pp->size = 0;477 pp->asize = 0;478 pp->first = nil;479 pp->last = nil;480 return 0;481 }483 uchar *484 packetpeek(Packet *p, uchar *buf, int offset, int n)485 {486 Frag *f;487 int nn;488 uchar *b;490 NOTFREE(p);491 if(n == 0)492 return buf;494 if(offset < 0 || offset >= p->size) {495 werrstr(EPacketOffset);496 return nil;497 }499 if(n < 0 || offset + n > p->size) {500 werrstr(EPacketSize);501 return nil;502 }504 /* skip up to offset */505 for(f=p->first; offset >= FRAGSIZE(f); f=f->next)506 offset -= FRAGSIZE(f);508 /* easy case */509 if(offset + n <= FRAGSIZE(f))510 return f->rp + offset;512 for(b=buf; n>0; n -= nn) {513 nn = FRAGSIZE(f) - offset;514 if(nn > n)515 nn = n;516 memmove(b, f->rp+offset, nn);517 offset = 0;518 f = f->next;519 b += nn;520 }522 return buf;523 }525 int526 packetcopy(Packet *p, uchar *buf, int offset, int n)527 {528 uchar *b;530 NOTFREE(p);531 b = packetpeek(p, buf, offset, n);532 if(b == nil)533 return -1;534 if(b != buf)535 memmove(buf, b, n);536 return 0;537 }539 int540 packetfragments(Packet *p, IOchunk *io, int nio, int offset)541 {542 Frag *f;543 int size;544 IOchunk *eio;546 NOTFREE(p);547 if(p->size == 0 || nio <= 0)548 return 0;550 if(offset < 0 || offset > p->size) {551 werrstr(EPacketOffset);552 return -1;553 }555 for(f=p->first; offset >= FRAGSIZE(f); f=f->next)556 offset -= FRAGSIZE(f);558 size = 0;559 eio = io + nio;560 for(; f != nil && io < eio; f=f->next) {561 io->addr = f->rp + offset;562 io->len = f->wp - (f->rp + offset);563 offset = 0;564 size += io->len;565 io++;566 }568 return size;569 }571 void572 packetstats(void)573 {574 Packet *p;575 Frag *f;576 Mem *m;578 int np, nf, nsm, nbm;580 lock(&freelist.lk);581 np = 0;582 for(p=freelist.packet; p; p=p->next)583 np++;584 nf = 0;585 for(f=freelist.frag; f; f=f->next)586 nf++;587 nsm = 0;588 for(m=freelist.smallmem; m; m=m->next)589 nsm++;590 nbm = 0;591 for(m=freelist.bigmem; m; m=m->next)592 nbm++;594 fprint(2, "packet: %d/%d frag: %d/%d small mem: %d/%d big mem: %d/%d\n",595 np, freelist.npacket,596 nf, freelist.nfrag,597 nsm, freelist.nsmallmem,598 nbm, freelist.nbigmem);600 unlock(&freelist.lk);601 }604 uint605 packetsize(Packet *p)606 {607 NOTFREE(p);608 if(0) {609 Frag *f;610 int size = 0;612 for(f=p->first; f; f=f->next)613 size += FRAGSIZE(f);614 if(size != p->size)615 fprint(2, "packetsize %d %d\n", size, p->size);616 assert(size == p->size);617 }618 return p->size;619 }621 uint622 packetasize(Packet *p)623 {624 NOTFREE(p);625 if(0) {626 Frag *f;627 int asize = 0;629 for(f=p->first; f; f=f->next)630 asize += FRAGASIZE(f);631 if(asize != p->asize)632 fprint(2, "packetasize %d %d\n", asize, p->asize);633 assert(asize == p->asize);634 }635 return p->asize;636 }638 void639 packetsha1(Packet *p, uchar digest[VtScoreSize])640 {641 DigestState ds;642 Frag *f;643 int size;645 NOTFREE(p);646 memset(&ds, 0, sizeof ds);647 size = p->size;648 for(f=p->first; f; f=f->next) {649 sha1(f->rp, FRAGSIZE(f), nil, &ds);650 size -= FRAGSIZE(f);651 }652 assert(size == 0);653 sha1(nil, 0, digest, &ds);654 }656 int657 packetcmp(Packet *pkt0, Packet *pkt1)658 {659 Frag *f0, *f1;660 int n0, n1, x;662 NOTFREE(pkt0);663 NOTFREE(pkt1);664 f0 = pkt0->first;665 f1 = pkt1->first;667 if(f0 == nil)668 return (f1 == nil)?0:-1;669 if(f1 == nil)670 return 1;671 n0 = FRAGSIZE(f0);672 n1 = FRAGSIZE(f1);674 for(;;) {675 if(n0 < n1) {676 x = memcmp(f0->wp - n0, f1->wp - n1, n0);677 if(x != 0)678 return x;679 n1 -= n0;680 f0 = f0->next;681 if(f0 == nil)682 return -1;683 n0 = FRAGSIZE(f0);684 } else if (n0 > n1) {685 x = memcmp(f0->wp - n0, f1->wp - n1, n1);686 if(x != 0)687 return x;688 n0 -= n1;689 f1 = f1->next;690 if(f1 == nil)691 return 1;692 n1 = FRAGSIZE(f1);693 } else { /* n0 == n1 */694 x = memcmp(f0->wp - n0, f1->wp - n1, n0);695 if(x != 0)696 return x;697 f0 = f0->next;698 f1 = f1->next;699 if(f0 == nil)700 return (f1 == nil)?0:-1;701 if(f1 == nil)702 return 1;703 n0 = FRAGSIZE(f0);704 n1 = FRAGSIZE(f1);705 }706 }707 return 0; /* for ken */708 }711 static Frag *712 fragalloc(Packet *p, int n, int pos, Frag *next)713 {714 Frag *f, *ef;715 Mem *m;717 /* look for local frag */718 f = &p->local[0];719 ef = &p->local[NLocalFrag];720 for(;f<ef; f++) {721 if(f->state == FragLocalFree) {722 f->state = FragLocalAlloc;723 goto Found;724 }725 }726 lock(&freelist.lk);727 f = freelist.frag;728 if(f != nil)729 freelist.frag = f->next;730 else731 freelist.nfrag++;732 unlock(&freelist.lk);734 if(f == nil) {735 f = vtbrk(sizeof(Frag));736 f->state = FragGlobal;737 }739 Found:740 f->next = next;742 if(n == 0){743 f->mem = 0;744 f->rp = 0;745 f->wp = 0;746 return f;747 }749 if(pos == PEnd && next == nil)750 pos = PMiddle;751 m = memalloc(n, pos);752 f->mem = m;753 f->rp = m->rp;754 f->wp = m->wp;755 return f;756 }758 Packet*759 packetforeign(uchar *buf, int n, void (*free)(void *a), void *a)760 {761 Packet *p;762 Frag *f;764 p = packetalloc();765 f = fragalloc(p, 0, 0, nil);766 f->free = free;767 f->a = a;768 f->next = nil;769 f->rp = buf;770 f->wp = buf+n;772 p->first = f;773 p->size = n;774 return p;775 }777 static Frag *778 fragdup(Packet *p, Frag *f)779 {780 Frag *ff;781 Mem *m;783 m = f->mem;785 /*786 * m->rp && m->wp can be out of date when ref == 1787 * also, potentially reclaims space from previous frags788 */789 if(m && m->ref == 1) {790 m->rp = f->rp;791 m->wp = f->wp;792 }794 ff = fragalloc(p, 0, 0, nil);795 *ff = *f;796 if(m){797 lock(&m->lk);798 m->ref++;799 unlock(&m->lk);800 }801 return ff;802 }805 static void806 fragfree(Frag *f)807 {808 if(f->mem == nil){809 if(f->free)810 (*f->free)(f->a);811 }else{812 memfree(f->mem);813 f->mem = 0;814 }816 if(f->state == FragLocalAlloc) {817 f->state = FragLocalFree;818 return;819 }821 lock(&freelist.lk);822 f->next = freelist.frag;823 freelist.frag = f;824 unlock(&freelist.lk);825 }827 static Mem *828 memalloc(int n, int pos)829 {830 Mem *m;831 int nn;833 if(n < 0 || n > MaxFragSize) {834 werrstr(EPacketSize);835 return 0;836 }837 if(n <= SmallMemSize) {838 lock(&freelist.lk);839 m = freelist.smallmem;840 if(m != nil)841 freelist.smallmem = m->next;842 else843 freelist.nsmallmem++;844 unlock(&freelist.lk);845 nn = SmallMemSize;846 } else {847 lock(&freelist.lk);848 m = freelist.bigmem;849 if(m != nil)850 freelist.bigmem = m->next;851 else852 freelist.nbigmem++;853 unlock(&freelist.lk);854 nn = BigMemSize;855 }857 if(m == nil) {858 m = vtbrk(sizeof(Mem));859 m->bp = vtbrk(nn);860 m->ep = m->bp + nn;861 }862 assert(m->ref == 0);863 m->ref = 1;865 switch(pos) {866 default:867 assert(0);868 case PFront:869 m->rp = m->bp;870 break;871 case PMiddle:872 /* leave a little bit at end */873 m->rp = m->ep - n - 32;874 break;875 case PEnd:876 m->rp = m->ep - n;877 break;878 }879 /* check we did not blow it */880 if(m->rp < m->bp)881 m->rp = m->bp;882 m->wp = m->rp + n;883 assert(m->rp >= m->bp && m->wp <= m->ep);884 return m;885 }887 static void888 memfree(Mem *m)889 {890 lock(&m->lk);891 m->ref--;892 if(m->ref > 0) {893 unlock(&m->lk);894 return;895 }896 unlock(&m->lk);897 assert(m->ref == 0);899 switch(m->ep - m->bp) {900 default:901 assert(0);902 case SmallMemSize:903 lock(&freelist.lk);904 m->next = freelist.smallmem;905 freelist.smallmem = m;906 unlock(&freelist.lk);907 break;908 case BigMemSize:909 lock(&freelist.lk);910 m->next = freelist.bigmem;911 freelist.bigmem = m;912 unlock(&freelist.lk);913 break;914 }915 }917 static int918 memhead(Mem *m, uchar *rp, int n)919 {920 lock(&m->lk);921 if(m->rp != rp) {922 unlock(&m->lk);923 return -1;924 }925 m->rp -= n;926 unlock(&m->lk);927 return 0;928 }930 static int931 memtail(Mem *m, uchar *wp, int n)932 {933 lock(&m->lk);934 if(m->wp != wp) {935 unlock(&m->lk);936 return -1;937 }938 m->wp += n;939 unlock(&m->lk);940 return 0;941 }