Exemplo n.º 1
0
void ext2fs_block_alloc_stats(ext2_filsys fs, blk_t blk, int inuse)
{
	int	group = ext2fs_group_of_blk(fs, blk);

#ifndef OMIT_COM_ERR
	if (blk >= fs->super->s_blocks_count) {
		com_err("ext2fs_block_alloc_stats", 0,
			"Illegal block number: %lu", (unsigned long) blk);
		return;
	}
#endif
	if (inuse > 0)
		ext2fs_mark_block_bitmap(fs->block_map, blk);
	else
		ext2fs_unmark_block_bitmap(fs->block_map, blk);
	fs->group_desc[group].bg_free_blocks_count -= inuse;
	fs->group_desc[group].bg_flags &= ~EXT2_BG_BLOCK_UNINIT;
	ext2fs_group_desc_csum_set(fs, group);

	fs->super->s_free_blocks_count -= inuse;
	ext2fs_mark_super_dirty(fs);
	ext2fs_mark_bb_dirty(fs);
	if (fs->block_alloc_stats)
		(fs->block_alloc_stats)(fs, (blk64_t) blk, inuse);
}
Exemplo n.º 2
0
errcode_t quota_write_inode(quota_ctx_t qctx, int qtype)
{
	int		retval = 0, i;
	dict_t		*dict;
	ext2_filsys	fs;
	struct quota_handle *h = NULL;
	int		fmt = QFMT_VFS_V1;

	if (!qctx)
		return 0;

	fs = qctx->fs;
	retval = ext2fs_get_mem(sizeof(struct quota_handle), &h);
	if (retval) {
		log_err("Unable to allocate quota handle", "");
		goto out;
	}

	ext2fs_read_bitmaps(fs);

	for (i = 0; i < MAXQUOTAS; i++) {
		if ((qtype != -1) && (i != qtype))
			continue;

		dict = qctx->quota_dict[i];
		if (!dict)
			continue;

		retval = quota_file_create(h, fs, i, fmt);
		if (retval < 0) {
			log_err("Cannot initialize io on quotafile", "");
			continue;
		}

		write_dquots(dict, h);
		retval = quota_file_close(h);
		if (retval < 0) {
			log_err("Cannot finish IO on new quotafile: %s",
				strerror(errno));
			if (h->qh_qf.e2_file)
				ext2fs_file_close(h->qh_qf.e2_file);
			quota_inode_truncate(fs, h->qh_qf.ino);
			continue;
		}

		/* Set quota inode numbers in superblock. */
		quota_set_sb_inum(fs, h->qh_qf.ino, i);
		ext2fs_mark_super_dirty(fs);
		ext2fs_mark_bb_dirty(fs);
		fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
	}

	ext2fs_write_bitmaps(fs);
out:
	if (h)
		ext2fs_free_mem(&h);
	return retval;
}
Exemplo n.º 3
0
static void check_block_bitmap_checksum(e2fsck_t ctx)
{
	struct problem_context	pctx;
	char		*buf;
	dgrp_t		i;
	int		nbytes;
	blk64_t		blk_itr;
	errcode_t	retval;

	if (!EXT2_HAS_RO_COMPAT_FEATURE(ctx->fs->super,
					EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
		return;

	/* If bitmap is dirty from being fixed, checksum will be corrected */
	if (ext2fs_test_bb_dirty(ctx->fs))
		return;

	nbytes = (size_t)(EXT2_CLUSTERS_PER_GROUP(ctx->fs->super) / 8);
	retval = ext2fs_get_memalign(ctx->fs->blocksize, ctx->fs->blocksize,
				     &buf);
	if (retval) {
		com_err(ctx->program_name, 0,
		    _("check_block_bitmap_checksum: Memory allocation error"));
		fatal_error(ctx, 0);
	}

	clear_problem_context(&pctx);
	for (i = 0; i < ctx->fs->group_desc_count; i++) {
		if (ext2fs_bg_flags_test(ctx->fs, i, EXT2_BG_BLOCK_UNINIT))
			continue;

		blk_itr = EXT2FS_B2C(ctx->fs,
				     ctx->fs->super->s_first_data_block) +
			  (i * (nbytes << 3));
		retval = ext2fs_get_block_bitmap_range2(ctx->fs->block_map,
							blk_itr, nbytes << 3,
							buf);
		if (retval)
			break;

		if (ext2fs_block_bitmap_csum_verify(ctx->fs, i, buf, nbytes))
			continue;
		pctx.group = i;
		if (!fix_problem(ctx, PR_5_BLOCK_BITMAP_CSUM_INVALID, &pctx))
			continue;

		/*
		 * Fixing one checksum will rewrite all of them.  The bitmap
		 * will be checked against the one we made during pass1 for
		 * discrepancies, and fixed if need be.
		 */
		ext2fs_mark_bb_dirty(ctx->fs);
		break;
	}

	ext2fs_free_mem(&buf);
}
Exemplo n.º 4
0
errcode_t write_quota_inode(quota_ctx_t qctx, int qtype)
{
	int		retval, i;
	unsigned long	qf_inums[MAXQUOTAS];
	struct dquot	*dquot;
	dict_t		*dict;
	ext2_filsys	fs;
	struct quota_handle *h;
	int		fmt = QFMT_VFS_V1;

	if (!qctx)
		return;

	fs = qctx->fs;
	h = smalloc(sizeof(struct quota_handle));
	ext2fs_read_bitmaps(fs);

	for (i = 0; i < MAXQUOTAS; i++) {
		if ((qtype != -1) && (i != qtype))
			continue;

		dict = qctx->quota_dict[i];
		if (!dict)
			continue;

		retval = new_io(h, fs, i, fmt);
		if (retval < 0) {
			log_err("Cannot initialize io on quotafile", "");
			continue;
		}

		write_dquots(dict, h);
		retval = end_io(h);
		if (retval < 0) {
			log_err("Cannot finish IO on new quotafile: %s",
				strerror(errno));
			if (h->qh_qf.e2_file)
				ext2fs_file_close(h->qh_qf.e2_file);
			truncate_quota_inode(fs, h->qh_qf.ino);
			continue;
		}

		/* Set quota inode numbers in superblock. */
		set_sb_quota_inum(fs, h->qh_qf.ino, i);
		ext2fs_mark_super_dirty(fs);
		ext2fs_mark_bb_dirty(fs);
		fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
	}

	ext2fs_write_bitmaps(fs);
out:
	free(h);
	return retval;
}
Exemplo n.º 5
0
void ext2fs_block_alloc_stats(ext2_filsys fs, blk_t blk, int inuse)
{
	int	group = ext2fs_group_of_blk(fs, blk);

	if (inuse > 0)
		ext2fs_mark_block_bitmap(fs->block_map, blk);
	else
		ext2fs_unmark_block_bitmap(fs->block_map, blk);
	fs->group_desc[group].bg_free_blocks_count -= inuse;
	fs->super->s_free_blocks_count -= inuse;
	ext2fs_mark_super_dirty(fs);
	ext2fs_mark_bb_dirty(fs);
}
Exemplo n.º 6
0
/*
 * Clear the uninit block bitmap flag if necessary
 */
static void clear_block_uninit(ext2_filsys fs, dgrp_t group)
{
	if (!ext2fs_has_group_desc_csum(fs) ||
	    !(ext2fs_bg_flags_test(fs, group, EXT2_BG_BLOCK_UNINIT)))
		return;

	/* uninit block bitmaps are now initialized in read_bitmaps() */

	ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT);
	ext2fs_group_desc_csum_set(fs, group);
	ext2fs_mark_super_dirty(fs);
	ext2fs_mark_bb_dirty(fs);
}
Exemplo n.º 7
0
/*
 * This fuction deallocates an inode
 */
static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
{
    ext2_filsys fs = ctx->fs;
    struct ext2_inode	inode;
    struct problem_context	pctx;

    ext2fs_icount_store(ctx->inode_link_info, ino, 0);
    e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode");
    inode.i_links_count = 0;
    inode.i_dtime = time(0);
    e2fsck_write_inode(ctx, ino, &inode, "deallocate_inode");
    clear_problem_context(&pctx);
    pctx.ino = ino;

    /*
     * Fix up the bitmaps...
     */
    e2fsck_read_bitmaps(ctx);
    ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
    ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
    if (ctx->inode_bad_map)
        ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
    ext2fs_unmark_inode_bitmap(fs->inode_map, ino);
    ext2fs_mark_ib_dirty(fs);

    if (!ext2fs_inode_has_valid_blocks(&inode))
        return;

    if (!LINUX_S_ISDIR(inode.i_mode) &&
            (inode.i_size_high || inode.i_size & 0x80000000UL))
        ctx->large_files--;

    if (inode.i_file_acl) {
        ext2fs_unmark_block_bitmap(ctx->block_found_map,
                                   inode.i_file_acl);
        ext2fs_unmark_block_bitmap(fs->block_map, inode.i_file_acl);
    }

    ext2fs_mark_bb_dirty(fs);
    pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
                                         deallocate_inode_block, ctx);
    if (pctx.errcode) {
        fix_problem(ctx, PR_2_DEALLOC_INODE, &pctx);
        ctx->flags |= E2F_FLAG_ABORT;
        return;
    }
}
Exemplo n.º 8
0
/*
 * Check for uninit block bitmaps and deal with them appropriately
 */
