Browse Source

Plan 9 from Bell Labs 2003-01-12

David du Colombier 21 years ago
parent
commit
7287ac9e78

+ 15 - 15
dist/replica/plan9.db

@@ -2850,7 +2850,7 @@ power/mkfile - 664 sys sys 948141304 46
 rc - 20000000775 sys sys 944959447 0
 rc/bin - 20000000775 sys sys 1018637942 0
 rc/bin/9fat: - 775 sys sys 1015089559 354
-rc/bin/9fs - 775 sys sys 1041013198 709
+rc/bin/9fs - 775 sys sys 1042305252 869
 rc/bin/B - 775 sys sys 945617206 645
 rc/bin/C - 775 sys sys 985732271 557
 rc/bin/Kill - 775 sys sys 1018637942 115
@@ -4508,7 +4508,7 @@ sys/man/1/spell - 664 sys sys 964455062 1873
 sys/man/1/spin - 664 sys sys 953242867 3588
 sys/man/1/split - 664 sys sys 1038183072 1171
 sys/man/1/src - 664 sys sys 954266293 1138
-sys/man/1/ssh - 664 sys sys 1038293627 6964
+sys/man/1/ssh - 664 sys sys 1042330461 6968
 sys/man/1/stop - 664 sys sys 944959673 658
 sys/man/1/strings - 664 sys sys 944959675 774
 sys/man/1/strip - 664 sys sys 958580250 448
@@ -4830,7 +4830,7 @@ sys/man/8/cpurc - 664 sys sys 971455510 1275
 sys/man/8/cron - 664 sys sys 944959679 1750
 sys/man/8/dhcpd - 664 sys sys 1032654987 5237
 sys/man/8/drawterm - 664 sys sys 958419689 2458
-sys/man/8/fossilcons - 664 sys sys 1042005415 12630
+sys/man/8/fossilcons - 664 sys sys 1042312265 12639
 sys/man/8/fs - 664 sys sys 1037805200 13843
 sys/man/8/fsconfig - 664 sys sys 1037805200 7966
 sys/man/8/httpd - 664 sys sys 1037690024 4516
@@ -5216,7 +5216,7 @@ sys/src/9/port/devpipe.c - 664 sys sys 1032640439 5825
 sys/src/9/port/devpnp.c - 664 sys sys 1019864265 13027
 sys/src/9/port/devproc.c - 664 sys sys 1036813000 23484
 sys/src/9/port/devrealtime.c - 664 sys sys 1037669299 15991
-sys/src/9/port/devroot.c - 664 sys sys 1039753332 3593
+sys/src/9/port/devroot.c - 664 sys sys 1042304978 3593
 sys/src/9/port/devsd.c - 664 sys sys 1026847547 28679
 sys/src/9/port/devsdp.c - 664 sys sys 1026847548 44841
 sys/src/9/port/devsegment.c - 664 sys sys 1017679394 9600
@@ -6990,18 +6990,18 @@ sys/src/cmd/file.c - 664 sys sys 1038186733 20196
 sys/src/cmd/fmt.c - 664 sys sys 1025298248 3897
 sys/src/cmd/fortune.c - 664 sys sys 1035832953 1674
 sys/src/cmd/fossil - 20000000775 sys sys 1042005512 0
-sys/src/cmd/fossil/9.h - 664 sys sys 1042005502 3379
-sys/src/cmd/fossil/9auth.c - 664 sys sys 1042005502 2389
+sys/src/cmd/fossil/9.h - 664 sys sys 1042311685 3412
+sys/src/cmd/fossil/9auth.c - 664 sys sys 1042311686 3023
 sys/src/cmd/fossil/9dir.c - 664 sys sys 1042005502 1995
 sys/src/cmd/fossil/9excl.c - 664 sys sys 1042005502 1887
 sys/src/cmd/fossil/9fid.c - 664 sys sys 1042005502 5236
-sys/src/cmd/fossil/9fsys.c - 664 sys sys 1042005503 26731
+sys/src/cmd/fossil/9fsys.c - 664 sys sys 1042311686 26805
 sys/src/cmd/fossil/9lstn.c - 664 sys sys 1042005503 2865
 sys/src/cmd/fossil/9p.c - 664 sys sys 1042005503 21328
 sys/src/cmd/fossil/9ping.c - 664 sys sys 1042005503 1563
 sys/src/cmd/fossil/9proc.c - 664 sys sys 1042005503 7358
 sys/src/cmd/fossil/9srv.c - 664 sys sys 1042005504 3215
-sys/src/cmd/fossil/9user.c - 664 sys sys 1042005504 17476
+sys/src/cmd/fossil/9user.c - 664 sys sys 1042311687 17473
 sys/src/cmd/fossil/Ccli.c - 664 sys sys 1042005504 1624
 sys/src/cmd/fossil/Ccmd.c - 664 sys sys 1042005504 7169
 sys/src/cmd/fossil/Ccons.c - 664 sys sys 1042005504 6524
@@ -7010,29 +7010,29 @@ sys/src/cmd/fossil/archive.c - 664 sys sys 1042005505 9083
 sys/src/cmd/fossil/build - 664 sys sys 1042005505 449
 sys/src/cmd/fossil/buildsh - 775 sys sys 1042005505 561
 sys/src/cmd/fossil/bwatch.c - 664 sys sys 1042005505 6754
