Beispiel #1
0
static
void
adjust_filelinks(void)
{
	struct sfs_inode sfi;
	int i;

	for (i=0; i<ninodes; i++) {
		if (inodes[i].linkcount==0) {
			/* directory */
			continue;
		}
		diskread(&sfi, inodes[i].ino);
		swapinode(&sfi);
		assert(sfi.sfi_type == SFS_TYPE_FILE);
		if (sfi.sfi_linkcount != inodes[i].linkcount) {
			warnx("File %lu link count %lu should be %lu (fixed)",
			      (unsigned long) inodes[i].ino,
			      (unsigned long) sfi.sfi_linkcount,
			      (unsigned long) inodes[i].linkcount);
			sfi.sfi_linkcount = inodes[i].linkcount;
			setbadness(EXIT_RECOV);
			swapinode(&sfi);
			diskwrite(&sfi, inodes[i].ino);
		}
		count_files++;
	}
}
Beispiel #2
0
static
void
check_root_dir(void)
{
	struct sfs_inode sfi;
	diskread(&sfi, SFS_ROOT_LOCATION);
	swapinode(&sfi);

	switch (sfi.sfi_type) {
	    case SFS_TYPE_DIR:
		break;
	    case SFS_TYPE_FILE:
		warnx("Root directory inode is a regular file (fixed)");
		goto fix;
	    default:
		warnx("Root directory inode has invalid type %lu (fixed)",
		      (unsigned long) sfi.sfi_type);
	    fix:
		setbadness(EXIT_RECOV);
		sfi.sfi_type = SFS_TYPE_DIR;
		swapinode(&sfi);
		diskwrite(&sfi, SFS_ROOT_LOCATION);
		break;
	}

	check_dir(SFS_ROOT_LOCATION, SFS_ROOT_LOCATION, "");
}
Beispiel #3
0
int
set_bcache(fileid_t *fp)
{
	/*
	 *  Insert Disk Block Cache Entry:
	 *
	 *  In this case, we actually read the requested block into a
	 *  dynamically allocated buffer before inserting it into the
	 *  cache.  If the read fails, we return a non-zero value.
	 *
	 *  The search keys for disk blocks are the block number and
	 *  buffer size.  The data associated with each entry is the
	 *  corresponding data buffer.
	 */
	bc_t *bcp;

	if (fp->fi_memp = bkmem_alloc(x_len = fp->fi_count)) {
		/*
		 *  We were able to succesffully allocate an input
		 *  buffer, now read the data into it.
		 */
		if (diskread(fp) != 0) {
			/*
			 * I/O error on read. Free the input buffer,
			 * print an error message, and bail out.
			 */
			bkmem_free(fp->fi_memp, x_len);
			printf("disk read error\n");
			return (-1);
		}

		x_blkno = fp->fi_blocknum;
		x_dev = fp->fi_devp->di_dcookie;
		bcp = (bc_t *)
			set_cache(&bc_hash[BC_HASH(x_dev, x_blkno, x_len)],
								&bc_head, 0);
		bcp->bc_blk = x_blkno;
		bcp->bc_hdr.dev = x_dev;
		bcp->bc_hdr.size = x_len;
		bcp->bc_hdr.data = (void *)fp->fi_memp;

	} else {
		/*
		 * We could be a bit more convervative here by
		 * calling "set_cache" before we try to allocate a
		 * buffer (thereby giving us a chance to re-use a
		 * previously allocated buffer) but the error recovery
		 * is a bit trickier, and if we're that short on memory
		 * we'll have trouble elsewhere anyway!
		 */
		prom_panic("can't read - no memory");
	}

	return (0);
}
Beispiel #4
0
static int
ext2sync(Fsys *fsys)
{
	int i;
	Group g;
	Block *b;
	Super super;
	Ext2 *fs;
	Disk *disk;

	fs = fsys->priv;
	disk = fs->disk;
	if((b = diskread(disk, SBSIZE, SBOFF)) == nil)
		return -1;
	parsesuper(&super, b->data);
	blockput(b);
	if(checksuper(&super) < 0)
		return -1;
	fs->blocksize = MINBLOCKSIZE<<super.logblocksize;
	fs->nblock = super.nblock;
	fs->ngroup = (super.nblock+super.blockspergroup-1)
		/ super.blockspergroup;
	fs->inospergroup = super.inospergroup;
	fs->blockspergroup = super.blockspergroup;
	if(super.revlevel >= 1)
		fs->inosize = super.inosize;
	else
		fs->inosize = 128;
	fs->inosperblock = fs->blocksize / fs->inosize;
	if(fs->blocksize == SBOFF)
		fs->groupaddr = 2;
	else
		fs->groupaddr = 1;
	fs->descperblock = fs->blocksize / GroupSize;
	fs->firstblock = super.firstdatablock;

	fsys->blocksize = fs->blocksize;
	fsys->nblock = fs->nblock;
	if(debug) fprint(2, "ext2 %d %d-byte blocks, first data block %d, %d groups of %d\n",
		fs->nblock, fs->blocksize, fs->firstblock, fs->ngroup, fs->blockspergroup);

	if(0){
		for(i=0; i<fs->ngroup; i++)
			if(ext2group(fs, i, &g) >= 0)
				fprint(2, "grp %d: bitblock=%d\n", i, g.bitblock);
	}
	return 0;
}
Beispiel #5
0
static
void
check_sb(void)
{
	struct sfs_super sp;
	uint32_t i;
	int schanged=0;

	diskread(&sp, SFS_SB_LOCATION);
	swapsb(&sp);
	if (sp.sp_magic != SFS_MAGIC) {
		errx(EXIT_UNRECOV, "Not an sfs filesystem");
	}

	assert(nblocks==0);
	assert(bitblocks==0);
	nblocks = sp.sp_nblocks;
	bitblocks = SFS_BITBLOCKS(nblocks);
	assert(nblocks>0);
	assert(bitblocks>0);

	bitmap_init(bitblocks);
	for (i=nblocks; i<bitblocks*SFS_BLOCKBITS; i++) {
		bitmap_mark(i, B_PASTEND, 0);
	}

	if (checknullstring(sp.sp_volname, sizeof(sp.sp_volname))) {
		warnx("Volume name not null-terminated (fixed)");
		setbadness(EXIT_RECOV);
		schanged = 1;
	}
	if (checkbadstring(sp.sp_volname)) {
		warnx("Volume name contains illegal characters (fixed)");
		setbadness(EXIT_RECOV);
		schanged = 1;
	}

	if (schanged) {
		swapsb(&sp);
		diskwrite(&sp, SFS_SB_LOCATION);
	}

	bitmap_mark(SFS_SB_LOCATION, B_SUPERBLOCK, 0);
	for (i=0; i<bitblocks; i++) {
		bitmap_mark(SFS_MAP_LOCATION+i, B_BITBLOCK, i);
	}
}
Beispiel #6
0
static int
ext2group(Ext2 *fs, u32int i, Group *g)
{
	Block *b;
	u64int addr;

	if(i >= fs->ngroup)
		return -1;

	addr = fs->groupaddr + i/fs->descperblock;
	b = diskread(fs->disk, fs->blocksize, addr*fs->blocksize);
	if(b == nil)
		return -1;
	parsegroup(g, b->data+i%fs->descperblock*GroupSize);
	blockput(b);
	return 0;
}
Beispiel #7
0
static
void
setcache(Buffer *b, uint q0)
{
	Block **blp, *bl;
	uint i, q;

	if(q0 > b->nc)
		panic("internal error: setcache");
	/*
	 * flush and reload if q0 is not in cache.
	 */
	if(b->nc == 0 || (b->cq<=q0 && q0<b->cq+b->cnc))
		return;
	/*
	 * if q0 is at end of file and end of cache, continue to grow this block
	 */
	if(q0==b->nc && q0==b->cq+b->cnc && b->cnc<=Maxblock)
		return;
	flush(b);
	/* find block */
	if(q0 < b->cq){
		q = 0;
		i = 0;
	}else{
		q = b->cq;
		i = b->cbi;
	}
	blp = &b->bl[i];
	while(q+(*blp)->n <= q0 && q+(*blp)->n < b->nc){
		q += (*blp)->n;
		i++;
		blp++;
		if(i >= b->nbl)
			panic("block not found");
	}
	bl = *blp;
	/* remember position */
	b->cbi = i;
	b->cq = q;
	sizecache(b, bl->n);
	b->cnc = bl->n;
	/*read block*/
	diskread(disk, bl, b->c, b->cnc);
}
Beispiel #8
0
static
void
dirread(struct sfs_inode *sfi, struct sfs_dir *d, unsigned nd)
{
	const unsigned atonce = SFS_BLOCKSIZE/sizeof(struct sfs_dir);
	unsigned nblocks = SFS_ROUNDUP(nd, atonce) / atonce;
	unsigned i, j;

	for (i=0; i<nblocks; i++) {
		uint32_t block = dobmap(sfi, i);
		if (block!=0) {
			diskread(d + i*atonce, block);
			for (j=0; j<atonce; j++) {
				swapdir(&d[i*atonce+j]);
			}
		}
		else {
			warnx("Warning: sparse directory found");
			bzero(d + i*atonce, SFS_BLOCKSIZE);
		}
	}
}
Beispiel #9
0
static
uint32_t
ibmap(uint32_t iblock, uint32_t offset, uint32_t entrysize)
{
	uint32_t entries[SFS_DBPERIDB];

	if (iblock == 0) {
		return 0;
	}

	diskread(entries, iblock);
	swapindir(entries);

	if (entrysize > 1) {
		uint32_t index = offset / entrysize;
		offset %= entrysize;
		return ibmap(entries[index], offset, entrysize/SFS_DBPERIDB);
	}
	else {
		assert(offset < SFS_DBPERIDB);
		return entries[offset];
	}
}
Beispiel #10
0
static
int
check_dir(uint32_t ino, uint32_t parentino, const char *pathsofar)
{
	struct sfs_inode sfi;
	struct sfs_dir *direntries;
	int *sortvector;
	uint32_t dirsize, ndirentries, maxdirentries, subdircount, i;
	int ichanged=0, dchanged=0, dotseen=0, dotdotseen=0;

	diskread(&sfi, ino);
	swapinode(&sfi);

	if (remember_dir(ino, pathsofar)) {
		/* crosslinked dir */
		return 1;
	}

	bitmap_mark(ino, B_INODE, ino);
	count_dirs++;

	if (sfi.sfi_size % sizeof(struct sfs_dir) != 0) {
		setbadness(EXIT_RECOV);
		warnx("Directory /%s has illegal size %lu (fixed)",
		      pathsofar, (unsigned long) sfi.sfi_size);
		sfi.sfi_size = SFS_ROUNDUP(sfi.sfi_size,
					   sizeof(struct sfs_dir));
		ichanged = 1;
	}

	if (check_inode_blocks(ino, &sfi, 1)) {
		ichanged = 1;
	}

	ndirentries = sfi.sfi_size/sizeof(struct sfs_dir);
	maxdirentries = SFS_ROUNDUP(ndirentries,
				    SFS_BLOCKSIZE/sizeof(struct sfs_dir));
	dirsize = maxdirentries * sizeof(struct sfs_dir);
	direntries = domalloc(dirsize);
	sortvector = domalloc(ndirentries * sizeof(int));

	dirread(&sfi, direntries, ndirentries);
	for (i=ndirentries; i<maxdirentries; i++) {
		direntries[i].sfd_ino = SFS_NOINO;
		bzero(direntries[i].sfd_name, sizeof(direntries[i].sfd_name));
	}

	for (i=0; i<ndirentries; i++) {
		if (check_dir_entry(pathsofar, i, &direntries[i])) {
			dchanged = 1;
		}
		sortvector[i] = i;
	}

	sortdir(sortvector, direntries, ndirentries);

	/* don't use ndirentries-1 here in case ndirentries == 0 */
	for (i=0; i+1<ndirentries; i++) {
		struct sfs_dir *d1 = &direntries[sortvector[i]];
		struct sfs_dir *d2 = &direntries[sortvector[i+1]];
		assert(d1 != d2);

		if (d1->sfd_ino == SFS_NOINO) {
			continue;
		}

		if (!strcmp(d1->sfd_name, d2->sfd_name)) {
			if (d1->sfd_ino == d2->sfd_ino) {
				setbadness(EXIT_RECOV);
				warnx("Directory /%s: Duplicate entries for "
				      "%s (merged)",
				      pathsofar, d1->sfd_name);
				d1->sfd_ino = SFS_NOINO;
				d1->sfd_name[0] = 0;
			}
			else {
				snprintf(d1->sfd_name, sizeof(d1->sfd_name),
					 "FSCK.%lu.%lu",
					 (unsigned long) d1->sfd_ino,
					 (unsigned long) uniquecounter++);
				setbadness(EXIT_RECOV);
				warnx("Directory /%s: Duplicate names %s "
				      "(one renamed: %s)",
				      pathsofar, d2->sfd_name, d1->sfd_name);
			}
			dchanged = 1;
		}
	}

	for (i=0; i<ndirentries; i++) {
		if (!strcmp(direntries[i].sfd_name, ".")) {
			if (direntries[i].sfd_ino != ino) {
				setbadness(EXIT_RECOV);
				warnx("Directory /%s: Incorrect `.' entry "
				      "(fixed)", pathsofar);
				direntries[i].sfd_ino = ino;
				dchanged = 1;
			}
			assert(dotseen==0); /* due to duplicate checking */
			dotseen = 1;
		}
		else if (!strcmp(direntries[i].sfd_name, "..")) {
			if (direntries[i].sfd_ino != parentino) {
				setbadness(EXIT_RECOV);
				warnx("Directory /%s: Incorrect `..' entry "
				      "(fixed)", pathsofar);
				direntries[i].sfd_ino = parentino;
				dchanged = 1;
			}
			assert(dotdotseen==0); /* due to duplicate checking */
			dotdotseen = 1;
		}
	}

	if (!dotseen) {
		if (dir_tryadd(direntries, ndirentries, ".", ino)==0) {
			setbadness(EXIT_RECOV);
			warnx("Directory /%s: No `.' entry (added)",
			      pathsofar);
			dchanged = 1;
		}
		else if (dir_tryadd(direntries, maxdirentries, ".", ino)==0) {
			setbadness(EXIT_RECOV);
			warnx("Directory /%s: No `.' entry (added)",
			      pathsofar);
			ndirentries++;
			dchanged = 1;
			sfi.sfi_size += sizeof(struct sfs_dir);
			ichanged = 1;
		}
		else {
			setbadness(EXIT_UNRECOV);
			warnx("Directory /%s: No `.' entry (NOT FIXED)",
			      pathsofar);
		}
	}

	if (!dotdotseen) {
		if (dir_tryadd(direntries, ndirentries, "..", parentino)==0) {
			setbadness(EXIT_RECOV);
			warnx("Directory /%s: No `..' entry (added)",
			      pathsofar);
			dchanged = 1;
		}
		else if (dir_tryadd(direntries, maxdirentries, "..",
				    parentino)==0) {
			setbadness(EXIT_RECOV);
			warnx("Directory /%s: No `..' entry (added)",
			      pathsofar);
			ndirentries++;
			dchanged = 1;
			sfi.sfi_size += sizeof(struct sfs_dir);
			ichanged = 1;
		}
		else {
			setbadness(EXIT_UNRECOV);
			warnx("Directory /%s: No `..' entry (NOT FIXED)",
			      pathsofar);
		}
	}

	subdircount=0;
	for (i=0; i<ndirentries; i++) {
		if (!strcmp(direntries[i].sfd_name, ".")) {
			/* nothing */
		}
		else if (!strcmp(direntries[i].sfd_name, "..")) {
			/* nothing */
		}
		else if (direntries[i].sfd_ino == SFS_NOINO) {
			/* nothing */
		}
		else {
			char path[strlen(pathsofar)+SFS_NAMELEN+1];
			struct sfs_inode subsfi;

			diskread(&subsfi, direntries[i].sfd_ino);
			swapinode(&subsfi);
			snprintf(path, sizeof(path), "%s/%s",
				 pathsofar, direntries[i].sfd_name);

			switch (subsfi.sfi_type) {
			    case SFS_TYPE_FILE:
				if (check_inode_blocks(direntries[i].sfd_ino,
						       &subsfi, 0)) {
					swapinode(&subsfi);
					diskwrite(&subsfi,
						  direntries[i].sfd_ino);
				}
				observe_filelink(direntries[i].sfd_ino);
				break;
			    case SFS_TYPE_DIR:
				if (check_dir(direntries[i].sfd_ino,
					      ino,
					      path)) {
					setbadness(EXIT_RECOV);
					warnx("Directory /%s: Crosslink to "
					      "other directory (removed)",
					      path);
					direntries[i].sfd_ino = SFS_NOINO;
					direntries[i].sfd_name[0] = 0;
					dchanged = 1;
				}
				else {
					subdircount++;
				}
				break;
			    default:
				setbadness(EXIT_RECOV);
				warnx("Object /%s: Invalid inode type "
				      "(removed)", path);
				direntries[i].sfd_ino = SFS_NOINO;
				direntries[i].sfd_name[0] = 0;
				dchanged = 1;
				break;
			}
		}
	}

	if (sfi.sfi_linkcount != subdircount+2) {
		setbadness(EXIT_RECOV);
		warnx("Directory /%s: Link count %lu should be %lu (fixed)",
		      pathsofar, (unsigned long) sfi.sfi_linkcount,
		      (unsigned long) subdircount+2);
		sfi.sfi_linkcount = subdircount+2;
		ichanged = 1;
	}

	if (dchanged) {
		dirwrite(&sfi, direntries, ndirentries);
	}

	if (ichanged) {
		swapinode(&sfi);
		diskwrite(&sfi, ino);
	}

	free(direntries);
	free(sortvector);

	return 0;
}
Beispiel #11
0
static
void
check_indirect_block(uint32_t ino, uint32_t *ientry, uint32_t *blockp,
		     uint32_t nblocks, uint32_t *badcountp,
		     int isdir, int indirection)
{
	uint32_t entries[SFS_DBPERIDB];
	uint32_t i, ct;

	if (*ientry !=0) {
		diskread(entries, *ientry);
		swapindir(entries);
		bitmap_mark(*ientry, B_IBLOCK, ino);
	}
	else {
		for (i=0; i<SFS_DBPERIDB; i++) {
			entries[i] = 0;
		}
	}

	if (indirection > 1) {
		for (i=0; i<SFS_DBPERIDB; i++) {
			check_indirect_block(ino, &entries[i],
					     blockp, nblocks,
					     badcountp,
					     isdir,
					     indirection-1);
		}
	}
	else {
		assert(indirection==1);

		for (i=0; i<SFS_DBPERIDB; i++) {
			if (*blockp < nblocks) {
				if (entries[i] != 0) {
					bitmap_mark(entries[i],
						    isdir ? B_DIRDATA : B_DATA,
						    ino);
				}
			}
			else {
				if (entries[i] != 0) {
					(*badcountp)++;
					bitmap_mark(entries[i],
						    isdir ? B_DIRDATA : B_DATA,
						    ino);
					entries[i] = 0;
				}
			}
			(*blockp)++;
		}
	}

	ct=0;
	for (i=ct=0; i<SFS_DBPERIDB; i++) {
		if (entries[i]!=0) ct++;
	}
	if (ct==0) {
		if (*ientry != 0) {
			(*badcountp)++;
			bitmap_mark(*ientry, B_TOFREE, 0);
			*ientry = 0;
		}
	}
	else {
		assert(*ientry != 0);
		if (*badcountp > 0) {
			swapindir(entries);
			diskwrite(entries, *ientry);
		}
	}
}
Beispiel #12
0
static
void
check_bitmap(void)
{
	uint8_t bits[SFS_BLOCKSIZE], *found, *tofree, tmp;
	uint32_t alloccount=0, freecount=0, i, j;
	int bchanged;

	for (i=0; i<bitblocks; i++) {
		diskread(bits, SFS_MAP_LOCATION+i);
		swapbits(bits);
		found = bitmapdata + i*SFS_BLOCKSIZE;
		tofree = tofreedata + i*SFS_BLOCKSIZE;
		bchanged = 0;

		for (j=0; j<SFS_BLOCKSIZE; j++) {
			/* we shouldn't have blocks marked both ways */
			assert((found[j] & tofree[j])==0);

			if (bits[j]==found[j]) {
				continue;
			}

			if (bits[j]==(found[j] | tofree[j])) {
				bits[j] = found[j];
				bchanged = 1;
				continue;
			}

			/* free the ones we're freeing */
			bits[j] &= ~tofree[j];

			/* are we short any? */
			if ((bits[j] & found[j]) != found[j]) {
				tmp = found[j] & ~bits[j];
				alloccount += countbits(tmp);
				if (tmp != 0) {
					reportbits(i, j, tmp, "free");
				}
			}

			/* do we have any extra? */
			if ((bits[j] & found[j]) != bits[j]) {
				tmp = bits[j] & ~found[j];
				freecount += countbits(tmp);
				if (tmp != 0) {
					reportbits(i, j, tmp, "allocated");
				}
			}

			bits[j] = found[j];
			bchanged = 1;
		}

		if (bchanged) {
			swapbits(bits);
			diskwrite(bits, SFS_MAP_LOCATION+i);
		}
	}

	if (alloccount > 0) {
		warnx("%lu blocks erroneously shown free in bitmap (fixed)",
		      (unsigned long) alloccount);
		setbadness(EXIT_RECOV);
	}
	if (freecount > 0) {
		warnx("%lu blocks erroneously shown used in bitmap (fixed)",
		      (unsigned long) freecount);
		setbadness(EXIT_RECOV);
	}
}
Beispiel #13
0
static Block*
ext2blockread(Fsys *fsys, u64int vbno)
{
	Block *bitb;
	Group g;
	uchar *bits;
	u32int bno, boff, bitblock;
	u64int bitpos;
	Ext2 *fs;

	fs = fsys->priv;
	if(vbno >= fs->nblock)
		return nil;
	bno = vbno;
	if(bno != vbno)
		return nil;

/*	
	if(bno < fs->firstblock)
		return diskread(fs->disk, fs->blocksize, (u64int)bno*fs->blocksize);
*/
	if(bno < fs->firstblock)
		return nil;

	bno -= fs->firstblock;
	if(ext2group(fs, bno/fs->blockspergroup, &g) < 0){
		if(debug)
			fprint(2, "loading group: %r...");
		return nil;
	}
/*
	if(debug)
		fprint(2, "ext2 group %d: bitblock=%ud inodebitblock=%ud inodeaddr=%ud freeblocks=%ud freeinodes=%ud useddirs=%ud\n",
			(int)(bno/fs->blockspergroup),
			g.bitblock,
			g.inodebitblock,
			g.inodeaddr,
			g.freeblockscount,
			g.freeinodescount,
			g.useddirscount);
	if(debug)
		fprint(2, "group %d bitblock=%d...", bno/fs->blockspergroup, g.bitblock);
*/
	bitblock = g.bitblock;
	bitpos = (u64int)bitblock*fs->blocksize;

	if((bitb = diskread(fs->disk, fs->blocksize, bitpos)) == nil){
		if(debug)
			fprint(2, "loading bitblock: %r...");
		return nil;
	}
	bits = bitb->data;
	boff = bno%fs->blockspergroup;
	if((bits[boff>>3] & (1<<(boff&7))) == 0){
		if(debug)
			fprint(2, "block %d not allocated in group %d: bitblock %d/%lld bits[%d] = %#x\n",
				boff, bno/fs->blockspergroup, 
				(int)bitblock,
				bitpos,
				boff>>3,
				bits[boff>>3]);
		blockput(bitb);
		return nil;
	}
	blockput(bitb);

	bno += fs->firstblock;
	return diskread(fs->disk, fs->blocksize, (u64int)bno*fs->blocksize);
}