~kris/9p

9hist

5172dc4629e85e7c32dca5e2a8b4fc95754e1ebf — David du Colombier 30 years ago 702753d
Plan 9 from Bell Labs 1996-02-20
1 files changed, 215 insertions(+), 115 deletions(-)

M port/devtinyfs.c
M port/devtinyfs.c => port/devtinyfs.c +215 -115
@@ 49,7 49,7 @@ typedef struct Mdata Mdata;
struct Mdata {
	uchar	type;
	uchar	bno[2];
	char	data[Dlen];
	uchar	data[Dlen];
	uchar	sum;
};



@@ 63,6 63,10 @@ struct Tfile {
	ushort	pin;
	uchar	flag;
	ulong	length;

	/* hint to avoid egregious reading */
	ushort	fbno;
	ulong	finger;
};

typedef struct Tfs Tfs;


@@ 80,7 84,6 @@ struct Tfs {
struct {
	QLock;
	Tfs	fs[Maxfs];
	short	nfs;
} tinyfs;

#define GETS(x) ((x)[0]|((x)[1]<<8))


@@ 125,7 128,6 @@ mapalloc(Tfs *fs)
	int i, j, lim;
	uchar x;

	qlock(fs);
	lim = (fs->nblocks + 8 - 1)/8;
	for(i = 0; i < lim; i++){
		x = fs->map[i];


@@ 134,12 136,11 @@ mapalloc(Tfs *fs)
		for(j = 0; j < 8; j++)
			if((x & (1<<j)) == 0){
				fs->map[i] = x|(1<<j);
				qunlock(fs);
				return i*8 + j;
			}
	}
	qunlock(fs);
	return -1;

	return Notabno;
}

static Mdir*


@@ 245,19 246,17 @@ writedir(Tfs *fs, Tfile *f)
}

static void
freefile(Tfs *fs, Tfile *f, ulong bend)
freeblocks(Tfs *fs, ulong bno, ulong bend)
{
	uchar buf[Blen];
	ulong bno;
	int n;
	Mdata *md;

	/* remove blocks from map */
	bno = f->dbno;
	if(waserror())
		return;

	while(bno != bend && bno != Notabno){
		mapclr(fs, bno);
		n = devtab[fs->c->type].read(fs->c, buf, Blen, Blen*bno);
		if(n != Blen)
		if(devtab[fs->c->type].read(fs->c, buf, Blen, Blen*bno) != Blen)
			break;
		md = validdata(fs, buf, 0);
		if(md == 0)


@@ 267,13 266,24 @@ freefile(Tfs *fs, Tfile *f, ulong bend)
		bno = GETS(md->bno);
	}

	poperror();
}

static void
freefile(Tfs *fs, Tfile *f, ulong bend)
{
	uchar buf[Blen];

	/* remove blocks from map */
	freeblocks(fs, f->dbno, bend);

	/* change file type to free on medium */
	if(f->bno != Notabno){
		n = devtab[fs->c->type].read(fs->c, buf, Blen, Blen*f->bno);
		if(n != Blen)
		if(devtab[fs->c->type].read(fs->c, buf, Blen, Blen*f->bno) != Blen)
			return;
		buf[0] = Tagfree;
		devtab[fs->c->type].write(fs->c, buf, Blen, Blen*f->bno);
		mapclr(fs, f->bno);
	}

	/* forget we ever knew about it */


@@ 288,8 298,10 @@ expand(Tfs *fs)
	fs->fsize += 8;
	f = smalloc(fs->fsize*sizeof(*f));

	memmove(f, fs->f, fs->nf*sizeof(f));
	free(fs->f);
	if(fs->f){
		memmove(f, fs->f, fs->nf*sizeof(*f));
		free(fs->f);
	}
	fs->f = f;
}



@@ 310,8 322,11 @@ newfile(Tfs *fs, char *name)
			}
		}

		if(i < fs->fsize)
		if(i < fs->fsize){
			if(i >= fs->nf)
				fs->nf = i+1;
			break;
		}

		expand(fs);
	}


