xref: /plan9/sys/src/cmd/aux/disksim.c (revision 11e1fb05e6e53d365d5a9dab7cd6360fed28781a)
13ff48bf5SDavid du Colombier #include <u.h>
23ff48bf5SDavid du Colombier #include <libc.h>
33ff48bf5SDavid du Colombier #include <auth.h>
43ff48bf5SDavid du Colombier #include <fcall.h>
53ff48bf5SDavid du Colombier #include <thread.h>
63ff48bf5SDavid du Colombier #include <9p.h>
73ff48bf5SDavid du Colombier 
83ff48bf5SDavid du Colombier typedef struct Part Part;
93ff48bf5SDavid du Colombier typedef struct Trip Trip;
103ff48bf5SDavid du Colombier typedef struct Dbl Dbl;
113ff48bf5SDavid du Colombier typedef struct Ind Ind;
123ff48bf5SDavid du Colombier 
133ff48bf5SDavid du Colombier /*
143ff48bf5SDavid du Colombier  * with 8192-byte blocks and 4-byte pointers,
153ff48bf5SDavid du Colombier  * double-indirect gets us 34 GB.
163ff48bf5SDavid du Colombier  * triple-indirect gets us 70,368 GB.
173ff48bf5SDavid du Colombier  */
183ff48bf5SDavid du Colombier 
193ff48bf5SDavid du Colombier enum
203ff48bf5SDavid du Colombier {
213ff48bf5SDavid du Colombier 	LOGBLKSZ = 13,
223ff48bf5SDavid du Colombier 	BLKSZ = 1<<LOGBLKSZ,	/* 8192 */
233ff48bf5SDavid du Colombier 	LOGNPTR = LOGBLKSZ-2,	/* assume sizeof(void*) == 4 */
243ff48bf5SDavid du Colombier 	NPTR = 1<<LOGNPTR,
253ff48bf5SDavid du Colombier };
263ff48bf5SDavid du Colombier 
273ff48bf5SDavid du Colombier struct Trip
283ff48bf5SDavid du Colombier {
293ff48bf5SDavid du Colombier 	Dbl *dbl[NPTR];
303ff48bf5SDavid du Colombier };
313ff48bf5SDavid du Colombier 
323ff48bf5SDavid du Colombier struct Dbl
333ff48bf5SDavid du Colombier {
343ff48bf5SDavid du Colombier 	Ind *ind[NPTR];
353ff48bf5SDavid du Colombier };
363ff48bf5SDavid du Colombier 
373ff48bf5SDavid du Colombier struct Ind
383ff48bf5SDavid du Colombier {
393ff48bf5SDavid du Colombier 	uchar *blk[NPTR];
403ff48bf5SDavid du Colombier };
413ff48bf5SDavid du Colombier 
423ff48bf5SDavid du Colombier Trip trip;
433ff48bf5SDavid du Colombier 
443ff48bf5SDavid du Colombier struct Part
453ff48bf5SDavid du Colombier {
463ff48bf5SDavid du Colombier 	int inuse;
473ff48bf5SDavid du Colombier 	int vers;
483ff48bf5SDavid du Colombier 	ulong mode;
493ff48bf5SDavid du Colombier 	char *name;
503ff48bf5SDavid du Colombier 	vlong offset;	/* in sectors */
513ff48bf5SDavid du Colombier 	vlong length;	/* in sectors */
523ff48bf5SDavid du Colombier };
533ff48bf5SDavid du Colombier 
543ff48bf5SDavid du Colombier enum
553ff48bf5SDavid du Colombier {
563ff48bf5SDavid du Colombier 	Qroot = 0,
573ff48bf5SDavid du Colombier 	Qdir,
583ff48bf5SDavid du Colombier 	Qctl,
593ff48bf5SDavid du Colombier 	Qpart,
603ff48bf5SDavid du Colombier };
613ff48bf5SDavid du Colombier 
623ff48bf5SDavid du Colombier Part tab[64];
63*11e1fb05SDavid du Colombier int fd = -1;
643ff48bf5SDavid du Colombier char *sdname = "sdXX";
653ff48bf5SDavid du Colombier ulong ctlmode = 0666;
663ff48bf5SDavid du Colombier char *inquiry = "aux/disksim hard drive";
673ff48bf5SDavid du Colombier vlong nsect, sectsize, c, h, s;
683ff48bf5SDavid du Colombier ulong time0;
69*11e1fb05SDavid du Colombier int rdonly;
703ff48bf5SDavid du Colombier 
713ff48bf5SDavid du Colombier char*
723ff48bf5SDavid du Colombier ctlstring(void)
733ff48bf5SDavid du Colombier {
743ff48bf5SDavid du Colombier 	int i;
753ff48bf5SDavid du Colombier 	Fmt fmt;
763ff48bf5SDavid du Colombier 
773ff48bf5SDavid du Colombier 	fmtstrinit(&fmt);
783ff48bf5SDavid du Colombier 	fmtprint(&fmt, "inquiry %s\n", inquiry);
793ff48bf5SDavid du Colombier 	fmtprint(&fmt, "geometry %lld %lld %lld %lld %lld\n", nsect, sectsize, c, h, s);
803ff48bf5SDavid du Colombier 	for(i=0; i<nelem(tab); i++)
813ff48bf5SDavid du Colombier 		if(tab[i].inuse)
823ff48bf5SDavid du Colombier 			fmtprint(&fmt, "part %s %lld %lld\n", tab[i].name, tab[i].offset, tab[i].length);
833ff48bf5SDavid du Colombier 	return fmtstrflush(&fmt);
843ff48bf5SDavid du Colombier }
853ff48bf5SDavid du Colombier 
863ff48bf5SDavid du Colombier int
873ff48bf5SDavid du Colombier addpart(char *name, vlong start, vlong end)
883ff48bf5SDavid du Colombier {
893ff48bf5SDavid du Colombier 	int i;
903ff48bf5SDavid du Colombier 
913ff48bf5SDavid du Colombier 	if(start < 0 || start > end || end > nsect){
923ff48bf5SDavid du Colombier 		werrstr("bad partition boundaries");
933ff48bf5SDavid du Colombier 		return -1;
943ff48bf5SDavid du Colombier 	}
953ff48bf5SDavid du Colombier 
963ff48bf5SDavid du Colombier 	for(i=0; i<nelem(tab); i++)
973ff48bf5SDavid du Colombier 		if(tab[i].inuse == 0)
983ff48bf5SDavid du Colombier 			break;
993ff48bf5SDavid du Colombier 	if(i == nelem(tab)){
1003ff48bf5SDavid du Colombier 		werrstr("no free partition slots");
1013ff48bf5SDavid du Colombier 		return -1;
1023ff48bf5SDavid du Colombier 	}
1033ff48bf5SDavid du Colombier 
1043ff48bf5SDavid du Colombier 	free(tab[i].name);
1053ff48bf5SDavid du Colombier 	tab[i].inuse = 1;
1063ff48bf5SDavid du Colombier 	tab[i].name = estrdup9p(name);
1073ff48bf5SDavid du Colombier 	tab[i].offset = start;
1083ff48bf5SDavid du Colombier 	tab[i].length = end - start;
1093ff48bf5SDavid du Colombier 	tab[i].mode = ctlmode;
1103ff48bf5SDavid du Colombier 	tab[i].vers++;
1113ff48bf5SDavid du Colombier 
1123ff48bf5SDavid du Colombier 	return 0;
1133ff48bf5SDavid du Colombier }
1143ff48bf5SDavid du Colombier 
1153ff48bf5SDavid du Colombier int
1163ff48bf5SDavid du Colombier delpart(char *s)
1173ff48bf5SDavid du Colombier {
1183ff48bf5SDavid du Colombier 	int i;
1193ff48bf5SDavid du Colombier 
1203ff48bf5SDavid du Colombier 	for(i=0; i<nelem(tab); i++)
1213ff48bf5SDavid du Colombier 		if(tab[i].inuse && strcmp(tab[i].name, s) == 0)
1223ff48bf5SDavid du Colombier 			break;
1233ff48bf5SDavid du Colombier 	if(i==nelem(tab)){
1243ff48bf5SDavid du Colombier 		werrstr("partition not found");
1253ff48bf5SDavid du Colombier 		return -1;
1263ff48bf5SDavid du Colombier 	}
1273ff48bf5SDavid du Colombier 
1283ff48bf5SDavid du Colombier 	tab[i].inuse = 0;
1293ff48bf5SDavid du Colombier 	free(tab[i].name);
1303ff48bf5SDavid du Colombier 	tab[i].name = 0;
1313ff48bf5SDavid du Colombier 	return 0;
1323ff48bf5SDavid du Colombier }
1333ff48bf5SDavid du Colombier 
1343ff48bf5SDavid du Colombier void
1353ff48bf5SDavid du Colombier ctlwrite(Req *r)
1363ff48bf5SDavid du Colombier {
1373ff48bf5SDavid du Colombier 	int i;
1383ff48bf5SDavid du Colombier 	Cmdbuf *cb;
1393ff48bf5SDavid du Colombier 	vlong start, end;
1403ff48bf5SDavid du Colombier 
1413ff48bf5SDavid du Colombier 	r->ofcall.count = r->ifcall.count;
1423ff48bf5SDavid du Colombier 	cb = parsecmd(r->ifcall.data, r->ifcall.count);
1433ff48bf5SDavid du Colombier 	if(cb->nf < 1){
1443ff48bf5SDavid du Colombier 		respond(r, "empty control message");
1453ff48bf5SDavid du Colombier 		free(cb);
1463ff48bf5SDavid du Colombier 		return;
1473ff48bf5SDavid du Colombier 	}
1483ff48bf5SDavid du Colombier 
1493ff48bf5SDavid du Colombier 	if(strcmp(cb->f[0], "part") == 0){
1503ff48bf5SDavid du Colombier 		if(cb->nf != 4){
1513ff48bf5SDavid du Colombier 			respondcmderror(r, cb, "part takes 3 args");
1523ff48bf5SDavid du Colombier 			free(cb);
1533ff48bf5SDavid du Colombier 			return;
1543ff48bf5SDavid du Colombier 		}
1553ff48bf5SDavid du Colombier 		start = strtoll(cb->f[2], 0, 0);
1563ff48bf5SDavid du Colombier 		end = strtoll(cb->f[3], 0, 0);
1573ff48bf5SDavid du Colombier 		if(addpart(cb->f[1], start, end) < 0){
1583ff48bf5SDavid du Colombier 			respondcmderror(r, cb, "%r");
1593ff48bf5SDavid du Colombier 			free(cb);
1603ff48bf5SDavid du Colombier 			return;
1613ff48bf5SDavid du Colombier 		}
1623ff48bf5SDavid du Colombier 	}
1633ff48bf5SDavid du Colombier 	else if(strcmp(cb->f[0], "delpart") == 0){
1643ff48bf5SDavid du Colombier 		if(cb->nf != 2){
1653ff48bf5SDavid du Colombier 			respondcmderror(r, cb, "delpart takes 1 arg");
1663ff48bf5SDavid du Colombier 			free(cb);
1673ff48bf5SDavid du Colombier 			return;
1683ff48bf5SDavid du Colombier 		}
1693ff48bf5SDavid du Colombier 		if(delpart(cb->f[1]) < 0){
1703ff48bf5SDavid du Colombier 			respondcmderror(r, cb, "%r");
1713ff48bf5SDavid du Colombier 			free(cb);
1723ff48bf5SDavid du Colombier 			return;
1733ff48bf5SDavid du Colombier 		}
1743ff48bf5SDavid du Colombier 	}
1753ff48bf5SDavid du Colombier 	else if(strcmp(cb->f[0], "inquiry") == 0){
1763ff48bf5SDavid du Colombier 		if(cb->nf != 2){
1773ff48bf5SDavid du Colombier 			respondcmderror(r, cb, "inquiry takes 1 arg");
1783ff48bf5SDavid du Colombier 			free(cb);
1793ff48bf5SDavid du Colombier 			return;
1803ff48bf5SDavid du Colombier 		}
1813ff48bf5SDavid du Colombier 		free(inquiry);
1823ff48bf5SDavid du Colombier 		inquiry = estrdup9p(cb->f[1]);
1833ff48bf5SDavid du Colombier 	}
1843ff48bf5SDavid du Colombier 	else if(strcmp(cb->f[0], "geometry") == 0){
1853ff48bf5SDavid du Colombier 		if(cb->nf != 6){
1863ff48bf5SDavid du Colombier 			respondcmderror(r, cb, "geometry takes 5 args");
1873ff48bf5SDavid du Colombier 			free(cb);
1883ff48bf5SDavid du Colombier 			return;
1893ff48bf5SDavid du Colombier 		}
1903ff48bf5SDavid du Colombier 		nsect = strtoll(cb->f[1], 0, 0);
1913ff48bf5SDavid du Colombier 		sectsize = strtoll(cb->f[2], 0, 0);
1923ff48bf5SDavid du Colombier 		c = strtoll(cb->f[3], 0, 0);
1933ff48bf5SDavid du Colombier 		h = strtoll(cb->f[4], 0, 0);
1943ff48bf5SDavid du Colombier 		s = strtoll(cb->f[5], 0, 0);
1953ff48bf5SDavid du Colombier 		if(tab[0].inuse && strcmp(tab[0].name, "data") == 0 && tab[0].vers == 0){
1963ff48bf5SDavid du Colombier 			tab[0].offset = 0;
1973ff48bf5SDavid du Colombier 			tab[0].length = nsect;
1983ff48bf5SDavid du Colombier 		}
1993ff48bf5SDavid du Colombier 		for(i=0; i<nelem(tab); i++){
2003ff48bf5SDavid du Colombier 			if(tab[i].inuse && tab[i].offset+tab[i].length > nsect){
2013ff48bf5SDavid du Colombier 				tab[i].inuse = 0;
2023ff48bf5SDavid du Colombier 				free(tab[i].name);
2033ff48bf5SDavid du Colombier 				tab[i].name = 0;
2043ff48bf5SDavid du Colombier 			}
2053ff48bf5SDavid du Colombier 		}
2063ff48bf5SDavid du Colombier 	}
2073ff48bf5SDavid du Colombier 	else{
2083ff48bf5SDavid du Colombier 		respondcmderror(r, cb, "unknown control message");
2093ff48bf5SDavid du Colombier 		free(cb);
2103ff48bf5SDavid du Colombier 		return;
2113ff48bf5SDavid du Colombier 	}
2123ff48bf5SDavid du Colombier 
2133ff48bf5SDavid du Colombier 	free(cb);
2143ff48bf5SDavid du Colombier 	respond(r, nil);
2153ff48bf5SDavid du Colombier }
2163ff48bf5SDavid du Colombier 
2173ff48bf5SDavid du Colombier void*
218*11e1fb05SDavid du Colombier allocblk(vlong addr)
2193ff48bf5SDavid du Colombier {
2203ff48bf5SDavid du Colombier 	uchar *op;
2213ff48bf5SDavid du Colombier 	static uchar *p;
2223ff48bf5SDavid du Colombier 	static ulong n;
2233ff48bf5SDavid du Colombier 
2243ff48bf5SDavid du Colombier 	if(n == 0){
2253ff48bf5SDavid du Colombier 		p = malloc(4*1024*1024);
2263ff48bf5SDavid du Colombier 		if(p == 0)
2273ff48bf5SDavid du Colombier 			sysfatal("out of memory");
2283ff48bf5SDavid du Colombier 		n = 4*1024*1024;
2293ff48bf5SDavid du Colombier 	}
2303ff48bf5SDavid du Colombier 	op = p;
2313ff48bf5SDavid du Colombier 	p += BLKSZ;
2323ff48bf5SDavid du Colombier 	n -= BLKSZ;
2333ff48bf5SDavid du Colombier 	memset(op, 0, BLKSZ);
234*11e1fb05SDavid du Colombier 	if(fd != -1 && addr != -1)
235*11e1fb05SDavid du Colombier 		pread(fd, op, BLKSZ, addr);
2363ff48bf5SDavid du Colombier 	return op;
2373ff48bf5SDavid du Colombier }
2383ff48bf5SDavid du Colombier 
2393ff48bf5SDavid du Colombier uchar*
2403ff48bf5SDavid du Colombier getblock(vlong addr, int alloc)
2413ff48bf5SDavid du Colombier {
2423ff48bf5SDavid du Colombier 	static uchar zero[BLKSZ];
2433ff48bf5SDavid du Colombier  	Dbl *p2;
2443ff48bf5SDavid du Colombier 	Ind *p1;
2453ff48bf5SDavid du Colombier 	uchar *p0;
2463ff48bf5SDavid du Colombier 	uint i0, i1, i2;
247*11e1fb05SDavid du Colombier 	vlong oaddr;
248*11e1fb05SDavid du Colombier 
249*11e1fb05SDavid du Colombier 	if(fd)
250*11e1fb05SDavid du Colombier 		alloc = 1;
2513ff48bf5SDavid du Colombier 
2523ff48bf5SDavid du Colombier 	addr >>= LOGBLKSZ;
253*11e1fb05SDavid du Colombier 	oaddr = addr<<LOGBLKSZ;
2543ff48bf5SDavid du Colombier 	i0 = addr & (NPTR-1);
2553ff48bf5SDavid du Colombier 	addr >>= LOGNPTR;
2563ff48bf5SDavid du Colombier 	i1 = addr & (NPTR-1);
2573ff48bf5SDavid du Colombier 	addr >>= LOGNPTR;
2583ff48bf5SDavid du Colombier 	i2 = addr & (NPTR-1);
2593ff48bf5SDavid du Colombier 	addr >>= LOGNPTR;
2603ff48bf5SDavid du Colombier 	assert(addr == 0);
2613ff48bf5SDavid du Colombier 
2623ff48bf5SDavid du Colombier 	if((p2 = trip.dbl[i2]) == 0){
2633ff48bf5SDavid du Colombier 		if(!alloc)
2643ff48bf5SDavid du Colombier 			return zero;
265*11e1fb05SDavid du Colombier 		trip.dbl[i2] = p2 = allocblk(-1);
2663ff48bf5SDavid du Colombier 	}
2673ff48bf5SDavid du Colombier 
2683ff48bf5SDavid du Colombier 	if((p1 = p2->ind[i1]) == 0){
2693ff48bf5SDavid du Colombier 		if(!alloc)
2703ff48bf5SDavid du Colombier 			return zero;
271*11e1fb05SDavid du Colombier 		p2->ind[i1] = p1 = allocblk(-1);
2723ff48bf5SDavid du Colombier 	}
2733ff48bf5SDavid du Colombier 
2743ff48bf5SDavid du Colombier 	if((p0 = p1->blk[i0]) == 0){
2753ff48bf5SDavid du Colombier 		if(!alloc)
2763ff48bf5SDavid du Colombier 			return zero;
277*11e1fb05SDavid du Colombier 		p1->blk[i0] = p0 = allocblk(oaddr);
2783ff48bf5SDavid du Colombier 	}
2793ff48bf5SDavid du Colombier 	return p0;
2803ff48bf5SDavid du Colombier }
2813ff48bf5SDavid du Colombier 
282*11e1fb05SDavid du Colombier void
283*11e1fb05SDavid du Colombier dirty(vlong addr, uchar *buf)
284*11e1fb05SDavid du Colombier {
285*11e1fb05SDavid du Colombier 	vlong oaddr;
286*11e1fb05SDavid du Colombier 
287*11e1fb05SDavid du Colombier 	if(fd == -1 || rdonly)
288*11e1fb05SDavid du Colombier 		return;
289*11e1fb05SDavid du Colombier 	oaddr = addr&~((vlong)BLKSZ-1);
290*11e1fb05SDavid du Colombier 	if(pwrite(fd, buf, BLKSZ, oaddr) != BLKSZ)
291*11e1fb05SDavid du Colombier 		sysfatal("write: %r");
292*11e1fb05SDavid du Colombier }
293*11e1fb05SDavid du Colombier 
2943ff48bf5SDavid du Colombier int
2953ff48bf5SDavid du Colombier rootgen(int off, Dir *d, void*)
2963ff48bf5SDavid du Colombier {
2973ff48bf5SDavid du Colombier 	memset(d, 0, sizeof *d);
2983ff48bf5SDavid du Colombier 	d->atime = time0;
2993ff48bf5SDavid du Colombier 	d->mtime = time0;
3003ff48bf5SDavid du Colombier 	if(off == 0){
3013ff48bf5SDavid du Colombier 		d->name = estrdup9p(sdname);
3023ff48bf5SDavid du Colombier 		d->mode = DMDIR|0777;
3033ff48bf5SDavid du Colombier 		d->qid.path = Qdir;
3043ff48bf5SDavid du Colombier 		d->qid.type = QTDIR;
3053ff48bf5SDavid du Colombier 		d->uid = estrdup9p("disksim");
3063ff48bf5SDavid du Colombier 		d->gid = estrdup9p("disksim");
3073ff48bf5SDavid du Colombier 		d->muid = estrdup9p("");
3083ff48bf5SDavid du Colombier 		return 0;
3093ff48bf5SDavid du Colombier 	}
3103ff48bf5SDavid du Colombier 	return -1;
3113ff48bf5SDavid du Colombier }
3123ff48bf5SDavid du Colombier 
3133ff48bf5SDavid du Colombier int
3143ff48bf5SDavid du Colombier dirgen(int off, Dir *d, void*)
3153ff48bf5SDavid du Colombier {
3163ff48bf5SDavid du Colombier 	int n, j;
3173ff48bf5SDavid du Colombier 
3183ff48bf5SDavid du Colombier 	memset(d, 0, sizeof *d);
3193ff48bf5SDavid du Colombier 	d->atime = time0;
3203ff48bf5SDavid du Colombier 	d->mtime = time0;
3213ff48bf5SDavid du Colombier 	if(off == 0){
3223ff48bf5SDavid du Colombier 		d->name = estrdup9p("ctl");
3233ff48bf5SDavid du Colombier 		d->mode = ctlmode;
3243ff48bf5SDavid du Colombier 		d->qid.path = Qctl;
3253ff48bf5SDavid du Colombier 		goto Have;
3263ff48bf5SDavid du Colombier 	}
3273ff48bf5SDavid du Colombier 
3283ff48bf5SDavid du Colombier 	off--;
3293ff48bf5SDavid du Colombier 	n = 0;
3303ff48bf5SDavid du Colombier 	for(j=0; j<nelem(tab); j++){
3313ff48bf5SDavid du Colombier 		if(tab[j].inuse==0)
3323ff48bf5SDavid du Colombier 			continue;
3333ff48bf5SDavid du Colombier 		if(n == off){
3343ff48bf5SDavid du Colombier 			d->name = estrdup9p(tab[j].name);
33581cf8742SDavid du Colombier 			d->length = tab[j].length*sectsize;
3363ff48bf5SDavid du Colombier 			d->mode = tab[j].mode;
3373ff48bf5SDavid du Colombier 			d->qid.path = Qpart+j;
3383ff48bf5SDavid du Colombier 			d->qid.vers = tab[j].vers;
3393ff48bf5SDavid du Colombier 			goto Have;
3403ff48bf5SDavid du Colombier 		}
3413ff48bf5SDavid du Colombier 		n++;
3423ff48bf5SDavid du Colombier 	}
3433ff48bf5SDavid du Colombier 	return -1;
3443ff48bf5SDavid du Colombier 
3453ff48bf5SDavid du Colombier Have:
3463ff48bf5SDavid du Colombier 	d->uid = estrdup9p("disksim");
3473ff48bf5SDavid du Colombier 	d->gid = estrdup9p("disksim");
3483ff48bf5SDavid du Colombier 	d->muid = estrdup9p("");
3493ff48bf5SDavid du Colombier 	return 0;
3503ff48bf5SDavid du Colombier }
3513ff48bf5SDavid du Colombier 
3523ff48bf5SDavid du Colombier void*
3533ff48bf5SDavid du Colombier evommem(void *a, void *b, ulong n)
3543ff48bf5SDavid du Colombier {
3553ff48bf5SDavid du Colombier 	return memmove(b, a, n);
3563ff48bf5SDavid du Colombier }
3573ff48bf5SDavid du Colombier 
3583ff48bf5SDavid du Colombier int
3593ff48bf5SDavid du Colombier rdwrpart(Req *r)
3603ff48bf5SDavid du Colombier {
3613ff48bf5SDavid du Colombier 	int q;
3623ff48bf5SDavid du Colombier 	Part *p;
3633ff48bf5SDavid du Colombier 	vlong offset;
3643ff48bf5SDavid du Colombier 	long count, tot, n, o;
3653ff48bf5SDavid du Colombier 	uchar *blk, *dat;
3663ff48bf5SDavid du Colombier 	void *(*move)(void*, void*, ulong);
3673ff48bf5SDavid du Colombier 
3683ff48bf5SDavid du Colombier 	q = r->fid->qid.path-Qpart;
3693ff48bf5SDavid du Colombier 	if(q < 0 || q > nelem(tab) || !tab[q].inuse || tab[q].vers != r->fid->qid.vers){
3703ff48bf5SDavid du Colombier 		respond(r, "unknown partition");
3713ff48bf5SDavid du Colombier 		return -1;
3723ff48bf5SDavid du Colombier 	}
3733ff48bf5SDavid du Colombier 
3743ff48bf5SDavid du Colombier 	p = &tab[q];
3753ff48bf5SDavid du Colombier 	offset = r->ifcall.offset;
3763ff48bf5SDavid du Colombier 	count = r->ifcall.count;
3773ff48bf5SDavid du Colombier 	if(offset < 0){
3783ff48bf5SDavid du Colombier 		respond(r, "negative offset");
3793ff48bf5SDavid du Colombier 		return -1;
3803ff48bf5SDavid du Colombier 	}
3813ff48bf5SDavid du Colombier 	if(count < 0){
3823ff48bf5SDavid du Colombier 		respond(r, "negative count");
3833ff48bf5SDavid du Colombier 		return -1;
3843ff48bf5SDavid du Colombier 	}
3853ff48bf5SDavid du Colombier 	if(offset > p->length*sectsize){
3863ff48bf5SDavid du Colombier 		respond(r, "offset past end of partition");
3873ff48bf5SDavid du Colombier 		return -1;
3883ff48bf5SDavid du Colombier 	}
3893ff48bf5SDavid du Colombier 	if(offset+count > p->length*sectsize)
3903ff48bf5SDavid du Colombier 		count = p->length*sectsize - offset;
3913ff48bf5SDavid du Colombier 	offset += p->offset*sectsize;
3923ff48bf5SDavid du Colombier 
3933ff48bf5SDavid du Colombier 	if(r->ifcall.type == Tread)
3943ff48bf5SDavid du Colombier 		move = memmove;
3953ff48bf5SDavid du Colombier 	else
3963ff48bf5SDavid du Colombier 		move = evommem;
3973ff48bf5SDavid du Colombier 
3983ff48bf5SDavid du Colombier 	tot = 0;
3993ff48bf5SDavid du Colombier 	if(r->ifcall.type == Tread)
4003ff48bf5SDavid du Colombier 		dat = (uchar*)r->ofcall.data;
4013ff48bf5SDavid du Colombier 	else
4023ff48bf5SDavid du Colombier 		dat = (uchar*)r->ifcall.data;
4033ff48bf5SDavid du Colombier 	o = offset & (BLKSZ-1);
4043ff48bf5SDavid du Colombier 
4053ff48bf5SDavid du Colombier 	/* left fringe block */
4063ff48bf5SDavid du Colombier 	if(o && count){
4073ff48bf5SDavid du Colombier 		blk = getblock(offset, r->ifcall.type==Twrite);
4083ff48bf5SDavid du Colombier 		if(blk == nil)
4093ff48bf5SDavid du Colombier 			abort();
4103ff48bf5SDavid du Colombier 		n = BLKSZ - o;
4113ff48bf5SDavid du Colombier 		if(n > count)
4123ff48bf5SDavid du Colombier 			n = count;
4133ff48bf5SDavid du Colombier 		(*move)(dat, blk+o, n);
414*11e1fb05SDavid du Colombier 		if(r->ifcall.type == Twrite)
415*11e1fb05SDavid du Colombier 			dirty(offset, blk);
4163ff48bf5SDavid du Colombier 		tot += n;
4173ff48bf5SDavid du Colombier 	}
4183ff48bf5SDavid du Colombier 	/* full and right fringe blocks */
4193ff48bf5SDavid du Colombier 	while(tot < count){
4203ff48bf5SDavid du Colombier 		blk = getblock(offset+tot, r->ifcall.type==Twrite);
4213ff48bf5SDavid du Colombier 		if(blk == nil)
4223ff48bf5SDavid du Colombier 			abort();
4233ff48bf5SDavid du Colombier 		n = BLKSZ;
424*11e1fb05SDavid du Colombier 		if(n > count-tot)
425*11e1fb05SDavid du Colombier 			n = count-tot;
4263ff48bf5SDavid du Colombier 		(*move)(dat+tot, blk, n);
427*11e1fb05SDavid du Colombier 		if(r->ifcall.type == Twrite)
428*11e1fb05SDavid du Colombier 			dirty(offset+tot, blk);
4293ff48bf5SDavid du Colombier 		tot += n;
4303ff48bf5SDavid du Colombier 	}
4313ff48bf5SDavid du Colombier 	r->ofcall.count = tot;
4323ff48bf5SDavid du Colombier 	respond(r, nil);
4333ff48bf5SDavid du Colombier 	return 0;
4343ff48bf5SDavid du Colombier }
4353ff48bf5SDavid du Colombier 
4363ff48bf5SDavid du Colombier void
4373ff48bf5SDavid du Colombier fsread(Req *r)
4383ff48bf5SDavid du Colombier {
4393ff48bf5SDavid du Colombier 	char *s;
4403ff48bf5SDavid du Colombier 
4413ff48bf5SDavid du Colombier 	switch((int)r->fid->qid.path){
4423ff48bf5SDavid du Colombier 	case Qroot:
4433ff48bf5SDavid du Colombier 		dirread9p(r, rootgen, nil);
4443ff48bf5SDavid du Colombier 		respond(r, nil);
4453ff48bf5SDavid du Colombier 		break;
4463ff48bf5SDavid du Colombier 
4473ff48bf5SDavid du Colombier 	case Qdir:
4483ff48bf5SDavid du Colombier 		dirread9p(r, dirgen, nil);
4493ff48bf5SDavid du Colombier 		respond(r, nil);
4503ff48bf5SDavid du Colombier 		break;
4513ff48bf5SDavid du Colombier 
4523ff48bf5SDavid du Colombier 	case Qctl:
4533ff48bf5SDavid du Colombier 		s = ctlstring();
4543ff48bf5SDavid du Colombier 		readstr(r, s);
4553ff48bf5SDavid du Colombier 		free(s);
4563ff48bf5SDavid du Colombier 		respond(r, nil);
4573ff48bf5SDavid du Colombier 		break;
4583ff48bf5SDavid du Colombier 
4593ff48bf5SDavid du Colombier 	default:
4603ff48bf5SDavid du Colombier 		rdwrpart(r);
4613ff48bf5SDavid du Colombier 		break;
4623ff48bf5SDavid du Colombier 	}
4633ff48bf5SDavid du Colombier }
4643ff48bf5SDavid du Colombier 
4653ff48bf5SDavid du Colombier void
4663ff48bf5SDavid du Colombier fswrite(Req *r)
4673ff48bf5SDavid du Colombier {
4683ff48bf5SDavid du Colombier 	switch((int)r->fid->qid.path){
4693ff48bf5SDavid du Colombier 	case Qroot:
4703ff48bf5SDavid du Colombier 	case Qdir:
4713ff48bf5SDavid du Colombier 		respond(r, "write to a directory?");
4723ff48bf5SDavid du Colombier 		break;
4733ff48bf5SDavid du Colombier 
4743ff48bf5SDavid du Colombier 	case Qctl:
4753ff48bf5SDavid du Colombier 		ctlwrite(r);
4763ff48bf5SDavid du Colombier 		break;
4773ff48bf5SDavid du Colombier 
4783ff48bf5SDavid du Colombier 	default:
4793ff48bf5SDavid du Colombier 		rdwrpart(r);
4803ff48bf5SDavid du Colombier 		break;
4813ff48bf5SDavid du Colombier 	}
4823ff48bf5SDavid du Colombier }
4833ff48bf5SDavid du Colombier 
4843ff48bf5SDavid du Colombier void
4853ff48bf5SDavid du Colombier fsopen(Req *r)
4863ff48bf5SDavid du Colombier {
4873ff48bf5SDavid du Colombier 	if(r->ifcall.mode&ORCLOSE)
4883ff48bf5SDavid du Colombier 		respond(r, "cannot open ORCLOSE");
4893ff48bf5SDavid du Colombier 
4903ff48bf5SDavid du Colombier 	switch((int)r->fid->qid.path){
4913ff48bf5SDavid du Colombier 	case Qroot:
4923ff48bf5SDavid du Colombier 	case Qdir:
4933ff48bf5SDavid du Colombier 		if(r->ifcall.mode != OREAD){
4943ff48bf5SDavid du Colombier 			respond(r, "bad mode for directory open");
4953ff48bf5SDavid du Colombier 			return;
4963ff48bf5SDavid du Colombier 		}
4973ff48bf5SDavid du Colombier 	}
4983ff48bf5SDavid du Colombier 
4993ff48bf5SDavid du Colombier 	respond(r, nil);
5003ff48bf5SDavid du Colombier }
5013ff48bf5SDavid du Colombier 
5023ff48bf5SDavid du Colombier void
5033ff48bf5SDavid du Colombier fsstat(Req *r)
5043ff48bf5SDavid du Colombier {
5053ff48bf5SDavid du Colombier 	int q;
5063ff48bf5SDavid du Colombier 	Dir *d;
5073ff48bf5SDavid du Colombier 	Part *p;
5083ff48bf5SDavid du Colombier 
5093ff48bf5SDavid du Colombier 	d = &r->d;
5103ff48bf5SDavid du Colombier 	memset(d, 0, sizeof *d);
5113ff48bf5SDavid du Colombier 	d->qid = r->fid->qid;
5123ff48bf5SDavid du Colombier 	d->atime = d->mtime = time0;
5133ff48bf5SDavid du Colombier 	q = r->fid->qid.path;
5143ff48bf5SDavid du Colombier 	switch(q){
5153ff48bf5SDavid du Colombier 	case Qroot:
5163ff48bf5SDavid du Colombier 		d->name = estrdup9p("/");
5173ff48bf5SDavid du Colombier 		d->mode = DMDIR|0777;
5183ff48bf5SDavid du Colombier 		break;
5193ff48bf5SDavid du Colombier 
5203ff48bf5SDavid du Colombier 	case Qdir:
5213ff48bf5SDavid du Colombier 		d->name = estrdup9p(sdname);
5223ff48bf5SDavid du Colombier 		d->mode = DMDIR|0777;
5233ff48bf5SDavid du Colombier 		break;
5243ff48bf5SDavid du Colombier 
5253ff48bf5SDavid du Colombier 	default:
5263ff48bf5SDavid du Colombier 		q -= Qpart;
5273ff48bf5SDavid du Colombier 		if(q < 0 || q > nelem(tab) || tab[q].inuse==0 || r->fid->qid.vers != tab[q].vers){
5283ff48bf5SDavid du Colombier 			respond(r, "partition no longer exists");
5293ff48bf5SDavid du Colombier 			return;
5303ff48bf5SDavid du Colombier 		}
5313ff48bf5SDavid du Colombier 		p = &tab[q];
5323ff48bf5SDavid du Colombier 		d->name = estrdup9p(p->name);
5333ff48bf5SDavid du Colombier 		d->length = p->length * sectsize;
5343ff48bf5SDavid du Colombier 		d->mode = p->mode;
5353ff48bf5SDavid du Colombier 		break;
5363ff48bf5SDavid du Colombier 	}
5373ff48bf5SDavid du Colombier 
5383ff48bf5SDavid du Colombier 	d->uid = estrdup9p("disksim");
5393ff48bf5SDavid du Colombier 	d->gid = estrdup9p("disksim");
5403ff48bf5SDavid du Colombier 	d->muid = estrdup9p("");
5413ff48bf5SDavid du Colombier 	respond(r, nil);
5423ff48bf5SDavid du Colombier }
5433ff48bf5SDavid du Colombier 
5443ff48bf5SDavid du Colombier void
5453ff48bf5SDavid du Colombier fsattach(Req *r)
5463ff48bf5SDavid du Colombier {
5473ff48bf5SDavid du Colombier 	char *spec;
5483ff48bf5SDavid du Colombier 
5493ff48bf5SDavid du Colombier 	spec = r->ifcall.aname;
5503ff48bf5SDavid du Colombier 	if(spec && spec[0]){
5513ff48bf5SDavid du Colombier 		respond(r, "invalid attach specifier");
5523ff48bf5SDavid du Colombier 		return;
5533ff48bf5SDavid du Colombier 	}
5543ff48bf5SDavid du Colombier 	r->ofcall.qid = (Qid){Qroot, 0, QTDIR};
5553ff48bf5SDavid du Colombier 	r->fid->qid = r->ofcall.qid;
5563ff48bf5SDavid du Colombier 	respond(r, nil);
5573ff48bf5SDavid du Colombier }
5583ff48bf5SDavid du Colombier 
5593ff48bf5SDavid du Colombier char*
5603ff48bf5SDavid du Colombier fswalk1(Fid *fid, char *name, Qid *qid)
5613ff48bf5SDavid du Colombier {
5623ff48bf5SDavid du Colombier 	int i;
5633ff48bf5SDavid du Colombier 	switch((int)fid->qid.path){
5643ff48bf5SDavid du Colombier 	case Qroot:
5653ff48bf5SDavid du Colombier 		if(strcmp(name, sdname) == 0){
5663ff48bf5SDavid du Colombier 			fid->qid.path = Qdir;
5673ff48bf5SDavid du Colombier 			fid->qid.type = QTDIR;
5683ff48bf5SDavid du Colombier 			*qid = fid->qid;
5693ff48bf5SDavid du Colombier 			return nil;
5703ff48bf5SDavid du Colombier 		}
5713ff48bf5SDavid du Colombier 		break;
5723ff48bf5SDavid du Colombier 	case Qdir:
5733ff48bf5SDavid du Colombier 		if(strcmp(name, "ctl") == 0){
5743ff48bf5SDavid du Colombier 			fid->qid.path = Qctl;
5753ff48bf5SDavid du Colombier 			fid->qid.vers = 0;
5763ff48bf5SDavid du Colombier 			fid->qid.type = 0;
5773ff48bf5SDavid du Colombier 			*qid = fid->qid;
5783ff48bf5SDavid du Colombier 			return nil;
5793ff48bf5SDavid du Colombier 		}
5803ff48bf5SDavid du Colombier 		for(i=0; i<nelem(tab); i++){
5813ff48bf5SDavid du Colombier 			if(tab[i].inuse && strcmp(tab[i].name, name) == 0){
5823ff48bf5SDavid du Colombier 				fid->qid.path = i+Qpart;
5833ff48bf5SDavid du Colombier 				fid->qid.vers = tab[i].vers;
5843ff48bf5SDavid du Colombier 				fid->qid.type = 0;
5853ff48bf5SDavid du Colombier 				*qid = fid->qid;
5863ff48bf5SDavid du Colombier 				return nil;
5873ff48bf5SDavid du Colombier 			}
5883ff48bf5SDavid du Colombier 		}
5893ff48bf5SDavid du Colombier 		break;
5903ff48bf5SDavid du Colombier 	}
5913ff48bf5SDavid du Colombier 	return "file not found";
5923ff48bf5SDavid du Colombier }
5933ff48bf5SDavid du Colombier 
5943ff48bf5SDavid du Colombier Srv fs = {
5953ff48bf5SDavid du Colombier 	.attach=	fsattach,
5963ff48bf5SDavid du Colombier 	.open=	fsopen,
5973ff48bf5SDavid du Colombier 	.read=	fsread,
5983ff48bf5SDavid du Colombier 	.write=	fswrite,
5993ff48bf5SDavid du Colombier 	.stat=	fsstat,
6003ff48bf5SDavid du Colombier 	.walk1=	fswalk1,
6013ff48bf5SDavid du Colombier };
6023ff48bf5SDavid du Colombier 
6033ff48bf5SDavid du Colombier char *mtpt = "/dev";
6043ff48bf5SDavid du Colombier char *srvname;
6053ff48bf5SDavid du Colombier 
6063ff48bf5SDavid du Colombier void
6073ff48bf5SDavid du Colombier usage(void)
6083ff48bf5SDavid du Colombier {
609*11e1fb05SDavid du Colombier 	fprint(2, "usage: aux/disksim [-D] [-f file] [-s srvname] [-m mtpt] [sdXX]\n");
6103ff48bf5SDavid du Colombier 	fprint(2, "\tdefault mtpt is /dev\n");
6113ff48bf5SDavid du Colombier 	exits("usage");
6123ff48bf5SDavid du Colombier }
6133ff48bf5SDavid du Colombier 
6143ff48bf5SDavid du Colombier void
6153ff48bf5SDavid du Colombier main(int argc, char **argv)
6163ff48bf5SDavid du Colombier {
617*11e1fb05SDavid du Colombier 	char *file;
618*11e1fb05SDavid du Colombier 
619*11e1fb05SDavid du Colombier 	file = nil;
6203ff48bf5SDavid du Colombier 	quotefmtinstall();
6213ff48bf5SDavid du Colombier 	time0 = time(0);
6223ff48bf5SDavid du Colombier 	if(NPTR != BLKSZ/sizeof(void*))
6233ff48bf5SDavid du Colombier 		sysfatal("unexpected pointer size");
6243ff48bf5SDavid du Colombier 
6253ff48bf5SDavid du Colombier 	ARGBEGIN{
6263ff48bf5SDavid du Colombier 	case 'D':
6273ff48bf5SDavid du Colombier 		chatty9p++;
6283ff48bf5SDavid du Colombier 		break;
629*11e1fb05SDavid du Colombier 	case 'f':
630*11e1fb05SDavid du Colombier 		file = EARGF(usage());
631*11e1fb05SDavid du Colombier 		break;
632*11e1fb05SDavid du Colombier 	case 'r':
633*11e1fb05SDavid du Colombier 		rdonly = 1;
634*11e1fb05SDavid du Colombier 		break;
6353ff48bf5SDavid du Colombier 	case 's':
6363ff48bf5SDavid du Colombier 		srvname = EARGF(usage());
6373ff48bf5SDavid du Colombier 		break;
6383ff48bf5SDavid du Colombier 	case 'm':
6393ff48bf5SDavid du Colombier 		mtpt = EARGF(usage());
6403ff48bf5SDavid du Colombier 		break;
6413ff48bf5SDavid du Colombier 	default:
6423ff48bf5SDavid du Colombier 		usage();
6433ff48bf5SDavid du Colombier 	}ARGEND
6443ff48bf5SDavid du Colombier 
6453ff48bf5SDavid du Colombier 	if(argc > 1)
6463ff48bf5SDavid du Colombier 		usage();
6473ff48bf5SDavid du Colombier 	if(argc == 1)
6483ff48bf5SDavid du Colombier 		sdname = argv[0];
6493ff48bf5SDavid du Colombier 
650*11e1fb05SDavid du Colombier 	if(file){
651*11e1fb05SDavid du Colombier 		if((fd = open(file, rdonly ? OREAD : ORDWR)) < 0)
652*11e1fb05SDavid du Colombier 			sysfatal("open %s: %r", file);
653*11e1fb05SDavid du Colombier 	}
654*11e1fb05SDavid du Colombier 
6553ff48bf5SDavid du Colombier 	inquiry = estrdup9p(inquiry);
6563ff48bf5SDavid du Colombier 	tab[0].name = estrdup9p("data");
6573ff48bf5SDavid du Colombier 	tab[0].inuse = 1;
6583ff48bf5SDavid du Colombier 	tab[0].mode = 0666;
6593ff48bf5SDavid du Colombier 
6603ff48bf5SDavid du Colombier 	postmountsrv(&fs, srvname, mtpt, MBEFORE);
6613ff48bf5SDavid du Colombier 	exits(nil);
6623ff48bf5SDavid du Colombier }
663