shithub: riscv

Download patch

ref: d24b5a7a0e45186f13d19ddefde62b0932726e42
parent: 101b3c2724779fcb0e503ae274abd7b751a3a48f
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Apr 30 14:44:29 EDT 2023

dossrv: Implement support for != 512 sector and track sizes

The iotrack buffer layer always assumed 512 byte sector
size and 9 sectors per track.

To support 4K sector size fats, make the iotrack code
deal with it.

Instead of the fixed size Track structure, we just allocate
the pointers and buffers dynamically, and move the sector
size and tack size in the Xfs structure.

Tracks can still be reused between differnet file-systems
after a purgetrack().

The initial fat header has to be read with devread()
instead of getsect() to determine the sector/track size
of the file-system.

--- a/sys/src/cmd/dossrv/dat.h
+++ b/sys/src/cmd/dossrv/dat.h
@@ -118,7 +118,6 @@
  */
 struct Dosbpb{
 	MLock;				/* access to fat */
-	int	sectsize;		/* in bytes */
 	int	clustsize;		/* in sectors */
 	int	nresrv;			/* sectors */
 	int	nfats;			/* usually 2; modified to 1 if fat mirroring disabled */
@@ -190,7 +189,7 @@
 	Dosdir *d;
 };
 
-#define	QIDPATH(p)	((p)->addr*(Sectorsize/DOSDIRSIZE) + \
+#define	QIDPATH(p, xf)	((p)->addr*((xf)->sectsize/DOSDIRSIZE) + \
 			 (p)->offset/DOSDIRSIZE)
 
 struct Xfs{
@@ -203,6 +202,8 @@
 	uchar	isfat32;	/* is a fat 32 file system? */
 	short	dev;
 	short	fmt;
+	int	sectsize;
+	int	sect2trk;
 	vlong	offset;
 	void	*ptr;
 };
--- a/sys/src/cmd/dossrv/devio.c
+++ b/sys/src/cmd/dossrv/devio.c
@@ -7,7 +7,7 @@
 int readonly;
 
 static int
-deverror(char *name, Xfs *xf, long addr, long n, long nret)
+deverror(char *name, Xfs *xf, vlong addr, long n, long nret)
 {
 	errno = Eio;
 	if(nret < 0){
@@ -16,7 +16,7 @@
 		xf->dev = -1;
 		return -1;
 	}
-	fprint(2, "dev %d sector %ld, %s: %ld, should be %ld\n", xf->dev, addr, name, nret, n);
+	fprint(2, "dev %d sector %lld, %s: %ld, should be %ld\n", xf->dev, addr, name, nret, n);
 	return -1;
 }
 
@@ -27,7 +27,7 @@
 
 	if(xf->dev < 0)
 		return -1;
-	nread = pread(xf->dev, buf, n, xf->offset+addr*Sectorsize);
+	nread = pread(xf->dev, buf, n, xf->offset+addr*xf->sectsize);
 	if (nread == n)
 		return 0;
 	return deverror("read", xf, addr, n, nread);
@@ -43,23 +43,8 @@
 
 	if(xf->dev < 0)
 		return -1;
-	nwrite = pwrite(xf->dev, buf, n, xf->offset+addr*Sectorsize);
+	nwrite = pwrite(xf->dev, buf, n, xf->offset+addr*xf->sectsize);
 	if (nwrite == n)
 		return 0;
 	return deverror("write", xf, addr, n, nwrite);
-}
-
-int
-devcheck(Xfs *xf)
-{
-	char buf[Sectorsize];
-
-	if(xf->dev < 0)
-		return -1;
-	if(pread(xf->dev, buf, Sectorsize, 0) != Sectorsize){
-		close(xf->dev);
-		xf->dev = -1;
-		return -1;
-	}
-	return 0;
 }
--- a/sys/src/cmd/dossrv/dosfs.c
+++ b/sys/src/cmd/dossrv/dosfs.c
@@ -138,7 +138,7 @@
 				if(isroot(dp->addr))
 					f->qid.path = f->xf->rootqid.path;
 				else
