⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 devfs.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
/* * File system devices. * '#k'. * Follows device config in Ken's file server. * Builds mirrors, device cats, interleaving, and partition of devices out of * other (inner) devices. */#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 */	Ndevs	= 64,	Nfsdevs = 2*Ndevs,	Qtop	= 0,		/* top dir (contains "fs") */	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 inner 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);	mp = nil;	cb = nil;	oldc = confstr + strlen(confstr);	qlock(&lck);	if (waserror()){		*oldc = 0;		if (mp != nil)			mpshut(mp);		qunlock(&lck);		if (cb)			free(cb);		nexterror();	}	cb = parsecmd(a, n);	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, increase Ndevs");	for (i = 0; i < cb->nf; i++)		validname(cb->f[i], (i != 0));	mp = devalloc();	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();	configed = 1;	qunlock(&lck);	free(cb);}static voidrdconf(void){	int	mustrd;	char	*s;	char	*c;	char	*p;	char	*e;	Chan *cc;	Chan **ccp;	s = getconf("fsconfig");	if (s == nil){		mustrd = 0;		s = "/dev/sdC0/fscfg";	} else		mustrd = 1;	ccp = &cc;	*ccp = nil;	c = nil;	if (waserror()){		configed = 1;		if (*ccp != nil)			cclose(*ccp);		if (c)			free(c);		if (!mustrd)			return;		nexterror();	}	*ccp = namec(s, Aopen, OREAD, 0);	devtab[(*ccp)->type]->read(*ccp, confstr, sizeof(confstr), 0);	cclose(*ccp);	*ccp = nil;	if (strncmp(confstr, Cfgstr, strlen(Cfgstr)) != 0)		error("Bad config, first line must be: 'fsdev:\\n'");	kstrdup(&c, confstr + strlen(Cfgstr));	memset(confstr, 0, sizeof(confstr));	for (p = c; p != nil && *p != 0; p = e){		e = strchr(p, '\n');		if (e == nil)			e = p + strlen(p);		if (e == p) {			e++;			continue;		}		mconfig(p, e - p);	}	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, "fs", 0, eve, DMDIR|0775, dp);			return 1;		default:			return -1;		}	if (c->qid.path != Qdir)		switch(i){		case DEVDOTDOT:			devdir(c, dqid, "fs", 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, "fs", 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;	switch(mp->type){	case Fmirror:		for (i = 0; i < mp->ndevs; i++){			mc = mp->idev[i];			if (waserror()){				/*				 * if a read fails we let the user know and try				 * another device.				 */				print("#k: mread: (%llx %d): %s\n",					c->qid.path, i, up->errstr);				continue;			}			l = devtab[mc->type]->read(mc, a, n, off);			poperror();			if (l >= 0){				res = l;				break;			}		}		if (i == mp->ndevs)			error(Eio);		break;	case Fcat:		res = catio(mp, 1, a, n, off);		break;	case Finter:		res = interio(mp, 1, a, n, off);		break;	case Fpart:		off += mp->start;		mc = mp->idev[0];		res = devtab[mc->type]->read(mc, a, n, off);		break;	}	return res;}static longmwrite(Chan *c, void *a, long n, vlong off){	Fsdev	*mp;	long	l, res;	int	i;	Chan	*mc;	if (c->qid.type & QTDIR)		error(Eperm);	if (c->qid.path == Qctl){		mconfig(a, n);		return n;	}	mp = path2dev(c->qid.path - Qfirst, 1);	if (off >= mp->size)		return 0;	if (off + n > mp->size)		n = mp->size - off;	if (n == 0)		return 0;	res = n;	switch(mp->type){	case Fmirror:		for (i = mp->ndevs-1; i >=0; i--){			mc = mp->idev[i];			l = devtab[mc->type]->write(mc, a, n, off);			if (l < res)				res = l;		}		break;	case Fcat:		res = catio(mp, 0, a, n, off);		break;	case Finter:		res = interio(mp, 0, a, n, off);		break;	case Fpart:		mc = mp->idev[0];		off += mp->start;		l = devtab[mc->type]->write(mc, a, n, off);		if (l < res)			res = l;		break;	}	return res;}Dev fsdevtab = {	'k',	"devfs",	devreset,	devinit,	devshutdown,	mattach,	mwalk,	mstat,	mopen,	devcreate,	mclose,	mread,	devbread,	mwrite,	devbwrite,	devremove,	devwstat,	devpower,	devconfig,};

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -