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);