ref: 4974f11f7c2e917de605d02d5c07ad87c241ff80
dir: /gpufs.c/
#include <u.h> #include <libc.h> #include <fcall.h> #include <thread.h> #include <9p.h> #include <String.h> #include "vm.h" void usage(void) { fprint(2, "usage: %s [-d]\n", argv0); exits("usage"); } void* emalloc(int n) { void *v; v = emalloc9p(n); setmalloctag(v, getcallerpc(&n)); memset(v, 0, n); return v; } char* estrdup(char *s) { s = estrdup9p(s); setmalloctag(s, getcallerpc(&s)); return s; } enum { Qroot, Qrctl, Qobject, Qctl, Qbuffer, Qshader, }; static char *nametab[] = { "/", "ctl", nil, "ctl", "buffer", "shader", }; typedef struct Gpuobject Gpuobject; struct Gpuobject { Ref; int type; int id; }; typedef struct Gpufid Gpufid; struct Gpufid { int level; Gpuobject *object; }; static Gpuobject objects[256]; static int nobjects = 0; #define OBJECTID(c) ((int)(((Gpuobject*)(c)) - objects)) #define GO(c) ((Gpuobject*)(c)) String *fsqueue = nil; int debug = 0; static char *user; static long time0; u32int magic = 0x07230203; static void freeobject(Gpuobject *obj) { if (obj == nil || decref(obj)) return; memset(obj, 0, sizeof(*obj)); } static void* wfaux(Gpufid *f) { if (f->level < Qobject) return nil; return f->object; } static void fsmkqid(Qid *q, int level, void *aux) { q->type = 0; q->vers = 0; switch (level) { case Qroot: case Qobject: q->type = QTDIR; default: q->path = (level<<24) | (((uintptr)aux ^ time0) & 0x00ffffff); } } static void fsmkdir(Dir *d, int level, void *aux) { char buf[1024]; memset(d, 0, sizeof(*d)); fsmkqid(&d->qid, level, aux); d->mode = 0666; d->atime = d->mtime = time0; d->uid = estrdup(user); d->gid = estrdup(user); d->muid = estrdup(user); if (d->qid.type & QTDIR) d->mode |= DMDIR | 0111; switch (level) { case Qobject: snprint(buf, sizeof(buf), "%d", GO(aux)->id); d->name = estrdup(buf); break; case Qrctl: case Qctl: d->mode = 0666; d->name = estrdup(nametab[level]); break; case Qbuffer: d->length = getbufferlength(GO(aux)->id); d->mode = 0666; d->name = estrdup(nametab[level]); break; case Qshader: d->length = getshaderlength(GO(aux)->id); d->mode = 0666; d->name = estrdup(nametab[level]); break; default: d->name = estrdup(nametab[level]); } } static int rootgen(int i, Dir *d, void*) { i += Qroot + 1; if (i < Qobject) { fsmkdir(d, i, 0); return 0; } i -= Qobject; if (i < nobjects) { fsmkdir(d, Qobject, &objects[i]); return 0; } return -1; } static int objectgen(int i, Dir *d, void *aux) { i += Qobject + 1; fsmkdir(d, i, aux); // Qshader is last file in list if (i >= Qshader) return -1; return 0; } static void readrctl(Req *r) { readstr(r, s_to_c(fsqueue)); s_reset(fsqueue); } static void fsread(Req *r) { //char buf[1024]; Gpufid *f; f = r->fid->aux; switch (f->level) { case Qroot: dirread9p(r, rootgen, nil); respond(r, nil); return; case Qobject: dirread9p(r, objectgen, f->object); respond(r, nil); return; case Qrctl: readrctl(r); respond(r, nil); return; } respond(r, "not implemented"); } static void fsstart(Srv*) { fsqueue = s_new(); } static void fsend(Srv*) { postnote(PNGROUP, getpid(), "shutdown"); exits(nil); } static void fsattach(Req *r) { Gpufid *f; if (r->ifcall.aname && r->ifcall.aname[0]) { respond(r, "invalid attach specifier"); return; } f = emalloc(sizeof(*f)); f->level = Qroot; fsmkqid(&r->fid->qid, f->level, wfaux(f)); r->ofcall.qid = r->fid->qid; r->fid->aux = f; respond(r, nil); } static void fsstat(Req *r) { Gpufid *f; f = r->fid->aux; fsmkdir(&r->d, f->level, wfaux(f)); respond(r, nil); } static char* fswalk1(Fid *fid, char *name, Qid *qid) { Gpufid *f; int i, j; if (!(fid->qid.type & QTDIR)) return "walk in non-directory"; f = fid->aux; if (strcmp(name, "..") == 0) { switch (f->level) { case Qroot: break; case Qobject: freeobject(f->object); break; default: f->level = Qobject; } } else { for (i = f->level+1; i < nelem(nametab); i++) { if (nametab[i]) { if (strcmp(name, nametab[i]) == 0) break; } if (i == Qobject) { j = atoi(name); if (j >= 0 && j < nobjects) { f->object = &objects[j]; incref(f->object); break; } } } if (i >= nelem(nametab)) return "directory entry not found"; f->level = i; } fsmkqid(qid, f->level, wfaux(f)); fid->qid = *qid; return nil; } static void fsopen(Req *r) { respond(r, nil); } static int newshader(void) { int id = genshader(); if (id < 0) { return -1; } Gpuobject *o = &objects[nobjects]; memset(o, 0, sizeof(*o)); o->type = Qshader; o->id = id; char *s = smprint("s %d\n", o->id); s_append(fsqueue, s); free(s); nobjects++; return o->id; } static int newbuffer(long len) { int id = genbuffer(len); if (id < 0) { return -1; } Gpuobject *o = &objects[nobjects]; memset(o, 0, sizeof(*o)); o->type = Qbuffer; o->id = id; char *s = smprint("b %d\n", o->id); s_append(fsqueue, s); free(s); nobjects++; return o->id; } static void procrootcommand(Req *r, int argc, char **argv) { // n(ew) s(hader) // n(ew) b(uffer) <len> if (strcmp(argv[0], "n") == 0) { switch (argc) { case 2: if (strcmp(argv[1], "s") == 0) { if (newshader() < 0) respond(r, "error creating shader!"); else respond(r, nil); return; } break; case 3: if (strcmp(argv[1], "b") == 0) { long len = atol(argv[2]); if (newbuffer(len) < 0) respond(r, "error creating buffer!"); else respond(r, nil); return; } } } respond(r, "error: bad command!"); } static void rootcommand(Req *r, char *cmd) { char *lines[10]; int linec; linec = getfields(cmd, lines, 10, 1, "\n"); for (int i = 0; i < linec; i++) { char *c[10]; int num = getfields(lines[i], c, 10, 1, " \t"); procrootcommand(r, num, c); } } static void fswrite(Req *r) { Gpufid *f; int n; char *s; f = r->fid->aux; switch (f->level) { case Qrctl: n = r->ofcall.count = r->ifcall.count; s = emalloc(n+1); memmove(s, r->ifcall.data, n); rootcommand(r, s); return; } respond(r, "not implemented"); } static void fsdestroyfid(Fid *fid) { Gpufid *f; if (f = fid->aux) { fid->aux = nil; freeobject(f->object); free(f); } } static char* fsclone(Fid *oldfid, Fid *newfid) { Gpufid *f, *o; o = oldfid->aux; if (o == nil) return "bad fid"; f = emalloc(sizeof(*f)); memmove(f, o, sizeof(*f)); if (f->object) incref(f->object); newfid->aux = f; return nil; } Srv fs = { .start = fsstart, .attach = fsattach, .stat = fsstat, .walk1 = fswalk1, .clone = fsclone, .open = fsopen, .read = fsread, .write = fswrite, .destroyfid = fsdestroyfid, .end = fsend, }; void main(int argc, char **argv) { char *mtpt = "/mnt/gpu"; char *service = nil; time0 = time(0); user = getuser(); ARGBEGIN { case 'd': debug++; break; } ARGEND; rfork(RFNOTEG); postmountsrv(&fs, service, mtpt, MREPL); exits(nil); }