xref: /plan9/sys/src/cmd/dossrv/iotrack.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier #include "iotrack.h"
43e12c5d1SDavid du Colombier #include "dat.h"
53e12c5d1SDavid du Colombier #include "fns.h"
63e12c5d1SDavid du Colombier 
73e12c5d1SDavid du Colombier #define	HIOB		31	/* a prime */
83e12c5d1SDavid du Colombier #define	NIOBUF		80
93e12c5d1SDavid du Colombier 
103e12c5d1SDavid du Colombier static Iotrack	hiob[HIOB+1];		/* hash buckets + lru list */
113e12c5d1SDavid du Colombier static Iotrack	iobuf[NIOBUF];		/* the real ones */
123e12c5d1SDavid du Colombier 
133e12c5d1SDavid du Colombier #define	UNLINK(p, nx, pr)	((p)->pr->nx = (p)->nx, (p)->nx->pr = (p)->pr)
143e12c5d1SDavid du Colombier 
153e12c5d1SDavid du Colombier #define	LINK(h, p, nx, pr)	((p)->nx = (h)->nx, (p)->pr = (h), \
163e12c5d1SDavid du Colombier 				 (h)->nx->pr = (p), (h)->nx = (p))
173e12c5d1SDavid du Colombier 
187dd7cddfSDavid du Colombier #define	HTOFRONT(h, p)	((h)->hnext != (p) && (UNLINK(p,hnext,hprev), LINK(h,p,hnext,hprev)))
193e12c5d1SDavid du Colombier 
207dd7cddfSDavid du Colombier #define	TOFRONT(h, p)	((h)->next  != (p) && (UNLINK(p, next, prev), LINK(h,p, next, prev)))
213e12c5d1SDavid du Colombier 
223e12c5d1SDavid du Colombier Iosect *
getsect(Xfs * xf,long addr)233e12c5d1SDavid du Colombier getsect(Xfs *xf, long addr)
243e12c5d1SDavid du Colombier {
253e12c5d1SDavid du Colombier 	return getiosect(xf, addr, 1);
263e12c5d1SDavid du Colombier }
273e12c5d1SDavid du Colombier 
283e12c5d1SDavid du Colombier Iosect *
getosect(Xfs * xf,long addr)293e12c5d1SDavid du Colombier getosect(Xfs *xf, long addr)
303e12c5d1SDavid du Colombier {
313e12c5d1SDavid du Colombier 	return getiosect(xf, addr, 0);
323e12c5d1SDavid du Colombier }
333e12c5d1SDavid du Colombier 
343e12c5d1SDavid du Colombier Iosect *
getiosect(Xfs * xf,long addr,int rflag)353e12c5d1SDavid du Colombier getiosect(Xfs *xf, long addr, int rflag)
363e12c5d1SDavid du Colombier {
373e12c5d1SDavid du Colombier 	Iotrack *t;
383e12c5d1SDavid du Colombier 	long taddr;
393e12c5d1SDavid du Colombier 	int toff;
403e12c5d1SDavid du Colombier 	Iosect *p;
413e12c5d1SDavid du Colombier 
423e12c5d1SDavid du Colombier 	toff = addr % Sect2trk;
433e12c5d1SDavid du Colombier 	taddr = addr - toff;
443e12c5d1SDavid du Colombier 	t = getiotrack(xf, taddr);
453e12c5d1SDavid du Colombier 	if(rflag && (t->flags&BSTALE)){
463e12c5d1SDavid du Colombier 		if(tread(t) < 0){
477dd7cddfSDavid du Colombier 			unmlock(&t->lock);
483e12c5d1SDavid du Colombier 			return 0;
493e12c5d1SDavid du Colombier 		}
503e12c5d1SDavid du Colombier 		t->flags &= ~BSTALE;
513e12c5d1SDavid du Colombier 	}
523e12c5d1SDavid du Colombier 	t->ref++;
533e12c5d1SDavid du Colombier 	p = t->tp->p[toff];
543e12c5d1SDavid du Colombier 	if(p == 0){
553e12c5d1SDavid du Colombier 		p = newsect();
563e12c5d1SDavid du Colombier 		t->tp->p[toff] = p;
573e12c5d1SDavid du Colombier 		p->flags = t->flags&BSTALE;
583e12c5d1SDavid du Colombier 		p->lock.key = 0;
593e12c5d1SDavid du Colombier 		p->t = t;
603e12c5d1SDavid du Colombier 		p->iobuf = t->tp->buf[toff];
613e12c5d1SDavid du Colombier 	}
627dd7cddfSDavid du Colombier 	unmlock(&t->lock);
637dd7cddfSDavid du Colombier 	mlock(&p->lock);
643e12c5d1SDavid du Colombier 	return p;
653e12c5d1SDavid du Colombier }
663e12c5d1SDavid du Colombier 
673e12c5d1SDavid du Colombier void
putsect(Iosect * p)683e12c5d1SDavid du Colombier putsect(Iosect *p)
693e12c5d1SDavid du Colombier {
703e12c5d1SDavid du Colombier 	Iotrack *t;
713e12c5d1SDavid du Colombier 
727dd7cddfSDavid du Colombier 	if(canmlock(&p->lock))
733e12c5d1SDavid du Colombier 		panic("putsect");
743e12c5d1SDavid du Colombier 	t = p->t;
757dd7cddfSDavid du Colombier 	mlock(&t->lock);
763e12c5d1SDavid du Colombier 	t->flags |= p->flags;
773e12c5d1SDavid du Colombier 	p->flags = 0;
783e12c5d1SDavid du Colombier 	t->ref--;
793e12c5d1SDavid du Colombier 	if(t->flags & BIMM){
803e12c5d1SDavid du Colombier 		if(t->flags & BMOD)
813e12c5d1SDavid du Colombier 			twrite(t);
823e12c5d1SDavid du Colombier 		t->flags &= ~(BMOD|BIMM);
833e12c5d1SDavid du Colombier 	}
847dd7cddfSDavid du Colombier 	unmlock(&t->lock);
857dd7cddfSDavid du Colombier 	unmlock(&p->lock);
863e12c5d1SDavid du Colombier }
873e12c5d1SDavid du Colombier 
883e12c5d1SDavid du Colombier Iotrack *
getiotrack(Xfs * xf,long addr)893e12c5d1SDavid du Colombier getiotrack(Xfs *xf, long addr)
903e12c5d1SDavid du Colombier {
913e12c5d1SDavid du Colombier 	Iotrack *hp, *p;
923e12c5d1SDavid du Colombier 	Iotrack *mp = &hiob[HIOB];
933e12c5d1SDavid du Colombier 	long h;
943e12c5d1SDavid du Colombier /*
953e12c5d1SDavid du Colombier  *	chat("iotrack %d,%d...", dev, addr);
963e12c5d1SDavid du Colombier  */
973e12c5d1SDavid du Colombier 	h = (xf->dev<<24) ^ addr;
983e12c5d1SDavid du Colombier 	if(h < 0)
993e12c5d1SDavid du Colombier 		h = ~h;
1003e12c5d1SDavid du Colombier 	h %= HIOB;
1013e12c5d1SDavid du Colombier 	hp = &hiob[h];
1023e12c5d1SDavid du Colombier 
1033e12c5d1SDavid du Colombier loop:
1043e12c5d1SDavid du Colombier 
1053e12c5d1SDavid du Colombier /*
1063e12c5d1SDavid du Colombier  * look for it in the active list
1073e12c5d1SDavid du Colombier  */
1087dd7cddfSDavid du Colombier 	mlock(&hp->lock);
1093e12c5d1SDavid du Colombier 	for(p=hp->hnext; p != hp; p=p->hnext){
1103e12c5d1SDavid du Colombier 		if(p->addr != addr || p->xf != xf)
1113e12c5d1SDavid du Colombier 			continue;
1127dd7cddfSDavid du Colombier 		unmlock(&hp->lock);
1137dd7cddfSDavid du Colombier 		mlock(&p->lock);
1143e12c5d1SDavid du Colombier 		if(p->addr == addr && p->xf == xf)
1153e12c5d1SDavid du Colombier 			goto out;
1167dd7cddfSDavid du Colombier 		unmlock(&p->lock);
1173e12c5d1SDavid du Colombier 		goto loop;
1183e12c5d1SDavid du Colombier 	}
1197dd7cddfSDavid du Colombier 	unmlock(&hp->lock);
1203e12c5d1SDavid du Colombier /*
1213e12c5d1SDavid du Colombier  * not found
1223e12c5d1SDavid du Colombier  * take oldest unref'd entry
1233e12c5d1SDavid du Colombier  */
1247dd7cddfSDavid du Colombier 	mlock(&mp->lock);
1253e12c5d1SDavid du Colombier 	for(p=mp->prev; p != mp; p=p->prev)
1267dd7cddfSDavid du Colombier 		if(p->ref == 0 && canmlock(&p->lock)){
1273e12c5d1SDavid du Colombier 			if(p->ref == 0)
1283e12c5d1SDavid du Colombier 				break;
1297dd7cddfSDavid du Colombier 			unmlock(&p->lock);
1303e12c5d1SDavid du Colombier 		}
1317dd7cddfSDavid du Colombier 	unmlock(&mp->lock);
1323e12c5d1SDavid du Colombier 	if(p == mp){
1333e12c5d1SDavid du Colombier 		print("iotrack all ref'd\n");
1343e12c5d1SDavid du Colombier 		goto loop;
1353e12c5d1SDavid du Colombier 	}
1363e12c5d1SDavid du Colombier 	if(p->flags & BMOD){
1373e12c5d1SDavid du Colombier 		twrite(p);
1383e12c5d1SDavid du Colombier 		p->flags &= ~(BMOD|BIMM);
1397dd7cddfSDavid du Colombier 		unmlock(&p->lock);
1403e12c5d1SDavid du Colombier 		goto loop;
1413e12c5d1SDavid du Colombier 	}
1423e12c5d1SDavid du Colombier 	purgetrack(p);
1433e12c5d1SDavid du Colombier 	p->addr = addr;
1443e12c5d1SDavid du Colombier 	p->xf = xf;
1453e12c5d1SDavid du Colombier 	p->flags = BSTALE;
1463e12c5d1SDavid du Colombier out:
1477dd7cddfSDavid du Colombier 	mlock(&hp->lock);
1487dd7cddfSDavid du Colombier 	HTOFRONT(hp, p);
1497dd7cddfSDavid du Colombier 	unmlock(&hp->lock);
1507dd7cddfSDavid du Colombier 	mlock(&mp->lock);
1517dd7cddfSDavid du Colombier 	TOFRONT(mp, p);
1527dd7cddfSDavid du Colombier 	unmlock(&mp->lock);
1533e12c5d1SDavid du Colombier 	return p;
1543e12c5d1SDavid du Colombier }
1553e12c5d1SDavid du Colombier 
1563e12c5d1SDavid du Colombier void
purgetrack(Iotrack * t)1573e12c5d1SDavid du Colombier purgetrack(Iotrack *t)
1583e12c5d1SDavid du Colombier {
1593e12c5d1SDavid du Colombier 	int i, ref = Sect2trk;
1603e12c5d1SDavid du Colombier 	Iosect *p;
1613e12c5d1SDavid du Colombier 
1623e12c5d1SDavid du Colombier 	for(i=0; i<Sect2trk; i++){
1633e12c5d1SDavid du Colombier 		p = t->tp->p[i];
1643e12c5d1SDavid du Colombier 		if(p == 0){
1653e12c5d1SDavid du Colombier 			--ref;
1663e12c5d1SDavid du Colombier 			continue;
1673e12c5d1SDavid du Colombier 		}
1687dd7cddfSDavid du Colombier 		if(canmlock(&p->lock)){
1693e12c5d1SDavid du Colombier 			freesect(p);
1703e12c5d1SDavid du Colombier 			--ref;
1713e12c5d1SDavid du Colombier 			t->tp->p[i] = 0;
1723e12c5d1SDavid du Colombier 		}
1733e12c5d1SDavid du Colombier 	}
1743e12c5d1SDavid du Colombier 	if(t->ref != ref)
1753e12c5d1SDavid du Colombier 		panic("purgetrack");
1763e12c5d1SDavid du Colombier }
1773e12c5d1SDavid du Colombier 
1783e12c5d1SDavid du Colombier int
twrite(Iotrack * t)1793e12c5d1SDavid du Colombier twrite(Iotrack *t)
1803e12c5d1SDavid du Colombier {
1813e12c5d1SDavid du Colombier 	int i, ref;
1823e12c5d1SDavid du Colombier 
183*9a747e4fSDavid du Colombier 	chat("[twrite %ld...", t->addr);
1843e12c5d1SDavid du Colombier 	if(t->flags & BSTALE){
1853e12c5d1SDavid du Colombier 		for(ref=0,i=0; i<Sect2trk; i++)
1863e12c5d1SDavid du Colombier 			if(t->tp->p[i])
1873e12c5d1SDavid du Colombier 				++ref;
1883e12c5d1SDavid du Colombier 		if(ref < Sect2trk){
1893e12c5d1SDavid du Colombier 			if(tread(t) < 0){
1903e12c5d1SDavid du Colombier 				chat("error]");
1913e12c5d1SDavid du Colombier 				return -1;
1923e12c5d1SDavid du Colombier 			}
1933e12c5d1SDavid du Colombier 		}else
1943e12c5d1SDavid du Colombier 			t->flags &= ~BSTALE;
1953e12c5d1SDavid du Colombier 	}
1963e12c5d1SDavid du Colombier 	if(devwrite(t->xf, t->addr, t->tp->buf, Trksize) < 0){
1973e12c5d1SDavid du Colombier 		chat("error]");
1983e12c5d1SDavid du Colombier 		return -1;
1993e12c5d1SDavid du Colombier 	}
2003e12c5d1SDavid du Colombier 	chat(" done]");
2013e12c5d1SDavid du Colombier 	return 0;
2023e12c5d1SDavid du Colombier }
2033e12c5d1SDavid du Colombier 
2043e12c5d1SDavid du Colombier int
tread(Iotrack * t)2053e12c5d1SDavid du Colombier tread(Iotrack *t)
2063e12c5d1SDavid du Colombier {
2073e12c5d1SDavid du Colombier 	int i, ref = 0;
2083e12c5d1SDavid du Colombier 	uchar buf[Sect2trk][Sectorsize];
2093e12c5d1SDavid du Colombier 
2103e12c5d1SDavid du Colombier 	for(i=0; i<Sect2trk; i++)
2113e12c5d1SDavid du Colombier 		if(t->tp->p[i])
2123e12c5d1SDavid du Colombier 			++ref;
213*9a747e4fSDavid du Colombier 	chat("[tread %ld+%ld...", t->addr, t->xf->offset);
2143e12c5d1SDavid du Colombier 	if(ref == 0){
2153e12c5d1SDavid du Colombier 		if(devread(t->xf, t->addr, t->tp->buf, Trksize) < 0){
2163e12c5d1SDavid du Colombier 			chat("error]");
2173e12c5d1SDavid du Colombier 			return -1;
2183e12c5d1SDavid du Colombier 		}
2193e12c5d1SDavid du Colombier 		chat("done]");
2203e12c5d1SDavid du Colombier 		t->flags &= ~BSTALE;
2213e12c5d1SDavid du Colombier 		return 0;
2223e12c5d1SDavid du Colombier 	}
2233e12c5d1SDavid du Colombier 	if(devread(t->xf, t->addr, buf, Trksize) < 0){
2243e12c5d1SDavid du Colombier 		chat("error]");
2253e12c5d1SDavid du Colombier 		return -1;
2263e12c5d1SDavid du Colombier 	}
2273e12c5d1SDavid du Colombier 	for(i=0; i<Sect2trk; i++)
2283e12c5d1SDavid du Colombier 		if(t->tp->p[i] == 0){
2293e12c5d1SDavid du Colombier 			memmove(t->tp->buf[i], buf[i], Sectorsize);
2303e12c5d1SDavid du Colombier 			chat("%d ", i);
2313e12c5d1SDavid du Colombier 		}
2323e12c5d1SDavid du Colombier 	chat("done]");
2333e12c5d1SDavid du Colombier 	t->flags &= ~BSTALE;
2343e12c5d1SDavid du Colombier 	return 0;
2353e12c5d1SDavid du Colombier }
2363e12c5d1SDavid du Colombier 
2373e12c5d1SDavid du Colombier void
purgebuf(Xfs * xf)2383e12c5d1SDavid du Colombier purgebuf(Xfs *xf)
2393e12c5d1SDavid du Colombier {
2403e12c5d1SDavid du Colombier 	Iotrack *p;
2413e12c5d1SDavid du Colombier 
2423e12c5d1SDavid du Colombier 	for(p=&iobuf[0]; p<&iobuf[NIOBUF]; p++){
2433e12c5d1SDavid du Colombier 		if(p->xf != xf)
2443e12c5d1SDavid du Colombier 			continue;
2457dd7cddfSDavid du Colombier 		mlock(&p->lock);
2463e12c5d1SDavid du Colombier 		if(p->xf == xf){
2473e12c5d1SDavid du Colombier 			if(p->flags & BMOD)
2483e12c5d1SDavid du Colombier 				twrite(p);
2493e12c5d1SDavid du Colombier 			p->flags = BSTALE;
2503e12c5d1SDavid du Colombier 			purgetrack(p);
2513e12c5d1SDavid du Colombier 		}
2527dd7cddfSDavid du Colombier 		unmlock(&p->lock);
2533e12c5d1SDavid du Colombier 	}
2543e12c5d1SDavid du Colombier }
2553e12c5d1SDavid du Colombier 
2563e12c5d1SDavid du Colombier void
sync(void)2573e12c5d1SDavid du Colombier sync(void)
2583e12c5d1SDavid du Colombier {
2593e12c5d1SDavid du Colombier 	Iotrack *p;
2603e12c5d1SDavid du Colombier 
2613e12c5d1SDavid du Colombier 	for(p=&iobuf[0]; p<&iobuf[NIOBUF]; p++){
2623e12c5d1SDavid du Colombier 		if(!(p->flags & BMOD))
2633e12c5d1SDavid du Colombier 			continue;
2647dd7cddfSDavid du Colombier 		mlock(&p->lock);
2653e12c5d1SDavid du Colombier 		if(p->flags & BMOD){
2663e12c5d1SDavid du Colombier 			twrite(p);
2673e12c5d1SDavid du Colombier 			p->flags &= ~(BMOD|BIMM);
2683e12c5d1SDavid du Colombier 		}
2697dd7cddfSDavid du Colombier 		unmlock(&p->lock);
2703e12c5d1SDavid du Colombier 	}
2713e12c5d1SDavid du Colombier }
2723e12c5d1SDavid du Colombier 
2733e12c5d1SDavid du Colombier void
iotrack_init(void)2743e12c5d1SDavid du Colombier iotrack_init(void)
2753e12c5d1SDavid du Colombier {
2763e12c5d1SDavid du Colombier 	Iotrack *mp, *p;
2773e12c5d1SDavid du Colombier 
2783e12c5d1SDavid du Colombier 	for (mp=&hiob[0]; mp<&hiob[HIOB]; mp++)
2793e12c5d1SDavid du Colombier 		mp->hprev = mp->hnext = mp;
2803e12c5d1SDavid du Colombier 	mp->prev = mp->next = mp;
2813e12c5d1SDavid du Colombier 
2823e12c5d1SDavid du Colombier 	for (p=&iobuf[0]; p<&iobuf[NIOBUF]; p++) {
2833e12c5d1SDavid du Colombier 		p->hprev = p->hnext = p;
2843e12c5d1SDavid du Colombier 		p->prev = p->next = p;
2853e12c5d1SDavid du Colombier 		TOFRONT(mp, p);
286219b2ee8SDavid du Colombier 		p->tp = sbrk(sizeof(Track));
2873e12c5d1SDavid du Colombier 		memset(p->tp->p, 0, sizeof p->tp->p);
2883e12c5d1SDavid du Colombier 	}
2893e12c5d1SDavid du Colombier }
2903e12c5d1SDavid du Colombier 
2917dd7cddfSDavid du Colombier static MLock	freelock;
2923e12c5d1SDavid du Colombier static Iosect *	freelist;
2933e12c5d1SDavid du Colombier 
2943e12c5d1SDavid du Colombier Iosect *
newsect(void)2953e12c5d1SDavid du Colombier newsect(void)
2963e12c5d1SDavid du Colombier {
2973e12c5d1SDavid du Colombier 	Iosect *p;
2983e12c5d1SDavid du Colombier 
2997dd7cddfSDavid du Colombier 	mlock(&freelock);
3003e12c5d1SDavid du Colombier 	if(p = freelist)	/* assign = */
3013e12c5d1SDavid du Colombier 		freelist = p->next;
3023e12c5d1SDavid du Colombier 	else
3033e12c5d1SDavid du Colombier 		p = malloc(sizeof(Iosect));
3047dd7cddfSDavid du Colombier 	unmlock(&freelock);
3053e12c5d1SDavid du Colombier 	p->next = 0;
3063e12c5d1SDavid du Colombier 	return p;
3073e12c5d1SDavid du Colombier }
3083e12c5d1SDavid du Colombier 
3093e12c5d1SDavid du Colombier void
freesect(Iosect * p)3103e12c5d1SDavid du Colombier freesect(Iosect *p)
3113e12c5d1SDavid du Colombier {
3127dd7cddfSDavid du Colombier 	mlock(&freelock);
3133e12c5d1SDavid du Colombier 	p->next = freelist;
3143e12c5d1SDavid du Colombier 	freelist = p;
3157dd7cddfSDavid du Colombier 	unmlock(&freelock);
3163e12c5d1SDavid du Colombier }
317