Пример #1
0
/* returns nonzero if inode modified */
static
int
check_inode_blocks(uint32_t ino, struct sfs_inode *sfi, int isdir)
{
	uint32_t size, block, nblocks, badcount;

	badcount = 0;

	size = SFS_ROUNDUP(sfi->sfi_size, SFS_BLOCKSIZE);
	nblocks = size/SFS_BLOCKSIZE;

	for (block=0; block<SFS_NDIRECT; block++) {
		if (block < nblocks) {
			if (sfi->sfi_direct[block] != 0) {
				bitmap_mark(sfi->sfi_direct[block],
					    isdir ? B_DIRDATA : B_DATA, ino);
			}
		}
		else {
			if (sfi->sfi_direct[block] != 0) {
				badcount++;
				bitmap_mark(sfi->sfi_direct[block],
					    B_TOFREE, 0);
			}
		}
	}

#ifdef SFS_NIDIRECT
	for (i=0; i<SFS_NIDIRECT; i++) {
		check_indirect_block(ino, &sfi->sfi_indirect[i],
				     &block, nblocks, &badcount, isdir, 1);
	}
#else
	check_indirect_block(ino, &sfi->sfi_indirect,
			     &block, nblocks, &badcount, isdir, 1);
#endif

#ifdef SFS_NDIDIRECT
	for (i=0; i<SFS_NDIDIRECT; i++) {
		check_indirect_block(ino, &sfi->sfi_dindirect[i],
				     &block, nblocks, &badcount, isdir, 2);
	}
#else
#ifdef HAS_DIDIRECT
	check_indirect_block(ino, &sfi->sfi_dindirect,
			     &block, nblocks, &badcount, isdir, 2);
#endif
#endif

#ifdef SFS_NTIDIRECT
	for (i=0; i<SFS_NTIDIRECT; i++) {
		check_indirect_block(ino, &sfi->sfi_tindirect[i],
				     &block, nblocks, &badcount, isdir, 3);
	}
#else
#ifdef HAS_TIDIRECT
	check_indirect_block(ino, &sfi->sfi_tindirect,
			     &block, nblocks, &badcount, isdir, 3);
#endif
#endif

	if (badcount > 0) {
		warnx("Inode %lu: %lu blocks after EOF (freed)",
		     (unsigned long) ino, (unsigned long) badcount);
		setbadness(EXIT_RECOV);
		return 1;
	}

	return 0;
}
Пример #2
0
/*
 * Traverse an indirect block, recording blocks that are in use,
 * dropping any entries that are past EOF, and clearing any entries
 * that point outside the volume.
 *
 * XXX: this should be extended to be able to recover from crosslinked
 * blocks. Currently it just complains in bitmap.c and sets
 * EXIT_UNRECOV.
 *
 * The traversal is recursive; the state is maintained in IBS (as
 * described above). IENTRY is a pointer to the entry in the parent
 * indirect block (or the inode) that names the block we're currently
 * scanning. IECHANGEDP should be set to 1 if *IENTRY is changed.
 * INDIRECTION is the indirection level of this block (1, 2, or 3).
 */
