218 lines · 5.1 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <blockalloc.h> u64intpreadn(int fd, void *buf, u64int offset, u64int len){	int nfd = dup(fd,-1);	seek(nfd, (vlong) offset, 0);	u64int retval = (u64int) readn(nfd, buf, (vlong) len);	close(nfd);	return retval;} u64intpwriten(int fd, void *buf, u64int offset, u64int len){	return (u64int)pwrite(fd,buf,(long) len, (vlong) offset);} intloadbptrs(Disk *d){	Fn *f = infn("loadbptrs");	int fd = d->fd;	Metablock *m = d->meta;	u64int ptrbitmapsize = m->totalblocks*BPTRSIZE;	action(f,"preadn 1");	if(preadn(fd, d->ptrs, m->ptrmapstart, ptrbitmapsize) < ptrbitmapsize){		action(f,"failure");		d->blocks_cached = 0;		outfn(f);		return -1;	}	d->blocks_cached = 1;	outfn(f);	return 0;} intsyncbptrs(Disk *d){	Fn *f = infn("syncbptrs");	iqlock(f,&d->synclock);	iqlock(f,&d->writelock);	if(d->blocks_cached){		for(u64int i = 0; i < d->meta->totalblocks; i++){			writebptr(d,&d->ptrs[i]);			if(&d->ptrs[i].buffer != nil){				writeblock(d,&d->ptrs[i],&d->ptrs[i].buffer);				free(&d->ptrs[i].buffer);			}		}		iqunlock(f,&d->synclock);		outfn(f);		return 0;	}	iqunlock(f,&d->synclock);	outfn(f);	return -1;} u64intreadbptr(Disk *d, Blockptr *b, u64int block){	Fn *f = infn("readbptr");	if(d->blocks_cached){		iqlock(f,&d->synclock);		b = &d->ptrs[block];		iqunlock(f,&d->synclock);		outfn(f);		return BPTRSIZE;	} else {		action(f,"preadn 1");		/* TODO: make a Blockptr odf type and use that instead of the Blockptr type directly.				 In theory, using the Blockptr type directly without a mallocz could possibly				 cause some issues if the user doesn't know whether caching is on or not.				 Using mallocz has performance implications and I should probably avoid it.		*/		u64int retval = preadn(d->fd, b, d->meta->ptrmapstart+(BPTRSIZE*block),BPTRSIZE);		b->buffer = nil;		outfn(f);		return retval;	}} /*writebptr should basically only be used by sync or in cases whenyou're using the block pointer rewriting capabilities of blockalloc todo copy-on-write of data blocks or some shit.  writebptr *always* doesa write(2) to the disk where as readbptr uses the in-memory structuresinstead of the on-disk structures.  Also if you're modifyingreadbptr'd Blockptrs and the cache is available then you *are*modifying the on-disk Blockptrs.  Remember, all of these functions areprobably dangerous; think carefully and don't do stupid things withother people's data.*/u64intwritebptr(Disk *d, Blockptr *b){	Fn *f = infn("writebptr");	Metablock *m = d->meta;	u64int blocksize = m->blocksize;	u64int blockaddr = b->offset/blocksize;	action(f,"pwriten 1 (retval)");	outfn(f);	return pwriten(d->fd,b,m->ptrmapstart+(BPTRSIZE*blockaddr),BPTRSIZE);} u64intallocblock(Disk *d, Blockptr *b){	Fn *f = infn("allocblock");	if(d->blocks_cached){		iqlock(f,&d->synclock);		for(u64int i = 0; i < d->meta->totalblocks; i++){			if(d->ptrs[i].used == 0){				b = &d->ptrs[i];				iqunlock(f,&d->synclock);				outfn(f);				return i+1;			}		}		iqunlock(f,&d->synclock);		action(f,"retval -1");		outfn(f);		return -1;	} else {		Blockptr *bf = malloc(sizeof(Blockptr));		action(f,smprint("allocated %p",bf));		for(u64int i = 0 ; i < d->meta->totalblocks; i++){			preadn(d->fd,bf,d->meta->ptrmapstart+(i*BPTRSIZE),BPTRSIZE);			if(bf->used == 0){				b = bf;				outfn(f);				return i;			}		}		action(f,smprint("freeing %p",bf));		free(bf);		b = nil;		outfn(f);		return 0;	}} intfreeblock(Disk *d, Blockptr *b){	Fn *f = infn("freeblock");	if(d->blocks_cached){		iqlock(f,&d->synclock);		b->used = 0;		iqunlock(f,&d->synclock);		outfn(f);		return 0;	} else {		b->used = 0;		for(int i = 0; i < 10 ; i++){			if(writebptr(d,b) >= BPTRSIZE){				outfn(f);				return 0;			}		}	}	action(f,"retval -1");	outfn(f);	return -1;		} u64intreadblock(Disk *d, Blockptr *b, void *buf){	Fn *f = infn("readblock");	int fd = d->fd;	u64int blocksize = d->meta->blocksize;	u64int offset = b->offset+d->meta->blocksize+d->meta->bitmapstart;	iqlock(f,&d->synclock);	if(d->blocks_cached && b->buffer != nil){		buf = b->buffer;		iqunlock(f,&d->synclock);		outfn(f);		return blocksize;	} else if (d->blocks_cached && b->buffer == nil){		u64int retval = preadn(fd,b->buffer,offset,blocksize);		buf = b->buffer;		iqunlock(f,&d->synclock);		outfn(f);		return retval;	} else {		iqunlock(f,&d->synclock);		outfn(f);		return preadn(fd,buf,offset,blocksize);	}} u64intwriteblock(Disk *d, Blockptr *b, void *buf){	Fn *f= infn("writeblock");	int fd = d->fd;	if(canqlock(&d->synclock) && d->blocks_cached){		iqlock(f,&d->writelock);		memcpy(b->buffer,buf,d->meta->blocksize);		action(f,"return (not writing, blocks cached, no sync)");		iqunlock(f,&d->writelock);		outfn(f);		return d->meta->blocksize;	} else if (!canqlock(&d->synclock) && d->blocks_cached) {		action(f,"return (writing, blocks cached, syncing)");		outfn(f);		return pwriten(fd,buf,b->offset+d->meta->bitmapstart,d->meta->blocksize);	} else {		action(f,"return (writing, blocks not cached, not syncing)");		outfn(f);		return pwriten(fd,buf,b->offset+d->meta->bitmapstart,d->meta->blocksize);	}}