326 lines
5.5 KiB
C
326 lines
5.5 KiB
C
/*
|
|
* This file is part of the UCB release of Plan 9. It is subject to the license
|
|
* terms in the LICENSE file found in the top-level directory of this
|
|
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
|
* part of the UCB release of Plan 9, including this file, may be copied,
|
|
* modified, propagated, or distributed except according to the terms contained
|
|
* in the LICENSE file.
|
|
*/
|
|
|
|
#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) if((h)->hnext != (p)) { UNLINK(p,hnext,hprev); LINK(h,p,hnext,hprev); }
|
|
|
|
#define TOFRONT(h, p) if((h)->next != (p)) { UNLINK(p, next, prev); LINK(h,p, next, prev); }
|
|
|
|
Iosect *
|
|
getsect(Xfs *xf, int32_t addr)
|
|
{
|
|
return getiosect(xf, addr, 1);
|
|
}
|
|
|
|
Iosect *
|
|
getosect(Xfs *xf, int32_t addr)
|
|
{
|
|
return getiosect(xf, addr, 0);
|
|
}
|
|
|
|
Iosect *
|
|
getiosect(Xfs *xf, int32_t addr, int rflag)
|
|
{
|
|
Iotrack *t;
|
|
int32_t 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, int32_t addr)
|
|
{
|
|
Iotrack *hp, *p;
|
|
Iotrack *mp = &hiob[HIOB];
|
|
int32_t 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){
|
|
jehanne_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;
|
|
uint8_t 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){
|
|
jehanne_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));
|
|
jehanne_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 = jehanne_malloc(sizeof(Iosect));
|
|
unmlock(&freelock);
|
|
p->next = 0;
|
|
return p;
|
|
}
|
|
|
|
void
|
|
freesect(Iosect *p)
|
|
{
|
|
mlock(&freelock);
|
|
p->next = freelist;
|
|
freelist = p;
|
|
unmlock(&freelock);
|
|
}
|