shithub: gefs

Download patch

ref: 6b3bff3c893fa5ffab171cf8010a23512926e196
parent: 57a0e2453cc74df81d1e2ed2ecd256e7ab1f322f
author: Ori Bernstein <ori@eigenstate.org>
date: Sun Jan 9 23:27:34 EST 2022

fs: implement '..' with backlinks in directories.

--- a/cons.c
+++ b/cons.c
@@ -142,6 +142,18 @@
 }
 
 static void
+stats(int fd, char**, int)
+{
+	Stats *s;
+
+	s = &fs->stats;
+	fprint(fd, "stats:\n");
+	fprint(fd, "	cache hits:	%lld\n", s->cachehit);
+	fprint(fd, "	cache lookups:	%lld\n", s->cachelook);
+	fprint(fd, "	cache ratio:	%f\n", (double)s->cachehit/(double)s->cachelook);
+}
+
+static void
 showdf(int fd, char**, int)
 {
 	vlong size, used;
@@ -188,6 +200,17 @@
 }
 
 static void
+showblkdump(int fd, char **ap, int)
+{
+	Bptr bp;
+
+	bp.addr = atoll(ap[0]);
+	bp.hash = -1;
+	bp.gen = -1;
+	showbp(fd, bp, 0);
+}
+
+static void
 help(int fd, char**, int)
 {
 	char *msg =
@@ -230,6 +253,7 @@
 	{.name="help",	.sub=nil,	.minarg=0, .maxarg=0, .fn=help},
 	{.name="df",	.sub=nil, 	.minarg=0, .maxarg=0, .fn=showdf},
 	{.name="users",	.sub=nil,	.minarg=0, .maxarg=1, .fn=refreshusers},
+	{.name="stats", .sub=nil,	.minarg=0, .maxarg=0, .fn=stats},
 
 	/* debugging */
 	{.name="show",	.sub="cache",	.minarg=0, .maxarg=0, .fn=showcache},
@@ -239,6 +263,7 @@
 	{.name="show",	.sub="snap",	.minarg=0, .maxarg=1, .fn=showsnap},
 	{.name="show",	.sub="tree",	.minarg=0, .maxarg=1, .fn=showtree},
 	{.name="show",	.sub="users",	.minarg=0, .maxarg=0, .fn=showusers},
+	{.name="show",	.sub="blk",	.minarg=1, .maxarg=1, .fn=showblkdump},
 	{.name="debug",	.sub=nil,	.minarg=1, .maxarg=1, .fn=setdbg},
 
 	{.name=nil, .sub=nil},
--- a/dat.h
+++ b/dat.h
@@ -22,6 +22,7 @@
 typedef struct Oplog	Oplog;
 typedef struct Mount	Mount;
 typedef struct User	User;
+typedef struct Stats	Stats;
 
 enum {
 	KiB	= 1024ULL,
@@ -84,7 +85,7 @@
 	Klabel,	/* name[] => snapid[]:		snapshot label */
 	Ktref,	/* tag[8] = snapid[]		scratch snapshot label */
 	Ksnap,	/* sid[8] => ref[8], tree[52]:	snapshot root */
-	Ksuper,	/* qid[8] => pqid[8]:		parent dir */
+	Ksuper,	/* qid[8] => Kent:		parent dir */
 	Kdirty,	/* [0] => [0]:			mark dirty unmount */
 };
 
@@ -92,7 +93,8 @@
 	Bdirty	= 1 << 0,
 	Bqueued	= 1 << 1,
 	Bfinal	= 1 << 2,
-	Bcached	= 1 << 3,
+	Bfreed	= 1 << 3,
+	Bcached	= 1 << 4,
 };
 
 /* internal errors */
@@ -122,6 +124,7 @@
 #define Efsize	"file too big"
 #define Ebadu	"attach -- unknown user or failed authentication"
 #define Erdonly	"file system read only"