static void check_block_uninit(ext2_filsys fs, ext2fs_block_bitmap map,
			       dgrp_t group)
{
	blk_t		i;
	blk64_t		blk, super_blk, old_desc_blk, new_desc_blk;
	int		old_desc_blocks;

	if (!(EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
					 EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) ||
	    !(ext2fs_bg_flags_test(fs, group, EXT2_BG_BLOCK_UNINIT)))
		return;

	blk = (group * fs->super->s_blocks_per_group) +
		fs->super->s_first_data_block;

	ext2fs_super_and_bgd_loc2(fs, group, &super_blk,
				  &old_desc_blk, &new_desc_blk, 0);

	if (fs->super->s_feature_incompat &
	    EXT2_FEATURE_INCOMPAT_META_BG)
		old_desc_blocks = fs->super->s_first_meta_bg;
	else
		old_desc_blocks = fs->desc_blocks + fs->super->s_reserved_gdt_blocks;

	for (i=0; i < fs->super->s_blocks_per_group; i++, blk++)
		ext2fs_fast_unmark_block_bitmap2(map, blk);

	blk = (group * fs->super->s_blocks_per_group) +
		fs->super->s_first_data_block;
	for (i=0; i < fs->super->s_blocks_per_group; i++, blk++) {
		if ((blk == super_blk) ||
		    (old_desc_blk && old_desc_blocks &&
		     (blk >= old_desc_blk) &&
		     (blk < old_desc_blk + old_desc_blocks)) ||
		    (new_desc_blk && (blk == new_desc_blk)) ||
		    (blk == ext2fs_block_bitmap_loc(fs, group)) ||
		    (blk == ext2fs_inode_bitmap_loc(fs, group)) ||
		    (blk >= ext2fs_inode_table_loc(fs, group) &&
		     (blk < ext2fs_inode_table_loc(fs, group)
		      + fs->inode_blocks_per_group)))
			ext2fs_fast_mark_block_bitmap2(map, blk);
	}
	ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT);
	ext2fs_group_desc_csum_set(fs, group);
	ext2fs_mark_super_dirty(fs);
	ext2fs_mark_bb_dirty(fs);
}
Exemplo n.º 9
0
static void check_block_end(e2fsck_t ctx)
{
	ext2_filsys fs = ctx->fs;
	blk64_t	end, save_blocks_count, i;
	struct problem_context	pctx;

	clear_problem_context(&pctx);

	end = ext2fs_get_block_bitmap_start2(fs->block_map) +
		((blk64_t)EXT2_CLUSTERS_PER_GROUP(fs->super) * fs->group_desc_count) - 1;
	pctx.errcode = ext2fs_fudge_block_bitmap_end2(fs->block_map, end,
						     &save_blocks_count);
	if (pctx.errcode) {
		pctx.num = 3;
		fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
		ctx->flags |= E2F_FLAG_ABORT; /* fatal */
		return;
	}
	if (save_blocks_count == end)
		return;

	/* Protect loop from wrap-around if end is maxed */
	for (i = save_blocks_count + 1; i <= end && i > save_blocks_count; i++) {
		if (!ext2fs_test_block_bitmap2(fs->block_map,
					       EXT2FS_C2B(fs, i))) {
			if (fix_problem(ctx, PR_5_BLOCK_BMAP_PADDING, &pctx)) {
				for (; i <= end; i++)
					ext2fs_mark_block_bitmap2(fs->block_map,
							EXT2FS_C2B(fs, i));
				ext2fs_mark_bb_dirty(fs);
			} else
				ext2fs_unmark_valid(fs);
			break;
		}
	}

	pctx.errcode = ext2fs_fudge_block_bitmap_end2(fs->block_map,
						     save_blocks_count, 0);
	if (pctx.errcode) {
		pctx.num = 4;
		fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
		ctx->flags |= E2F_FLAG_ABORT; /* fatal */
		return;
	}
}
Exemplo n.º 10
0
errcode_t quota_write_inode(quota_ctx_t qctx, unsigned int qtype_bits)
{
	int		retval = 0;
	enum quota_type	qtype;
	dict_t		*dict;
	ext2_filsys	fs;
	struct quota_handle *h = NULL;
	int		fmt = QFMT_VFS_V1;

	if (!qctx)
		return 0;

	fs = qctx->fs;
	retval = ext2fs_get_mem(sizeof(struct quota_handle), &h);
	if (retval) {
		log_debug("Unable to allocate quota handle: %s",
			error_message(retval));
		goto out;
	}

	retval = ext2fs_read_bitmaps(fs);
	if (retval) {
		log_debug("Couldn't read bitmaps: %s", error_message(retval));
		goto out;
	}

	for (qtype = 0; qtype < MAXQUOTAS; qtype++) {
		if (((1 << qtype) & qtype_bits) == 0)
			continue;

		dict = qctx->quota_dict[qtype];
		if (!dict)
			continue;

		retval = quota_file_create(h, fs, qtype, fmt);
		if (retval) {
			log_debug("Cannot initialize io on quotafile: %s",
				  error_message(retval));
			goto out;
		}

		write_dquots(dict, h);
		retval = quota_file_close(qctx, h);
		if (retval) {
			log_debug("Cannot finish IO on new quotafile: %s",
				  strerror(errno));
			if (h->qh_qf.e2_file)
				ext2fs_file_close(h->qh_qf.e2_file);
			(void) quota_inode_truncate(fs, h->qh_qf.ino);
			goto out;
		}

		/* Set quota inode numbers in superblock. */
		quota_set_sb_inum(fs, h->qh_qf.ino, qtype);
		ext2fs_mark_super_dirty(fs);
		ext2fs_mark_bb_dirty(fs);
		fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
	}

	retval = ext2fs_write_bitmaps(fs);
	if (retval) {
		log_debug("Couldn't write bitmaps: %s", error_message(retval));
		goto out;
	}
out:
	if (h)
		ext2fs_free_mem(&h);
	return retval;
}
Exemplo n.º 11
0
/*
 * This makes sure the root inode is present; if not, we ask if the
 * user wants us to create it.  Not creating it is a fatal error.
 */
static void check_root(e2fsck_t ctx)
{
	ext2_filsys fs = ctx->fs;
	blk64_t			blk;
	struct ext2_inode	inode;
	char *			block;
	struct problem_context	pctx;

	clear_problem_context(&pctx);

	if (ext2fs_test_inode_bitmap2(ctx->inode_used_map, EXT2_ROOT_INO)) {
		/*
		 * If the root inode is not a directory, die here.  The
		 * user must have answered 'no' in pass1 when we
		 * offered to clear it.
		 */
		if (!(ext2fs_test_inode_bitmap2(ctx->inode_dir_map,
					       EXT2_ROOT_INO))) {
			fix_problem(ctx, PR_3_ROOT_NOT_DIR_ABORT, &pctx);
			ctx->flags |= E2F_FLAG_ABORT;
		}
		return;
	}

	if (!fix_problem(ctx, PR_3_NO_ROOT_INODE, &pctx)) {
		fix_problem(ctx, PR_3_NO_ROOT_INODE_ABORT, &pctx);
		ctx->flags |= E2F_FLAG_ABORT;
		return;
	}

	e2fsck_read_bitmaps(ctx);

	/*
	 * First, find a free block
	 */
	pctx.errcode = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk);
	if (pctx.errcode) {
		pctx.str = "ext2fs_new_block";
		fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
		ctx->flags |= E2F_FLAG_ABORT;
		return;
	}
	ext2fs_mark_block_bitmap2(ctx->block_found_map, blk);
	ext2fs_mark_block_bitmap2(fs->block_map, blk);
	ext2fs_mark_bb_dirty(fs);

	/*
	 * Now let's create the actual data block for the inode
	 */
	pctx.errcode = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO,
					    &block);
	if (pctx.errcode) {
		pctx.str = "ext2fs_new_dir_block";
		fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
		ctx->flags |= E2F_FLAG_ABORT;
		return;
	}

	pctx.errcode = ext2fs_write_dir_block4(fs, blk, block, 0,
					       EXT2_ROOT_INO);
	if (pctx.errcode) {
		pctx.str = "ext2fs_write_dir_block";
		fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
		ctx->flags |= E2F_FLAG_ABORT;
		return;
	}
	ext2fs_free_mem(&block);

	/*
	 * Set up the inode structure
	 */
	memset(&inode, 0, sizeof(inode));
	inode.i_mode = 040755;
	inode.i_size = fs->blocksize;
	inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now;
	inode.i_links_count = 2;
	ext2fs_iblk_set(fs, &inode, 1);
	inode.i_block[0] = blk;

	/*
	 * Write out the inode.
	 */
	pctx.errcode = ext2fs_write_new_inode(fs, EXT2_ROOT_INO, &inode);
	if (pctx.errcode) {
		pctx.str = "ext2fs_write_inode";
		fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
		ctx->flags |= E2F_FLAG_ABORT;
		return;
	}

	/*
	 * Miscellaneous bookkeeping...
	 */
	e2fsck_add_dir_info(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO);
	ext2fs_icount_store(ctx->inode_count, EXT2_ROOT_INO, 2);
	ext2fs_icount_store(ctx->inode_link_info, EXT2_ROOT_INO, 2);

	ext2fs_mark_inode_bitmap2(ctx->inode_used_map, EXT2_ROOT_INO);
	ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, EXT2_ROOT_INO);
	ext2fs_mark_inode_bitmap2(fs->inode_map, EXT2_ROOT_INO);
	ext2fs_mark_ib_dirty(fs);
}
Exemplo n.º 12
0
/*
 * allocate_dir_block --- this function allocates a new directory
 * 	block for a particular inode; this is done if a directory has
 * 	a "hole" in it, or if a directory has a illegal block number
 * 	that was zeroed out and now needs to be replaced.
 */
static int allocate_dir_block(e2fsck_t ctx,
                              struct ext2_db_entry *db,
                              char *buf, struct problem_context *pctx)
{
    ext2_filsys fs = ctx->fs;
    blk_t			blk;
    char			*block;
    struct ext2_inode	inode;

    if (fix_problem(ctx, PR_2_DIRECTORY_HOLE, pctx) == 0)
        return 1;

    /*
     * Read the inode and block bitmaps in; we'll be messing with
     * them.
     */
    e2fsck_read_bitmaps(ctx);

    /*
     * First, find a free block
     */
    pctx->errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
    if (pctx->errcode) {
        pctx->str = "ext2fs_new_block";
        fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
        return 1;
    }
    ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
    ext2fs_mark_block_bitmap(fs->block_map, blk);
    ext2fs_mark_bb_dirty(fs);

    /*
     * Now let's create the actual data block for the inode
     */
    if (db->blockcnt)
        pctx->errcode = ext2fs_new_dir_block(fs, 0, 0, &block);
    else
        pctx->errcode = ext2fs_new_dir_block(fs, db->ino,
                                             EXT2_ROOT_INO, &block);

    if (pctx->errcode) {
        pctx->str = "ext2fs_new_dir_block";
        fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
        return 1;
    }

    pctx->errcode = ext2fs_write_dir_block(fs, blk, block);
    ext2fs_free_mem((void **) &block);
    if (pctx->errcode) {
        pctx->str = "ext2fs_write_dir_block";
        fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
        return 1;
    }

    /*
     * Update the inode block count
     */
    e2fsck_read_inode(ctx, db->ino, &inode, "allocate_dir_block");
    inode.i_blocks += fs->blocksize / 512;
    if (inode.i_size < (db->blockcnt+1) * fs->blocksize)
        inode.i_size = (db->blockcnt+1) * fs->blocksize;
    e2fsck_write_inode(ctx, db->ino, &inode, "allocate_dir_block");

    /*
     * Finally, update the block pointers for the inode
     */
    db->blk = blk;
    pctx->errcode = ext2fs_block_iterate2(fs, db->ino, BLOCK_FLAG_HOLE,
                                          0, update_dir_block, db);
    if (pctx->errcode) {
        pctx->str = "ext2fs_block_iterate";
        fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
        return 1;
    }

    return 0;
}
Exemplo n.º 13
0
static void check_block_bitmaps(e2fsck_t ctx)
{
	ext2_filsys fs = ctx->fs;
	blk64_t	i;
	unsigned int	*free_array;
	int	group = 0;
	unsigned int	blocks = 0;
	blk64_t	free_blocks = 0;
	blk64_t first_free = ext2fs_blocks_count(fs->super);
	unsigned int	group_free = 0;
	int	actual, bitmap;
	struct problem_context	pctx;
	int	problem, save_problem, fixit, had_problem;
	errcode_t	retval;
	int		csum_flag;
	int		skip_group = 0;
	int	old_desc_blocks = 0;
	int	count = 0;
	int	cmp_block = 0;
	int	redo_flag = 0;
	blk64_t	super_blk, old_desc_blk, new_desc_blk;

	clear_problem_context(&pctx);
	free_array = (unsigned int *) e2fsck_allocate_memory(ctx,
	    fs->group_desc_count * sizeof(unsigned int), "free block count array");

	if ((B2C(fs->super->s_first_data_block) <
	     ext2fs_get_block_bitmap_start2(ctx->block_found_map)) ||
	    (B2C(ext2fs_blocks_count(fs->super)-1) >
	     ext2fs_get_block_bitmap_end2(ctx->block_found_map))) {
		pctx.num = 1;
		pctx.blk = B2C(fs->super->s_first_data_block);
		pctx.blk2 = B2C(ext2fs_blocks_count(fs->super) - 1);
		pctx.ino = ext2fs_get_block_bitmap_start2(ctx->block_found_map);
		pctx.ino2 = ext2fs_get_block_bitmap_end2(ctx->block_found_map);
		fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);

		ctx->flags |= E2F_FLAG_ABORT; /* fatal */
		goto errout;
	}

	if ((B2C(fs->super->s_first_data_block) <
	     ext2fs_get_block_bitmap_start2(fs->block_map)) ||
	    (B2C(ext2fs_blocks_count(fs->super)-1) >
	     ext2fs_get_block_bitmap_end2(fs->block_map))) {
		pctx.num = 2;
		pctx.blk = B2C(fs->super->s_first_data_block);
		pctx.blk2 = B2C(ext2fs_blocks_count(fs->super) - 1);
		pctx.ino = ext2fs_get_block_bitmap_start2(fs->block_map);
		pctx.ino2 = ext2fs_get_block_bitmap_end2(fs->block_map);
		fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);

		ctx->flags |= E2F_FLAG_ABORT; /* fatal */
		goto errout;
	}

	csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
					       EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
