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