+#define Elocked	"open/create -- file is locked"
 
 #define Ewstatb	"wstat -- unknown bits in qid.type/mode"
 #define Ewstatd	"wstat -- attempt to change directory"
@@ -151,7 +154,6 @@
 //#define Edot		"create/wstat -- . and .. illegal names"
 //#define Ewalk		"walk -- too many (system wide)"
 //#define Eoffset	"read/write -- offset negative"
-//#define Elocked	"open/create -- file is locked"
 //#define Ebroken	"read/write -- lock is broken"
 //#define Eauth		"attach -- authentication failed"
 //#define Eauth2	"read/write -- authentication unimplemented"
@@ -372,6 +374,11 @@
 	char	name[128];
 };
 
+struct Stats {
+	vlong	cachehit;
+	vlong	cachelook;
+};
+
 /*
  * Overall state of the file sytem.
  * Shadows the superblock contents.
@@ -438,6 +445,8 @@
 	Blk	*ctail;
 	int	ccount;
 	int	cmax;
+
+	Stats	stats;
 };
 
 struct Arena {
@@ -513,11 +522,13 @@
 	 * instead of the most recent root, to prevent
 	 * paging in the wrong executable.
 	 */
-	char	snap[64];
 	Mount	*mnt;
+	Scan	*scan;	/* in progres scan */
+	Dent	*dent;	/* (pqid, name) ref, modified on rename */
 
 	u32int	fid;
 	vlong	qpath;
+	vlong	pqpath;
 	long	ref;
 	int	mode;
 	int	iounit;
@@ -525,9 +536,6 @@
 	int	duid;
 	int	dgid;
 	int	dmode;
-
-	Scan	*scan;	/* in progres scan */
-	Dent	*dent;	/* (pqid, name) ref, modified on rename */
 };
 
 enum {
--- a/dump.c
+++ b/dump.c
@@ -34,7 +34,7 @@
 		n = fmtprint(fmt, "snap id:\"%llx\"", GBIT64(k->k+1));
 		break;
 	case Ksuper:	/* qid[8] => pqid[8]:		parent dir */
-		n = fmtprint(fmt, "up parent:%llx ptr:%llx", GBIT64(k->k+1), GBIT64(k->k+9));
+		n = fmtprint(fmt, "up dir:%llx", GBIT64(k->k+1));
 		break;
 	default:
 		n = fmtprint(fmt, "%.*H", k->nk, k->k);
@@ -69,7 +69,6 @@
 			n = fmtprint(fmt, "ptr:%B", unpackbp(v->v, v->nv));
 			break;
 		}
-		break;
 	case Kent:	/* pqid[8] name[n] => dir[n]:	serialized Dir */
 		switch(op){
 		case Onop:
@@ -131,7 +130,7 @@
 		n = fmtprint(fmt, "snap id:\"%llx\"", GBIT64(v->v+1));
 		break;
 	case Ksuper:	/* qid[8] => pqid[8]:		parent dir */
-		n = fmtprint(fmt, "parent: %llx", GBIT64(v->v));
+		n = fmtprint(fmt, "super dir:%llx, name:\"%.*s\")", GBIT64(v->v+1), v->nv-11, v->v+11);
 		break;
 	default:
 		n = fmtprint(fmt, "%.*H", v->nk, v->k);
@@ -302,7 +301,7 @@
 {
 	Blk *b;
 
-	b = getblk(bp, 0);
+	b = getblk(bp, GBnochk);
 	rshowblk(fd, b, 0, recurse);
 	putblk(b);
 }
--- a/fns.h
+++ b/fns.h
@@ -114,9 +114,11 @@
 char*	packtree(char*, int, Tree*);
 Tree*	unpacktree(Tree*, char*, int);
 char*	packdkey(char*, int, vlong, char*);
+char*	unpackdkey(char*, int, vlong*);
 char*	packdval(char*, int, Xdir*);
 char*	packsnap(char*, int, vlong);
 char*	packlabel(char*, int, char*);
+char*	packsuper(char*, int, vlong);
 
 /* fmt */
 int	Bconv(Fmt*);
--- a/fs.c
+++ b/fs.c
@@ -67,33 +67,6 @@
 	fprint(fd, "snap taken: %s\n", new);
 }
 
