code: mafs

Download patch

ref: c8500961fbf7f65a5fd5e0e522c702b17a79ca27
parent: 0b55bc315e748a6f3b855a6611eab059729a748f
author: 9ferno <gophone2015@gmail.com>
date: Fri Oct 14 16:20:54 EDT 2022

streamline the use of Ref and Iobuf.io

--- a/all.h
+++ b/all.h
@@ -38,16 +38,32 @@
 /*
 	using Ref to avoid locking up the hash bucket when a process
 	is waiting for a lock on an Iobuf in that hash bucket.
+
+	The Ref ensures that an Iobuf is not stolen before another process
+	can get to wlock()'ing it after letting go of the lock on the hash bucket.
+	We cannot hold the lock on the hash bucket until we wlock() the iobuf
+	as that blocks other processes from using the hash bucket. This could
+	also result in a deadlock. For example, the directory entry is block 18,
+	which hashes to a hash index of 7. A writer() locked the directory entry
+	iobuf and wants to add a data block 84 to the directory entry. Block 84
+	hashes to the same hash index of 7. Another process wanting to access the
+	directory entry is waiting for a lock on that io buffer. While doing so,
+	it has locked the hash bucket. Now, this has caused a deadlock between
+	both these processes. The first process cannot proceed until it can
+	lock the hash bucket holding block 84 and is still holding the lock
+	on the directory entry in block 18. The second process cannot lock
+	block 18 and is holding the lock on the hash bucket.
+
 	for locking a buffer:
-		qlock(hash bucket); incref(buffer); qunlock(hash bucket); wlock(buffer)
+		qlock(hash bucket); incref(buffer); qunlock(hash bucket);
+			wlock(buffer); decref(buffer);
+
 	for stealing an unused buffer:
 		qlock(hash bucket);
-		find a buffer with ref == 0 and wlock'able.
-		incref(buffer);
+		find a buffer with ref == 0 and wlock()'able.
 		qunlock(hash bucket);
-		wlock(buffer);
+
 	for unlocking a buffer:
-		decref(buffer);
 		wunlock(buffer);
  */
 struct Iobuf
@@ -58,8 +74,10 @@
 	u16 len;		/* number of blocks of data xiobuf points to */
 	Iobuf	*fore;	/* for lru */
 	Iobuf	*back;	/* for lru */
-	u8	*xiobuf;	/* "real" buffer pointer */
-	Content *io;	/* buffer pointer that is only active while locked. */
+	union{
+		u8	*xiobuf;	/* "real" buffer pointer */
+		Content *io;	/* cast'able to contents */
+	};
 	int	flags;
 };
 
--- a/docs/mafs.ms
+++ b/docs/mafs.ms
@@ -640,8 +640,10 @@
 	u16	len;		/* number of blocks of data xiobuf points to */
 	Iobuf *fore;	/* for lru */
 	Iobuf *back;	/* for lru */
-	u8 *xiobuf;	/* "real" buffer pointer */
-	Content *io;	/* buffer pointer that is only active while locked. */
+	union{
+		u8	*xiobuf;	/* "real" buffer pointer */
+		Content *io;	/* cast'able to contents */
+	}
 	int	flags;
 };
 .fi
binary files a/docs/mafs.pdf b/docs/mafs.pdf differ
--- a/iobuf.c
+++ b/iobuf.c
@@ -35,7 +35,6 @@
 	p->blkno = 0;
 	p->len   = len;
 	p->xiobuf = emalloc9p(len*Rawblocksize);
-	p->io = nil;
 	return p;
 }
 
@@ -95,7 +94,7 @@
 			incref(p);
 			qunlock(hp);
 			if(chatty9p > 4)
