henesyinit from lsubb0c8bdb6 years agoHistory
554 lines · 10.7 KB · C
RawDownload
/* * Plan B volume file system server. * * Is Plan B safe? * * When used as directed, Plan B is safe for most women.  There have been * no serious complications associated with Plan B. Common side effects * include nausea, abdominal pain, fatigue, headache, and menstrual * changes.  Women who are pregnant, have undiagnosed vaginal bleeding, * or have an allergy to the product should not use Plan B. Plan B cannot * terminate an established pregnancy * * How effective is Plan B? * * Taken within 72 hours of unprotected intercourse, Plan B can, when * used correctly, reduce the risk of pregnancy by 89 percent after a * single act of unprotected sex.  Effectiveness declines as the interval * between intercourse and the start of treatment increases. * * http://www.go2planb.com * * How to use Plan B? * * This replaces the old vold (with the discovery protocol) * and the kernel volume mechanism. * * When supplied a volume spec it provides * a file tree that corresponds to a volume instance, which one, * it depends on the set of volumes known. * * This translates the client RPCs to RPCs for the appropriate fs. * Using the local kernel as a client was beareable but a bit slow. * * 5.48u 4.30s 49.72r 	 mk at /sys/src/9/pc volfs * 5.45u 5.40s 43.68r 	 mk at /sys/src/9/pc planb 3rd ed. */  #include <u.h>#include <libc.h>#include <fcall.h>#include <bio.h>#include <ip.h>#include <thread.h>#include <pool.h>#include <auth.h>#include "names.h"#include "vols.h" typedef struct Work Work; struct Work {	Frpc*	rpc;	// being serviced	int	nrpcs;	// serviced	Channel*c;	// where to send requests};  int	debug, vdebug; /* general debug (xtra if > 1); volume debug */ static int	srvfd = -1;static int	ctlfd = -1;static Channel*	reqc;static Channel*	repc;static Channel*	tmrc; static char*	sname;static char*	csname; static int	dodiscover; static Work	work[Nthreads];static char*	adsaddr; /* When feasible, we use the client's Frpc to issue all * our rpcs to the server. This means that some routines * in volfs.c and in vols.c receive an fop parameter. * (A benefit of this is that we can use the client tags * as our tags for RPCs made to servers. Another benefit * is that we avoid extra allocation of Frpcs.) * Beware that such routines will overwrite whatever * is in the fop to issue appropriate rpcs. However, * tag is guaranteed to remain untouched. */static QLock	rpclck;static Frpc*	freerpcs;static int	nrpcs;	// #rpcs allocated.  Frpc*rpcalloc(void){	int	x[1];	Frpc*	m;	Channel*sc; 	qlock(&rpclck);	if (freerpcs == nil){		nrpcs++;		m = emalloc(sizeof(Frpc));		setmalloctag(m, getcallerpc(x+2));		memset(m, 0, sizeof(Frpc));		m->sc = chancreate(sizeof(ulong), 0);	} else {		m = freerpcs;		freerpcs = m->next;		sc = m->sc;		memset(m, 0, sizeof(Frpc));		m->sc = sc;	}	if (nrpcs > Nrpcs && !(nrpcs%20))		fprint(2, "%s: warning: #%d allocated rpcs\n", argv0, nrpcs);	qunlock(&rpclck);	return m;} voidrpcfree(Frpc* m){	if (m == nil)		return;	if (m->time == 0xbbbb){		fprint(2, "rpcfree: double free for %p\n", m);		abort();	}	m->time = 0xbbbb;	rpcfree(m->rep);	m->rep = nil;	qlock(&rpclck);	free(m->d);	m->d = nil;	m->next = freerpcs;	freerpcs = m;	qunlock(&rpclck);} static voidflushtag(int tag){	static int nflushed;	int	i; 	for (i = 0; i < nelem(work); i++){		if (work[i].rpc && work[i].rpc->f.tag == tag)			break;	}	if (i == nelem(work)){		dprint(2, "flush: no tag %d (%d flushes)\n", tag, nflushed++);		return;	}	work[i].rpc->flushed = 1;	work[i].rpc->time = 0;} static voidworkthread(void* a){	Work*	w = a;	Frpc*	m; 	threadsetname("work");	while(m = recvp(w->c)){		w->nrpcs++;		assert(m->f.type >= 0 && m->f.type < Tmax);		assert(fscalls[m->f.type]); 		w->rpc = m;		fscalls[m->f.type](m);		if (m->f.type == Tflush)			flushtag(m->f.oldtag);		sendp(repc, m);		w->rpc = nil;	}	threadexits(nil);} static voidreplythread(void *){	Frpc*	m;	Fid*	df; 	threadsetname("replythread");	df = emalloc(sizeof(Fid));	while(m = recvp(repc)){		if (m->fid && m->fid->debug)			df->debug = m->fid->debug;		else			df->debug = 0;		fidfree(m->freefid, m);		if (m->flushed){			dprint(2, "flushed reply (type %d, tag %d) ignored\n",				m->r.type, m->r.tag);		} else {			m->fid = df;			if (putfrep(srvfd, m) < 0)				fprint(2, "%s: reply: %r\n", argv0);		}		rpcfree(m);	}	sysfatal("no output process");} static voiddiscover(char* addr){	static char*	raddr = nil;	static int	fd = -1;	char	dir[50];	NetConnInfo*ni; 	if (fd < 0)		if (raddr != nil)			fd = dial(netmkaddr(raddr, nil, "ads"), 0, 0, 0);		else			fd = dial(netmkaddr(addr, nil, "ads"), 0, dir, 0);	if (fd < 0){		fprint(2, "%s: %s: %r\n", argv0, addr);	} else {		if (raddr == nil){			ni = getnetconninfo(dir, fd);			if (ni != nil){				raddr = estrdup(ni->raddr);				free(ni);			}		}		// This print is ignored by old protocol		// the new one uses it as a request to dump announces.		if (fprint(fd, "PlanB announces\n") < 0){			close(fd);			fd = -1;			// We'll try reopening next time they call us.		} else			fdconfig(fd, addr);	}}  static voidtimerthread(void*){	ulong now;	ulong last; 	threadsetname("timers");	last = 0;	for(;;){		now = recvul(tmrc);		fstimer(now);		if (dodiscover && adsaddr && now - last > Disctick){			discover(adsaddr);			last = time(nil);		}	}} static voidstats(void){	int	i;	int	nused; 	fprint(2, "%d rpcs allocated %d workers ", nrpcs, nelem(work));	nused = 0;	for (i = 0; i < nelem(work); i++){		if (work[i].nrpcs)			nused++;	}	fprint(2, "%d idle\n", nelem(work) - nused);} static voidctlproc(void*){	static Biobuf	bcmd;	char*	ln;	char*	c; 	threadsetname("ctlproc");	Binit(&bcmd, ctlfd, OREAD);	while(ln = Brdstr(&bcmd, '\n', 1)){		switch(ln[0]){		case 'V':			fprint(2, "Debug dump:\n");			dumpvols();			dumpfss();			dumpmvols();			dumpfids();			break;		case 'S':			fprint(2, "Debug dump:\n");			stats();			fsstats();			break;		case 'D':			debug = vdebug = 0;			for(c = ln+1; *c; c++)				switch(*c){				case 'n':					break;				case 'D':					debug = 2;					break;				case 'd':					debug = 1;					break;				case 'v':					vdebug = 1;					break;				}			break;		case 'T':			c = strchr(ln+1, ' ');			if (c)				*c = 0;			c = strchr(ln+1, '\n');			if (c)				*c = 0;			if (ln[1] == 'T')				tracemvol(ln+2, 2);			else				tracemvol(ln+1, 1);			break;		case 'N':			tracemvol(nil, 0);			break;		default:			cmdline(ln, "/srv/volctl", 0);		}		free(ln);	}	Bterm(&bcmd);	exits(nil);} static voiddispatchproc(void*){	Frpc*	m;	int	i;	int	rr;	Frpc*	fop; 	threadsetname("dispatcher");	for (i = 0; i < Nthreads; i++)		threadcreate(workthread, work+i, Wstack);	threadcreate(replythread, nil, Stack);	threadcreate(timerthread, nil, Stack);	rr = 0;	fop = rpcalloc();	fop->f.tag = 1;	while(m = recvp(reqc)){		checkvols(fop);		for (i = 0; i < Nthreads; i++){			if (work[i].rpc == nil){				sendp(work[i].c, m);				break;			}		}		if (i == Nthreads){			dprint(2, "%s: all workers busy\n", argv0);			sendp(work[rr].c, m);			rr = (rr + 1) % Nthreads;		}	}	threadexits(nil);} static voidtimerproc(void*){	ulong	now; 	threadsetname("timerproc");	for(;;){		sleep(Tmout*1000);		now = time(nil);		nbsendul(tmrc, now);	// time does not block!	}} static voidsrvinproc(void *){	Frpc*	m; 	threadsetname("srvinproc");	for(;;){		m = rpcalloc();		if (getfcall(srvfd, m) <= 0){			rpcfree(m);			fprint(2, "%s: getfcall: %r\n", argv0);			break;		}		sendp(reqc, m);	}	sysfatal("no input process");} static char*mkadsaddr(void){	char*	r;	char*	s; 	s = getenv("fileserver");	if (s == nil)		return smprint("tcp!193.147.71.86!11010");	r =  smprint("tcp!%s!11010", s);	free(s);	return r;} /* To prevent deadlocks, bns runs with just this:  * /mnt/factotum /net /dev /env and /srv */ static voidcleanns(void){	int	fd; 	if (bind("#/", "/", MREPL) < 0)		fprint(2, "FAIL> bind /: %r\n");	fd = open("#s/factotum", ORDWR);	mount(fd, -1, "/mnt", MREPL|MCREATE, "");	close(fd);	if (bind("#I","/net",  MAFTER) < 0)		fprint(2, "cannot bind /net: %r\n");	if (access("/net/tcp/clone", AEXIST) < 0)		fprint(2, "NO TCP\n");	if (bind("#c","/dev",  MREPL|MCREATE) < 0)		fprint(2, "cannot bind /dev: %r\n");	if (bind("#s","/srv",  MREPL|MCREATE) < 0)		fprint(2, "cannot bind /srv: %r\n");	if (bind("#r","/dev",  MAFTER|MCREATE) < 0)		fprint(2, "cannot bind #r: %r\n");	bind("#e","/env",  MREPL|MCREATE);} static voidmainproc(void* a){	int	fd[2];	int	cfd[2];	int	i;	Channel*c = a; 	threadsetname("mainproc");	cleanns();	config(nil);	if (pipe(fd)<0 || pipe(cfd) < 0)		sysfatal("pipe: %r");	if (postfd(sname, fd[0]) < 0)		sysfatal("can't post srv: %s: %r", sname);	csname = smprint("%sctl", sname);	if (postfd(csname, cfd[0]) < 0)		sysfatal("can't post srv: %s: %r", csname);	rfork(RFFDG);	close(fd[0]);	close(cfd[0]);	srvfd = fd[1];	ctlfd = cfd[1];	reqc = chancreate(sizeof(Frpc*), 0);	for (i = 0; i < Nthreads; i++)		work[i].c = chancreate(sizeof(Frpc*), 0);	repc = chancreate(sizeof(Frpc*), 5);	tmrc = chancreate(sizeof(ulong), 0);	assert(reqc && repc);	if (proccreate(ctlproc, nil, Stack) < 0)		sysfatal("procrfork: %r");	if (proccreate(timerproc, nil, Stack) < 0)		sysfatal("procrfork: %r");	if (proccreate(srvinproc, nil, Stack) < 0)		sysfatal("procrfork: %r");	if (proccreate(dispatchproc, nil, Stack) < 0)		sysfatal("procrfork: %r");	free(csname);	sendul(c, 0);	threadexits(nil);}  static voidusage(void){	fprint(2,"usage: %s [-DHdv] [-l] [-s srv]\n", argv0);	exits("usage");} voidthreadmain(int argc, char *argv[]){	Channel*	sc;	int		domnt;	extern int 	newnsdebug; 	sname = "vol";	adsaddr = nil;	domnt = 1;	ARGBEGIN {

Lines 1–500 of 554.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t