-static Tree*
-scratchsnap(Fid *f)
-{
-	Tree *t, *n;
-	char *e;
-
-	t = f->mnt->root;
-	if((n = newsnap(t)) == nil){
-		fprint(2, "snap: save %s: %s\n", f->mnt->name, "create snap");
-		abort();
-	}
-	if((e = labelsnap(f->mnt->name, t->gen)) != nil){
-		fprint(2, "snap: save %s: %s\n", f->mnt->name, e);
-		abort();
-	}
-	if(t->prev[0] != -1){
-		if((e = unrefsnap(t->prev[0], t->gen)) != nil){
-			fprint(2, "snap: unref old: %s\n", e);
-			abort();
-		}
-	}
-	f->mnt->root = n;
-	closesnap(t);
-	sync();
-	return nil;
-}
-
 void
 freemsg(Fmsg *m)
 {
@@ -433,7 +406,8 @@
 		if(f->fid == fid)
 			break;
 	unlock(&fs->fidtablk);
-	ainc(&f->ref);
+	if(f != nil)
+		ainc(&f->ref);
 	return f;
 }
 
@@ -477,7 +451,7 @@
 	unlock(&fs->fidtablk);
 
 	if(o != nil){
-		fprint(2, "fid in use: %d == %d\n", o->fid, new);
+		fprint(2, "fid in use: %d == %d", o->fid, new);
 		abort();
 		free(n);
 		return nil;
@@ -681,6 +655,7 @@
 	f.fid = NOFID;
 	f.mnt = mnt;
 	f.qpath = d.qid.path;
+	f.pqpath = d.qid.path;
 	f.mode = -1;
 	f.iounit = iounit;
 	f.dent = de;
@@ -700,10 +675,28 @@
 	return;
 }
 
