887 lines · 14.2 KB · C
RawDownload
#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.