@@ 319,6 334,8 @@ newfile(Tfs *fs, char *name)
	f->flag = Fcreating;
	f->dbno = Notabno;
	f->bno = mapalloc(fs);
	f->fbno = Notabno;
	f->r = 1;

	/* write directory block */
	if(waserror()){


@@ 437,6 454,8 @@ tinyfsgen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp)
	if(i >= fs->nf)
		return -1;
	f = &fs->f[i];
	if(f->name[0] == 0)
		return 0;
	qid.path = i;
	qid.vers = 0;
	devdir(c, qid, f->name, f->length, eve, 0664, dp);


@@ 461,37 480,49 @@ tinyfsattach(char *spec)
	Tfs *fs;
	Chan *c, *cc;
	int i;
	char *p;

	cc = namec(spec, Aopen, ORDWR, 0);
	p = 0;
	if(strcmp(spec, "hd0") == 0)
		p = "#H/hd0nvram";
	else
		error("bad spec");

	cc = namec(p, Aopen, ORDWR, 0);
	if(waserror()){
		close(cc);
		qunlock(&tinyfs);
		nexterror();
	}

	qlock(&tinyfs);
	fs = 0;
	for(i = 0; i < tinyfs.nfs; i++){
	for(i = 0; i < Maxfs; i++){
		fs = &tinyfs.fs[i];
		if(fs && eqchan(cc, fs->c, 0))
		qlock(fs);
		if(fs->r && eqchan(cc, fs->c, 0))
			break;
		qunlock(fs);
	}
	if(i < tinyfs.nfs){
		qlock(fs);
	if(i < Maxfs){
		fs->r++;
		qunlock(fs);
		close(cc);
	} else {
		if(tinyfs.nfs >= Maxfs)
		for(fs = tinyfs.fs; fs < &tinyfs.fs[Maxfs]; fs++){
			qlock(fs);
			if(fs->r == 0)
				break;
			qunlock(fs);
		}
		if(fs == &tinyfs.fs[Maxfs])
			error("too many tinyfs's");
		fs = &tinyfs.fs[tinyfs.nfs];
		memset(fs, 0, sizeof(*fs));
		fs->c = cc;
		fs->r = 1;
		fs->f = 0;
		fs->nf = 0;
		fs->fsize = 0;
		fsinit(fs);
		tinyfs.nfs++;
		qunlock(fs);
	}
	qunlock(&tinyfs);
	poperror();

	c = devattach('U', spec);


@@ 553,14 584,24 @@ tinyfsopen(Chan *c, int omode)
			error(Eperm);
	} else {
		qlock(fs);
		if(omode == (OTRUNC|ORDWR)){
		if(waserror()){
			qunlock(fs);
			nexterror();
		}
		switch(omode){
		case OTRUNC|ORDWR:
		case OTRUNC|OWRITE:
			f = newfile(fs, fs->f[c->qid.path].name);
			fs->f[c->qid.path].r--;
			c->qid.path = f - fs->f;
		} else if(omode != OREAD){
			qunlock(fs);
			break;
		case OREAD:
			break;
		default:
			error(Eperm);
		}
		qunlock(fs);
		poperror();
	}

	return devopen(c, omode, 0, 0, tinyfsgen);


@@ 572,14 613,18 @@ tinyfscreate(Chan *c, char *name, int omode, ulong perm)
	Tfs *fs;
	Tfile *f;

	if(perm & CHDIR)
		error("directory creation illegal");
	USED(perm);

	fs = &tinyfs.fs[c->dev];

	qlock(fs);
	if(waserror()){
		qunlock(fs);
		nexterror();
	}
	f = newfile(fs, name);
	qunlock(fs);
	poperror();

	c->qid.path = f - fs->f;
	c->qid.vers = 0;


@@ 589,8 634,16 @@ tinyfscreate(Chan *c, char *name, int omode, ulong perm)
void
tinyfsremove(Chan *c)
{
	USED(c);
	error(Eperm);
	Tfs *fs;
	Tfile *f;

	if(c->qid.path == CHDIR)
		error(Eperm);
	fs = &tinyfs.fs[c->dev];
	f = &fs->f[c->qid.path];
	qlock(fs);
	freefile(fs, f, Notabno);
	qunlock(fs);
}

void


@@ 603,7 656,7 @@ tinyfswstat(Chan *c, char *dp)
void
tinyfsclose(Chan *c)
{
	Tfs *fs, **l;
	Tfs *fs;
	Tfile *f, *nf;
	int i;



@@ 612,48 665,48 @@ tinyfsclose(Chan *c)
	qlock(fs);

	/* dereference file and remove old versions */
	if(c->qid.path != CHDIR){
		f = &fs->f[c->qid.path];
		f->r--;
		if(f->r == 0){
			if(f->flag & Fcreating){
				/* remove all other files with this name */
				for(i = 0; i < fs->fsize; i++){
					nf = &fs->f[i];
					if(f == nf)
						continue;
					if(strcmp(nf->name, f->name) == 0){
						if(nf->r)
							nf->flag |= Frmonclose;
						else
							freefile(fs, nf, Notabno);
	if(!waserror()){
		if(c->qid.path != CHDIR){
			f = &fs->f[c->qid.path];
			f->r--;
			if(f->r == 0){
				if(f->flag & Frmonclose)
					freefile(fs, f, Notabno);
				else if(f->flag & Fcreating){
					/* remove all other files with this name */
					for(i = 0; i < fs->fsize; i++){
						nf = &fs->f[i];
						if(f == nf)
							continue;
						if(strcmp(nf->name, f->name) == 0){
							if(nf->r)
								nf->flag |= Frmonclose;
							else
								freefile(fs, nf, Notabno);
						}
					}
					f->flag &= ~Fcreating;
				}
				f->flag &= ~(Frmonclose|Fcreating);
			}
			if(f->flag & Frmonclose)
				freefile(fs, f, Notabno);
		}
		poperror();
	}

	/* dereference fs and remove on zero refs */
	fs->r--;
	qunlock(fs);
	qlock(&tinyfs);
	if(fs->r == 0){
		for(l = &fs->l; *l;){
			if(*l == fs){
				*l = fs->next;
				break;
			}
			l = &(*l)->next;
		}
		free(fs->f);
		free(fs->map);
		if(fs->f)
			free(fs->f);
		fs->f = 0;
		fs->nf = 0;
		fs->fsize = 0;
		if(fs->map)
			free(fs->map);
		fs->map = 0;
		close(fs->c);
		memset(fs, 0, sizeof(*fs));
		fs->c = 0;
	}
	qunlock(&tinyfs);
	qunlock(fs);
}

long


@@ 661,7 714,7 @@ tinyfsread(Chan *c, void *a, long n, ulong offset)
{
	Tfs *fs;
	Tfile *f;
	int sofar, i;
	int sofar, i, off;
	ulong bno;
	Mdata *md;
	uchar buf[Blen];


@@ 670,34 723,56 @@ tinyfsread(Chan *c, void *a, long n, ulong offset)
	if(c->qid.path & CHDIR)
		return devdirread(c, a, n, 0, 0, tinyfsgen);

	fs = tinyfs.fs[c->dev];
	fs = &tinyfs.fs[c->dev];
	f = &fs->f[c->qid.path];
	if(offset >= f->length)
		return 0;

	qlock(fs);
	if(waserror()){
		qunlock(fs);
		nexterror();
	}
	if(n + offset >= f->length)
		n = f->length - offset;

	/* walk to starting data block */
	bno = f->dbno;
	for(sofar = 0; sofar + Blen < offset; sofar += Blen){
	if(f->finger < offset && f->fbno != Notabno){
		sofar = f->finger;
		bno = f->fbno;
	} else {
		sofar = 0;
		bno = f->dbno;
	}
	for(; sofar + Dlen < offset; sofar += Dlen){
		md = readdata(fs, bno, buf, 0);
		if(md == 0)
			error(Eio);
		bno = GETS(md->bno);
	}

	/* read data */
	offset = offset%Blen;
	off = offset%Dlen;
	offset -= off;
	for(sofar = 0; sofar < n; sofar += i){
		md = readdata(fs, bno, buf, &i);
		i -= offset;
		if(md == 0)
			error(Eio);

		/* update finger for successful read */
		f->finger = offset + sofar;
		f->fbno = bno;

		i -= off;
		if(i > n)
			i = n;
		if(i < 0)
			break;
		memmove(p, md->data, i);
		p += i;
		bno = GETS(md->bno);
		offset = 0;
		off = 0;
	}
	qunlock(fs);
	poperror();

	return sofar;
}


@@ 708,13 783,17 @@ tinyfsbread(Chan *c, long n, ulong offset)
	return devbread(c, n, offset);
}

/*
 *  if we get a write error in this routine, blocks will
 *  be lost.  They should be recovered next fsinit.
 */
long
tinyfswrite(Chan *c, char *a, long n, ulong offset)
tinyfswrite(Chan *c, void *a, long n, ulong offset)
{
	Tfs *fs;
	Tfile *f;
	int sofar, i, x;
	ulong bno, tbno;
	int last, next, i, off, finger;
	ulong bno, dbno, fbno;
	Mdata *md;
	uchar buf[Blen];
	uchar *p = a;


@@ 725,7 804,7 @@ tinyfswrite(Chan *c, char *a, long n, ulong offset)
	if(n == 0)
		return 0;

	fs = tinyfs.fs[c->dev];
	fs = &tinyfs.fs[c->dev];
	f = &fs->f[c->qid.path];

	/* files are append only, anything else is illegal */


@@ 733,57 812,78 @@ tinyfswrite(Chan *c, char *a, long n, ulong offset)
		error("append only");

	qlock(fs);
	dbno = Notabno;
	if(waserror()){
		f->flag |= Frmonclose;
		freeblocks(fs, dbno, Notabno);
		qunlock(fs);
		nexterror();
	}

	/* write blocks backwards */
	p += n;
	last = offset + n;
	off = offset;
	fbno = Notabno;
	finger = 0;
	for(next = (last/Dlen)*Dlen; next >= off; next -= Dlen){
		bno = mapalloc(fs);
		if(bno == Notabno){
			error("out of space");
		}
		i = last - next;
		p -= i;
		if(last == n+offset){
			writedata(fs, bno, dbno, p, i, 1);
			finger = next;	/* remember for later */
			fbno = bno;
		} else
			writedata(fs, bno, dbno, p, i, 0);
		dbno = bno;
		last = next;
	}

	/* walk to last data block */
	bno = f->dbno;
	for(sofar = 0; sofar + Blen < offset; sofar += Blen){
	md = (Mdata*)buf;
	if(f->finger < offset && f->fbno != Notabno){
		next = f->finger;
		bno = f->fbno;
	} else {
		next = 0;
		bno = f->dbno;
	}
	for(; next < offset; next += Dlen){
		md = readdata(fs, bno, buf, 0);
		if(md == 0)
			error(Eio);
		if(md->type == Tagend)
			break;
		bno = GETS(md->bno);
	}

	sofar = 0;
	i = offset%Dlen;
	if(i){
		x = n;
		if(i + x > Dlen)
			x = Dlen - i;
		memmove(md->data + i, p, sofar);
		f->length += x;
		sofar += x;
	}

	while(x = n - sofar) {
		tbno = mapalloc(fs);
		if(f->length == 0){
			f->dbno = tbno;
			writedir(fs, f);
		} else {
			writedata(fs, bno, tbno, md->data, Dlen, 0);
	/* point to new blocks */
	if(offset == 0){
		f->dbno = dbno;
		writedir(fs, f);
	} else {
		i = last - offset;
		next = offset%Dlen;
		if(i > 0){
			p -= i;
			memmove(md->data + next, p, i);
		}
		if(x > Dlen)
			x = Dlen;
		memmove(md->data, p + sofar, x);
		sofar += x;
		f->length += x;
		bno = tbno;
		writedata(fs, bno, dbno, md->data, i+next, last == n+offset);
	}
	f->length += n;

	i = f->length%Dlen;
	if(i == 0)
		i = Dlen;
	writedata(fs, bno, tbno, md->data, i, 1);

	/* update finger */
	if(fbno != Notabno){
		f->finger = finger;
		f->fbno =  fbno;
	}
	poperror();
	qunlock(fs);

	return sofar;
	return n;
}

long