git: 9front

Download patch

ref: 3f120c546f91572a86d8c4cd1e91f2d41a5c2ca9
parent: aa219605f0375f72520bfe796b9db938d11d0fcc
author: Ori Bernstein <ori@eigenstate.org>
date: Sun Nov 2 21:31:49 EST 2025

gefs: add fuzzer support for block creation

--- a/sys/src/cmd/gefs/fuzz.c
+++ b/sys/src/cmd/gefs/fuzz.c
@@ -8,6 +8,7 @@
 #include "fns.h"
 
 typedef struct Fuzz	Fuzz;
+typedef struct Rand	Rand;
 typedef struct Shadow	Shadow;
 
 struct Shadow {
@@ -16,6 +17,12 @@
 	char buf[Kvmax];
 };
 
+struct Rand {
+	u32int s[4];
+};
+
+Rand Wr, Rr;
+
 struct Fuzz {
 	Mount *mnt;
 	int nops;
@@ -26,13 +33,39 @@
 Lock	shadowlk;
 int	nshadow;
 
+static ulong
+xrand(Rand *r, ulong n)
+{
+	ulong v, t, x, slop;
+
+	slop = 0x7fffffffL % n;
+	do{
+		x = r->s[0] + r->s[3];
+		v = (x << 7 | x >> (32-7)) + r->s[0];
+		t = r->s[1] << 9;
+		r->s[2] ^= r->s[0];
+		r->s[3] ^= r->s[1];
+		r->s[1] ^= r->s[2];
+		r->s[0] ^= r->s[3];
+		r->s[2] ^= t;
+		r->s[3] = r->s[3] << 11 | r->s[3] >> (32-11);
+	}while(v <= slop);
+	return v%n;
+}
+
+static void
+xsrand(Rand *r, ulong seed)
+{
+	r->s[0] = seed;
+}
+
 static uvlong
-vrand(void)
+vrand(Rand *r)
 {
 	uvlong v;
-	v = nrand(1<<4);
-	v = (v<<30) | nrand(1<<30);
-	v = (v<<30) | nrand(1<<30);
+	v = xrand(r, 1<<4);
+	v = (v<<30) | xrand(r, 1<<30);
+	v = (v<<30) | xrand(r, 1<<30);
 	return v;
 }
 
@@ -55,77 +88,88 @@
 }
 
 static void
-genname(char *name, int *nname)
+genname(char *s, int n)
 {
-	int n, i;
-	char c;
+	int i, c;
 
-	n = 1 + nrand(244);
 	for(i = 0; i < n; i++){
 		do {
-			c = nrand(256);
+			c = xrand(&Wr, 256);
 		} while(c == '/' || c == '\0');
-		name[i] = c;
+		*s++ = c;
 	}
-	*nname = n;
+	*s = 0;
 }
 
 static void
-genent(char *k, int *nk)
+genent(Msg *m, char *k)
 {
-	char name[256], *p;
+	char buf[256], *p;
 	vlong pqid;
-	int nname;
+	int n;
 
-	pqid = (vlong)nrand(1<<30) << 32 | nrand(1<<30);
-	genname(name, &nname);
-	name[nname] = '\0';
-	p = packdkey(k, Keymax, pqid, name);
-	*nk = p - k;
+	n = 1 + xrand(&Wr, 243);
+	pqid = vrand(&Wr);
+	genname(buf, n);
+
+	p = packdkey(k, Keymax, pqid, buf);
+	m->k = k;
+	m->nk = p - k;
 }
 
 static void
-gendir(char *v, short *nv)
+gendptr(Msg *m, char *k)
 {
+	vlong qid, off;
 	char *p;
-	Xdir d;
 
-	memset(&d, 0, sizeof(d));
-	d.flag = 0;
-	d.qid.path = vrand();
-	d.qid.vers = nrand(1<<20);
-	d.qid.type = nrand(2) ? QTFILE : QTDIR;
-	d.mode = nrand(2) ? 0644 : (DMDIR|0755);
-	d.atime = vrand();
-	d.mtime = vrand();
-	d.length = nrand(1<<20);
-	d.uid = nrand(100);
-	d.gid = nrand(100);
-	d.muid = nrand(100);
-
-	p = packdval(v, Inlmax, &d);
-	*nv = p - v;
+	qid = vrand(&Wr);
+	off = vrand(&Wr) & ~(Blksz-1);
+	p = k;
+	p[0] = Kdat;	p += 1;
+	PACK64(p, qid);	p += 8;
+	PACK64(p, off);	p += 8;
+	m->k = k;
+	m->nk = p - k;
 }
 
 static void
