code: mafs

ref: b3ccded71dc0330ba63fdb7d7a0e6fc6ded1657e
dir: /mafs.c/

View raw version
#include	"all.h"
#include	"pool.h"

int	sfd;
int	cmdmode = 0660;
int	rfd;
int	chat;

Uid*	uid;
char*	uidspace;
short*	gidspace;
RWLock	mainlock;
Tlock	*tlocks;
char	*progname;
char	*procname;

char *devfile = nil;	/* device file path */
char service[Namelen] = "\0";
u8	noauth = 0;
u8	readonly = 0;
u8	shuttingdown = 0;
extern u64 npendingwrites;		/* write throttling */

int	writeallow;	/* never on; for compatibility with fs */
int	wstatallow;
int	writegroup;
int	allownone;
static void	usage(void);
static void	printsizes(void);
static u64	memsize(void);
Config config = {0};

static void
usage(void)
{
	fprint(2, "usage: mafs [-Ds] [-r service] [-n service] [-m nmemunits] [-h nbuckets] [-w npendingwrites] [-a announce-string]... file\n");
	exits("usage");
}

void
main(int argc, char **argv)
{
	static char *nets[8];
	int doream, stdio, netc;
	char buf[Namelen];
	int pid, ctl;
	u64 nmemunits, size;

	progname = "mafs";
	procname = "init";

	/* mainmem->flags |= POOL_PARANOIA|POOL_LOGGING; */

	/*
	 * insulate from invoker's environment and keep it from swapping
	 */
	rfork(RFNAMEG|RFNOTEG|RFREND);

	nbuckets = 0;
	npendingwrites = 0;
	nmemunits = 0;
	sfd = -1;
	doream = stdio = netc = 0;

	pid = getpid();
	snprint(buf, sizeof buf, "/proc/%d/ctl", pid);
	ctl = open(buf, OWRITE);
	fprint(ctl, "noswap\n");
	close(ctl);

	ARGBEGIN{
	default:	usage();
	case 'D':	chatty9p++; break;
	case 'f':	devfile = ARGF(); break;
	case 'h':	nbuckets = atoll(EARGF(usage())); break;
	case 'w':	npendingwrites = atoll(EARGF(usage())); break;
	case 'm':	nmemunits = atoll(EARGF(usage())); break;
	case 'r':
		doream = 1;
		/* fall through */
	case 'n':
		snprint(service, Namelen, "%s", EARGF(usage()));
		break;
	case 's':	stdio++;    break;
	case 'a':
		if(netc >= nelem(nets)-1){
			fprint(2, "%s: too many networks to announce\n", argv0);
			exits("too many nets");
		}
		nets[netc++] = estrdup9p(EARGF(usage()));
		break;
	}ARGEND

	if(argc != 1 || (doream && service[0] == '\0'))
		usage();

	devfile = argv[0];
	if(devfile == nil)
		sysfatal("no disk file");

	if (access(devfile, AREAD|AWRITE) == -1)
		sysfatal("%s cannot access device", devfile);

	size = devinit(devfile);
	if(size == 0)
		panic("null size %s", devfile);

	/* 2/3rds of the memory for the pending writes
		and 1/3rd for the buffer cache */
	if(nmemunits == 0)
		nmemunits = size/Rawblocksize > 8*MiB ? 8*MiB : size/Rawblocksize;
	if(nmemunits < KiB)
		nmemunits = KiB;
	if(npendingwrites == 0)
		npendingwrites = 2*nmemunits/3;
	if(nbuckets == 0)
		nbuckets = nmemunits/(3*Ncollisions);

	if(chatty9p){
		dprint("\nPlan 9 %d-bit file server with %d-deep indirect blocks\n",
			sizeof(u64)*8, Niblock);
		printsizes();
		dprint("nmemunits %llud npendingwrites %llud nbuckets %llud\n",
				nmemunits, npendingwrites, nbuckets);
	}

	formatinit();

	initmemunitpool(nmemunits);
	initextents(&frees);

	tlocks = emalloc9p(NTLOCK * sizeof *tlocks);
	initwriter();
	iobufinit();

	/*
	 * init the file system, ream it if needed, and get the block sizes.
	 * service = config.service, if service is nil.
	 */
	init(doream, size);
	if(service[0] == '\0')
		snprint(service, Namelen, "%s", config.service);

	start9p(nets, stdio);
	/*
		we have started another proc to process /srv/service
		and it is my time to exit
	 */
	exits(nil);
}

static
struct
{
	int	nfilter;
	Filter*	filters[100];
}f;

int alarmed;

void
catchalarm(void *regs, char *msg)
{
	USED(regs, msg);
	if(strcmp(msg, "alarm") == 0){
		alarmed = 1;
		noted(NCONT);
	} else
		noted(NDFLT);
}

void
dofilter(Filter *ft)
{
	int i;

	i = f.nfilter;
	if(i >= sizeof f.filters / sizeof f.filters[0]) {
		dprint("dofilter: too many filters\n");
		return;
	}
	f.filters[i] = ft;
	f.nfilter = i+1;
}

static u64
memsize(void)
{
	char *p, buf[128];
	int fd, n, by2pg, secs;

	by2pg = 4*1024;
	p = getenv("cputype");
	if(p && strcmp(p, "68020") == 0)
		by2pg = 8*1024;

	secs = 4*1024*1024;
	
	fd = open("/dev/swap", OREAD);
	if(fd < 0)
		return secs;
	n = read(fd, buf, sizeof(buf)-1);
	close(fd);
	if(n <= 0)
		return secs;
	buf[n] = 0;
	p = strchr(buf, '/');
	if(p)
		secs = strtoul(p+1, 0, 0)*by2pg;
	return secs;
}

/*
 * compute BUFSIZE*(Ndblock+INDPERBUF+INDPERBUF²+INDPERBUF³+INDPERBUF⁴ .. upto ^Niblock)
 * while watching for overflow; in that case, return 0.
 */

static u64
maxsize(void)
{
	int i;
	uvlong max = Ndblock, ind;

	dprint("maxsize direct spans max %llud\n", max);
	for (i = 0; i < Niblock; i++) {
		ind = nperiblock(Tind0+i);
		max += ind;
		dprint("maxsize %s %llud max %llud\n", tagnames[Tind0+i], ind, max);
	}
	return max;
}

/* also in tests/sizes.c */
static void
printsizes(void)
{
	int i;
	u64 n, max;

	dprint("Namelen %d Ndblock %d Niblock %d\n", Namelen, Ndblock, Niblock);
	dprint("Blocksize %d Nindperblock %d\n",
			Blocksize, Nindperblock);

	for (i = Tind0; i < Maxtind; i++) {
		n = nperindunit(i);
		dprint("A %s unit points to %lld data spans (%llud bytes)\n",
			 tagnames[i], n, n*Blocksize);
		dprint("	block points to %lld data spans\n", nperiblock(i));
	}
	dprint("sizeof(Dentry1) %d Namelen %d\n",
			sizeof(Dentry1), Namelen);
	max = maxsize();
	dprint("maximum possible spans %llud\n", max);
	dprint("	(%llud*Rawblocksize = %llud bytes = %llud TiB)\n",
			max, max*Rawblocksize, (max*Rawblocksize)/(MiB*MiB));
}