-sys/src/cmd/fossil/cache.c - 664 sys sys 1042005506 40534
-sys/src/cmd/fossil/dat.h - 664 sys sys 1042005506 7775
+sys/src/cmd/fossil/cache.c - 664 sys sys 1042311688 41291
+sys/src/cmd/fossil/dat.h - 664 sys sys 1042311689 7790
 sys/src/cmd/fossil/deadlock - 775 sys sys 1042005506 413
 sys/src/cmd/fossil/disk.c - 664 sys sys 1042005506 5634
 sys/src/cmd/fossil/dump.c - 664 sys sys 1042005506 1340
 sys/src/cmd/fossil/error.c - 664 sys sys 1042005507 1367
 sys/src/cmd/fossil/error.h - 664 sys sys 1042005507 744
-sys/src/cmd/fossil/file.c - 664 sys sys 1042005507 27500
+sys/src/cmd/fossil/file.c - 664 sys sys 1042311690 27520
 sys/src/cmd/fossil/flchk.c - 664 sys sys 1042005507 13670
 sys/src/cmd/fossil/flfmt.c - 664 sys sys 1042005507 10314
 sys/src/cmd/fossil/flproto - 664 sys sys 1042005508 210
-sys/src/cmd/fossil/fns.h - 664 sys sys 1042005508 2950
+sys/src/cmd/fossil/fns.h - 664 sys sys 1042311690 2958
 sys/src/cmd/fossil/fossil-acid - 664 sys sys 1042005508 3965
 sys/src/cmd/fossil/fossil.c - 664 sys sys 1042005508 1256
-sys/src/cmd/fossil/fs.c - 664 sys sys 1042005508 16962
+sys/src/cmd/fossil/fs.c - 664 sys sys 1042311691 17030
 sys/src/cmd/fossil/fs.h - 664 sys sys 1042005509 1222
-sys/src/cmd/fossil/history - 664 sys sys 1042005509 482
+sys/src/cmd/fossil/history - 664 sys sys 1042311694 881
 sys/src/cmd/fossil/invariants - 664 sys sys 1042005509 4073
 sys/src/cmd/fossil/mkfile - 664 sys sys 1042005509 1589
 sys/src/cmd/fossil/nobwatch.c - 664 sys sys 1042005509 329
 sys/src/cmd/fossil/pack.c - 664 sys sys 1042005510 4683
 sys/src/cmd/fossil/periodic.c - 664 sys sys 1042005510 1091
-sys/src/cmd/fossil/source.c - 664 sys sys 1042005510 18124
+sys/src/cmd/fossil/source.c - 664 sys sys 1042311692 18406
 sys/src/cmd/fossil/srcload.c - 664 sys sys 1042005510 4178
 sys/src/cmd/fossil/stdinc.h - 664 sys sys 1042005510 155
 sys/src/cmd/fossil/trunc.c - 664 sys sys 1042005511 280

+ 16 - 0
dist/replica/plan9.log

@@ -17010,3 +17010,19 @@
 1042221764 4 c sys/lib/man/lookman/index - 664 sys sys 1042220693 1397584
 1042221764 5 c sys/man/4/INDEX - 664 sys sys 1042220690 967
 1042221764 6 c sys/man/8/INDEX - 664 sys sys 1042220690 2494
+1042304915 0 c rc/bin/9fs - 775 sys sys 1042304903 799
+1042305268 0 c rc/bin/9fs - 775 sys sys 1042305252 869
+1042305268 1 c sys/src/9/port/devroot.c - 664 sys sys 1042304978 3593
+1042311764 0 c sys/src/cmd/fossil/9.h - 664 sys sys 1042311685 3412
+1042311764 1 c sys/src/cmd/fossil/9auth.c - 664 sys sys 1042311686 3023
+1042311764 2 c sys/src/cmd/fossil/9fsys.c - 664 sys sys 1042311686 26805
+1042311764 3 c sys/src/cmd/fossil/9user.c - 664 sys sys 1042311687 17473
+1042311764 4 c sys/src/cmd/fossil/cache.c - 664 sys sys 1042311688 41291
+1042311764 5 c sys/src/cmd/fossil/dat.h - 664 sys sys 1042311689 7790
+1042311764 6 c sys/src/cmd/fossil/file.c - 664 sys sys 1042311690 27520
+1042311764 7 c sys/src/cmd/fossil/fns.h - 664 sys sys 1042311690 2958
+1042311764 8 c sys/src/cmd/fossil/fs.c - 664 sys sys 1042311691 17030
+1042311764 9 c sys/src/cmd/fossil/history - 664 sys sys 1042311694 881
+1042311764 10 c sys/src/cmd/fossil/source.c - 664 sys sys 1042311692 18406
+1042312269 0 c sys/man/8/fossilcons - 664 sys sys 1042312265 12639
+1042331465 0 c sys/man/1/ssh - 664 sys sys 1042330461 6968

+ 5 - 1
rc/bin/9fs

@@ -10,7 +10,11 @@ case kfs
 case netlib
 	9fs netlib2 && bind /n/netlib2/netlib /netlib
 case dump
-	mount /srv/boot /n/dump dump
+	mount /srv/boot /n/dump dump >[2]/dev/null ||
+	mount /srv/boot /n/dump main/archive ||
+	mount /srv/boot /n/dump dump	# again to print error
+case snap
+	mount /srv/boot /n/snap main/snapshot
 case other
 	mount -C /srv/boot /n/other other
 case juke

+ 2 - 2
sys/man/1/ssh

