907 lines · 18.8 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <thread.h>#include <sunrpc.h>#include <nfs3.h>#include <diskfs.h>#include "ffs.h" #define BADBNO	((u64int)~0ULL) #define checkcg 0#define debug 0 static int checkfsblk(Fsblk*);static int checkcgblk(Cgblk*);static Block *ffsblockread(Fsys*, u64int);static int ffssync(Fsys*);static void ffsclose(Fsys*); static u64int ffsxfileblock(Fsys *fs, Nfs3Handle *h, u64int offset);static Nfs3Status ffsroot(Fsys*, Nfs3Handle*);static Nfs3Status ffsgetattr(Fsys*, SunAuthUnix *au, Nfs3Handle*, Nfs3Attr*);static Nfs3Status ffslookup(Fsys*, SunAuthUnix *au, Nfs3Handle*, char*, Nfs3Handle*);static Nfs3Status ffsreadfile(Fsys*, SunAuthUnix *au, Nfs3Handle*, u32int, u64int, uchar**, u32int*, u1int*);static Nfs3Status ffsreadlink(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char **link);static Nfs3Status ffsreaddir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int, u64int, uchar**, u32int*, u1int*);static Nfs3Status ffsaccess(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int want, u32int *got, Nfs3Attr *attr); Fsys*fsysopenffs(Disk *disk, u32int bs, u64int off){	Ffs *fs;	Fsys *fsys; 	fsys = emalloc(sizeof(Fsys));	fs = emalloc(sizeof(Ffs));	fs->disk = disk;	fsys->priv = fs;	fsys->type = "ffs";	fsys->_readblock = ffsblockread;	fsys->_sync = ffssync;	fsys->_root = ffsroot;	fsys->_getattr = ffsgetattr;	fsys->_access = ffsaccess;	fsys->_lookup = ffslookup;	fsys->_readfile = ffsreadfile;	fsys->_readlink = ffsreadlink;	fsys->_readdir = ffsreaddir;	fsys->_close = ffsclose;	fsys->fileblock = ffsxfileblock; 	if(ffssync(fsys) < 0)		goto error; 	return fsys; error:	ffsclose(fsys);	return nil;} static Cgblk*ffscylgrp(Ffs *fs, u32int i, Block **pb){	Block *b;	Cgblk *cg; 	if(i >= fs->ncg)		return nil; 	b = diskread(fs->disk, fs->blocksize, (u64int)fs->cg[i].cgblkno*fs->blocksize);	if(b == nil)		return nil;	cg = (Cgblk*)b->data;	if(checkcgblk(cg) < 0){fprint(2, "checkcgblk %d %lud: %r\n", i, (ulong)fs->cg[i].cgblkno);		blockput(b);		return nil;	}	*pb = b;	return cg;} static intffssync(Fsys *fsys){	int i;	int off[] = { SBOFF, SBOFF2, SBOFFPIGGY };	Block *b, *cgb;	Cgblk *cgblk;	Cylgrp *cg;	Disk *disk;	Ffs *fs;	Fsblk *fsblk; 	fs = fsys->priv;	disk = fs->disk; 	/*	 * Read super block.	 */	b = nil;	for(i=0; i<nelem(off); i++){		if((b = diskread(disk, SBSIZE, off[i])) == nil)			goto error;		fsblk = (Fsblk*)b->data;	//	fprint(2, "offset of magic: %ld\n", offsetof(Fsblk, magic));		if((fs->ufs = checkfsblk(fsblk)) > 0)			goto okay;		blockput(b);		b = nil;	}	goto error; okay:	fs->blocksize = fsblk->blocksize;	fs->nblock = (fsblk->nfrag+fsblk->fragsperblock-1) / fsblk->fragsperblock;	fs->fragsize = fsblk->fragsize;	fs->fragspergroup = fsblk->fragspergroup;	fs->fragsperblock = fsblk->fragsperblock;	fs->inosperblock = fsblk->inosperblock;	fs->inospergroup = fsblk->inospergroup; 	fs->nfrag = fsblk->nfrag;	fs->ndfrag = fsblk->ndfrag;	/*	 * used to use 	 *	fs->blockspergroup = (u64int)fsblk->_cylspergroup * 	 *		fsblk->secspercyl * BYTESPERSEC / fsblk->blocksize;	 * for UFS1, but this should work for both UFS1 and UFS2	 */	fs->blockspergroup = (u64int)fsblk->fragspergroup / fsblk->fragsperblock;	fs->ncg = fsblk->ncg; 	fsys->blocksize = fs->blocksize;	fsys->nblock = fs->nblock; 	if(debug) fprint(2, "ffs %lld %d-byte blocks, %d cylinder groups\n",		fs->nblock, fs->blocksize, fs->ncg);	if(debug) fprint(2, "\tinospergroup %d perblock %d blockspergroup %lld\n",		fs->inospergroup, fs->inosperblock, fs->blockspergroup); 	if(fs->cg == nil)		fs->cg = emalloc(fs->ncg*sizeof(Cylgrp));	for(i=0; i<fs->ncg; i++){		cg = &fs->cg[i];		if(fs->ufs == 2)			cg->bno = (u64int)fs->blockspergroup*i;		else			cg->bno = fs->blockspergroup*i + fsblk->_cgoffset * (i & ~fsblk->_cgmask);		cg->cgblkno = cg->bno + fsblk->cfragno/fs->fragsperblock;		cg->ibno = cg->bno + fsblk->ifragno/fs->fragsperblock;		cg->dbno = cg->bno + fsblk->dfragno/fs->fragsperblock; 		if(checkcg){			if((cgb = diskread(disk, fs->blocksize, (u64int)cg->cgblkno*fs->blocksize)) == nil)				goto error; 			cgblk = (Cgblk*)cgb->data;			if(checkcgblk(cgblk) < 0){				blockput(cgb);				goto error;			}			if(cgblk->nfrag % fs->fragsperblock && i != fs->ncg-1){				werrstr("fractional number of blocks in non-last cylinder group %d", cgblk->nfrag);				blockput(cgb);				goto error;			}			/* cg->nfrag = cgblk->nfrag; */			/* cg->nblock = (cgblk->nfrag+fs->fragsperblock-1) / fs->fragsperblock; */			/* fprint(2, "cg #%d: cgblk %lud, %d blocks, %d inodes\n", cgblk->num, (ulong)cg->cgblkno, cg->nblock, cg->nino); */		}	}	blockput(b);	return 0; error:	blockput(b);	return -1;} static voidffsclose(Fsys *fsys){	Ffs *fs; 	fs = fsys->priv;	if(fs->cg)		free(fs->cg);	free(fs);	free(fsys);}	static intcheckfsblk(Fsblk *super){// fprint(2, "ffs magic 0x%ux\n", super->magic);	if(super->magic == FSMAGIC){		super->time = super->_time;		super->nfrag = super->_nfrag;		super->ndfrag = super->_ndfrag;		super->flags = super->_flags;		return 1;	}	if(super->magic == FSMAGIC2){		return 2;	} 	werrstr("bad super block");	return -1;} static intcheckcgblk(Cgblk *cg){	if(cg->magic != CGMAGIC){		werrstr("bad cylinder group block");		return -1;	}	return 0;} /* * Read block #bno from the disk, zeroing unused data. * If there is no data whatsoever, it's okay to return nil. */int nskipx;static Block*ffsblockread(Fsys *fsys, u64int bno){	int i, o;	u8int *fmap;	int frag, fsize, avail;	Block *b;	Cgblk *cgblk;	Ffs *fs; 	fs = fsys->priv;	i = bno / fs->blockspergroup;	o = bno % fs->blockspergroup;	if(i >= fs->ncg)		return nil; 	if((cgblk = ffscylgrp(fs, i, &b)) == nil)		return nil; 	fmap = (u8int*)cgblk+cgblk->fmapoff;	frag = fs->fragsperblock;	switch(frag){	default:		sysfatal("bad frag");	case 8:		avail = fmap[o];		break;	case 4:		avail = (fmap[o>>1] >> ((o&1)*4)) & 0xF;		break;	case 2:		avail = (fmap[o>>2] >> ((o&3)*2)) & 0x3;		break;	case 1:		avail = (fmap[o>>3] >> (o&7)) & 0x1;		break;	}	blockput(b); 	if(avail == ((1<<frag)-1)){nskipx++;		return nil;}	if((b = diskread(fs->disk, fs->blocksize, bno*fs->blocksize)) == nil){		fprint(2, "diskread failed!!!\n");		return nil;	} 	fsize = fs->fragsize;	for(i=0; i<frag; i++)		if(avail & (1<<i))			memset(b->data + fsize*i, 0, fsize);	return b;} static Block*ffsdatablock(Ffs *fs, u64int bno, int size){	int fsize;	u64int diskaddr;	Block *b; 	if(bno == 0)		return nil; 	fsize = size;	if(fsize < fs->fragsize)		fsize = fs->fragsize; 	if(bno >= fs->nfrag){		fprint(2, "ffs: request for block %#lux; nfrag %#llux\n", (ulong)bno, fs->nfrag);		return nil;	}	diskaddr = (u64int)bno*fs->fragsize;	b = diskread(fs->disk, fsize, diskaddr);	if(b == nil){		fprint(2, "ffs: disk i/o at %#llux for %#ux: %r\n", diskaddr, fsize);		return nil;	}	if(b->len < fsize){		fprint(2, "ffs: disk i/o at %#llux for %#ux got %#ux\n", diskaddr, fsize,			b->len);		blockput(b);		return nil;	}		return b;} static u64intifetch(Ffs *fs, u64int bno, u32int off){	Block *b;		if(bno == BADBNO)		return BADBNO;	b = ffsdatablock(fs, bno, fs->blocksize);	if(b == nil)		return BADBNO;	if(fs->ufs == 2)		bno = ((u64int*)b->data)[off];	else		bno = ((u32int*)b->data)[off];	blockput(b);	return bno;} static u64intffsfileblockno(Ffs *fs, Inode *ino, u64int bno){	int ppb; 	if(bno < NDADDR){		if(debug) fprint(2, "ffsfileblock %lud: direct %#lux\n", (ulong)bno, (ulong)ino->db[bno]);		return ino->db[bno];	}	bno -= NDADDR;	ppb = fs->blocksize/4; 	if(bno < ppb)	/* single indirect */		return ifetch(fs, ino->ib[0], bno);	bno -= ppb; 	if(bno < ppb*ppb)		return ifetch(fs, ifetch(fs, ino->ib[1], bno/ppb), bno%ppb);	bno -= ppb*ppb;		if(bno/ppb/ppb/ppb == 0)	/* bno < ppb*ppb*ppb w/o overflow */		return ifetch(fs, ifetch(fs, ifetch(fs, ino->ib[2], bno/ppb/ppb), (bno/ppb)%ppb), bno%ppb);		fprint(2, "ffsfileblock %llud: way too big\n", bno+NDADDR+ppb+ppb*ppb);	return BADBNO;} static Block*ffsfileblock(Ffs *fs, Inode *ino, u64int bno, int size){	u64int b;		b = ffsfileblockno(fs, ino, bno);	if(b == ~0)		return nil;	return ffsdatablock(fs, b, size);} /* * NFS handles are 4-byte inode number. */static voidmkhandle(Nfs3Handle *h, u64int ino){	h->h[0] = ino >> 24;	h->h[1] = ino >> 16;	h->h[2] = ino >> 8;	h->h[3] = ino;	h->len = 4;} static u32intbyte2u32(uchar *p){	return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];} static u64int lastiaddr;	/* debugging */ static voidinode1to2(Inode1 *i1, Inode *i2){	int i;		memset(i2, 0, sizeof *i2);	i2->mode = i1->mode;	i2->nlink = i1->nlink;	i2->size = i1->size;	i2->atime = i1->atime;	i2->atimensec = i1->atimensec;	i2->mtime = i1->mtime;	i2->mtimensec = i1->mtimensec;	i2->ctime = i1->ctime;	i2->ctimensec = i1->ctimensec;	for(i=0; i<NDADDR; i++)		i2->db[i] = i1->db[i];	for(i=0; i<NIADDR; i++)		i2->ib[i] = i1->ib[i];	i2->flags = i1->flags;	i2->nblock = i1->nblock;	i2->gen = i1->gen;	i2->uid = i1->uid;	i2->gid = i1->gid;} static Nfs3Statushandle2ino(Ffs *fs, Nfs3Handle *h, u32int *pinum, Inode *ino){	int i;	u32int ioff;	u32int inum;	u64int iaddr;	Block *b;	Cylgrp *cg;	Inode1 ino1; 	if(h->len != 4)		return Nfs3ErrBadHandle;	inum = byte2u32(h->h);	if(pinum)		*pinum = inum;	if(debug) print("inum %d...", (int)inum); 	/* fetch inode from disk */	i = inum / fs->inospergroup;	ioff = inum % fs->inospergroup;	if(debug)print("cg %d off %d...", i, (int)ioff);	if(i >= fs->ncg)		return Nfs3ErrBadHandle;	cg = &fs->cg[i]; 	if(debug) print("cg->ibno %lld ufs %d...", cg->ibno, fs->ufs);	iaddr = (cg->ibno+ioff/fs->inosperblock)*(vlong)fs->blocksize;	ioff = ioff%fs->inosperblock;	if((b = diskread(fs->disk, fs->blocksize, iaddr)) == nil)		return Nfs3ErrIo;	if(fs->ufs == 2){		*ino = ((Inode*)b->data)[ioff];		lastiaddr = iaddr+ioff*sizeof(Inode);	}else{		ino1 = ((Inode1*)b->data)[ioff];		inode1to2(&ino1, ino);		lastiaddr = iaddr+ioff*sizeof(Inode1);	}	blockput(b);	return Nfs3Ok;} static Nfs3Statusffsroot(Fsys *fsys, Nfs3Handle *h){	USED(fsys);	mkhandle(h, 2);	return Nfs3Ok;} static Nfs3Statusino2attr(Ffs *fs, Inode *ino, u32int inum, Nfs3Attr *attr){	u32int rdev; 	attr->type = -1;	switch(ino->mode&IFMT){	case IFIFO:		attr->type = Nfs3FileFifo;		break;	case IFCHR:		attr->type = Nfs3FileChar;		break;	case IFDIR:		attr->type = Nfs3FileDir;		break;	case IFBLK:		attr->type = Nfs3FileBlock;		break;	case IFREG:		attr->type = Nfs3FileReg;		break;	case IFLNK:		attr->type = Nfs3FileSymlink;		break;	case IFSOCK:		attr->type = Nfs3FileSocket;		break;	case IFWHT:

Lines 1–500 of 907.