redo_counts:
	had_problem = 0;
	save_problem = 0;
	pctx.blk = pctx.blk2 = NO_BLK;
	if (csum_flag &&
	    (ext2fs_bg_flags_test(fs, group, EXT2_BG_BLOCK_UNINIT)))
		skip_group++;
	for (i = B2C(fs->super->s_first_data_block);
	     i < ext2fs_blocks_count(fs->super);
	     i += EXT2FS_CLUSTER_RATIO(fs)) {
		actual = ext2fs_fast_test_block_bitmap2(ctx->block_found_map, i);

		if (skip_group) {
			if ((B2C(i) - B2C(fs->super->s_first_data_block)) %
			    fs->super->s_clusters_per_group == 0) {
				super_blk = 0;
				old_desc_blk = 0;
				new_desc_blk = 0;
				ext2fs_super_and_bgd_loc2(fs, group, &super_blk,
					 &old_desc_blk, &new_desc_blk, 0);

				if (fs->super->s_feature_incompat &
						EXT2_FEATURE_INCOMPAT_META_BG)
					old_desc_blocks =
						fs->super->s_first_meta_bg;
				else
					old_desc_blocks = fs->desc_blocks +
					fs->super->s_reserved_gdt_blocks;

				count = 0;
				cmp_block = fs->super->s_clusters_per_group;
				if (group == (int)fs->group_desc_count - 1)
					cmp_block = EXT2FS_NUM_B2C(fs,
						    ext2fs_group_blocks_count(fs, group));
			}

			bitmap = 0;
			if (EQ_CLSTR(i, super_blk) ||
			    (old_desc_blk && old_desc_blocks &&
			     GE_CLSTR(i, old_desc_blk) &&
			     LE_CLSTR(i, old_desc_blk + old_desc_blocks-1)) ||
			    (new_desc_blk && EQ_CLSTR(i, new_desc_blk)) ||
			    EQ_CLSTR(i, ext2fs_block_bitmap_loc(fs, group)) ||
			    EQ_CLSTR(i, ext2fs_inode_bitmap_loc(fs, group)) ||
			    (GE_CLSTR(i, ext2fs_inode_table_loc(fs, group)) &&
			     LE_CLSTR(i, (ext2fs_inode_table_loc(fs, group) +
					  fs->inode_blocks_per_group - 1)))) {
				bitmap = 1;
				actual = (actual != 0);
				count++;
				cmp_block--;
			} else if ((EXT2FS_B2C(fs, i) - count -
				    EXT2FS_B2C(fs, fs->super->s_first_data_block)) %
				   fs->super->s_clusters_per_group == 0) {
				/*
				 * When the compare data blocks in block bitmap
				 * are 0, count the free block,
				 * skip the current block group.
				 */
				if (ext2fs_test_block_bitmap_range2(
					    ctx->block_found_map,
					    EXT2FS_B2C(fs, i),
					    cmp_block)) {
					/*
					 * -1 means to skip the current block
					 * group.
					 */
					blocks = fs->super->s_clusters_per_group - 1;
					group_free = cmp_block;
					free_blocks += cmp_block;
					/*
					 * The current block group's last block
					 * is set to i.
					 */
					i += EXT2FS_C2B(fs, cmp_block - 1);
					bitmap = 1;
					goto do_counts;
				}
			}
		} else if (redo_flag)
			bitmap = actual;
		else
			bitmap = ext2fs_fast_test_block_bitmap2(fs->block_map, i);

		if (!actual == !bitmap)
			goto do_counts;

		if (!actual && bitmap) {
			/*
			 * Block not used, but marked in use in the bitmap.
			 */
			problem = PR_5_BLOCK_UNUSED;
		} else {
			/*
			 * Block used, but not marked in use in the bitmap.
			 */
			problem = PR_5_BLOCK_USED;

			if (skip_group) {
				struct problem_context pctx2;
				pctx2.blk = i;
				pctx2.group = group;
				if (fix_problem(ctx, PR_5_BLOCK_UNINIT,&pctx2)){
					ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT);
					skip_group = 0;
				}
			}
		}
		if (pctx.blk == NO_BLK) {
			pctx.blk = pctx.blk2 = i;
			save_problem = problem;
		} else {
			if ((problem == save_problem) &&
			    (pctx.blk2 == i-1))
				pctx.blk2++;
			else {
				print_bitmap_problem(ctx, save_problem, &pctx);
				pctx.blk = pctx.blk2 = i;
				save_problem = problem;
			}
		}
		ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
		had_problem++;

		/*
		 * If there a problem we should turn off the discard so we
		 * do not compromise the filesystem.
		 */
		ctx->options &= ~E2F_OPT_DISCARD;

	do_counts:
		if (!bitmap) {
			group_free++;
			free_blocks++;
			if (first_free > i)
				first_free = i;
		} else if (i > first_free) {
			e2fsck_discard_blocks(ctx, first_free,
					      (i - first_free));
			first_free = ext2fs_blocks_count(fs->super);
		}
		blocks ++;
		if ((blocks == fs->super->s_clusters_per_group) ||
		    (EXT2FS_B2C(fs, i) ==
		     EXT2FS_B2C(fs, ext2fs_blocks_count(fs->super)-1))) {
			/*
			 * If the last block of this group is free, then we can
			 * discard it as well.
			 */
			if (!bitmap && i >= first_free)
				e2fsck_discard_blocks(ctx, first_free,
						      (i - first_free) + 1);
			first_free = ext2fs_blocks_count(fs->super);

			free_array[group] = group_free;
			group ++;
			blocks = 0;
			group_free = 0;
			skip_group = 0;
			if (ctx->progress)
				if ((ctx->progress)(ctx, 5, group,
						    fs->group_desc_count*2))
					goto errout;
			if (csum_flag &&
			    (i != ext2fs_blocks_count(fs->super)-1) &&
			    ext2fs_bg_flags_test(fs, group, 
						EXT2_BG_BLOCK_UNINIT))
				skip_group++;
		}
	}
	if (pctx.blk != NO_BLK)
		print_bitmap_problem(ctx, save_problem, &pctx);
	if (had_problem)
		fixit = end_problem_latch(ctx, PR_LATCH_BBITMAP);
	else
		fixit = -1;
	ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;

	if (fixit == 1) {
		ext2fs_free_block_bitmap(fs->block_map);
		retval = ext2fs_copy_bitmap(ctx->block_found_map,
						  &fs->block_map);
		if (retval) {
			clear_problem_context(&pctx);
			fix_problem(ctx, PR_5_COPY_BBITMAP_ERROR, &pctx);
			ctx->flags |= E2F_FLAG_ABORT;
			goto errout;
		}
		ext2fs_set_bitmap_padding(fs->block_map);
		ext2fs_mark_bb_dirty(fs);

		/* Redo the counts */
		blocks = 0; free_blocks = 0; group_free = 0; group = 0;
		memset(free_array, 0, fs->group_desc_count * sizeof(int));
		redo_flag++;
		goto redo_counts;
	} else if (fixit == 0)
		ext2fs_unmark_valid(fs);

	for (i = 0; i < fs->group_desc_count; i++) {
		if (free_array[i] != ext2fs_bg_free_blocks_count(fs, i)) {
			pctx.group = i;
			pctx.blk = ext2fs_bg_free_blocks_count(fs, i);
			pctx.blk2 = free_array[i];

			if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT_GROUP,
					&pctx)) {
				ext2fs_bg_free_blocks_count_set(fs, i, free_array[i]);
				ext2fs_mark_super_dirty(fs);
			} else
				ext2fs_unmark_valid(fs);
		}
	}
	free_blocks = EXT2FS_C2B(fs, free_blocks);
	if (free_blocks != ext2fs_free_blocks_count(fs->super)) {
		pctx.group = 0;
		pctx.blk = ext2fs_free_blocks_count(fs->super);
		pctx.blk2 = free_blocks;

		if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT, &pctx)) {
			ext2fs_free_blocks_count_set(fs->super, free_blocks);
			ext2fs_mark_super_dirty(fs);
		}
	}
errout:
	ext2fs_free_mem(&free_array);
}
Exemplo n.º 14
0
errcode_t ext2fs_initialize(const char *name, int flags,
                            struct ext2_super_block *param,
                            io_manager manager, ext2_filsys *ret_fs)
{
    ext2_filsys	fs;
    errcode_t	retval;
    struct ext2_super_block *super;
    int		frags_per_block;
    unsigned int	rem;
    unsigned int	overhead = 0;
    unsigned int	ipg;
    dgrp_t		i;
    blk_t		numblocks;
    int		rsv_gdt;
    int		io_flags;
    char		*buf;
    char		c;

    if (!param || !param->s_blocks_count)
        return EXT2_ET_INVALID_ARGUMENT;

    retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs);
    if (retval)
        return retval;

    memset(fs, 0, sizeof(struct struct_ext2_filsys));
    fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS;
    fs->flags = flags | EXT2_FLAG_RW;
    fs->umask = 022;