@@ -78,8 +78,8 @@ force input to be read in cooked mode:
 ``line at a time'' with local echo.
 .TP
 .B -f
-diable agent forwarding.
-By default,
+enable agent forwarding.
+With this flag,
 .I ssh
 uses SSH's agent forwarding protocol to allow
 programs running on the remote server to

+ 7 - 17
sys/man/8/fossilcons

@@ -83,11 +83,6 @@ con /srv/fscons
 .B fsys
 .I name
 .B venti
-.B -d
-|
-[
-.B -r
-]
 [
 .I host
 ]
@@ -336,8 +331,7 @@ If the in-memory table was read from a file
 (see the
 .I users
 command below),
-the new table is written to
-.IR /active/adm/users .
+the new table is written to that file.
 There is no distinction between users and groups:
 a user is a group with one member.
 The user table records a mapping between
@@ -493,16 +487,12 @@ If no
 command is issued before
 .IR open ,
 the default Venti server will be used.
-The
-.B -d
-flag closes the connection to the Venti server
-and can only be used when the file system is closed.
-The
-.B -r
-flag redials the Venti server and can only
-be used when the file system is open;
-.I host
-must be given again.
+If the file system is open, the command
+redials the Venti server.
+This can be used to reestablish broken connections.
+It is not a good idea to use the command to switch
+between Venti servers, since Fossil does not keep track
+of which blocks are stored on which servers.
 .PP
 .I Open
 opens the file system, reading the

+ 1 - 1
sys/src/9/port/devroot.c

@@ -11,7 +11,7 @@ enum
 	Qboot = 0x1000,
 
 	Nrootfiles = 32,
-	Nbootfiles = 16,
+	Nbootfiles = 32,
 };
 
 typedef struct Dirlist Dirlist;

+ 1 - 0
sys/src/cmd/fossil/9.h

@@ -143,6 +143,7 @@ extern int fsysNoAuthCheck(Fsys*);
 extern int fsysNoPermCheck(Fsys*);
 extern void fsysPut(Fsys*);
 extern int fsysWstatAllow(Fsys*);
+extern char* fsysGetName(Fsys*);
 
 /*
  * 9lstn.c

+ 19 - 11
sys/src/cmd/fossil/9auth.c

@@ -61,38 +61,44 @@ authCheck(Fcall* t, Fid* fid, Fs* fsys)
 	 * protocol to do. Use a separate lock to protect altering
 	 * the auth information inside afid.
 	 */