-genins(Msg *m, char *kbuf, char *vbuf)
+gendblk(Tree *t, Msg *m, char *v)
 {
-	m->op = Oinsert;
-	m->k = kbuf;
-	genent(kbuf, &m->nk);
-	m->v = vbuf;
-	gendir(vbuf, &m->nv);
-}
+	Blk *b;
+	int seq;
 
+	seq = xrand(&Wr, 2);
+	b = newdblk(t, 0, seq);
+	memset(b->buf, 0x42, Blksz);
+	packbp(v, Ptrsz, &b->bp);
+	enqueue(b);
+	dropblk(b);
+	m->v = v;
+	m->nv = Ptrsz;
+}
 static void
-gendel(Msg *m, Key *k, char *kbuf)
+gendir(Msg *m, char *v)
 {
-	memcpy(kbuf, k->k, k->nk);
-	m->op = Odelete;
-	m->k = kbuf;
-	m->nk = k->nk;
-	m->v = nil;
-	m->nv = 0;
+	char *p;
+	Xdir d;
+
+	memset(&d, 0, sizeof(d));
+	d.flag = 0;
+	d.qid.path = vrand(&Wr);
+	d.qid.vers = xrand(&Wr, 1<<20);
+	d.qid.type = xrand(&Wr, 2) ? QTFILE : QTDIR;
+	d.mode = xrand(&Wr, 2) ? 0644 : (DMDIR|0755);
+	d.atime = vrand(&Wr);
+	d.mtime = vrand(&Wr);
+	d.length = xrand(&Wr, 1<<20);
+	d.uid = xrand(&Wr, 100);
+	d.gid = xrand(&Wr, 100);
+	d.muid = xrand(&Wr, 100);
+
+	p = packdval(v, Inlmax, &d);
+	m->v = v;
+	m->nv = p - v;
 }
 
 static void
@@ -144,41 +188,41 @@
 
 	p = vbuf;
 	do {
-		flags = nrand(128);
+		flags = xrand(&Wr, 128);
 	} while(flags == 0);
 	*p++ = flags;
 	if(flags & Owsize){
-		size = nrand(1<<20);
+		size = xrand(&Wr, 1<<20);
 		PACK64(p, size);
 		p += 8;
 	}
 	if(flags & Owmode){
-		mode = nrand(2) ? 0644 : (DMDIR|0755);
+		mode = xrand(&Wr, 2) ? 0644 : (DMDIR|0755);
 		PACK32(p, mode);
 		p += 4;
 	}
 	if(flags & Owmtime){
-		mtime = vrand();
+		mtime = vrand(&Wr);
 		PACK64(p, mtime);
 		p += 8;
 	}
 	if(flags & Owatime){
-		atime = vrand();
+		atime = vrand(&Wr);
 		PACK64(p, atime);
 		p += 8;
 	}
 	if(flags & Owuid){
-		uid = nrand(100);
+		uid = xrand(&Wr, 100);
 		PACK32(p, uid);
 		p += 4;
 	}
 	if(flags & Owgid){
-		gid = nrand(100);
+		gid = xrand(&Wr, 100);
 		PACK32(p, gid);
 		p += 4;
 	}
 	if(flags & Owmuid){
-		muid = nrand(100);
+		muid = xrand(&Wr, 100);
 		PACK32(p, muid);
 		p += 4;
 	}
@@ -197,7 +241,7 @@
 }
 
 static Shadow*