+static char*
+findparent(Fid *f, vlong *qpath, char **name, char *buf, int nbuf)
+{
+	char *p, *e, kbuf[Keymax];
+	Kvp kv;
+	Key k;
+
+	if((p = packsuper(kbuf, sizeof(kbuf), f->pqpath)) == nil)
+		return Elength;
+	k.k = kbuf;
+	k.nk = p - kbuf;
+	if((e = lookup(f, &k, &kv, buf, nbuf, 0)) != nil)
+		return e;
+	if((*name = unpackdkey(kv.v, kv.nv, qpath)) == nil)
+		return Efs;
+	return nil;
+}
+
 void
 fswalk(Fmsg *m)
 {
-	char *p, *e, kbuf[Maxent], kvbuf[Kvmax];
+	char *p, *e, *name, kbuf[Maxent], kvbuf[Kvmax];
 	int duid, dgid, dmode;
 	vlong up, prev;
 	Fid *o, *f;
@@ -731,7 +724,15 @@
 	dmode = d.mode;
 	r.type = Rwalk;
 	for(i = 0; i < m->nwname; i++){
-		if((p = packdkey(kbuf, sizeof(kbuf), prev, m->wname[i])) == nil){
+		name = m->wname[i];
+		if(strcmp(m->wname[i], "..") == 0){
+			if((e = findparent(o, &prev, &name, kbuf, sizeof(kbuf))) != nil){
+				rerror(m, e);
+				putfid(o);
+				return;
+			}
+		}
+		if((p = packdkey(kbuf, sizeof(kbuf), prev, name)) == nil){
 			rerror(m, Elength);
 			putfid(o);
 			return;
@@ -738,9 +739,8 @@
 		}
 		k.k = kbuf;
 		k.nk = p - kbuf;
-		if((e = lookup(o, &k, &kv, kvbuf, sizeof(kvbuf), 0)) != nil){
+		if((e = lookup(o, &k, &kv, kvbuf, sizeof(kvbuf), 0)) != nil)
 			break;
-		}
 		duid = d.uid;
 		dgid = d.gid;
 		dmode = d.mode;
@@ -779,6 +779,7 @@
 		}
 		if(i == m->nwname){
 			f->qpath = r.wqid[i-1].path;
+			f->pqpath = up;
 			f->dent = dent;
 			f->duid = duid;
 			f->dgid = dgid;
@@ -986,12 +987,13 @@
 void
 fscreate(Fmsg *m)
 {
-	char *e, buf[Kvmax];
+	char *p, *e, buf[Kvmax], upkbuf[Keymax], upvbuf[Inlmax];
 	Dent *de;
 	Fcall r;
-	Msg mb;
+	Msg mb[2];
 	Fid *f;
 	Xdir d;
+	int nm;
 
 	if(okname(m->name) == -1){
 		rerror(m, Ename);
@@ -1014,6 +1016,7 @@
 	}
 	runlock(de);
 
+	nm = 0;
 	d.qid.type = 0;
 	if(m->perm & DMDIR)
 		d.qid.type |= QTDIR;
@@ -1034,13 +1037,27 @@
 	d.gid = f->dgid;
 	d.muid = f->mnt->uid;
 
-	mb.op = Oinsert;
-	if(dir2kv(f->qpath, &d, &mb, buf, sizeof(buf)) == -1){
+	mb[nm].op = Oinsert;
+	if(dir2kv(f->qpath, &d, &mb[nm], buf, sizeof(buf)) == -1){
 		rerror(m, Efs);
 		putfid(f);
 		return;
 	}
-	if((e = btupsert(f->mnt->root, &mb, 1)) != nil){
+	nm++;
+
+	if(m->perm & DMDIR){
+		mb[nm].op = Oinsert;
+		if((p = packsuper(upkbuf, sizeof(upkbuf), d.qid.path)) == nil)
+			sysfatal("ream: pack super");
+		mb[nm].k = upkbuf;
+		mb[nm].nk = p - upkbuf;
+		if((p = packdkey(upvbuf, sizeof(upvbuf), f->qpath, d.name)) == nil)
+			sysfatal("ream: pack super");
+		mb[nm].v = upvbuf;
+		mb[nm].nv = p - upvbuf;
+		nm++;
+	}
+	if((e = btupsert(f->mnt->root, mb, nm)) != nil){
 		rerror(m, e);
 		putfid(f);
 		return;
@@ -1215,7 +1232,7 @@
 //	}
 	if(f->mode & OTRUNC){
 		wlock(f->dent);
-//		freeb(f->dent, 0, dent->length);
+		clearb(f, 0, f->dent->length);
 		f->dent->length = 0;
 		wunlock(f->dent);
 	}
@@ -1565,7 +1582,7 @@
 	Amsg *a;
 
 	while(1){
-		sleep(500);
+		sleep(5000);
 		m = mallocz(sizeof(Fmsg), 1);
 		a = mallocz(sizeof(Amsg), 1);
 		if(m == nil || a == nil){
--- a/pack.c
+++ b/pack.c
@@ -165,6 +165,37 @@
 }
 
 char*
+unpackdkey(char *p, int sz, vlong *up)
+{
+	char t, *ep, *name;
+	int err;
+
+	err = 0;
+	ep = p + sz;
+	p = unpack8(&err, p, ep, &t);
+	p = unpack64(&err, p, ep, up);
+	p = unpackstr(&err, p, ep, &name);
+	if(err || t != Kent || p != ep)
+		return nil;
+	return name;
+}
+
+char*
+packsuper(char *p, int sz, vlong up)
+{
+	char *ep;
+	int err;
+
+	err = 0;
+	ep = p + sz;
+	p = pack8(&err, p, ep, Ksuper);
+	p = pack64(&err, p, ep, up);
+	if(err)
+		return nil;
+	return p;
+}
+
+char*
 packdval(char *p, int sz, Xdir *d)
 {
 	char *e;
--- a/ream.c
+++ b/ream.c
@@ -11,7 +11,7 @@
 static void
 initroot(Blk *r)
 {
-	char buf[512];
+	char *p, kbuf[Keymax], vbuf[Inlmax];
 	Kvp kv;
 	Xdir d;
 
@@ -26,17 +26,18 @@
 	d.uid = 2;
 	d.gid = 2;
 	d.muid = 2;
-	if(dir2kv(-1, &d, &kv, buf, sizeof(buf)) == -1)
+	if(dir2kv(-1, &d, &kv, vbuf, sizeof(vbuf)) == -1)
 		sysfatal("ream: pack root: %r");
 	setval(r, 0, &kv);
 
-	kv.k = buf;
-	kv.nk = 9;
-	kv.v = buf+9;
-	kv.nv = 8;
-	buf[0] = Ksuper;
-	PBIT64(buf+1, 0ULL);
-	PBIT64(buf+9, 0ULL);
+	if((p = packsuper(kbuf, sizeof(kbuf), 0)) == nil)
+		sysfatal("ream: pack super");
+	kv.k = kbuf;
+	kv.nk = p - kbuf;
+	if((p = packdkey(vbuf, sizeof(vbuf), -1, "")) == nil)
+		sysfatal("ream: pack super");
+	kv.v = vbuf;
+	kv.nv = p - vbuf;
 	setval(r, 1, &kv);
 }
 
@@ -105,7 +106,7 @@
 
 	p = b->data+Loghdsz;
 	PBIT64(p, addr|LogFree);	p += 8;	/* addr */
-	PBIT64(p, asz);			p += 8;	/* len */
+	PBIT64(p, asz-Blksz);		p += 8;	/* len */
 	PBIT64(p, b->bp.addr|LogAlloc);	p += 8;	/* addr */
 	PBIT64(p, Blksz);		p += 8;	/* len */
 	PBIT64(p, (uvlong)LogEnd);	/* done */
--- a/tree.c
+++ b/tree.c
@@ -7,6 +7,23 @@
 #include "fns.h"
 
 void
+stablesort(Msg *m, int nm)
+{
+	int i, j;
+	Msg t;
+
+	for(i = 1; i < nm; i++){
+		for(j = i; j > 0; j--){
+			if(keycmp(&m[j-1], &m[j]) <= 0)
+				break;
+			t = m[j-1];
+			m[j-1] = m[j];
+			m[j] = t;
+		}
+	}
+}
+
+void
 cpkey(Key *dst, Key *src, char *buf, int nbuf)
 {
 	assert(src->nk <= nbuf);
@@ -1169,12 +1186,9 @@
 	Bptr bp;
 
 	sz = 0;
-	qsort(msg, nmsg, sizeof(Msg), msgcmp);
-	for(i = 0; i < nmsg; i++){
-		if(msg[i].nk + 2 > Keymax)
-			return Efs;
+	stablesort(msg, nmsg);
+	for(i = 0; i < nmsg; i++)
 		sz += msgsz(&msg[i]);
-	}
 
 Again:
 	if((b = getroot(t, &height)) == nil)
@@ -1298,7 +1312,15 @@
 		j = bufsearch(p[i], k, &m, &same);
 		if(j < 0 || !same)
 			continue;
-		assert(ok || m.op == Oinsert);
+		if(!(ok || m.op == Oinsert)){
+			fprint(2, "lookup %K << %M missing insert\n", k, &m);
+			for(int j = 0; j < h; j++){
+				print("busted %d\n",j);
+				if(p[j] != nil)
+					showblk(2, p[j], "busted insert", 0);
+			}
+			abort();
+		}
 		ok = apply(r, &m, buf, nbuf);
 		for(j++; j < p[i]->nbuf; j++){
 			getmsg(p[i], j, &m);