-	if((afid = fidGet(fid->con, t->afid, 0)) == nil){
+	if(t->afid == NOFID){
 		/*
 		 * If no authentication is asked for, allow
 		 * "none" provided the connection has already
 		 * been authenticatated.
-		 */
-		if(strcmp(fid->uname, unamenone) == 0 && fid->con->aok){
-			if((fid->uid = uidByUname(fid->uname)) == nil)
-				return 0;
-			return 1;
-		}
-
-		/*
+		 * 
 		 * The console is allowed to attach without
 		 * authentication.
 		 */
-		if(!fid->con->isconsole)
+		if(!fid->con->isconsole &&
+		(strcmp(fid->uname, unamenone) != 0 || !fid->con->aok)){
+			consPrint("attach %s as %s: connection not authenticated, not console\n", fsysGetName(fsys), fid->uname);
 			return 0;
-		if((fid->uid = uidByUname(fid->uname)) == nil)
+		}
+
+		if((fid->uid = uidByUname(fid->uname)) == nil){
+			consPrint("attach %s as %s: unknown uname\n", fsysGetName(fsys), fid->uname);
 			return 0;
+		}
 		return 1;
 	}
 
+	if((afid = fidGet(fid->con, t->afid, 0)) == nil){
+		consPrint("attach %s as %s: bad afid\n", fsysGetName(fsys), fid->uname);
+		return 0;
+	}
+
 	/*
 	 * Check valid afid;
 	 * check uname and aname match.
 	 */
 	if(!(afid->qid.type & QTAUTH)){
+		consPrint("attach %s as %s: afid not an auth file\n", fsysGetName(fsys), fid->uname);
 		fidPut(afid);
 		return 0;
 	}
 	if(strcmp(afid->uname, fid->uname) != 0 || afid->fsys != fsys){
+		consPrint("attach %s as %s: afid is for %s as %s\n", fsysGetName(fsys), fid->uname, fsysGetName(afid->fsys), afid->uname);
 		fidPut(afid);
 		return 0;
 	}
@@ -101,6 +107,7 @@ authCheck(Fcall* t, Fid* fid, Fs* fsys)
 	if(afid->cuname == nil){
 		if(authRead(afid, buf, 0) != 0 || afid->cuname == nil){
 			vtUnlock(afid->alock);
+			consPrint("attach %s as %s: auth protocol not finished\n", fsysGetName(fsys), fid->uname);
 			fidPut(afid);
 			return 0;
 		}
@@ -109,6 +116,7 @@ authCheck(Fcall* t, Fid* fid, Fs* fsys)
 
 	assert(fid->uid == nil);
 	if((fid->uid = uidByUname(afid->cuname)) == nil){
+		consPrint("attach %s as %s: unknown cuname %s\n", fsysGetName(fsys), fid->uname, afid->cuname);
 		fidPut(afid);
 		return 0;
 	}

+ 7 - 1
sys/src/cmd/fossil/9fsys.c

@@ -107,6 +107,12 @@ fsysGet(char* name)
 	return fsys;
 }
 
+char*
+fsysGetName(Fsys *fsys)
+{
+	return fsys->name;
+}
+
 Fsys*
 fsysIncRef(Fsys* fsys)
 {
@@ -1226,7 +1232,7 @@ fsysOpen(char* name, int argc, char* argv[])
 			host = nil;
 		fsys->session = vtDial(host, 1);
 		if(!vtConnect(fsys->session, nil))
-			fprint(2, "vtConnect: %R\n");
+			fprint(2, "warning: connecting to venti: %R\n");
 	}
 	if((fsys->fs = fsOpen(fsys->dev, fsys->session, ncache, rflag)) == nil){
 		vtUnlock(fsys->lock);

+ 1 - 1
sys/src/cmd/fossil/9user.c

@@ -712,7 +712,7 @@ cmdUname(int argc, char* argv[])
 	User *u, *up;
 	int d, dflag, i, r;
 	char *p, *uid, *uname;
-	char *createfmt = "fsys main create -d /active/usr/%s %s %s 0775";
+	char *createfmt = "fsys main create /active/usr/%s %s %s d775";
 	char *usage = "usage: uname uname [uid|:uid|%%newname|=leader|+member|-member]";
 
 	dflag = 0;

+ 108 - 72
sys/src/cmd/fossil/cache.c

@@ -27,6 +27,7 @@ struct Cache
 
 	Disk 	*disk;
 	int	size;			/* block size */
+	int	ndmap;		/* size of per-block dirty pointer map used in blockWrite */
 	VtSession *z;
 	u32int	now;			/* ticks for usage timestamps */
 	Block	**heads;		/* hash table for finding address */
@@ -55,6 +56,8 @@ struct Cache
 	int bw, br, be;
 	int nflush;
 
+	Periodic *sync;
+
 	/* unlink daemon */
 	BList *uhead;
 	BList *utail;
@@ -71,8 +74,10 @@ struct BList {
 	
 	/* for roll back */
 	int index;			/* -1 indicates not valid */
-	uchar score[VtScoreSize];
-
+	union {
+		uchar score[VtScoreSize];
+		uchar entry[VtEntrySize];
+	} old;
 	BList *next;
 };
 
@@ -101,7 +106,7 @@ static void flushThread(void *a);
 static void flushBody(Cache *c);
 static void unlinkBody(Cache *c);
 static int cacheFlushBlock(Cache *c);
-
+static void cacheSync(void*);
 /*
  * Mapping from local block type to Venti type
  */
@@ -141,7 +146,7 @@ cacheAlloc(Disk *disk, VtSession *z, ulong nblocks, int mode)
 
 	/* reasonable number of BList elements */
 	nbl = nblocks * 4;
-	
+
 	c->lk = vtLockAlloc();
 	c->ref = 1;
 	c->disk = disk;
@@ -150,12 +155,13 @@ cacheAlloc(Disk *disk, VtSession *z, ulong nblocks, int mode)
 bwatchSetBlockSize(c->size);
 	/* round c->size up to be a nice multiple */
 	c->size = (c->size + 127) & ~127;
+	c->ndmap = (c->size/20 + 7) / 8;
 	c->nblocks = nblocks;
 	c->hashSize = nblocks;
 	c->heads = vtMemAllocZ(c->hashSize*sizeof(Block*));
 	c->heap = vtMemAllocZ(nblocks*sizeof(Block*));
 	c->blocks = vtMemAllocZ(nblocks*sizeof(Block));
-	c->mem = vtMemAllocZ(nblocks * c->size + nbl * sizeof(BList));
+	c->mem = vtMemAllocZ(nblocks * (c->size + c->ndmap) + nbl * sizeof(BList));
 	c->baddr = vtMemAllocZ(nblocks * sizeof(BAddr));
 	c->mode = mode;
 	c->vers++;
@@ -171,13 +177,19 @@ bwatchSetBlockSize(c->size);
 		p += c->size;
 	}
 	c->nheap = nblocks;
-
-	for(i=0; i<nbl; i++){
+	for(i = 0; i < nbl; i++){
 		bl = (BList*)p;
 		bl->next = c->blfree;
 		c->blfree = bl;
 		p += sizeof(BList);
 	}
+	/* separate loop to keep blocks and blists reasonably aligned */
+	for(i = 0; i < nblocks; i++){
+		b = &c->blocks[i];
+		b->dmap = p;
+		p += c->ndmap;
+	}
+
 	c->blrend = vtRendezAlloc(c->lk);
 
 	c->maxdirty = nblocks*(DirtyPercentage*0.01);
@@ -187,6 +199,7 @@ bwatchSetBlockSize(c->size);
 	c->unlink = vtRendezAlloc(c->lk);
 	c->flush = vtRendezAlloc(c->lk);
 	c->flushwait = vtRendezAlloc(c->lk);
+	c->sync = periodicAlloc(cacheSync, c, 30*1000);
 
 	if(mode == OReadWrite){
 		c->ref += 2;
@@ -209,6 +222,7 @@ cacheFree(Cache *c)
 	/* kill off daemon threads */
 	vtLock(c->lk);
 	c->die = vtRendezAlloc(c->lk);
+	periodicKill(c->sync);
 	vtWakeup(c->flush);
 	vtWakeup(c->unlink);
 	while(c->ref > 1)
@@ -805,7 +819,7 @@ blockCopy(Block *b, u32int tag, u32int ehi, u32int elo)
 			blockPut(bb);
 			return nil;
 		}
-		blockDependency(bb, lb, -1, nil);
+		blockDependency(bb, lb, -1, nil, nil);
 		blockPut(lb);
 	}
 
@@ -1131,19 +1145,31 @@ blockFlush(Block *b)
 }
 
 /*
- * record that bb must be written out before b.
- * if index is given, we're about to overwrite the score
- * at that index in the block.  save the old value so we
+ * Record that bb must be written out before b.
+ * If index is given, we're about to overwrite the score/e
+ * at that index in the block.  Save the old value so we
  * can write a safer ``old'' version of the block if pressed.
  */
 void
