code: mafs

Download patch

ref: ddd35edac6785918a0c4ca11548db2a7f211a732
parent: 80e6c118c65b013bde24f8b9c95881c0e3a73d3e
author: 9ferno <gophone2015@gmail.com>
date: Thu Dec 1 08:19:20 EST 2022

copy on write on updates

--- a/9p.c
+++ b/9p.c
@@ -1350,13 +1350,12 @@
 }
 
 /* only for updating existing data */
-/* TODO copy on write */
 s32
-update(Dentry *d, u64 /* dblkno */, char *wbuf, s32 wbufsize, u64 offset)
+update(Dentry *d, u64 dblkno, char *wbuf, s32 wbufsize, u64 offset)
 {
-	Iobuf *buf;
+	Iobuf *oldbuf, *newbuf;
 	s32 howmuch;
-	u64 blkno, to, nblocks;
+	u64 oldblkno, newblkno, to, nblocks, nblockssize;
 
 	if(d == nil || wbuf == nil || wbufsize == 0)
 		return 0;
@@ -1365,36 +1364,41 @@
 				"	offset %llud wbufsize %d d->size %llud",
 				offset, wbufsize, d->size);
 
-	/*	get the extent
-		overlay data
-	 */
-	blkno = rel2abs(d, offset/Maxdatablocksize);
-	if(offset/Maxdatablocksize < d->size/Maxdatablocksize)
+	/*	get the old data	 */
+	oldblkno = rel2abs(d, offset/Maxdatablocksize);
+	if(offset/Maxdatablocksize < d->size/Maxdatablocksize){
 		nblocks = Maxdatablockunits;
-	else
+		nblockssize = Maxdatablocksize;
+	}else{
 		nblocks = nlastdatablocks(d->size);
-	if(chatty9p > 1)
-	dprint("update d->name %s d->size %llud offset %llud"
-				" rel2abs(offset/Datablocksize %llud) = blkno %llud\n",
-				d->name, d->size, offset, offset/Maxdatablocksize, blkno);
-	buf = getbufchk(blkno, nblocks, Bwritable, Tdata, d->path);
-	if(buf == nil)
+		nblockssize = nblocks*Blocksize -Ddataidssize;
+	}
+	oldbuf = getbufchk(oldblkno, nblocks, Bwritable, Tdata, d->path);
+	if(oldbuf == nil)
 		return -1;
 
-	/* overlay the new contents */
+	/* update with the new contents */
 	to = offset%Maxdatablocksize;
-	howmuch = min((nblocks*Blocksize)-to, wbufsize);
-	if(chatty9p > 1){
-		dprint("updating buf->blkno %llud offset %llud size %llud\n",
-				buf->blkno, to, howmuch);
-		showbuf(buf);
+	howmuch = min(nblockssize-to, wbufsize);
+	memcpy(oldbuf->io->buf+to, wbuf, howmuch);
+
+	/* allocate new blocks to copy on write */
+	newbuf = allocblocks(nblocks,Tdata, d->path);
+	if(newbuf == nil)
+		return -1;
+	newblkno = newbuf->blkno;
+
+	/* put the old contents in these new blocks */
+	memcpy(newbuf->io->buf, oldbuf->io->buf, nblocks*Blocksize);
+	putbuf(newbuf, 1);
+
+	/* add the newly allocated blocks to the Dentry */
+	if(addrelative(d, dblkno, offset/Maxdatablocksize, newblkno) == 0){
+		panic("could not write Tdata block\n");
+		freeblocks(newblkno, nblocks, Tdata, d->path);
+		return -2;
 	}
-	memcpy(buf->io->buf+to, wbuf, howmuch);
-	if(chatty9p > 1){
-		dprint("update after\n");
-		showbuf(buf);
-	}
-	putbuf(buf, 1);
+	freeblockbuf(oldbuf);
 	return howmuch;
 }
 
@@ -1695,8 +1699,10 @@
 			if(n<0){
 				dprint("update has an issue %d\n", n);
 				goto writeend;
-			}else
+			}else{
 				written += n;
+				dowrite = 1;
+			}
 
 		}else if(offset+written >= d->size &&
 					offset+written < d->size+dbuf->appendsize){
--- a/TODO
+++ b/TODO
@@ -5,8 +5,6 @@
 		finds stuff quicker - really, by how much?
 test exclusive use file access
 test syncusers()
-update() is not copy on write
-	this seems to be reasonable behaviour(?)
 not updating Qid.version on writes or changes
 fswstat TODO
 streamline the error codes