static
void
check_indirect_block(struct ibstate *ibs, uint32_t *ientry, int *iechangedp,
		     int indirection)
{
	uint32_t entries[SFS_DBPERIDB];
	uint32_t i, ct;
	uint32_t coveredblocks;
	int localchanged = 0;
	int j;

	if (*ientry > 0 && *ientry < ibs->volblocks) {
		sfs_readindirect(*ientry, entries);
		bitmap_blockinuse(*ientry, B_IBLOCK, ibs->ino);
	}
	else {
		if (*ientry >= ibs->volblocks) {
			warnx("Inode %lu: indirect block pointer (level %d) "
			      "for block %lu outside of volume "
			      "(cleared)\n",
			      (unsigned long)ibs->ino, indirection,
			      (unsigned long)ibs->curfileblock);
			*ientry = 0;
			*iechangedp = 1;
		}
		coveredblocks = 1;
		for (j=0; j<indirection; j++) {
			coveredblocks *= SFS_DBPERIDB;
		}
		ibs->curfileblock += coveredblocks;
		return;
	}

	if (indirection > 1) {
		for (i=0; i<SFS_DBPERIDB; i++) {
			check_indirect_block(ibs, &entries[i], &localchanged,
					     indirection-1);
		}
	}
	else {
		assert(indirection==1);

		for (i=0; i<SFS_DBPERIDB; i++) {
			if (entries[i] >= ibs->volblocks) {
				warnx("Inode %lu: direct block pointer for "
				      "block %lu outside of volume "
				      "(cleared)\n",
				      (unsigned long)ibs->ino,
				      (unsigned long)ibs->curfileblock);
				entries[i] = 0;
				localchanged = 1;
			}
			else if (entries[i] != 0) {
				if (ibs->curfileblock < ibs->fileblocks) {
					bitmap_blockinuse(entries[i],
							  ibs->usagetype,
							  ibs->ino);
				}
				else {
					ibs->pasteofcount++;
					bitmap_blockfree(entries[i]);
					entries[i] = 0;
					localchanged = 1;
				}
			}
			ibs->curfileblock++;
		}
	}

	ct=0;
	for (i=ct=0; i<SFS_DBPERIDB; i++) {
		if (entries[i]!=0) ct++;
	}
	if (ct==0) {
		if (*ientry != 0) {
			/* this is not necessarily correct */
			/*ibs->pasteofcount++;*/
			*iechangedp = 1;
			bitmap_blockfree(*ientry);
			*ientry = 0;
		}
	}
	else {
		assert(*ientry != 0);
		if (localchanged) {
			sfs_writeindirect(*ientry, entries);
		}
	}
}
Пример #3
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);
		}
	}
}
Пример #4
0
/*
 * Check the blocks belonging to inode INO, whose inode has already
 * been loaded into SFI. ISDIR is a shortcut telling us if the inode
 * is a directory.
 *
 * Returns nonzero if SFI has been modified and needs to be written
 * back.
 */
static
int
check_inode_blocks(uint32_t ino, struct sfs_dinode *sfi, int isdir)
{
	struct ibstate ibs;
	uint32_t size, datablock;
	int changed;
	int i;

	size = SFS_ROUNDUP(sfi->sfi_size, SFS_BLOCKSIZE);

	ibs.ino = ino;
	/*ibs.curfileblock = 0;*/
	ibs.fileblocks = size/SFS_BLOCKSIZE;
	ibs.volblocks = sb_totalblocks();
	ibs.pasteofcount = 0;
	ibs.usagetype = isdir ? B_DIRDATA : B_DATA;

	changed = 0;

	for (ibs.curfileblock=0; ibs.curfileblock<NUM_D; ibs.curfileblock++) {
		datablock = GET_D(sfi, ibs.curfileblock);
		if (datablock >= ibs.volblocks) {
			warnx("Inode %lu: direct block pointer for "
			      "block %lu outside of volume "
			      "(cleared)\n",
			      (unsigned long)ibs.ino,
			      (unsigned long)ibs.curfileblock);
			SET_D(sfi, ibs.curfileblock) = 0;
			changed = 1;
		}
		else if (datablock > 0) {
			if (ibs.curfileblock < ibs.fileblocks) {
				bitmap_blockinuse(datablock, ibs.usagetype,
						  ibs.ino);
			}
			else {
				ibs.pasteofcount++;
				changed = 1;
				bitmap_blockfree(datablock);
				SET_D(sfi, ibs.curfileblock) = 0;
			}
		}
	}

	for (i=0; i<NUM_I; i++) {
		check_indirect_block(&ibs, &SET_I(sfi, i), &changed, 1);
	}
	for (i=0; i<NUM_II; i++) {
		check_indirect_block(&ibs, &SET_II(sfi, i), &changed, 2);
	}
	for (i=0; i<NUM_III; i++) {
		check_indirect_block(&ibs, &SET_III(sfi, i), &changed, 3);
	}

	if (ibs.pasteofcount > 0) {
		warnx("Inode %lu: %u blocks after EOF (freed)",
		     (unsigned long) ibs.ino, ibs.pasteofcount);
		setbadness(EXIT_RECOV);
	}

	return changed;
}