-blockDependency(Block *b, Block *bb, int index, uchar *score)
+blockDependency(Block *b, Block *bb, int index, uchar *score, Entry *e)
 {
 	BList *p;
 
 	if(bb->iostate == BioClean)
 		return;
 
+	/*
+	 * Dependencies for blocks containing Entry structures
+	 * or scores must always be explained.  The problem with
+	 * only explaining some of them is this.  Suppose we have two 
+	 * dependencies for the same field, the first explained
+	 * and the second not.  We try to write the block when the first
+	 * dependency is not written but the second is.  We will roll back
+	 * the first change even though the second trumps it.
+	 */
+	if(index == -1 && bb->part == PartData)
+		assert(b->l.type == BtData);
+
 	assert(bb->iostate == BioDirty);
 
 	p = blistAlloc(bb);
@@ -1157,8 +1183,16 @@ if(0)fprint(2, "%d:%x:%d depends on %d:%x:%d\n", b->part, b->addr, b->l.type, bb
 	p->type = bb->l.type;
 	p->vers = bb->vers;
 	p->index = index;
-	if(p->index >= 0)
-		memmove(p->score, score, VtScoreSize);
+	if(p->index >= 0){
+		/*
+		 * This test would just be b->l.type==BtDir except
+		 * we need to exclude the super block.
+		 */
+		if(b->l.type == BtDir && b->part == PartData)
+			entryPack(e, p->old.entry, 0);
+		else
+			memmove(p->old.score, score, VtScoreSize);
+	}
 	p->next = b->prior;
 	b->prior = p;
 }
@@ -1186,9 +1220,9 @@ blockDirty(Block *b)
 	if(b->iostate == BioDirty)
 		return 1;
 	assert(b->iostate == BioClean);
-	b->iostate = BioDirty;
 
 	vtLock(c->lk);
+	b->iostate = BioDirty;
 	c->ndirty++;
 	if(c->ndirty > (c->maxdirty>>1))
 		vtWakeup(c->flush);
@@ -1222,29 +1256,6 @@ blockDirty(Block *b)
  * so bb can be reclaimed once b has been written to disk.  blockRemoveLink
  * checks !(b.state&Copied) as an optimization.  UnlinkBlock and blockCleanup
  * will check the conditions again for each block they consider.
- *
- * 12/28/2002 01:11 RSC BUG
- * When Entry structures are changed, most code does (for example):
- *
- *	oe = e;
- *	memset(&e, 0, sizeof e);
- *	entryPack(&e, b->data, index);
- *	blockDirty(b);
- *	blockDependency(b, block referenced by new e);
- *	addr = globalToLocal(oe.score);
- *	if(addr != NilBlock)
- *		blockRemoveLink(b, addr, entryType(&oe), oe.tag);
- *
- * This is wrong if there is already a different dependency for that entry
- * and the entries have different types (different heights of the hash tree).
- * Because the dependency only records the block address and not the
- * entry type, putting the old block address into the new entry results in
- * a bogus entry structure.  blockRollback catches this in an assert failure.
- * I think the solution is to record the entry type and tag in the BList structure,
- * but I want to mull it over a bit longer.
- *
- * In two and a half months running the system I have seen exactly one
- * crash due to this bug.
  */
 int
 blockRemoveLink(Block *b, u32int addr, int type, u32int tag)
@@ -1357,18 +1368,15 @@ blockSetLabel(Block *b, Label *l)
 	 */
 
 	if(oldl.state == BsFree)
-		blockDependency(b, lb, -1, nil);
+		blockDependency(b, lb, -1, nil, nil);
 	blockPut(lb);
 	return 1;
 }
 
 /*
- * We've decided to write out b.
- * Maybe b has some pointers to blocks
- * that haven't yet been written to disk.
- * If so, construct a slightly out-of-date
- * copy of b that is safe to write out.
- * (diskThread will make sure the block
+ * We've decided to write out b.  Maybe b has some pointers to blocks
+ * that haven't yet been written to disk.  If so, construct a slightly out-of-date
+ * copy of b that is safe to write out.  (diskThread will make sure the block
  * remains marked as dirty.)
  */
 uchar *