-					f->qid.path = QIDPATH(dp);
+					f->qid.path = QIDPATH(dp, f->xf);
 			}
 		}else{
 			fixname(req->wname[rep->nwqid]);
@@ -155,7 +155,7 @@
 			if(r < 0)
 				goto error;
 			memmove(f->ptr, dp, sizeof(Dosptr));
-			f->qid.path = QIDPATH(dp);
+			f->qid.path = QIDPATH(dp, f->xf);
 			f->qid.type = QTFILE;
 			if(isroot(dp->addr))
 				f->qid.path = f->xf->rootqid.path;
@@ -457,7 +457,7 @@
 	 */
 	f->ptr = ndp;
 	f->qid.type = QTFILE;
-	f->qid.path = QIDPATH(ndp);
+	f->qid.path = QIDPATH(ndp, f->xf);
 
 //ZZZ set type for excl, append?
 	if(req->perm & DMDIR){
@@ -567,7 +567,7 @@
 	}
 	if(prevdo < 0 && dp->prevaddr != -1){
 		p = getsect(xf, dp->prevaddr);
-		for(prevdo = ((Dosbpb*)xf->ptr)->sectsize-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
+		for(prevdo = xf->sectsize-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
 			if(p->iobuf[prevdo+11] != 0xf)
 				break;
 			p->iobuf[prevdo] = DOSEMPTY;
@@ -636,17 +636,17 @@
 static int
 dostat(Xfile *f, Dir *d)
 {
-	Dosptr *dp;
+	Xfs *xf = f->xf;
+	Dosptr *dp = f->ptr;
 	Iosect *p;
 	char *name, namebuf[DOSNAMELEN];
 	int islong, sum, prevdo;
 
-	dp = f->ptr;
 	if(isroot(dp->addr)){
 		memset(d, 0, sizeof(Dir));
 		d->name = "/";
 		d->qid.type = QTDIR;
-		d->qid.path = f->xf->rootqid.path;
+		d->qid.path = xf->rootqid.path;
 		d->mode = DMDIR|0777;
 		d->uid = "bill";
 		d->muid = "bill";
@@ -664,10 +664,10 @@
 			name = getnamesect(namebuf, name, &dp->p->iobuf[prevdo], &islong, &sum, -1);
 		}
 		if(prevdo < 0 && dp->prevaddr != -1){
-			p = getsect(f->xf, dp->prevaddr);
+			p = getsect(xf, dp->prevaddr);
 			if(p == nil)
 				return -1;
-			for(prevdo = ((Dosbpb*)f->xf->ptr)->sectsize-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
+			for(prevdo = xf->sectsize-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
 				if(p->iobuf[prevdo+11] != 0xf)
 					break;
 				name = getnamesect(namebuf, name, &p->iobuf[prevdo], &islong, &sum, -1);
@@ -674,7 +674,7 @@
 			}
 			putsect(p);
 		}
-		getdir(f->xf, d, dp->d, dp->addr, dp->offset);
+		getdir(xf, d, dp->d, dp->addr, dp->offset);
 		if(islong && sum == -1 && nameok(namebuf))
 			strcpy(d->name, namebuf);
 	}
@@ -894,7 +894,7 @@
 		/*
 		 * relocate up other fids to the same file, if it moved
 		 */
-		f->qid.path = QIDPATH(dp);
+		f->qid.path = QIDPATH(dp, pf.xf);
 		if(oaddr != dp->addr || ooffset != dp->offset)
 			dosptrreloc(f, dp, oaddr, ooffset);
 
--- a/sys/src/cmd/dossrv/dossubs.c
+++ b/sys/src/cmd/dossrv/dossubs.c
@@ -39,9 +39,10 @@
 int
 dosfs(Xfs *xf)
 {
-	Iosect *p, *p1;
-	Dosboot *b;
+	Iosect *p1;
 	Fatinfo *fi;
+	uchar	buf[512];
+	Dosboot *b;
 	Dosboot32 *b32;
 	Dosbpb *bp;
 	long fisec, extflags;
@@ -72,22 +73,28 @@
 		isdos['&'] = 1;
 	}
 
-	p = getsect(xf, 0);
-	if(p == nil)
+	/* don't use getsect() before we we determinted real values */
+	xf->sectsize = 512;
+	xf->sect2trk = 9;
+	devread(xf, 0, buf, sizeof(buf));
+
+	if(!isdosfs(buf))
 		return -1;
 
-	b = (Dosboot*)p->iobuf;
-	if(b->clustsize == 0 || isdosfs(p->iobuf) == 0){
-		putsect(p);
+	b = (Dosboot*)buf;
+
+	xf->sectsize = GSHORT(b->sectsize);
+	if(xf->sectsize < 32)
 		return -1;
-	}
 
+	xf->sect2trk = GSHORT(b->trksize);
+	if(xf->sect2trk < 1)
+		return -1;
+
 	bp = malloc(sizeof(Dosbpb));
 	memset(bp, 0, sizeof(Dosbpb));	/* clear lock */
 	xf->ptr = bp;
 	xf->fmt = 1;
-
-	bp->sectsize = GSHORT(b->sectsize);
 	bp->clustsize = b->clustsize;
 	bp->nresrv = GSHORT(b->nresrv);
 	bp->nfats = b->nfats;
@@ -102,13 +109,12 @@
 	bp->fatinfo = 0;
 
 	if(bp->fatsize == 0){	/* is FAT32 */
+		b32 = (Dosboot32*)buf;
 		if(chatty)
-			bootsecdump32(2, xf, (Dosboot32*)b);
+			bootsecdump32(2, xf, b32);
 		xf->isfat32 = 1;
-		b32 = (Dosboot32*)b;
 		bp->fatsize = GLONG(b32->fatsize32);
 		if(bp->fatsize == 0){
-			putsect(p);
 			if(chatty)
 				fprint(2, "fatsize 0\n");
 			return -1;
@@ -155,7 +161,7 @@
 			bootdump(2, b);
 		bp->rootaddr = bp->fataddr + bp->nfats*bp->fatsize;
 		bp->rootstart = 0;
-		bp->dataaddr = bp->rootaddr + (bp->rootsize*DOSDIRSIZE + bp->sectsize-1)/bp->sectsize;
+		bp->dataaddr = bp->rootaddr + (bp->rootsize*DOSDIRSIZE + xf->sectsize-1)/xf->sectsize;
 		bp->freeptr = FATRESRV;
 	}
 	bp->fatclusters = FATRESRV + (bp->volsize - bp->dataaddr)/bp->clustsize;
@@ -172,7 +178,6 @@
 		chat("fat %d: %lld...", i, bp->fataddr+i*bp->fatsize);
 	chat("root: %lld...", bp->rootaddr);
 	chat("data: %lld...", bp->dataaddr);
-	putsect(p);
 	return 0;
 }
 
@@ -215,8 +220,8 @@
 	 */
 	dp->d = nil;
 	if(!isroot(dp->addr)){
-		if(f->qid.path != QIDPATH(dp)){
-			chat("qid mismatch f=%#llux d=%#llux...", f->qid.path, QIDPATH(dp));
+		if(f->qid.path != QIDPATH(dp, f->xf)){
+			chat("qid mismatch f=%#llux d=%#llux...", f->qid.path, QIDPATH(dp, f->xf));
 			putsect(p);
 			errno = Enonexist;
 			return -1;
@@ -265,33 +270,29 @@
 long
 fileclust(Xfile *f, long iclust, int cflag)
 {
-	Dosbpb *bp;
-	Dosptr *dp;
-	Dosdir *d;
-	long start, clust, nskip, next;
+	Xfs *xf = f->xf;
+	Dosbpb *bp = xf->ptr;
+	Dosptr *dp = f->ptr;
+	Dosdir *d = dp->d;
+	long start, clust, nskip, next = 0;
 
-	bp = f->xf->ptr;
-	dp = f->ptr;
-	d = dp->d;
-	next = 0;
-
 	/* 
 	 * asking for the cluster of the root directory
 	 * is not a well-formed question, since the root directory
 	 * does not begin on a cluster boundary.
 	 */
-	if(!f->xf->isfat32 && isroot(dp->addr))
+	if(!xf->isfat32 && isroot(dp->addr))
 		return -1;
 
-	if(f->xf->isfat32 && isroot(dp->addr)){
+	if(xf->isfat32 && isroot(dp->addr)){
 		start = bp->rootstart;
 	}else{
-		start = getstart(f->xf, d);
+		start = getstart(xf, d);
 		if(start == 0){
 			if(!cflag)
 				return -1;
 			mlock(bp);
-			start = falloc(f->xf);
+			start = falloc(xf);
 			unmlock(bp);
 			if(start <= 0)
 				return -1;
@@ -315,7 +316,7 @@
 	if(nskip > 0){
 		mlock(bp);
 		while(--nskip >= 0){
-			next = getfat(f->xf, clust);
+			next = getfat(xf, clust);
 			if(chatty > 1)
 				chat("->%#lx", next);
 			if(next > 0){
@@ -329,10 +330,10 @@
 					break;
 				/* cfalloc will call putfat for us, since clust may change */
 			} else {
-				next = falloc(f->xf);
+				next = falloc(xf);
 				if(next < 0)
 					break;
-				putfat(f->xf, clust, next);
+				putfat(xf, clust, next);
 			}
 			clust = next;
 		}
@@ -353,14 +354,15 @@
 vlong
 fileaddr(Xfile *f, long isect, int cflag)
 {
+	Xfs *xf = f->xf;
 	Dosbpb *bp;
 	Dosptr *dp;
 	long clust;
 
-	bp = f->xf->ptr;
+	bp = xf->ptr;
 	dp = f->ptr;
 	if(!f->xf->isfat32 && isroot(dp->addr)){
-		if(isect*bp->sectsize >= bp->rootsize*DOSDIRSIZE)
+		if(isect*xf->sectsize >= bp->rootsize*DOSDIRSIZE)
 			return -1;
 		return bp->rootaddr + isect;
 	}
@@ -512,7 +514,6 @@
 {
 	Xfs *xf;
 	Iosect *p;
-	Dosbpb *bp;
 	Dosdir *d;
 	char buf[261], *bname;
 	int isect, o, o1, islong, have, need, sum;
@@ -519,7 +520,6 @@
 	vlong addr, addr1, addr2, prevaddr, prevaddr1;
 
 	xf = f->xf;
-	bp = xf->ptr;
 	addr1 = -1;
 	addr2 = -1;
 	prevaddr1 = -1;
@@ -548,7 +548,7 @@
 		p = getsect(xf, addr);
 		if(p == nil)
 			break;
-		for(o=0; o<bp->sectsize; o+=DOSDIRSIZE){
+		for(o=0; o<xf->sectsize; o+=DOSDIRSIZE){
 			d = (Dosdir *)&p->iobuf[o];
 			if(d->name[0] == 0x00){
 				chat("end dir(0)...");
@@ -569,7 +569,7 @@
 					prevaddr1 = prevaddr;
 					o1 = o;
 				}
-				if(addr2 < 0 && (bp->sectsize-o)/DOSDIRSIZE + have < need){
+				if(addr2 < 0 && (xf->sectsize-o)/DOSDIRSIZE + have < need){
 					addr2 = fileaddr(f, isect+1, cflag);
 					if(addr2 < 0)
 						goto breakout;
@@ -641,7 +641,6 @@
 emptydir(Xfile *f)
 {
 	Xfs *xf = f->xf;
-	Dosbpb *bp = xf->ptr;
 	int isect, o;
 	vlong addr;
 	Iosect *p;
@@ -654,7 +653,7 @@
 		p = getsect(xf, addr);
 		if(p == nil)
 			return -1;
-		for(o=0; o<bp->sectsize; o+=DOSDIRSIZE){
+		for(o=0; o<xf->sectsize; o+=DOSDIRSIZE){
 			d = (Dosdir *)&p->iobuf[o];
 			if(d->name[0] == 0x00){
 				putsect(p);
@@ -678,7 +677,6 @@
 readdir(Xfile *f, void *vbuf, vlong offset, long count)
 {
 	Xfs *xf;
-	Dosbpb *bp;
 	Dir dir;
 	int isect, o, islong, sum;
 	vlong addr;
@@ -691,7 +689,6 @@
 	buf = vbuf;
 	rcnt = 0;
 	xf = f->xf;
-	bp = xf->ptr;
 	if(count <= 0)
 		return 0;
 	islong = 0;
@@ -704,7 +701,7 @@
 		p = getsect(xf, addr);
 		if(p == nil)
 			return -1;
-		for(o=0; o<bp->sectsize; o+=DOSDIRSIZE){
+		for(o=0; o<xf->sectsize; o+=DOSDIRSIZE){
 			d = (Dosdir *)&p->iobuf[o];
 			if(d->name[0] == 0x00){
 				putsect(p);
@@ -763,15 +760,14 @@
 int
 walkup(Xfile *f, Dosptr *ndp)
 {
-	Dosbpb *bp;
-	Dosptr *dp;
+	Xfs *xf = f->xf;
+	Dosbpb *bp = xf->ptr;
+	Dosptr *dp = f->ptr;
 	Dosdir *xd;
 	Iosect *p;
 	long o, so, start, pstart, ppstart, st, ppclust;
 	vlong k;
 
-	bp = f->xf->ptr;
-	dp = f->ptr;
 	memset(ndp, 0, sizeof(Dosptr));
 	ndp->prevaddr = -1;
 	ndp->naddr = -1;
@@ -789,12 +785,12 @@
 	/*
 	 * find the start of our parent's directory
 	 */
-	p = getsect(f->xf, dp->paddr);
+	p = getsect(xf, dp->paddr);
 	if(p == nil)
 		goto error;
 	xd = (Dosdir *)&p->iobuf[dp->poffset];
 	dirdump(xd);
-	start = getstart(f->xf, xd);
+	start = getstart(xf, xd);
 	chat("start=%#lx...", start);
 	if(start == 0)
 		goto error;
@@ -808,7 +804,7 @@
 		goto error;
 	xd = (Dosdir *)p->iobuf;
 	dirdump(xd);
-	st = getstart(f->xf, xd);
+	st = getstart(xf, xd);
 	if(xd->name[0]!='.' || xd->name[1]!=' ' || start!=st)
 		goto error;
 
@@ -819,19 +815,19 @@
 	dirdump(xd);
 	if(xd->name[0] != '.' || xd->name[1] != '.')
 		goto error;
-	pstart = getstart(f->xf, xd);
+	pstart = getstart(xf, xd);
 	putsect(p);
 
 	/*
 	 * we're done if parent is root
 	 */
-	if(pstart == 0 || f->xf->isfat32 && pstart == bp->rootstart)
+	if(pstart == 0 || xf->isfat32 && pstart == bp->rootstart)
 		return 0;
 
 	/*
 	 * verify that parent's . points to itself
 	 */
-	p = getsect(f->xf, clust2sect(bp, pstart));
+	p = getsect(xf, clust2sect(bp, pstart));
 	if(p == nil){
 		chat("getsect %ld failed\n", pstart);
 		goto error;
@@ -838,7 +834,7 @@
 	}
 	xd = (Dosdir *)p->iobuf;
 	dirdump(xd);
-	st = getstart(f->xf, xd);
+	st = getstart(xf, xd);
 	if(xd->name[0]!='.' || xd->name[1]!=' ' || pstart!=st)
 		goto error;
 
@@ -849,7 +845,7 @@
 	dirdump(xd);
 	if(xd->name[0] != '.' || xd->name[1] != '.')
 		goto error;
-	ppstart = getstart(f->xf, xd);
+	ppstart = getstart(xf, xd);
 	putsect(p);
 
 	/*
@@ -857,12 +853,12 @@
 	 * need this to find parent's parent's addr and offset
 	 */
 	ppclust = ppstart;
-	if(f->xf->isfat32 && ppclust == 0){
+	if(xf->isfat32 && ppclust == 0){
 		ppclust = bp->rootstart;
 		chat("ppclust 0, resetting to rootstart\n");
 	}
 	k = ppclust ? clust2sect(bp, ppclust) : bp->rootaddr;
-	p = getsect(f->xf, k);
+	p = getsect(xf, k);
 	if(p == nil){
 		chat("getsect %lld failed\n", k);
 		goto error;
@@ -870,12 +866,12 @@
 	xd = (Dosdir *)p->iobuf;
 	dirdump(xd);
 	if(ppstart){
-		st = getstart(f->xf, xd);
+		st = getstart(xf, xd);
 		if(xd->name[0]!='.' || xd->name[1]!=' ' || ppstart!=st)
 			goto error;
 	}
 	for(so=1;; so++){
-		for(o=0; o<bp->sectsize; o+=DOSDIRSIZE){
+		for(o=0; o<xf->sectsize; o+=DOSDIRSIZE){
 			xd = (Dosdir *)&p->iobuf[o];
 			if(xd->name[0] == 0x00){
 				chat("end dir\n");
@@ -883,7 +879,7 @@
 			}
 			if(xd->name[0] == DOSEMPTY)
 				continue;
-			st = getstart(f->xf, xd);
+			st = getstart(xf, xd);
 			if(st == pstart)
 				goto out;
 		}
@@ -890,7 +886,7 @@
 		if(ppclust){
 			if(so%bp->clustsize == 0){
 				mlock(bp);
-				ppclust = getfat(f->xf, ppclust);
+				ppclust = getfat(xf, ppclust);
 				unmlock(bp);
 				if(ppclust < 0){
 					chat("getfat %ld failed\n", ppclust);
@@ -899,12 +895,12 @@
 			}
 			k = clust2sect(bp, ppclust) + so%bp->clustsize;
 		}else{
-			if(so*bp->sectsize >= bp->rootsize*DOSDIRSIZE)
+			if(so*xf->sectsize >= bp->rootsize*DOSDIRSIZE)
 				goto error;
 			k = bp->rootaddr + so;
 		}
 		putsect(p);
-		p = getsect(f->xf, k);
+		p = getsect(xf, k);
 		if(p == nil){
 			chat("getsect %lld failed\n", k);
 			goto error;
@@ -926,7 +922,6 @@
 readfile(Xfile *f, void *vbuf, vlong offset, long count)
 {
 	Xfs *xf = f->xf;
-	Dosbpb *bp = xf->ptr;
 	Dosptr *dp = f->ptr;
 	Dosdir *d = dp->d;
 	int isect, o, c;
@@ -947,13 +942,13 @@
 		return 0;
 	if(offset+count >= length)
 		count = length - offset;
-	isect = offset/bp->sectsize;
-	o = offset%bp->sectsize;
+	isect = offset/xf->sectsize;
+	o = offset%xf->sectsize;
 	while(count > 0){
 		addr = fileaddr(f, isect++, 0);
 		if(addr < 0)
 			break;
-		c = bp->sectsize - o;
+		c = xf->sectsize - o;
 		if(c > count)
 			c = count;
 		p = getsect(xf, addr);
@@ -989,16 +984,16 @@
 	rcnt = 0;
 	addr = 0;
 	buf = vbuf;
-	isect = offset/bp->sectsize;
-	o = offset%bp->sectsize;
+	isect = offset/xf->sectsize;
+	o = offset%xf->sectsize;
 	while(count > 0){
 		addr = fileaddr(f, isect++, 1);
 		if(addr < 0)
 			break;
-		c = bp->sectsize - o;
+		c = xf->sectsize - o;
 		if(c > count)
 			c = count;
-		if(c == bp->sectsize){
+		if(c == xf->sectsize){
 			p = getosect(xf, addr);
 			p->flags = 0;
 		}else{
@@ -1020,7 +1015,7 @@
 	if(rcnt > 0)
 		length = offset+rcnt;
 	else if(dp->addr && dp->clust){
-		c = bp->clustsize*bp->sectsize;
+		c = bp->clustsize*xf->sectsize;
 		if(dp->iclust > (dlen+c-1)/c)
 			length = (ulong)c*dp->iclust;
 	}
@@ -1045,18 +1040,18 @@
 		return -1;
 
 	mlock(bp);
-	clust = getstart(f->xf, d);
+	clust = getstart(xf, d);
 	n = length;
 	if(n <= 0)
-		putstart(f->xf, d, 0);
+		putstart(xf, d, 0);
 	else
-		n -= bp->sectsize;
+		n -= xf->sectsize;
 	while(clust > 0){
 		next = getfat(xf, clust);
 		if(n <= 0)
 			putfat(xf, clust, 0);
 		else
-			n -= bp->clustsize*bp->sectsize;
+			n -= bp->clustsize*xf->sectsize;
 		clust = next;
 	}
 	unmlock(bp);
@@ -1089,7 +1084,7 @@
  * creation and access dates
  */
 void
-getdir(Xfs *xfs, Dir *dp, Dosdir *d, vlong addr, int offset)
+getdir(Xfs *xf, Dir *dp, Dosdir *d, vlong addr, int offset)
 {
 	if(d == nil || addr == 0)
 		panic("getdir on root");
@@ -1097,7 +1092,7 @@
 	dp->dev = 0;
 	getname(dp->name, d);
 
-	dp->qid.path = addr*(Sectorsize/DOSDIRSIZE) +
+	dp->qid.path = addr*(xf->sectsize/DOSDIRSIZE) +
 			offset/DOSDIRSIZE;
 	dp->qid.vers = 0;
 
@@ -1116,7 +1111,7 @@
 		dp->length = GLONG(d->length);
 	if(d->attr & DSYSTEM){
 		dp->mode |= DMEXCL;
-		if(iscontig(xfs, d))
+		if(iscontig(xf, d))
 			dp->mode |= DMAPPEND;
 	}
 
@@ -1308,7 +1303,6 @@
 int
 putlongname(Xfs *xf, Dosptr *ndp, char *name, char sname[13])
 {
-	Dosbpb *bp;
 	Dosdir tmpd;
 	Rune longname[DOSNAMELEN+1];
 	int i, first, sum, nds, len;
@@ -1317,7 +1311,6 @@
 	putname(sname, &tmpd);
 	sum = aliassum(&tmpd);
 
-	bp = xf->ptr;
 	first = 1;
 	len = utftorunes(longname, name, DOSNAMELEN);
 	if(chatty){
@@ -1330,7 +1323,7 @@
 		putnamesect(&ndp->p->iobuf[ndp->offset], longname, nds, first, sum);
 		first = 0;
 		ndp->offset += 32;
-		if(ndp->offset == bp->sectsize){
+		if(ndp->offset == xf->sectsize){
 			chat("long name moving over sector boundary\n");
 			ndp->p->flags |= BMOD;
 			putsect(ndp->p);
@@ -1368,15 +1361,15 @@
 		return -1;
 	fb = bp->fatbits;
 	k = (fb * n) >> 3;
-	if(k >= bp->fatsize*bp->sectsize)
+	if(k >= bp->fatsize*xf->sectsize)
 		panic("getfat");
-	sect = k/bp->sectsize + bp->fataddr;
-	o = k%bp->sectsize;
+	sect = k/xf->sectsize + bp->fataddr;
+	o = k%xf->sectsize;
 	p = getsect(xf, sect);
 	if(p == nil)
 		return -1;
 	k = p->iobuf[o++];
-	if(o >= bp->sectsize){
+	if(o >= xf->sectsize){
 		putsect(p);
 		p = getsect(xf, sect+1);
 		if(p == nil)
@@ -1426,12 +1419,12 @@
 	if(n < FATRESRV || n >= bp->fatclusters)
 		panic("putfat n=%d", n);
 	k = (bp->fatbits * n) >> 3;
-	if(k >= bp->fatsize*bp->sectsize)
+	if(k >= bp->fatsize*xf->sectsize)
 		panic("putfat");
-	sect = k/bp->sectsize + bp->fataddr;
+	sect = k/xf->sectsize + bp->fataddr;
 	esect = sect + bp->nfats * bp->fatsize;
 	for(; sect<esect; sect+=bp->fatsize){
-		o = k%bp->sectsize;
+		o = k%xf->sectsize;
 		p = getsect(xf, sect);
 		if(p == nil)
 			continue;
@@ -1440,7 +1433,7 @@
 			if(n&1){
 				p->iobuf[o] &= 0x0f;
 				p->iobuf[o++] |= val<<4;
-				if(o >= bp->sectsize){
+				if(o >= xf->sectsize){
 					p->flags |= BMOD;
 					putsect(p);
 					p = getsect(xf, sect+1);
@@ -1451,7 +1444,7 @@
 				p->iobuf[o] = val>>4;
 			}else{
 				p->iobuf[o++] = val;
-				if(o >= bp->sectsize){
+				if(o >= xf->sectsize){
 					p->flags |= BMOD;
 					putsect(p);
 					p = getsect(xf, sect+1);
@@ -1633,7 +1626,7 @@
 				return -1;
 			wp = getosect(xf, ws);
 			assert(wp != nil);
-			memmove(wp->iobuf, rp->iobuf, bp->sectsize);
+			memmove(wp->iobuf, rp->iobuf, xf->sectsize);
 			wp->flags = BMOD;
 			putsect(rp);
 			putsect(wp);
@@ -1702,7 +1695,7 @@
 	k = clust2sect(bp, n);
 	for(i=0; i<bp->clustsize; i++){
 		p = getosect(xf, k+i);
-		memset(p->iobuf, 0, bp->sectsize);
+		memset(p->iobuf, 0, xf->sectsize);
 		p->flags = BMOD;
 		putsect(p);
 	}
--- a/sys/src/cmd/dossrv/iotrack.c
+++ b/sys/src/cmd/dossrv/iotrack.c
@@ -4,6 +4,9 @@
 #include "dat.h"
 #include "fns.h"
 
+static MLock	freelock;
+static Iosect *	freelist;
+
 #define	HIOB		31	/* a prime */
 #define	NIOBUF		80
 
@@ -19,6 +22,10 @@
 
 #define	TOFRONT(h, p)	((h)->next  != (p) && (UNLINK(p, next, prev), LINK(h,p, next, prev)))
 
+static Iotrack *getiotrack(Xfs*, vlong);
+static Iosect *getiosect(Xfs*, vlong, int);
+static void purgetrack(Iotrack*);
+
 Iosect *
 getsect(Xfs *xf, vlong addr)
 {
@@ -31,19 +38,21 @@
 	return getiosect(xf, addr, 0);
 }
 
-Iosect *
+static Iosect *
 getiosect(Xfs *xf, vlong addr, int rflag)
 {
-	Iotrack *t;
 	vlong taddr;
 	int toff;
+	Iotrack *t;
 	Iosect *p;
 
 	if(addr < 0)
 		return nil;
-	toff = addr % Sect2trk;
+	toff = addr % xf->sect2trk;
 	taddr = addr - toff;
 	t = getiotrack(xf, taddr);
+	if(t == nil)
+		return nil;
 	if(rflag && (t->flags&BSTALE)){
 		if(tread(t) < 0){
 			unmlock(&t->lock);
@@ -51,16 +60,31 @@
 		}
 		t->flags &= ~BSTALE;
 	}
-	t->ref++;
-	p = t->tp->p[toff];
-	if(p == 0){
-		p = newsect();
-		t->tp->p[toff] = p;
+	p = t->tp[toff];
+	if(p == nil){
+		mlock(&freelock);
+		p = freelist;
+		if(p != nil)
+			freelist = p->next;
+		else {
+			p = malloc(sizeof(Iosect));
+			if(p == nil) {
+				unmlock(&freelock);
+				unmlock(&t->lock);
+				return nil;
+			}
+		}
+		p->next = nil;
+		unmlock(&freelock);
+
 		p->flags = t->flags&BSTALE;
 		p->lock.key = 0;
+		p->iobuf = ((uchar*)&t->tp[xf->sect2trk]) + toff*xf->sectsize;
 		p->t = t;
-		p->iobuf = t->tp->buf[toff];
+
+		t->tp[toff] = p;
 	}
+	t->ref++;
 	unmlock(&t->lock);
 	mlock(&p->lock);
 	return p;
@@ -87,7 +111,7 @@
 	unmlock(&p->lock);
 }
 
-Iotrack *
+static Iotrack *
 getiotrack(Xfs *xf, vlong addr)
 {
 	Iotrack *hp, *p;
@@ -142,8 +166,14 @@
 		goto loop;
 	}
 	purgetrack(p);
-	p->addr = addr;
+	p->tp = malloc(xf->sect2trk*sizeof(Iosect*) + xf->sect2trk*xf->sectsize);
+	if(p->tp == nil){
+		unmlock(&p->lock);
+		return nil;
+	}
+	memset(p->tp, 0, xf->sect2trk*sizeof(Iosect*));
 	p->xf = xf;
+	p->addr = addr;
 	p->flags = BSTALE;
 out:
 	mlock(&hp->lock);
@@ -155,39 +185,55 @@
 	return p;
 }
 
-void
+static void
 purgetrack(Iotrack *t)
 {
-	int i, ref = Sect2trk;
-	Iosect *p;
+	if(t->tp != nil){
+		Xfs *xf = t->xf;
+		int i, ref = xf->sect2trk;
 
-	for(i=0; i<Sect2trk; i++){
-		p = t->tp->p[i];
-		if(p == 0){
-			--ref;
-			continue;
+		for(i=0; i<xf->sect2trk; i++){
+			Iosect *p = t->tp[i];
+			if(p == nil){
+				--ref;
+				continue;
+			}
+			if(canmlock(&p->lock)){
+				t->tp[i] = nil;
+
+				mlock(&freelock);
+				p->next = freelist;
+				freelist = p;
+				unmlock(&freelock);
+				--ref;
+			}
 		}
-		if(canmlock(&p->lock)){
-			freesect(p);
-			--ref;
-			t->tp->p[i] = 0;
-		}
+		if(t->ref != ref)
+			panic("purgetrack");
+		if(ref != 0)
+			return;
+
+		free(t->tp);
 	}
-	if(t->ref != ref)
-		panic("purgetrack");
+	assert(t->ref == 0);
+	t->tp = nil;
+	t->xf = nil;
+	t->addr = -1;
+	t->flags = 0;
 }
 
 int
 twrite(Iotrack *t)
 {
-	int i, ref;
+	Xfs *xf = t->xf;
 
-	chat("[twrite %lld...", t->addr);
+	chat("[twrite %lld+%lld...", t->addr, xf->offset);
 	if(t->flags & BSTALE){
-		for(ref=0,i=0; i<Sect2trk; i++)
-			if(t->tp->p[i])
+		int i, ref = 0;
+		for(i=0; i<xf->sect2trk; i++)
+			if(t->tp[i] != nil)
 				++ref;
-		if(ref < Sect2trk){
+		if(ref < xf->sect2trk){
 			if(tread(t) < 0){
 				chat("error]");
 				return -1;
@@ -195,7 +241,7 @@
 		}else
 			t->flags &= ~BSTALE;
 	}
-	if(devwrite(t->xf, t->addr, t->tp->buf, Trksize) < 0){
+	if(devwrite(xf, t->addr, (uchar*)&t->tp[xf->sect2trk], xf->sect2trk*xf->sectsize) < 0){
 		chat("error]");
 		return -1;
 	}
@@ -206,33 +252,31 @@
 int
 tread(Iotrack *t)
 {
+	Xfs *xf = t->xf;
 	int i, ref = 0;
-	uchar buf[Sect2trk][Sectorsize];
 
-	for(i=0; i<Sect2trk; i++)
-		if(t->tp->p[i])
+	chat("[tread %lld+%lld...", t->addr, xf->offset);
+	for(i=0; i<xf->sect2trk; i++)
+		if(t->tp[i] != nil)
 			++ref;
-	chat("[tread %lld+%lld...", t->addr, t->xf->offset);
 	if(ref == 0){
-		if(devread(t->xf, t->addr, t->tp->buf, Trksize) < 0){
+		if(devread(xf, t->addr, (uchar*)&t->tp[xf->sect2trk], xf->sect2trk*xf->sectsize) < 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);
+	} else {
+		for(i=0; i<xf->sect2trk; i++){
+			if(t->tp[i] != nil)
+				continue;
+			if(devread(xf, t->addr + i, ((uchar*)&t->tp[xf->sect2trk]) + i*xf->sectsize, xf->sectsize) < 0){
+				chat("error]");
+				return -1;
+			}
 			chat("%d ", i);
 		}
-	chat("done]");
+	}
 	t->flags &= ~BSTALE;
+	chat("done]");
 	return 0;
 }
 
@@ -285,34 +329,6 @@
 		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);
+		purgetrack(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);
 }
--- a/sys/src/cmd/dossrv/iotrack.h
+++ b/sys/src/cmd/dossrv/iotrack.h
@@ -1,7 +1,6 @@
 typedef struct MLock	MLock;
 typedef	struct Iosect	Iosect;
 typedef	struct Iotrack	Iotrack;
-typedef struct Track	Track;
 typedef struct Xfs	Xfs;
 
 struct MLock
@@ -29,41 +28,23 @@
 	Iotrack	*hprev;
 	MLock	lock;
 	int	ref;
-	Track	*tp;
+	Iosect	**tp;
 };
 
-enum{
-	Sectorsize = 512,
-	Sect2trk = 9,
-	Trksize = Sectorsize*Sect2trk
-};
-
-struct Track
-{
-	Iosect *p[Sect2trk];
-	uchar	buf[Sect2trk][Sectorsize];
-};
-
 #define	BMOD		(1<<0)
 #define	BIMM		(1<<1)
 #define	BSTALE		(1<<2)
 
-Iosect*	getiosect(Xfs*, vlong, int);
 Iosect*	getosect(Xfs*, vlong);
 Iosect*	getsect(Xfs*, vlong);
-Iosect*	newsect(void);
-Iotrack*	getiotrack(Xfs*, vlong);
 int	canmlock(MLock*);
-int	devcheck(Xfs*);
 int	devread(Xfs*, vlong, void*, long);
 int	devwrite(Xfs*, vlong, void*, long);
 int	tread(Iotrack*);
 int	twrite(Iotrack*);
-void	freesect(Iosect*);
 void	iotrack_init(void);
 void	mlock(MLock*);
 void	purgebuf(Xfs*);
-void	purgetrack(Iotrack*);
 void	putsect(Iosect*);
 void	sync(void);
 void	unmlock(MLock*);
--- a/sys/src/cmd/dossrv/xfile.c
+++ b/sys/src/cmd/dossrv/xfile.c
@@ -44,7 +44,8 @@
 			errno = Enofilsys;
 			return 0;
 		}
-		offset *= Sectorsize;
+		/* FIXME: should probably use devices sector size? */
+		offset *= 512;
 	}
 
 	if(readonly)
@@ -83,8 +84,6 @@
 			continue;
 		if(strcmp(xf->name, name) != 0 || xf->dev < 0)
 			continue;
-		if(devcheck(xf) < 0) /* look for media change */
-			continue;
 		if(offset && xf->offset != offset)
 			continue;
 		chat("incref \"%s\", dev=%d...", xf->name, xf->dev);
@@ -239,7 +238,7 @@
 				memmove(xdp, dp, sizeof(Dosptr));
 				xdp->p = nil;
 				xdp->d = nil;
-				p->qid.path = QIDPATH(xdp);
+				p->qid.path = QIDPATH(xdp, f->xf);
 			}
 		}
 	}