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 NPTR = BLKSZ/sizeof(void*),
25 static uchar zero[BLKSZ];
50 vlong offset; /* in sectors */
51 vlong length; /* in sectors */
64 char *sdname = "sdXX";
66 char *inquiry = "aux/disksim hard drive";
67 vlong nsect, sectsize, c, h, s;
78 fmtprint(&fmt, "inquiry %s\n", inquiry);
79 fmtprint(&fmt, "geometry %lld %lld %lld %lld %lld\n", nsect, sectsize, c, h, s);
80 for(i=0; i<nelem(tab); i++)
82 fmtprint(&fmt, "part %s %lld %lld\n", tab[i].name, tab[i].offset, tab[i].length);
83 return fmtstrflush(&fmt);
87 addpart(char *name, vlong start, vlong end)
91 if(start < 0 || start > end || end > nsect){
92 werrstr("bad partition boundaries");
96 for(i=0; i<nelem(tab); i++)
100 werrstr("no free partition slots");
106 tab[i].name = estrdup9p(name);
107 tab[i].offset = start;
108 tab[i].length = end - start;
109 tab[i].mode = ctlmode;
120 for(i=0; i<nelem(tab); i++)
121 if(tab[i].inuse && strcmp(tab[i].name, s) == 0)
124 werrstr("partition not found");
141 r->ofcall.count = r->ifcall.count;
142 cb = parsecmd(r->ifcall.data, r->ifcall.count);
144 respond(r, "empty control message");
149 if(strcmp(cb->f[0], "part") == 0){
151 respondcmderror(r, cb, "part takes 3 args");
155 start = strtoll(cb->f[2], 0, 0);
156 end = strtoll(cb->f[3], 0, 0);
157 if(addpart(cb->f[1], start, end) < 0){
158 respondcmderror(r, cb, "%r");
163 else if(strcmp(cb->f[0], "delpart") == 0){
165 respondcmderror(r, cb, "delpart takes 1 arg");
169 if(delpart(cb->f[1]) < 0){
170 respondcmderror(r, cb, "%r");
175 else if(strcmp(cb->f[0], "inquiry") == 0){
177 respondcmderror(r, cb, "inquiry takes 1 arg");
182 inquiry = estrdup9p(cb->f[1]);
184 else if(strcmp(cb->f[0], "geometry") == 0){
186 respondcmderror(r, cb, "geometry takes 5 args");
190 nsect = strtoll(cb->f[1], 0, 0);
191 sectsize = strtoll(cb->f[2], 0, 0);
192 c = strtoll(cb->f[3], 0, 0);
193 h = strtoll(cb->f[4], 0, 0);
194 s = strtoll(cb->f[5], 0, 0);
195 if(tab[0].inuse && strcmp(tab[0].name, "data") == 0 && tab[0].vers == 0){
197 tab[0].length = nsect;
199 for(i=0; i<nelem(tab); i++){
200 if(tab[i].inuse && tab[i].offset+tab[i].length > nsect){
208 respondcmderror(r, cb, "unknown control message");
225 p = malloc(4*1024*1024);
227 sysfatal("out of memory");
233 memset(op, 0, BLKSZ);
234 if(fd != -1 && addr != -1)
235 pread(fd, op, BLKSZ, addr);
240 getblock(vlong addr, int alloc)
252 oaddr = addr<<LOGBLKSZ;
261 if((p2 = trip.dbl[i2]) == 0){
264 trip.dbl[i2] = p2 = allocblk(-1);
267 if((p1 = p2->ind[i1]) == 0){
270 p2->ind[i1] = p1 = allocblk(-1);
273 if((p0 = p1->blk[i0]) == 0){
276 p1->blk[i0] = p0 = allocblk(oaddr);
282 dirty(vlong addr, uchar *buf)
286 if(fd == -1 || rdonly)
288 oaddr = addr&~((vlong)BLKSZ-1);
289 if(pwrite(fd, buf, BLKSZ, oaddr) != BLKSZ)
290 sysfatal("write: %r");
294 rootgen(int off, Dir *d, void*)
296 memset(d, 0, sizeof *d);
300 d->name = estrdup9p(sdname);
301 d->mode = DMDIR|0777;
304 d->uid = estrdup9p("disksim");
305 d->gid = estrdup9p("disksim");
306 d->muid = estrdup9p("");
313 dirgen(int off, Dir *d, void*)
317 memset(d, 0, sizeof *d);
321 d->name = estrdup9p("ctl");
329 for(j=0; j<nelem(tab); j++){
333 d->name = estrdup9p(tab[j].name);
334 d->length = tab[j].length*sectsize;
335 d->mode = tab[j].mode;
336 d->qid.path = Qpart+j;
337 d->qid.vers = tab[j].vers;
345 d->uid = estrdup9p("disksim");
346 d->gid = estrdup9p("disksim");
347 d->muid = estrdup9p("");
352 evommem(void *a, void *b, ulong n)
354 return memmove(b, a, n);
358 isnonzero(void *v, ulong n)
376 long count, tot, n, o;
378 void *(*move)(void*, void*, ulong);
380 q = r->fid->qid.path-Qpart;
381 if(q < 0 || q > nelem(tab) || !tab[q].inuse || tab[q].vers != r->fid->qid.vers){
382 respond(r, "unknown partition");
387 offset = r->ifcall.offset;
388 count = r->ifcall.count;
390 respond(r, "negative offset");
394 respond(r, "negative count");
397 if(offset > p->length*sectsize){
398 respond(r, "offset past end of partition");
401 if(offset+count > p->length*sectsize)
402 count = p->length*sectsize - offset;
403 offset += p->offset*sectsize;
405 if(r->ifcall.type == Tread)
412 if(r->ifcall.type == Tread)
413 dat = (uchar*)r->ofcall.data;
415 dat = (uchar*)r->ifcall.data;
416 nonzero = isnonzero(dat, r->ifcall.count);
418 o = offset & (BLKSZ-1);
420 /* left fringe block */
422 blk = getblock(offset, r->ifcall.type==Twrite && nonzero);
426 if(r->ifcall.type != Twrite || blk != zero)
427 (*move)(dat, blk+o, n);
428 if(r->ifcall.type == Twrite)
432 /* full and right fringe blocks */
434 blk = getblock(offset+tot, r->ifcall.type==Twrite && nonzero);
438 if(r->ifcall.type != Twrite || blk != zero)
439 (*move)(dat+tot, blk, n);
440 if(r->ifcall.type == Twrite)
441 dirty(offset+tot, blk);
444 r->ofcall.count = tot;
454 switch((int)r->fid->qid.path){
456 dirread9p(r, rootgen, nil);
461 dirread9p(r, dirgen, nil);
481 switch((int)r->fid->qid.path){
484 respond(r, "write to a directory?");
500 if(r->ifcall.mode&ORCLOSE)
501 respond(r, "cannot open ORCLOSE");
503 switch((int)r->fid->qid.path){
506 if(r->ifcall.mode != OREAD){
507 respond(r, "bad mode for directory open");
523 memset(d, 0, sizeof *d);
524 d->qid = r->fid->qid;
525 d->atime = d->mtime = time0;
526 q = r->fid->qid.path;
529 d->name = estrdup9p("/");
530 d->mode = DMDIR|0777;
534 d->name = estrdup9p(sdname);
535 d->mode = DMDIR|0777;
540 if(q < 0 || q > nelem(tab) || tab[q].inuse==0 || r->fid->qid.vers != tab[q].vers){
541 respond(r, "partition no longer exists");
545 d->name = estrdup9p(p->name);
546 d->length = p->length * sectsize;
551 d->uid = estrdup9p("disksim");
552 d->gid = estrdup9p("disksim");
553 d->muid = estrdup9p("");
562 spec = r->ifcall.aname;
564 respond(r, "invalid attach specifier");
567 r->ofcall.qid = (Qid){Qroot, 0, QTDIR};
568 r->fid->qid = r->ofcall.qid;
573 fswalk1(Fid *fid, char *name, Qid *qid)
576 switch((int)fid->qid.path){
578 if(strcmp(name, sdname) == 0){
579 fid->qid.path = Qdir;
580 fid->qid.type = QTDIR;
586 if(strcmp(name, "ctl") == 0){
587 fid->qid.path = Qctl;
593 for(i=0; i<nelem(tab); i++){
594 if(tab[i].inuse && strcmp(tab[i].name, name) == 0){
595 fid->qid.path = i+Qpart;
596 fid->qid.vers = tab[i].vers;
604 return "file not found";
622 fprint(2, "usage: aux/disksim [-D] [-f file] [-s srvname] [-m mtpt] [sdXX]\n");
623 fprint(2, "\tdefault mtpt is /dev\n");
628 main(int argc, char **argv)
641 file = EARGF(usage());
647 srvname = EARGF(usage());
650 mtpt = EARGF(usage());
662 if((fd = open(file, rdonly ? OREAD : ORDWR)) < 0)
663 sysfatal("open %s: %r", file);
666 inquiry = estrdup9p(inquiry);
667 tab[0].name = estrdup9p("data");
671 postmountsrv(&fs, srvname, mtpt, MBEFORE);