-pickrand(void)
+pickrand(Rand *r)
 {
 	Avl *a, *c;
 	int n, i;
@@ -204,7 +248,7 @@
 
 	if(shadow->root == nil)
 		return nil;
-	n = nrand(nshadow);
+	n = xrand(r, nshadow);
 	a = shadow->root;
 	i = nshadow;
 	while(i > 1){
@@ -370,39 +414,52 @@
 }
 
 static void
-genrand(Msg *m, char *kbuf, char *vbuf, Msg *batch, int nbatch)
+genrand(Tree *t, Msg *m, char *kbuf, char *vbuf, Msg *batch, int nbatch)
 {
 	Shadow *s;
 	int op, d;
 
-	s = pickrand();
-	op = nrand(100);
+Again:
+	s = pickrand(&Wr);
+	op = xrand(&Wr, 100);
 	/* If deleted, we need to do an insert or a replacement */
 	d = deleted(batch, nbatch, s);
-	if(d) d += nrand(2);
+	if(d) d += xrand(&Wr, 2);
 	/* 40% chance of new insertion */
 	if(s == nil || op < 40 || d == 1){
-		genins(m, kbuf, vbuf);
+		m->op = Oinsert;
+		if(xrand(&Wr, 2) == 0){
+			genent(m, kbuf);
+			gendir(m, vbuf);
+		}else{
+			gendptr(m, kbuf);
+			gendblk(t, m, vbuf);
+		}
 		return;
 	}
 	/* 20% chance of clobber */
 	if(op < 60 || d == 2){
-		memmove(kbuf, s->k, s->nk);
 		m->op = Oinsert;
-		m->k = kbuf;
-		m->nk = s->nk;
-		m->v = vbuf;
-		gendir(vbuf, &m->nv);
+		cpkey(m, s, kbuf, Keymax);
+		switch(m->k[0]){
+		case Kent:	gendir(m, vbuf);	break;
+		case Kdat:	gendblk(t, m, vbuf);	break;
+		default:	goto Again;		break;
+		}
 		return;
 	}
+	assert(d == 0);
 	/* 20% of Owstat */
-	if(op < 80){
+	if(op < 80 && s->k[0] == Kent){
 		genwstat(m, s, kbuf, vbuf);
 		return;
 	}
 	/* 20% chance of delete */
 	if(op < 100){
-		gendel(m, s, kbuf);
+		m->op = Odelete;
+		cpkey(m, s, kbuf, Keymax);
+		m->v = nil;
+		m->nv = 0;
 		return;
 	}
 	abort();
@@ -426,16 +483,19 @@
 	 * the upsert, so we need to keep the tree somewhere
 	 * temporary as we do the update.
 	 */
+	qlock(&fs->mutlk);
 	lock(&shadowlk);
 	memset(&t, 0, sizeof(Tree));
 	r = agetp(&fz->mnt->root);
+	nm = 1 + xrand(&Wr, nelem(m)-1);
+	for(i = 0; i < nm; i++)
+		genrand(r, &m[i], kbuf[i], vbuf[i], m, i);
 	lock(&r->lk);
 	t.bp = r->bp;
 	t.ht = r->ht;
+	t.gen = r->gen;
+	t.memgen = r->memgen;
 	unlock(&r->lk);
-	nm = 1 + nrand(nelem(m)-1);
-	for(i = 0; i < nm; i++)
-		genrand(&m[i], kbuf[i], vbuf[i], m, i);
 	unlock(&shadowlk);
 
 	if(waserror()){
@@ -446,7 +506,6 @@
 			fprint(2, "  msg[%d]: %M\n", i, &m[i]);
 		fail("btupsert failure\n");
 	}
-	qlock(&fs->mutlk);
 	epochstart(tid);
 	btupsert(&t, m, nm);
 	epochend(tid);
@@ -456,10 +515,11 @@
 	lock(&shadowlk);
 	for(i = 0; i < nm; i++)
 		shadowapply(&m[i]);
-	r = agetp(&fz->mnt->root);
 	lock(&r->lk);
 	r->bp = t.bp;
 	r->ht = t.ht;
+	r->gen = t.gen;
+	r->memgen = t.memgen;
 	unlock(&r->lk);
 	fz->nops += nm;
 	unlock(&shadowlk);
@@ -499,7 +559,7 @@
 	for(i = 0; i < nsamp; i++){
 		if(nshadow == 0)
 			break;
-		s = pickrand();
+		s = pickrand(&Rr);
 		ok = btlookup(t, s, &kv, buf, sizeof(buf));
 		if(!ok)
 			fail("key %K not found in tree, nops: %d\n", &s->Key, fz->nops);
@@ -584,7 +644,8 @@
 		sysfatal("getmount fuzz: %r");
 	fz->nops = 0;
 
-	srand(fuzzseed);
+	xsrand(&Rr, fuzzseed);
+	xsrand(&Wr, fuzzseed);
 	buf[0] = Kent;
 	btnewscan(&sc, buf, 1);
 	t = agetp(&fz->mnt->root);
--