2011-03-30 12:46:40 +00:00
|
|
|
#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 *
|
2018-12-22 19:49:24 +00:00
|
|
|
getsect(Xfs *xf, vlong addr)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
|
|
|
return getiosect(xf, addr, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
Iosect *
|
2018-12-22 19:49:24 +00:00
|
|
|
getosect(Xfs *xf, vlong addr)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
|
|
|
return getiosect(xf, addr, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
Iosect *
|
2018-12-22 19:49:24 +00:00
|
|
|
getiosect(Xfs *xf, vlong addr, int rflag)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
|
|
|
Iotrack *t;
|
2018-12-22 19:49:24 +00:00
|
|
|
vlong taddr;
|
2011-03-30 12:46:40 +00:00
|
|
|
int toff;
|
|
|
|
Iosect *p;
|
|
|
|
|
2020-04-25 17:57:17 +00:00
|
|
|
if(addr < 0)
|
2018-12-24 00:21:47 +00:00
|
|
|
return nil;
|
2011-03-30 12:46:40 +00:00
|
|
|
toff = addr % Sect2trk;
|
|
|
|
taddr = addr - toff;
|
|
|
|
t = getiotrack(xf, taddr);
|
|
|
|
if(rflag && (t->flags&BSTALE)){
|
|
|
|
if(tread(t) < 0){
|
|
|
|
unmlock(&t->lock);
|
2018-12-24 00:21:47 +00:00
|
|
|
return nil;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
t->flags &= ~BSTALE;
|
|
|
|
}
|
|
|
|
t->ref++;
|
|
|
|
p = t->tp->p[toff];
|
2020-04-25 17:57:17 +00:00
|
|
|
if(p == 0){
|
2011-03-30 12:46:40 +00:00
|
|
|
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 *
|
2018-12-22 19:49:24 +00:00
|
|
|
getiotrack(Xfs *xf, vlong addr)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
|
|
|
Iotrack *hp, *p;
|
|
|
|
Iotrack *mp = &hiob[HIOB];
|
|
|
|
long h;
|
|
|
|
/*
|
|
|
|
* chat("iotrack %d,%d...", dev, addr);
|
|
|
|
*/
|
2018-12-22 19:49:24 +00:00
|
|
|
h = (xf->dev<<24) ^ (long)addr;
|
2011-03-30 12:46:40 +00:00
|
|
|
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){
|
2020-03-07 13:23:34 +00:00
|
|
|
fprint(2, "iotrack all ref'd\n");
|
2011-03-30 12:46:40 +00:00
|
|
|
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;
|
|
|
|
|
2018-12-22 19:49:24 +00:00
|
|
|
chat("[twrite %lld...", t->addr);
|
2011-03-30 12:46:40 +00:00
|
|
|
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){
|
2020-04-25 17:57:17 +00:00
|
|
|
chat("error]");
|
2011-03-30 12:46:40 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2020-04-25 17:57:17 +00:00
|
|
|
chat(" done]");
|
2011-03-30 12:46:40 +00:00
|
|
|
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;
|
2018-12-22 19:49:24 +00:00
|
|
|
chat("[tread %lld+%lld...", t->addr, t->xf->offset);
|
2011-03-30 12:46:40 +00:00
|
|
|
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);
|
|
|
|
}
|