code: mafs

ref: 1a4e1fc2e52ab80b55ef0d7fdccca973267fb4cc
dir: /tag.c/

View raw version
#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);
}