123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 |
- #include <u.h>
- #include <libc.h>
- #include "iotrack.h"
- #include "dat.h"
- #include "fns.h"
- #define HIOB 31 /* a prime */
- #define NIOBUF 80
- static Iotrack hiob[HIOB+1]; /* hash buckets + lru list */
- static Iotrack iobuf[NIOBUF]; /* the real ones */
- #define UNLINK(p, nx, pr) ((p)->pr->nx = (p)->nx, (p)->nx->pr = (p)->pr)
- #define LINK(h, p, nx, pr) ((p)->nx = (h)->nx, (p)->pr = (h), \
- (h)->nx->pr = (p), (h)->nx = (p))
- #define HTOFRONT(h, p) ((h)->hnext != (p) && (UNLINK(p,hnext,hprev), LINK(h,p,hnext,hprev)))
- #define TOFRONT(h, p) ((h)->next != (p) && (UNLINK(p, next, prev), LINK(h,p, next, prev)))
- Iosect *
- getsect(Xfs *xf, long addr)
- {
- return getiosect(xf, addr, 1);
- }
- Iosect *
- getosect(Xfs *xf, long addr)
- {
- return getiosect(xf, addr, 0);
- }
- Iosect *
- getiosect(Xfs *xf, long addr, int rflag)
- {
- Iotrack *t;
- long taddr;
- int toff;
- Iosect *p;
- toff = addr % Sect2trk;
- taddr = addr - toff;
- t = getiotrack(xf, taddr);
- if(rflag && (t->flags&BSTALE)){
- if(tread(t) < 0){
- unmlock(&t->lock);
- return 0;
- }
- t->flags &= ~BSTALE;
- }
- t->ref++;
- p = t->tp->p[toff];
- if(p == 0){
- p = newsect();
- t->tp->p[toff] = p;
- p->flags = t->flags&BSTALE;
- p->lock.key = 0;
- p->t = t;
- p->iobuf = t->tp->buf[toff];
- }
- unmlock(&t->lock);
- mlock(&p->lock);
- return p;
- }
- void
- putsect(Iosect *p)
- {
- Iotrack *t;
- if(canmlock(&p->lock))
- panic("putsect");
- t = p->t;
- mlock(&t->lock);
- t->flags |= p->flags;
- p->flags = 0;
- t->ref--;
- if(t->flags & BIMM){
- if(t->flags & BMOD)
- twrite(t);
- t->flags &= ~(BMOD|BIMM);
- }
- unmlock(&t->lock);
- unmlock(&p->lock);
- }
- Iotrack *
- getiotrack(Xfs *xf, long addr)
- {
- Iotrack *hp, *p;
- Iotrack *mp = &hiob[HIOB];
- long h;
- /*
- * chat("iotrack %d,%d...", dev, addr);
- */
- h = (xf->dev<<24) ^ addr;
- if(h < 0)
- h = ~h;
- h %= HIOB;
- hp = &hiob[h];
- loop:
- /*
- * look for it in the active list
- */
- mlock(&hp->lock);
- for(p=hp->hnext; p != hp; p=p->hnext){
- if(p->addr != addr || p->xf != xf)
- continue;
- unmlock(&hp->lock);
- mlock(&p->lock);
- if(p->addr == addr && p->xf == xf)
- goto out;
- unmlock(&p->lock);
- goto loop;
- }
- unmlock(&hp->lock);
- /*
- * not found
- * take oldest unref'd entry
- */
- mlock(&mp->lock);
- for(p=mp->prev; p != mp; p=p->prev)
- if(p->ref == 0 && canmlock(&p->lock)){
- if(p->ref == 0)
- break;
- unmlock(&p->lock);
- }
- unmlock(&mp->lock);
- if(p == mp){
- print("iotrack all ref'd\n");
- goto loop;
- }
- if(p->flags & BMOD){
- twrite(p);
- p->flags &= ~(BMOD|BIMM);
- unmlock(&p->lock);
- goto loop;
- }
- purgetrack(p);
- p->addr = addr;
- p->xf = xf;
- p->flags = BSTALE;
- out:
- mlock(&hp->lock);
- HTOFRONT(hp, p);
- unmlock(&hp->lock);
- mlock(&mp->lock);
- TOFRONT(mp, p);
- unmlock(&mp->lock);
- return p;
- }
- void
- purgetrack(Iotrack *t)
- {
- int i, ref = Sect2trk;
- Iosect *p;
- for(i=0; i<Sect2trk; i++){
- p = t->tp->p[i];
- if(p == 0){
- --ref;
- continue;
- }
- if(canmlock(&p->lock)){
- freesect(p);
- --ref;
- t->tp->p[i] = 0;
- }
- }
- if(t->ref != ref)
- panic("purgetrack");
- }
- int
- twrite(Iotrack *t)
- {
- int i, ref;
- chat("[twrite %ld...", t->addr);
- if(t->flags & BSTALE){
- for(ref=0,i=0; i<Sect2trk; i++)
- if(t->tp->p[i])
- ++ref;
- if(ref < Sect2trk){
- if(tread(t) < 0){
- chat("error]");
- return -1;
- }
- }else
- t->flags &= ~BSTALE;
- }
- if(devwrite(t->xf, t->addr, t->tp->buf, Trksize) < 0){
- chat("error]");
- return -1;
- }
- chat(" done]");
- return 0;
- }
- int
- tread(Iotrack *t)
- {
- int i, ref = 0;
- uchar buf[Sect2trk][Sectorsize];
- for(i=0; i<Sect2trk; i++)
- if(t->tp->p[i])
- ++ref;
- chat("[tread %ld+%ld...", t->addr, t->xf->offset);
- if(ref == 0){
- if(devread(t->xf, t->addr, t->tp->buf, Trksize) < 0){
- chat("error]");
- return -1;
- }
- chat("done]");
- t->flags &= ~BSTALE;
- return 0;
- }
- if(devread(t->xf, t->addr, buf, Trksize) < 0){
- chat("error]");
- return -1;
- }
- for(i=0; i<Sect2trk; i++)
- if(t->tp->p[i] == 0){
- memmove(t->tp->buf[i], buf[i], Sectorsize);
- chat("%d ", i);
- }
- chat("done]");
- t->flags &= ~BSTALE;
- return 0;
- }
- void
- purgebuf(Xfs *xf)
- {
- Iotrack *p;
- for(p=&iobuf[0]; p<&iobuf[NIOBUF]; p++){
- if(p->xf != xf)
- continue;
- mlock(&p->lock);
- if(p->xf == xf){
- if(p->flags & BMOD)
- twrite(p);
- p->flags = BSTALE;
- purgetrack(p);
- }
- unmlock(&p->lock);
- }
- }
- void
- sync(void)
- {
- Iotrack *p;
- for(p=&iobuf[0]; p<&iobuf[NIOBUF]; p++){
- if(!(p->flags & BMOD))
- continue;
- mlock(&p->lock);
- if(p->flags & BMOD){
- twrite(p);
- p->flags &= ~(BMOD|BIMM);
- }
- unmlock(&p->lock);
- }
- }
- void
- iotrack_init(void)
- {
- Iotrack *mp, *p;
- for (mp=&hiob[0]; mp<&hiob[HIOB]; mp++)
- mp->hprev = mp->hnext = mp;
- mp->prev = mp->next = mp;
- for (p=&iobuf[0]; p<&iobuf[NIOBUF]; p++) {
- p->hprev = p->hnext = p;
- p->prev = p->next = p;
- TOFRONT(mp, p);
- p->tp = sbrk(sizeof(Track));
- memset(p->tp->p, 0, sizeof p->tp->p);
- }
- }
- static MLock freelock;
- static Iosect * freelist;
- Iosect *
- newsect(void)
- {
- Iosect *p;
- mlock(&freelock);
- if(p = freelist) /* assign = */
- freelist = p->next;
- else
- p = malloc(sizeof(Iosect));
- unmlock(&freelock);
- p->next = 0;
- return p;
- }
- void
- freesect(Iosect *p)
- {
- mlock(&freelock);
- p->next = freelist;
- freelist = p;
- unmlock(&freelock);
- }
|