ref: 676c163887770438587b64aae2679a93ba836de2
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 Gpufid Gpufid;
struct Gpufid {
int level;
int id;
};
#define OBJECTID(c) (((Gpufid*)(c))->id)
String *fsqueue = nil;
int debug = 0;
static char *user;
static long time0;
u32int magic = 0x07230203;
static void*
wfaux(Gpufid *f)
{
if (f->level < Qobject)
return nil;
return f;
}
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), "%lld", (vlong)aux);
d->name = estrdup(buf);
return;
case Qrctl:
case Qctl:
break;
case Qbuffer:
d->length = getbufferlength(OBJECTID(aux));
break;
case Qshader:
d->length = getshaderlength(OBJECTID(aux));
break;
}
d->mode = 0666;
d->name = strdup(nametab[level]);
}
static int
rootgen(int i, Dir *d, void*)
{
vlong id;
i += Qroot + 1;
if (i < Qobject) {
fsmkdir(d, i, 0);
return 0;
}
i -= Qobject;
if (i < getnumobjects()) {
id = getobjectid(i);
if (id < 0) {
fprint(2, "error: %r\n");
return -1;
}
fsmkdir(d, Qobject, (void*)id);
return 0;
}
return -1;
}
static int
objectgen(int i, Dir *d, void *aux)
{
Gpufid *f;
i += Qobject + 1;
f = aux;
switch (i) {
case Qctl:
fsmkdir(d, Qctl, aux);
return 0;
case Qbuffer:
fsmkdir(d, getobjecttype(f->id) == BUFFER ? Qbuffer : Qshader, aux);
return 0;
}
return -1;
}
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);
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 < getnumobjects()) {
//f->object = &objects[j];
f->id = 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;
}
char *s = smprint("s %d\n", id);
s_append(fsqueue, s);
free(s);
return id;
}
static int
newbuffer(long len)
{
int id = genbuffer(len);
if (id < 0) {
return -1;
}
char *s = smprint("b %d\n", id);
s_append(fsqueue, s);
free(s);
return 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);
}