ref: 334cd4d87fc9fd8e48183128e9d60de669ab29fe
parent: 16f09290e03ec4fba68b6587dc01c13299c2a6f6
author: 9ferno <gophone2015@gmail.com>
date: Sat Nov 19 09:18:43 EST 2022
copy on write for data blocks
--- a/9p.c
+++ b/9p.c
@@ -1267,13 +1267,13 @@
tosend = filesize - offset;
for(sent = 0; sent < tosend && offset+sent < d->size; ){
- buf = getdatablkat(d, (offset+sent)/Blocksize, Breadonly);
+ buf = getdatablkat(d, (offset+sent)/Datablocksize, Breadonly);
if(buf == nil){
putbuf(dbuf);
return -1;
}
- n = min(Blocksize-((offset+sent)%Blocksize), tosend-sent);
- memcpy(rbuf+sent, buf->io->buf+((offset+sent)%Blocksize), n);
+ n = min(Datablocksize-((offset+sent)%Datablocksize), tosend-sent);
+ memcpy(rbuf+sent, buf->io->buf+((offset+sent)%Datablocksize), n);
sent += n;
putbuf(buf);
}
@@ -1305,18 +1305,18 @@
overlay data
*/
- blkno = rel2abs(d, offset/Blocksize);
+ blkno = rel2abs(d, offset/Datablocksize);
if(chatty9p > 1)
dprint("update d->name %s d->size %llud offset %llud"
- " rel2abs(offset/Blocksize %llud) = blkno %llud\n",
- d->name, d->size, offset, offset/Blocksize, blkno);
+ " rel2abs(offset/Datablocksize %llud) = blkno %llud\n",
+ d->name, d->size, offset, offset/Datablocksize, blkno);
buf = getbufchk(blkno, Bwritable, Tdata, d->qid.path);
if(buf == nil)
return -1;
/* overlay the new contents */
- to = offset%Blocksize;
- howmuch = min(Blocksize-to, wbufsize);
+ to = offset%Datablocksize;
+ howmuch = min(Datablocksize-to, wbufsize);
if(chatty9p > 1){
dprint("updating buf->blkno %llud offset %llud size %llud\n",
buf->blkno, to, howmuch);
@@ -1343,15 +1343,15 @@
if(chatty9p > 1)
dprint("append wbufsize %d\n", wbufsize);
- if((lastblksize=d->size%Blocksize) == 0){
+ if((lastblksize=d->size%Datablocksize) == 0){
/* last block is full, use a new block */
if(chatty9p > 1)
dprint("append new data block rel2abs d->name %s reli d->size %llud"
- " d->size/Blocksize %llud\n",
- d->name, d->size, d->size/Blocksize);
+ " d->size/Datablocksize %llud\n",
+ d->name, d->size, d->size/Datablocksize);
/* write single block */
- howmuch = min(Blocksize, wbufsize);
+ howmuch = min(Datablocksize, wbufsize);
buf = allocblock(Tdata, d->qid.path);
if(buf == nil)
return -1;
@@ -1359,7 +1359,7 @@
memcpy(buf->io->buf, wbuf, howmuch);
putbuf(buf);
- if(addrelative(d, dblkno, d->size/Blocksize, blkno) == 0){
+ if(addrelative(d, dblkno, d->size/Datablocksize, blkno) == 0){
panic("could not write Tdata block\n");
freeblock(blkno, Tdata, d->qid.path);
return -2;
@@ -1368,21 +1368,21 @@
}else{
/* last block is partially full, fill it up */
- blkno = rel2abs(d, d->size/Blocksize);
+ blkno = rel2abs(d, d->size/Datablocksize);
if(blkno == 0)
panic("append update rel2abs blkno == 0"
" d->name %s reli d->size %llud"
- " d->size/Blocksize %llud s.blkno %llud\n",
- d->name, d->size, d->size/Blocksize, blkno);
+ " d->size/Datablocksize %llud s.blkno %llud\n",
+ d->name, d->size, d->size/Datablocksize, blkno);
if(chatty9p > 1)
dprint("append update rel2abs d->name %s reli d->size %llud"
- " d->size/Blocksize %llud blkno %llud\n",
- d->name, d->size, d->size/Blocksize, blkno);
+ " d->size/Datablocksize %llud blkno %llud\n",
+ d->name, d->size, d->size/Datablocksize, blkno);
buf = getbufchk(blkno, Bwritable, Tdata, d->qid.path);
if(buf == nil)
return -1;
- howmuch = min(Blocksize-lastblksize, wbufsize);
+ howmuch = min(Datablocksize-lastblksize, wbufsize);
if(chatty9p > 1)
dprint("fill lastblksize %llud howmuch %llud\n",
lastblksize, howmuch);
@@ -1401,7 +1401,7 @@
if(d == nil || size <= 0)
return 0;
- n = min(size, Blocksize - d->size%Blocksize);
+ n = min(size, Datablocksize - d->size%Datablocksize);
buf = emalloc9p(n);
n = append(d, dblkno, buf, n);
free(buf);
--- a/TODO
+++ b/TODO
@@ -1,5 +1,6 @@
test exclusive use file access
test syncusers()
+not updating Qid.version on writes or changes
fswstat TODO
streamline the error codes
mafswrite():
--- a/all.h
+++ b/all.h
@@ -23,6 +23,10 @@
through a linked list.
*/
Ncollisions = 3, /* soft limit after which we start reusing older Iobuf's */
+
+ /* for dirty */
+ Add = 1,
+ Remove
};
typedef struct Hiob Hiob;
@@ -71,15 +75,25 @@
RWLock; /* controls access to this Iobuf */
u64 blkno; /* block number on the disk, primary key */
u16 len; /* number of Units */
- Iobuf *fore; /* for lru */
- Iobuf *back; /* for lru */
+ Iobuf *fore; /* for lru */
+ Iobuf *back; /* for lru */
union{
u8 *xiobuf; /* "real" buffer pointer */
- Content *io; /* cast'able to contents */
- Dentry *d;
+ Data *io;
+ Metadata *m;
};
+ Metadata *use; /* use this unit for changes */
- /*
+ /* head of a linked list of children with changes yet to be written */
+ Iobuf *changes;
+
+ /* linked list of sibling changes not yet written */
+ u8 change; /* Add or Remove. Am I being added or removed? */
+ Iobuf *prev, *next;
+
+ u8 *append; /* appended data added not yet written to disk */
+
+ /* obsolete
This field is used by mafs to ensure that Iobufs are not reused
while there are pending writes.
@@ -105,8 +119,8 @@
u8 *allocmemunits(u16 len);
void freememunits(u8 *m, u16 len);
int checktag(Iobuf *p, u8 tag, u64 qpath);
-Iobuf* getbuf(u64 blkno, u16 len, u8 readonly, u8 freshalloc);
-Iobuf* getbufchk(u64 blkno, u8 readonly, int tag, u64 qpath);
+Iobuf* getbuf(u64 blkno, u64 len, u8 readonly, u8 freshalloc);
+Iobuf* getbufchk(u64 blkno, u64 len, u8 readonly, int tag, u64 qpath);
void iobufinit(void);
void putbuf(Iobuf *p);
void putbuffree(Iobuf *p);
@@ -120,9 +134,9 @@
u64 pendingwrites(void);
/* routines to manipulate the contents */
-Iobuf* allocblock(int tag, u64 qpath);
+Iobuf* allocblocks(u64 len, int tag, u64 qpath);
void freeblockbuf(Iobuf *buf);
-void freeblock(u64 blkno, u16 tag, u64 qpath);
+void freeblocks(u64 blkno, u64 len, u16 tag, u64 qpath);
void fsok(int ok);
void init(int doream, u64 size);
u64 newqpath();
@@ -173,10 +187,6 @@
int leadgroup(s16 uid, s16 gid);
s16 lookupid(char *name);
u64 min(u64 a, u64 b);
-int mkqidcmp(Qid*, Dentry*);
-void mkqid9p1(Qid9p1*, Qid*);
-void mkqid9p2(Qid*, Qid9p1*, int);
-int netserve(char*);
Aux *newaux(u64 addr, u16 uid);
u64 newqpath(void);
void newstart(void);
--- a/blk.c
+++ b/blk.c
@@ -17,8 +17,8 @@
fprint(fd, "pdblkno %llud\n", d->pdblkno);
fprint(fd, "pqpath %llud\n", d->pqpath);
fprint(fd, "mtime %llud\n", d->mtime);
- fprint(fd, "qid.path %llud\n", d->qid.path);
- fprint(fd, "qid.version %ud\n", d->qid.version);
+ fprint(fd, "path %llud\n", d->path);
+ fprint(fd, "version %ud\n", d->version);
fprint(fd, "mode %uo\n", d->mode);
}
void
@@ -34,9 +34,9 @@
void
showsuper(int fd, u8 *d)
{
- Super *s;
+ Dentry *s;
- s = (Super*)d;
+ s = (Dentry*)d;
fprint(fd, "qidgen %llud\n", s->qidgen);
fprint(fd, "fsok %llud\n", s->fsok);
}
@@ -48,14 +48,14 @@
showdentryhdr(fd, buf);
d = (Dentry*)buf;
- if(d->path == Qpconfig || d->path == Qpconfig0 || d->path == Qpconfig1)
+ if(d->path == Qpconfig || d->path == Qpconfig0)
showconfig(fd, buf);
- else if(d->path == Qpsuper || d->path == Qpsuper0 || d->path == Qpsuper1)
+ else if(d->path == Qpsuper || d->path == Qpsuper0)
showsuper(fd, buf);
else if(d->path == Qpmagic)
showmagic(fd, buf);
else if(d->size <= Ddatasize && (d->mode&DMDIR) == 0 &&
- d->qid.path != Qproot0 && d->qid.path != Qproot1){
+ d->path != Qproot0){
fprint(fd, "%s", d->buf);
}else{
fprint(fd, "direct blocks\n");
@@ -70,9 +70,9 @@
showind(int fd, u8 *buf)
{
int j;
- Content *t;
+ Indirect *t;
- t = (Content*)buf;
+ t = (Indirect*)buf;
for(j = 0; j<Nindperblock; j++)
fprint(fd, " %d %llud\n", j, t->bufa[j]);
}
@@ -79,9 +79,9 @@
void
showdata(int fd, u8 *buf)
{
- Content *c;
+ Data *c;
- c = (Content*)buf;
+ c = (Data*)buf;
fprint(fd, "%s", (s8*)c->buf);
}
@@ -88,31 +88,31 @@
void
showblock(int fd, u8 *buf)
{
- Content *t;
+ Data *t;
Dentry *d;
+ u8 tag;
+ Indirect *r;
+ tag = buf[0];
d = (Dentry*)buf;
- if(d->tag == Tblank){
- fprint(fd, "%s\n", tagnames[d->tag]);
+ t = (Data*)buf;
+ r = (Indirect*)buf;
+ if(tag == Tblank){
+ fprint(fd, "%s\n", tagnames[tag]);
return;
- }else if(d->tag == Tdentry){
- fprint(fd, "%s %llud\n", tagnames[d->tag], d->path);
+ }else if(tag == Tdentry){
+ fprint(fd, "%s %llud %d\n", tagnames[tag], d->path, d->ver);
showdentry(fd, buf);
return;
- }
- t = (Content*)buf;
- if(t->tag < Maxtind)
- fprint(fd, "%s %llud\n", tagnames[t->tag], t->path);
- if(t->tag == Tdata)
+ }else if(tag == Tdata){
+ fprint(fd, "%s %d %llud %llud\n", tagnames[tag], t->len, t->dblkno, t->path);
showdata(fd, buf);
- else if(t->tag >= Tind0 && t->tag < Maxtind)
+ return;
+ }else if(tag < Maxtind)
+ fprint(fd, "%s %d %llud %llud\n", tagnames[tag], r->ver, r->dblkno, r->path);
+
+ if(t->tag >= Tind0 && t->tag < Maxtind)
showind(fd, buf);
else if(t->tag != 0 || t->path != 0)
fprint(fd, "unknown tag type %d path %llud\n", t->tag, t->path);
-}
-
-u16
-blklen(u16 tag)
-{
- return (tag == Tdentry || tag == Tblank) ? Dentryunits : Rawblockunits;
}
--- a/config.c
+++ b/config.c
@@ -5,7 +5,7 @@
initconfig(u64 dblkno)
{
Iobuf *buf;
- char *tokens[128], cfg[Blocksize], *nl;
+ char *tokens[128], cfg[Datablocksize], *nl;
s32 n, i;
buf = getbufchk(dblkno, Breadonly, Tdentry, Qpconfig);
--- a/ctl.c
+++ b/ctl.c
@@ -100,14 +100,14 @@
"(GiB) free %ulld, used %ulld, total %ulld\n"
"(TiB) free %ulld, used %ulld, total %ulld\n",
free, used, config.nblocks,
- free * Unit / MiB,
- used * Unit / MiB,
+ free * Blocksize / MiB,
+ used * Blocksize / MiB,
config.size / MiB,
- free * Unit / GiB,
- used * Unit / GiB,
+ free * Blocksize / GiB,
+ used * Blocksize / GiB,
config.size / GiB,
- free * Unit / TiB,
- used * Unit / TiB,
+ free * Blocksize / TiB,
+ used * Blocksize / TiB,
config.size / TiB
);
else if(config.size > GiB)
@@ -115,11 +115,11 @@
"(MiB) free %ulld, used %ulld, total %ulld\n"
"(GiB) free %ulld, used %ulld, total %ulld\n",
free, used, config.nblocks,
- free * Unit / MiB,
- used * Unit / MiB,
+ free * Blocksize / MiB,
+ used * Blocksize / MiB,
config.size / MiB,
- free * Unit / GiB,
- used * Unit / GiB,
+ free * Blocksize / GiB,
+ used * Blocksize / GiB,
config.size / GiB
);
else if(config.size > MiB)
@@ -126,8 +126,8 @@
n += snprint(buf+n, 1024-n, "(blocks) free %ulld, used %ulld, total %ulld\n"
"(MiB) free %ulld, used %ulld, total %ulld\n",
free, used, config.nblocks,
- free * Unit / MiB,
- used * Unit / MiB,
+ free * Blocksize / MiB,
+ used * Blocksize / MiB,
config.size / MiB
);
else
@@ -134,8 +134,8 @@
n += snprint(buf+n, 1024-n, "(blocks) free %ulld, used %ulld, total %ulld\n"
"(KiB) free %ulld, used %ulld, total %ulld\n",
free, used, config.nblocks,
- free * Unit / KiB,
- used * Unit / KiB,
+ free * Blocksize / KiB,
+ used * Blocksize / KiB,
config.size / KiB
);
if(req->ifcall.offset < n){
--- a/dat.c
+++ b/dat.c
@@ -10,6 +10,8 @@
[Tind0] "Tind0",
[Tind1] "Tind1",
[Tind2] "Tind2",
+ [Tind3] "Tind3",
+ [Tind4] "Tind4",
/* add more Tind tags here ... */
};
--- a/dat.h
+++ b/dat.h
@@ -9,10 +9,12 @@
typedef unsigned long long u64;
typedef struct Config Config;
-typedef struct Content Content;
+typedef struct Data Data;
+typedef struct Metadata Metadata;
typedef struct Dentryhdr Dentryhdr;
typedef struct Dentry Dentry;
-typedef struct Qid9p1 Qid9p1;
+typedef struct Datahdr Datahdr;
+typedef struct Indirect Indirect;
typedef struct Super Super;
typedef struct Tlock Tlock;
typedef struct User User;
@@ -33,7 +35,7 @@
Nsec = 1000ULL*1000*1000,
Usec = 1000ULL*1000,
Msec = 1000ULL,
- Nbkp = 2,
+ Nbkp = 1,
};
/*
@@ -48,38 +50,34 @@
* Nindperblock number of block pointers in a block
*/
enum {
- Unit = 512ULL, /* minimum data unit size */
- Dentryunits = 1, /* number of units per Tdentry */
- Rawblockunits= 16, /* number of units for others */
+ Blocksize = 512ULL, /* minimum data unit size */
- Dentrysize = Dentryunits*Unit, /* real block size of a Tdentry */
- /* real block size of others. a multiple of Unit to keep the extents code uniform */
- Rawblocksize= Rawblockunits*Unit,
- Blocksize = Rawblocksize - sizeof(u8 /* tag */) -sizeof(u64 /* path */),
- Nindperblock= (Blocksize-7)/sizeof(u64),/* number of pointers per block. -7 for pad */
+ Metadataunits = 2,
+ Metadatablocksize = Metadataunits*Blocksize, /* Keep the original and a copy together */
- Namelen = 129, /* maximum length of a file name, calculated manually */
+ Maxdatablockunits = 2048,
+ Nindperblock= (Blocksize-3*sizeof(u64))/sizeof(u64),/* number of pointers per block */
+
+ Namelen = 127, /* maximum length of a file name, calculated manually */
Ndblock = 32, /* number of direct blocks in a Dentry */
- Niblock = 3, /* maximum depth of indirect blocks, can increase it to 6 without issues */
- MAXRPC = Blocksize,/* Tdata block size in bytes */
- Iounit = MAXRPC, /* in bytes, TODO adjust for the 9p header size? */
+ Niblock = 5, /* maximum depth of indirect blocks, can increase it to 8 without issues */
/* global block numbers. The bkp contents locations are calculated by ream() */
Bdmagic = 0, /* block number of first block. Bmagic conflicts with bio.h */
- Bdconfig= 1, /* block number of /adm/config dentry and contents */
- Bdsuper = 2, /* block number of /adm/super dentry and contents */
- Bdadm = 3, /* block number of /adm directory */
- Bdusers = 4, /* block number of /adm/users/ dentry */
+ Bdconfig= 2, /* block number of /adm/config dentry and contents */
+ Bdsuper = 4, /* block number of /adm/super dentry and contents */
+ Bdadm = 6, /* block number of /adm directory */
+ Bdusers = 8, /* block number of /adm/users/ dentry */
/* contents of blocks below change on use */
- Bdbkp = 5, /* block number of /adm/bkp directory */
- Bdusersinuse = 6, /* block number of /adm/users/inuse dentry and contents */
- Bdfrees = 7, /* block number of /adm/frees dentry, text file of free extents */
+ Bdbkp = 10, /* block number of /adm/bkp directory */
+ Bdusersinuse = 12, /* block number of /adm/users/inuse dentry and contents */
+ Bdfrees = 14, /* block number of /adm/frees dentry, text file of free extents */
/* no user writes allowed on blocks below Bdctl */
- Bdctl = 8, /* block number of /adm/ctl dentry, empty contents, virtual file */
- Bdusersstaging = 9,/* block number of /adm/users/staging dentry */
- Bdroot = 10, /* block number of root directory */
+ Bdctl = 16, /* block number of /adm/ctl dentry, empty contents, virtual file */
+ Bdusersstaging = 18,/* block number of /adm/users/staging dentry */
+ Bdroot = 20, /* block number of root directory */
Nbused, /* blocks used up by default */
Nminblocks = Nbused+(Nbkp*3), /* number of blocks used by the above and the backup blocks */
@@ -100,13 +98,10 @@
Qproot = Bdroot, /* /, so fscreate() can disallow any create's below */
/* system qpaths */
- Qpmagic, /* magic block Tag.qpath */
- Qpconfig0, /* /adm/bkp/config.0 block Tag.qpath */
- Qpsuper0, /* /adm/bkp/super.0 block Tag.qpath */
- Qproot0 , /* /adm/bkp/root.0 block Tag.qpath */
- Qpconfig1, /* /adm/bkp/config.1 block Tag.qpath */
- Qpsuper1, /* /adm/bkp/super.1 block Tag.qpath */
- Qproot1 , /* /adm/bkp/root.1 block Tag.qpath */
+ Qpmagic = 1, /* magic block Tag.qpath */
+ Qpconfig0 = 3, /* /adm/bkp/config.0 block Tag.qpath */
+ Qpsuper0 = 5, /* /adm/bkp/super.0 block Tag.qpath */
+ Qproot0 = 21, /* /adm/bkp/root.0 block Tag.qpath */
Nqidgen = 64,
@@ -118,38 +113,49 @@
#pragma pack on
/* DONT TOUCH, this is the disk structure */
-struct Qid9p1
+/* no access time */
+struct Dentryhdr
{
- u64 path; /* unique identifier */
- u32 version;
+ u8 tag;
+ u8 ver; /* a counter to do copy on write */
+ s16 uid;
+ s16 gid;
+ s16 muid; /* 8 */
+ u64 size; /* 0 for directories. For files, size in bytes of the content - 16 */
+ u64 pdblkno; /* block number of the parent directory entry. Will be 0 for root. - 24 */
+ u64 pqpath; /* parent qid.path - 32 */
+ u64 mtime; /* modified time in nano seconds from epoch - 40 */
+ u64 path; /* unique identifier Qid.path 48 */
+ u32 version; /* Qid.version 52 */
+ u32 mode; /* same bits as defined in /sys/include/libc.h:/Dir\.mode/ - 56 */
+ u8 namelen; /* store name as a counted string 57 */
+ s8 name[Namelen]; /* Namelen = 127 - 184*/
};
-
-/* DONT TOUCH, this is the disk structure */
-/*
- * no access time
- */
-struct Dentryhdr
+struct Datahdr
{
u8 tag;
- s8 name[Namelen]; /* 130, Namelen = 129 to align to a u64 after the ids*/
- s16 uid; /* 132 */
- s16 gid; /* 134 */
- s16 muid; /* 136 */
- u64 size; /* 0 for directories. For files, size in bytes of the content - 8 */
- u64 pdblkno; /* block number of the parent directory entry. Will be 0 for root. - 16 */
- u64 pqpath; /* parent qid.path - 24 */
- u64 mtime; /* modified time in nano seconds from epoch - 32 */
- Qid9p1 qid; /* 44 bytes */
- u32 mode; /* same bits as defined in /sys/include/libc.h:/Dir\.mode/ - 48 */
+ u8 unused; /* for alignment and future use */
+ u16 len;
+ u64 dblkno; /* block number of the directory entry */
+ u64 path; /* same as qid.path */
};
#pragma pack off
enum {
/* max possible size of data that can be stuffed into a Dentry */
- Ddatasize = Dentrysize -sizeof(u64 /* path */) -sizeof(Dentryhdr),
+ Ddatasize = Blocksize -sizeof(u64 /* path */) -sizeof(Dentryhdr),
+ Maxdatablocksize = Maxdatablockunits*Blocksize -sizeof(Datahdr) -sizeof(u64 /* trailing path */),
+ Iounit = Maxdatablocksize, /* in bytes, TODO adjust for the 9p header size? */
};
#pragma pack on
+/* DONT TOUCH, these are all disk structures */
+struct Super
+{
+ u64 qidgen; /* generator for unique ids. starts from 1024. */
+ /* TODO make fsok a time stamp in nano seconds */
+ u64 fsok; /* fsck status, using 64 bits to keep it all aligned */
+};
struct Dentry
{
Dentryhdr;
@@ -162,35 +168,40 @@
Tdentry block numbers for directories */
u64 iblocks[Niblock]; /* indirect blocks */
};
+ Super;
+
/* when size <= Dentrysize-184-sizeof(Tag), store the data here itself */
s8 buf[Ddatasize];
};
u64 path;
};
-/* DONT TOUCH, this is the disk structure */
-struct Super
+struct Indirect
{
- Dentryhdr;
- u64 qidgen; /* generator for unique ids. starts from 1024. */
- /* make fsok a time stamp with the highest bit being the fsok flag */
- u64 fsok; /* fsck status, using 64 bits to keep it all aligned */
- u64 path;
+ u8 tag;
+ u8 ver;
+ u8 pad[6]; /* unused, to align to a multiple of 8 */
+ u64 dblkno; /* block number of the directory entry */
+ u64 bufa[Nindperblock];
+ u64 path; /* same as qid.path */
};
-/* DONT TOUCH, this is the disk structure */
-struct Content /* used to unmarshall the disk contents */
+struct Metadataunit
{
- u8 tag;
union
{
- u8 buf[Blocksize];
- struct
- {
- u8 pad[7]; /* unused, to align to a multiple of 8 */
- u64 bufa[Nindperblock];
- };
+ Indirect;
+ Dentry;
};
- u64 path; /* same as qid.path */
};
+struct Metadata
+{
+ struct Metadataunit m[2];
+};
+struct Data /* used to unmarshall the disk contents */
+{
+ Datahdr;
+ u8 buf[1]; /* upto Maxdatablocksize, followed by u64 qid.path */
+ /* u64 path; same as qid.path at the end of the data content */
+};
#pragma pack off
/*
@@ -227,12 +238,12 @@
User *prev, *next; /* linked list sorted by id */
};
+/* storing this in ascii to the Bdconfig block */
struct Bkp
{
u64 srcbno; /* source of the backup */
u64 dest[Nbkp]; /* destinations written to */
};
-
struct Config
{
u64 size; /* size from dirfstat */
@@ -327,8 +338,10 @@
and Tdentry block numbers for directories.*/
Tind1, /* contains a list of Tind0 block numbers */
Tind2, /* contains a list of Tind1 block numbers */
+ Tind3, /* contains a list of Tind1 block numbers */
+ Tind4, /* contains a list of Tind1 block numbers */
/* gap for more indirect block depth in future.
- It can be put upto Tind5 without needing any code changes */
+ It can be put upto Tind7 without needing any code changes */
Maxtind, /* should be Tind0+Niblock */
MAXTAG,
--- a/dev.c
+++ b/dev.c
@@ -23,9 +23,8 @@
{
s32 n;
- if((n= pread(devfd, b, len*Unit, blkno*Unit)) != len*Unit)
+ if((n= pread(devfd, b, len*Blocksize, blkno*Blocksize)) != len*Blocksize)
panic("devread failed: %r\n");
- /* print("devread i %d n %d\n", i, n); */
return n;
}
@@ -34,7 +33,7 @@
{
s32 wn;
- if((wn = pwrite(devfd, b, len*Unit, blkno*Unit)) != len*Unit)
+ if((wn = pwrite(devfd, b, len*Blocksize, blkno*Blocksize)) != len*Blocksize)
panic("devwrite failed: %r\n");
return wn;
}
--- a/free.c
+++ b/free.c
@@ -91,7 +91,7 @@
buf = emalloc(Rawblocksize);
devread(blkno, buf, Rawblockunits);
- loadextents(&frees, buf, Blocksize);
+ loadextents(&frees, buf, Datablocksize);
free(buf);
}
--- a/iobuf.c
+++ b/iobuf.c
@@ -339,7 +339,8 @@
memcpy(buf, p->d->buf, Ddatasize);
}
if(synchronouswrites){
- devwrite(p->blkno, p->xiobuf, p->len);
+ if(p->blkno < 10)
+ devwrite(p->blkno, p->xiobuf, p->len);
if(chkwunlock(p) == 0){
showbuf(p);
panic("putbuf: chkwunlock(p) == 0 called by %#p\n", getcallerpc(&p));
--- a/mafs.c
+++ b/mafs.c
@@ -84,13 +84,13 @@
and 1/3rd for the buffer cache
*/
if(nmemunits == 0)
- nmemunits = size/Unit > 8*MiB ? 8*MiB : size/Unit;
- if(nmemunits < KiB)
- nmemunits = KiB;
- if(npendingwrites == 0)
- npendingwrites = nmemunits/(2*Rawblockunits);
+ nmemunits = size/Blocksize > 8*MiB ? 8*MiB : size/Blocksize;
+ if(nmemunits < 16*MiB)
+ nmemunits = 16*MiB;
if(nbuckets == 0)
- nbuckets = nmemunits/(4*Ncollisions*Rawblockunits);
+ nbuckets = nmemunits/(4*Ncollisions*Maxdatablockunits);
+ if(nbuckets == 0)
+ nbuckets = 7;
if(chatty9p){
dprint("\nPlan 9 %d-bit file server with %d-deep indirect blocks\n",
--- a/mkfile
+++ b/mkfile
@@ -1,6 +1,6 @@
</$objtype/mkfile
-TARG=mfs mafs used reconcile block find free unused updatefrees
+TARG=mafs used reconcile block find free unused updatefrees # mfs
OFILES=\
9p.$O\
--- a/sub.c
+++ b/sub.c
@@ -7,15 +7,15 @@
{
u64 qpath;
Iobuf *sb;
- Super *s;
+ Dentry *s;
s32 on, nn;
s8 buf[Ddatasize-16];
- sb = getbufchk(Bdsuper, Bwritable, Tdentry, Qpsuper);
+ sb = getbufchk(Bdsuper, Metadataunits, Bwritable, Tdentry, Qpsuper);
if(sb == nil){
panic("newqpath: sb == nil\n");
}
- s = (Super*)sb->d;
+ s = (Dentry*)sb->use;
on = snprint(buf, Ddatasize-16, "%llud", s->qidgen);
qpath = s->qidgen++;
nn = snprint(buf, Ddatasize-16, "%llud", s->qidgen);
@@ -64,9 +64,9 @@
int
isbkp(u64 bno)
{
- if(bno == config.config.dest[0] || bno == config.config.dest[1] ||
- bno == config.super.dest[0] || bno == config.super.dest[1] ||
- bno == config.root.dest[0] || bno == config.root.dest[1])
+ if(bno == config.config.dest[0] ||
+ bno == config.super.dest[0] ||
+ bno == config.root.dest[0])
return 1;
else
return 0;
@@ -74,13 +74,11 @@
/* making the assumption that all allocations are not readonly */
Iobuf *
-allocblock(int tag, u64 qpath)
+allocblocks(u64 len, int tag, u64 qpath)
{
u64 blkno;
Iobuf *buf;
- u16 len;
- len = blklen(tag);
blkno = balloc(&frees, len);
if(blkno == 0)
return nil; /* the caller should trigger an Efull message */
@@ -87,10 +85,12 @@
if(chatty9p > 1)
dprint("alloc %llud\n", blkno);
+
/* cannot do getbufchk() unless we ream the whole disk at start */
buf = getbuf(blkno, len, Bwritable, Bfreshalloc);
+
/* clear the buf to avoid leaks on reuse */
- memset(buf->xiobuf, 0, len*Unit);
+ memset(buf->xiobuf, 0, len*Blocksize);
settag(buf, tag, qpath);
return buf;
}
@@ -103,7 +103,7 @@
panic("freeblockbuf without Bwritable");
/* clear the buf to avoid leaks on reuse */
- memset(buf->xiobuf, 0, buf->len*Unit);
+ memset(buf->xiobuf, 0, buf->len*Blocksize);
bfree(&frees, buf->blkno, buf->len);
putbuffree(buf);
}
@@ -110,7 +110,7 @@
/* add the block to the extents used to manage free blocks */
void
-freeblock(u64 blkno, u16 tag, u64 qpath)
+freeblocks(u64 blkno, u64 len, u16 tag, u64 qpath)
{
Iobuf *buf;
@@ -120,7 +120,7 @@
return;
}
- buf = getbufchk(blkno, Bwritable, tag, qpath);
+ buf = getbufchk(blkno, len, Bwritable, tag, qpath);
if(buf == nil)
dprint("%s",errstring[Ephase]);
freeblockbuf(buf);
@@ -149,13 +149,13 @@
fsok(int ok)
{
Iobuf *sb;
- Super *s;
+ Dentry *s;
- sb = getbufchk(Bdsuper, Bwritable, Tdentry, Qpsuper);
+ sb = getbufchk(Bdsuper, Metadataunits, Bwritable, Tdentry, Qpsuper);
if(sb == nil){
panic("fsok: sb == nil\n");
}
- s = (Super*)sb->d;
+ s = (Dentry*)sb->use;
s->fsok = ok;
if(chatty9p > 1){
dprint("fsok ok %d\n", ok);
@@ -177,10 +177,12 @@
Iobuf *b;
Dentry *d;
- b = getbuf(dblkno, Dentryunits, Bwritable, Bfreshalloc);
- memset(b->io, 0, Dentrysize);
+ b = getbuf(dblkno, Metadataunits, Bwritable, Bfreshalloc);
+ memset(b->m, 0, Metadatablocksize);
settag(b, Tdentry, qpath);
- d = b->d;
+ d = (Dentry*)b->use;
+ d->ver++;
+ d->namelen = strlen(name);
strcpy(d->name, name);
d->uid = d->muid = d->gid = -1;
d->mode =
@@ -187,8 +189,8 @@
((DMREAD) << 6) |
((DMREAD) << 3) |
((DMREAD) << 0);
- d->qid.path = qpath;
- d->qid.version = 0;
+ d->path = qpath;
+ d->version = 0;
d->mtime = nsec();
d->size = size;
d->pdblkno = pdblkno;
@@ -204,7 +206,7 @@
*/
char magic[] = "m[a]fs device\n";
void
-reamdefaults(u64 bdconfig0, u64 bdsuper0, u64 bdroot0, u64 bdconfig1, u64 bdsuper1, u64 bdroot1)
+reamdefaults(u64 bdconfig0, u64 bdsuper0, u64 bdroot0)
{
Iobuf *b;
Dentry *d;
@@ -221,10 +223,12 @@
"10006:%s:%s:\n", user, user, user);
/* cannot show this in /adm though as the block number is 0 */
- b = getbuf(Bdmagic, Dentryunits, Bwritable, Bfreshalloc);
- memset(b->d, 0, Dentrysize);
+ b = getbuf(Bdmagic, Metadataunits, Bwritable, Bfreshalloc);
+ memset(b->m, 0, Metadatablocksize);
settag(b, Tdentry, Qpmagic);
- d = b->d;
+ d = (Dentry*)b->use;
+ d->ver++;
+ d->namelen = 5;
strncpy(d->name, "magic", 6);
d->uid = d->muid = d->gid = -1;
d->mode = DMDIR |
@@ -231,20 +235,22 @@
((DMREAD|DMWRITE|DMEXEC) << 6) |
((DMREAD|DMWRITE|DMEXEC) << 3) |
((DMREAD|DMWRITE|DMEXEC) << 0);
- d->qid.path = Qpmagic;
- d->qid.version = 0;
+ d->path = Qpmagic;
+ d->version = 0;
d->mtime = nsec();
d->pdblkno = Bdadm;
d->pqpath = Qpadm;
n = snprint((s8*)d->buf, Ddatasize, "%s%llud\n",
- magic, Unit);
+ magic, Blocksize);
d->size = n;
putbuf(b);
- b = getbuf(Bdadm, Dentryunits, Bwritable, Bfreshalloc);
- memset(b->d, 0, Dentrysize);
+ b = getbuf(Bdadm, Metadataunits, Bwritable, Bfreshalloc);
+ memset(b->m, 0, Metadatablocksize);
settag(b, Tdentry, Qpadm);
- d = b->d;
+ d = (Dentry*)b->use;
+ d->ver++;
+ d->namelen = 3;
strncpy(d->name, "adm", 4);
d->uid = d->muid = d->gid = -1;
d->mode = DMDIR |
@@ -251,8 +257,8 @@
((DMREAD|DMWRITE|DMEXEC) << 6) |
((DMREAD|DMWRITE|DMEXEC) << 3) |
((DMREAD|DMWRITE|DMEXEC) << 0);
- d->qid.path = Qpadm;
- d->qid.version = 0;
+ d->path = Qpadm;
+ d->version = 0;
d->mtime = nsec();
d->pdblkno = Bdroot;
d->pqpath = Qproot;
@@ -264,10 +270,12 @@
d->dblocks[5] = Bdctl;
putbuf(b);
- b = getbuf(Bdbkp, Dentryunits, Bwritable, Bfreshalloc);
- memset(b->d, 0, Dentrysize);
+ b = getbuf(Bdbkp, Metadataunits, Bwritable, Bfreshalloc);
+ memset(b->m, 0, Metadatablocksize);
settag(b, Tdentry, Qpbkp);
- d = b->d;
+ d = (Dentry*)b->use;
+ d->ver++;
+ d->namelen = 3;
strncpy(d->name, "bkp", 4);
d->uid = d->muid = d->gid = -1;
d->mode = DMDIR |
@@ -274,8 +282,8 @@
((DMREAD|DMWRITE|DMEXEC) << 6) |
((DMREAD|DMWRITE|DMEXEC) << 3) |
((DMREAD|DMWRITE|DMEXEC) << 0);
- d->qid.path = Qpbkp;
- d->qid.version = 0;
+ d->path = Qpbkp;
+ d->version = 0;
d->mtime = nsec();
d->size = strlen(users)+1;
d->pdblkno = Bdadm;
@@ -283,15 +291,14 @@
d->dblocks[0] = bdconfig0;
d->dblocks[1] = bdsuper0;
d->dblocks[2] = bdroot0;
- d->dblocks[3] = bdconfig1;
- d->dblocks[4] = bdsuper1;
- d->dblocks[5] = bdroot1;
putbuf(b);
- b = getbuf(Bdusers, Dentryunits, Bwritable, Bfreshalloc);
- memset(b->d, 0, Dentrysize);
+ b = getbuf(Bdusers, Metadataunits, Bwritable, Bfreshalloc);
+ memset(b->m, 0, Metadatablocksize);
settag(b, Tdentry, Qpusers);
- d = b->d;
+ d = (Dentry*)b->use;
+ d->ver++;
+ d->namelen = 5;
strncpy(d->name, "users", 6);
d->uid = d->muid = d->gid = -1;
d->mode = DMDIR |
@@ -298,8 +305,8 @@
((DMREAD|DMWRITE|DMEXEC) << 6) |
((DMREAD|DMWRITE|DMEXEC) << 3) |
((DMREAD|DMWRITE|DMEXEC) << 0);
- d->qid.path = Qpusers;
- d->qid.version = 0;
+ d->path = Qpusers;
+ d->version = 0;
d->mtime = nsec();
d->size = strlen(users)+1;
d->pdblkno = Bdadm;
@@ -308,10 +315,12 @@
d->dblocks[1] = Bdusersstaging;
putbuf(b);
- b = getbuf(Bdusersinuse, Dentryunits, Bwritable, Bfreshalloc);
- memset(b->d, 0, Dentrysize);
+ b = getbuf(Bdusersinuse, Metadataunits, Bwritable, Bfreshalloc);
+ memset(b->m, 0, Metadatablocksize);
settag(b, Tdentry, Qpusersinuse);
- d = b->d;
+ d = (Dentry*)b->use;
+ d->ver++;
+ d->namelen = 5;
strncpy(d->name, "inuse", 6);
d->uid = d->muid = d->gid = -1;
d->mode =
@@ -318,8 +327,8 @@
((DMREAD) << 6) |
((DMREAD) << 3) |
((DMREAD) << 0);
- d->qid.path = Qpusersinuse;
- d->qid.version = 0;
+ d->path = Qpusersinuse;
+ d->version = 0;
d->mtime = nsec();
d->size = userslen;
d->pdblkno = Bdusers;
@@ -327,10 +336,12 @@
strcpy((s8*)d->buf, users);
putbuf(b);
- b = getbuf(Bdroot, Dentryunits, Bwritable, Bfreshalloc);
- memset(b->d, 0, Dentrysize);
+ b = getbuf(Bdroot, Metadataunits, Bwritable, Bfreshalloc);
+ memset(b->m, 0, Metadatablocksize);
settag(b, Tdentry, Qproot);
- d = b->d;
+ d = (Dentry*)b->use;
+ d->ver++;
+ d->namelen = 1;
strncpy(d->name, "/", 5);
d->uid = d->muid = -1;
d->gid = -1;
@@ -338,8 +349,8 @@
((DMREAD|DMWRITE|DMEXEC) << 6) |
((DMREAD|DMWRITE|DMEXEC) << 3) |
((DMREAD|DMWRITE|DMEXEC) << 0);
- d->qid.path = Qproot;
- d->qid.version = 0;
+ d->path = Qproot;
+ d->version = 0;
d->mtime = nsec();
d->dblocks[0] = Bdadm;
putbuf(b);
@@ -356,16 +367,18 @@
superream(u64 size, u64 nblocks)
{
Iobuf *sbuf;
- Super *s;
+ Dentry *s;
u64 nbused;
nbused = Nbused;
- sbuf = getbuf(Bdsuper, Dentryunits, Bwritable, Bfreshalloc);
+ sbuf = getbuf(Bdsuper, Metadataunits, Bwritable, Bfreshalloc);
if(sbuf == nil)
panic("superream: sbuf == nil");
- memset(sbuf->d, 0, Dentrysize);
+ memset(sbuf->m, 0, Metadatablocksize);
settag(sbuf, Tdentry, Qpsuper);
- s = (Super*)sbuf->d;
+ s = (Dentry*)sbuf->use;
+ s->ver++;
+ s->namelen = 5;
strncpy(s->name, "super", 6);
s->uid = s->muid = s->gid = -1;
s->mode =
@@ -372,8 +385,8 @@
((DMREAD) << 6) |
((DMREAD) << 3) |
((DMREAD) << 0);
- s->qid.path = Qpsuper;
- s->qid.version = 0;
+ s->path = Qpsuper;
+ s->version = 0;
s->mtime = nsec();
s->size = 18;
s->pdblkno = Bdadm;
@@ -386,11 +399,8 @@
config.size = size;
config.nblocks = nblocks;
config.config.dest[0] = nblocks-Bdconfig;
- config.config.dest[1] = nbused+((nblocks-nbused)/2)-Bdconfig;
config.super.dest[0] = nblocks-Bdsuper;
- config.super.dest[1] = nbused+((nblocks-nbused)/2)-Bdsuper;
config.root.dest[0] = nblocks-3;
- config.root.dest[1] = nbused+((nblocks-nbused)/2)-3;
reamfile(config.config.dest[0], Qpconfig0, "config.0",
0, Bdbkp, Qpbkp, config.config.dest[0]);
@@ -398,28 +408,19 @@
0, Bdbkp, Qpbkp, config.super.dest[0]);
reamfile(config.root.dest[0], Qproot0, "root.0",
0, Bdbkp, Qpbkp, config.root.dest[0]);
-
- reamfile(config.config.dest[1], Qpconfig1, "config.1",
- 0, Bdbkp, Qpbkp, config.config.dest[1]);
- reamfile(config.super.dest[1], Qpsuper1, "super.1",
- 0, Bdbkp, Qpbkp, config.super.dest[1]);
- reamfile(config.root.dest[1], Qproot1, "root.1",
- 0, Bdbkp, Qpbkp, config.root.dest[1]);
putbuf(sbuf);
if(chatty9p > 1)
- dprint("backup config %llud %llud"
- " super %llud %llud"
- " root %llud %llud\n",
- config.config.dest[0], config.config.dest[1],
- config.super.dest[0], config.super.dest[1],
- config.root.dest[0], config.root.dest[1]);
+ dprint("backup config %llud"
+ " super %llud"
+ " root %llud\n",
+ config.config.dest[0],
+ config.super.dest[0],
+ config.root.dest[0]);
- reamdefaults(config.config.dest[0], config.super.dest[0], config.root.dest[0],
- config.config.dest[1], config.super.dest[1], config.root.dest[1]);
+ reamdefaults(config.config.dest[0], config.super.dest[0], config.root.dest[0]);
- bfree(&frees, config.config.dest[1]+1, config.root.dest[0]-config.config.dest[1]-1);
- bfree(&frees, nbused, config.root.dest[1]-nbused);
+ bfree(&frees, nbused, config.root.dest[0]-nbused);
if(chatty9p > 1)
showextents(2, "free extents: ", &frees);
if(chatty9p > 1)
@@ -442,24 +443,24 @@
void
ream(u64 size)
{
- char buf[Unit];
+ char buf[Blocksize];
int i;
u64 nblocks;
- nblocks = size/Unit;
+ nblocks = size/Blocksize;
if(nblocks <= Nminblocks)
panic("not enough space");
if(chatty9p > 1){
- dprint("%s %s ream %llud bytes into %llud units of %d bytes\n",
- service, devfile, size, nblocks, Unit);
- dprint(" (dentry size: raw %d bytes)\n", Dentrysize);
- dprint(" (data block size: raw %d bytes, usable %d bytes)\n",
- Rawblocksize, Blocksize);
+ dprint("%s %s ream %llud bytes into %llud blocks of %d bytes\n",
+ service, devfile, size, nblocks, Blocksize);
+ dprint(" (dentry size: raw %d bytes)\n", Metadatablocksize);
+ dprint(" (data block size: usable %d bytes)\n",
+ Maxdatablocksize);
dprint(" (name length: %d bytes)\n", Namelen);
}
- memset(buf, 0, Unit);
+ memset(buf, 0, Blocksize);
for(i = 0; i < Nbused; i++)
devwrite(i, buf, 1);
@@ -478,7 +479,7 @@
{
u32 unitsize;
Iobuf *sb, *b;
- Super *s;
+ Dentry *s;
s8 *rptr;
if(doream)
@@ -489,30 +490,30 @@
}
/* check magic */
- b = getbufchk(Bdmagic, Breadonly, Tdentry, Qpmagic);
+ b = getbufchk(Bdmagic, Metadataunits, Breadonly, Tdentry, Qpmagic);
if(b == nil){
panic("Invalid magic: %s",errstring[Ephase]);
return;
}
- if(strncmp((s8*)b->d->buf,magic,strlen(magic)) != 0){
+ if(strncmp((s8*)((Dentry*)b->use)->buf,magic,strlen(magic)) != 0){
print("init: bad magic -%s-", (s8*)b->io+256);
panic("bad magic");
}
- unitsize = strtoul((s8*)b->d->buf+strlen(magic), &rptr, 10);
- if(unitsize != Unit){
- print("init incorrect block size Unit %llud unitsize %d\n",
- Unit, unitsize);
- panic("bad Unit != unitsize");
+ unitsize = strtoul((s8*)((Dentry*)b->use)->buf+strlen(magic), &rptr, 10);
+ if(unitsize != Blocksize){
+ print("init incorrect block size Blocksize %llud unitsize %d\n",
+ Blocksize, unitsize);
+ panic("bad Blocksize != unitsize");
}
putbuf(b);
/* check super */
- sb = getbufchk(Bdsuper, Breadonly, Tdentry, Qpsuper);
+ sb = getbufchk(Bdsuper, Metadataunits, Breadonly, Tdentry, Qpsuper);
if(sb == nil){
panic("Invalid super: %s",errstring[Ephase]);
return;
}
- s = (Super*)sb->io;
+ s = (Dentry*)sb->use;
if(s->fsok != 1 || config.size != size)
panic(errstring[Edirty]);
--- a/tag.c
+++ b/tag.c
@@ -88,9 +88,8 @@
/* blocks above this index have this tag
For example,
- Tind0 starts from a reli >= 24
- Tind1 starts from a reli >= 74
- Tind2 starts from a reli >= 3100
+ Tind0 starts from a reli >= Ndblock
+ Tind1 starts from a reli >= Ndblock+Nindperblock
*/
u64
tagstartreli(u8 tag)
--- a/tests/sizes.c
+++ b/tests/sizes.c
@@ -9,32 +9,32 @@
int t;
u64 n;
- print("Unit %llud Dentrysize %llud Rawblocksize %llud\n",
- Unit, Dentrysize, Rawblocksize);
+ print("Blocksize %llud Metadataunits %d Maxdatablockunits %d\n",
+ Blocksize, Metadataunits, Maxdatablockunits);
print("Dentryhdr size %d Ddatasize %llud\n",
sizeof(Dentryhdr), Ddatasize);
print("Dentry size %d Namelen %d\n",
sizeof(Dentry), Namelen);
print("Namelen %d Ndblock %d Niblock %d\n", Namelen, Ndblock, Niblock);
- print("Blocksize %llud Nindperblock %llud\n",
- Blocksize, Nindperblock);
+ print("Nindperblock %llud Maxdatablocksize %llud\n",
+ Nindperblock, Maxdatablocksize);
for (t = Tind0; t < Maxtind; t++) {
n = nperindunit(t);
print("A %s unit points to %lld data blocks (%llud bytes)\n",
- tagnames[t], n, n*Blocksize);
+ tagnames[t], n, n*Maxdatablocksize);
print(" block points to %llud data blocks\n", nperiblock(t));
print(" reli start %llud max %llud\n",
tagstartreli(t), maxreli(t));
- print(" max size %llud*Blocksize = %llud bytes",
+ print(" max size %llud*Maxdatablocksize = %llud bytes",
maxblocks(t),
- maxblocks(t)*Blocksize);
- if(maxblocks(t)*Blocksize/(TiB) > 0)
- print(" = %llud TiB\n",maxblocks(t)*Blocksize/(TiB));
- else if(maxblocks(t)*Blocksize/(GiB) > 0)
- print(" = %llud GiB\n",maxblocks(t)*Blocksize/(GiB));
- else if(maxblocks(t)*Blocksize/(MiB) > 0)
- print(" = %llud MiB\n",maxblocks(t)*Blocksize/(MiB));
+ maxblocks(t)*Maxdatablocksize);
+ if(maxblocks(t)*Maxdatablocksize/(TiB) > 0)
+ print(" = %llud TiB\n",maxblocks(t)*Maxdatablocksize/(TiB));
+ else if(maxblocks(t)*Maxdatablocksize/(GiB) > 0)
+ print(" = %llud GiB\n",maxblocks(t)*Maxdatablocksize/(GiB));
+ else if(maxblocks(t)*Maxdatablocksize/(MiB) > 0)
+ print(" = %llud MiB\n",maxblocks(t)*Maxdatablocksize/(MiB));
else
print("\n");
}
--- a/updatefrees.c
+++ b/updatefrees.c
@@ -57,9 +57,9 @@
nfreesize = read(fd, frees, Rawblocksize);
if(nfreesize <= 0)
sysfatal("updatefrees: nfreesize %d <= 0\n", nfreesize);
- if(nfreesize > Blocksize)
- sysfatal("updatefrees: unsupported nfreesize %d > Blocksize %llud\n",
- nfreesize, Blocksize);
+ if(nfreesize > Datablocksize)
+ sysfatal("updatefrees: unsupported nfreesize %d > Datablocksize %llud\n",
+ nfreesize, Datablocksize);
close(fd);
freeblkno = atoll((s8*)frees);