@@ -1376,7 +1384,6 @@ blockRollback(Block *b, uchar *buf)
 {
 	u32int addr;
 	BList *p;
-	Entry e;
 	Super super;
 
 	/* easy case */
@@ -1393,28 +1400,19 @@ blockRollback(Block *b, uchar *buf)
 		if(b->part == PartSuper){
 			assert(p->index == 0);
 			superUnpack(&super, buf);
-			addr = globalToLocal(p->score);
+			addr = globalToLocal(p->old.score);
 			if(addr == NilBlock){
-				fprint(2, "rolling back super block: bad replacement addr %V\n", p->score);
+				fprint(2, "rolling back super block: bad replacement addr %V\n", p->old.score);
 				abort();
 			}
 			super.active = addr;
 			superPack(&super, buf);
 			continue;
 		}
-		if(b->l.type != BtDir){
-			memmove(buf+p->index*VtScoreSize, p->score, VtScoreSize);
-			continue;
-		}
-		entryUnpack(&e, buf, p->index);
-		assert(entryType(&e) == p->type);
-		memmove(e.score, p->score, VtScoreSize);
-		if(globalToLocal(p->score) == NilBlock){
-			e.flags &= ~VtEntryLocal;	
-			e.tag = 0;
-			e.snap = 0;
-		}
-		entryPack(&e, buf, p->index);
+		if(b->l.type == BtDir)
+			memmove(buf+p->index*VtEntrySize, p->old.entry, VtEntrySize);
+		else
+			memmove(buf+p->index*VtScoreSize, p->old.score, VtScoreSize);
 	}
 	return buf;
 }