-				dprint("	after qunlock(hp) hp 0x%p blkno %llud\n",
+				dprint("	in cache, after qunlock(hp) hp 0x%p blkno %llud\n",
 						hp, blkno);
 			if(p->len != len){
 				if(chatty9p > 4)
@@ -112,13 +111,11 @@
 				p->xiobuf = emalloc9p(len*Rawblocksize);
 				p->len = len;
 				devread(blkno, p->xiobuf, len);
-				chkwunlock(p);
-			}
-			if(flags & Bmod){
-				if(chatty9p > 4)
-					dprint("	in cache iobuf 0x%p has len %llud blkno %llud len %llud .."
-								" wlock() p->readers %d\n",
-							p, p->len, blkno, len, p->readers);
+				if((flags & Bmod) == 0){
+					chkwunlock(p);
+					rlock(p);
+				}
+			}else if(flags & Bmod){
 				wlock(p);
 				if(chatty9p > 4)
 					dprint("	after wlock() blkno %llud\n", blkno);
@@ -128,8 +125,8 @@
 							" rlock()\n", p, p->len, blkno, len);
 				rlock(p);
 			}
+			decref(p);
 			p->flags |= flags;
-			p->io = (Content*)p->xiobuf;
 			return p;
 		}
 		p = p->fore;
@@ -155,14 +152,12 @@
 					p->xiobuf = emalloc9p(len*Rawblocksize);
 					p->len = len;
 				}
-				incref(p);
-				chkwunlock(p); /* lock'ing done in found */
 				hp->link = p;
 				if(chatty9p > 4)
 					dprint("	stealing iobuf 0x%p of %llud blocks"
 							" for blkno %llud len %llud\n",
 							p, p->len, blkno, len);
-				goto found;
+				goto found;	/* p is wlock() */
 			}
 			s = p;
 		}while(p != hp->link);
@@ -173,7 +168,9 @@
 	if(chatty9p > 4)
 		dprint("	adding new Iobuf for blkno %llud\n", blkno);
 	p = newbuf(hp, len);
-	incref(p);
+	if(chatty9p > 4)
+		dprint(" .. wlock() blkno %llud\n", blkno);
+	wlock(p);
 
 found:
 	p->blkno = blkno;
@@ -181,18 +178,16 @@
 	if(chatty9p > 4)
 		dprint("	after qunlock(hp) hp 0x%p blkno %llud\n",
 				hp, blkno);
-	if(flags & Bmod){
+	devread(blkno, p->xiobuf, len);
+	if((flags & Bmod) == 0){
 		if(chatty9p > 4)
-		dprint(" .. wlock() blkno %llud\n", blkno);
-		wlock(p);
-	}else{
-		if(chatty9p > 4)
-		dprint(" .. rlock() blkno %llud\n", blkno);
+		dprint("new buffer: switching from wlock() to rlock() blkno %llud\n", blkno);
+		incref(p);
+		wunlock(p);
 		rlock(p);
+		decref(p);
 	}
-	devread(blkno, p->xiobuf, len);
 	p->flags = flags;
-	p->io = (Content*)p->xiobuf;
 	return p;
 }
 
@@ -230,9 +225,9 @@
 	if(chatty9p > 4)
 		dprint("putbuf p->blkno 0x%d t->c->type %d devtab[t->c->type]->dc %c\n"
 				"	p 0x%p p->flags 0x%ux %d\n"
-				"	p->xiobuf 0x%p p->iobuf 0x%p",
+				"	p->xiobuf 0x%p",
 				p->blkno, t->c->type, devtab[t->c->type]->dc,
-				p, p->flags, p->flags, p->xiobuf, p->io);
+				p, p->flags, p->flags, p->xiobuf);
 
  */
 void
@@ -312,8 +307,6 @@
 		}
 	}
 
-	p->io = nil;
-	decref(p);
 	if(p->flags & Bmod){
 		p->flags = 0;
 		chkwunlock(p);
@@ -419,11 +412,11 @@
 	}
 	dprint("showbuf p 0x%p blkno %llud len %d\n"
 			"	fore 0x%p back 0x%p\n"
-			"	xiobuf 0x%p io 0x%p flags 0x%x\n"
+			"	xiobuf 0x%p flags 0x%x\n"
 			"	caller %#p\n",
 			p, p->blkno, p->len,
 			p->fore, p->back,
-			p->xiobuf, p->io, p->flags,
+			p->xiobuf, p->flags,
 			getcallerpc(&p));
 	if(p->io != nil)
 		showblock((u8*)p->io);