123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676 |
- #include <u.h>
- #include <libc.h>
- #include <auth.h>
- #include <fcall.h>
- #include <thread.h>
- #include <9p.h>
- typedef struct Part Part;
- typedef struct Trip Trip;
- typedef struct Dbl Dbl;
- typedef struct Ind Ind;
- /*
- * with 8192-byte blocks and 4-byte pointers,
- * double-indirect gets us 34 GB.
- * triple-indirect gets us 70,368 GB.
- */
- enum
- {
- LOGBLKSZ = 13,
- BLKSZ = 1<<LOGBLKSZ, /* 8192 */
- LOGNPTR = LOGBLKSZ-2, /* assume sizeof(void*) == 4 */
- NPTR = 1<<LOGNPTR,
- };
- static uchar zero[BLKSZ];
- struct Trip
- {
- Dbl *dbl[NPTR];
- };
- struct Dbl
- {
- Ind *ind[NPTR];
- };
- struct Ind
- {
- uchar *blk[NPTR];
- };
- Trip trip;
- struct Part
- {
- int inuse;
- int vers;
- ulong mode;
- char *name;
- vlong offset; /* in sectors */
- vlong length; /* in sectors */
- };
- enum
- {
- Qroot = 0,
- Qdir,
- Qctl,
- Qpart,
- };
- Part tab[64];
- int fd = -1;
- char *sdname = "sdXX";
- ulong ctlmode = 0666;
- char *inquiry = "aux/disksim hard drive";
- vlong nsect, sectsize, c, h, s;
- ulong time0;
- int rdonly;
- char*
- ctlstring(void)
- {
- int i;
- Fmt fmt;
- fmtstrinit(&fmt);
- fmtprint(&fmt, "inquiry %s\n", inquiry);
- fmtprint(&fmt, "geometry %lld %lld %lld %lld %lld\n", nsect, sectsize, c, h, s);
- for(i=0; i<nelem(tab); i++)
- if(tab[i].inuse)
- fmtprint(&fmt, "part %s %lld %lld\n", tab[i].name, tab[i].offset, tab[i].length);
- return fmtstrflush(&fmt);
- }
- int
- addpart(char *name, vlong start, vlong end)
- {
- int i;
- if(start < 0 || start > end || end > nsect){
- werrstr("bad partition boundaries");
- return -1;
- }
- for(i=0; i<nelem(tab); i++)
- if(tab[i].inuse == 0)
- break;
- if(i == nelem(tab)){
- werrstr("no free partition slots");
- return -1;
- }
- free(tab[i].name);
- tab[i].inuse = 1;
- tab[i].name = estrdup9p(name);
- tab[i].offset = start;
- tab[i].length = end - start;
- tab[i].mode = ctlmode;
- tab[i].vers++;
- return 0;
- }
- int
- delpart(char *s)
- {
- int i;
- for(i=0; i<nelem(tab); i++)
- if(tab[i].inuse && strcmp(tab[i].name, s) == 0)
- break;
- if(i==nelem(tab)){
- werrstr("partition not found");
- return -1;
- }
- tab[i].inuse = 0;
- free(tab[i].name);
- tab[i].name = 0;
- return 0;
- }
- void
- ctlwrite(Req *r)
- {
- int i;
- Cmdbuf *cb;
- vlong start, end;
- r->ofcall.count = r->ifcall.count;
- cb = parsecmd(r->ifcall.data, r->ifcall.count);
- if(cb->nf < 1){
- respond(r, "empty control message");
- free(cb);
- return;
- }
- if(strcmp(cb->f[0], "part") == 0){
- if(cb->nf != 4){
- respondcmderror(r, cb, "part takes 3 args");
- free(cb);
- return;
- }
- start = strtoll(cb->f[2], 0, 0);
- end = strtoll(cb->f[3], 0, 0);
- if(addpart(cb->f[1], start, end) < 0){
- respondcmderror(r, cb, "%r");
- free(cb);
- return;
- }
- }
- else if(strcmp(cb->f[0], "delpart") == 0){
- if(cb->nf != 2){
- respondcmderror(r, cb, "delpart takes 1 arg");
- free(cb);
- return;
- }
- if(delpart(cb->f[1]) < 0){
- respondcmderror(r, cb, "%r");
- free(cb);
- return;
- }
- }
- else if(strcmp(cb->f[0], "inquiry") == 0){
- if(cb->nf != 2){
- respondcmderror(r, cb, "inquiry takes 1 arg");
- free(cb);
- return;
- }
- free(inquiry);
- inquiry = estrdup9p(cb->f[1]);
- }
- else if(strcmp(cb->f[0], "geometry") == 0){
- if(cb->nf != 6){
- respondcmderror(r, cb, "geometry takes 5 args");
- free(cb);
- return;
- }
- nsect = strtoll(cb->f[1], 0, 0);
- sectsize = strtoll(cb->f[2], 0, 0);
- c = strtoll(cb->f[3], 0, 0);
- h = strtoll(cb->f[4], 0, 0);
- s = strtoll(cb->f[5], 0, 0);
- if(tab[0].inuse && strcmp(tab[0].name, "data") == 0 && tab[0].vers == 0){
- tab[0].offset = 0;
- tab[0].length = nsect;
- }
- for(i=0; i<nelem(tab); i++){
- if(tab[i].inuse && tab[i].offset+tab[i].length > nsect){
- tab[i].inuse = 0;
- free(tab[i].name);
- tab[i].name = 0;
- }
- }
- }
- else{
- respondcmderror(r, cb, "unknown control message");
- free(cb);
- return;
- }
- free(cb);
- respond(r, nil);
- }
-
- void*
- allocblk(vlong addr)
- {
- uchar *op;
- static uchar *p;
- static ulong n;
- if(n == 0){
- p = malloc(4*1024*1024);
- if(p == 0)
- sysfatal("out of memory");
- n = 4*1024*1024;
- }
- op = p;
- p += BLKSZ;
- n -= BLKSZ;
- memset(op, 0, BLKSZ);
- if(fd != -1 && addr != -1)
- pread(fd, op, BLKSZ, addr);
- return op;
- }
- uchar*
- getblock(vlong addr, int alloc)
- {
- Dbl *p2;
- Ind *p1;
- uchar *p0;
- uint i0, i1, i2;
- vlong oaddr;
- if(fd >= 0)
- alloc = 1;
- addr >>= LOGBLKSZ;
- oaddr = addr<<LOGBLKSZ;
- i0 = addr & (NPTR-1);
- addr >>= LOGNPTR;
- i1 = addr & (NPTR-1);
- addr >>= LOGNPTR;
- i2 = addr & (NPTR-1);
- addr >>= LOGNPTR;
- assert(addr == 0);
- if((p2 = trip.dbl[i2]) == 0){
- if(!alloc)
- return zero;
- trip.dbl[i2] = p2 = allocblk(-1);
- }
- if((p1 = p2->ind[i1]) == 0){
- if(!alloc)
- return zero;
- p2->ind[i1] = p1 = allocblk(-1);
- }
- if((p0 = p1->blk[i0]) == 0){
- if(!alloc)
- return zero;
- p1->blk[i0] = p0 = allocblk(oaddr);
- }
- return p0;
- }
- void
- dirty(vlong addr, uchar *buf)
- {
- vlong oaddr;
- if(fd == -1 || rdonly)
- return;
- oaddr = addr&~((vlong)BLKSZ-1);
- if(pwrite(fd, buf, BLKSZ, oaddr) != BLKSZ)
- sysfatal("write: %r");
- }
-
- int
- rootgen(int off, Dir *d, void*)
- {
- memset(d, 0, sizeof *d);
- d->atime = time0;
- d->mtime = time0;
- if(off == 0){
- d->name = estrdup9p(sdname);
- d->mode = DMDIR|0777;
- d->qid.path = Qdir;
- d->qid.type = QTDIR;
- d->uid = estrdup9p("disksim");
- d->gid = estrdup9p("disksim");
- d->muid = estrdup9p("");
- return 0;
- }
- return -1;
- }
-
- int
- dirgen(int off, Dir *d, void*)
- {
- int n, j;
- memset(d, 0, sizeof *d);
- d->atime = time0;
- d->mtime = time0;
- if(off == 0){
- d->name = estrdup9p("ctl");
- d->mode = ctlmode;
- d->qid.path = Qctl;
- goto Have;
- }
- off--;
- n = 0;
- for(j=0; j<nelem(tab); j++){
- if(tab[j].inuse==0)
- continue;
- if(n == off){
- d->name = estrdup9p(tab[j].name);
- d->length = tab[j].length*sectsize;
- d->mode = tab[j].mode;
- d->qid.path = Qpart+j;
- d->qid.vers = tab[j].vers;
- goto Have;
- }
- n++;
- }
- return -1;
- Have:
- d->uid = estrdup9p("disksim");
- d->gid = estrdup9p("disksim");
- d->muid = estrdup9p("");
- return 0;
- }
- void*
- evommem(void *a, void *b, ulong n)
- {
- return memmove(b, a, n);
- }
- int
- isnonzero(void *v, ulong n)
- {
- uchar *a, *ea;
-
- a = v;
- ea = a+n;
- for(; a<ea; a++)
- if(*a)
- return 1;
- return 0;
- }
- int
- rdwrpart(Req *r)
- {
- int q, nonzero;
- Part *p;
- vlong offset;
- long count, tot, n, o;
- uchar *blk, *dat;
- void *(*move)(void*, void*, ulong);
- q = r->fid->qid.path-Qpart;
- if(q < 0 || q > nelem(tab) || !tab[q].inuse || tab[q].vers != r->fid->qid.vers){
- respond(r, "unknown partition");
- return -1;
- }
- p = &tab[q];
- offset = r->ifcall.offset;
- count = r->ifcall.count;
- if(offset < 0){
- respond(r, "negative offset");
- return -1;
- }
- if(count < 0){
- respond(r, "negative count");
- return -1;
- }
- if(offset > p->length*sectsize){
- respond(r, "offset past end of partition");
- return -1;
- }
- if(offset+count > p->length*sectsize)
- count = p->length*sectsize - offset;
- offset += p->offset*sectsize;
- if(r->ifcall.type == Tread)
- move = memmove;
- else
- move = evommem;
- tot = 0;
- nonzero = 1;
- if(r->ifcall.type == Tread)
- dat = (uchar*)r->ofcall.data;
- else{
- dat = (uchar*)r->ifcall.data;
- nonzero = isnonzero(dat, r->ifcall.count);
- }
- o = offset & (BLKSZ-1);
- /* left fringe block */
- if(o && count){
- blk = getblock(offset, r->ifcall.type==Twrite && nonzero);
- n = BLKSZ - o;
- if(n > count)
- n = count;
- if(r->ifcall.type != Twrite || blk != zero)
- (*move)(dat, blk+o, n);
- if(r->ifcall.type == Twrite)
- dirty(offset, blk);
- tot += n;
- }
- /* full and right fringe blocks */
- while(tot < count){
- blk = getblock(offset+tot, r->ifcall.type==Twrite && nonzero);
- n = BLKSZ;
- if(n > count-tot)
- n = count-tot;
- if(r->ifcall.type != Twrite || blk != zero)
- (*move)(dat+tot, blk, n);
- if(r->ifcall.type == Twrite)
- dirty(offset+tot, blk);
- tot += n;
- }
- r->ofcall.count = tot;
- respond(r, nil);
- return 0;
- }
- void
- fsread(Req *r)
- {
- char *s;
- switch((int)r->fid->qid.path){
- case Qroot:
- dirread9p(r, rootgen, nil);
- respond(r, nil);
- break;
- case Qdir:
- dirread9p(r, dirgen, nil);
- respond(r, nil);
- break;
- case Qctl:
- s = ctlstring();
- readstr(r, s);
- free(s);
- respond(r, nil);
- break;
- default:
- rdwrpart(r);
- break;
- }
- }
- void
- fswrite(Req *r)
- {
- switch((int)r->fid->qid.path){
- case Qroot:
- case Qdir:
- respond(r, "write to a directory?");
- break;
- case Qctl:
- ctlwrite(r);
- break;
- default:
- rdwrpart(r);
- break;
- }
- }
- void
- fsopen(Req *r)
- {
- if(r->ifcall.mode&ORCLOSE)
- respond(r, "cannot open ORCLOSE");
- switch((int)r->fid->qid.path){
- case Qroot:
- case Qdir:
- if(r->ifcall.mode != OREAD){
- respond(r, "bad mode for directory open");
- return;
- }
- }
- respond(r, nil);
- }
- void
- fsstat(Req *r)
- {
- int q;
- Dir *d;
- Part *p;
- d = &r->d;
- memset(d, 0, sizeof *d);
- d->qid = r->fid->qid;
- d->atime = d->mtime = time0;
- q = r->fid->qid.path;
- switch(q){
- case Qroot:
- d->name = estrdup9p("/");
- d->mode = DMDIR|0777;
- break;
- case Qdir:
- d->name = estrdup9p(sdname);
- d->mode = DMDIR|0777;
- break;
- default:
- q -= Qpart;
- if(q < 0 || q > nelem(tab) || tab[q].inuse==0 || r->fid->qid.vers != tab[q].vers){
- respond(r, "partition no longer exists");
- return;
- }
- p = &tab[q];
- d->name = estrdup9p(p->name);
- d->length = p->length * sectsize;
- d->mode = p->mode;
- break;
- }
-
- d->uid = estrdup9p("disksim");
- d->gid = estrdup9p("disksim");
- d->muid = estrdup9p("");
- respond(r, nil);
- }
- void
- fsattach(Req *r)
- {
- char *spec;
- spec = r->ifcall.aname;
- if(spec && spec[0]){
- respond(r, "invalid attach specifier");
- return;
- }
- r->ofcall.qid = (Qid){Qroot, 0, QTDIR};
- r->fid->qid = r->ofcall.qid;
- respond(r, nil);
- }
- char*
- fswalk1(Fid *fid, char *name, Qid *qid)
- {
- int i;
- switch((int)fid->qid.path){
- case Qroot:
- if(strcmp(name, sdname) == 0){
- fid->qid.path = Qdir;
- fid->qid.type = QTDIR;
- *qid = fid->qid;
- return nil;
- }
- break;
- case Qdir:
- if(strcmp(name, "ctl") == 0){
- fid->qid.path = Qctl;
- fid->qid.vers = 0;
- fid->qid.type = 0;
- *qid = fid->qid;
- return nil;
- }
- for(i=0; i<nelem(tab); i++){
- if(tab[i].inuse && strcmp(tab[i].name, name) == 0){
- fid->qid.path = i+Qpart;
- fid->qid.vers = tab[i].vers;
- fid->qid.type = 0;
- *qid = fid->qid;
- return nil;
- }
- }
- break;
- }
- return "file not found";
- }
- Srv fs = {
- .attach= fsattach,
- .open= fsopen,
- .read= fsread,
- .write= fswrite,
- .stat= fsstat,
- .walk1= fswalk1,
- };
- char *mtpt = "/dev";
- char *srvname;
- void
- usage(void)
- {
- fprint(2, "usage: aux/disksim [-D] [-f file] [-s srvname] [-m mtpt] [sdXX]\n");
- fprint(2, "\tdefault mtpt is /dev\n");
- exits("usage");
- }
- void
- main(int argc, char **argv)
- {
- char *file;
- file = nil;
- quotefmtinstall();
- time0 = time(0);
- if(NPTR != BLKSZ/sizeof(void*))
- sysfatal("unexpected pointer size");
- ARGBEGIN{
- case 'D':
- chatty9p++;
- break;
- case 'f':
- file = EARGF(usage());
- break;
- case 'r':
- rdonly = 1;
- break;
- case 's':
- srvname = EARGF(usage());
- break;
- case 'm':
- mtpt = EARGF(usage());
- break;
- default:
- usage();
- }ARGEND
- if(argc > 1)
- usage();
- if(argc == 1)
- sdname = argv[0];
- if(file){
- if((fd = open(file, rdonly ? OREAD : ORDWR)) < 0)
- sysfatal("open %s: %r", file);
- }
- inquiry = estrdup9p(inquiry);
- tab[0].name = estrdup9p("data");
- tab[0].inuse = 1;
- tab[0].mode = 0666;
- postmountsrv(&fs, srvname, mtpt, MBEFORE);
- exits(nil);
- }
|