ref: c6cc8aa4a902899d25e485cce95c1cb01fb5cb06
parent: 916fe767404498e0108f7b1d3fd0994ae19913f3
author: 9ferno <[email protected]>
date: Wed Sep 8 10:16:05 EDT 2021
write the data blocks and then the pointers to it to avoid dangling pointers and corruption on an improper shutdown
--- a/appl/cmd/disk/kfs64.b
+++ b/appl/cmd/disk/kfs64.b
@@ -47,7 +47,7 @@
# fundamental constants
#
# keeps Dentrysize to 252
-NAMELEN: con 104; # ext2, ext3, ext4, zfs - 255 bytes, kfs - 28, cwfs - 144
+NAMELEN: con 112; # ext2, ext3, ext4, zfs - 255 bytes, kfs - 28, cwfs - 144
NDBLOCK: con 8; # number of direct blocks in Dentry
NIBLOCK: con 5; # max depth of indirect blocks in Dentry - quintuple-indirect blocks
MAXFILESIZE: con big 16r7FFFFFFFFFFFFFFF; # Plan 9's limit (kfs's size is signed)
@@ -126,6 +126,8 @@
# a is the block number of the Direntry being retrieved
getblk: fn(d: self ref Dentry, a: big, tag: int): ref Iobuf;
getblk1: fn(d: self ref Dentry, a: big, tag: int): ref Iobuf;
+ # boffset is offset from the start of a block, so should never be more than the block size
+ putblk: fn (d: self ref Dentry, a: big, tag: int, boffset: int, b: array of byte): ref Iobuf;
rel2abs: fn(d: self ref Dentry, a: big, tag: int, putb: int): big;
trunc: fn(d: self ref Dentry, uid: int);
update: fn(d: self ref Dentry);
@@ -157,7 +159,11 @@
fsize: big; # size in blocks
tfree: big; # total number of free blocks
qidgen: big; # generator for unique ids
- hwblock: big; # highest touched block number, high water block number
+ # using hwblock to avoid reaming all blocks in the beginning
+ # or while building the list of free blocks in check()
+ # It is assumed that fsize-hwblock are all free blocks as kfs64 has not
+ # touched them yet
+ hwblock: big; # highest touched block number, high-water block number
fsok: int;
@@ -517,7 +523,8 @@
if(!ream && !readonly && !superok(0)){
sys->print("kfs needs check\n");
if(!nocheck)
- check(thedevice, Cquiet|Cfree);
+# check(thedevice, Cquiet|Cfree);
+ check(thedevice, Cfree);
}
(d, e) := Dentry.geta(thedevice, ROOTADDR, 0, QPROOT, Bread);
@@ -1374,13 +1381,17 @@
if(f.name == "." || f.name == "..")
return ferr(f, Edot, file, p);
+ # loop through all directory children to check for duplicates
addr1 := big 0; # block with first empty slot, if any
slot1 := 0;
for(addr := big 0; ; addr++){
if((p1 := d.getblk(addr, 0)) == nil){
+ # no more directory children
+ # if an empty slot was found, use it
+ # else create an empty block for the new Dentry
if(addr1 != big 0)
break;
- p1 = d.getblk(addr, Tdir);
+ p1 = d.putblk(addr, Tdir, 0, emptyblock);
}
if(p1 == nil)
return ferr(f, Efull, file, p);
@@ -1392,11 +1403,13 @@
d1 := Dentry.get(p1, slot);
if(!(d1.mode & DALLOC)){
if(addr1 == big 0){
+ # use the first empty slot for creating
addr1 = p1.addr;
slot1 = slot; # + addr*DIRPERBUF; # TODO
}
continue;
}
+ # check all
if(f.name == d1.name){
p1.put();
return ferr(f, Eexist, file, p);
@@ -1708,7 +1721,7 @@
if(n > count)
n = count;
qpath := d.qid.path;
- p1 := d.getblk1(addr, Tfile);
+ p1 := d.putblk(addr, Tfile, o, f.data[nwrite:nwrite+n]);
if(p1 == nil)
return ferr(f, Efull, file, nil);
if(p1.checktag(Tfile, qpath)){
@@ -1715,9 +1728,6 @@
p1.put();
return ferr(f, Ealloc, file, nil);
}
- p1.iobuf[o:] = f.data[nwrite:nwrite+n];
- p1.flags |= Bmod;
- p1.put();
count -= n;
nwrite += n;
offset += big n;
@@ -2279,11 +2289,11 @@
# RBUFSIZE - 16 Tagsize = BUFSIZE
# BUFSIZE / 4 = Dentrysize
# RBUFSIZE = 1024, BUFSIZE = 1008, Dentry size = 252
-# Dentry size 252 - 148 = NAMELEN 104
+# Dentry size 252 - 140 = NAMELEN 112
# this is the disk structure:
# u8 name[NAMELEN];
# u16 uid;
-# u16 gid; [2*2]
+# u16 gid; [2*2] 4
# u16 mode;
# #define DALLOC 0x8000
# #define DDIR 0x4000
@@ -2292,14 +2302,14 @@
# #define DREAD 0x4
# #define DWRITE 0x2
# #define DEXEC 0x1
-# [u16 muid] [2*2]
+# [u16 muid] [2*2] 8
# Qid.path; [8] 16
# Qid.version; [4] 20
# u64 size; [8] 28
# u64 dblock[NDBLOCK];[8*8] 92
-# u64 iblock[NIBLOCK];[8*6] 140
-# u32 atime; 144
-# u32 mtime; 148
+# u64 iblock[NIBLOCK];[8*5] 132
+# u32 atime; 136
+# u32 mtime; 140
# Dentry size = 252
Oname: con 0;
@@ -2428,7 +2438,7 @@
}
#
-# same as Dentry.buf but calls d.release
+# same as Dentry.getblk but calls d.release
# to reduce interference.
#
Dentry.getblk1(d: self ref Dentry, a: big, tag: int): ref Iobuf
@@ -2453,11 +2463,6 @@
dev := p.dev;
if(a < big NDBLOCK){
addr := get8(data, Odblock+int a*8);
- if(addr == big 0 && tag){
- addr = balloc(dev, tag, qpath);
- put8(data, Odblock+int a*8, addr);
- p.flags |= Bmod|Bimm;
- }
if(putb)
d.release();
return addr;
@@ -2465,72 +2470,47 @@
a -= big NDBLOCK;
if(a < INDPERBUF){
addr := get8(data, Oiblock);
- if(addr == big 0 && tag){
- addr = balloc(dev, Tind1, qpath);
- put8(data, Oiblock, addr);
- p.flags |= Bmod|Bimm;
- }
if(putb)
d.release();
- return indfetch(dev, qpath, addr, a, Tind1, tag);
+ return indfetch(dev, qpath, addr, a, Tind1);
}
a -= INDPERBUF;
if(a < INDPERBUF2){
addr := get8(data, Oiblock+1*8);
- if(addr == big 0 && tag){
- addr = balloc(dev, Tind2, qpath);
- put8(data, Oiblock+1*8, addr);
- p.flags |= Bmod|Bimm;
- }
if(putb)
d.release();
- addr = indfetch(dev, qpath, addr, a/INDPERBUF, Tind2, Tind1);
- return indfetch(dev, qpath, addr, a%INDPERBUF, Tind1, tag);
+ addr = indfetch(dev, qpath, addr, a/INDPERBUF, Tind2);
+ return indfetch(dev, qpath, addr, a%INDPERBUF, Tind1);
}
a -= INDPERBUF2;
if(a < INDPERBUF3){
addr := get8(data, Oiblock+2*8);
- if(addr == big 0 && tag){
- addr = balloc(dev, Tind3, qpath);
- put8(data, Oiblock+2*8, addr);
- p.flags |= Bmod|Bimm;
- }
if(putb)
d.release();
- addr = indfetch(dev, qpath, addr, a/INDPERBUF2, Tind3, Tind2);
- addr = indfetch(dev, qpath, addr, a/INDPERBUF, Tind2, Tind1);
- return indfetch(dev, qpath, addr, a%INDPERBUF, Tind1, tag);
+ addr = indfetch(dev, qpath, addr, a/INDPERBUF2, Tind3);
+ addr = indfetch(dev, qpath, addr, a/INDPERBUF, Tind2);
+ return indfetch(dev, qpath, addr, a%INDPERBUF, Tind1);
}
a -= INDPERBUF3;
if(a < INDPERBUF4){
addr := get8(data, Oiblock+3*8);
- if(addr == big 0 && tag){
- addr = balloc(dev, Tind4, qpath);
- put8(data, Oiblock+3*8, addr);
- p.flags |= Bmod|Bimm;
- }
if(putb)
d.release();
- addr = indfetch(dev, qpath, addr, a/INDPERBUF3, Tind4, Tind3);
- addr = indfetch(dev, qpath, addr, a/INDPERBUF2, Tind3, Tind2);
- addr = indfetch(dev, qpath, addr, a/INDPERBUF, Tind2, Tind1);
- return indfetch(dev, qpath, addr, a%INDPERBUF, Tind1, tag);
+ addr = indfetch(dev, qpath, addr, a/INDPERBUF3, Tind4);
+ addr = indfetch(dev, qpath, addr, a/INDPERBUF2, Tind3);
+ addr = indfetch(dev, qpath, addr, a/INDPERBUF, Tind2);
+ return indfetch(dev, qpath, addr, a%INDPERBUF, Tind1);
}
a -= INDPERBUF4;
if(a < INDPERBUF5){
addr := get8(data, Oiblock+4*8);
- if(addr == big 0 && tag){
- addr = balloc(dev, Tind5, qpath);
- put8(data, Oiblock+4*8, addr);
- p.flags |= Bmod|Bimm;
- }
if(putb)
d.release();
- addr = indfetch(dev, qpath, addr, a/INDPERBUF4, Tind5, Tind4);
- addr = indfetch(dev, qpath, addr, a/INDPERBUF3, Tind4, Tind3);
- addr = indfetch(dev, qpath, addr, a/INDPERBUF2, Tind3, Tind2);
- addr = indfetch(dev, qpath, addr, a/INDPERBUF, Tind2, Tind1);
- return indfetch(dev, qpath, addr, a%INDPERBUF, Tind1, tag);
+ addr = indfetch(dev, qpath, addr, a/INDPERBUF4, Tind5);
+ addr = indfetch(dev, qpath, addr, a/INDPERBUF3, Tind4);
+ addr = indfetch(dev, qpath, addr, a/INDPERBUF2, Tind3);
+ addr = indfetch(dev, qpath, addr, a/INDPERBUF, Tind2);
+ return indfetch(dev, qpath, addr, a%INDPERBUF, Tind1);
}
if(putb)
d.release();
@@ -2538,35 +2518,136 @@
return big 0;
}
-indfetch(dev: ref Device, path: big, addr: big, a: big, itag: int, tag: int): big
+indfetch(dev: ref Device, path: big, addr: big, a: big, itag: int): big
{
if(addr == big 0)
return big 0;
bp := Iobuf.get(dev, addr, Bread);
if(bp == nil){
- sys->print("ind fetch bp = nil\n");
+ cprint("ind fetch bp = nil\n");
return big 0;
}
if(bp.checktag(itag, path)){
- sys->print("ind fetch tag\n");
+ cprint("ind fetch tag\n");
bp.put();
return big 0;
}
addr = get8(bp.iobuf, int a*8);
- if(addr == big 0 && tag){
- addr = balloc(dev, tag, path);
- if(addr != big 0){
- put8(bp.iobuf, int a*8, addr);
- bp.flags |= Bmod;
- if(localfs || tag == Tdir)
- bp.flags |= Bimm;
- bp.settag(itag, path);
+ return addr;
+}
+
+#
+# save b to the a'th block of this Dentry at boffset
+# boffset is offset from the start of a block, so should never be more than the block size
+#
+Dentry.putblk(d: self ref Dentry, a: big, tag: int, boffset: int, b: array of byte): ref Iobuf
+{
+ if(a < big 0){
+ cprint("Dentry.rel2abs: neg\n");
+ return nil;
+ }
+ p := d.iob;
+ if(p == nil || d.buf == nil)
+ panic("nil iob");
+ data := d.buf;
+ qpath := d.qid.path;
+ dev := p.dev;
+ if(a < big NDBLOCK){
+ p1 := putdata(dev, qpath, d.iob, data[Odblock:], a, tag, boffset, b);
+ d.release();
+ return p1;
+ }
+ a -= big NDBLOCK;
+ if(a < INDPERBUF){
+ p1 := indstore(dev, qpath, d.iob, data[Oiblock:], a, Tind1, tag, boffset, b);
+ d.release();
+ return p1;
+ }
+ a -= INDPERBUF;
+ if(a < INDPERBUF2){
+ p1 := indstore(dev, qpath, d.iob, data[Oiblock+1*8:], a, Tind2, tag, boffset, b);
+ d.release();
+ return p1;
+ }
+ a -= INDPERBUF2;
+ if(a < INDPERBUF3){
+ p1 := indstore(dev, qpath, d.iob, data[Oiblock+2*8:], a, Tind3, tag, boffset, b);
+ d.release();
+ return p1;
+ }
+ a -= INDPERBUF3;
+ if(a < INDPERBUF4){
+ p1 := indstore(dev, qpath, d.iob, data[Oiblock+3*8:], a, Tind4, tag, boffset, b);
+ d.release();
+ return p1;
+ }
+ a -= INDPERBUF4;
+ if(a < INDPERBUF5){
+ p1 := indstore(dev, qpath, d.iob, data[Oiblock+4*8:], a, Tind5, tag, boffset, b);
+ d.release();
+ return p1;
+ }
+ d.release();
+ sys->print("Dentry.buf: trip indirect a %bd tag %d %s\n", a, tag, tagname(tag));
+ return nil;
+}
+
+# finally storing the data
+putdata(dev: ref Device, qpath: big, p: ref Iobuf, buf: array of byte, a: big, tag: int, boffset: int, b: array of byte): ref Iobuf
+{
+ addr := get8(buf, int a* 8);
+ if(addr == big 0 && tag){
+ addr = balloc(dev, tag, qpath);
+ put8(buf, int a* 8, addr);
+ p.flags |= Bmod|Bimm;
}
+ p1 := Iobuf.get(thedevice, addr, Bread);
+ p1.iobuf[boffset:] = b;
+ p1.flags |= Bmod;
+ p1.put();
+ return p1;
+}
+
+indoffset(tag: int): big
+{
+ case tag
+ {
+ Tind1 => return INDPERBUF;
+ Tind2 => return INDPERBUF2;
+ Tind3 => return INDPERBUF3;
+ Tind4 => return INDPERBUF4;
+ Tind5 => return INDPERBUF5;
+ * => cprint("unknown tag");
+ return big 0;
}
- bp.put();
- return addr;
+ return big 0;
}
+# walk the indirect pointer tree to the relevant data block and put data there
+# if there is no indirect pointer yet to this data block, create one
+indstore(dev: ref Device, qpath: big, p: ref Iobuf, buf: array of byte, a: big, itag: int, tag: int, boffset: int, b: array of byte): ref Iobuf
+{
+ if(a == big 0)
+ return nil;
+ indoff := indoffset(itag);
+ addrloc := int (a/indoff)*8;
+ addr := get8(buf, addrloc);
+ if(addr == big 0 && tag){
+ addr = balloc(dev, itag, qpath);
+ put8(buf, addrloc, addr);
+ p.flags |= Bmod|Bimm;
+ }
+ p1 := Iobuf.get(thedevice, addr, Bread);
+ p2 : ref Iobuf;
+ if(itag == Tind1)
+ p2 = putdata(dev, qpath, p1, p1.iobuf, a%indoff, tag, boffset, b);
+ else
+ p2 = indstore(dev, qpath, p1, p1.iobuf, a%indoff, itag-1, tag, boffset, b);
+ p1.flags |= Bmod;
+ p1.put();
+ return p2;
+}
+
# allocate a disk block
balloc(dev: ref Device, tag: int, qpath: big): big
{
@@ -3697,11 +3778,18 @@
cprint(sys->sprint("invalid size in superblock"));
return;
}
- c.amap = Map.new(fstart, fsize);
+ hwblock := sb.hwblock;
+ if(hwblock < fstart || hwblock > fsize){
+ cprint(sys->sprint("invalid hwblock in superblock"));
+ return;
+ }
+ c.amap = Map.new(fstart, hwblock);
nqid := sb.qidgen+big 100; # not as much of a botch
- if(nqid > big (1024*1024*8))
+ if(nqid > big (1024*1024*8)){
+ cprint(sys->sprint("nqid > big (1024*1024*8)"));
nqid = big (1024*1024*8);
+ }
if(nqid < big (64*1024))
nqid = big (64*1024);
c.qmap = Map.new(big 0, nqid);
@@ -3759,7 +3847,7 @@
cprint(sys->sprint("%8bd files", c.nfiles));
cprint(sys->sprint("%8bd blocks in the file system", fsize-fstart));
cprint(sys->sprint("%8bd used blocks", nused));
- cprint(sys->sprint("%8bd free blocks", sb.tfree));
+ cprint(sys->sprint("%8bd free blocks", sb.tfree+fsize-hwblock));
}
if(!(c.flags & Cfree)){
if(nfree != sb.tfree)
@@ -3767,7 +3855,7 @@
if(nfdup > big 0)
cprint(sys->sprint("%8bd blocks duplicated in the free list", nfdup));
if(fsize-fstart-nused-nfree > big 0)
- cprint(sys->sprint("%8bd missing blocks", fsize-fstart-nused-nfree));
+ cprint(sys->sprint("%8bd missing blocks", hwblock-fstart-nused-nfree));
}
if(ndup > big 0)
cprint(sys->sprint("%8bd address duplications", ndup));
@@ -4108,7 +4196,7 @@
Check.missing(c: self ref Check, sb: ref Superb)
{
n := 0;
- for(a:=sb.fsize-sb.fstart-big 1; a>=big 0; a--){
+ for(a:=sb.hwblock-sb.fstart-big 1; a>=big 0; a--){
i := a>>3;
b := byte (1 << int (a&big 7));
if((c.amap.bits[int i] & b) == byte 0){