#ifdef WORDS_BIGENDIAN
    fs->flags |= EXT2_FLAG_SWAP_BYTES;
#endif
    io_flags = IO_FLAG_RW;
    if (flags & EXT2_FLAG_EXCLUSIVE)
        io_flags |= IO_FLAG_EXCLUSIVE;
    retval = manager->open(name, io_flags, &fs->io);
    if (retval)
        goto cleanup;
    fs->image_io = fs->io;
    fs->io->app_data = fs;
    retval = ext2fs_get_mem(strlen(name)+1, &fs->device_name);
    if (retval)
        goto cleanup;

    strcpy(fs->device_name, name);
    retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &super);
    if (retval)
        goto cleanup;
    fs->super = super;

    memset(super, 0, SUPERBLOCK_SIZE);

#define set_field(field, default) (super->field = param->field ? \
				   param->field : (default))

    super->s_magic = EXT2_SUPER_MAGIC;
    super->s_state = EXT2_VALID_FS;

    set_field(s_log_block_size, 0);	/* default blocksize: 1024 bytes */
    set_field(s_log_frag_size, 0); /* default fragsize: 1024 bytes */
    set_field(s_first_data_block, super->s_log_block_size ? 0 : 1);
    set_field(s_max_mnt_count, EXT2_DFL_MAX_MNT_COUNT);
    set_field(s_errors, EXT2_ERRORS_DEFAULT);
    set_field(s_feature_compat, 0);
    set_field(s_feature_incompat, 0);
    set_field(s_feature_ro_compat, 0);
    set_field(s_first_meta_bg, 0);
    if (super->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) {
        retval = EXT2_ET_UNSUPP_FEATURE;
        goto cleanup;
    }
    if (super->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) {
        retval = EXT2_ET_RO_UNSUPP_FEATURE;
        goto cleanup;
    }

    set_field(s_rev_level, EXT2_GOOD_OLD_REV);
    if (super->s_rev_level >= EXT2_DYNAMIC_REV) {
        set_field(s_first_ino, EXT2_GOOD_OLD_FIRST_INO);
        set_field(s_inode_size, EXT2_GOOD_OLD_INODE_SIZE);
    }

    set_field(s_checkinterval, EXT2_DFL_CHECKINTERVAL);
    super->s_mkfs_time = super->s_lastcheck = fs->now ? fs->now : time(NULL);

    super->s_creator_os = CREATOR_OS;

    fs->blocksize = EXT2_BLOCK_SIZE(super);
    fs->fragsize = EXT2_FRAG_SIZE(super);
    frags_per_block = fs->blocksize / fs->fragsize;

    /* default: (fs->blocksize*8) blocks/group, up to 2^16 (GDT limit) */
    set_field(s_blocks_per_group, fs->blocksize * 8);
    if (super->s_blocks_per_group > EXT2_MAX_BLOCKS_PER_GROUP(super))
        super->s_blocks_per_group = EXT2_MAX_BLOCKS_PER_GROUP(super);
    super->s_frags_per_group = super->s_blocks_per_group * frags_per_block;

    super->s_blocks_count = param->s_blocks_count;
    super->s_r_blocks_count = param->s_r_blocks_count;
    if (super->s_r_blocks_count >= param->s_blocks_count) {
        retval = EXT2_ET_INVALID_ARGUMENT;
        goto cleanup;
    }

    /*
     * If we're creating an external journal device, we don't need
     * to bother with the rest.
     */
    if (super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
        fs->group_desc_count = 0;
        ext2fs_mark_super_dirty(fs);
        *ret_fs = fs;
        return 0;
    }

retry:
    fs->group_desc_count = ext2fs_div_ceil(super->s_blocks_count -
                                           super->s_first_data_block,
                                           EXT2_BLOCKS_PER_GROUP(super));
    if (fs->group_desc_count == 0) {
        retval = EXT2_ET_TOOSMALL;
        goto cleanup;
    }
    fs->desc_blocks = ext2fs_div_ceil(fs->group_desc_count,
                                      EXT2_DESC_PER_BLOCK(super));

    i = fs->blocksize >= 4096 ? 1 : 4096 / fs->blocksize;
    set_field(s_inodes_count, super->s_blocks_count / i);

    /*
     * Make sure we have at least EXT2_FIRST_INO + 1 inodes, so
     * that we have enough inodes for the filesystem(!)
     */
    if (super->s_inodes_count < EXT2_FIRST_INODE(super)+1)
        super->s_inodes_count = EXT2_FIRST_INODE(super)+1;

    /*
     * There should be at least as many inodes as the user
     * requested.  Figure out how many inodes per group that
     * should be.  But make sure that we don't allocate more than
     * one bitmap's worth of inodes each group.
     */
    ipg = ext2fs_div_ceil(super->s_inodes_count, fs->group_desc_count);
    if (ipg > fs->blocksize * 8) {
        if (super->s_blocks_per_group >= 256) {
            /* Try again with slightly different parameters */
            super->s_blocks_per_group -= 8;
            super->s_blocks_count = param->s_blocks_count;
            super->s_frags_per_group = super->s_blocks_per_group *
                                       frags_per_block;
            goto retry;
        } else
            return EXT2_ET_TOO_MANY_INODES;
    }

    if (ipg > (unsigned) EXT2_MAX_INODES_PER_GROUP(super))
        ipg = EXT2_MAX_INODES_PER_GROUP(super);

ipg_retry:
    super->s_inodes_per_group = ipg;

    /*
     * Make sure the number of inodes per group completely fills
     * the inode table blocks in the descriptor.  If not, add some
     * additional inodes/group.  Waste not, want not...
     */
    fs->inode_blocks_per_group = (((super->s_inodes_per_group *
                                    EXT2_INODE_SIZE(super)) +
                                   EXT2_BLOCK_SIZE(super) - 1) /
                                  EXT2_BLOCK_SIZE(super));
    super->s_inodes_per_group = ((fs->inode_blocks_per_group *
                                  EXT2_BLOCK_SIZE(super)) /
                                 EXT2_INODE_SIZE(super));
    /*
     * Finally, make sure the number of inodes per group is a
     * multiple of 8.  This is needed to simplify the bitmap
     * splicing code.
     */
    super->s_inodes_per_group &= ~7;
    fs->inode_blocks_per_group = (((super->s_inodes_per_group *
                                    EXT2_INODE_SIZE(super)) +
                                   EXT2_BLOCK_SIZE(super) - 1) /
                                  EXT2_BLOCK_SIZE(super));

    /*
     * adjust inode count to reflect the adjusted inodes_per_group
     */
    if ((__u64)super->s_inodes_per_group * fs->group_desc_count > ~0U) {
        ipg--;
        goto ipg_retry;
    }
    super->s_inodes_count = super->s_inodes_per_group *
                            fs->group_desc_count;
    super->s_free_inodes_count = super->s_inodes_count;

    /*
     * check the number of reserved group descriptor table blocks
     */
    if (super->s_feature_compat & EXT2_FEATURE_COMPAT_RESIZE_INODE)
        rsv_gdt = calc_reserved_gdt_blocks(fs);
    else
        rsv_gdt = 0;
    set_field(s_reserved_gdt_blocks, rsv_gdt);
    if (super->s_reserved_gdt_blocks > EXT2_ADDR_PER_BLOCK(super)) {
        retval = EXT2_ET_RES_GDT_BLOCKS;
        goto cleanup;
    }

    /*
     * Overhead is the number of bookkeeping blocks per group.  It
     * includes the superblock backup, the group descriptor
     * backups, the inode bitmap, the block bitmap, and the inode
     * table.
     */

    overhead = (int) (2 + fs->inode_blocks_per_group);

    if (ext2fs_bg_has_super(fs, fs->group_desc_count - 1))
        overhead += 1 + fs->desc_blocks + super->s_reserved_gdt_blocks;

    /* This can only happen if the user requested too many inodes */
    if (overhead > super->s_blocks_per_group)
        return EXT2_ET_TOO_MANY_INODES;

    /*
     * See if the last group is big enough to support the
     * necessary data structures.  If not, we need to get rid of
     * it.
     */
    rem = ((super->s_blocks_count - super->s_first_data_block) %
           super->s_blocks_per_group);
    if ((fs->group_desc_count == 1) && rem && (rem < overhead))
        return EXT2_ET_TOOSMALL;
    if (rem && (rem < overhead+50)) {
        super->s_blocks_count -= rem;
        goto retry;
    }

    /*
     * At this point we know how big the filesystem will be.  So
     * we can do any and all allocations that depend on the block
     * count.
     */

    retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf);
    if (retval)
        goto cleanup;

    sprintf(buf, "block bitmap for %s", fs->device_name);
    retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map);
    if (retval)
        goto cleanup;

    sprintf(buf, "inode bitmap for %s", fs->device_name);
    retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map);
    if (retval)
        goto cleanup;

    ext2fs_free_mem(&buf);

    retval = ext2fs_get_mem((size_t) fs->desc_blocks * fs->blocksize,
                            &fs->group_desc);
    if (retval)
        goto cleanup;

    memset(fs->group_desc, 0, (size_t) fs->desc_blocks * fs->blocksize);

    /*
     * Reserve the superblock and group descriptors for each
     * group, and fill in the correct group statistics for group.
     * Note that although the block bitmap, inode bitmap, and
     * inode table have not been allocated (and in fact won't be
     * by this routine), they are accounted for nevertheless.
     */
    super->s_free_blocks_count = 0;
    for (i = 0; i < fs->group_desc_count; i++) {
        numblocks = ext2fs_reserve_super_and_bgd(fs, i, fs->block_map);

        super->s_free_blocks_count += numblocks;
        fs->group_desc[i].bg_free_blocks_count = numblocks;
        fs->group_desc[i].bg_free_inodes_count =
            fs->super->s_inodes_per_group;
        fs->group_desc[i].bg_used_dirs_count = 0;
    }

    c = (char) 255;
    if (((int) c) == -1) {
        super->s_flags |= EXT2_FLAGS_SIGNED_HASH;
    } else {
        super->s_flags |= EXT2_FLAGS_UNSIGNED_HASH;
    }

    ext2fs_mark_super_dirty(fs);
    ext2fs_mark_bb_dirty(fs);
    ext2fs_mark_ib_dirty(fs);

    io_channel_set_blksize(fs->io, fs->blocksize);

    *ret_fs = fs;
    return 0;
