code: mafs

ref: 5c21eca829380c28769f79beabb7cc51f1787f97
dir: /free.c/

View raw version
#include <u.h>
#include <libc.h>
#include "dat.h"
#include "fns.h"
#include "extents.h"

/*
	go through the contents of Bfrees and write out the list of free blocks
	used by reconcile.c to identify discrepancies
 */

Extents frees;
int chatty9p = 0;
char *devfile = nil;
void walkdentry(u64 blkno);
int checkblock(u64 blkno, s16 tag, u64 qpath);
void getfrees(u64 dblkno);

static void
usage(void)
{
	fprint(2, "usage: free [-D ] fsfile\n");
	exits("usage");
}

void
main(int argc, char *argv[])
{
	u64 size;

	ARGBEGIN{
	default:	usage();
	case 'D':	chatty9p++; break;
	}ARGEND

	if(argc != 1)
		usage();

	devfile = argv[0];
	if(devfile == nil)
		sysfatal("no disk file");

	if (access(devfile, AREAD) == -1)
		sysfatal("%s cannot access device", devfile);

	size = devinit(devfile);
	if(size == 0)
		panic("null size %s", devfile);
	if(chatty9p)
		print("%s %llud bytes %llud blocks\n", devfile, size, size/Rawblocksize);

	checkblock(Bdfrees, Tdentry, Qpfrees);
	getfrees(Bdfrees);
// showextents("after getfrees", &frees);
	showblocknos(&frees);
	exits(0);
}

int
checkvalid(u64 blkno, Tag *t, s16 tag, u64 qpath)
{
	if(t->type != tag || t->path != qpath){
		/* if(chatty9p) */
			fprint(2, "check invalid %llud tag/path expected %s/%llud actual %s/%llud\n",
					blkno, tagnames[tag], qpath, tagnames[t->type], t->path);
		fprint(2, "free: %llud\n", blkno);
		return 0;
	}
	if(chatty9p)
	print("%llud\n", blkno);
	return 1;
}

int
checkblock(u64 blkno, s16 tag, u64 qpath)
{
	u8 buf[Rawblocksize];
	Tag *t;

	devread(blkno, buf, 1);
	t = (Tag*)buf;
	return checkvalid(blkno, t, tag, qpath);
}

void
loadfreeextents(u64 blkno, u16 len)
{
	s8 *buf;

	buf = emalloc(len*Rawblocksize);
	devread(blkno, buf, len);
	loadextents(&frees, buf+sizeof(Tag), (len*Rawblocksize)-sizeof(Tag));
	free(buf);
}

void
walkindir(u64 blkno, u16 tag, u16 bottomtag, u64 qpath)
{
	u8 buf[Rawblocksize], cbuf[Rawblocksize];
	Tag *t;
	u64 cblkno, *bufa;
	Spanid *s;
	u16 len;
	int i;

	devread(blkno, buf, 1);
	t = (Tag*)buf;
	if(checkvalid(blkno, t, tag, qpath)){
		if(t->type == Tind0){
			s = (Spanid*)(buf+sizeof(Tag));
			for(i = 0; i<Nspanidperblock; i++){
				cblkno = s[i].blkno;
				len = s[i].len;
				if(cblkno == 0)
					return;
				loadfreeextents(cblkno, len);
			}
		}else{
			bufa = (u64*)(buf+sizeof(Tag));
			for(i = 0; i<Nindperblock; i++){
				cblkno = bufa[i];
				if(cblkno == 0)
					return;
				devread(cblkno, cbuf, 1);
				/* check tag */
				walkindir(cblkno, tag-1,  bottomtag, qpath);
			}
		}
	}
}

void
getfrees(u64 dblkno)
{
	u64 size;
	u8 buf[Rawblocksize], cbuf[Rawblocksize];
	Dentry *d;
	Tag *t;
	u64 cblkno;
	int i;
	u16 len;

	devread(dblkno, buf, 1);
	t = (Tag*)buf;
	d = (Dentry*)(buf+sizeof(Tag));
	size = d->size;
	if(size == 0)
		panic("loadfreeextents size == 0");

	if(checkvalid(dblkno, t, Tdentry, d->qid.path)){
		for(i = 0; i<Ndspanid; i++){
			cblkno = d->dspans[i].blkno;
			len = d->dspans[i].len;
			if(cblkno == 0)
				return;
			loadfreeextents(cblkno, len);
		}
		for(i = Tind0; i<Niblock+Tind0; i++){
			cblkno = d->iblocks[i];
			if(cblkno == 0)
				return;
			devread(cblkno, cbuf, 1);
			walkindir(cblkno, i, Tdata, Qpfrees);
		}
	}
}