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

📄 disksim.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#include <u.h>#include <libc.h>#include <auth.h>#include <fcall.h>#include <thread.h>#include <9p.h>typedef struct Part Part;typedef struct Trip Trip;typedef struct Dbl Dbl;typedef struct Ind Ind;/* * with 8192-byte blocks and 4-byte pointers, * double-indirect gets us 34 GB.  * triple-indirect gets us 70,368 GB. */enum{	LOGBLKSZ = 13,	BLKSZ = 1<<LOGBLKSZ,	/* 8192 */	LOGNPTR = LOGBLKSZ-2,	/* assume sizeof(void*) == 4 */	NPTR = 1<<LOGNPTR,};static uchar zero[BLKSZ];struct Trip{	Dbl *dbl[NPTR];	};struct Dbl{	Ind *ind[NPTR];};struct Ind{	uchar *blk[NPTR];};Trip trip;struct Part{	int inuse;	int vers;	ulong mode;	char *name;	vlong offset;	/* in sectors */	vlong length;	/* in sectors */};enum{	Qroot = 0,	Qdir,	Qctl,	Qpart,};Part tab[64];int fd = -1;char *sdname = "sdXX";ulong ctlmode = 0666;char *inquiry = "aux/disksim hard drive";vlong nsect, sectsize, c, h, s;ulong time0;int rdonly;char*ctlstring(void){	int i;	Fmt fmt;	fmtstrinit(&fmt);	fmtprint(&fmt, "inquiry %s\n", inquiry);	fmtprint(&fmt, "geometry %lld %lld %lld %lld %lld\n", nsect, sectsize, c, h, s);	for(i=0; i<nelem(tab); i++)		if(tab[i].inuse)			fmtprint(&fmt, "part %s %lld %lld\n", tab[i].name, tab[i].offset, tab[i].length);	return fmtstrflush(&fmt);}intaddpart(char *name, vlong start, vlong end){	int i;	if(start < 0 || start > end || end > nsect){		werrstr("bad partition boundaries");		return -1;	}	for(i=0; i<nelem(tab); i++)		if(tab[i].inuse == 0)			break;	if(i == nelem(tab)){		werrstr("no free partition slots");		return -1;		}	free(tab[i].name);	tab[i].inuse = 1;	tab[i].name = estrdup9p(name);	tab[i].offset = start;	tab[i].length = end - start;	tab[i].mode = ctlmode;	tab[i].vers++;	return 0;}intdelpart(char *s){	int i;	for(i=0; i<nelem(tab); i++)		if(tab[i].inuse && strcmp(tab[i].name, s) == 0)			break;	if(i==nelem(tab)){		werrstr("partition not found");		return -1;	}	tab[i].inuse = 0;	free(tab[i].name);	tab[i].name = 0;	return 0;}voidctlwrite(Req *r){	int i;	Cmdbuf *cb;	vlong start, end;	r->ofcall.count = r->ifcall.count;	cb = parsecmd(r->ifcall.data, r->ifcall.count);	if(cb->nf < 1){		respond(r, "empty control message");		free(cb);		return;	}	if(strcmp(cb->f[0], "part") == 0){		if(cb->nf != 4){			respondcmderror(r, cb, "part takes 3 args");			free(cb);			return;		}		start = strtoll(cb->f[2], 0, 0);		end = strtoll(cb->f[3], 0, 0);		if(addpart(cb->f[1], start, end) < 0){			respondcmderror(r, cb, "%r");			free(cb);			return;		}	}	else if(strcmp(cb->f[0], "delpart") == 0){		if(cb->nf != 2){			respondcmderror(r, cb, "delpart takes 1 arg");			free(cb);			return;		}		if(delpart(cb->f[1]) < 0){			respondcmderror(r, cb, "%r");			free(cb);			return;		}	}	else if(strcmp(cb->f[0], "inquiry") == 0){		if(cb->nf != 2){			respondcmderror(r, cb, "inquiry takes 1 arg");			free(cb);			return;		}		free(inquiry);		inquiry = estrdup9p(cb->f[1]);	}	else if(strcmp(cb->f[0], "geometry") == 0){		if(cb->nf != 6){			respondcmderror(r, cb, "geometry takes 5 args");			free(cb);			return;		}		nsect = strtoll(cb->f[1], 0, 0);		sectsize = strtoll(cb->f[2], 0, 0);		c = strtoll(cb->f[3], 0, 0);		h = strtoll(cb->f[4], 0, 0);		s = strtoll(cb->f[5], 0, 0);		if(tab[0].inuse && strcmp(tab[0].name, "data") == 0 && tab[0].vers == 0){			tab[0].offset = 0;			tab[0].length = nsect;		}		for(i=0; i<nelem(tab); i++){			if(tab[i].inuse && tab[i].offset+tab[i].length > nsect){				tab[i].inuse = 0;				free(tab[i].name);				tab[i].name = 0;			}		}	}	else{		respondcmderror(r, cb, "unknown control message");		free(cb);		return;	}	free(cb);	respond(r, nil);}	void*allocblk(vlong addr){	uchar *op;	static uchar *p;	static ulong n;	if(n == 0){		p = malloc(4*1024*1024);		if(p == 0)			sysfatal("out of memory");		n = 4*1024*1024;	}	op = p;	p += BLKSZ;	n -= BLKSZ;	memset(op, 0, BLKSZ);	if(fd != -1 && addr != -1)		pread(fd, op, BLKSZ, addr);	return op;}uchar*getblock(vlong addr, int alloc){ 	Dbl *p2;	Ind *p1;	uchar *p0;	uint i0, i1, i2;	vlong oaddr;	if(fd >= 0)		alloc = 1;	addr >>= LOGBLKSZ;	oaddr = addr<<LOGBLKSZ;	i0 = addr & (NPTR-1);	addr >>= LOGNPTR;	i1 = addr & (NPTR-1);	addr >>= LOGNPTR;	i2 = addr & (NPTR-1);	addr >>= LOGNPTR;	assert(addr == 0);	if((p2 = trip.dbl[i2]) == 0){		if(!alloc)			return zero;		trip.dbl[i2] = p2 = allocblk(-1);	}	if((p1 = p2->ind[i1]) == 0){		if(!alloc)			return zero;		p2->ind[i1] = p1 = allocblk(-1);	}	if((p0 = p1->blk[i0]) == 0){		if(!alloc)			return zero;		p1->blk[i0] = p0 = allocblk(oaddr);	}	return p0;}voiddirty(vlong addr, uchar *buf){	vlong oaddr;	if(fd == -1 || rdonly)		return;	oaddr = addr&~((vlong)BLKSZ-1);	if(pwrite(fd, buf, BLKSZ, oaddr) != BLKSZ)		sysfatal("write: %r");}	introotgen(int off, Dir *d, void*){	memset(d, 0, sizeof *d);	d->atime = time0;	d->mtime = time0;	if(off == 0){		d->name = estrdup9p(sdname);		d->mode = DMDIR|0777;		d->qid.path = Qdir;		d->qid.type = QTDIR;		d->uid = estrdup9p("disksim");		d->gid = estrdup9p("disksim");		d->muid = estrdup9p("");		return 0;	}	return -1;}			intdirgen(int off, Dir *d, void*){	int n, j;	memset(d, 0, sizeof *d);	d->atime = time0;	d->mtime = time0;	if(off == 0){		d->name = estrdup9p("ctl");		d->mode = ctlmode;		d->qid.path = Qctl;		goto Have;	}	off--;	n = 0;	for(j=0; j<nelem(tab); j++){		if(tab[j].inuse==0)			continue;		if(n == off){			d->name = estrdup9p(tab[j].name);			d->length = tab[j].length*sectsize;			d->mode = tab[j].mode;			d->qid.path = Qpart+j;			d->qid.vers = tab[j].vers;			goto Have;		}		n++;	}	return -1;Have:	d->uid = estrdup9p("disksim");	d->gid = estrdup9p("disksim");	d->muid = estrdup9p("");	return 0;}void*evommem(void *a, void *b, ulong n){	return memmove(b, a, n);}intisnonzero(void *v, ulong n){	uchar *a, *ea;		a = v;	ea = a+n;	for(; a<ea; a++)		if(*a)			return 1;	return 0;}intrdwrpart(Req *r){	int q, nonzero;	Part *p;	vlong offset;	long count, tot, n, o;	uchar *blk, *dat;	void *(*move)(void*, void*, ulong);	q = r->fid->qid.path-Qpart;	if(q < 0 || q > nelem(tab) || !tab[q].inuse || tab[q].vers != r->fid->qid.vers){		respond(r, "unknown partition");		return -1;	}	p = &tab[q];	offset = r->ifcall.offset;	count = r->ifcall.count;	if(offset < 0){		respond(r, "negative offset");		return -1;	}	if(count < 0){		respond(r, "negative count");		return -1;	}	if(offset > p->length*sectsize){		respond(r, "offset past end of partition");		return -1;	}	if(offset+count > p->length*sectsize)		count = p->length*sectsize - offset;	offset += p->offset*sectsize;	if(r->ifcall.type == Tread)		move = memmove;	else		move = evommem;	tot = 0;	nonzero = 1;	if(r->ifcall.type == Tread)		dat = (uchar*)r->ofcall.data;	else{		dat = (uchar*)r->ifcall.data;		nonzero = isnonzero(dat, r->ifcall.count);	}	o = offset & (BLKSZ-1);	/* left fringe block */	if(o && count){		blk = getblock(offset, r->ifcall.type==Twrite && nonzero);		n = BLKSZ - o;		if(n > count)			n = count;		if(r->ifcall.type != Twrite || blk != zero)			(*move)(dat, blk+o, n);		if(r->ifcall.type == Twrite)			dirty(offset, blk);		tot += n;	}	/* full and right fringe blocks */	while(tot < count){		blk = getblock(offset+tot, r->ifcall.type==Twrite && nonzero);		n = BLKSZ;		if(n > count-tot)			n = count-tot;		if(r->ifcall.type != Twrite || blk != zero)			(*move)(dat+tot, blk, n);		if(r->ifcall.type == Twrite)			dirty(offset+tot, blk);		tot += n;	}	r->ofcall.count = tot;	respond(r, nil);	return 0;}voidfsread(Req *r){	char *s;	switch((int)r->fid->qid.path){	case Qroot:		dirread9p(r, rootgen, nil);		respond(r, nil);		break;	case Qdir:		dirread9p(r, dirgen, nil);		respond(r, nil);		break;	case Qctl:		s = ctlstring();		readstr(r, s);		free(s);		respond(r, nil);		break;	default:		rdwrpart(r);		break;	}}voidfswrite(Req *r){	switch((int)r->fid->qid.path){	case Qroot:	case Qdir:		respond(r, "write to a directory?");		break;	case Qctl:		ctlwrite(r);		break;	default:		rdwrpart(r);		break;	}}voidfsopen(Req *r){	if(r->ifcall.mode&ORCLOSE)		respond(r, "cannot open ORCLOSE");	switch((int)r->fid->qid.path){	case Qroot:	case Qdir:		if(r->ifcall.mode != OREAD){			respond(r, "bad mode for directory open");			return;		}	}	respond(r, nil);}voidfsstat(Req *r){	int q;	Dir *d;	Part *p;	d = &r->d;	memset(d, 0, sizeof *d);	d->qid = r->fid->qid;	d->atime = d->mtime = time0;	q = r->fid->qid.path;	switch(q){	case Qroot:		d->name = estrdup9p("/");		d->mode = DMDIR|0777;		break;	case Qdir:		d->name = estrdup9p(sdname);		d->mode = DMDIR|0777;		break;	default:		q -= Qpart;		if(q < 0 || q > nelem(tab) || tab[q].inuse==0 || r->fid->qid.vers != tab[q].vers){			respond(r, "partition no longer exists");			return;		}		p = &tab[q];		d->name = estrdup9p(p->name);		d->length = p->length * sectsize;		d->mode = p->mode;		break;	}			d->uid = estrdup9p("disksim");	d->gid = estrdup9p("disksim");	d->muid = estrdup9p("");	respond(r, nil);}voidfsattach(Req *r){	char *spec;	spec = r->ifcall.aname;	if(spec && spec[0]){		respond(r, "invalid attach specifier");		return;	}	r->ofcall.qid = (Qid){Qroot, 0, QTDIR};	r->fid->qid = r->ofcall.qid;	respond(r, nil);}char*fswalk1(Fid *fid, char *name, Qid *qid){	int i;	switch((int)fid->qid.path){	case Qroot:		if(strcmp(name, sdname) == 0){			fid->qid.path = Qdir;			fid->qid.type = QTDIR;			*qid = fid->qid;			return nil;		}		break;	case Qdir:		if(strcmp(name, "ctl") == 0){			fid->qid.path = Qctl;			fid->qid.vers = 0;			fid->qid.type = 0;			*qid = fid->qid;			return nil;		}		for(i=0; i<nelem(tab); i++){			if(tab[i].inuse && strcmp(tab[i].name, name) == 0){				fid->qid.path = i+Qpart;				fid->qid.vers = tab[i].vers;				fid->qid.type = 0;				*qid = fid->qid;				return nil;			}		}		break;	}	return "file not found";}Srv fs = {	.attach=	fsattach,	.open=	fsopen,	.read=	fsread,	.write=	fswrite,	.stat=	fsstat,	.walk1=	fswalk1,};char *mtpt = "/dev";char *srvname;voidusage(void){	fprint(2, "usage: aux/disksim [-D] [-f file] [-s srvname] [-m mtpt] [sdXX]\n");	fprint(2, "\tdefault mtpt is /dev\n");	exits("usage");}voidmain(int argc, char **argv){	char *file;	file = nil;	quotefmtinstall();	time0 = time(0);	if(NPTR != BLKSZ/sizeof(void*))		sysfatal("unexpected pointer size");	ARGBEGIN{	case 'D':		chatty9p++;		break;	case 'f':		file = EARGF(usage());		break;	case 'r':		rdonly = 1;		break;	case 's':		srvname = EARGF(usage());		break;	case 'm':		mtpt = EARGF(usage());		break;	default:		usage();	}ARGEND	if(argc > 1)		usage();	if(argc == 1)		sdname = argv[0];	if(file){		if((fd = open(file, rdonly ? OREAD : ORDWR)) < 0)			sysfatal("open %s: %r", file);	}	inquiry = estrdup9p(inquiry);	tab[0].name = estrdup9p("data");	tab[0].inuse = 1;	tab[0].mode = 0666;	postmountsrv(&fs, srvname, mtpt, MBEFORE);	exits(nil);}

⌨️ 快捷键说明

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