cleanup:
    ext2fs_free(fs);
    return retval;
}
Exemplo n.º 15
0
static void check_block_bitmaps(e2fsck_t ctx)
{
	ext2_filsys fs = ctx->fs;
	blk64_t	i;
	unsigned int	*free_array;
	dgrp_t		g, group = 0;
	unsigned int	blocks = 0;
	blk64_t	free_blocks = 0;
	blk64_t first_free = ext2fs_blocks_count(fs->super);
	unsigned int	group_free = 0;
	int	actual, bitmap;
	struct problem_context	pctx;
	problem_t	problem, save_problem;
	int		fixit, had_problem;
	errcode_t	retval;
	int	old_desc_blocks = 0;
	int	count = 0;
	int	cmp_block = 0;
	int	redo_flag = 0;
	blk64_t	super_blk, old_desc_blk, new_desc_blk;
	char *actual_buf, *bitmap_buf;

	actual_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize,
						     "actual bitmap buffer");
	bitmap_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize,
						     "bitmap block buffer");

	clear_problem_context(&pctx);
	free_array = (unsigned int *) e2fsck_allocate_memory(ctx,
	    fs->group_desc_count * sizeof(unsigned int), "free block count array");

	if ((B2C(fs->super->s_first_data_block) <
	     ext2fs_get_block_bitmap_start2(ctx->block_found_map)) ||
	    (B2C(ext2fs_blocks_count(fs->super)-1) >
	     ext2fs_get_block_bitmap_end2(ctx->block_found_map))) {
		pctx.num = 1;
		pctx.blk = B2C(fs->super->s_first_data_block);
		pctx.blk2 = B2C(ext2fs_blocks_count(fs->super) - 1);
		pctx.ino = ext2fs_get_block_bitmap_start2(ctx->block_found_map);
		pctx.ino2 = ext2fs_get_block_bitmap_end2(ctx->block_found_map);
		fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);

		ctx->flags |= E2F_FLAG_ABORT; /* fatal */
		goto errout;
	}

	if ((B2C(fs->super->s_first_data_block) <
	     ext2fs_get_block_bitmap_start2(fs->block_map)) ||
	    (B2C(ext2fs_blocks_count(fs->super)-1) >
	     ext2fs_get_block_bitmap_end2(fs->block_map))) {
		pctx.num = 2;
		pctx.blk = B2C(fs->super->s_first_data_block);
		pctx.blk2 = B2C(ext2fs_blocks_count(fs->super) - 1);
		pctx.ino = ext2fs_get_block_bitmap_start2(fs->block_map);
		pctx.ino2 = ext2fs_get_block_bitmap_end2(fs->block_map);
		fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);

		ctx->flags |= E2F_FLAG_ABORT; /* fatal */
		goto errout;
	}

redo_counts:
	had_problem = 0;
	save_problem = 0;
	pctx.blk = pctx.blk2 = NO_BLK;
	for (i = B2C(fs->super->s_first_data_block);
	     i < ext2fs_blocks_count(fs->super);
	     i += EXT2FS_CLUSTER_RATIO(fs)) {
		int first_block_in_bg = (B2C(i) -
					 B2C(fs->super->s_first_data_block)) %
			fs->super->s_clusters_per_group == 0;
		int n, nbytes = fs->super->s_clusters_per_group / 8;

		actual = ext2fs_fast_test_block_bitmap2(ctx->block_found_map, i);

		/*
		 * Try to optimize pass5 by extracting a bitmap block
		 * as expected from what we have on disk, and then
		 * comparing the two.  If they are identical, then
		 * update the free block counts and go on to the next
		 * block group.  This is much faster than doing the
		 * individual bit-by-bit comparison.  The one downside
		 * is that this doesn't work if we are asking e2fsck
		 * to do a discard operation.
		 */
		if (!first_block_in_bg ||
		    (group == (int)fs->group_desc_count - 1) ||
		    (ctx->options & E2F_OPT_DISCARD))
			goto no_optimize;

		retval = ext2fs_get_block_bitmap_range2(ctx->block_found_map,
				B2C(i), fs->super->s_clusters_per_group,
				actual_buf);
		if (retval)
			goto no_optimize;
		retval = ext2fs_get_block_bitmap_range2(fs->block_map,
				B2C(i), fs->super->s_clusters_per_group,
				bitmap_buf);
		if (retval)
			goto no_optimize;
		if (memcmp(actual_buf, bitmap_buf, nbytes) != 0)
			goto no_optimize;
		n = ext2fs_bitcount(actual_buf, nbytes);
		group_free = fs->super->s_clusters_per_group - n;
		free_blocks += group_free;
		i += EXT2FS_C2B(fs, fs->super->s_clusters_per_group - 1);
		goto next_group;
	no_optimize:

		if (redo_flag)
			bitmap = actual;
		else
			bitmap = ext2fs_fast_test_block_bitmap2(fs->block_map, i);

		if (!actual == !bitmap)
			goto do_counts;

		if (!actual && bitmap) {
			/*
			 * Block not used, but marked in use in the bitmap.
			 */
			problem = PR_5_BLOCK_UNUSED;
		} else {
			/*
			 * Block used, but not marked in use in the bitmap.
			 */
			problem = PR_5_BLOCK_USED;

			if (ext2fs_bg_flags_test(fs, group,
						 EXT2_BG_BLOCK_UNINIT)) {
				struct problem_context pctx2;
				pctx2.blk = i;
				pctx2.group = group;
				if (fix_problem(ctx, PR_5_BLOCK_UNINIT,
						&pctx2))
					ext2fs_bg_flags_clear(fs, group,
							EXT2_BG_BLOCK_UNINIT);
			}
		}
		if (pctx.blk == NO_BLK) {
			pctx.blk = pctx.blk2 = i;
			save_problem = problem;
		} else {
			if ((problem == save_problem) &&
			    (pctx.blk2 == i - EXT2FS_CLUSTER_RATIO(fs)))
				pctx.blk2 += EXT2FS_CLUSTER_RATIO(fs);
			else {
				print_bitmap_problem(ctx, save_problem, &pctx);
				pctx.blk = pctx.blk2 = i;
				save_problem = problem;
			}
		}
		ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
		had_problem++;

		/*
		 * If there a problem we should turn off the discard so we
		 * do not compromise the filesystem.
		 */
		ctx->options &= ~E2F_OPT_DISCARD;

	do_counts:
		if (!bitmap) {
			group_free++;
			free_blocks++;
			if (first_free > i)
				first_free = i;
		} else if (i > first_free) {
			e2fsck_discard_blocks(ctx, first_free,
					      (i - first_free));
			first_free = ext2fs_blocks_count(fs->super);
		}
		blocks ++;
		if ((blocks == fs->super->s_clusters_per_group) ||
		    (EXT2FS_B2C(fs, i) ==
		     EXT2FS_B2C(fs, ext2fs_blocks_count(fs->super)-1))) {
			/*
			 * If the last block of this group is free, then we can
			 * discard it as well.
			 */
			if (!bitmap && i >= first_free)
				e2fsck_discard_blocks(ctx, first_free,
						      (i - first_free) + 1);
		next_group:
			first_free = ext2fs_blocks_count(fs->super);

			free_array[group] = group_free;
			group ++;
			blocks = 0;
			group_free = 0;
			if (ctx->progress)
				if ((ctx->progress)(ctx, 5, group,
						    fs->group_desc_count*2))
					goto errout;
		}
	}
	if (pctx.blk != NO_BLK)
		print_bitmap_problem(ctx, save_problem, &pctx);
	if (had_problem)
		fixit = end_problem_latch(ctx, PR_LATCH_BBITMAP);
	else
		fixit = -1;
	ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;

	if (fixit == 1) {
		ext2fs_free_block_bitmap(fs->block_map);
		retval = ext2fs_copy_bitmap(ctx->block_found_map,
						  &fs->block_map);
		if (retval) {
			clear_problem_context(&pctx);
			fix_problem(ctx, PR_5_COPY_BBITMAP_ERROR, &pctx);
			ctx->flags |= E2F_FLAG_ABORT;
			goto errout;
		}
		ext2fs_set_bitmap_padding(fs->block_map);
		ext2fs_mark_bb_dirty(fs);

		/* Redo the counts */
		blocks = 0; free_blocks = 0; group_free = 0; group = 0;
		memset(free_array, 0, fs->group_desc_count * sizeof(int));
		redo_flag++;
		goto redo_counts;
	} else if (fixit == 0)
		ext2fs_unmark_valid(fs);

	for (g = 0; g < fs->group_desc_count; g++) {
		if (free_array[g] != ext2fs_bg_free_blocks_count(fs, g)) {
			pctx.group = g;
			pctx.blk = ext2fs_bg_free_blocks_count(fs, g);
			pctx.blk2 = free_array[g];

			if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT_GROUP,
					&pctx)) {
				ext2fs_bg_free_blocks_count_set(fs, g, free_array[g]);
				ext2fs_mark_super_dirty(fs);
			} else
				ext2fs_unmark_valid(fs);
		}
	}
	free_blocks = EXT2FS_C2B(fs, free_blocks);
	if (free_blocks != ext2fs_free_blocks_count(fs->super)) {
		pctx.group = 0;
		pctx.blk = ext2fs_free_blocks_count(fs->super);
		pctx.blk2 = free_blocks;

		if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT, &pctx)) {
			ext2fs_free_blocks_count_set(fs->super, free_blocks);
			ext2fs_mark_super_dirty(fs);
		}
	}
errout:
	ext2fs_free_mem(&free_array);
	ext2fs_free_mem(&actual_buf);
	ext2fs_free_mem(&bitmap_buf);
}
Exemplo n.º 16
0
errcode_t ext2fs_initialize(const char *name, int flags,
			    struct ext2_super_block *param,
			    io_manager manager, ext2_filsys *ret_fs)
{
	ext2_filsys	fs;
	errcode_t	retval;
	struct ext2_super_block *super;
	unsigned int	rem;
	unsigned int	overhead = 0;
	unsigned int	ipg;
	dgrp_t		i;
	blk64_t		free_blocks;
	blk_t		numblocks;
	int		rsv_gdt;
	int		csum_flag;
	int		bigalloc_flag;
	int		io_flags;
	unsigned	reserved_inos;
	char		*buf = 0;
	char		c;
	double		reserved_ratio;

	if (!param || !ext2fs_blocks_count(param))
		return EXT2_ET_INVALID_ARGUMENT;

	retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs);
	if (retval)
		return retval;

	memset(fs, 0, sizeof(struct struct_ext2_filsys));
	fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS;
	fs->flags = flags | EXT2_FLAG_RW;
	fs->umask = 022;
	fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE;
#ifdef WORDS_BIGENDIAN
	fs->flags |= EXT2_FLAG_SWAP_BYTES;
