Charles.Forsyth20060303644188019 years agoHistory
605 lines · 10.7 KB · C
RawDownload
/* * (file system) device subsystems * '#k'.  * Follows device config in Ken's file server. * Builds mirrors, device cats, interleaving, and partition of devices out of * other (inner) devices. * * This code is from Plan 9, and subject to the Lucent Public License 1.02. * Only the name changed for Inferno (name clash). */ #include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "ureg.h"#include "../port/error.h" enum {	Fmirror,	// mirror of others	Fcat,		// catenation of others	Finter,		// interleaving of others	Fpart,		// part of others 	Blksize	= 8*1024,	// for Finter only	Maxconf	= 1024,		// max length for config 	Nfsdevs = 64,	Ndevs	= 8, 	Qtop	= 0,	// top dir (contains "ds")	Qdir	= 1,	// actual dir	Qctl	= 2,	// ctl file	Qfirst	= 3,	// first fs file}; #define	Cfgstr	"fsdev:\n" typedef struct Fsdev Fsdev; struct Fsdev{	int	type;	char	*name;		// name for this fsdev	vlong	start;		// start address (for Fpart)	vlong	size;		// min(idev sizes)	int	ndevs;		// number of inner devices	char	*iname[Ndevs];	// inner device names	Chan	*idev[Ndevs];	// inner devices	vlong	isize[Ndevs];	// sizes for inneer devices}; /* * Once configured, a fsdev is never removed. The name of those * configured is never nil. We have no locks here. */static Fsdev	fsdev[Nfsdevs]; static Qid	tqid = {Qtop, 0, QTDIR};static Qid	dqid = {Qdir, 0, QTDIR};static Qid	cqid = {Qctl, 0, 0}; static Cmdtab configs[] = {	Fmirror,"mirror",	0,	Fcat,	"cat",		0,	Finter,	"inter",	0,	Fpart,	"part",		5,}; static char	confstr[Maxconf];static int	configed;  static Fsdev*path2dev(int i, int mustexist){	if (i < 0 || i >= nelem(fsdev))		error("bug: bad index in devfsdev");	if (mustexist && fsdev[i].name == nil)		error(Enonexist); 	if (fsdev[i].name == nil)		return nil;	else		return &fsdev[i];} static Fsdev*devalloc(void){	int	i; 	for (i = 0; i < nelem(fsdev); i++)		if (fsdev[i].name == nil)			break;	if (i == nelem(fsdev))		error(Enodev); 	return &fsdev[i];} static voidsetdsize(Fsdev* mp){	uchar	buf[128];	/* old DIRLEN plus a little should be plenty */	int	i;	Chan	*mc;	Dir	d;	long	l; 	if (mp->type != Fpart){		mp->start= 0;		mp->size = 0LL;	}	for (i = 0; i < mp->ndevs; i++){		mc = mp->idev[i];		l = devtab[mc->type]->stat(mc, buf, sizeof(buf));		convM2D(buf, l, &d, nil);		mp->isize[i] = d.length;		switch(mp->type){		case Fmirror:			if (mp->size == 0LL || mp->size > d.length)				mp->size = d.length;			break;		case Fcat:			mp->size += d.length;			break;		case Finter:			// truncate to multiple of Blksize			d.length = (d.length & ~(Blksize-1));			mp->isize[i] = d.length;			mp->size += d.length;			break;		case Fpart:			// should raise errors here?			if (mp->start > d.length)				mp->start = d.length;			if (d.length < mp->start + mp->size)				mp->size = d.length - mp->start;			break;		}	}} static voidmpshut(Fsdev *mp){	int	i;	char	*nm; 	nm = mp->name;	mp->name = nil;		// prevent others from using this.	if (nm)		free(nm);	for (i = 0; i < mp->ndevs; i++){		if (mp->idev[i] != nil)			cclose(mp->idev[i]);		if (mp->iname[i])			free(mp->iname[i]);	}	memset(mp, 0, sizeof(*mp));}  static voidmconfig(char* a, long n)	// "name idev0 idev1"{	static	QLock	lck;	Cmdbuf	*cb;	Cmdtab	*ct;	Fsdev	*mp;	int	i;	char	*oldc;	char	*c;	vlong	size, start; 	size = 0;	start = 0;	if (confstr[0] == 0)		seprint(confstr, confstr+sizeof(confstr), Cfgstr);	oldc = confstr + strlen(confstr);	qlock(&lck);	if (waserror()){		*oldc = 0;		qunlock(&lck);		nexterror();	}	cb = parsecmd(a, n);	if(waserror()){		free(cb);		nexterror();	}	c = oldc;	for (i = 0; i < cb->nf; i++)		c = seprint(c, confstr+sizeof(confstr), "%s ", cb->f[i]);	*(c-1) = '\n';	ct = lookupcmd(cb, configs, nelem(configs));	cb->f++;	// skip command	cb->nf--;	if (ct->index == Fpart){		size = strtoll(cb->f[3], nil, 10);		cb->nf--;		start = strtoll(cb->f[2], nil, 10);		cb->nf--;	}	for (i = 0; i < nelem(fsdev); i++)		if (fsdev[i].name != nil && strcmp(fsdev[i].name, cb->f[0])==0)			error(Eexist);	if (cb->nf - 1 > Ndevs)		error("too many devices; fix me");	for (i = 0; i < cb->nf; i++)		validname(cb->f[i], (i != 0));	mp = devalloc();	if(waserror()){		mpshut(mp);		nexterror();	}	mp->type = ct->index;	if (mp->type == Fpart){		mp->size = size;		mp->start = start;	}	kstrdup(&mp->name, cb->f[0]);	for (i = 1; i < cb->nf; i++){		kstrdup(&mp->iname[i-1], cb->f[i]);		mp->idev[i-1] = namec(mp->iname[i-1], Aopen, ORDWR, 0);		if (mp->idev[i-1] == nil)			error(Egreg);		mp->ndevs++;	}	setdsize(mp);	poperror();	free(cb);	poperror();	poperror();	configed = 1;	qunlock(&lck);	} static voidrdconf(void){	int	mustrd;	char	*s;	char	*c;	char	*p;	char	*e;	Chan	*cc; 	s = getconf("fsconfig");	if (s == nil){		mustrd = 0;		s = "/dev/sdC0/fscfg";	} else		mustrd = 1;	if (waserror()){		configed = 1;		if (!mustrd)			return;		nexterror();	}	cc = namec(s, Aopen, OREAD, 0);	if(waserror()){		cclose(cc);		nexterror();	}	devtab[cc->type]->read(cc, confstr, sizeof(confstr), 0);	poperror();	cclose(cc);	if (strncmp(confstr, Cfgstr, strlen(Cfgstr)) != 0)		error("config string must start with `fsdev:'");	kstrdup(&c, confstr + strlen(Cfgstr));	if(waserror()){		free(c);		nexterror();	}	memset(confstr, 0, sizeof(confstr));	for (p = c; p != nil && *p != 0; p = e){		e = strchr(p, '\n');		if (e == p){			e++;			continue;		}		if (e == nil)			e = p + strlen(p);		mconfig(p, e - p);	}	poperror();	poperror();}  static intmgen(Chan *c, char*, Dirtab*, int, int i, Dir *dp){	Qid	qid;	Fsdev	*mp; 	if (c->qid.path == Qtop){		switch(i){		case DEVDOTDOT:			devdir(c, tqid, "#k", 0, eve, DMDIR|0775, dp);			return 1;		case 0:			devdir(c, dqid, "ds", 0, eve, DMDIR|0775, dp);			return 1;		default:			return -1;		}	}	if (c->qid.path != Qdir){		switch(i){		case DEVDOTDOT:			devdir(c, dqid, "ds", 0, eve, DMDIR|0775, dp);			return 1;		default:			return -1;		}	}	switch(i){	case DEVDOTDOT:		devdir(c, tqid, "#k", 0, eve, DMDIR|0775, dp);		return 1;	case 0:		devdir(c, cqid, "ctl", 0, eve, 0664, dp);		return 1;	}	i--;	// for ctl	qid.path = Qfirst + i;	qid.vers = 0;	qid.type = 0;	mp = path2dev(i, 0);	if (mp == nil)		return -1;	kstrcpy(up->genbuf, mp->name, sizeof(up->genbuf));	devdir(c, qid, up->genbuf, mp->size, eve, 0664, dp);	return 1;} static Chan*mattach(char *spec){	*confstr = 0;	return devattach(L'k', spec);} static Walkqid*mwalk(Chan *c, Chan *nc, char **name, int nname){	if (!configed)		rdconf();	return devwalk(c, nc, name, nname, 0, 0, mgen);} static intmstat(Chan *c, uchar *db, int n){	Dir	d;	Fsdev	*mp;	int	p; 	p = c->qid.path;	memset(&d, 0, sizeof(d));	switch(p){	case Qtop:		devdir(c, tqid, "#k", 0, eve, DMDIR|0775, &d);		break;	case Qdir:		devdir(c, dqid, "ds", 0, eve, DMDIR|0775, &d);		break;	case Qctl:		devdir(c, cqid, "ctl", 0, eve, 0664, &d);		break;	default:		mp = path2dev(p - Qfirst, 1);		devdir(c, c->qid, mp->name, mp->size, eve, 0664, &d);	}	n = convD2M(&d, db, n);	if (n == 0)		error(Ebadarg);	return n;} static Chan*mopen(Chan *c, int omode){	if((c->qid.type & QTDIR) && omode != OREAD)		error(Eperm);	if (omode & OTRUNC)		omode &= ~OTRUNC;	c->mode = openmode(omode);	c->flag |= COPEN;	c->offset = 0;	return c;} static voidmclose(Chan*){	// that's easy} static longcatio(Fsdev *mp, int isread, void *a, long n, vlong off){	int	i;	Chan*	mc;	long	l, wl, res;	//print("catio %d %p %ld %lld\n", isread, a, n, off);	res = n;	for (i = 0; n >= 0 && i < mp->ndevs ; i++){		mc = mp->idev[i];		if (off > mp->isize[i]){			off -= mp->isize[i];			continue;		}		if (off + n > mp->isize[i])			l = mp->isize[i] - off;		else			l = n;		//print("\tdev %d %p %ld %lld\n", i, a, l, off); 		if (isread)			wl = devtab[mc->type]->read(mc, a, l, off);		else			wl = devtab[mc->type]->write(mc, a, l, off);		if (wl != l)			error("#k: write failed");		a = (char*)a + l;		off = 0;		n -= l;	}	//print("\tres %ld\n", res - n);	return res - n;} static longinterio(Fsdev *mp, int isread, void *a, long n, vlong off){	int	i;	Chan*	mc;	long	l, wl, wsz;	vlong	woff, blk, mblk;	long	boff, res; 	blk  = off / Blksize;	boff = off % Blksize;	wsz  = Blksize - boff;	res = n;	while(n > 0){		i    = blk % mp->ndevs;		mc   = mp->idev[i];		mblk = blk / mp->ndevs;		woff = mblk * Blksize + boff;		if (n > wsz)			l = wsz;		else			l = n;		if (isread)			wl = devtab[mc->type]->read(mc, a, l, woff);		else			wl = devtab[mc->type]->write(mc, a, l, woff);		if (wl != l || l == 0)			error(Eio);		a = (char*)a + l;		n -= l;		blk++;		boff = 0;		wsz = Blksize;	}	return res;} static longmread(Chan *c, void *a, long n, vlong off){	int	i;	Fsdev	*mp;	Chan	*mc;	long	l;	long	res; 	if (c->qid.type & QTDIR)		return devdirread(c, a, n, 0, 0, mgen);	if (c->qid.path == Qctl)		return readstr((long)off, a, n, confstr + strlen(Cfgstr));	i = c->qid.path - Qfirst;	mp = path2dev(i, 1); 	if (off >= mp->size)		return 0;	if (off + n > mp->size)		n = mp->size - off;	if (n == 0)		return 0; 	res = -1;

Lines 1–500 of 605.