8 typedef struct Part Part;
9 typedef struct Trip Trip;
10 typedef struct Dbl Dbl;
11 typedef struct Ind Ind;
14 * with 8192-byte blocks and 4-byte pointers,
15 * double-indirect gets us 34 GB.
16 * triple-indirect gets us 70,368 GB.
22 BLKSZ = 1<<LOGBLKSZ, /* 8192 */
23 LOGNPTR = LOGBLKSZ-2, /* assume sizeof(void*) == 4 */
26 static uchar zero[BLKSZ];
51 vlong offset; /* in sectors */
52 vlong length; /* in sectors */
65 char *sdname = "sdXX";
67 char *inquiry = "aux/disksim hard drive";
68 vlong nsect, sectsize, c, h, s;
79 fmtprint(&fmt, "inquiry %s\n", inquiry);
80 fmtprint(&fmt, "geometry %lld %lld %lld %lld %lld\n", nsect, sectsize, c, h, s);
81 for(i=0; i<nelem(tab); i++)
83 fmtprint(&fmt, "part %s %lld %lld\n", tab[i].name, tab[i].offset, tab[i].length);
84 return fmtstrflush(&fmt);
88 addpart(char *name, vlong start, vlong end)
92 if(start < 0 || start > end || end > nsect){
93 werrstr("bad partition boundaries");
97 for(i=0; i<nelem(tab); i++)
101 werrstr("no free partition slots");
107 tab[i].name = estrdup9p(name);
108 tab[i].offset = start;
109 tab[i].length = end - start;
110 tab[i].mode = ctlmode;
121 for(i=0; i<nelem(tab); i++)
122 if(tab[i].inuse && strcmp(tab[i].name, s) == 0)
125 werrstr("partition not found");
142 r->ofcall.count = r->ifcall.count;
143 cb = parsecmd(r->ifcall.data, r->ifcall.count);
145 respond(r, "empty control message");
150 if(strcmp(cb->f[0], "part") == 0){
152 respondcmderror(r, cb, "part takes 3 args");
156 start = strtoll(cb->f[2], 0, 0);
157 end = strtoll(cb->f[3], 0, 0);
158 if(addpart(cb->f[1], start, end) < 0){
159 respondcmderror(r, cb, "%r");
164 else if(strcmp(cb->f[0], "delpart") == 0){
166 respondcmderror(r, cb, "delpart takes 1 arg");
170 if(delpart(cb->f[1]) < 0){
171 respondcmderror(r, cb, "%r");
176 else if(strcmp(cb->f[0], "inquiry") == 0){
178 respondcmderror(r, cb, "inquiry takes 1 arg");
183 inquiry = estrdup9p(cb->f[1]);
185 else if(strcmp(cb->f[0], "geometry") == 0){
187 respondcmderror(r, cb, "geometry takes 5 args");
191 nsect = strtoll(cb->f[1], 0, 0);
192 sectsize = strtoll(cb->f[2], 0, 0);
193 c = strtoll(cb->f[3], 0, 0);
194 h = strtoll(cb->f[4], 0, 0);
195 s = strtoll(cb->f[5], 0, 0);
196 if(tab[0].inuse && strcmp(tab[0].name, "data") == 0 && tab[0].vers == 0){
198 tab[0].length = nsect;
200 for(i=0; i<nelem(tab); i++){
201 if(tab[i].inuse && tab[i].offset+tab[i].length > nsect){
209 respondcmderror(r, cb, "unknown control message");
226 p = malloc(4*1024*1024);
228 sysfatal("out of memory");
234 memset(op, 0, BLKSZ);
235 if(fd != -1 && addr != -1)
236 pread(fd, op, BLKSZ, addr);
241 getblock(vlong addr, int alloc)
253 oaddr = addr<<LOGBLKSZ;
254 i0 = addr & (NPTR-1);
256 i1 = addr & (NPTR-1);
258 i2 = addr & (NPTR-1);
262 if((p2 = trip.dbl[i2]) == 0){
265 trip.dbl[i2] = p2 = allocblk(-1);
268 if((p1 = p2->ind[i1]) == 0){
271 p2->ind[i1] = p1 = allocblk(-1);
274 if((p0 = p1->blk[i0]) == 0){
277 p1->blk[i0] = p0 = allocblk(oaddr);
283 dirty(vlong addr, uchar *buf)
287 if(fd == -1 || rdonly)
289 oaddr = addr&~((vlong)BLKSZ-1);
290 if(pwrite(fd, buf, BLKSZ, oaddr) != BLKSZ)
291 sysfatal("write: %r");
295 rootgen(int off, Dir *d, void*)
297 memset(d, 0, sizeof *d);
301 d->name = estrdup9p(sdname);
302 d->mode = DMDIR|0777;
305 d->uid = estrdup9p("disksim");
306 d->gid = estrdup9p("disksim");
307 d->muid = estrdup9p("");
314 dirgen(int off, Dir *d, void*)
318 memset(d, 0, sizeof *d);
322 d->name = estrdup9p("ctl");
330 for(j=0; j<nelem(tab); j++){
334 d->name = estrdup9p(tab[j].name);
335 d->length = tab[j].length*sectsize;
336 d->mode = tab[j].mode;
337 d->qid.path = Qpart+j;
338 d->qid.vers = tab[j].vers;
346 d->uid = estrdup9p("disksim");
347 d->gid = estrdup9p("disksim");
348 d->muid = estrdup9p("");
353 evommem(void *a, void *b, ulong n)
355 return memmove(b, a, n);
359 isnonzero(void *v, ulong n)
377 long count, tot, n, o;
379 void *(*move)(void*, void*, ulong);
381 q = r->fid->qid.path-Qpart;
382 if(q < 0 || q > nelem(tab) || !tab[q].inuse || tab[q].vers != r->fid->qid.vers){
383 respond(r, "unknown partition");
388 offset = r->ifcall.offset;
389 count = r->ifcall.count;
391 respond(r, "negative offset");
395 respond(r, "negative count");
398 if(offset > p->length*sectsize){
399 respond(r, "offset past end of partition");
402 if(offset+count > p->length*sectsize)
403 count = p->length*sectsize - offset;
404 offset += p->offset*sectsize;
406 if(r->ifcall.type == Tread)
413 if(r->ifcall.type == Tread)
414 dat = (uchar*)r->ofcall.data;
416 dat = (uchar*)r->ifcall.data;
417 nonzero = isnonzero(dat, r->ifcall.count);
419 o = offset & (BLKSZ-1);
421 /* left fringe block */
423 blk = getblock(offset, r->ifcall.type==Twrite && nonzero);
427 if(r->ifcall.type != Twrite || blk != zero)
428 (*move)(dat, blk+o, n);
429 if(r->ifcall.type == Twrite)
433 /* full and right fringe blocks */
435 blk = getblock(offset+tot, r->ifcall.type==Twrite && nonzero);
439 if(r->ifcall.type != Twrite || blk != zero)
440 (*move)(dat+tot, blk, n);
441 if(r->ifcall.type == Twrite)
442 dirty(offset+tot, blk);
445 r->ofcall.count = tot;
455 switch((int)r->fid->qid.path){
457 dirread9p(r, rootgen, nil);
462 dirread9p(r, dirgen, nil);
482 switch((int)r->fid->qid.path){
485 respond(r, "write to a directory?");
501 if(r->ifcall.mode&ORCLOSE)
502 respond(r, "cannot open ORCLOSE");
504 switch((int)r->fid->qid.path){
507 if(r->ifcall.mode != OREAD){
508 respond(r, "bad mode for directory open");
524 memset(d, 0, sizeof *d);
525 d->qid = r->fid->qid;
526 d->atime = d->mtime = time0;
527 q = r->fid->qid.path;
530 d->name = estrdup9p("/");
531 d->mode = DMDIR|0777;
535 d->name = estrdup9p(sdname);
536 d->mode = DMDIR|0777;
541 if(q < 0 || q > nelem(tab) || tab[q].inuse==0 || r->fid->qid.vers != tab[q].vers){
542 respond(r, "partition no longer exists");
546 d->name = estrdup9p(p->name);
547 d->length = p->length * sectsize;
552 d->uid = estrdup9p("disksim");
553 d->gid = estrdup9p("disksim");
554 d->muid = estrdup9p("");
563 spec = r->ifcall.aname;
565 respond(r, "invalid attach specifier");
568 r->ofcall.qid = (Qid){Qroot, 0, QTDIR};
569 r->fid->qid = r->ofcall.qid;
574 fswalk1(Fid *fid, char *name, Qid *qid)
577 switch((int)fid->qid.path){
579 if(strcmp(name, sdname) == 0){
580 fid->qid.path = Qdir;
581 fid->qid.type = QTDIR;
587 if(strcmp(name, "ctl") == 0){
588 fid->qid.path = Qctl;
594 for(i=0; i<nelem(tab); i++){
595 if(tab[i].inuse && strcmp(tab[i].name, name) == 0){
596 fid->qid.path = i+Qpart;
597 fid->qid.vers = tab[i].vers;
605 return "file not found";
623 fprint(2, "usage: aux/disksim [-D] [-f file] [-s srvname] [-m mtpt] [sdXX]\n");
624 fprint(2, "\tdefault mtpt is /dev\n");
629 main(int argc, char **argv)
636 if(NPTR != BLKSZ/sizeof(void*))
637 sysfatal("unexpected pointer size");
644 file = EARGF(usage());
650 srvname = EARGF(usage());
653 mtpt = EARGF(usage());
665 if((fd = open(file, rdonly ? OREAD : ORDWR)) < 0)
666 sysfatal("open %s: %r", file);
669 inquiry = estrdup9p(inquiry);
670 tab[0].name = estrdup9p("data");
674 postmountsrv(&fs, srvname, mtpt, MBEFORE);