#endif
	io_flags = IO_FLAG_RW;
	if (flags & EXT2_FLAG_EXCLUSIVE)
		io_flags |= IO_FLAG_EXCLUSIVE;
	if (flags & EXT2_FLAG_DIRECT_IO)
		io_flags |= IO_FLAG_DIRECT_IO;
	retval = manager->open(name, io_flags, &fs->io);
	if (retval)
		goto cleanup;
	fs->image_io = fs->io;
	fs->io->app_data = fs;
	retval = ext2fs_get_mem(strlen(name)+1, &fs->device_name);
	if (retval)
		goto cleanup;

	strcpy(fs->device_name, name);
	retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &super);
	if (retval)
		goto cleanup;
	fs->super = super;

	memset(super, 0, SUPERBLOCK_SIZE);

#define set_field(field, default) (super->field = param->field ? \
				   param->field : (default))
#define assign_field(field)	(super->field = param->field)

	super->s_magic = EXT2_SUPER_MAGIC;
	super->s_state = EXT2_VALID_FS;

	bigalloc_flag = EXT2_HAS_RO_COMPAT_FEATURE(param,
				   EXT4_FEATURE_RO_COMPAT_BIGALLOC);

	assign_field(s_log_block_size);

	if (bigalloc_flag) {
		set_field(s_log_cluster_size, super->s_log_block_size+4);
		if (super->s_log_block_size > super->s_log_cluster_size) {
			retval = EXT2_ET_INVALID_ARGUMENT;
			goto cleanup;
		}
	} else
		super->s_log_cluster_size = super->s_log_block_size;

	set_field(s_first_data_block, super->s_log_cluster_size ? 0 : 1);
	set_field(s_max_mnt_count, 0);
	set_field(s_errors, EXT2_ERRORS_DEFAULT);
	set_field(s_feature_compat, 0);
	set_field(s_feature_incompat, 0);
	set_field(s_feature_ro_compat, 0);
	set_field(s_default_mount_opts, 0);
	set_field(s_first_meta_bg, 0);
	set_field(s_raid_stride, 0);		/* default stride size: 0 */
	set_field(s_raid_stripe_width, 0);	/* default stripe width: 0 */
	set_field(s_log_groups_per_flex, 0);
	set_field(s_flags, 0);
	assign_field(s_backup_bgs[0]);
	assign_field(s_backup_bgs[1]);
	if (super->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) {
		retval = EXT2_ET_UNSUPP_FEATURE;
		goto cleanup;
	}
	if (super->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) {
		retval = EXT2_ET_RO_UNSUPP_FEATURE;
		goto cleanup;
	}

	set_field(s_rev_level, EXT2_GOOD_OLD_REV);
	if (super->s_rev_level >= EXT2_DYNAMIC_REV) {
		set_field(s_first_ino, EXT2_GOOD_OLD_FIRST_INO);
		set_field(s_inode_size, EXT2_GOOD_OLD_INODE_SIZE);
		if (super->s_inode_size >= sizeof(struct ext2_inode_large)) {
			int extra_isize = sizeof(struct ext2_inode_large) -
				EXT2_GOOD_OLD_INODE_SIZE;
			set_field(s_min_extra_isize, extra_isize);
			set_field(s_want_extra_isize, extra_isize);
		}
	} else {
		super->s_first_ino = EXT2_GOOD_OLD_FIRST_INO;
		super->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;
	}

	set_field(s_checkinterval, 0);
	super->s_mkfs_time = super->s_lastcheck = fs->now ? fs->now : time(NULL);

	super->s_creator_os = CREATOR_OS;

	fs->fragsize = fs->blocksize = EXT2_BLOCK_SIZE(super);
	fs->cluster_ratio_bits = super->s_log_cluster_size -
		super->s_log_block_size;

	if (bigalloc_flag) {
		unsigned long long bpg;

		if (param->s_blocks_per_group &&
		    param->s_clusters_per_group &&
		    ((param->s_clusters_per_group * EXT2FS_CLUSTER_RATIO(fs)) !=
		     param->s_blocks_per_group)) {
			retval = EXT2_ET_INVALID_ARGUMENT;
			goto cleanup;
		}
		if (param->s_clusters_per_group)
			assign_field(s_clusters_per_group);
		else if (param->s_blocks_per_group)
			super->s_clusters_per_group = 
				param->s_blocks_per_group /
				EXT2FS_CLUSTER_RATIO(fs);
		else if (super->s_log_cluster_size + 15 < 32)
			super->s_clusters_per_group = fs->blocksize * 8;
		else
			super->s_clusters_per_group = (fs->blocksize - 1) * 8;
		if (super->s_clusters_per_group > EXT2_MAX_CLUSTERS_PER_GROUP(super))
			super->s_clusters_per_group = EXT2_MAX_CLUSTERS_PER_GROUP(super);
		bpg = EXT2FS_C2B(fs,
			(unsigned long long) super->s_clusters_per_group);
		if (bpg >= (((unsigned long long) 1) << 32)) {
			retval = EXT2_ET_INVALID_ARGUMENT;
			goto cleanup;
		}
		super->s_blocks_per_group = bpg;
	} else {
		set_field(s_blocks_per_group, fs->blocksize * 8);
		if (super->s_blocks_per_group > EXT2_MAX_BLOCKS_PER_GROUP(super))
			super->s_blocks_per_group = EXT2_MAX_BLOCKS_PER_GROUP(super);
		super->s_clusters_per_group = super->s_blocks_per_group;
	}

	ext2fs_blocks_count_set(super, ext2fs_blocks_count(param) &
				~((blk64_t) EXT2FS_CLUSTER_MASK(fs)));
	ext2fs_r_blocks_count_set(super, ext2fs_r_blocks_count(param));
	if (ext2fs_r_blocks_count(super) >= ext2fs_blocks_count(param)) {
		retval = EXT2_ET_INVALID_ARGUMENT;
		goto cleanup;
	}

	set_field(s_mmp_update_interval, 0);

	/*
	 * If we're creating an external journal device, we don't need
	 * to bother with the rest.
	 */
	if (super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
		fs->group_desc_count = 0;
		ext2fs_mark_super_dirty(fs);
		*ret_fs = fs;
		return 0;
	}

retry:
	fs->group_desc_count = (dgrp_t) ext2fs_div64_ceil(
		ext2fs_blocks_count(super) - super->s_first_data_block,
		EXT2_BLOCKS_PER_GROUP(super));
	if (fs->group_desc_count == 0) {
		retval = EXT2_ET_TOOSMALL;
		goto cleanup;
	}

	set_field(s_desc_size,
		  super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT ?
		  EXT2_MIN_DESC_SIZE_64BIT : 0);

	fs->desc_blocks = ext2fs_div_ceil(fs->group_desc_count,
					  EXT2_DESC_PER_BLOCK(super));

	i = fs->blocksize >= 4096 ? 1 : 4096 / fs->blocksize;

	if (super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT &&
	    (ext2fs_blocks_count(super) / i) > (1ULL << 32))
		set_field(s_inodes_count, ~0U);
	else
		set_field(s_inodes_count, ext2fs_blocks_count(super) / i);

	/*
	 * Make sure we have at least EXT2_FIRST_INO + 1 inodes, so
	 * that we have enough inodes for the filesystem(!)
	 */
	if (super->s_inodes_count < EXT2_FIRST_INODE(super)+1)
		super->s_inodes_count = EXT2_FIRST_INODE(super)+1;

	/*
	 * There should be at least as many inodes as the user
	 * requested.  Figure out how many inodes per group that
	 * should be.  But make sure that we don't allocate more than
	 * one bitmap's worth of inodes each group.
	 */
	ipg = ext2fs_div_ceil(super->s_inodes_count, fs->group_desc_count);
	if (ipg > fs->blocksize * 8) {
		if (!bigalloc_flag && super->s_blocks_per_group >= 256) {
			/* Try again with slightly different parameters */
			super->s_blocks_per_group -= 8;
			ext2fs_blocks_count_set(super,
						ext2fs_blocks_count(param));
			super->s_clusters_per_group = super->s_blocks_per_group;
			goto retry;
		} else {
			retval = EXT2_ET_TOO_MANY_INODES;
			goto cleanup;
		}
	}

	if (ipg > (unsigned) EXT2_MAX_INODES_PER_GROUP(super))
		ipg = EXT2_MAX_INODES_PER_GROUP(super);

