#include <u.h>#include <libc.h>#include <stdio.h>#include <fcall.h>#include <thread.h>#include <9p.h> #include "dat.h"#include "fns.h" int casl(ulong *addr, ulong ov, ulong nv); #define DEFPERM 0650#define CHANSZ 0 /* by default the channel is unbuffered */#define MAXFILES 256#define MAXFSIZE 64 * 1024#define RSTOP 1#define WSTOP 2#define CTLMAX 1024 static char Enotimpl[] = "dchan: not implemented";static char Enotperm[] = "dchan: operation not permitted";static char Ewrfail[] = "dchan: write failed"; static char Eintern[] = "dchan: internal error";static char Ebadspec[] = "dchan: bad attach specification";static char Eexist[] = "dchan: file already exists";static char Enotowner[] = "dchan: not owner";static char Ebadoff[] = "dchan: bad file offset or count";static char Elocked[] = "dchan: file locked";static char Emaxfiles[] = "dchan: Maximum number of files reached: 256";static char Ectlfmt[] = "dchan: Invalid ctl config format.";static char Enotfound[] = "dchan: ctl write failed. Target file not found.";static char Edir[] = "dchan: invalid operation for directory.";static char Edirnotempty[] = "dchan: directory not empty.";static char Edirdeep[] = "dchan: directory too deep."; static FauxList *files = nil;QLock filelk;static Ctl ctl; intwaitforctl(int src){ DBG("Sending message of stopping. %d\n", src); int err = sendul(ctl.rwok, src); if(err != 1) return 0; recvul(ctl.done); /* block the caller until config is updated */ return 1;} voidfilestats(void *arg){ Faux *aux; long t; aux = arg; for(t = 0;; t+=60) { sleep(1000); qlock(&aux->slock); aux->rx = aux->nreads; aux->tx = aux->nwrites; if(aux->avgtx == 0) aux->avgtx = aux->tx; else if(aux->tx > 0) aux->avgtx = (aux->avgtx + aux->tx)/2; if(aux->avgrx == 0) aux->avgrx = aux->rx; else if(aux->rx > 0) aux->avgrx = (aux->avgrx + aux->rx)/2; qunlock(&aux->slock); casl(&aux->nreads, aux->nreads, 0); /* TODO: err handling */ casl(&aux->nwrites, aux->nwrites, 0); /* TODO: err handling */ }} voidfsattach(Req *r){ char *spec; spec = r->ifcall.aname; if(spec && spec[0]){ respond(r, Ebadspec); return; } r->fid->qid = r->srv->tree->root->qid; r->ofcall.qid = r->fid->qid; respond(r, nil);} voidreadersetname(Faux *aux, char *fn, char *name){ if(aux->rthreadname[0] == 0){ snprintf(aux->rthreadname, THNAMESZ, "dchan: %s in file %s", fn, name); threadsetname(aux->rthreadname); }} voidwritersetname(Faux *aux, char *fn, char *name){ if(aux->wthreadname[0] == 0){ snprintf(aux->wthreadname, THNAMESZ, "dchan: %s in file %s", fn, name); threadsetname(aux->wthreadname); }} voidsyncread(Req *r){ Faux *faux; Data *d; ulong offset; int onctl; faux = r->fid->file->aux; if(faux == nil) sysfatal("syncread: faux is nil."); readersetname(faux, "syncread", r->fid->file->name); Recv: d = recvp(faux->chan); if(d == nil) { /* recv failed, client interrupted, disconnected or ctl is being updated*/ qlock(&ctl.l); onctl = ctl.onctl; qunlock(&ctl.l); if(onctl){ if(!waitforctl(RSTOP)) goto RecvFail; goto Recv; } RecvFail: /* no respond here */ return; } offset = r->ifcall.offset; r->ifcall.offset = 0; DBG("Recv: %s\n", d->val); readbuf(r, d->val, d->valsz); r->ifcall.offset = offset; free(d->val); free(d); accessfile(r->fid->file, AREAD); ainc((long *)&faux->nreads); DBG("fsread: Reporting a success read: (%s):(count: %d)(offset: %d)\n", r->ofcall.data, r->ofcall.count, (int)r->ofcall.offset); respond(r, nil);} void readctl(Req *r){ int total = 0, written; Faux *aux; FauxList *l; char *buffer = nil; char line[1024]; qlock(&filelk); for(l = files; l; l = l->next) { assert(l != nil); aux = l->aux; memset(line, 0, sizeof line); qlock(&aux->slock); /* sync with filestats() */ written = snprintf(line, 1024, "%s\t%d\t%ld\t%ld\t%ld\t%ld\n", aux->fullpath, aux->chansize, aux->rx, aux->tx, aux->avgrx, aux->avgtx); qunlock(&aux->slock); buffer = realloc(buffer, total + written + 1); if(!buffer) sysfatal("Failed to allocate memory.\n"); memset(buffer+total, 0, written + 1); buffer = strcat(buffer, line); total += written; } qunlock(&filelk); if(buffer) { readstr(r, buffer); free(buffer); } else { readstr(r, ""); } respond(r, nil);} intfilldata(Data *d, Req *r){ d->valsz = r->ifcall.count; d->val = mallocz(sizeof(char) * (d->valsz + 1), 1); if(!d->val) return -1; d->val = memcpy(d->val, r->ifcall.data, d->valsz); d->val[d->valsz] = 0; return 0;} voidsyncwrite(Req *r){ Faux *faux; Data *d; int err, onctl; d = mallocz(sizeof *d, 1); if(!d) goto Enomem; faux = r->fid->file->aux; if(faux == nil) sysfatal("syncwrite: faux is nil."); writersetname(faux, "syncwrite", r->fid->file->name); /* copy request into data */ if(filldata(d, r) == -1) goto Enomem; r->ofcall.count = d->valsz; /* store valsz now because after sendp return the value will be freed by syncread */ Send: err = sendp(faux->chan, d); /* now d is an invalid pointer, free'd in another coroutine */ if(err != 1) { DBG("Sendp failed: %d\n", err); if(err == -1){ qlock(&ctl.l); onctl = ctl.onctl; qunlock(&ctl.l); if(onctl){ DBG("ONCTL: waiting for ctl complete the task\n"); if(!waitforctl(WSTOP)) goto SendFail; goto Send; } } SendFail: DBG("Sendp really failed.\n"); /* data does not arrived in the other side, we need to release memory here */ free(d->val); free(d); /* does not respond anything, flush will do the job */ return; } /* success write */ accessfile(r->fid->file, AWRITE); ainc((long *)&faux->nwrites); respond(r, nil); return; Enomem: respond(r, Eintern);} Faux *getfileaux(char *name){ Faux *tmp; FauxList *l; if(files == nil) return nil; qlock(&filelk); for(l = files; l; l = l->next){ tmp = l->aux; if(strcmp(tmp->fullpath, name) == 0) { qunlock(&filelk); return tmp; } } qunlock(&filelk); return nil;} char *updatecfg(char *filename, int chansize){ Faux *taux; int op, err, i; Channel *chan; taux = getfileaux(filename); if(taux == nil){ return Enotfound; } qlock(&ctl.l); ctl.onctl = 1; qunlock(&ctl.l); chan = chancreate(sizeof(void *), chansize); if(!chan) sysfatal("failed to allocate channel"); /* close the channel of target file */ chanclose(taux->chan); /* no one can open files while updating cfg */ qlock(&taux->openl); if(taux->open > 0) { for(i = 0; i < 2; i++){ err = recv(ctl.rwok, &op); if(err == -1){ qunlock(&taux->openl); return Eintern; } if(op == WSTOP) DBG("Thread writer stopped.\n"); else if(op == RSTOP) DBG("Thread reader stopped.\n"); } } /* we're ready to update channel */ chanfree(taux->chan); taux->chan = chan; taux->chansize = chansize; qlock(&ctl.l); ctl.onctl = 0; qunlock(&ctl.l); /* notify the reader and writer threads */ if(taux->open > 0) if( sendul(ctl.done, 1) == -1 || sendul(ctl.done, 1) == -1){ qunlock(&taux->openl); return Eintern; } qunlock(&taux->openl); return nil;} voidwritectl(Req *r){ char line[CTLMAX]; char *err = nil, *name, *buf, *buf2; int chansize; memset(line, 0, CTLMAX); if(r->ifcall.count >= CTLMAX){ respond(r, Ectlfmt); return; } memcpy(line, r->ifcall.data, r->ifcall.count); name = line; while(buf = strchr(name, ' ')){ if(buf == nil){ respond(r, Ectlfmt); return; } buf[0] = '\0'; buf++; buf2 = strchr(buf, '\n'); if(buf2 != nil){ buf2[0] = '\0'; buf2++; } chansize = atoi(buf); /* returns 0 if buf is not a number */ if((err = updatecfg(name, chansize)) != nil) break; if(buf2 == nil) break; name = buf2; } if(err != nil) respond(r, err); else respond(r, nil);} voidfsread(Req *r){ Faux *faux = r->fid->file->aux; void *callb = syncread; if(faux == nil) sysfatal("aux is nil"); if(faux->ftype == Xdir){ respond(r, Edir); return; } if(faux->ftype == Xctl) callb = readctl; reqqueuepush(faux->rq, r, callb);} voidfswrite(Req *r){ Faux *faux = r->fid->file->aux; void *callb = syncwrite; if(faux == nil) sysfatal("aux is nil"); if(faux->ftype == Xdir){ respond(r, Edir); return; } if(faux->ftype == Xctl) callb = writectl; reqqueuepush(faux->wq, r, callb);} voidfscreate(Req *r){ File *f; Faux *faux; Channel *chan; FauxList *fl; char *path; f = createfile(r->fid->file, r->ifcall.name, r->fid->uid, DEFPERM|r->ifcall.perm, nil); if(f) { path = fullpath(f);Lines 1–500 of 887. Load more
#include <u.h> #include <libc.h> #include <stdio.h> #include <fcall.h> #include <thread.h> #include <9p.h> #include "dat.h" #include "fns.h" int casl(ulong *addr, ulong ov, ulong nv); #define DEFPERM 0650 #define CHANSZ 0 /* by default the channel is unbuffered */ #define MAXFILES 256 #define MAXFSIZE 64 * 1024 #define RSTOP 1 #define WSTOP 2 #define CTLMAX 1024 static char Enotimpl[] = "dchan: not implemented"; static char Enotperm[] = "dchan: operation not permitted"; static char Ewrfail[] = "dchan: write failed"; static char Eintern[] = "dchan: internal error"; static char Ebadspec[] = "dchan: bad attach specification"; static char Eexist[] = "dchan: file already exists"; static char Enotowner[] = "dchan: not owner"; static char Ebadoff[] = "dchan: bad file offset or count"; static char Elocked[] = "dchan: file locked"; static char Emaxfiles[] = "dchan: Maximum number of files reached: 256"; static char Ectlfmt[] = "dchan: Invalid ctl config format."; static char Enotfound[] = "dchan: ctl write failed. Target file not found."; static char Edir[] = "dchan: invalid operation for directory."; static char Edirnotempty[] = "dchan: directory not empty."; static char Edirdeep[] = "dchan: directory too deep."; static FauxList *files = nil; QLock filelk; static Ctl ctl; int waitforctl(int src) { DBG("Sending message of stopping. %d\n", src); int err = sendul(ctl.rwok, src); if(err != 1) return 0; recvul(ctl.done); /* block the caller until config is updated */ return 1; } void filestats(void *arg) { Faux *aux; long t; aux = arg; for(t = 0;; t+=60) { sleep(1000); qlock(&aux->slock); aux->rx = aux->nreads; aux->tx = aux->nwrites; if(aux->avgtx == 0) aux->avgtx = aux->tx; else if(aux->tx > 0) aux->avgtx = (aux->avgtx + aux->tx)/2; if(aux->avgrx == 0) aux->avgrx = aux->rx; else if(aux->rx > 0) aux->avgrx = (aux->avgrx + aux->rx)/2; qunlock(&aux->slock); casl(&aux->nreads, aux->nreads, 0); /* TODO: err handling */ casl(&aux->nwrites, aux->nwrites, 0); /* TODO: err handling */ } } void fsattach(Req *r) { char *spec; spec = r->ifcall.aname; if(spec && spec[0]){ respond(r, Ebadspec); return; } r->fid->qid = r->srv->tree->root->qid; r->ofcall.qid = r->fid->qid; respond(r, nil); } void readersetname(Faux *aux, char *fn, char *name) { if(aux->rthreadname[0] == 0){ snprintf(aux->rthreadname, THNAMESZ, "dchan: %s in file %s", fn, name); threadsetname(aux->rthreadname); } } void writersetname(Faux *aux, char *fn, char *name) { if(aux->wthreadname[0] == 0){ snprintf(aux->wthreadname, THNAMESZ, "dchan: %s in file %s", fn, name); threadsetname(aux->wthreadname); } } void syncread(Req *r) { Faux *faux; Data *d; ulong offset; int onctl; faux = r->fid->file->aux; if(faux == nil) sysfatal("syncread: faux is nil."); readersetname(faux, "syncread", r->fid->file->name); Recv: d = recvp(faux->chan); if(d == nil) { /* recv failed, client interrupted, disconnected or ctl is being updated*/ qlock(&ctl.l); onctl = ctl.onctl; qunlock(&ctl.l); if(onctl){ if(!waitforctl(RSTOP)) goto RecvFail; goto Recv; } RecvFail: /* no respond here */ return; } offset = r->ifcall.offset; r->ifcall.offset = 0; DBG("Recv: %s\n", d->val); readbuf(r, d->val, d->valsz); r->ifcall.offset = offset; free(d->val); free(d); accessfile(r->fid->file, AREAD); ainc((long *)&faux->nreads); DBG("fsread: Reporting a success read: (%s):(count: %d)(offset: %d)\n", r->ofcall.data, r->ofcall.count, (int)r->ofcall.offset); respond(r, nil); } void readctl(Req *r) { int total = 0, written; Faux *aux; FauxList *l; char *buffer = nil; char line[1024]; qlock(&filelk); for(l = files; l; l = l->next) { assert(l != nil); aux = l->aux; memset(line, 0, sizeof line); qlock(&aux->slock); /* sync with filestats() */ written = snprintf(line, 1024, "%s\t%d\t%ld\t%ld\t%ld\t%ld\n", aux->fullpath, aux->chansize, aux->rx, aux->tx, aux->avgrx, aux->avgtx); qunlock(&aux->slock); buffer = realloc(buffer, total + written + 1); if(!buffer) sysfatal("Failed to allocate memory.\n"); memset(buffer+total, 0, written + 1); buffer = strcat(buffer, line); total += written; } qunlock(&filelk); if(buffer) { readstr(r, buffer); free(buffer); } else { readstr(r, ""); } respond(r, nil); } int filldata(Data *d, Req *r) { d->valsz = r->ifcall.count; d->val = mallocz(sizeof(char) * (d->valsz + 1), 1); if(!d->val) return -1; d->val = memcpy(d->val, r->ifcall.data, d->valsz); d->val[d->valsz] = 0; return 0; } void syncwrite(Req *r) { Faux *faux; Data *d; int err, onctl; d = mallocz(sizeof *d, 1); if(!d) goto Enomem; faux = r->fid->file->aux; if(faux == nil) sysfatal("syncwrite: faux is nil."); writersetname(faux, "syncwrite", r->fid->file->name); /* copy request into data */ if(filldata(d, r) == -1) goto Enomem; r->ofcall.count = d->valsz; /* store valsz now because after sendp return the value will be freed by syncread */ Send: err = sendp(faux->chan, d); /* now d is an invalid pointer, free'd in another coroutine */ if(err != 1) { DBG("Sendp failed: %d\n", err); if(err == -1){ qlock(&ctl.l); onctl = ctl.onctl; qunlock(&ctl.l); if(onctl){ DBG("ONCTL: waiting for ctl complete the task\n"); if(!waitforctl(WSTOP)) goto SendFail; goto Send; } } SendFail: DBG("Sendp really failed.\n"); /* data does not arrived in the other side, we need to release memory here */ free(d->val); free(d); /* does not respond anything, flush will do the job */ return; } /* success write */ accessfile(r->fid->file, AWRITE); ainc((long *)&faux->nwrites); respond(r, nil); return; Enomem: respond(r, Eintern); } Faux * getfileaux(char *name) { Faux *tmp; FauxList *l; if(files == nil) return nil; qlock(&filelk); for(l = files; l; l = l->next){ tmp = l->aux; if(strcmp(tmp->fullpath, name) == 0) { qunlock(&filelk); return tmp; } } qunlock(&filelk); return nil; } char * updatecfg(char *filename, int chansize) { Faux *taux; int op, err, i; Channel *chan; taux = getfileaux(filename); if(taux == nil){ return Enotfound; } qlock(&ctl.l); ctl.onctl = 1; qunlock(&ctl.l); chan = chancreate(sizeof(void *), chansize); if(!chan) sysfatal("failed to allocate channel"); /* close the channel of target file */ chanclose(taux->chan); /* no one can open files while updating cfg */ qlock(&taux->openl); if(taux->open > 0) { for(i = 0; i < 2; i++){ err = recv(ctl.rwok, &op); if(err == -1){ qunlock(&taux->openl); return Eintern; } if(op == WSTOP) DBG("Thread writer stopped.\n"); else if(op == RSTOP) DBG("Thread reader stopped.\n"); } } /* we're ready to update channel */ chanfree(taux->chan); taux->chan = chan; taux->chansize = chansize; qlock(&ctl.l); ctl.onctl = 0; qunlock(&ctl.l); /* notify the reader and writer threads */ if(taux->open > 0) if( sendul(ctl.done, 1) == -1 || sendul(ctl.done, 1) == -1){ qunlock(&taux->openl); return Eintern; } qunlock(&taux->openl); return nil; } void writectl(Req *r) { char line[CTLMAX]; char *err = nil, *name, *buf, *buf2; int chansize; memset(line, 0, CTLMAX); if(r->ifcall.count >= CTLMAX){ respond(r, Ectlfmt); return; } memcpy(line, r->ifcall.data, r->ifcall.count); name = line; while(buf = strchr(name, ' ')){ if(buf == nil){ respond(r, Ectlfmt); return; } buf[0] = '\0'; buf++; buf2 = strchr(buf, '\n'); if(buf2 != nil){ buf2[0] = '\0'; buf2++; } chansize = atoi(buf); /* returns 0 if buf is not a number */ if((err = updatecfg(name, chansize)) != nil) break; if(buf2 == nil) break; name = buf2; } if(err != nil) respond(r, err); else respond(r, nil); } void fsread(Req *r) { Faux *faux = r->fid->file->aux; void *callb = syncread; if(faux == nil) sysfatal("aux is nil"); if(faux->ftype == Xdir){ respond(r, Edir); return; } if(faux->ftype == Xctl) callb = readctl; reqqueuepush(faux->rq, r, callb); } void fswrite(Req *r) { Faux *faux = r->fid->file->aux; void *callb = syncwrite; if(faux == nil) sysfatal("aux is nil"); if(faux->ftype == Xdir){ respond(r, Edir); return; } if(faux->ftype == Xctl) callb = writectl; reqqueuepush(faux->wq, r, callb); } void fscreate(Req *r) { File *f; Faux *faux; Channel *chan; FauxList *fl; char *path; f = createfile(r->fid->file, r->ifcall.name, r->fid->uid, DEFPERM|r->ifcall.perm, nil); if(f) { path = fullpath(f);