1294 lines · 25.1 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * File system devices. * Follows device config in Ken's file server. * Builds mirrors, concatenations, interleavings, and partitions * of devices out of other (inner) devices. * It is ok if inner devices are provided by this driver. * * Built files are grouped on different directories * (called trees, and used to represent disks). * The "#k/fs" tree is always available and never goes away. * Configuration changes happen only while no I/O is in progress. * * Default sector size is one byte unless changed by the "disk" ctl. */ #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{	Fnone,	Fmirror,		/* mirror of others */	Fcat,			/* catenation of others */	Finter,			/* interleaving of others */	Fpart,			/* part of other */	Fclear,			/* start over */	Fdel,			/* delete a configure device */	Fdisk,			/* set default tree and sector sz*/ 	Sectorsz = 1,	Blksize	= 8*1024,	/* for Finter only */ 	Incr = 5,		/* Increments for the dev array */ 	/*	 * All qids are decorated with the tree number.	 * #k/fs is tree number 0, is automatically added and	 * its first qid is for the ctl file. It never goes away.	 */	Qtop	= 0,		/* #k */	Qdir,			/* directory (#k/fs) */	Qctl,			/* ctl, only for #k/fs/ctl */	Qfirst,			/* first qid assigned for device */ 	Iswrite = 0,	Isread, 	Optional = 0,	Mustexist, 	/* tunable parameters */	Maxconf	= 4*1024,	/* max length for config */	Ndevs	= 32,		/* max. inner devs per command */	Ntrees	= 128,		/* max. number of trees */	Maxretries = 3,		/* max. retries of i/o errors */	Retrypause = 5000,	/* ms. to pause between retries */}; typedef struct Inner Inner;typedef struct Fsdev Fsdev;typedef struct Tree Tree; struct Inner{	char	*iname;		/* inner device name */	vlong	isize;		/* size of inner device */	Chan	*idev;		/* inner device */}; struct Fsdev{	Ref;			/* one per Chan doing I/O */	int	gone;		/* true if removed */	int	vers;		/* qid version for this device */	int	type;		/* Fnone, Fmirror, ... */	char	*name;		/* name for this fsdev */	Tree*	tree;		/* where the device is kept */	vlong	size;		/* min(inner[X].isize) */	vlong	start;		/* start address (for Fpart) */	uint	ndevs;		/* number of inner devices */	int	perm;		/* minimum of inner device perms */	Inner	*inner[Ndevs];	/* inner devices */}; struct Tree{	char	*name;		/* name for #k/<name> */	Fsdev	**devs;		/* devices in dir. */	uint	ndevs;		/* number of devices */	uint	nadevs;		/* number of allocated devices in devs */}; #define dprint if(debug)print extern Dev fsdevtab;		/* forward */ static RWlock lck;		/* r: use devices; w: change config  */static Tree fstree;		/* The main "fs" tree. Never goes away */static Tree *trees[Ntrees];	/* internal representation of config */static int ntrees;		/* max number of trees */static int qidvers; static char *disk;		/* default tree name used */static char *source;		/* default inner device used */static int sectorsz = Sectorsz;	/* default sector size */ static char confstr[Maxconf];	/* textual configuration */ static int debug; static char cfgstr[] = "fsdev:\n"; static Qid tqid = {Qtop, 0, QTDIR};static Qid cqid = {Qctl, 0, 0}; static char* tnames[] = {	[Fmirror]	"mirror",	[Fcat]		"cat",	[Finter]	"inter",	[Fpart]		"part",}; static Cmdtab configs[] = {	Fmirror,"mirror",	0,	Fcat,	"cat",		0,	Finter,	"inter",	0,	Fpart,	"part",		0,	Fclear,	"clear",	1,	Fdel,	"del",		2,	Fdisk,	"disk",		0,}; static char Egone[] = "device is gone";		/* file has been removed */ static char*seprintdev(char *s, char *e, Fsdev *mp){	int i; 	if(mp == nil)		return seprint(s, e, "<null Fsdev>");	if(mp->type < 0 || mp->type >= nelem(tnames) || tnames[mp->type] == nil)		return seprint(s, e, "bad device type %d\n", mp->type); 	s = strecpy(s, e, tnames[mp->type]);	if(mp->tree != &fstree)		s = seprint(s, e, " %s/%s", mp->tree->name, mp->name);	else		s = seprint(s, e, " %s", mp->name);	for(i = 0; i < mp->ndevs; i++)		s = seprint(s, e, " %s", mp->inner[i]->iname);	switch(mp->type){	case Fmirror:	case Fcat:	case Finter:		s = strecpy(s, e, "\n");		break;	case Fpart:		s = seprint(s, e, " %ulld %ulld\n", mp->start, mp->size);		break;	default:		panic("#k: seprintdev bug");	}	return s;} static vlongmkpath(int tree, int devno){	return (tree&0xFFFF)<<16 | devno&0xFFFF;} static intpath2treeno(int q){	return q>>16 & 0xFFFF;} static intpath2devno(int q){	return q & 0xFFFF;} static Tree*gettree(int i, int mustexist){	dprint("gettree %d\n", i);	if(i < 0)		panic("#k: bug: bad tree index %d in gettree", i);	if(i >= ntrees || trees[i] == nil)		if(mustexist)			error(Enonexist);		else			return nil;	return trees[i];} static Fsdev*getdev(Tree *t, int i, int mustexist){	dprint("getdev %d\n", i);	if(i < 0)		panic("#k: bug: bad dev index %d in getdev", i);	if(i >= t->nadevs || t->devs[i] == nil)		if(mustexist)			error(Enonexist);		else			return nil;	return t->devs[i];} static Fsdev*path2dev(int q){	Tree	*t; 	dprint("path2dev %ux\n", q);	t = gettree(path2treeno(q), Mustexist);	return getdev(t, path2devno(q) - Qfirst, Mustexist);} static Tree*treealloc(char *name){	int	i;	Tree	*t; 	dprint("treealloc %s\n", name);	for(i = 0; i < nelem(trees); i++)		if(trees[i] == nil)			break;	if(i == nelem(trees))		return nil;	t = trees[i] = mallocz(sizeof(Tree), 1);	if(t == nil)		return nil;	if(i == ntrees)		ntrees++;	kstrdup(&t->name, name);	return t;} static Tree*lookuptree(char *name){	int i; 	dprint("lookuptree %s\n", name);	for(i = 0; i < ntrees; i++)		if(trees[i] != nil && strcmp(trees[i]->name, name) == 0)			return trees[i];	return nil;} static Fsdev*devalloc(Tree *t, char *name){	int	i, ndevs;	Fsdev	*mp, **devs; 	dprint("devalloc %s %s\n", t->name, name);	mp = mallocz(sizeof(Fsdev), 1);	if(mp == nil)		return nil;	for(i = 0; i < t->nadevs; i++)		if(t->devs[i] == nil)			break;	if(i >= t->nadevs){		if(t->nadevs % Incr == 0){			ndevs = t->nadevs + Incr;			devs = realloc(t->devs, ndevs * sizeof(Fsdev*));			if(devs == nil){				free(mp);				return nil;			}			t->devs = devs;		}		t->devs[t->nadevs] = nil;		t->nadevs++;	}	kstrdup(&mp->name, name);	mp->vers = ++qidvers;	mp->tree = t;	t->devs[i] = mp;	t->ndevs++;	return mp;} static voiddeltree(Tree *t){	int i; 	dprint("deltree %s\n", t->name);	for(i = 0; i < ntrees; i++)		if(trees[i] == t){			if(i > 0){		/* "fs" never goes away */				free(t->name);				free(t->devs);				free(t);				trees[i] = nil;			}			return;		}	panic("#k: deltree: bug: tree not found");} /* * A device is gone and we know that all its users are gone. * A tree is gone when all its devices are gone ("fs" is never gone). * Must close devices outside locks, so we could nest our own devices. */static voidmdeldev(Fsdev *mp){	int	i;	Inner	*in;	Tree	*t; 	dprint("deldev %s gone %d ref %uld\n", mp->name, mp->gone, mp->ref); 	mp->gone = 1;	mp->vers = ++qidvers; 	wlock(&lck);	t = mp->tree;	for(i = 0; i < t->nadevs; i++)		if(t->devs[i] == mp){			t->devs[i] = nil;			t->ndevs--;			if(t->ndevs == 0)				deltree(t);			break;		}	wunlock(&lck); 	free(mp->name);	for(i = 0; i < mp->ndevs; i++){		in = mp->inner[i];		if(in->idev != nil)			cclose(in->idev);		free(in->iname);		free(in);	}	if(debug)		memset(mp, 9, sizeof *mp);	/* poison */	free(mp);} /* * Delete one or all devices in one or all trees. */static voidmdelctl(char *tname, char *dname){	int i, alldevs, alltrees, some;	Fsdev *mp;	Tree *t; 	dprint("delctl %s\n", dname);	alldevs = strcmp(dname, "*") == 0;	alltrees = strcmp(tname, "*") == 0;	some = 0;Again:	wlock(&lck);	for(i = 0; i < ntrees; i++){		t = trees[i];		if(t == nil)			continue;		if(alltrees == 0 && strcmp(t->name, tname) != 0)			continue;		for(i = 0; i < t->nadevs; i++){			mp = t->devs[i];			if(t->devs[i] == nil)				continue;			if(alldevs == 0 && strcmp(mp->name, dname) != 0)				continue;			/*			 * Careful: must close outside locks and that			 * may change the file tree we are looking at.			 */			some++;			mp->gone = 1;			if(mp->ref == 0){				incref(mp);	/* keep it there */				wunlock(&lck);				mdeldev(mp);				goto Again;	/* tree can change */			}		}	}	wunlock(&lck);	if(some == 0 && alltrees == 0)		error(Enonexist);} static voidsetdsize(Fsdev* mp, vlong *ilen){	int	i;	vlong	inlen;	Inner	*in; 	dprint("setdsize %s\n", mp->name);	for (i = 0; i < mp->ndevs; i++){		in = mp->inner[i];		in->isize = ilen[i];		inlen = in->isize;		switch(mp->type){		case Finter:			/* truncate to multiple of Blksize */			inlen &= ~(Blksize-1);			in->isize = inlen;			/* fall through */		case Fmirror:			/* use size of smallest inner device */			if (mp->size == 0 || mp->size > inlen)				mp->size = inlen;			break;		case Fcat:			mp->size += inlen;			break;		case Fpart:			if(mp->start > inlen)				error("partition starts after device end");			if(inlen < mp->start + mp->size){				print("#k: %s: partition truncated from "					"%lld to %lld bytes\n", mp->name,					mp->size, inlen - mp->start);				mp->size = inlen - mp->start;			}			break;		}	}	if(mp->type == Finter)		mp->size *= mp->ndevs;} static voidvaliddevname(Tree *t, char *dname){	int i; 	for(i = 0; i < t->nadevs; i++)		if(t->devs[i] != nil && strcmp(t->devs[i]->name, dname) == 0)			error(Eexist);} static voidparseconfig(char *a, long n, Cmdbuf **cbp, Cmdtab **ctp){	Cmdbuf	*cb;	Cmdtab	*ct; 	*cbp = cb = parsecmd(a, n);	*ctp = ct = lookupcmd(cb, configs, nelem(configs)); 	cb->f++;			/* skip command */	cb->nf--;	switch(ct->index){	case Fmirror:	case Fcat:	case Finter:		if(cb->nf < 2)			error("too few arguments for ctl");		if(cb->nf - 1 > Ndevs)			error("too many devices in ctl");		break;	case Fdisk:		if(cb->nf < 1 || cb->nf > 3)			error("ctl usage: disk name [sz dev]");		break;	case Fpart:		if(cb->nf != 4 && (cb->nf != 3 || source == nil))			error("ctl usage: part new [file] off len");		break;	}} static voidparsename(char *name, char *disk, char **tree, char **dev){	char *slash; 

Lines 1–500 of 1294.