ipg_retry:
	super->s_inodes_per_group = ipg;

	/*
	 * Make sure the number of inodes per group completely fills
	 * the inode table blocks in the descriptor.  If not, add some
	 * additional inodes/group.  Waste not, want not...
	 */
	fs->inode_blocks_per_group = (((super->s_inodes_per_group *
					EXT2_INODE_SIZE(super)) +
				       EXT2_BLOCK_SIZE(super) - 1) /
				      EXT2_BLOCK_SIZE(super));
	super->s_inodes_per_group = ((fs->inode_blocks_per_group *
				      EXT2_BLOCK_SIZE(super)) /
				     EXT2_INODE_SIZE(super));
	/*
	 * Finally, make sure the number of inodes per group is a
	 * multiple of 8.  This is needed to simplify the bitmap
	 * splicing code.
	 */
	if (super->s_inodes_per_group < 8)
		super->s_inodes_per_group = 8;
	super->s_inodes_per_group &= ~7;
	fs->inode_blocks_per_group = (((super->s_inodes_per_group *
					EXT2_INODE_SIZE(super)) +
				       EXT2_BLOCK_SIZE(super) - 1) /
				      EXT2_BLOCK_SIZE(super));

	/*
	 * adjust inode count to reflect the adjusted inodes_per_group
	 */
	if ((__u64)super->s_inodes_per_group * fs->group_desc_count > ~0U) {
		ipg--;
		goto ipg_retry;
	}
	super->s_inodes_count = super->s_inodes_per_group *
		fs->group_desc_count;
	super->s_free_inodes_count = super->s_inodes_count;

	/*
	 * check the number of reserved group descriptor table blocks
	 */
	if (super->s_feature_compat & EXT2_FEATURE_COMPAT_RESIZE_INODE)
		rsv_gdt = calc_reserved_gdt_blocks(fs);
	else
		rsv_gdt = 0;
	set_field(s_reserved_gdt_blocks, rsv_gdt);
	if (super->s_reserved_gdt_blocks > EXT2_ADDR_PER_BLOCK(super)) {
		retval = EXT2_ET_RES_GDT_BLOCKS;
		goto cleanup;
	}

	/*
	 * Calculate the maximum number of bookkeeping blocks per
	 * group.  It includes the superblock, the block group
	 * descriptors, the block bitmap, the inode bitmap, the inode
	 * table, and the reserved gdt blocks.
	 */
	overhead = (int) (3 + fs->inode_blocks_per_group +
			  fs->desc_blocks + super->s_reserved_gdt_blocks);

	/* This can only happen if the user requested too many inodes */
	if (overhead > super->s_blocks_per_group) {
		retval = EXT2_ET_TOO_MANY_INODES;
		goto cleanup;
	}

	/*
	 * See if the last group is big enough to support the
	 * necessary data structures.  If not, we need to get rid of
	 * it.  We need to recalculate the overhead for the last block
	 * group, since it might or might not have a superblock
	 * backup.
	 */
	overhead = (int) (2 + fs->inode_blocks_per_group);
	if (ext2fs_bg_has_super(fs, fs->group_desc_count - 1))
		overhead += 1 + fs->desc_blocks + super->s_reserved_gdt_blocks;
	rem = ((ext2fs_blocks_count(super) - super->s_first_data_block) %
	       super->s_blocks_per_group);
	if ((fs->group_desc_count == 1) && rem && (rem < overhead)) {
		retval = EXT2_ET_TOOSMALL;
		goto cleanup;
	}
	if (rem && (rem < overhead+50)) {
		ext2fs_blocks_count_set(super, ext2fs_blocks_count(super) -
					rem);
		/*
		 * If blocks count is changed, we need to recalculate
		 * reserved blocks count not to exceed 50%.
		 */
		reserved_ratio = 100.0 * ext2fs_r_blocks_count(param) /
			ext2fs_blocks_count(param);
		ext2fs_r_blocks_count_set(super, reserved_ratio *
			ext2fs_blocks_count(super) / 100.0);

		goto retry;
	}

	/*
	 * At this point we know how big the filesystem will be.  So
	 * we can do any and all allocations that depend on the block
	 * count.
	 */

	/* Set up the locations of the backup superblocks */
	if (super->s_feature_compat & EXT4_FEATURE_COMPAT_SPARSE_SUPER2) {
		if (super->s_backup_bgs[0] >= fs->group_desc_count)
			super->s_backup_bgs[0] = fs->group_desc_count - 1;
		if (super->s_backup_bgs[1] >= fs->group_desc_count)
			super->s_backup_bgs[1] = fs->group_desc_count - 1;
		if (super->s_backup_bgs[0] == super->s_backup_bgs[1])
			super->s_backup_bgs[1] = 0;
		if (super->s_backup_bgs[0] > super->s_backup_bgs[1]) {
			__u32 t = super->s_backup_bgs[0];
			super->s_backup_bgs[0] = super->s_backup_bgs[1];
			super->s_backup_bgs[1] = t;
		}
	}

	retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf);
	if (retval)
		goto cleanup;

	strcpy(buf, "block bitmap for ");
	strcat(buf, fs->device_name);
	retval = ext2fs_allocate_subcluster_bitmap(fs, buf, &fs->block_map);
	if (retval)
		goto cleanup;

	strcpy(buf, "inode bitmap for ");
	strcat(buf, fs->device_name);
	retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map);
	if (retval)
		goto cleanup;

	ext2fs_free_mem(&buf);

	retval = ext2fs_get_array(fs->desc_blocks, fs->blocksize,
				&fs->group_desc);
	if (retval)
		goto cleanup;

	memset(fs->group_desc, 0, (size_t) fs->desc_blocks * fs->blocksize);

	/*
	 * Reserve the superblock and group descriptors for each
	 * group, and fill in the correct group statistics for group.
	 * Note that although the block bitmap, inode bitmap, and
	 * inode table have not been allocated (and in fact won't be
	 * by this routine), they are accounted for nevertheless.
	 *
	 * If FLEX_BG meta-data grouping is used, only account for the
	 * superblock and group descriptors (the inode tables and
	 * bitmaps will be accounted for when allocated).
	 */
	free_blocks = 0;
	csum_flag = ext2fs_has_group_desc_csum(fs);
	reserved_inos = super->s_first_ino;
	for (i = 0; i < fs->group_desc_count; i++) {
		/*
		 * Don't set the BLOCK_UNINIT group for the last group
		 * because the block bitmap needs to be padded.
		 */
		if (csum_flag) {
			if (i != fs->group_desc_count - 1)
				ext2fs_bg_flags_set(fs, i,
						    EXT2_BG_BLOCK_UNINIT);
			ext2fs_bg_flags_set(fs, i, EXT2_BG_INODE_UNINIT);
			numblocks = super->s_inodes_per_group;
			if (reserved_inos) {
				if (numblocks > reserved_inos) {
					numblocks -= reserved_inos;
					reserved_inos = 0;
				} else {
					reserved_inos -= numblocks;
					numblocks = 0;
				}
			}
			ext2fs_bg_itable_unused_set(fs, i, numblocks);
		}
		numblocks = ext2fs_reserve_super_and_bgd(fs, i, fs->block_map);
		if (fs->super->s_log_groups_per_flex)
			numblocks += 2 + fs->inode_blocks_per_group;

		free_blocks += numblocks;
		ext2fs_bg_free_blocks_count_set(fs, i, numblocks);
		ext2fs_bg_free_inodes_count_set(fs, i, fs->super->s_inodes_per_group);
		ext2fs_bg_used_dirs_count_set(fs, i, 0);
		ext2fs_group_desc_csum_set(fs, i);
	}
	free_blocks &= ~EXT2FS_CLUSTER_MASK(fs);
	ext2fs_free_blocks_count_set(super, free_blocks);

	c = (char) 255;
	if (((int) c) == -1) {
		super->s_flags |= EXT2_FLAGS_SIGNED_HASH;
	} else {
		super->s_flags |= EXT2_FLAGS_UNSIGNED_HASH;
	}

	ext2fs_mark_super_dirty(fs);
	ext2fs_mark_bb_dirty(fs);
	ext2fs_mark_ib_dirty(fs);

	io_channel_set_blksize(fs->io, fs->blocksize);

	*ret_fs = fs;
	return 0;
cleanup:
	free(buf);
	ext2fs_free(fs);
	return retval;
}
Exemplo n.º 17
0
static void check_block_bitmaps(e2fsck_t ctx)
{
	ext2_filsys fs = ctx->fs;
	blk_t	i, super;
	int	*free_array;
	int	group = 0;
	unsigned int	blocks = 0;
	unsigned int	free_blocks = 0;
	int	group_free = 0;
	int	actual, bitmap;
	struct problem_context	pctx;
	int	problem, save_problem, fixit, had_problem;
	errcode_t	retval;
	int		lazy_bg = 0;
	int		skip_group = 0;

	clear_problem_context(&pctx);
	free_array = (int *) e2fsck_allocate_memory(ctx,
	    fs->group_desc_count * sizeof(int), "free block count array");

	if ((fs->super->s_first_data_block <
	     ext2fs_get_block_bitmap_start(ctx->block_found_map)) ||
	    (fs->super->s_blocks_count-1 >
	     ext2fs_get_block_bitmap_end(ctx->block_found_map))) {
		pctx.num = 1;
		pctx.blk = fs->super->s_first_data_block;
		pctx.blk2 = fs->super->s_blocks_count -1;
		pctx.ino = ext2fs_get_block_bitmap_start(ctx->block_found_map);
		pctx.ino2 = ext2fs_get_block_bitmap_end(ctx->block_found_map);
		fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);

		ctx->flags |= E2F_FLAG_ABORT; /* fatal */
		goto errout;
	}

	if ((fs->super->s_first_data_block <
	     ext2fs_get_block_bitmap_start(fs->block_map)) ||
	    (fs->super->s_blocks_count-1 >
	     ext2fs_get_block_bitmap_end(fs->block_map))) {
		pctx.num = 2;
		pctx.blk = fs->super->s_first_data_block;
		pctx.blk2 = fs->super->s_blocks_count -1;
		pctx.ino = ext2fs_get_block_bitmap_start(fs->block_map);
		pctx.ino2 = ext2fs_get_block_bitmap_end(fs->block_map);
		fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);

		ctx->flags |= E2F_FLAG_ABORT; /* fatal */
		goto errout;
	}

	if (EXT2_HAS_COMPAT_FEATURE(fs->super, EXT2_FEATURE_COMPAT_LAZY_BG))
		lazy_bg++;

redo_counts:
	had_problem = 0;
	save_problem = 0;
	pctx.blk = pctx.blk2 = NO_BLK;
	if (lazy_bg && (fs->group_desc[group].bg_flags &
			EXT2_BG_BLOCK_UNINIT))
		skip_group++;
	super = fs->super->s_first_data_block;
	for (i = fs->super->s_first_data_block;
	     i < fs->super->s_blocks_count;
	     i++) {
		actual = ext2fs_fast_test_block_bitmap(ctx->block_found_map, i);

		if (skip_group) {
			if ((i >= super) &&
			    (i <= super + fs->desc_blocks) &&
			    ext2fs_bg_has_super(fs, group))
				bitmap = 1;
			else if (i == fs->group_desc[group].bg_block_bitmap)
				bitmap = 1;
			else if (i == fs->group_desc[group].bg_inode_bitmap)
				bitmap = 1;
			else if (i >= fs->group_desc[group].bg_inode_table &&
				 (i < fs->group_desc[group].bg_inode_table
				  + fs->inode_blocks_per_group))
				bitmap = 1;
			else
				bitmap = 0;
			actual = (actual != 0);
		} else
			bitmap = ext2fs_fast_test_block_bitmap(fs->block_map, i);

		if (actual == bitmap)
			goto do_counts;

		if (!actual && bitmap) {
			/*
			 * Block not used, but marked in use in the bitmap.
			 */
			problem = PR_5_BLOCK_UNUSED;
		} else {
			/*
			 * Block used, but not marked in use in the bitmap.
			 */
			problem = PR_5_BLOCK_USED;
		}
		if (pctx.blk == NO_BLK) {
			pctx.blk = pctx.blk2 = i;
			save_problem = problem;
		} else {
			if ((problem == save_problem) &&
			    (pctx.blk2 == i-1))
				pctx.blk2++;
			else {
				print_bitmap_problem(ctx, save_problem, &pctx);
				pctx.blk = pctx.blk2 = i;
				save_problem = problem;
			}
		}
		ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
		had_problem++;

	do_counts:
		if (!bitmap && !skip_group) {
			group_free++;
			free_blocks++;
		}
		blocks ++;
		if ((blocks == fs->super->s_blocks_per_group) ||
		    (i == fs->super->s_blocks_count-1)) {
			free_array[group] = group_free;
			group ++;
			blocks = 0;
			group_free = 0;
			skip_group = 0;
			super += fs->super->s_blocks_per_group;
			if (ctx->progress)
				if ((ctx->progress)(ctx, 5, group,
						    fs->group_desc_count*2))
					goto errout;
			if (lazy_bg &&
			    (i != fs->super->s_blocks_count-1) &&
			    (fs->group_desc[group].bg_flags &
			     EXT2_BG_BLOCK_UNINIT))
				skip_group++;
		}
	}
	if (pctx.blk != NO_BLK)
		print_bitmap_problem(ctx, save_problem, &pctx);
	if (had_problem)
		fixit = end_problem_latch(ctx, PR_LATCH_BBITMAP);
	else
		fixit = -1;
	ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;

	if (fixit == 1) {
		ext2fs_free_block_bitmap(fs->block_map);
		retval = ext2fs_copy_bitmap(ctx->block_found_map,
						  &fs->block_map);
		if (retval) {
			clear_problem_context(&pctx);
			fix_problem(ctx, PR_5_COPY_BBITMAP_ERROR, &pctx);
			ctx->flags |= E2F_FLAG_ABORT;
			goto errout;
		}
		ext2fs_set_bitmap_padding(fs->block_map);
		ext2fs_mark_bb_dirty(fs);

		/* Redo the counts */
		blocks = 0; free_blocks = 0; group_free = 0; group = 0;
		memset(free_array, 0, fs->group_desc_count * sizeof(int));
		goto redo_counts;
	} else if (fixit == 0)
		ext2fs_unmark_valid(fs);

	for (i = 0; i < fs->group_desc_count; i++) {
		if (free_array[i] != fs->group_desc[i].bg_free_blocks_count) {
			pctx.group = i;
			pctx.blk = fs->group_desc[i].bg_free_blocks_count;
			pctx.blk2 = free_array[i];

			if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT_GROUP,
					&pctx)) {
				fs->group_desc[i].bg_free_blocks_count =
					free_array[i];
				ext2fs_mark_super_dirty(fs);
			} else
				ext2fs_unmark_valid(fs);
		}
	}
	if (free_blocks != fs->super->s_free_blocks_count) {
		pctx.group = 0;
		pctx.blk = fs->super->s_free_blocks_count;
		pctx.blk2 = free_blocks;

		if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT, &pctx)) {
			fs->super->s_free_blocks_count = free_blocks;
			ext2fs_mark_super_dirty(fs);
		} else
			ext2fs_unmark_valid(fs);
	}
