ref: fb53d7e68bcb2108fb304c81dccb1d7ff50ffa1f
dir: /tag.c/
#include <u.h> #include <libc.h> #include "dat.h" #include "fns.h" static u64 addu64ov(u64 a, u64 b) { u64 r = a + b; if (r < a || r < b) return 0; return r; } static u64 mulu64ov(u64 a, u64 b) { u64 r = a * b; if (a != 0 && r/a != b || r < a || r < b) return 0; return r; } /* could use muluvlongov() here but it does not add any value for us raise base to n-th power; n >= 0 */ u64 power(u64 base, int n) { int i; u64 v; v = 1; for(i = 1; i <= n; i++) v = v*base; return v; } /* cache the values instead of calculating each time */ u64 nvals[Niblock] = {0}; /* Each u64 address in this indirect block links to n Tdata/Tdentry blocks */ u64 nperindunit(u16 tag) { if(tag < Tind0 || tag > Tmaxind+1) return 0; if(nvals[tag-Tind0] == 0) nvals[tag-Tind0] = power(Nindperblock, tag-Tind0); return nvals[tag-Tind0]; } /* * compute BLOCKSIZE*(Ndblock+INDPERBUF+INDPERBUF²+INDPERBUF³+INDPERBUF⁴ .. upto ^Niblock) * while watching for overflow; in that case, return 0. */ /* extern double pow(double x, double y); *//* return x ^ y (exponentiation) */ /* Each u64 address in the indirect block links to n Tdata/Tdentry blocks */ /* Each u64 address in the indirect block links to n Tdata/Tdentry blocks */ u64 nperiblock(u16 tag) { return nperindunit(tag+1); } /* get the Tindn tag of the block that a reli belongs to */ u8 rel2tind(u64 reli) { u64 maxfortag, tag, i; if(reli < Ndblock){ panic("should not be here"); } reli -= Ndblock; for(tag = Tind0, i = reli; tag <= Tmaxind; tag++){ maxfortag = nperiblock(tag); if(i < maxfortag) break; i -= maxfortag; } return tag; } /* blocks above this index have this tag For example, Tind0 starts from a reli >= Ndblock Tind1 starts from a reli >= Ndblock+Nindperblock */ u64 tagstartreli(u8 tag) { if(tag == Tind0) return Ndblock; else if(tag == Tind1) return Ndblock+Nindperblock; return nperiblock(tag-1)+tagstartreli(tag-1); } u64 maxreli(u8 tag) { return tagstartreli(tag+1)-1; } u64 maxblocks(u8 tag) { return maxreli(tag)+1; } /* size to Tdata reli */ u64 size2datareli(u64 size) { return size/Maxdatablocksize; } /* number of Tdata blocks for this size */ u64 size2ndata(u64 size) { if(size == 0) return 0; if(size%Maxdatablocksize == 0) return size/Maxdatablocksize; else return 1+ size/Maxdatablocksize; } /* for allocate on flush. number of blocks of the last Tdata block tests/chknlastdatablocks.rc tests/nlastdatablocks.c */ u64 nlastdatablocks(u64 size) { u64 tot, lastblksize; if(size == 0) return 0; if((lastblksize = size%Maxdatablocksize) == 0) return Maxdatablockunits; tot = lastblksize +Ddataidssize; if(tot%Blocksize == 0) return tot/Blocksize; /* aligns to the Blocksize */ else return 1+(tot/Blocksize); }