@@ -1432,6 +1430,7 @@ blockRollback(Block *b, uchar *buf)
 int
 blockWrite(Block *b)
 {
+	uchar *dmap;
 	Cache *c;
 	BList *p, **pp;
 	Block *bb;
@@ -1442,16 +1441,24 @@ blockWrite(Block *b)
 	if(b->iostate != BioDirty)
 		return 1;
 
+	dmap = b->dmap;
+	memset(dmap, 0, c->ndmap);
 	pp = &b->prior;
 	for(p=*pp; p; p=*pp){
+		if(p->index >= 0){
+			/* more recent dependency has succeeded; this one can go */
+			if(dmap[p->index/8] & (1<<(p->index%8)))
+				goto ignblock;
+		}
+
+		lockfail = 0;
 		bb = _cacheLocalLookup(c, p->part, p->addr, p->vers, 0, &lockfail);
 		if(bb == nil){
 			if(lockfail)
 				return 0;
-			/* block must have been written already */
-			*pp = p->next;
-			blistFree(c, p);
-			continue;
+			/* block not in cache => was written already */
+			dmap[p->index/8] |= 1<<(p->index%8);
+			goto ignblock;
 		}
 
 		/*
@@ -1474,6 +1481,12 @@ blockWrite(Block *b)
 		}
 		/* keep walking down the list */
 		pp = &p->next;
+		continue;
+
+ignblock:
+		*pp = p->next;
+		blistFree(c, p);
+		continue;
 	}
 
 	diskWrite(c->disk, b);
@@ -1525,6 +1538,7 @@ if(0) fprint(2, "iostate part=%d addr=%x %s->%s\n", b->part, b->addr, bioStr(b->
 		if(b->iostate == BioDirty || b->iostate == BioWriting){
 			vtLock(c->lk);
 			c->ndirty--;
+			b->iostate = iostate;	/* change here to keep in sync with ndirty */
 			b->vers = c->vers++;
 			if(b->uhead){
 				/* add unlink blocks to unlink queue */
@@ -1871,32 +1885,42 @@ baddrCmp(void *a0, void *a1)
 static void
 flushFill(Cache *c)
 {
-	int i;
+	int i, ndirty;
 	BAddr *p;
 	Block *b;
 
 	vtLock(c->lk);
-	if(c->ndirty == 0){
-		vtUnlock(c->lk);
-		return;
-	}
+//	if(c->ndirty == 0){
+//		vtUnlock(c->lk);
+//		return;
+//	}
 
 	p = c->baddr;
+	ndirty = 0;
 	for(i=0; i<c->nblocks; i++){
 		b = c->blocks + i;
-		if(b->part == PartError || b->iostate != BioDirty)
+		if(b->part == PartError)
+			continue;
+		if(b->iostate == BioDirty || b->iostate == BioWriting)
+			ndirty++;
+		if(b->iostate != BioDirty)
 			continue;
 		p->part = b->part;
 		p->addr = b->addr;
 		p->vers = b->vers;
 		p++;
 	}
+	if(ndirty != c->ndirty){
+		fprint(2, "ndirty mismatch expected %d found %d\n",
+			c->ndirty, ndirty);
+		c->ndirty = ndirty;
+	}
 	vtUnlock(c->lk);
 	
 	c->bw = p - c->baddr;
 	qsort(c->baddr, c->bw, sizeof(BAddr), baddrCmp);
 }
-	
+
 /*
  * This is not thread safe, i.e. it can't be called from multiple threads.
  * 
@@ -1998,3 +2022,15 @@ cacheFlush(Cache *c, int wait)
 		vtWakeup(c->flush);
 	vtUnlock(c->lk);
 }
+
+/*
+ * Kick the flushThread every 30 seconds.
+ */
+static void
+cacheSync(void *v)
+{
+	Cache *c;
+
+	c = v;
+	cacheFlush(c, 0);
+}

+ 2 - 0
sys/src/cmd/fossil/dat.h

@@ -252,6 +252,8 @@ struct Block {
 	uchar	score[VtScoreSize];	/* score */
 	Label l;
 
+	uchar	*dmap;
+
 	uchar 	*data;
 
 	/* the following is private; used by cache */

+ 4 - 4
sys/src/cmd/fossil/file.c

@@ -939,7 +939,7 @@ fprint(2, "fileMetaFlush moving entry from %ud -> %ud\n", f->boff, boff);
 	bb = sourceBlock(fp->msource, f->boff, OReadWrite);
 	mbDelete(&mb, i);
 	mbPack(&mb);	
-	blockDependency(b, bb, -1, nil);
+	blockDependency(b, bb, -1, nil, nil);
 	blockPut(bb);
 	blockDirty(b);
 	blockPut(b);
@@ -1393,17 +1393,17 @@ fileMetaAlloc(File *f, DirEntry *dir, u32int start)
 
 	/* meta block depends on super block for qid ... */
 	bb = cacheLocal(b->c, PartSuper, 0, OReadOnly);
-	blockDependency(b, bb, -1, nil);
+	blockDependency(b, bb, -1, nil, nil);
 	blockPut(bb);
 
 	/* ... and one or two dir entries */
 	epb = s->dsize/VtEntrySize;
 	bb = sourceBlock(s, dir->entry/epb, OReadOnly);
-	blockDependency(b, bb, -1, nil);
+	blockDependency(b, bb, -1, nil, nil);
 	blockPut(bb);
 	if(dir->mode & ModeDir){
 		bb = sourceBlock(s, dir->mentry/epb, OReadOnly);
-		blockDependency(b, bb, -1, nil);
+		blockDependency(b, bb, -1, nil, nil);
 		blockPut(bb);
 	}
 	

+ 1 - 1
sys/src/cmd/fossil/fns.h

@@ -26,7 +26,7 @@ u32int cacheLocalSize(Cache*, int);
 Block* blockCopy(Block*, u32int, u32int, u32int);
 void blockDupLock(Block*);
 void blockPut(Block*);
-void blockDependency(Block*, Block*, int, uchar*);
+void blockDependency(Block*, Block*, int, uchar*, Entry*);
 int blockDirty(Block*);
 int blockRemoveLink(Block*, u32int, int, u32int);
 int blockSetLabel(Block*, Label*);

+ 19 - 15
sys/src/cmd/fossil/fs.c

@@ -16,6 +16,7 @@ fsOpen(char *file, VtSession *z, long ncache, int mode)
 	Block *b, *bs;
 	Super super;
 	int m;
+	uchar oscore[VtScoreSize];
 
 	switch(mode){
 	default:
@@ -82,6 +83,7 @@ fprint(2, "fs->ehi %d fs->elo %d active=%d\n", fs->ehi, fs->elo, super.active);
 		b = blockCopy(b, RootTag, fs->ehi, fs->elo);
 		if(b == nil)
 			goto Err;
+		localToGlobal(super.active, oscore);
 		super.active = b->addr;
 		bs = cacheLocal(fs->cache, PartSuper, 0, OReadWrite);
 		if(bs == nil){
@@ -89,7 +91,7 @@ fprint(2, "fs->ehi %d fs->elo %d active=%d\n", fs->ehi, fs->elo, super.active);
 			goto Err;
 		}
 		superPack(&super, bs->data);
-		blockDependency(bs, b, -1, nil);
+		blockDependency(bs, b, 0, oscore, nil);
 		blockDirty(bs);
 		blockPut(bs);
 		blockPut(b);
@@ -208,7 +210,7 @@ superPut(Block* b, Super* super, int forceWrite)
 
 /*
  * Prepare the directory to store a snapshot.
- * Temporary snapshots go into /snapshot/#.
+ * Temporary snapshots go into /snapshot/yyyy/mmdd/hhmm[.#]
  * Archival snapshots go into /archive/yyyy/mmdd[.#].
  *
  * TODO This should be rewritten to eliminate most of the duplication.
@@ -312,17 +314,20 @@ fileOpenSnapshot(Fs *fs, int doarchive)
 			return nil;
 		dir = f;
 
-		/* hhmm */
+		/* hhmm[.#] */
 		snprint(buf, sizeof buf, "%02d%02d", now.hour, now.min);
-		f = fileWalk(dir, buf);
-		if(f != nil){
-			fileDecRef(f);
-			fileDecRef(dir);
-			fprint(2, "/snapshot/%d/%02d%02d/%s already exists!\n",
-				now.year+1900, now.mon+1, now.mday, buf);
-			return nil;
+		s = buf+strlen(buf);
+		for(n=0;; n++){
+			if(n)
+				seprint(s, buf+sizeof(buf), ".%d", n);
+			f = fileWalk(dir, buf);
+			if(f != nil){
+				fileDecRef(f);
+				continue;
+			}
+			f = fileCreate(dir, buf, ModeDir|ModeSnapshot|0555, "adm");
+			break;
 		}
-		f = fileCreate(dir, buf, ModeDir|ModeSnapshot|0555, "adm");
 		fileDecRef(dir);
 		return f;
 	}
@@ -357,7 +362,7 @@ fsEpochLow(Fs *fs, u32int low)
 static int
 bumpEpoch(Fs *fs, int doarchive)
 {
-	uchar score[VtScoreSize];
+	uchar oscore[VtScoreSize];
 	u32int oldaddr;
 	Block *b, *bs;
 	Entry e;
@@ -381,7 +386,6 @@ bumpEpoch(Fs *fs, int doarchive)
 	memmove(e.score, b->score, VtScoreSize);
 	e.tag = RootTag;
 	e.snap = b->l.epoch;
-	oldaddr = b->addr;
 
 	b = blockCopy(b, RootTag, fs->ehi+1, fs->elo);
 	if(b == nil){
@@ -413,8 +417,8 @@ bumpEpoch(Fs *fs, int doarchive)
 	 * Record that the new super.active can't get written out until
 	 * the new b gets written out.  Until then, use the old value.
 	 */
-	localToGlobal(oldaddr, score);
-	blockDependency(bs, b, 0, score);
+	localToGlobal(oldaddr, oscore);
+	blockDependency(bs, b, 0, oscore, nil);
 	blockPut(b);
 
 	/*

+ 10 - 0
sys/src/cmd/fossil/history

@@ -14,4 +14,14 @@ changes since initial alpha release
 	make fossil chatter a bit less to stderr.  errors
 	still go to stderr.
 
+11 jan 2003
+	add console prints on auth failure, for debugging
+	mark vtConnect message as warning
+	fix create command in user command
+	add background process to sync disk periodically
+	allow multiple snapshots per minute
+	fix bugs in soft updates
+	add double-check of ndirty to flushFill.  i've seen metadata
+		not get updated when you change it right before a reboot,
+		and i don't understand why.
 

+ 20 - 8
sys/src/cmd/fossil/source.c

@@ -498,6 +498,8 @@ blockWalk(Block *p, int index, int mode, Fs *fs, Entry *e)
 	Cache *c;
 	u32int addr;
 	int type;
+	uchar oscore[VtScoreSize];
+	Entry oe;
 
 	c = fs->cache;
 
@@ -517,6 +519,8 @@ blockWalk(Block *p, int index, int mode, Fs *fs, Entry *e)
 	if(!(b->l.state&BsClosed) && b->l.epoch == fs->ehi)
 		return b;
 
+	oe = *e;
+
 	/*
 	 * Copy on write.
 	 */
@@ -533,14 +537,16 @@ blockWalk(Block *p, int index, int mode, Fs *fs, Entry *e)
 
 	assert(b->l.epoch == fs->ehi);
 
+	blockDirty(b);
 	if(p->l.type == BtDir){
 		memmove(e->score, b->score, VtScoreSize);
 		entryPack(e, p->data, index);
-	}else{	
+		blockDependency(p, b, index, nil, &oe);
+	}else{
+		memmove(oscore, p->data+index*VtScoreSize, VtScoreSize);
 		memmove(p->data+index*VtScoreSize, b->score, VtScoreSize);
+		blockDependency(p, b, index, oscore, nil);
 	}
-	blockDirty(b);
-	blockDependency(p, b, index, b->score);
 	blockDirty(p);
 
 	if(addr != NilBlock)
@@ -559,6 +565,7 @@ sourceGrowDepth(Source *r, Block *p, Entry *e, int depth)
 	Block *b, *bb;
 	u32int tag;
 	int type;
+	Entry oe;
 
 	assert(sourceIsLocked(r));
 	assert(depth <= VtPointerDepth);
@@ -572,6 +579,8 @@ sourceGrowDepth(Source *r, Block *p, Entry *e, int depth)
 	if(tag == 0)
 		tag = tagGen();
 
+	oe = *e;
+
 	/*
 	 * Keep adding layers until we get to the right depth
 	 * or an error occurs.
@@ -586,14 +595,14 @@ sourceGrowDepth(Source *r, Block *p, Entry *e, int depth)
 		type++;
 		e->tag = tag;
 		e->flags |= VtEntryLocal;
-		blockDependency(bb, b, -1, nil);
+		blockDependency(bb, b, 0, vtZeroScore, nil);
 		blockPut(b);
 		blockDirty(bb);
 		b = bb;
 	}
 
 	entryPack(e, p->data, r->offset % r->epb);
-	blockDependency(p, b, -1, nil);
+	blockDependency(p, b, r->offset % r->epb, nil, &oe);
 	blockPut(b);
 	blockDirty(p);
 
@@ -606,6 +615,7 @@ sourceShrinkDepth(Source *r, Block *p, Entry *e, int depth)
 	Block *b, *nb, *ob, *rb;
 	u32int tag;
 	int type, d;
+	Entry oe;
 
 	assert(sourceIsLocked(r));
 	assert(depth <= VtPointerDepth);
@@ -623,6 +633,8 @@ sourceShrinkDepth(Source *r, Block *p, Entry *e, int depth)
 	 * Walk down to the new root block.
 	 * We may stop early, but something is better than nothing.
 	 */
+	oe = *e;
+
 	ob = nil;
 	b = rb;
 	for(d=e->depth; d > depth; d--, type++){
@@ -656,11 +668,12 @@ sourceShrinkDepth(Source *r, Block *p, Entry *e, int depth)
 	e->depth = d;
 	memmove(e->score, b->score, VtScoreSize);
 	entryPack(e, p->data, r->offset % r->epb);
+	blockDependency(p, b, r->offset % r->epb, nil, &oe);
 	blockDirty(p);
 
 	/* (ii) */
 	memmove(ob->data, vtZeroScore, VtScoreSize);
-	blockDependency(ob, p, -1, nil);
+	blockDependency(ob, p, 0, b->score, nil);
 	blockDirty(ob);
 
 	/* (iii) */
@@ -670,8 +683,7 @@ sourceShrinkDepth(Source *r, Block *p, Entry *e, int depth)
 	blockPut(rb);
 	if(ob!=nil && ob!=rb)
 		blockPut(ob);
-	if(b!=rb)
-		blockPut(b);
+	blockPut(b);
 
 	return d == depth;
 }