errout:
	ext2fs_free_mem(&free_array);
}
Exemplo n.º 18
0
static void check_block_bitmaps(e2fsck_t ctx)
{
	ext2_filsys fs = ctx->fs;
	blk64_t	i;
	int	*free_array;
	int	group = 0;
	blk_t	blocks = 0;
	blk_t	free_blocks = 0;
	int	group_free = 0;
	int	actual, bitmap;
	struct problem_context	pctx;
	int	problem, save_problem, fixit, had_problem;
	errcode_t	retval;
	int		csum_flag;
	int		skip_group = 0;
	int	old_desc_blocks = 0;
	int	count = 0;
	int	cmp_block = 0;
	int	redo_flag = 0;
	blk64_t	super_blk, old_desc_blk, new_desc_blk;

	clear_problem_context(&pctx);
	free_array = (int *) e2fsck_allocate_memory(ctx,
	    fs->group_desc_count * sizeof(int), "free block count array");

	if ((fs->super->s_first_data_block <
	     ext2fs_get_block_bitmap_start2(ctx->block_found_map)) ||
	    (fs->super->s_blocks_count-1 >
	     ext2fs_get_block_bitmap_end2(ctx->block_found_map))) {
		pctx.num = 1;
		pctx.blk = fs->super->s_first_data_block;
		pctx.blk2 = fs->super->s_blocks_count -1;
		pctx.ino = ext2fs_get_block_bitmap_start2(ctx->block_found_map);
		pctx.ino2 = ext2fs_get_block_bitmap_end2(ctx->block_found_map);
		fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);

		ctx->flags |= E2F_FLAG_ABORT; /* fatal */
		goto errout;
	}

	if ((fs->super->s_first_data_block <
	     ext2fs_get_block_bitmap_start2(fs->block_map)) ||
	    (fs->super->s_blocks_count-1 >
	     ext2fs_get_block_bitmap_end2(fs->block_map))) {
		pctx.num = 2;
		pctx.blk = fs->super->s_first_data_block;
		pctx.blk2 = fs->super->s_blocks_count -1;
		pctx.ino = ext2fs_get_block_bitmap_start2(fs->block_map);
		pctx.ino2 = ext2fs_get_block_bitmap_end2(fs->block_map);
		fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);

		ctx->flags |= E2F_FLAG_ABORT; /* fatal */
		goto errout;
	}

	csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
					       EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
redo_counts:
	had_problem = 0;
	save_problem = 0;
	pctx.blk = pctx.blk2 = NO_BLK;
	if (csum_flag &&
	    (fs->group_desc[group].bg_flags & EXT2_BG_BLOCK_UNINIT))
		skip_group++;
	for (i = fs->super->s_first_data_block;
	     i < fs->super->s_blocks_count;
	     i++) {
		actual = ext2fs_fast_test_block_bitmap2(ctx->block_found_map, i);

		if (skip_group) {
			if ((i - fs->super->s_first_data_block) %
			    fs->super->s_blocks_per_group == 0) {
				super_blk = 0;
				old_desc_blk = 0;
				new_desc_blk = 0;
				ext2fs_super_and_bgd_loc2(fs, group, &super_blk,
					 &old_desc_blk, &new_desc_blk, 0);

				if (fs->super->s_feature_incompat &
						EXT2_FEATURE_INCOMPAT_META_BG)
					old_desc_blocks =
						fs->super->s_first_meta_bg;
				else
					old_desc_blocks = fs->desc_blocks +
					fs->super->s_reserved_gdt_blocks;

				count = 0;
				cmp_block = fs->super->s_blocks_per_group;
				if (group == (int)fs->group_desc_count - 1)
					cmp_block =
						fs->super->s_blocks_count %
						fs->super->s_blocks_per_group;
			}

			bitmap = 0;
			if ((i == super_blk) ||
				(old_desc_blk && old_desc_blocks &&
				(i >= old_desc_blk) &&
				(i < old_desc_blk + old_desc_blocks)) ||
				(new_desc_blk && (i == new_desc_blk)) ||
				(i == fs->group_desc[group].bg_block_bitmap) ||
				(i == fs->group_desc[group].bg_inode_bitmap) ||
				(i >= fs->group_desc[group].bg_inode_table &&
				(i < fs->group_desc[group].bg_inode_table +
					fs->inode_blocks_per_group))) {
				bitmap = 1;
				actual = (actual != 0);
				count++;
				cmp_block--;
			} else if ((i - count - fs->super->s_first_data_block) %
				  fs->super->s_blocks_per_group == 0) {
				/*
				 * When the compare data blocks in block bitmap
				 * are 0, count the free block,
				 * skip the current block group.
				 */
				if (ext2fs_test_block_bitmap_range2(
					    ctx->block_found_map, i,
					    cmp_block)) {
					/*
					 * -1 means to skip the current block
					 * group.
					 */
					blocks = fs->super->s_blocks_per_group
									- 1;
					group_free = cmp_block;
					free_blocks += cmp_block;
					/*
					 * The current block group's last block
					 * is set to i.
					 */
					i += cmp_block - 1;
					bitmap = 1;
					goto do_counts;
				}
			}
		} else if (redo_flag)
			bitmap = actual;
		else
			bitmap = ext2fs_fast_test_block_bitmap2(fs->block_map, i);

		if (actual == bitmap)
			goto do_counts;

		if (!actual && bitmap) {
			/*
			 * Block not used, but marked in use in the bitmap.
			 */
			problem = PR_5_BLOCK_UNUSED;
		} else {
			/*
			 * Block used, but not marked in use in the bitmap.
			 */
			problem = PR_5_BLOCK_USED;

			if (skip_group) {
				struct problem_context pctx2;
				pctx2.blk = i;
				pctx2.group = group;
				if (fix_problem(ctx, PR_5_BLOCK_UNINIT,&pctx2)){
					fs->group_desc[group].bg_flags &=
						~EXT2_BG_BLOCK_UNINIT;
					skip_group = 0;
				}
			}
		}
		if (pctx.blk == NO_BLK) {
			pctx.blk = pctx.blk2 = i;
			save_problem = problem;
		} else {
			if ((problem == save_problem) &&
			    (pctx.blk2 == i-1))
				pctx.blk2++;
			else {
				print_bitmap_problem(ctx, save_problem, &pctx);
				pctx.blk = pctx.blk2 = i;
				save_problem = problem;
			}
		}
		ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
		had_problem++;

	do_counts:
		if (!bitmap && (!skip_group || csum_flag)) {
			group_free++;
			free_blocks++;
		}
		blocks ++;
		if ((blocks == fs->super->s_blocks_per_group) ||
		    (i == fs->super->s_blocks_count-1)) {
			free_array[group] = group_free;
			group ++;
			blocks = 0;
			group_free = 0;
			skip_group = 0;
			if (ctx->progress)
				if ((ctx->progress)(ctx, 5, group,
						    fs->group_desc_count*2))
					goto errout;
			if (csum_flag &&
			    (i != fs->super->s_blocks_count-1) &&
			    (fs->group_desc[group].bg_flags &
			     EXT2_BG_BLOCK_UNINIT))
				skip_group++;
		}
	}
	if (pctx.blk != NO_BLK)
		print_bitmap_problem(ctx, save_problem, &pctx);
	if (had_problem)
		fixit = end_problem_latch(ctx, PR_LATCH_BBITMAP);
	else
		fixit = -1;
	ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;

	if (fixit == 1) {
		ext2fs_free_block_bitmap(fs->block_map);
		retval = ext2fs_copy_bitmap(ctx->block_found_map,
						  &fs->block_map);
		if (retval) {
			clear_problem_context(&pctx);
			fix_problem(ctx, PR_5_COPY_BBITMAP_ERROR, &pctx);
			ctx->flags |= E2F_FLAG_ABORT;
			goto errout;
		}
		ext2fs_set_bitmap_padding(fs->block_map);
		ext2fs_mark_bb_dirty(fs);

		/* Redo the counts */
		blocks = 0; free_blocks = 0; group_free = 0; group = 0;
		memset(free_array, 0, fs->group_desc_count * sizeof(int));
		redo_flag++;
		goto redo_counts;
	} else if (fixit == 0)
		ext2fs_unmark_valid(fs);

	for (i = 0; i < fs->group_desc_count; i++) {
		if (free_array[i] != fs->group_desc[i].bg_free_blocks_count) {
			pctx.group = i;
			pctx.blk = fs->group_desc[i].bg_free_blocks_count;
			pctx.blk2 = free_array[i];

			if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT_GROUP,
					&pctx)) {
				fs->group_desc[i].bg_free_blocks_count =
					free_array[i];
				ext2fs_mark_super_dirty(fs);
			} else
				ext2fs_unmark_valid(fs);
		}
	}
	if (free_blocks != fs->super->s_free_blocks_count) {
		pctx.group = 0;
		pctx.blk = fs->super->s_free_blocks_count;
		pctx.blk2 = free_blocks;

		if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT, &pctx)) {
			fs->super->s_free_blocks_count = free_blocks;
			ext2fs_mark_super_dirty(fs);
		} else
			ext2fs_unmark_valid(fs);
	}
errout:
	ext2fs_free_mem(&free_array);
}