shithub: gefs

Download patch

ref: 40a7bbda7392fdc8183678ea82323cded91b14ce
parent: 1c52bff742ac452c853b93fa9a05b2ac0f243714
author: Ori Bernstein <ori@eigenstate.org>
date: Sun Oct 30 10:52:13 EDT 2022

fs: add 'dump' attach spec to mount snapshot dump

--- a/dat.h
+++ b/dat.h
@@ -103,6 +103,10 @@
 	Bcached	= 1 << 3,
 };
 
+enum {
+	Qdump = 1ULL << 63,
+};
+
 /* internal errors */
 #define Efs	(abort(), "fs broke")
 extern char Eimpl[];
@@ -435,9 +439,10 @@
 	Rendez	syncrz;
 
 	QLock	snaplk;	/* snapshot lock */
-	Tree	*osnap;
+	Tree	*opensnap;
 	Lock	mountlk;
 	Mount	*mounts;
+	Mount	*snapmnt;
 	Lock	connlk;
 	Conn	*conns;
 
--- a/fs.c
+++ b/fs.c
@@ -71,6 +71,23 @@
 }
 
 static void
+filldumpdir(Xdir *d)
+{
+	memset(d, 0, sizeof(Xdir));
+	d->name = "/";
+	d->qid.path = Qdump;
+	d->qid.vers = fs->nextgen;
+	d->qid.type = QTDIR;
+	d->mode = 0555;
+	d->atime = 0;
+	d->mtime = 0;
+	d->length = 0;
+	d->uid = -1;
+	d->gid = -1;
+	d->muid = -1;
+}
+
+static void
 freemsg(Fmsg *m)
 {
 	free(m->a);
@@ -202,17 +219,19 @@
 
 
 static char*
-lookup(Fid *f, Key *k, Kvp *kv, char *buf, int nbuf)
+lookup(Mount *mnt, Key *k, Kvp *kv, char *buf, int nbuf)
 {
 	char *e;
 	Tree *r;
 
-	if(f->mnt == nil)
+	if(mnt == nil)
 		return Eattach;
-	lock(f->mnt);
-	r = f->mnt->root;
+
+	lock(mnt);
+	r = mnt->root;
 	ainc(&r->memref);
-	unlock(f->mnt);
+	unlock(mnt);
+
 	e = btlookup(r, k, kv, buf, nbuf);
 	closesnap(r);
 	return e;
@@ -268,7 +287,7 @@
 	PACK64(k.k+1, f->qpath);
 	PACK64(k.k+9, fb);
 
-	e = lookup(f, &k, &kv, kvbuf, sizeof(kvbuf));
+	e = lookup(f->mnt, &k, &kv, kvbuf, sizeof(kvbuf));
 	if(e != nil){
 		if(e != Eexist){
 			werrstr(e);
@@ -308,7 +327,7 @@
 		return -1;
 	t = nil;
 	if(fb < sz && (fo != 0 || n != Blksz)){
-		e = lookup(f, m, &kv, buf, sizeof(buf));
+		e = lookup(f->mnt, m, &kv, buf, sizeof(buf));
 		if(e == nil){
 			bp = unpackbp(kv.v, kv.nv);
 			if((t = getblk(bp, GBraw)) == nil)
@@ -383,6 +402,10 @@
 	Mount *mnt;
 	Tree *t;
 
+	if(strcmp(name, "dump") == 0){
+		ainc(&fs->snapmnt->ref);
+		return fs->snapmnt;
+	}
 	lock(&fs->mountlk);
 	for(mnt = fs->mounts; mnt != nil; mnt = mnt->next)
 		if(strcmp(name, mnt->name) == 0){
@@ -849,20 +872,25 @@
 		goto Out;
 	}
 
-	if((p = packdkey(dbuf, sizeof(dbuf), -1ULL, "")) == nil){
-		rerror(m, Elength);
-		goto Out;
+	if(strcmp(m->aname, "dump") == 0){
+		memset(&d, 0, sizeof(d));
+		filldumpdir(&d);
+	}else{
+		if((p = packdkey(dbuf, sizeof(dbuf), -1ULL, "")) == nil){
+			rerror(m, Elength);
+			goto Out;
+		}
+		dk.k = dbuf;
+		dk.nk = p - dbuf;
+		if((e = btlookup(mnt->root, &dk, &kv, kvbuf, sizeof(kvbuf))) != nil){
+			rerror(m, e);
+			goto Out;
+		}
+		if(kv2dir(&kv, &d) == -1){
+			rerror(m, Efs);
+			goto Out;
+		}
 	}
-	dk.k = dbuf;
-	dk.nk = p - dbuf;
-	if((e = btlookup(mnt->root, &dk, &kv, kvbuf, sizeof(kvbuf))) != nil){
-		rerror(m, e);
-		goto Out;
-	}
-	if(kv2dir(&kv, &d) == -1){
-		rerror(m, Efs);
-		goto Out;
-	}
 	if((de = getdent(-1, &d)) == nil){
 		rerror(m, Efs);
 		goto Out;
@@ -905,7 +933,7 @@
 		return Elength;
 	k.k = kbuf;
 	k.nk = p - kbuf;
-	if((e = lookup(f, &k, &kv, buf, nbuf)) != nil)
+	if((e = lookup(f->mnt, &k, &kv, buf, nbuf)) != nil)
 		return e;
 	if((*name = unpackdkey(kv.v, kv.nv, qpath)) == nil)
 		return Efs;
@@ -920,6 +948,7 @@
 	vlong up, prev;
 	Fid *o, *f;
 	Dent *dent;
+	Mount *mnt;
 	Fcall r;
 	Xdir d;
 	Kvp kv;
@@ -936,6 +965,7 @@
 		return;
 	}
 	e = nil;
+	mnt = o->mnt;
 	up = o->qpath;
 	prev = o->qpath;
 	rlock(o->dent);
@@ -952,30 +982,47 @@
 			return;
 		}
 		name = m->wname[i];
-		if(strcmp(m->wname[i], "..") == 0){
-			if((e = findparent(o, &prev, &name, kbuf, sizeof(kbuf))) != nil){
-				rerror(m, e);
+		if(d.qid.path == Qdump){
+			if((mnt = getmount(m->wname[i])) == nil){
 				putfid(o);
 				return;
 			}
+			if((p = packdkey(kbuf, sizeof(kbuf), -1ULL, "")) == nil){
+				clunkmount(mnt);
+				putfid(o);
+				return;
+			}
+		}else{
+			if(strcmp(m->wname[i], "..") == 0){
+				if(o->pqpath == Qdump){
+					mnt = fs->snapmnt;
+					filldumpdir(&d);
+					goto Found;
+				}else 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;
+			}
 		}
-		if((p = packdkey(kbuf, sizeof(kbuf), prev, name)) == nil){
-			rerror(m, Elength);
-			putfid(o);
-			return;
-		}
 		k.k = kbuf;
 		k.nk = p - kbuf;
-		if((e = lookup(o, &k, &kv, kvbuf, sizeof(kvbuf))) != nil)
+		if((e = lookup(mnt, &k, &kv, kvbuf, sizeof(kvbuf))) != nil)
 			break;
-		duid = d.uid;
-		dgid = d.gid;
-		dmode = d.mode;
 		if(kv2dir(&kv, &d) == -1){
 			rerror(m, Efs);
 			putfid(o);
 			return;
 		}
+Found:
+		duid = d.uid;
+		dgid = d.gid;
+		dmode = d.mode;
 		up = prev;
 		prev = d.qid.path;
 		r.wqid[i] = d.qid;
@@ -996,14 +1043,24 @@
 		putfid(o);
 	}
 	if(i > 0 && i == m->nwname){
-		dent = getdent(up, &d);
+		lock(f);
+		if(up == Qdump)
+			dent = getdent(-1ULL, &d);
+		else
+			dent = getdent(up, &d);
 		if(dent == nil){
 			if(f != o)
 				clunkfid(m->conn, f);
 			rerror(m, Enomem);
+			unlock(f);
 			putfid(f);
 			return;
 		}
+		if(mnt != f->mnt){
+			clunkmount(f->mnt);
+			ainc(&mnt->ref);
+			f->mnt = mnt;
+		}
 		f->qpath = r.wqid[i-1].path;
 		f->pqpath = up;
 		f->dent = dent;
@@ -1010,6 +1067,7 @@
 		f->duid = duid;
 		f->dgid = dgid;
 		f->dmode = dmode;
+		unlock(f);
 	}
 	respond(m, &r);
 	putfid(f);
@@ -1063,7 +1121,7 @@
 	}
 	de = f->dent;
 	wlock(de);
-	if(de->qid.type & QTAUTH){
+	if((de->qid.type & QTAUTH) || (de->qid.path & Qdump)){
 		rerror(m, Emode);
 		goto Out;
 	}
@@ -1256,7 +1314,6 @@
 		rerror(m, Efid);
 		return;
 	}
-
 	lock(f);
 	if(f->scan != nil){
 		btdone(f->scan);
@@ -1486,16 +1543,21 @@
 		rerror(m, Efid);
 		return;
 	}
-	if((e = lookup(f, f->dent, &kv, buf, sizeof(buf))) != nil){
-		rerror(m, e);
-		putfid(f);
-		return;
+
+	if((f->qpath & Qdump) != 0){
+		filldumpdir(&d);
+	}else{
+		if((e = lookup(f->mnt, f->dent, &kv, buf, sizeof(buf))) != nil){
+			rerror(m, e);
+			putfid(f);
+			return;
+		}
+		if(kv2dir(&kv, &d) == -1){
+			rerror(m, Efs);
+			putfid(f);
+			return;
+		}
 	}
-	if(kv2dir(&kv, &d) == -1){
-		rerror(m, Efs);
-		putfid(f);
-		return;
-	}
 	if(fsaccess(f, d.mode, d.uid, d.gid, mbits) == -1){
 		rerror(m, Eperm);
 		putfid(f);
@@ -1590,6 +1652,73 @@
 }
 
 static char*
+readsnap(Fmsg *m, Fid *f, Fcall *r)
+{
+	char pfx[1], *p, *e;
+	int n, ns, done;
+	Scan *s;
+	Xdir d;
+
+	s = f->scan;
+	if(s != nil && s->offset != 0 && s->offset != m->offset)
+		return Edscan;
+	if(s == nil || m->offset == 0){
+		if((s = mallocz(sizeof(Scan), 1)) == nil)
+			return Enomem;
+		pfx[0] = Klabel;
+		if((e = btscan(&fs->snap, s, pfx, 1)) != nil){
+			btdone(s);
+			free(s);
+			return e;
+		}
+
+		lock(f);
+		if(f->scan != nil){
+			btdone(f->scan);
+			free(f->scan);
+		}
+		f->scan = s;
+		unlock(f);
+	}
+	if(s->done){
+		r->count = 0;
+		return nil;
+	}
+	p = r->data;
+	n = m->count;
+	d = f->dent->Xdir;
+	if(s->overflow){
+		memcpy(d.name, s->kv.k+1, s->kv.nk-1);
+		d.name[s->kv.nk-1] = 0;
+		d.qid.path = UNPACK64(s->kv.v + 1);
+		if((ns = dir2statbuf(&d, p, n)) == -1){
+			r->count = 0;
+			return nil;
+		}
+		s->overflow = 0;
+		p += ns;
+		n -= ns;
+	}
+	while(1){
+		if((e = btnext(s, &s->kv, &done)) != nil)
+			return e;
+		if(done)
+			break;
+		memcpy(d.name, s->kv.k+1, s->kv.nk-1);
+		d.name[s->kv.nk-1] = 0;
+		d.qid.path = UNPACK64(s->kv.v + 1);
+		if((ns = dir2statbuf(&d, p, n)) == -1){
+			s->overflow = 1;
+			break;
+		}
+		p += ns;
+		n -= ns;
+	}
+	r->count = p - r->data;
+	return nil;
+}
+
+static char*
 readdir(Fmsg *m, Fid *f, Fcall *r)
 {
 	char pfx[Dpfxsz], *p, *e;
@@ -1705,6 +1834,8 @@
 	}
 	if(f->dent->qid.type & QTAUTH)
 		e = readauth(m, f, &r);
+	else if(f->dent->qid.path == Qdump)
+		e = readsnap(m, f, &r);
 	else if(f->dent->qid.type & QTDIR)
 		e = readdir(m, f, &r);
 	else
@@ -1950,15 +2081,11 @@
 			}
 			break;
 		case AOsync:
-			if(m->a->fd != -1)
-				fprint(m->a->fd, "syncing [readonly: %d]\n", m->a->halt);
 			if(m->a->halt)
 				ainc(&fs->rdonly);
 			for(mnt = fs->mounts; mnt != nil; mnt = mnt->next)
 				updatemount(mnt);
 			sync();
-			if(m->a->fd != -1)
-				fprint(m->a->fd, "sync done\n");
 			freemsg(m);
 			break;
 		case AOsnap:
--- a/load.c
+++ b/load.c
@@ -46,6 +46,7 @@
 void
 loadfs(char *dev)
 {
+	Mount *mnt;
 	Fshdr fi;
 	Arena *a;
 	char *e;
@@ -52,7 +53,17 @@
 	Tree *t;
 	int i, k;
 
-	fs->osnap = nil;
+	if((mnt = mallocz(sizeof(*mnt), 1)) == nil)
+		sysfatal("malloc: %r");
+	if((mnt->name = strdup("dump")) == nil)
+		sysfatal("malloc: %r");
+	mnt->ref = 1;
+	mnt->root = nil;
+	mnt->gen = -1;
+	mnt->root = &fs->snap;
+
+	fs->opensnap = nil;
+	fs->snapmnt = mnt;
 	fs->gotinfo = 0;
 	fs->narena = 1;
 	if((fs->fd = open(dev, ORDWR)) == -1)
--- a/snap.c
+++ b/snap.c
@@ -175,7 +175,7 @@
 	Key k;
 
 	qlock(&fs->snaplk);
-	for(t = fs->osnap; t != nil; t = t->snext){
+	for(t = fs->opensnap; t != nil; t = t->snext){
 		if(t->gen == id){
 			ainc(&t->memref);
 			qunlock(&fs->snaplk);
@@ -195,8 +195,8 @@
 	if(unpacktree(t, kv.v, kv.nv) == nil)
 		goto Error;
 	t->memref = 1;
-	t->snext = fs->osnap;
-	fs->osnap = t;
+	t->snext = fs->opensnap;
+	fs->opensnap = t;
 	qunlock(&fs->snaplk);
 	return t;
 
@@ -225,8 +225,8 @@
 //FIXME: 	putblk(ins);
 	}
 
-	p = &fs->osnap;
-	for(te = fs->osnap; te != nil; te = te->snext){
+	p = &fs->opensnap;
+	for(te = fs->opensnap; te != nil; te = te->snext){
 		if(te == t)
 			break;
 		p = &te->snext;
@@ -275,6 +275,8 @@
 	char *p, *e, kbuf[Keymax], vbuf[Snapsz];
 	Msg m;
 
+	if(strcmp(name, "dump") == 0)
+		return Ename;
 	if(op == Oinsert)
 		e = refsnap(id);
 	else
@@ -399,7 +401,7 @@
 		return nil;
 	gen = aincv(&fs->nextgen, 1);
 	memset(&r->lk, 0, sizeof(r->lk));
-	r->snext = fs->osnap;
+	r->snext = fs->opensnap;
 	r->memref = 1;
 	r->ref = 0;
 	r->ht = t->ht;
@@ -414,7 +416,7 @@
 		r->dead[i].head.gen = -1;
 		r->dead[i].ins = nil;
 	}
-	fs->osnap = r;
+	fs->opensnap = r;
 
 	return r;
 }