コード例 #1
0
static void update_uuid(journal_t *journal)
{
	size_t z;
	ext2_filsys fs;

	if (journal->j_format_version < 2)
		return;

	for (z = 0; z < sizeof(journal->j_superblock->s_uuid); z++)
		if (journal->j_superblock->s_uuid[z])
			break;
	if (z == 0)
		return;

	fs = journal->j_fs_dev->k_fs;
	if (!EXT2_HAS_INCOMPAT_FEATURE(fs->super,
				       EXT4_FEATURE_INCOMPAT_64BIT))
		return;

	if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_64BIT) &&
	    EXT2_HAS_INCOMPAT_FEATURE(fs->super,
				      EXT4_FEATURE_INCOMPAT_64BIT))
		return;

	if (journal->j_tail != 0 ||
	    EXT2_HAS_INCOMPAT_FEATURE(fs->super,
				      EXT3_FEATURE_INCOMPAT_RECOVER)) {
		printf("Journal needs recovery, will not set 64bit.\n");
		return;
	}

	memcpy(journal->j_superblock->s_uuid, fs->super->s_uuid,
	       sizeof(fs->super->s_uuid));
}
コード例 #2
0
ファイル: ext2.c プロジェクト: Ctrlshiftm/ICU
static int set_EXT2_info(const struct ext2_super_block *sb, partition_t *partition, const int verbose)
{
  partition->blocksize=EXT2_MIN_BLOCK_SIZE<<le32(sb->s_log_block_size);
  set_part_name(partition,sb->s_volume_name,16);
  /* sb->s_last_mounted seems to be unemployed in kernel 2.2.16 */
  if(EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT4_FEATURE_RO_COMPAT_HUGE_FILE)!=0 ||
      EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT4_FEATURE_RO_COMPAT_GDT_CSUM)!=0 ||
      EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT4_FEATURE_RO_COMPAT_DIR_NLINK)!=0 ||
      EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE)!=0 ||
      EXT2_HAS_INCOMPAT_FEATURE(sb,EXT4_FEATURE_INCOMPAT_64BIT)!=0 ||
      EXT2_HAS_INCOMPAT_FEATURE(sb,EXT4_FEATURE_INCOMPAT_MMP)!=0)
    snprintf(partition->info, sizeof(partition->info), "ext4 blocksize=%u", partition->blocksize);
  else if(EXT2_HAS_COMPAT_FEATURE(sb,EXT3_FEATURE_COMPAT_HAS_JOURNAL)!=0)
    snprintf(partition->info, sizeof(partition->info), "ext3 blocksize=%u", partition->blocksize);
  else
    snprintf(partition->info, sizeof(partition->info), "ext2 blocksize=%u", partition->blocksize);
  if(EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT2_FEATURE_RO_COMPAT_LARGE_FILE)!=0)
    strcat(partition->info," Large_file");
  if(EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)!=0)
    strcat(partition->info," Sparse_SB");
  if(EXT2_HAS_INCOMPAT_FEATURE(sb,EXT3_FEATURE_INCOMPAT_RECOVER)!=0)
    strcat(partition->info," Recover");
  if(EXT2_HAS_INCOMPAT_FEATURE(sb,EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)!=0)
    strcat(partition->info," Journal_dev");
  if(le16(sb->s_block_group_nr)!=0)
  {
    strcat(partition->info," Backup_SB");
    if(verbose>0)
    {
      log_warning("\nblock_group_nr %u\n",le16(sb->s_block_group_nr));
    }
  }
  /* last mounted => date */
  return 0;
}
コード例 #3
0
static errcode_t journal_close_trans(journal_transaction_t *trans)
{
	journal_t *journal;

	JOURNAL_CHECK_TRANS_MAGIC(trans);

	if (!(trans->flags & J_TRANS_COMMITTED))
		return 0;

	journal = trans->journal;
	if (journal->j_tail == 0) {
		/* Update the tail */
		journal->j_tail_sequence = trans->tid;
		journal->j_tail = trans->start;
		journal->j_superblock->s_start = ext2fs_cpu_to_be32(trans->start);
	}

	/* Update the head */
	journal->j_head = trans->end + 1;
	journal->j_transaction_sequence = trans->tid + 1;

	trans->magic = 0;

	/* Mark ourselves as needing recovery */
	if (!(EXT2_HAS_INCOMPAT_FEATURE(trans->fs->super,
					EXT3_FEATURE_INCOMPAT_RECOVER))) {
		trans->fs->super->s_feature_incompat |=
					EXT3_FEATURE_INCOMPAT_RECOVER;
		ext2fs_mark_super_dirty(trans->fs);
	}

	return 0;
}
コード例 #4
0
ファイル: mk_hugefiles.c プロジェクト: timofonic/WinFLASHTool
static errcode_t mk_hugefile(ext2_filsys fs, blk64_t num,
                             ext2_ino_t dir, unsigned long idx, ext2_ino_t *ino)

{
    errcode_t		retval;
    struct ext2_inode	inode;

    retval = ext2fs_new_inode(fs, 0, LINUX_S_IFREG, NULL, ino);
    if (retval)
        return retval;

    memset(&inode, 0, sizeof(struct ext2_inode));
    inode.i_mode = LINUX_S_IFREG | (0666 & ~fs->umask);
    inode.i_links_count = 1;
    inode.i_uid = uid & 0xFFFF;
    ext2fs_set_i_uid_high(inode, (uid >> 16) & 0xffff);
    inode.i_gid = gid & 0xFFFF;
    ext2fs_set_i_gid_high(inode, (gid >> 16) & 0xffff);

    retval = ext2fs_write_new_inode(fs, *ino, &inode);
    if (retval)
        return retval;

    ext2fs_inode_alloc_stats2(fs, *ino, +1, 0);

    if (EXT2_HAS_INCOMPAT_FEATURE(fs->super,
                                  EXT3_FEATURE_INCOMPAT_EXTENTS))
        inode.i_flags |= EXT4_EXTENTS_FL;
    retval = ext2fs_fallocate(fs,
                              EXT2_FALLOCATE_FORCE_INIT |
                              EXT2_FALLOCATE_ZERO_BLOCKS,
                              *ino, &inode, goal, 0, num);
    if (retval)
        return retval;
    retval = ext2fs_inode_size_set(fs, &inode, num * fs->blocksize);
    if (retval)
        return retval;

    retval = ext2fs_write_inode(fs, *ino, &inode);
    if (retval)
        goto errout;

    if (idx_digits)
        sprintf(fn_numbuf, "%0*lu", idx_digits, idx);
    else if (num_files > 1)
        sprintf(fn_numbuf, "%lu", idx);

retry:
    retval = ext2fs_link(fs, dir, fn_buf, *ino, EXT2_FT_REG_FILE);
    if (retval == EXT2_ET_DIR_NO_SPACE) {
        retval = ext2fs_expand_dir(fs, dir);
        if (retval)
            goto errout;
        goto retry;
    }

errout:
    return retval;
}
コード例 #5
0
ファイル: inline_data.c プロジェクト: kikimo/w4118-hmwk6
static errcode_t
ext2fs_inline_data_dir_expand(ext2_filsys fs, ext2_ino_t ino,
                              struct ext2_inode *inode, char *buf, size_t size)
{
    errcode_t retval;
    blk64_t blk;
    char *blk_buf;

    retval = ext2fs_get_memzero(fs->blocksize, &blk_buf);
    if (retval)
        return retval;

#ifdef WORDS_BIGENDIAN
    retval = ext2fs_dirent_swab_in2(fs, buf + EXT4_INLINE_DATA_DOTDOT_SIZE,
                                    size, 0);
    if (retval)
        goto errout;
#endif

    /* Adjust the rec_len */
    retval = ext2fs_inline_data_convert_dir(fs, ino, blk_buf, buf, size);
    if (retval)
        goto errout;
    /* Allocate a new block */
    retval = ext2fs_new_block2(fs, 0, 0, &blk);
    if (retval)
        goto errout;
    retval = ext2fs_write_dir_block4(fs, blk, blk_buf, 0, ino);
    if (retval)
        goto errout;

    /* Update inode */
    if (EXT2_HAS_INCOMPAT_FEATURE(fs->super, EXT3_FEATURE_INCOMPAT_EXTENTS))
        inode->i_flags |= EXT4_EXTENTS_FL;
    inode->i_flags &= ~EXT4_INLINE_DATA_FL;
    retval = ext2fs_iblk_add_blocks(fs, inode, 1);
    if (retval)
        goto errout;
    inode->i_size = fs->blocksize;
    retval = ext2fs_bmap2(fs, ino, inode, 0, BMAP_SET, 0, 0, &blk);
    if (retval)
        goto errout;
    retval = ext2fs_write_inode(fs, ino, inode);
    if (retval)
        goto errout;
    ext2fs_block_alloc_stats(fs, blk, +1);

errout:
    ext2fs_free_mem(&blk_buf);
    return retval;
}
コード例 #6
0
static void update_journal_csum(journal_t *journal, int ver)
{
	journal_superblock_t *jsb;

	if (journal->j_format_version < 2)
		return;

	if (journal->j_tail != 0 ||
	    EXT2_HAS_INCOMPAT_FEATURE(journal->j_fs_dev->k_fs->super,
				      EXT3_FEATURE_INCOMPAT_RECOVER)) {
		printf("Journal needs recovery, will not add csums.\n");
		return;
	}

	/* metadata_csum implies journal csum v3 */
	jsb = journal->j_superblock;
	if (EXT2_HAS_RO_COMPAT_FEATURE(journal->j_fs_dev->k_fs->super,
				       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
		printf("Setting csum v%d\n", ver);
		switch (ver) {
		case 2:
			journal->j_superblock->s_feature_incompat &=
				ext2fs_cpu_to_be32(~JFS_FEATURE_INCOMPAT_CSUM_V3);
			journal->j_superblock->s_feature_incompat |=
				ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_CSUM_V2);
			journal->j_superblock->s_feature_compat &=
				ext2fs_cpu_to_be32(~JFS_FEATURE_COMPAT_CHECKSUM);
			break;
		case 3:
			journal->j_superblock->s_feature_incompat &=
				ext2fs_cpu_to_be32(~JFS_FEATURE_INCOMPAT_CSUM_V2);
			journal->j_superblock->s_feature_incompat |=
				ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_CSUM_V3);
			journal->j_superblock->s_feature_compat &=
				ext2fs_cpu_to_be32(~JFS_FEATURE_COMPAT_CHECKSUM);
			break;
		default:
			printf("Unknown checksum v%d\n", ver);
			break;
		}
		journal->j_superblock->s_checksum_type = JBD2_CRC32C_CHKSUM;
		journal->j_csum_seed = jbd2_chksum(journal, ~0, jsb->s_uuid,
						   sizeof(jsb->s_uuid));
	} else {
		journal->j_superblock->s_feature_compat |=
			ext2fs_cpu_to_be32(JFS_FEATURE_COMPAT_CHECKSUM);
		journal->j_superblock->s_feature_incompat &=
			ext2fs_cpu_to_be32(~(JFS_FEATURE_INCOMPAT_CSUM_V2 |
					     JFS_FEATURE_INCOMPAT_CSUM_V3));
	}
}
コード例 #7
0
static void update_64bit_flag(journal_t *journal)
{
	if (journal->j_format_version < 2)
		return;

	if (!EXT2_HAS_INCOMPAT_FEATURE(journal->j_fs_dev->k_fs->super,
				       EXT4_FEATURE_INCOMPAT_64BIT))
		return;

	if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_64BIT) &&
	    EXT2_HAS_INCOMPAT_FEATURE(journal->j_fs_dev->k_fs->super,
				      EXT4_FEATURE_INCOMPAT_64BIT))
		return;

	if (journal->j_tail != 0 ||
	    EXT2_HAS_INCOMPAT_FEATURE(journal->j_fs_dev->k_fs->super,
				      EXT3_FEATURE_INCOMPAT_RECOVER)) {
		printf("Journal needs recovery, will not set 64bit.\n");
		return;
	}

	journal->j_superblock->s_feature_incompat |=
				ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_64BIT);
}
コード例 #8
0
static unsigned long descriptor_loc(struct super_block *sb,
				    unsigned long logic_sb_block,
				    int nr)
{
	struct ext2_sb_info *sbi = EXT2_SB(sb);
	unsigned long bg, first_meta_bg;
	int has_super = 0;
	
	first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg);

	if (!EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_META_BG) ||
	    nr < first_meta_bg)
		return (logic_sb_block + nr + 1);
	bg = sbi->s_desc_per_block * nr;
	if (ext2_bg_has_super(sb, bg))
		has_super = 1;

	return ext2_group_first_block_no(sb, bg) + has_super;
}
コード例 #9
0
ファイル: ext2_lookup.c プロジェクト: AhmadTux/DragonFlyBSD
/*
 * Rewrite an existing directory entry to point at the inode
 * supplied.  The parameters describing the directory entry are
 * set up by a call to namei.
 */
int
ext2_dirrewrite(struct inode *dp, struct inode *ip, struct componentname *cnp)
{
	struct buf *bp;
	struct ext2_dir_entry_2 *ep;
	struct vnode *vdp = ITOV(dp);
	int error;

	if ((error = EXT2_BLKATOFF(vdp, (off_t)dp->i_offset, (char **)&ep, &bp)) != 0)
		return (error);
	ep->inode = ip->i_number;
	if (EXT2_HAS_INCOMPAT_FEATURE(ip->i_e2fs->s_es,
	    EXT2_FEATURE_INCOMPAT_FILETYPE))
		ep->file_type = DTTOFT(IFTODT(ip->i_mode));
	else
		ep->file_type = EXT2_FT_UNKNOWN;
	error = bwrite(bp);
	dp->i_flag |= IN_CHANGE | IN_UPDATE;
	return (error);
}
コード例 #10
0
ファイル: inline_data.c プロジェクト: kikimo/w4118-hmwk6
static errcode_t
ext2fs_inline_data_file_expand(ext2_filsys fs, ext2_ino_t ino,
                               struct ext2_inode *inode, char *buf, size_t size)
{
    ext2_file_t e2_file;
    errcode_t retval;

    /* Update inode */
    if (EXT2_HAS_INCOMPAT_FEATURE(fs->super,
                                  EXT3_FEATURE_INCOMPAT_EXTENTS)) {
        int i;
        struct ext3_extent_header *eh;

        eh = (struct ext3_extent_header *) &inode->i_block[0];
        eh->eh_depth = 0;
        eh->eh_entries = 0;
        eh->eh_magic = ext2fs_cpu_to_le16(EXT3_EXT_MAGIC);
        i = (sizeof(inode->i_block) - sizeof(*eh)) /
            sizeof(struct ext3_extent);
        eh->eh_max = ext2fs_cpu_to_le16(i);
        inode->i_flags |= EXT4_EXTENTS_FL;
    }
    inode->i_flags &= ~EXT4_INLINE_DATA_FL;
    inode->i_size = 0;
    retval = ext2fs_write_inode(fs, ino, inode);
    if (retval)
        return retval;

    /* Write out the block buffer */
    retval = ext2fs_file_open(fs, ino, EXT2_FILE_WRITE, &e2_file);
    if (retval)
        return retval;
    retval = ext2fs_file_write(e2_file, buf, size, 0);
    ext2fs_file_close(e2_file);
    return retval;
}
コード例 #11
0
ファイル: pass2.c プロジェクト: Gwinel/e2fsprogs
static int check_dir_block(ext2_filsys fs,
			   struct ext2_db_entry2 *db,
			   void *priv_data)
{
 	struct dx_dir_info	*dx_dir;
#ifdef ENABLE_HTREE
	struct dx_dirblock_info	*dx_db = 0;
#endif /* ENABLE_HTREE */
	struct ext2_dir_entry 	*dirent, *prev, dot, dotdot;
	ext2_dirhash_t		hash;
	unsigned int		offset = 0;
	int			dir_modified = 0;
	int			dot_state;
	unsigned int		rec_len;
	blk64_t			block_nr = db->blk;
	ext2_ino_t 		ino = db->ino;
	ext2_ino_t 		subdir_parent;
	__u16			links;
	struct check_dir_struct	*cd;
	char 			*buf;
	e2fsck_t		ctx;
	problem_t		problem;
	struct ext2_dx_root_info *root;
	struct ext2_dx_countlimit *limit;
	static dict_t de_dict;
	struct problem_context	pctx;
	int	dups_found = 0;
	int	ret;
	int	dx_csum_size = 0, de_csum_size = 0;
	int	failed_csum = 0;
	int	is_leaf = 1;
	size_t	inline_data_size = 0;
	int	filetype = 0;

	cd = (struct check_dir_struct *) priv_data;
	buf = cd->buf;
	ctx = cd->ctx;

	if (ctx->flags & E2F_FLAG_SIGNAL_MASK || ctx->flags & E2F_FLAG_RESTART)
		return DIRENT_ABORT;

	if (ctx->progress && (ctx->progress)(ctx, 2, cd->count++, cd->max))
		return DIRENT_ABORT;

	if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
				       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
		dx_csum_size = sizeof(struct ext2_dx_tail);
		de_csum_size = sizeof(struct ext2_dir_entry_tail);
	}

	if (EXT2_HAS_INCOMPAT_FEATURE(fs->super,
				      EXT2_FEATURE_INCOMPAT_FILETYPE))
		filetype = EXT2_FT_DIR << 8;

	/*
	 * Make sure the inode is still in use (could have been
	 * deleted in the duplicate/bad blocks pass.
	 */
	if (!(ext2fs_test_inode_bitmap2(ctx->inode_used_map, ino)))
		return 0;

	cd->pctx.ino = ino;
	cd->pctx.blk = block_nr;
	cd->pctx.blkcount = db->blockcnt;
	cd->pctx.ino2 = 0;
	cd->pctx.dirent = 0;
	cd->pctx.num = 0;

	if (EXT2_HAS_INCOMPAT_FEATURE(fs->super,
				      EXT4_FEATURE_INCOMPAT_INLINE_DATA)) {
		errcode_t ec;

		ec = ext2fs_inline_data_size(fs, ino, &inline_data_size);
		if (ec && ec != EXT2_ET_NO_INLINE_DATA)
			return DIRENT_ABORT;
	}

	if (db->blk == 0 && !inline_data_size) {
		if (allocate_dir_block(ctx, db, buf, &cd->pctx))
			return 0;
		block_nr = db->blk;
	}

	if (db->blockcnt)
		dot_state = 2;
	else
		dot_state = 0;

	if (ctx->dirs_to_hash &&
	    ext2fs_u32_list_test(ctx->dirs_to_hash, ino))
		dups_found++;

#if 0
	printf("In process_dir_block block %lu, #%d, inode %lu\n", block_nr,
	       db->blockcnt, ino);
#endif

	ehandler_operation(_("reading directory block"));
	if (inline_data_size)
		cd->pctx.errcode = ext2fs_inline_data_get(fs, ino, 0, buf, 0);
	else
		cd->pctx.errcode = ext2fs_read_dir_block4(fs, block_nr,
							  buf, 0, ino);
	ehandler_operation(0);
	if (cd->pctx.errcode == EXT2_ET_DIR_CORRUPTED)
		cd->pctx.errcode = 0; /* We'll handle this ourselves */
	else if (cd->pctx.errcode == EXT2_ET_DIR_CSUM_INVALID) {
		cd->pctx.errcode = 0; /* We'll handle this ourselves */
		failed_csum = 1;
	}
	if (cd->pctx.errcode) {
		char *buf2;
		if (!fix_problem(ctx, PR_2_READ_DIRBLOCK, &cd->pctx)) {
			ctx->flags |= E2F_FLAG_ABORT;
			return DIRENT_ABORT;
		}
		ext2fs_new_dir_block(fs, db->blockcnt == 0 ? ino : 0,
				     EXT2_ROOT_INO, &buf2);
		memcpy(buf, buf2, fs->blocksize);
		ext2fs_free_mem(&buf2);
	}
#ifdef ENABLE_HTREE
	dx_dir = e2fsck_get_dx_dir_info(ctx, ino);
	if (dx_dir && dx_dir->numblocks) {
		if (db->blockcnt >= dx_dir->numblocks) {
			if (fix_problem(ctx, PR_2_UNEXPECTED_HTREE_BLOCK,
					&pctx)) {
				clear_htree(ctx, ino);
				dx_dir->numblocks = 0;
				dx_db = 0;
				goto out_htree;
			}
			fatal_error(ctx, _("Can not continue."));
		}
		dx_db = &dx_dir->dx_block[db->blockcnt];
		dx_db->type = DX_DIRBLOCK_LEAF;
		dx_db->phys = block_nr;
		dx_db->min_hash = ~0;
		dx_db->max_hash = 0;

		dirent = (struct ext2_dir_entry *) buf;
		(void) ext2fs_get_rec_len(fs, dirent, &rec_len);
		limit = (struct ext2_dx_countlimit *) (buf+8);
		if (db->blockcnt == 0) {
			root = (struct ext2_dx_root_info *) (buf + 24);
			dx_db->type = DX_DIRBLOCK_ROOT;
			dx_db->flags |= DX_FLAG_FIRST | DX_FLAG_LAST;
			if ((root->reserved_zero ||
			     root->info_length < 8 ||
			     root->indirect_levels > 1) &&
			    fix_problem(ctx, PR_2_HTREE_BAD_ROOT, &cd->pctx)) {
				clear_htree(ctx, ino);
				dx_dir->numblocks = 0;
				dx_db = 0;
			}
			dx_dir->hashversion = root->hash_version;
			if ((dx_dir->hashversion <= EXT2_HASH_TEA) &&
			    (fs->super->s_flags & EXT2_FLAGS_UNSIGNED_HASH))
				dx_dir->hashversion += 3;
			dx_dir->depth = root->indirect_levels + 1;
		} else if ((dirent->inode == 0) &&
			   (rec_len == fs->blocksize) &&
			   (ext2fs_dirent_name_len(dirent) == 0) &&
			   (ext2fs_le16_to_cpu(limit->limit) ==
			    ((fs->blocksize - (8 + dx_csum_size)) /
			     sizeof(struct ext2_dx_entry))))
			dx_db->type = DX_DIRBLOCK_NODE;
		is_leaf = 0;
	}
out_htree:
#endif /* ENABLE_HTREE */

	/* Verify checksum. */
	if (is_leaf && de_csum_size && !inline_data_size) {
		/* No space for csum?  Rebuild dirs in pass 3A. */
		if (!ext2fs_dirent_has_tail(fs, (struct ext2_dir_entry *)buf)) {
			de_csum_size = 0;
			if (e2fsck_dir_will_be_rehashed(ctx, ino))
				goto skip_checksum;
			if (!fix_problem(cd->ctx, PR_2_LEAF_NODE_MISSING_CSUM,
					 &cd->pctx))
				goto skip_checksum;
			e2fsck_rehash_dir_later(ctx, ino);
			goto skip_checksum;
		}
		if (failed_csum) {
			char *buf2;
			if (!fix_problem(cd->ctx, PR_2_LEAF_NODE_CSUM_INVALID,
					 &cd->pctx))
				goto skip_checksum;
			ext2fs_new_dir_block(fs,
					     db->blockcnt == 0 ? ino : 0,
					     EXT2_ROOT_INO, &buf2);
			memcpy(buf, buf2, fs->blocksize);
			ext2fs_free_mem(&buf2);
			dir_modified++;
			failed_csum = 0;
		}
	}
	/* htree nodes don't use fake dirents to store checksums */
	if (!is_leaf)
		de_csum_size = 0;

skip_checksum:
	dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp);
	prev = 0;
	do {
		dgrp_t group;
		ext2_ino_t first_unused_inode;
		unsigned int name_len;

		problem = 0;
		if (!inline_data_size || dot_state > 1) {
			dirent = (struct ext2_dir_entry *) (buf + offset);
			(void) ext2fs_get_rec_len(fs, dirent, &rec_len);
			cd->pctx.dirent = dirent;
			cd->pctx.num = offset;
			if (((offset + rec_len) > fs->blocksize) ||
			    (rec_len < 12) ||
			    ((rec_len % 4) != 0) ||
			    ((ext2fs_dirent_name_len(dirent) + 8) > rec_len)) {
				if (fix_problem(ctx, PR_2_DIR_CORRUPTED, &cd->pctx)) {
					salvage_directory(fs, dirent, prev, &offset);
					dir_modified++;
					continue;
				} else
					goto abort_free_dict;
			}
		} else {
			if (dot_state == 0) {
				memset(&dot, 0, sizeof(dot));
				dirent = &dot;
				dirent->inode = ino;
				dirent->rec_len = EXT2_DIR_REC_LEN(1);
				dirent->name_len = 1 | filetype;
				dirent->name[0] = '.';
			} else if (dot_state == 1) {
				memset(&dotdot, 0, sizeof(dotdot));
				dirent = &dotdot;
				dirent->inode =
					((struct ext2_dir_entry *)buf)->inode;
				dirent->rec_len = EXT2_DIR_REC_LEN(2);
				dirent->name_len = 2 | filetype;
				dirent->name[0] = '.';
				dirent->name[1] = '.';
			} else {
				fatal_error(ctx, _("Can not continue."));
			}
			cd->pctx.dirent = dirent;
			cd->pctx.num = offset;
		}

		if (dot_state == 0) {
			if (check_dot(ctx, dirent, ino, &cd->pctx))
				dir_modified++;
		} else if (dot_state == 1) {
			ret = check_dotdot(ctx, dirent, ino, &cd->pctx);
			if (ret < 0)
				goto abort_free_dict;
			if (ret)
				dir_modified++;
		} else if (dirent->inode == ino) {
			problem = PR_2_LINK_DOT;
			if (fix_problem(ctx, PR_2_LINK_DOT, &cd->pctx)) {
				dirent->inode = 0;
				dir_modified++;
				goto next;
			}
		}
		if (!dirent->inode)
			goto next;

		/*
		 * Make sure the inode listed is a legal one.
		 */
		name_len = ext2fs_dirent_name_len(dirent);
		if (((dirent->inode != EXT2_ROOT_INO) &&
		     (dirent->inode < EXT2_FIRST_INODE(fs->super))) ||
		    (dirent->inode > fs->super->s_inodes_count)) {
			problem = PR_2_BAD_INO;
		} else if (ctx->inode_bb_map &&
			   (ext2fs_test_inode_bitmap2(ctx->inode_bb_map,
						     dirent->inode))) {
			/*
			 * If the inode is in a bad block, offer to
			 * clear it.
			 */
			problem = PR_2_BB_INODE;
		} else if ((dot_state > 1) && (name_len == 1) &&
			   (dirent->name[0] == '.')) {
			/*
			 * If there's a '.' entry in anything other
			 * than the first directory entry, it's a
			 * duplicate entry that should be removed.
			 */
			problem = PR_2_DUP_DOT;
		} else if ((dot_state > 1) && (name_len == 2) &&
			   (dirent->name[0] == '.') &&
			   (dirent->name[1] == '.')) {
			/*
			 * If there's a '..' entry in anything other
			 * than the second directory entry, it's a
			 * duplicate entry that should be removed.
			 */
			problem = PR_2_DUP_DOT_DOT;
		} else if ((dot_state > 1) &&
			   (dirent->inode == EXT2_ROOT_INO)) {
			/*
			 * Don't allow links to the root directory.
			 * We check this specially to make sure we
			 * catch this error case even if the root
			 * directory hasn't been created yet.
			 */
			problem = PR_2_LINK_ROOT;
		} else if ((dot_state > 1) && (name_len == 0)) {
			/*
			 * Don't allow zero-length directory names.
			 */
			problem = PR_2_NULL_NAME;
		}

		if (problem) {
			if (fix_problem(ctx, problem, &cd->pctx)) {
				dirent->inode = 0;
				dir_modified++;
				goto next;
			} else {
				ext2fs_unmark_valid(fs);
				if (problem == PR_2_BAD_INO)
					goto next;
			}
		}

		/*
		 * If the inode was marked as having bad fields in
		 * pass1, process it and offer to fix/clear it.
		 * (We wait until now so that we can display the
		 * pathname to the user.)
		 */
		if (ctx->inode_bad_map &&
		    ext2fs_test_inode_bitmap2(ctx->inode_bad_map,
					     dirent->inode)) {
			if (e2fsck_process_bad_inode(ctx, ino,
						     dirent->inode,
						     buf + fs->blocksize)) {
				dirent->inode = 0;
				dir_modified++;
				goto next;
			}
			if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
				return DIRENT_ABORT;
		}

		group = ext2fs_group_of_ino(fs, dirent->inode);
		first_unused_inode = group * fs->super->s_inodes_per_group +
					1 + fs->super->s_inodes_per_group -
					ext2fs_bg_itable_unused(fs, group);
		cd->pctx.group = group;

		/*
		 * Check if the inode was missed out because
		 * _INODE_UNINIT flag was set or bg_itable_unused was
		 * incorrect.  If so, clear the _INODE_UNINIT flag and
		 * restart e2fsck.  In the future it would be nice if
		 * we could call a function in pass1.c that checks the
		 * newly visible inodes.
		 */
		if (ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT)) {
			pctx.num = dirent->inode;
			if (fix_problem(ctx, PR_2_INOREF_BG_INO_UNINIT,
					&cd->pctx)){
				ext2fs_bg_flags_clear(fs, group,
						      EXT2_BG_INODE_UNINIT);
				ext2fs_mark_super_dirty(fs);
				ctx->flags |= E2F_FLAG_RESTART_LATER;
			} else {
				ext2fs_unmark_valid(fs);
				if (problem == PR_2_BAD_INO)
					goto next;
			}
		} else if (dirent->inode >= first_unused_inode) {
			pctx.num = dirent->inode;
			if (fix_problem(ctx, PR_2_INOREF_IN_UNUSED, &cd->pctx)){
				ext2fs_bg_itable_unused_set(fs, group, 0);
				ext2fs_mark_super_dirty(fs);
				ctx->flags |= E2F_FLAG_RESTART_LATER;
			} else {
				ext2fs_unmark_valid(fs);
				if (problem == PR_2_BAD_INO)
					goto next;
			}
		}

		/* 
		 * Offer to clear unused inodes; if we are going to be
		 * restarting the scan due to bg_itable_unused being
		 * wrong, then don't clear any inodes to avoid zapping
		 * inodes that were skipped during pass1 due to an
		 * incorrect bg_itable_unused; we'll get any real
		 * problems after we restart.
		 */
		if (!(ctx->flags & E2F_FLAG_RESTART_LATER) &&
		    !(ext2fs_test_inode_bitmap2(ctx->inode_used_map,
						dirent->inode)))
			problem = PR_2_UNUSED_INODE;

		if (problem) {
			if (fix_problem(ctx, problem, &cd->pctx)) {
				dirent->inode = 0;
				dir_modified++;
				goto next;
			} else {
				ext2fs_unmark_valid(fs);
				if (problem == PR_2_BAD_INO)
					goto next;
			}
		}

		if (check_name(ctx, dirent, ino, &cd->pctx))
			dir_modified++;

		if (check_filetype(ctx, dirent, ino, &cd->pctx))
			dir_modified++;

#ifdef ENABLE_HTREE
		if (dx_db) {
			ext2fs_dirhash(dx_dir->hashversion, dirent->name,
				       ext2fs_dirent_name_len(dirent),
				       fs->super->s_hash_seed, &hash, 0);
			if (hash < dx_db->min_hash)
				dx_db->min_hash = hash;
			if (hash > dx_db->max_hash)
				dx_db->max_hash = hash;
		}
#endif

		/*
		 * If this is a directory, then mark its parent in its
		 * dir_info structure.  If the parent field is already
		 * filled in, then this directory has more than one
		 * hard link.  We assume the first link is correct,
		 * and ask the user if he/she wants to clear this one.
		 */
		if ((dot_state > 1) &&
		    (ext2fs_test_inode_bitmap2(ctx->inode_dir_map,
					      dirent->inode))) {
			if (e2fsck_dir_info_get_parent(ctx, dirent->inode,
						       &subdir_parent)) {
				cd->pctx.ino = dirent->inode;
				fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
				goto abort_free_dict;
			}
			if (subdir_parent) {
				cd->pctx.ino2 = subdir_parent;
				if (fix_problem(ctx, PR_2_LINK_DIR,
						&cd->pctx)) {
					dirent->inode = 0;
					dir_modified++;
					goto next;
				}
				cd->pctx.ino2 = 0;
			} else {
				(void) e2fsck_dir_info_set_parent(ctx,
						  dirent->inode, ino);
			}
		}

		if (dups_found) {
			;
		} else if (dict_lookup(&de_dict, dirent)) {
			clear_problem_context(&pctx);
			pctx.ino = ino;
			pctx.dirent = dirent;
			fix_problem(ctx, PR_2_REPORT_DUP_DIRENT, &pctx);
			e2fsck_rehash_dir_later(ctx, ino);
			dups_found++;
		} else
			dict_alloc_insert(&de_dict, dirent, dirent);

		ext2fs_icount_increment(ctx->inode_count, dirent->inode,
					&links);
		if (links > 1)
			ctx->fs_links_count++;
		ctx->fs_total_count++;
	next:
		prev = dirent;
		if (dir_modified)
			(void) ext2fs_get_rec_len(fs, dirent, &rec_len);
		if (!inline_data_size || dot_state > 1) {
			offset += rec_len;
		} else {
			if (dot_state == 1)
				offset = 4;
		}
		dot_state++;
	} while (is_last_entry(fs, inline_data_size, offset, de_csum_size));
#if 0
	printf("\n");
#endif
#ifdef ENABLE_HTREE
	if (dx_db) {
#ifdef DX_DEBUG
		printf("db_block %d, type %d, min_hash 0x%0x, max_hash 0x%0x\n",
		       db->blockcnt, dx_db->type,
		       dx_db->min_hash, dx_db->max_hash);
#endif
		cd->pctx.dir = cd->pctx.ino;
		if ((dx_db->type == DX_DIRBLOCK_ROOT) ||
		    (dx_db->type == DX_DIRBLOCK_NODE))
			parse_int_node(fs, db, cd, dx_dir, buf, failed_csum);
	}
#endif /* ENABLE_HTREE */

	if (inline_data_size) {
		if (offset != inline_data_size) {
			cd->pctx.num = rec_len + offset - inline_data_size;
			if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
				dirent->rec_len = cd->pctx.num;
				dir_modified++;
			}
		}
	} else {
		if (offset != fs->blocksize - de_csum_size) {
			cd->pctx.num = rec_len - (fs->blocksize - de_csum_size) +
				       offset;
			if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
				dirent->rec_len = cd->pctx.num;
				dir_modified++;
			}
		}
	}
	if (dir_modified) {
		/* leaf block with no tail?  Rehash dirs later. */
		if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
				EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
		    is_leaf &&
		    !ext2fs_dirent_has_tail(fs, (struct ext2_dir_entry *)buf))
			e2fsck_rehash_dir_later(ctx, ino);

write_and_fix:
		if (e2fsck_dir_will_be_rehashed(ctx, ino))
			ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
		if (inline_data_size) {
			cd->pctx.errcode =
				ext2fs_inline_data_set(fs, ino, 0, buf,
						       inline_data_size);
		} else
			cd->pctx.errcode = ext2fs_write_dir_block4(fs, block_nr,
								   buf, 0, ino);
		if (e2fsck_dir_will_be_rehashed(ctx, ino))
			ctx->fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
		if (cd->pctx.errcode) {
			if (!fix_problem(ctx, PR_2_WRITE_DIRBLOCK,
					 &cd->pctx))
				goto abort_free_dict;
		}
		ext2fs_mark_changed(fs);
	} else if (is_leaf && failed_csum && !dir_modified) {
		/*
		 * If a leaf node that fails csum makes it this far without
		 * alteration, ask the user if the checksum should be fixed.
		 */
		if (fix_problem(ctx, PR_2_LEAF_NODE_ONLY_CSUM_INVALID,
				&cd->pctx))
			goto write_and_fix;
	}
	dict_free_nodes(&de_dict);
	return 0;
abort_free_dict:
	ctx->flags |= E2F_FLAG_ABORT;
	dict_free_nodes(&de_dict);
	return DIRENT_ABORT;
}
コード例 #12
0
ファイル: inline_data.c プロジェクト: kikimo/w4118-hmwk6
static errcode_t ext2fs_inline_data_convert_dir(ext2_filsys fs, ext2_ino_t ino,
        char *bbuf, char *ibuf, int size)
{
    struct ext2_dir_entry *dir, *dir2;
    struct ext2_dir_entry_tail *t;
    errcode_t retval;
    unsigned int offset, rec_len;
    int csum_size = 0;
    int filetype = 0;

    if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
                                   EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
        csum_size = sizeof(struct ext2_dir_entry_tail);

    /* Create '.' and '..' */
    if (EXT2_HAS_INCOMPAT_FEATURE(fs->super,
                                  EXT2_FEATURE_INCOMPAT_FILETYPE))
        filetype = EXT2_FT_DIR;

    /*
     * Set up entry for '.'
     */
    dir = (struct ext2_dir_entry *) bbuf;
    dir->inode = ino;
    ext2fs_dirent_set_name_len(dir, 1);
    ext2fs_dirent_set_file_type(dir, filetype);
    dir->name[0] = '.';
    rec_len = (fs->blocksize - csum_size) - EXT2_DIR_REC_LEN(1);
    dir->rec_len = EXT2_DIR_REC_LEN(1);

    /*
     * Set up entry for '..'
     */
    dir = (struct ext2_dir_entry *) (bbuf + dir->rec_len);
    dir->rec_len = EXT2_DIR_REC_LEN(2);
    dir->inode = ext2fs_le32_to_cpu(((__u32 *)ibuf)[0]);
    ext2fs_dirent_set_name_len(dir, 2);
    ext2fs_dirent_set_file_type(dir, filetype);
    dir->name[0] = '.';
    dir->name[1] = '.';

    /*
     * Ajust the last rec_len
     */
    offset = EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2);
    dir = (struct ext2_dir_entry *) (bbuf + offset);
    memcpy(bbuf + offset, ibuf + EXT4_INLINE_DATA_DOTDOT_SIZE,
           size - EXT4_INLINE_DATA_DOTDOT_SIZE);
    size += EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2) -
            EXT4_INLINE_DATA_DOTDOT_SIZE;

    do {
        dir2 = dir;
        retval = ext2fs_get_rec_len(fs, dir, &rec_len);
        if (retval)
            goto err;
        offset += rec_len;
        dir = (struct ext2_dir_entry *) (bbuf + offset);
    } while (offset < size);
    rec_len += fs->blocksize - csum_size - offset;
    retval = ext2fs_set_rec_len(fs, rec_len, dir2);
    if (retval)
        goto err;

    if (csum_size) {
        t = EXT2_DIRENT_TAIL(bbuf, fs->blocksize);
        ext2fs_initialize_dirent_tail(fs, t);
    }

err:
    return retval;
}
コード例 #13
0
ファイル: super.c プロジェクト: faddat/linux-mainline-next
static int ext2_fill_super(struct super_block *sb, void *data, int silent)
{
	struct buffer_head * bh;
	struct ext2_sb_info * sbi;
	struct ext2_super_block * es;
	struct inode *root;
	unsigned long block;
	unsigned long sb_block = get_sb_block(&data);
	unsigned long logic_sb_block;
	unsigned long offset = 0;
	unsigned long def_mount_opts;
	long ret = -EINVAL;
	int blocksize = BLOCK_SIZE;
	int db_count;
	int i, j;
	__le32 features;
	int err;

	err = -ENOMEM;
	sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
	if (!sbi)
		goto failed;

	sbi->s_blockgroup_lock =
		kzalloc(sizeof(struct blockgroup_lock), GFP_KERNEL);
	if (!sbi->s_blockgroup_lock) {
		kfree(sbi);
		goto failed;
	}
	sb->s_fs_info = sbi;
	sbi->s_sb_block = sb_block;

	spin_lock_init(&sbi->s_lock);

	/*
	 * See what the current blocksize for the device is, and
	 * use that as the blocksize.  Otherwise (or if the blocksize
	 * is smaller than the default) use the default.
	 * This is important for devices that have a hardware
	 * sectorsize that is larger than the default.
	 */
	blocksize = sb_min_blocksize(sb, BLOCK_SIZE);
	if (!blocksize) {
		ext2_msg(sb, KERN_ERR, "error: unable to set blocksize");
		goto failed_sbi;
	}

	/*
	 * If the superblock doesn't start on a hardware sector boundary,
	 * calculate the offset.  
	 */
	if (blocksize != BLOCK_SIZE) {
		logic_sb_block = (sb_block*BLOCK_SIZE) / blocksize;
		offset = (sb_block*BLOCK_SIZE) % blocksize;
	} else {
		logic_sb_block = sb_block;
	}

	if (!(bh = sb_bread(sb, logic_sb_block))) {
		ext2_msg(sb, KERN_ERR, "error: unable to read superblock");
		goto failed_sbi;
	}
	/*
	 * Note: s_es must be initialized as soon as possible because
	 *       some ext2 macro-instructions depend on its value
	 */
	es = (struct ext2_super_block *) (((char *)bh->b_data) + offset);
	sbi->s_es = es;
	sb->s_magic = le16_to_cpu(es->s_magic);

	if (sb->s_magic != EXT2_SUPER_MAGIC)
		goto cantfind_ext2;

	/* Set defaults before we parse the mount options */
	def_mount_opts = le32_to_cpu(es->s_default_mount_opts);
	if (def_mount_opts & EXT2_DEFM_DEBUG)
		set_opt(sbi->s_mount_opt, DEBUG);
	if (def_mount_opts & EXT2_DEFM_BSDGROUPS)
		set_opt(sbi->s_mount_opt, GRPID);
	if (def_mount_opts & EXT2_DEFM_UID16)
		set_opt(sbi->s_mount_opt, NO_UID32);
#ifdef CONFIG_EXT2_FS_XATTR
	if (def_mount_opts & EXT2_DEFM_XATTR_USER)
		set_opt(sbi->s_mount_opt, XATTR_USER);
#endif
#ifdef CONFIG_EXT2_FS_POSIX_ACL
	if (def_mount_opts & EXT2_DEFM_ACL)
		set_opt(sbi->s_mount_opt, POSIX_ACL);
#endif
	
	if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_PANIC)
		set_opt(sbi->s_mount_opt, ERRORS_PANIC);
	else if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_CONTINUE)
		set_opt(sbi->s_mount_opt, ERRORS_CONT);
	else
		set_opt(sbi->s_mount_opt, ERRORS_RO);

	sbi->s_resuid = make_kuid(&init_user_ns, le16_to_cpu(es->s_def_resuid));
	sbi->s_resgid = make_kgid(&init_user_ns, le16_to_cpu(es->s_def_resgid));
	
	set_opt(sbi->s_mount_opt, RESERVATION);

	if (!parse_options((char *) data, sb))
		goto failed_mount;

	sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
		((EXT2_SB(sb)->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ?
		 MS_POSIXACL : 0);
	sb->s_iflags |= SB_I_CGROUPWB;

	if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV &&
	    (EXT2_HAS_COMPAT_FEATURE(sb, ~0U) ||
	     EXT2_HAS_RO_COMPAT_FEATURE(sb, ~0U) ||
	     EXT2_HAS_INCOMPAT_FEATURE(sb, ~0U)))
		ext2_msg(sb, KERN_WARNING,
			"warning: feature flags set on rev 0 fs, "
			"running e2fsck is recommended");
	/*
	 * Check feature flags regardless of the revision level, since we
	 * previously didn't change the revision level when setting the flags,
	 * so there is a chance incompat flags are set on a rev 0 filesystem.
	 */
	features = EXT2_HAS_INCOMPAT_FEATURE(sb, ~EXT2_FEATURE_INCOMPAT_SUPP);
	if (features) {
		ext2_msg(sb, KERN_ERR,	"error: couldn't mount because of "
		       "unsupported optional features (%x)",
			le32_to_cpu(features));
		goto failed_mount;
	}
	if (!(sb->s_flags & MS_RDONLY) &&
	    (features = EXT2_HAS_RO_COMPAT_FEATURE(sb, ~EXT2_FEATURE_RO_COMPAT_SUPP))){
		ext2_msg(sb, KERN_ERR, "error: couldn't mount RDWR because of "
		       "unsupported optional features (%x)",
		       le32_to_cpu(features));
		goto failed_mount;
	}

	blocksize = BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size);

	if (sbi->s_mount_opt & EXT2_MOUNT_DAX) {
		struct blk_dax_ctl dax = {
			.sector = 0,
			.size = PAGE_SIZE,
		};
		if (blocksize != PAGE_SIZE) {
			ext2_msg(sb, KERN_ERR,
					"error: unsupported blocksize for dax");
			goto failed_mount;
		}
		err = bdev_direct_access(sb->s_bdev, &dax);
		if (err < 0) {
			switch (err) {
			case -EOPNOTSUPP:
				ext2_msg(sb, KERN_ERR,
					"error: device does not support dax");
				break;
			case -EINVAL:
				ext2_msg(sb, KERN_ERR,
					"error: unaligned partition for dax");
				break;
			default:
				ext2_msg(sb, KERN_ERR,
					"error: dax access failed (%d)", err);
				break;
			}
			goto failed_mount;
		}
	}

	/* If the blocksize doesn't match, re-read the thing.. */
	if (sb->s_blocksize != blocksize) {
		brelse(bh);

		if (!sb_set_blocksize(sb, blocksize)) {
			ext2_msg(sb, KERN_ERR,
				"error: bad blocksize %d", blocksize);
			goto failed_sbi;
		}

		logic_sb_block = (sb_block*BLOCK_SIZE) / blocksize;
		offset = (sb_block*BLOCK_SIZE) % blocksize;
		bh = sb_bread(sb, logic_sb_block);
		if(!bh) {
			ext2_msg(sb, KERN_ERR, "error: couldn't read"
				"superblock on 2nd try");
			goto failed_sbi;
		}
		es = (struct ext2_super_block *) (((char *)bh->b_data) + offset);
		sbi->s_es = es;
		if (es->s_magic != cpu_to_le16(EXT2_SUPER_MAGIC)) {
			ext2_msg(sb, KERN_ERR, "error: magic mismatch");
			goto failed_mount;
		}
	}

	sb->s_maxbytes = ext2_max_size(sb->s_blocksize_bits);
	sb->s_max_links = EXT2_LINK_MAX;

	if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV) {
		sbi->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;
		sbi->s_first_ino = EXT2_GOOD_OLD_FIRST_INO;
	} else {
		sbi->s_inode_size = le16_to_cpu(es->s_inode_size);
		sbi->s_first_ino = le32_to_cpu(es->s_first_ino);
		if ((sbi->s_inode_size < EXT2_GOOD_OLD_INODE_SIZE) ||
		    !is_power_of_2(sbi->s_inode_size) ||
		    (sbi->s_inode_size > blocksize)) {
			ext2_msg(sb, KERN_ERR,
				"error: unsupported inode size: %d",
				sbi->s_inode_size);
			goto failed_mount;
		}
	}

	sbi->s_frag_size = EXT2_MIN_FRAG_SIZE <<
				   le32_to_cpu(es->s_log_frag_size);
	if (sbi->s_frag_size == 0)
		goto cantfind_ext2;
	sbi->s_frags_per_block = sb->s_blocksize / sbi->s_frag_size;

	sbi->s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group);
	sbi->s_frags_per_group = le32_to_cpu(es->s_frags_per_group);
	sbi->s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group);

	if (EXT2_INODE_SIZE(sb) == 0)
		goto cantfind_ext2;
	sbi->s_inodes_per_block = sb->s_blocksize / EXT2_INODE_SIZE(sb);
	if (sbi->s_inodes_per_block == 0 || sbi->s_inodes_per_group == 0)
		goto cantfind_ext2;
	sbi->s_itb_per_group = sbi->s_inodes_per_group /
					sbi->s_inodes_per_block;
	sbi->s_desc_per_block = sb->s_blocksize /
					sizeof (struct ext2_group_desc);
	sbi->s_sbh = bh;
	sbi->s_mount_state = le16_to_cpu(es->s_state);
	sbi->s_addr_per_block_bits =
		ilog2 (EXT2_ADDR_PER_BLOCK(sb));
	sbi->s_desc_per_block_bits =
		ilog2 (EXT2_DESC_PER_BLOCK(sb));

	if (sb->s_magic != EXT2_SUPER_MAGIC)
		goto cantfind_ext2;

	if (sb->s_blocksize != bh->b_size) {
		if (!silent)
			ext2_msg(sb, KERN_ERR, "error: unsupported blocksize");
		goto failed_mount;
	}

	if (sb->s_blocksize != sbi->s_frag_size) {
		ext2_msg(sb, KERN_ERR,
			"error: fragsize %lu != blocksize %lu"
			"(not supported yet)",
			sbi->s_frag_size, sb->s_blocksize);
		goto failed_mount;
	}

	if (sbi->s_blocks_per_group > sb->s_blocksize * 8) {
		ext2_msg(sb, KERN_ERR,
			"error: #blocks per group too big: %lu",
			sbi->s_blocks_per_group);
		goto failed_mount;
	}
	if (sbi->s_frags_per_group > sb->s_blocksize * 8) {
		ext2_msg(sb, KERN_ERR,
			"error: #fragments per group too big: %lu",
			sbi->s_frags_per_group);
		goto failed_mount;
	}
	if (sbi->s_inodes_per_group > sb->s_blocksize * 8) {
		ext2_msg(sb, KERN_ERR,
			"error: #inodes per group too big: %lu",
			sbi->s_inodes_per_group);
		goto failed_mount;
	}

	if (EXT2_BLOCKS_PER_GROUP(sb) == 0)
		goto cantfind_ext2;
 	sbi->s_groups_count = ((le32_to_cpu(es->s_blocks_count) -
 				le32_to_cpu(es->s_first_data_block) - 1)
 					/ EXT2_BLOCKS_PER_GROUP(sb)) + 1;
	db_count = (sbi->s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) /
		   EXT2_DESC_PER_BLOCK(sb);
	sbi->s_group_desc = kmalloc (db_count * sizeof (struct buffer_head *), GFP_KERNEL);
	if (sbi->s_group_desc == NULL) {
		ext2_msg(sb, KERN_ERR, "error: not enough memory");
		goto failed_mount;
	}
	bgl_lock_init(sbi->s_blockgroup_lock);
	sbi->s_debts = kcalloc(sbi->s_groups_count, sizeof(*sbi->s_debts), GFP_KERNEL);
	if (!sbi->s_debts) {
		ext2_msg(sb, KERN_ERR, "error: not enough memory");
		goto failed_mount_group_desc;
	}
	for (i = 0; i < db_count; i++) {
		block = descriptor_loc(sb, logic_sb_block, i);
		sbi->s_group_desc[i] = sb_bread(sb, block);
		if (!sbi->s_group_desc[i]) {
			for (j = 0; j < i; j++)
				brelse (sbi->s_group_desc[j]);
			ext2_msg(sb, KERN_ERR,
				"error: unable to read group descriptors");
			goto failed_mount_group_desc;
		}
	}
	if (!ext2_check_descriptors (sb)) {
		ext2_msg(sb, KERN_ERR, "group descriptors corrupted");
		goto failed_mount2;
	}
	sbi->s_gdb_count = db_count;
	get_random_bytes(&sbi->s_next_generation, sizeof(u32));
	spin_lock_init(&sbi->s_next_gen_lock);

	/* per fileystem reservation list head & lock */
	spin_lock_init(&sbi->s_rsv_window_lock);
	sbi->s_rsv_window_root = RB_ROOT;
	/*
	 * Add a single, static dummy reservation to the start of the
	 * reservation window list --- it gives us a placeholder for
	 * append-at-start-of-list which makes the allocation logic
	 * _much_ simpler.
	 */
	sbi->s_rsv_window_head.rsv_start = EXT2_RESERVE_WINDOW_NOT_ALLOCATED;
	sbi->s_rsv_window_head.rsv_end = EXT2_RESERVE_WINDOW_NOT_ALLOCATED;
	sbi->s_rsv_window_head.rsv_alloc_hit = 0;
	sbi->s_rsv_window_head.rsv_goal_size = 0;
	ext2_rsv_window_add(sb, &sbi->s_rsv_window_head);

	err = percpu_counter_init(&sbi->s_freeblocks_counter,
				ext2_count_free_blocks(sb), GFP_KERNEL);
	if (!err) {
		err = percpu_counter_init(&sbi->s_freeinodes_counter,
				ext2_count_free_inodes(sb), GFP_KERNEL);
	}
	if (!err) {
		err = percpu_counter_init(&sbi->s_dirs_counter,
				ext2_count_dirs(sb), GFP_KERNEL);
	}
	if (err) {
		ext2_msg(sb, KERN_ERR, "error: insufficient memory");
		goto failed_mount3;
	}

#ifdef CONFIG_EXT2_FS_XATTR
	sbi->s_mb_cache = ext2_xattr_create_cache();
	if (!sbi->s_mb_cache) {
		ext2_msg(sb, KERN_ERR, "Failed to create an mb_cache");
		goto failed_mount3;
	}
#endif
	/*
	 * set up enough so that it can read an inode
	 */
	sb->s_op = &ext2_sops;
	sb->s_export_op = &ext2_export_ops;
	sb->s_xattr = ext2_xattr_handlers;

#ifdef CONFIG_QUOTA
	sb->dq_op = &dquot_operations;
	sb->s_qcop = &dquot_quotactl_ops;
	sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP;
#endif

	root = ext2_iget(sb, EXT2_ROOT_INO);
	if (IS_ERR(root)) {
		ret = PTR_ERR(root);
		goto failed_mount3;
	}
	if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
		iput(root);
		ext2_msg(sb, KERN_ERR, "error: corrupt root inode, run e2fsck");
		goto failed_mount3;
	}

	sb->s_root = d_make_root(root);
	if (!sb->s_root) {
		ext2_msg(sb, KERN_ERR, "error: get root inode failed");
		ret = -ENOMEM;
		goto failed_mount3;
	}
	if (EXT2_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL))
		ext2_msg(sb, KERN_WARNING,
			"warning: mounting ext3 filesystem as ext2");
	if (ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY))
		sb->s_flags |= MS_RDONLY;
	ext2_write_super(sb);
	return 0;

cantfind_ext2:
	if (!silent)
		ext2_msg(sb, KERN_ERR,
			"error: can't find an ext2 filesystem on dev %s.",
			sb->s_id);
	goto failed_mount;
failed_mount3:
	if (sbi->s_mb_cache)
		ext2_xattr_destroy_cache(sbi->s_mb_cache);
	percpu_counter_destroy(&sbi->s_freeblocks_counter);
	percpu_counter_destroy(&sbi->s_freeinodes_counter);
	percpu_counter_destroy(&sbi->s_dirs_counter);
failed_mount2:
	for (i = 0; i < db_count; i++)
		brelse(sbi->s_group_desc[i]);
failed_mount_group_desc:
	kfree(sbi->s_group_desc);
	kfree(sbi->s_debts);
failed_mount:
	brelse(bh);
failed_sbi:
	sb->s_fs_info = NULL;
	kfree(sbi->s_blockgroup_lock);
	kfree(sbi);
failed:
	return ret;
}

static void ext2_clear_super_error(struct super_block *sb)
{
	struct buffer_head *sbh = EXT2_SB(sb)->s_sbh;

	if (buffer_write_io_error(sbh)) {
		/*
		 * Oh, dear.  A previous attempt to write the
		 * superblock failed.  This could happen because the
		 * USB device was yanked out.  Or it could happen to
		 * be a transient write error and maybe the block will
		 * be remapped.  Nothing we can do but to retry the
		 * write and hope for the best.
		 */
		ext2_msg(sb, KERN_ERR,
		       "previous I/O error to superblock detected\n");
		clear_buffer_write_io_error(sbh);
		set_buffer_uptodate(sbh);
	}
}

static void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es,
			    int wait)
{
	ext2_clear_super_error(sb);
	spin_lock(&EXT2_SB(sb)->s_lock);
	es->s_free_blocks_count = cpu_to_le32(ext2_count_free_blocks(sb));
	es->s_free_inodes_count = cpu_to_le32(ext2_count_free_inodes(sb));
	es->s_wtime = cpu_to_le32(get_seconds());
	/* unlock before we do IO */
	spin_unlock(&EXT2_SB(sb)->s_lock);
	mark_buffer_dirty(EXT2_SB(sb)->s_sbh);
	if (wait)
		sync_dirty_buffer(EXT2_SB(sb)->s_sbh);
}
コード例 #14
0
ファイル: mk_hugefiles.c プロジェクト: timofonic/WinFLASHTool
errcode_t mk_hugefiles(ext2_filsys fs, const char *device_name)
{
    unsigned long	i;
    ext2_ino_t	dir;
    errcode_t	retval;
    blk64_t		fs_blocks, part_offset = 0;
    unsigned long	align;
    int		d, dsize;
    char		*t;

    if (!get_bool_from_profile(fs_types, "make_hugefiles", 0))
        return 0;

    if (!EXT2_HAS_INCOMPAT_FEATURE(fs->super,
                                   EXT3_FEATURE_INCOMPAT_EXTENTS))
        return EXT2_ET_EXTENT_NOT_SUPPORTED;

    uid = get_int_from_profile(fs_types, "hugefiles_uid", 0);
    gid = get_int_from_profile(fs_types, "hugefiles_gid", 0);
    fs->umask = get_int_from_profile(fs_types, "hugefiles_umask", 077);
    num_files = get_int_from_profile(fs_types, "num_hugefiles", 0);
    t = get_string_from_profile(fs_types, "hugefiles_slack", "1M");
    num_slack = parse_num_blocks2(t, fs->super->s_log_block_size);
    free(t);
    t = get_string_from_profile(fs_types, "hugefiles_size", "0");
    num_blocks = parse_num_blocks2(t, fs->super->s_log_block_size);
    free(t);
    t = get_string_from_profile(fs_types, "hugefiles_align", "0");
    align = parse_num_blocks2(t, fs->super->s_log_block_size);
    free(t);
    if (get_bool_from_profile(fs_types, "hugefiles_align_disk", 0)) {
        part_offset = get_partition_start(device_name) /
                      (fs->blocksize / 512);
        if (part_offset % EXT2FS_CLUSTER_RATIO(fs)) {
            fprintf(stderr,
                    _("Partition offset of %llu (%uk) blocks "
                      "not compatible with cluster size %u.\n"),
                    part_offset, fs->blocksize,
                    EXT2_CLUSTER_SIZE(fs->super));
            exit(1);
        }
    }
    num_blocks = round_up_align(num_blocks, align, 0);
    zero_hugefile = get_bool_from_profile(fs_types, "zero_hugefiles",
                                          zero_hugefile);

    t = get_string_from_profile(fs_types, "hugefiles_dir", "/");
    retval = create_directory(fs, t, &dir);
    free(t);
    if (retval)
        return retval;

    fn_prefix = get_string_from_profile(fs_types, "hugefiles_name",
                                        "hugefile");
    idx_digits = get_int_from_profile(fs_types, "hugefiles_digits", 5);
    d = int_log10(num_files) + 1;
    if (idx_digits > d)
        d = idx_digits;
    dsize = strlen(fn_prefix) + d + 16;
    fn_buf = malloc(dsize);
    if (!fn_buf) {
        free(fn_prefix);
        return ENOMEM;
    }
    strcpy(fn_buf, fn_prefix);
    fn_numbuf = fn_buf + strlen(fn_prefix);
    free(fn_prefix);

    fs_blocks = ext2fs_free_blocks_count(fs->super);
    if (fs_blocks < num_slack + align)
        return ENOSPC;
    fs_blocks -= num_slack + align;
    if (num_blocks && num_blocks > fs_blocks)
        return ENOSPC;
    if (num_blocks == 0 && num_files == 0)
        num_files = 1;

    if (num_files == 0 && num_blocks) {
        num_files = fs_blocks / num_blocks;
        fs_blocks -= (num_files / 16) + 1;
        fs_blocks -= calc_overhead(fs, num_blocks) * num_files;
        num_files = fs_blocks / num_blocks;
    }

    if (num_blocks == 0 && num_files > 1) {
        num_blocks = fs_blocks / num_files;
        fs_blocks -= (num_files / 16) + 1;
        fs_blocks -= calc_overhead(fs, num_blocks) * num_files;
        num_blocks = fs_blocks / num_files;
    }

    num_slack += calc_overhead(fs, num_blocks) * num_files;
    num_slack += (num_files / 16) + 1; /* space for dir entries */
    goal = get_start_block(fs, num_slack);
    goal = round_up_align(goal, align, part_offset);

    if ((num_blocks ? num_blocks : fs_blocks) >
            (0x80000000UL / fs->blocksize))
        fs->super->s_feature_ro_compat |=
            EXT2_FEATURE_RO_COMPAT_LARGE_FILE;

    if (!quiet) {
        if (zero_hugefile && verbose)
            printf("%s", _("Huge files will be zero'ed\n"));
        printf(_("Creating %lu huge file(s) "), num_files);
        if (num_blocks)
            printf(_("with %llu blocks each"), num_blocks);
        fputs(": ", stdout);
    }
    if (num_blocks == 0)
        num_blocks = ext2fs_blocks_count(fs->super) - goal;
    for (i=0; i < num_files; i++) {
        ext2_ino_t ino;

        retval = mk_hugefile(fs, num_blocks, dir, i, &ino);
        if (retval) {
            com_err(program_name, retval,
                    _("while creating huge file %lu"), i);
            goto errout;
        }
    }
    if (!quiet)
        fputs(_("done\n"), stdout);

errout:
    free(fn_buf);
    return retval;
}
コード例 #15
0
errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group,
				      ext2fs_block_bitmap bmap)
{
	errcode_t	retval;
	blk_t		group_blk, start_blk, last_blk, new_blk, blk;
	dgrp_t		last_grp = 0;
	int		j, rem_grps = 0, flexbg_size = 0;

	group_blk = ext2fs_group_first_block(fs, group);
	last_blk = ext2fs_group_last_block(fs, group);

	if (!bmap)
		bmap = fs->block_map;

	if (EXT2_HAS_INCOMPAT_FEATURE(fs->super,
				      EXT4_FEATURE_INCOMPAT_FLEX_BG) &&
	    fs->super->s_log_groups_per_flex) {
		flexbg_size = 1 << fs->super->s_log_groups_per_flex;
		last_grp = group | (flexbg_size - 1);
		rem_grps = last_grp - group;
		if (last_grp > fs->group_desc_count)
			last_grp = fs->group_desc_count;
	}

	/*
	 * Allocate the block and inode bitmaps, if necessary
	 */
	if (fs->stride) {
		retval = ext2fs_get_free_blocks(fs, group_blk, last_blk,
						1, bmap, &start_blk);
		if (retval)
			return retval;
		start_blk += fs->inode_blocks_per_group;
		start_blk += ((fs->stride * group) %
			      (last_blk - start_blk + 1));
		if (start_blk >= last_blk)
			start_blk = group_blk;
	} else
		start_blk = group_blk;

	if (flexbg_size) {
		blk64_t prev_block = 0;

		if (group && fs->group_desc[group-1].bg_block_bitmap)
			prev_block = fs->group_desc[group-1].bg_block_bitmap;
		start_blk = flexbg_offset(fs, group, prev_block, bmap,
						 0, rem_grps, 1);
		last_blk = ext2fs_group_last_block(fs, last_grp);
	}

	if (!fs->group_desc[group].bg_block_bitmap) {
		retval = ext2fs_get_free_blocks(fs, start_blk, last_blk,
						1, bmap, &new_blk);
		if (retval == EXT2_ET_BLOCK_ALLOC_FAIL)
			retval = ext2fs_get_free_blocks(fs, group_blk,
					last_blk, 1, bmap, &new_blk);
		if (retval)
			return retval;
		ext2fs_mark_block_bitmap2(bmap, new_blk);
		fs->group_desc[group].bg_block_bitmap = new_blk;
		if (flexbg_size) {
			dgrp_t gr = ext2fs_group_of_blk(fs, new_blk);
			fs->group_desc[gr].bg_free_blocks_count--;
			fs->super->s_free_blocks_count--;
			fs->group_desc[gr].bg_flags &= ~EXT2_BG_BLOCK_UNINIT;
			ext2fs_group_desc_csum_set(fs, gr);
		}
	}

	if (flexbg_size) {
		blk_t prev_block = 0;
		if (group && fs->group_desc[group-1].bg_inode_bitmap)
			prev_block = fs->group_desc[group-1].bg_inode_bitmap;
		start_blk = flexbg_offset(fs, group, prev_block, bmap,
						 flexbg_size, rem_grps, 1);
		last_blk = ext2fs_group_last_block(fs, last_grp);
	}

	if (!fs->group_desc[group].bg_inode_bitmap) {
		retval = ext2fs_get_free_blocks(fs, start_blk, last_blk,
						1, bmap, &new_blk);
		if (retval == EXT2_ET_BLOCK_ALLOC_FAIL)
			retval = ext2fs_get_free_blocks(fs, group_blk,
					last_blk, 1, bmap, &new_blk);
		if (retval)
			return retval;
		ext2fs_mark_block_bitmap2(bmap, new_blk);
		fs->group_desc[group].bg_inode_bitmap = new_blk;
		if (flexbg_size) {
			dgrp_t gr = ext2fs_group_of_blk(fs, new_blk);
			fs->group_desc[gr].bg_free_blocks_count--;
			fs->super->s_free_blocks_count--;
			fs->group_desc[gr].bg_flags &= ~EXT2_BG_BLOCK_UNINIT;
			ext2fs_group_desc_csum_set(fs, gr);
		}
	}

	/*
	 * Allocate the inode table
	 */
	if (flexbg_size) {
		blk_t prev_block = 0;
		if (group && fs->group_desc[group-1].bg_inode_table)
			prev_block = fs->group_desc[group-1].bg_inode_table;
		group_blk = flexbg_offset(fs, group, prev_block, bmap,
						 flexbg_size * 2,
						 fs->inode_blocks_per_group *
						 rem_grps,
						 fs->inode_blocks_per_group);
		last_blk = ext2fs_group_last_block(fs, last_grp);
	}

	if (!fs->group_desc[group].bg_inode_table) {
		retval = ext2fs_get_free_blocks(fs, group_blk, last_blk,
						fs->inode_blocks_per_group,
						bmap, &new_blk);
		if (retval)
			return retval;
		for (j=0, blk = new_blk;
		     j < fs->inode_blocks_per_group;
		     j++, blk++) {
			ext2fs_mark_block_bitmap2(bmap, blk);
			if (flexbg_size) {
				dgrp_t gr = ext2fs_group_of_blk(fs, blk);
				fs->group_desc[gr].bg_free_blocks_count--;
				fs->super->s_free_blocks_count--;
				fs->group_desc[gr].bg_flags &= ~EXT2_BG_BLOCK_UNINIT;
				ext2fs_group_desc_csum_set(fs, gr);
			}
		}
		fs->group_desc[group].bg_inode_table = new_blk;
	}
	ext2fs_group_desc_csum_set(fs, group);
	return 0;
}
コード例 #16
0
ファイル: ext2_lookup.c プロジェクト: AhmadTux/DragonFlyBSD
/*
 * Write a directory entry after a call to namei, using the parameters
 * that it left in the directory inode.  The argument ip is the inode which
 * the new directory entry will refer to.  Dvp is a pointer to the directory
 * to be written, which was left locked by namei. Remaining parameters
 * (dp->i_offset, dp->i_count) indicate how the space for the new
 * entry is to be obtained.
 */
int
ext2_direnter(struct inode *ip, struct vnode *dvp, struct componentname *cnp)
{
	struct ext2_dir_entry_2 *ep, *nep;
	struct inode *dp;
	struct buf *bp;
	struct ext2_dir_entry_2 newdir;
	struct iovec aiov;
	struct uio auio;
	u_int dsize;
	int error, loc, newentrysize, spacefree;
	char *dirbuf;
	int     DIRBLKSIZ = ip->i_e2fs->s_blocksize;


	dp = VTOI(dvp);
	newdir.inode = ip->i_number;
	newdir.name_len = cnp->cn_namelen;
	if (EXT2_HAS_INCOMPAT_FEATURE(ip->i_e2fs->s_es,
	    EXT2_FEATURE_INCOMPAT_FILETYPE))
		newdir.file_type = DTTOFT(IFTODT(ip->i_mode));
	else
		newdir.file_type = EXT2_FT_UNKNOWN;
	bcopy(cnp->cn_nameptr, newdir.name, (unsigned)cnp->cn_namelen + 1);
	newentrysize = EXT2_DIR_REC_LEN(newdir.name_len);
	if (dp->i_count == 0) {
		/*
		 * If dp->i_count is 0, then namei could find no
		 * space in the directory. Here, dp->i_offset will
		 * be on a directory block boundary and we will write the
		 * new entry into a fresh block.
		 */
		if (dp->i_offset & (DIRBLKSIZ - 1))
			panic("ext2_direnter: newblk");
		auio.uio_offset = dp->i_offset;
		newdir.rec_len = DIRBLKSIZ;
		auio.uio_resid = newentrysize;
		aiov.iov_len = newentrysize;
		aiov.iov_base = (caddr_t)&newdir;
		auio.uio_iov = &aiov;
		auio.uio_iovcnt = 1;
		auio.uio_rw = UIO_WRITE;
		auio.uio_segflg = UIO_SYSSPACE;
		auio.uio_td = NULL;
		error = VOP_WRITE(dvp, &auio, IO_SYNC, cnp->cn_cred);
		if (DIRBLKSIZ >
		    VFSTOEXT2(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
			/* XXX should grow with balloc() */
			panic("ext2_direnter: frag size");
		else if (!error) {
			dp->i_size = roundup(dp->i_size, DIRBLKSIZ);
			dp->i_flag |= IN_CHANGE;
		}
		return (error);
	}

	/*
	 * If dp->i_count is non-zero, then namei found space
	 * for the new entry in the range dp->i_offset to
	 * dp->i_offset + dp->i_count in the directory.
	 * To use this space, we may have to compact the entries located
	 * there, by copying them together towards the beginning of the
	 * block, leaving the free space in one usable chunk at the end.
	 */

	/*
	 * Increase size of directory if entry eats into new space.
	 * This should never push the size past a new multiple of
	 * DIRBLKSIZE.
	 *
	 * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN.
	 */
	if (dp->i_offset + dp->i_count > dp->i_size)
		dp->i_size = dp->i_offset + dp->i_count;
	/*
	 * Get the block containing the space for the new directory entry.
	 */
	if ((error = EXT2_BLKATOFF(dvp, (off_t)dp->i_offset, &dirbuf, &bp)) != 0)
		return (error);
	/*
	 * Find space for the new entry. In the simple case, the entry at
	 * offset base will have the space. If it does not, then namei
	 * arranged that compacting the region dp->i_offset to
	 * dp->i_offset + dp->i_count would yield the
	 * space.
	 */
	ep = (struct ext2_dir_entry_2 *)dirbuf;
	dsize = EXT2_DIR_REC_LEN(ep->name_len);
	spacefree = ep->rec_len - dsize;
	for (loc = ep->rec_len; loc < dp->i_count; ) {
		nep = (struct ext2_dir_entry_2 *)(dirbuf + loc);
		if (ep->inode) {
			/* trim the existing slot */
			ep->rec_len = dsize;
			ep = (struct ext2_dir_entry_2 *)((char *)ep + dsize);
		} else {
			/* overwrite; nothing there; header is ours */
			spacefree += dsize;
		}
		dsize = EXT2_DIR_REC_LEN(nep->name_len);
		spacefree += nep->rec_len - dsize;
		loc += nep->rec_len;
		bcopy((caddr_t)nep, (caddr_t)ep, dsize);
	}
	/*
	 * Update the pointer fields in the previous entry (if any),
	 * copy in the new entry, and write out the block.
	 */
	if (ep->inode == 0) {
		if (spacefree + dsize < newentrysize)
			panic("ext2_direnter: compact1");
		newdir.rec_len = spacefree + dsize;
	} else {
		if (spacefree < newentrysize)
			panic("ext2_direnter: compact2");
		newdir.rec_len = spacefree;
		ep->rec_len = dsize;
		ep = (struct ext2_dir_entry_2 *)((char *)ep + dsize);
	}
	bcopy((caddr_t)&newdir, (caddr_t)ep, (u_int)newentrysize);
	error = bwrite(bp);
	dp->i_flag |= IN_CHANGE | IN_UPDATE;
	if (!error && dp->i_endoff && dp->i_endoff < dp->i_size)
		error = EXT2_TRUNCATE(dvp, (off_t)dp->i_endoff, IO_SYNC,
				      cnp->cn_cred);
	return (error);
}
コード例 #17
0
/*
 * Mkdir system call
 */
static int
ext2_mkdir(struct vop_mkdir_args *ap)
{
	struct vnode *dvp = ap->a_dvp;
	struct vattr *vap = ap->a_vap;
	struct componentname *cnp = ap->a_cnp;
	struct inode *ip, *dp;
	struct vnode *tvp;
	struct dirtemplate dirtemplate, *dtp;
	int error, dmode;

#ifdef DIAGNOSTIC
	if ((cnp->cn_flags & HASBUF) == 0)
		panic("ext2_mkdir: no name");
#endif
	dp = VTOI(dvp);
	if ((nlink_t)dp->i_nlink >= EXT2_LINK_MAX) {
		error = EMLINK;
		goto out;
	}
	dmode = vap->va_mode & 0777;
	dmode |= IFDIR;
	/*
	 * Must simulate part of ext2_makeinode here to acquire the inode,
	 * but not have it entered in the parent directory. The entry is
	 * made later after writing "." and ".." entries.
	 */
	error = ext2_valloc(dvp, dmode, cnp->cn_cred, &tvp);
	if (error)
		goto out;
	ip = VTOI(tvp);
	ip->i_gid = dp->i_gid;
#ifdef SUIDDIR
	{
		/*
		 * if we are hacking owners here, (only do this where told to)
		 * and we are not giving it TOO root, (would subvert quotas)
		 * then go ahead and give it to the other user.
		 * The new directory also inherits the SUID bit. 
		 * If user's UID and dir UID are the same,
		 * 'give it away' so that the SUID is still forced on.
		 */
		if ( (dvp->v_mount->mnt_flag & MNT_SUIDDIR) &&
		   (dp->i_mode & ISUID) && dp->i_uid) {
			dmode |= ISUID;
			ip->i_uid = dp->i_uid;
		} else {
			ip->i_uid = cnp->cn_cred->cr_uid;
		}
	}
#else
	ip->i_uid = cnp->cn_cred->cr_uid;
#endif
	ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
	ip->i_mode = dmode;
	tvp->v_type = VDIR;	/* Rest init'd in getnewvnode(). */
	ip->i_nlink = 2;
	if (cnp->cn_flags & ISWHITEOUT)
		ip->i_flags |= UF_OPAQUE;
	error = ext2_update(tvp, 1);

	/*
	 * Bump link count in parent directory
	 * to reflect work done below.  Should
	 * be done before reference is created
	 * so reparation is possible if we crash.
	 */
	dp->i_nlink++;
	dp->i_flag |= IN_CHANGE;
	error = ext2_update(dvp, !DOINGASYNC(dvp));
	if (error)
		goto bad;

	/* Initialize directory with "." and ".." from static template. */
	if (EXT2_HAS_INCOMPAT_FEATURE(ip->i_e2fs,
	    EXT2F_INCOMPAT_FTYPE))
		dtp = &mastertemplate;
	else
		dtp = &omastertemplate;
	dirtemplate = *dtp;
	dirtemplate.dot_ino = ip->i_number;
	dirtemplate.dotdot_ino = dp->i_number;
	/* note that in ext2 DIRBLKSIZ == blocksize, not DEV_BSIZE 
	 * so let's just redefine it - for this function only
	 */
#undef  DIRBLKSIZ 
#define DIRBLKSIZ  VTOI(dvp)->i_e2fs->e2fs_bsize
	dirtemplate.dotdot_reclen = DIRBLKSIZ - 12;
	error = vn_rdwr(UIO_WRITE, tvp, (caddr_t)&dirtemplate,
	    sizeof(dirtemplate), (off_t)0, UIO_SYSSPACE,
	    IO_NODELOCKED | IO_SYNC | IO_NOMACCHECK, cnp->cn_cred, NOCRED,
	    NULL, NULL);
	if (error) {
		dp->i_nlink--;
		dp->i_flag |= IN_CHANGE;
		goto bad;
	}
	if (DIRBLKSIZ > VFSTOEXT2(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
		/* XXX should grow with balloc() */
		panic("ext2_mkdir: blksize");
	else {
		ip->i_size = DIRBLKSIZ;
		ip->i_flag |= IN_CHANGE;
	}

	/* Directory set up, now install its entry in the parent directory. */
	error = ext2_direnter(ip, dvp, cnp);
	if (error) {
		dp->i_nlink--;
		dp->i_flag |= IN_CHANGE;
	}
bad:
	/*
	 * No need to do an explicit VOP_TRUNCATE here, vrele will do this
	 * for us because we set the link count to 0.
	 */
	if (error) {
		ip->i_nlink = 0;
		ip->i_flag |= IN_CHANGE;
		vput(tvp);
	} else
		*ap->a_vpp = tvp;
out:
	return (error);
#undef  DIRBLKSIZ
#define DIRBLKSIZ  DEV_BSIZE
}
コード例 #18
0
ファイル: super.c プロジェクト: JBTech/ralink_rt5350
struct super_block * ext2_read_super (struct super_block * sb, void * data,
				      int silent)
{
	struct buffer_head * bh;
  	struct ext2_sb_info * sbi = EXT2_SB(sb);
	struct ext2_super_block * es;
	unsigned long sb_block = 1;
	unsigned short resuid = EXT2_DEF_RESUID;
	unsigned short resgid = EXT2_DEF_RESGID;
	unsigned long block;
	unsigned long logic_sb_block;
	unsigned long offset = 0;
	kdev_t dev = sb->s_dev;
	int blocksize = BLOCK_SIZE;
	int db_count;
	int i, j;

	/*
	 * See what the current blocksize for the device is, and
	 * use that as the blocksize.  Otherwise (or if the blocksize
	 * is smaller than the default) use the default.
	 * This is important for devices that have a hardware
	 * sectorsize that is larger than the default.
	 */
	blocksize = get_hardsect_size(dev);
	if(blocksize < BLOCK_SIZE )
	    blocksize = BLOCK_SIZE;

	sb->u.ext2_sb.s_mount_opt = 0;
	if (!parse_options ((char *) data, &sb_block, &resuid, &resgid,
	    &sb->u.ext2_sb.s_mount_opt)) {
		return NULL;
	}

	if (set_blocksize(dev, blocksize) < 0) {
		printk ("EXT2-fs: unable to set blocksize %d\n", blocksize);
		return NULL;
	}
	sb->s_blocksize = blocksize;

	/*
	 * If the superblock doesn't start on a sector boundary,
	 * calculate the offset.  FIXME(eric) this doesn't make sense
	 * that we would have to do this.
	 */
	if (blocksize != BLOCK_SIZE) {
		logic_sb_block = (sb_block*BLOCK_SIZE) / blocksize;
		offset = (sb_block*BLOCK_SIZE) % blocksize;
	} else {
		logic_sb_block = sb_block;
	}

	if (!(bh = sb_bread(sb, logic_sb_block))) {
		printk ("EXT2-fs: unable to read superblock\n");
		return NULL;
	}
	/*
	 * Note: s_es must be initialized as soon as possible because
	 *       some ext2 macro-instructions depend on its value
	 */
	es = (struct ext2_super_block *) (((char *)bh->b_data) + offset);
	sb->u.ext2_sb.s_es = es;
	sb->s_magic = le16_to_cpu(es->s_magic);
	if (sb->s_magic != EXT2_SUPER_MAGIC) {
		if (!silent)
			printk ("VFS: Can't find ext2 filesystem on dev %s.\n",
				bdevname(dev));
		goto failed_mount;
	}
	if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV &&
	    (EXT2_HAS_COMPAT_FEATURE(sb, ~0U) ||
	     EXT2_HAS_RO_COMPAT_FEATURE(sb, ~0U) ||
	     EXT2_HAS_INCOMPAT_FEATURE(sb, ~0U)))
		printk("EXT2-fs warning: feature flags set on rev 0 fs, "
		       "running e2fsck is recommended\n");
	/*
	 * Check feature flags regardless of the revision level, since we
	 * previously didn't change the revision level when setting the flags,
	 * so there is a chance incompat flags are set on a rev 0 filesystem.
	 */
	if ((i = EXT2_HAS_INCOMPAT_FEATURE(sb, ~EXT2_FEATURE_INCOMPAT_SUPP))) {
		printk("EXT2-fs: %s: couldn't mount because of "
		       "unsupported optional features (%x).\n",
		       bdevname(dev), i);
		goto failed_mount;
	}
	if (!(sb->s_flags & MS_RDONLY) &&
	    (i = EXT2_HAS_RO_COMPAT_FEATURE(sb, ~EXT2_FEATURE_RO_COMPAT_SUPP))){
		printk("EXT2-fs: %s: couldn't mount RDWR because of "
		       "unsupported optional features (%x).\n",
		       bdevname(dev), i);
		goto failed_mount;
	}
	if (EXT2_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL))
		ext2_warning(sb, __FUNCTION__,
			"mounting ext3 filesystem as ext2\n");
	sb->s_blocksize_bits =
		le32_to_cpu(EXT2_SB(sb)->s_es->s_log_block_size) + 10;
	sb->s_blocksize = 1 << sb->s_blocksize_bits;

	sb->s_maxbytes = ext2_max_size(sb->s_blocksize_bits);

	/* If the blocksize doesn't match, re-read the thing.. */
	if (sb->s_blocksize != blocksize) {
		blocksize = sb->s_blocksize;
		brelse(bh);

		if (set_blocksize(dev, blocksize) < 0) {
			printk(KERN_ERR "EXT2-fs: blocksize too small for device.\n");
			return NULL;
		}

		logic_sb_block = (sb_block*BLOCK_SIZE) / blocksize;
		offset = (sb_block*BLOCK_SIZE) % blocksize;
		bh = sb_bread(sb, logic_sb_block);
		if(!bh) {
			printk("EXT2-fs: Couldn't read superblock on "
			       "2nd try.\n");
			goto failed_mount;
		}
		es = (struct ext2_super_block *) (((char *)bh->b_data) + offset);
		sb->u.ext2_sb.s_es = es;
		if (es->s_magic != le16_to_cpu(EXT2_SUPER_MAGIC)) {
			printk ("EXT2-fs: Magic mismatch, very weird !\n");
			goto failed_mount;
		}
	}

	if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV) {
		sbi->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;
		sbi->s_first_ino = EXT2_GOOD_OLD_FIRST_INO;
	} else {
		sbi->s_inode_size = le16_to_cpu(es->s_inode_size);
		sbi->s_first_ino = le32_to_cpu(es->s_first_ino);
		if ((sbi->s_inode_size < EXT2_GOOD_OLD_INODE_SIZE) ||
		    (sbi->s_inode_size & (sbi->s_inode_size - 1)) ||
		    (sbi->s_inode_size > blocksize)) {
			printk ("EXT2-fs: unsupported inode size: %d\n",
				sbi->s_inode_size);
			goto failed_mount;
		}
	}
	sb->u.ext2_sb.s_frag_size = EXT2_MIN_FRAG_SIZE <<
				   le32_to_cpu(es->s_log_frag_size);
	if (sb->u.ext2_sb.s_frag_size)
		sb->u.ext2_sb.s_frags_per_block = sb->s_blocksize /
						  sb->u.ext2_sb.s_frag_size;
	else
		sb->s_magic = 0;
	sb->u.ext2_sb.s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group);
	sb->u.ext2_sb.s_frags_per_group = le32_to_cpu(es->s_frags_per_group);
	sb->u.ext2_sb.s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group);
	sb->u.ext2_sb.s_inodes_per_block = sb->s_blocksize /
					   EXT2_INODE_SIZE(sb);
	sb->u.ext2_sb.s_itb_per_group = sb->u.ext2_sb.s_inodes_per_group /
				        sb->u.ext2_sb.s_inodes_per_block;
	sb->u.ext2_sb.s_desc_per_block = sb->s_blocksize /
					 sizeof (struct ext2_group_desc);
	sb->u.ext2_sb.s_sbh = bh;
	if (resuid != EXT2_DEF_RESUID)
		sb->u.ext2_sb.s_resuid = resuid;
	else
		sb->u.ext2_sb.s_resuid = le16_to_cpu(es->s_def_resuid);
	if (resgid != EXT2_DEF_RESGID)
		sb->u.ext2_sb.s_resgid = resgid;
	else
		sb->u.ext2_sb.s_resgid = le16_to_cpu(es->s_def_resgid);
	sb->u.ext2_sb.s_mount_state = le16_to_cpu(es->s_state);
	sb->u.ext2_sb.s_addr_per_block_bits =
		log2 (EXT2_ADDR_PER_BLOCK(sb));
	sb->u.ext2_sb.s_desc_per_block_bits =
		log2 (EXT2_DESC_PER_BLOCK(sb));
	if (sb->s_magic != EXT2_SUPER_MAGIC) {
		if (!silent)
			printk ("VFS: Can't find an ext2 filesystem on dev "
				"%s.\n",
				bdevname(dev));
		goto failed_mount;
	}
	if (sb->s_blocksize != bh->b_size) {
		if (!silent)
			printk ("VFS: Unsupported blocksize on dev "
				"%s.\n", bdevname(dev));
		goto failed_mount;
	}

	if (sb->s_blocksize != sb->u.ext2_sb.s_frag_size) {
		printk ("EXT2-fs: fragsize %lu != blocksize %lu (not supported yet)\n",
			sb->u.ext2_sb.s_frag_size, sb->s_blocksize);
		goto failed_mount;
	}

	if (sb->u.ext2_sb.s_blocks_per_group > sb->s_blocksize * 8) {
		printk ("EXT2-fs: #blocks per group too big: %lu\n",
			sb->u.ext2_sb.s_blocks_per_group);
		goto failed_mount;
	}
	if (sb->u.ext2_sb.s_frags_per_group > sb->s_blocksize * 8) {
		printk ("EXT2-fs: #fragments per group too big: %lu\n",
			sb->u.ext2_sb.s_frags_per_group);
		goto failed_mount;
	}
	if (sb->u.ext2_sb.s_inodes_per_group > sb->s_blocksize * 8) {
		printk ("EXT2-fs: #inodes per group too big: %lu\n",
			sb->u.ext2_sb.s_inodes_per_group);
		goto failed_mount;
	}

	sb->u.ext2_sb.s_groups_count = (le32_to_cpu(es->s_blocks_count) -
				        le32_to_cpu(es->s_first_data_block) +
				       EXT2_BLOCKS_PER_GROUP(sb) - 1) /
				       EXT2_BLOCKS_PER_GROUP(sb);
	db_count = (sb->u.ext2_sb.s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) /
		   EXT2_DESC_PER_BLOCK(sb);
	sb->u.ext2_sb.s_group_desc = kmalloc (db_count * sizeof (struct buffer_head *), GFP_KERNEL);
	if (sb->u.ext2_sb.s_group_desc == NULL) {
		printk ("EXT2-fs: not enough memory\n");
		goto failed_mount;
	}
	for (i = 0; i < db_count; i++) {
		block = descriptor_loc(sb, logic_sb_block, i);
		sbi->s_group_desc[i] = sb_bread(sb, block);
		if (!sbi->s_group_desc[i]) {
			for (j = 0; j < i; j++)
				brelse (sbi->s_group_desc[j]);
			kfree(sbi->s_group_desc);
			printk ("EXT2-fs: unable to read group descriptors\n");
			goto failed_mount;
		}
	}
	if (!ext2_check_descriptors (sb)) {
		printk ("EXT2-fs: group descriptors corrupted!\n");
		db_count = i;
		goto failed_mount2;
	}
	for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++) {
		sb->u.ext2_sb.s_inode_bitmap_number[i] = 0;
		sb->u.ext2_sb.s_inode_bitmap[i] = NULL;
		sb->u.ext2_sb.s_block_bitmap_number[i] = 0;
		sb->u.ext2_sb.s_block_bitmap[i] = NULL;
	}
	sb->u.ext2_sb.s_loaded_inode_bitmaps = 0;
	sb->u.ext2_sb.s_loaded_block_bitmaps = 0;
	sb->u.ext2_sb.s_gdb_count = db_count;
	/*
	 * set up enough so that it can read an inode
	 */
	sb->s_op = &ext2_sops;
	sb->s_root = d_alloc_root(iget(sb, EXT2_ROOT_INO));
	if (!sb->s_root || !S_ISDIR(sb->s_root->d_inode->i_mode) ||
	    !sb->s_root->d_inode->i_blocks || !sb->s_root->d_inode->i_size) {
		if (sb->s_root) {
			dput(sb->s_root);
			sb->s_root = NULL;
			printk(KERN_ERR "EXT2-fs: corrupt root inode, run e2fsck\n");
		} else
			printk(KERN_ERR "EXT2-fs: get root inode failed\n");
		goto failed_mount2;
	}
	ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY);
	return sb;
failed_mount2:
	for (i = 0; i < db_count; i++)
		brelse(sb->u.ext2_sb.s_group_desc[i]);
	kfree(sb->u.ext2_sb.s_group_desc);
failed_mount:
	brelse(bh);
	return NULL;
}
コード例 #19
0
ファイル: rehash.c プロジェクト: DebdutBiswas/WinFLASHTool
errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino,
			    struct problem_context *pctx)
{
	ext2_filsys 		fs = ctx->fs;
	errcode_t		retval;
	struct ext2_inode 	inode;
	char			*dir_buf = 0;
	struct fill_dir_struct	fd;
	struct out_dir		outdir;

	outdir.max = outdir.num = 0;
	outdir.buf = 0;
	outdir.hashes = 0;
	e2fsck_read_inode(ctx, ino, &inode, "rehash_dir");

	if (EXT2_HAS_INCOMPAT_FEATURE(fs->super,
				      EXT4_FEATURE_INCOMPAT_INLINE_DATA) &&
	   (inode.i_flags & EXT4_INLINE_DATA_FL))
		return 0;

	retval = ENOMEM;
	fd.harray = 0;
	dir_buf = malloc(inode.i_size);
	if (!dir_buf)
		goto errout;

	fd.max_array = inode.i_size / 32;
	fd.num_array = 0;
	fd.harray = malloc(fd.max_array * sizeof(struct hash_entry));
	if (!fd.harray)
		goto errout;

	fd.ctx = ctx;
	fd.buf = dir_buf;
	fd.inode = &inode;
	fd.ino = ino;
	fd.err = 0;
	fd.dir_size = 0;
	fd.compress = 0;
	fd.dir = ino;
	if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) ||
	    (inode.i_size / fs->blocksize) < 2)
		fd.compress = 1;
	fd.parent = 0;

retry_nohash:
	/* Read in the entire directory into memory */
	retval = ext2fs_block_iterate3(fs, ino, 0, 0,
				       fill_dir_block, &fd);
	if (fd.err) {
		retval = fd.err;
		goto errout;
	}

	/* 
	 * If the entries read are less than a block, then don't index
	 * the directory
	 */
	if (!fd.compress && (fd.dir_size < (fs->blocksize - 24))) {
		fd.compress = 1;
		fd.dir_size = 0;
		fd.num_array = 0;
		goto retry_nohash;
	}

#if 0
	printf("%d entries (%d bytes) found in inode %d\n",
	       fd.num_array, fd.dir_size, ino);
#endif

	/* Sort the list */
resort:
	if (fd.compress && fd.num_array > 1)
		qsort(fd.harray+2, fd.num_array-2, sizeof(struct hash_entry),
		      hash_cmp);
	else
		qsort(fd.harray, fd.num_array, sizeof(struct hash_entry),
		      hash_cmp);

	/*
	 * Look for duplicates
	 */
	if (duplicate_search_and_fix(ctx, fs, ino, &fd))
		goto resort;

	if (ctx->options & E2F_OPT_NO) {
		retval = 0;
		goto errout;
	}

	/* Sort non-hashed directories by inode number */
	if (fd.compress && fd.num_array > 1)
		qsort(fd.harray+2, fd.num_array-2,
		      sizeof(struct hash_entry), ino_cmp);

	/*
	 * Copy the directory entries.  In a htree directory these
	 * will become the leaf nodes.
	 */
	retval = copy_dir_entries(ctx, &fd, &outdir);
	if (retval)
		goto errout;

	free(dir_buf); dir_buf = 0;

	if (!fd.compress) {
		/* Calculate the interior nodes */
		retval = calculate_tree(fs, &outdir, ino, fd.parent);
		if (retval)
			goto errout;
	}

	retval = write_directory(ctx, fs, &outdir, ino, &inode, fd.compress);
	if (retval)
		goto errout;

	if (ctx->options & E2F_OPT_CONVERT_BMAP)
		retval = e2fsck_rebuild_extents_later(ctx, ino);
	else
		retval = e2fsck_check_rebuild_extents(ctx, ino, &inode, pctx);
errout:
	free(dir_buf);
	free(fd.harray);

	free_out_dir(&outdir);
	return retval;
}
コード例 #20
0
ファイル: alloc_tables.c プロジェクト: Gwinel/e2fsprogs
errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group,
				      ext2fs_block_bitmap bmap)
{
	errcode_t	retval;
	blk64_t		group_blk, start_blk, last_blk, new_blk;
	dgrp_t		last_grp = 0;
	int		rem_grps = 0, flexbg_size = 0;

	group_blk = ext2fs_group_first_block2(fs, group);
	last_blk = ext2fs_group_last_block2(fs, group);

	if (!bmap)
		bmap = fs->block_map;

	if (EXT2_HAS_INCOMPAT_FEATURE(fs->super,
				      EXT4_FEATURE_INCOMPAT_FLEX_BG) &&
	    fs->super->s_log_groups_per_flex) {
		flexbg_size = 1 << fs->super->s_log_groups_per_flex;
		last_grp = group | (flexbg_size - 1);
		if (last_grp > fs->group_desc_count-1)
			last_grp = fs->group_desc_count-1;
		rem_grps = last_grp - group + 1;
	}

	/*
	 * Allocate the block and inode bitmaps, if necessary
	 */
	if (fs->stride) {
		retval = ext2fs_get_free_blocks2(fs, group_blk, last_blk,
						 1, bmap, &start_blk);
		if (retval)
			return retval;
		start_blk += fs->inode_blocks_per_group;
		start_blk += ((fs->stride * group) %
			      (last_blk - start_blk + 1));
		if (start_blk >= last_blk)
			start_blk = group_blk;
	} else
		start_blk = group_blk;

	if (flexbg_size) {
		blk64_t prev_block = 0;

		if (group % flexbg_size)
			prev_block = ext2fs_block_bitmap_loc(fs, group - 1) + 1;
		start_blk = flexbg_offset(fs, group, prev_block, bmap,
					  rem_grps, 1);
		last_blk = ext2fs_group_last_block2(fs, last_grp);
	}

	if (!ext2fs_block_bitmap_loc(fs, group)) {
		retval = ext2fs_get_free_blocks2(fs, start_blk, last_blk,
						 1, bmap, &new_blk);
		if (retval == EXT2_ET_BLOCK_ALLOC_FAIL)
			retval = ext2fs_get_free_blocks2(fs, group_blk,
					last_blk, 1, bmap, &new_blk);
		if (retval)
			return retval;
		ext2fs_mark_block_bitmap2(bmap, new_blk);
		ext2fs_block_bitmap_loc_set(fs, group, new_blk);
		if (flexbg_size) {
			dgrp_t gr = ext2fs_group_of_blk2(fs, new_blk);
			ext2fs_bg_free_blocks_count_set(fs, gr, ext2fs_bg_free_blocks_count(fs, gr) - 1);
			ext2fs_free_blocks_count_add(fs->super, -1);
			ext2fs_bg_flags_clear(fs, gr, EXT2_BG_BLOCK_UNINIT);
			ext2fs_group_desc_csum_set(fs, gr);
		}
	}

	if (flexbg_size) {
		blk64_t prev_block = 0;
		if (group % flexbg_size)
			prev_block = ext2fs_inode_bitmap_loc(fs, group - 1) + 1;
		else
			prev_block = ext2fs_block_bitmap_loc(fs, group) +
				flexbg_size;
		start_blk = flexbg_offset(fs, group, prev_block, bmap,
					  rem_grps, 1);
		last_blk = ext2fs_group_last_block2(fs, last_grp);
	}

	if (!ext2fs_inode_bitmap_loc(fs, group)) {
		retval = ext2fs_get_free_blocks2(fs, start_blk, last_blk,
						 1, bmap, &new_blk);
		if (retval == EXT2_ET_BLOCK_ALLOC_FAIL)
			retval = ext2fs_get_free_blocks2(fs, group_blk,
					 last_blk, 1, bmap, &new_blk);
		if (retval)
			return retval;
		ext2fs_mark_block_bitmap2(bmap, new_blk);
		ext2fs_inode_bitmap_loc_set(fs, group, new_blk);
		if (flexbg_size) {
			dgrp_t gr = ext2fs_group_of_blk2(fs, new_blk);
			ext2fs_bg_free_blocks_count_set(fs, gr, ext2fs_bg_free_blocks_count(fs, gr) - 1);
			ext2fs_free_blocks_count_add(fs->super, -1);
			ext2fs_bg_flags_clear(fs, gr, EXT2_BG_BLOCK_UNINIT);
			ext2fs_group_desc_csum_set(fs, gr);
		}
	}

	/*
	 * Allocate the inode table
	 */
	if (flexbg_size) {
		blk64_t prev_block = 0;

		if (group % flexbg_size)
			prev_block = ext2fs_inode_table_loc(fs, group - 1) +
				fs->inode_blocks_per_group;
		else
			prev_block = ext2fs_inode_bitmap_loc(fs, group) +
				flexbg_size;

		group_blk = flexbg_offset(fs, group, prev_block, bmap,
					  rem_grps, fs->inode_blocks_per_group);
		last_blk = ext2fs_group_last_block2(fs, last_grp);
	}

	if (!ext2fs_inode_table_loc(fs, group)) {
		retval = ext2fs_get_free_blocks2(fs, group_blk, last_blk,
						fs->inode_blocks_per_group,
						bmap, &new_blk);
		if (retval)
			return retval;
		if (flexbg_size)
			ext2fs_block_alloc_stats_range(fs, new_blk,
				       fs->inode_blocks_per_group, +1);
		else
			ext2fs_mark_block_bitmap_range2(fs->block_map,
					new_blk, fs->inode_blocks_per_group);
		ext2fs_inode_table_loc_set(fs, group, new_blk);
	}
	ext2fs_group_desc_csum_set(fs, group);
	return 0;
}
コード例 #21
0
static int ext2_fill_super(struct super_block *sb, void *data, int silent)
{
	struct buffer_head * bh;
	struct ext2_sb_info * sbi;
	struct ext2_super_block * es;
	struct inode *root;
	unsigned long block;
	unsigned long sb_block = get_sb_block(&data);
	unsigned long logic_sb_block;
	unsigned long offset = 0;
	unsigned long def_mount_opts;
	long ret = -EINVAL;
	int blocksize = BLOCK_SIZE;
	int db_count;
	int i, j;
	__le32 features;
	int err;

	sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
	if (!sbi)
		return -ENOMEM;

	sbi->s_blockgroup_lock =
		kzalloc(sizeof(struct blockgroup_lock), GFP_KERNEL);
	if (!sbi->s_blockgroup_lock) {
		kfree(sbi);
		return -ENOMEM;
	}
	sb->s_fs_info = sbi;
	sbi->s_sb_block = sb_block;

	/*
	 * See what the current blocksize for the device is, and
	 * use that as the blocksize.  Otherwise (or if the blocksize
	 * is smaller than the default) use the default.
	 * This is important for devices that have a hardware
	 * sectorsize that is larger than the default.
	 */
	blocksize = sb_min_blocksize(sb, BLOCK_SIZE);
	if (!blocksize) {
		printk ("EXT2-fs: unable to set blocksize\n");
		goto failed_sbi;
	}

	/*
	 * If the superblock doesn't start on a hardware sector boundary,
	 * calculate the offset.  
	 */
	if (blocksize != BLOCK_SIZE) {
		logic_sb_block = (sb_block*BLOCK_SIZE) / blocksize;
		offset = (sb_block*BLOCK_SIZE) % blocksize;
	} else {
		logic_sb_block = sb_block;
	}

	if (!(bh = sb_bread(sb, logic_sb_block))) {
		printk ("EXT2-fs: unable to read superblock\n");
		goto failed_sbi;
	}
	/*
	 * Note: s_es must be initialized as soon as possible because
	 *       some ext2 macro-instructions depend on its value
	 */
	es = (struct ext2_super_block *) (((char *)bh->b_data) + offset);
	sbi->s_es = es;
	sb->s_magic = le16_to_cpu(es->s_magic);

	if (sb->s_magic != EXT2_SUPER_MAGIC)
		goto cantfind_ext2;

	/* Set defaults before we parse the mount options */
	def_mount_opts = le32_to_cpu(es->s_default_mount_opts);
	if (def_mount_opts & EXT2_DEFM_DEBUG)
		set_opt(sbi->s_mount_opt, DEBUG);
	if (def_mount_opts & EXT2_DEFM_BSDGROUPS)
		set_opt(sbi->s_mount_opt, GRPID);
	if (def_mount_opts & EXT2_DEFM_UID16)
		set_opt(sbi->s_mount_opt, NO_UID32);
#ifdef CONFIG_EXT2_FS_XATTR
	if (def_mount_opts & EXT2_DEFM_XATTR_USER)
		set_opt(sbi->s_mount_opt, XATTR_USER);
#endif
#ifdef CONFIG_EXT2_FS_POSIX_ACL
	if (def_mount_opts & EXT2_DEFM_ACL)
		set_opt(sbi->s_mount_opt, POSIX_ACL);
#endif
	
	if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_PANIC)
		set_opt(sbi->s_mount_opt, ERRORS_PANIC);
	else if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_CONTINUE)
		set_opt(sbi->s_mount_opt, ERRORS_CONT);
	else
		set_opt(sbi->s_mount_opt, ERRORS_RO);

	sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
	sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
	
	set_opt(sbi->s_mount_opt, RESERVATION);

	if (!parse_options ((char *) data, sbi))
		goto failed_mount;

	sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
		((EXT2_SB(sb)->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ?
		 MS_POSIXACL : 0);

	ext2_xip_verify_sb(sb); /* see if bdev supports xip, unset
				    EXT2_MOUNT_XIP if not */

	if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV &&
	    (EXT2_HAS_COMPAT_FEATURE(sb, ~0U) ||
	     EXT2_HAS_RO_COMPAT_FEATURE(sb, ~0U) ||
	     EXT2_HAS_INCOMPAT_FEATURE(sb, ~0U)))
		printk("EXT2-fs warning: feature flags set on rev 0 fs, "
		       "running e2fsck is recommended\n");
	/*
	 * Check feature flags regardless of the revision level, since we
	 * previously didn't change the revision level when setting the flags,
	 * so there is a chance incompat flags are set on a rev 0 filesystem.
	 */
	features = EXT2_HAS_INCOMPAT_FEATURE(sb, ~EXT2_FEATURE_INCOMPAT_SUPP);
	if (features) {
		printk("EXT2-fs: %s: couldn't mount because of "
		       "unsupported optional features (%x).\n",
		       sb->s_id, le32_to_cpu(features));
		goto failed_mount;
	}
	if (!(sb->s_flags & MS_RDONLY) &&
	    (features = EXT2_HAS_RO_COMPAT_FEATURE(sb, ~EXT2_FEATURE_RO_COMPAT_SUPP))){
		printk("EXT2-fs: %s: couldn't mount RDWR because of "
		       "unsupported optional features (%x).\n",
		       sb->s_id, le32_to_cpu(features));
		goto failed_mount;
	}

	blocksize = BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size);

	if (ext2_use_xip(sb) && blocksize != PAGE_SIZE) {
		if (!silent)
			printk("XIP: Unsupported blocksize\n");
		goto failed_mount;
	}

	/* If the blocksize doesn't match, re-read the thing.. */
	if (sb->s_blocksize != blocksize) {
		brelse(bh);

		if (!sb_set_blocksize(sb, blocksize)) {
			printk(KERN_ERR "EXT2-fs: blocksize too small for device.\n");
			goto failed_sbi;
		}

		logic_sb_block = (sb_block*BLOCK_SIZE) / blocksize;
		offset = (sb_block*BLOCK_SIZE) % blocksize;
		bh = sb_bread(sb, logic_sb_block);
		if(!bh) {
			printk("EXT2-fs: Couldn't read superblock on "
			       "2nd try.\n");
			goto failed_sbi;
		}
		es = (struct ext2_super_block *) (((char *)bh->b_data) + offset);
		sbi->s_es = es;
		if (es->s_magic != cpu_to_le16(EXT2_SUPER_MAGIC)) {
			printk ("EXT2-fs: Magic mismatch, very weird !\n");
			goto failed_mount;
		}
	}

	sb->s_maxbytes = ext2_max_size(sb->s_blocksize_bits);

	if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV) {
		sbi->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;
		sbi->s_first_ino = EXT2_GOOD_OLD_FIRST_INO;
	} else {
		sbi->s_inode_size = le16_to_cpu(es->s_inode_size);
		sbi->s_first_ino = le32_to_cpu(es->s_first_ino);
		if ((sbi->s_inode_size < EXT2_GOOD_OLD_INODE_SIZE) ||
		    !is_power_of_2(sbi->s_inode_size) ||
		    (sbi->s_inode_size > blocksize)) {
			printk ("EXT2-fs: unsupported inode size: %d\n",
				sbi->s_inode_size);
			goto failed_mount;
		}
	}

	sbi->s_frag_size = EXT2_MIN_FRAG_SIZE <<
				   le32_to_cpu(es->s_log_frag_size);
	if (sbi->s_frag_size == 0)
		goto cantfind_ext2;
	sbi->s_frags_per_block = sb->s_blocksize / sbi->s_frag_size;

	sbi->s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group);
	sbi->s_frags_per_group = le32_to_cpu(es->s_frags_per_group);
	sbi->s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group);

	if (EXT2_INODE_SIZE(sb) == 0)
		goto cantfind_ext2;
	sbi->s_inodes_per_block = sb->s_blocksize / EXT2_INODE_SIZE(sb);
	if (sbi->s_inodes_per_block == 0 || sbi->s_inodes_per_group == 0)
		goto cantfind_ext2;
	sbi->s_itb_per_group = sbi->s_inodes_per_group /
					sbi->s_inodes_per_block;
	sbi->s_desc_per_block = sb->s_blocksize /
					sizeof (struct ext2_group_desc);
	sbi->s_sbh = bh;
	sbi->s_mount_state = le16_to_cpu(es->s_state);
	sbi->s_addr_per_block_bits =
		ilog2 (EXT2_ADDR_PER_BLOCK(sb));
	sbi->s_desc_per_block_bits =
		ilog2 (EXT2_DESC_PER_BLOCK(sb));

	if (sb->s_magic != EXT2_SUPER_MAGIC)
		goto cantfind_ext2;

	if (sb->s_blocksize != bh->b_size) {
		if (!silent)
			printk ("VFS: Unsupported blocksize on dev "
				"%s.\n", sb->s_id);
		goto failed_mount;
	}

	if (sb->s_blocksize != sbi->s_frag_size) {
		printk ("EXT2-fs: fragsize %lu != blocksize %lu (not supported yet)\n",
			sbi->s_frag_size, sb->s_blocksize);
		goto failed_mount;
	}

	if (sbi->s_blocks_per_group > sb->s_blocksize * 8) {
		printk ("EXT2-fs: #blocks per group too big: %lu\n",
			sbi->s_blocks_per_group);
		goto failed_mount;
	}
	if (sbi->s_frags_per_group > sb->s_blocksize * 8) {
		printk ("EXT2-fs: #fragments per group too big: %lu\n",
			sbi->s_frags_per_group);
		goto failed_mount;
	}
	if (sbi->s_inodes_per_group > sb->s_blocksize * 8) {
		printk ("EXT2-fs: #inodes per group too big: %lu\n",
			sbi->s_inodes_per_group);
		goto failed_mount;
	}

	if (EXT2_BLOCKS_PER_GROUP(sb) == 0)
		goto cantfind_ext2;
 	sbi->s_groups_count = ((le32_to_cpu(es->s_blocks_count) -
 				le32_to_cpu(es->s_first_data_block) - 1)
 					/ EXT2_BLOCKS_PER_GROUP(sb)) + 1;
	db_count = (sbi->s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) /
		   EXT2_DESC_PER_BLOCK(sb);
	sbi->s_group_desc = kmalloc (db_count * sizeof (struct buffer_head *), GFP_KERNEL);
	if (sbi->s_group_desc == NULL) {
		printk ("EXT2-fs: not enough memory\n");
		goto failed_mount;
	}
	bgl_lock_init(sbi->s_blockgroup_lock);
	sbi->s_debts = kcalloc(sbi->s_groups_count, sizeof(*sbi->s_debts), GFP_KERNEL);
	if (!sbi->s_debts) {
		printk ("EXT2-fs: not enough memory\n");
		goto failed_mount_group_desc;
	}
	for (i = 0; i < db_count; i++) {
		block = descriptor_loc(sb, logic_sb_block, i);
		sbi->s_group_desc[i] = sb_bread(sb, block);
		if (!sbi->s_group_desc[i]) {
			for (j = 0; j < i; j++)
				brelse (sbi->s_group_desc[j]);
			printk ("EXT2-fs: unable to read group descriptors\n");
			goto failed_mount_group_desc;
		}
	}
	if (!ext2_check_descriptors (sb)) {
		printk ("EXT2-fs: group descriptors corrupted!\n");
		goto failed_mount2;
	}
	sbi->s_gdb_count = db_count;
	get_random_bytes(&sbi->s_next_generation, sizeof(u32));
	spin_lock_init(&sbi->s_next_gen_lock);

	/* per fileystem reservation list head & lock */
	spin_lock_init(&sbi->s_rsv_window_lock);
	sbi->s_rsv_window_root = RB_ROOT;
	/*
	 * Add a single, static dummy reservation to the start of the
	 * reservation window list --- it gives us a placeholder for
	 * append-at-start-of-list which makes the allocation logic
	 * _much_ simpler.
	 */
	sbi->s_rsv_window_head.rsv_start = EXT2_RESERVE_WINDOW_NOT_ALLOCATED;
	sbi->s_rsv_window_head.rsv_end = EXT2_RESERVE_WINDOW_NOT_ALLOCATED;
	sbi->s_rsv_window_head.rsv_alloc_hit = 0;
	sbi->s_rsv_window_head.rsv_goal_size = 0;
	ext2_rsv_window_add(sb, &sbi->s_rsv_window_head);

	err = percpu_counter_init(&sbi->s_freeblocks_counter,
				ext2_count_free_blocks(sb));
	if (!err) {
		err = percpu_counter_init(&sbi->s_freeinodes_counter,
				ext2_count_free_inodes(sb));
	}
	if (!err) {
		err = percpu_counter_init(&sbi->s_dirs_counter,
				ext2_count_dirs(sb));
	}
	if (err) {
		printk(KERN_ERR "EXT2-fs: insufficient memory\n");
		goto failed_mount3;
	}
	/*
	 * set up enough so that it can read an inode
	 */
	sb->s_op = &ext2_sops;
	sb->s_export_op = &ext2_export_ops;
	sb->s_xattr = ext2_xattr_handlers;
	root = ext2_iget(sb, EXT2_ROOT_INO);
	if (IS_ERR(root)) {
		ret = PTR_ERR(root);
		goto failed_mount3;
	}
	if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
		iput(root);
		printk(KERN_ERR "EXT2-fs: corrupt root inode, run e2fsck\n");
		goto failed_mount3;
	}

	sb->s_root = d_alloc_root(root);
	if (!sb->s_root) {
		iput(root);
		printk(KERN_ERR "EXT2-fs: get root inode failed\n");
		ret = -ENOMEM;
		goto failed_mount3;
	}
	if (EXT2_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL))
		ext2_warning(sb, __func__,
			"mounting ext3 filesystem as ext2");
	ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY);
	return 0;

cantfind_ext2:
	if (!silent)
		printk("VFS: Can't find an ext2 filesystem on dev %s.\n",
		       sb->s_id);
	goto failed_mount;
failed_mount3:
	percpu_counter_destroy(&sbi->s_freeblocks_counter);
	percpu_counter_destroy(&sbi->s_freeinodes_counter);
	percpu_counter_destroy(&sbi->s_dirs_counter);
failed_mount2:
	for (i = 0; i < db_count; i++)
		brelse(sbi->s_group_desc[i]);
failed_mount_group_desc:
	kfree(sbi->s_group_desc);
	kfree(sbi->s_debts);
failed_mount:
	brelse(bh);
failed_sbi:
	sb->s_fs_info = NULL;
	kfree(sbi->s_blockgroup_lock);
	kfree(sbi);
	return ret;
}
コード例 #22
0
ファイル: check_desc.c プロジェクト: Docworld/chromiumos
/*
 * This routine sanity checks the group descriptors
 */
errcode_t ext2fs_check_desc(ext2_filsys fs)
{
	ext2fs_block_bitmap bmap;
	errcode_t retval;
	dgrp_t i;
	blk_t first_block = fs->super->s_first_data_block;
	blk_t last_block = fs->super->s_blocks_count-1;
	blk_t blk, b;
	int j;

	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);

	retval = ext2fs_allocate_block_bitmap(fs, "check_desc map", &bmap);
	if (retval)
		return retval;

	for (i = 0; i < fs->group_desc_count; i++)
		ext2fs_reserve_super_and_bgd(fs, i, bmap);

	for (i = 0; i < fs->group_desc_count; i++) {
		if (!EXT2_HAS_INCOMPAT_FEATURE(fs->super,
					       EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
			first_block = ext2fs_group_first_block(fs, i);
			last_block = ext2fs_group_last_block(fs, i);
			if (i == (fs->group_desc_count - 1))
				last_block = fs->super->s_blocks_count-1;
		}

		/*
		 * Check to make sure the block bitmap for group is sane
		 */
		blk = fs->group_desc[i].bg_block_bitmap;
		if (blk < first_block || blk > last_block ||
		    ext2fs_test_block_bitmap2(bmap, blk)) {
			retval = EXT2_ET_GDESC_BAD_BLOCK_MAP;
			goto errout;
		}
		ext2fs_mark_block_bitmap2(bmap, blk);

		/*
		 * Check to make sure the inode bitmap for group is sane
		 */
		blk = fs->group_desc[i].bg_inode_bitmap;
		if (blk < first_block || blk > last_block ||
		    ext2fs_test_block_bitmap2(bmap, blk)) {
			retval = EXT2_ET_GDESC_BAD_INODE_MAP;
			goto errout;
		}
		ext2fs_mark_block_bitmap2(bmap, blk);

		/*
		 * Check to make sure the inode table for group is sane
		 */
		blk = fs->group_desc[i].bg_inode_table;
		if (blk < first_block ||
		    ((blk + fs->inode_blocks_per_group - 1) > last_block)) {
			retval = EXT2_ET_GDESC_BAD_INODE_TABLE;
			goto errout;
		}
		for (j = 0, b = blk; j < fs->inode_blocks_per_group;
		     j++, b++) {
			if (ext2fs_test_block_bitmap2(bmap, b)) {
				retval = EXT2_ET_GDESC_BAD_INODE_TABLE;
				goto errout;
			}
			ext2fs_mark_block_bitmap2(bmap, b);
		}
	}
errout:
	ext2fs_free_block_bitmap(bmap);
	return retval;
}
コード例 #23
0
int main (int argc, char ** argv)
{
	errcode_t	retval;
	ext2_filsys	fs;
	int		c;
	int		flags = 0;
	int		flush = 0;
	int		force = 0;
	int		io_flags = 0;
	int		force_min_size = 0;
	int		print_min_size = 0;
	int		fd, ret;
	blk64_t		new_size = 0;
	blk64_t		max_size = 0;
	blk64_t		min_size = 0;
	io_manager	io_ptr;
	char		*new_size_str = 0;
	int		use_stride = -1;
	ext2fs_struct_stat st_buf;
	__s64		new_file_size;
	unsigned int	sys_page_size = 4096;
	long		sysval;
	int		len, mount_flags;
	char		*mtpt;

#ifdef ENABLE_NLS
	setlocale(LC_MESSAGES, "");
	setlocale(LC_CTYPE, "");
	bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
	textdomain(NLS_CAT_NAME);
	set_com_err_gettext(gettext);
#endif

	add_error_table(&et_ext2_error_table);

	fprintf (stderr, "resize2fs %s (%s)\n",
		 E2FSPROGS_VERSION, E2FSPROGS_DATE);
	if (argc && *argv)
		program_name = *argv;

	while ((c = getopt (argc, argv, "d:fFhMPpS:")) != EOF) {
		switch (c) {
		case 'h':
			usage(program_name);
			break;
		case 'f':
			force = 1;
			break;
		case 'F':
			flush = 1;
			break;
		case 'M':
			force_min_size = 1;
			break;
		case 'P':
			print_min_size = 1;
			break;
		case 'd':
			flags |= atoi(optarg);
			break;
		case 'p':
			flags |= RESIZE_PERCENT_COMPLETE;
			break;
		case 'S':
			use_stride = atoi(optarg);
			break;
		default:
			usage(program_name);
		}
	}
	if (optind == argc)
		usage(program_name);

	device_name = argv[optind++];
	if (optind < argc)
		new_size_str = argv[optind++];
	if (optind < argc)
		usage(program_name);

	io_options = strchr(device_name, '?');
	if (io_options)
		*io_options++ = 0;

	/*
	 * Figure out whether or not the device is mounted, and if it is
	 * where it is mounted.
	 */
	len=80;
	while (1) {
		mtpt = malloc(len);
		if (!mtpt)
			return ENOMEM;
		mtpt[len-1] = 0;
		retval = ext2fs_check_mount_point(device_name, &mount_flags,
						  mtpt, len);
		if (retval) {
			com_err("ext2fs_check_mount_point", retval,
				_("while determining whether %s is mounted."),
				device_name);
			exit(1);
		}
		if (!(mount_flags & EXT2_MF_MOUNTED) || (mtpt[len-1] == 0))
			break;
		free(mtpt);
		len = 2 * len;
	}

	fd = ext2fs_open_file(device_name, O_RDWR, 0);
	if (fd < 0) {
		com_err("open", errno, _("while opening %s"),
			device_name);
		exit(1);
	}

	ret = ext2fs_fstat(fd, &st_buf);
	if (ret < 0) {
		com_err("open", errno,
			_("while getting stat information for %s"),
			device_name);
		exit(1);
	}

	if (flush) {
		retval = ext2fs_sync_device(fd, 1);
		if (retval) {
			com_err(argv[0], retval,
				_("while trying to flush %s"),
				device_name);
			exit(1);
		}
	}

	if (!S_ISREG(st_buf.st_mode )) {
		close(fd);
		fd = -1;
	}

#ifdef CONFIG_TESTIO_DEBUG
	if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) {
		io_ptr = test_io_manager;
		test_io_backing_manager = unix_io_manager;
	} else
#endif
		io_ptr = unix_io_manager;

	if (!(mount_flags & EXT2_MF_MOUNTED))
		io_flags = EXT2_FLAG_RW | EXT2_FLAG_EXCLUSIVE;

	io_flags |= EXT2_FLAG_64BITS;

	retval = ext2fs_open2(device_name, io_options, io_flags,
			      0, 0, io_ptr, &fs);
	if (retval) {
		com_err (program_name, retval, _("while trying to open %s"),
			 device_name);
		printf (_("Couldn't find valid filesystem superblock.\n"));
		exit (1);
	}

	/*
	 * Check for compatibility with the feature sets.  We need to
	 * be more stringent than ext2fs_open().
	 */
	if (fs->super->s_feature_compat & ~EXT2_LIB_FEATURE_COMPAT_SUPP) {
		com_err(program_name, EXT2_ET_UNSUPP_FEATURE,
			"(%s)", device_name);
		exit(1);
	}

	min_size = calculate_minimum_resize_size(fs);

	if (print_min_size) {
		if (!force && ((fs->super->s_state & EXT2_ERROR_FS) ||
			       ((fs->super->s_state & EXT2_VALID_FS) == 0))) {
			fprintf(stderr,
				_("Please run 'e2fsck -f %s' first.\n\n"),
				device_name);
			exit(1);
		}
		printf(_("Estimated minimum size of the filesystem: %llu\n"),
		       min_size);
		exit(0);
	}

	/* Determine the system page size if possible */
#ifdef HAVE_SYSCONF
#if (!defined(_SC_PAGESIZE) && defined(_SC_PAGE_SIZE))
#define _SC_PAGESIZE _SC_PAGE_SIZE
#endif
#ifdef _SC_PAGESIZE
	sysval = sysconf(_SC_PAGESIZE);
	if (sysval > 0)
		sys_page_size = sysval;
#endif /* _SC_PAGESIZE */
#endif /* HAVE_SYSCONF */

	/*
	 * Get the size of the containing partition, and use this for
	 * defaults and for making sure the new filesystem doesn't
	 * exceed the partition size.
	 */
	retval = ext2fs_get_device_size2(device_name, fs->blocksize,
					 &max_size);
	if (retval) {
		com_err(program_name, retval,
			_("while trying to determine filesystem size"));
		exit(1);
	}
	if (force_min_size)
		new_size = min_size;
	else if (new_size_str) {
		new_size = parse_num_blocks2(new_size_str,
					     fs->super->s_log_block_size);
		if (new_size == 0) {
			com_err(program_name, 0,
				_("Invalid new size: %s\n"), new_size_str);
			exit(1);
		}
	} else {
		new_size = max_size;
		/* Round down to an even multiple of a pagesize */
		if (sys_page_size > fs->blocksize)
			new_size &= ~((sys_page_size / fs->blocksize)-1);
	}
	if (!EXT2_HAS_INCOMPAT_FEATURE(fs->super,
				       EXT4_FEATURE_INCOMPAT_64BIT)) {
		/* Take 16T down to 2^32-1 blocks */
		if (new_size == (1ULL << 32))
			new_size--;
		else if (new_size > (1ULL << 32)) {
			com_err(program_name, 0,
				_("New size too large to be "
				  "expressed in 32 bits\n"));
			exit(1);
		}
	}

	if (!force && new_size < min_size) {
		com_err(program_name, 0,
			_("New size smaller than minimum (%llu)\n"), min_size);
		exit(1);
	}
	if (use_stride >= 0) {
		if (use_stride >= (int) fs->super->s_blocks_per_group) {
			com_err(program_name, 0,
				_("Invalid stride length"));
			exit(1);
		}
		fs->stride = fs->super->s_raid_stride = use_stride;
		ext2fs_mark_super_dirty(fs);
	} else
		  determine_fs_stride(fs);

	/*
	 * If we are resizing a plain file, and it's not big enough,
	 * automatically extend it in a sparse fashion by writing the
	 * last requested block.
	 */
	new_file_size = ((__u64) new_size) * fs->blocksize;
	if ((__u64) new_file_size >
	    (((__u64) 1) << (sizeof(st_buf.st_size)*8 - 1)) - 1)
		fd = -1;
	if ((new_file_size > st_buf.st_size) &&
	    (fd > 0)) {
		if ((ext2fs_llseek(fd, new_file_size-1, SEEK_SET) >= 0) &&
		    (write(fd, "0", 1) == 1))
			max_size = new_size;
	}
	if (!force && (new_size > max_size)) {
		fprintf(stderr, _("The containing partition (or device)"
			" is only %llu (%dk) blocks.\nYou requested a new size"
			" of %llu blocks.\n\n"), max_size,
			fs->blocksize / 1024, new_size);
		exit(1);
	}
	if (new_size == ext2fs_blocks_count(fs->super)) {
		fprintf(stderr, _("The filesystem is already %llu blocks "
			"long.  Nothing to do!\n\n"), new_size);
		exit(0);
	}
	if (mount_flags & EXT2_MF_MOUNTED) {
		retval = online_resize_fs(fs, mtpt, &new_size, flags);
	} else {
		if (!force && ((fs->super->s_lastcheck < fs->super->s_mtime) ||
			       (fs->super->s_state & EXT2_ERROR_FS) ||
			       ((fs->super->s_state & EXT2_VALID_FS) == 0))) {
			fprintf(stderr,
				_("Please run 'e2fsck -f %s' first.\n\n"),
				device_name);
			exit(1);
		}
		/*
		 * XXXX The combination of flex_bg and !resize_inode
		 * causes major problems for resize2fs, since when the
		 * group descriptors grow in size this can potentially
		 * require multiple inode tables to be moved aside to
		 * make room, and resize2fs chokes rather badly in
		 * this scenario.  It's a rare combination, except
		 * when a filesystem is expanded more than a certain
		 * size, so for now, we'll just prohibit that
		 * combination.  This is something we should fix
		 * eventually, though.
		 */
		if ((fs->super->s_feature_incompat &
		     EXT4_FEATURE_INCOMPAT_FLEX_BG) &&
		    !(fs->super->s_feature_compat &
		      EXT2_FEATURE_COMPAT_RESIZE_INODE)) {
			com_err(program_name, 0, _("%s: The combination of "
				"flex_bg and\n\t!resize_inode features "
				"is not supported by resize2fs.\n"),
				device_name);
			exit(1);
		}
		printf(_("Resizing the filesystem on "
			 "%s to %llu (%dk) blocks.\n"),
		       device_name, new_size, fs->blocksize / 1024);
		retval = resize_fs(fs, &new_size, flags,
				   ((flags & RESIZE_PERCENT_COMPLETE) ?
				    resize_progress_func : 0));
	}
	free(mtpt);
	if (retval) {
		com_err(program_name, retval, _("while trying to resize %s"),
			device_name);
		fprintf(stderr,
			_("Please run 'e2fsck -fy %s' to fix the filesystem\n"
			  "after the aborted resize operation.\n"),
			device_name);
		ext2fs_close(fs);
		exit(1);
	}
	printf(_("The filesystem on %s is now %llu blocks long.\n\n"),
	       device_name, new_size);

	if ((st_buf.st_size > new_file_size) &&
	    (fd > 0)) {
#ifdef HAVE_FTRUNCATE64
		retval = ftruncate64(fd, new_file_size);
#else
		retval = 0;
		/* Only truncate if new_file_size doesn't overflow off_t */
		if (((off_t) new_file_size) == new_file_size)
			retval = ftruncate(fd, (off_t) new_file_size);
#endif
		if (retval)
			com_err(program_name, retval,
				_("while trying to truncate %s"),
				device_name);
	}
	if (fd > 0)
		close(fd);
	remove_error_table(&et_ext2_error_table);
	return (0);
}
コード例 #24
0
ファイル: create_inode.c プロジェクト: kikimo/w4118-hmwk6
/* Copy the native file to the fs */
errcode_t do_write_internal(ext2_filsys fs, ext2_ino_t cwd, const char *src,
			    const char *dest, ext2_ino_t root)
{
	int		fd;
	struct stat	statbuf;
	ext2_ino_t	newfile;
	errcode_t	retval;
	struct ext2_inode inode;
	int		bufsize = IO_BUFSIZE;
	int		make_holes = 0;

	fd = ext2fs_open_file(src, O_RDONLY, 0);
	if (fd < 0) {
		com_err(src, errno, 0);
		return errno;
	}
	if (fstat(fd, &statbuf) < 0) {
		com_err(src, errno, 0);
		close(fd);
		return errno;
	}

	retval = ext2fs_namei(fs, root, cwd, dest, &newfile);
	if (retval == 0) {
		close(fd);
		return EXT2_ET_FILE_EXISTS;
	}

	retval = ext2fs_new_inode(fs, cwd, 010755, 0, &newfile);
	if (retval) {
		com_err(__func__, retval, 0);
		close(fd);
		return retval;
	}
#ifdef DEBUGFS
	printf("Allocated inode: %u\n", newfile);
#endif
	retval = ext2fs_link(fs, cwd, dest, newfile,
				EXT2_FT_REG_FILE);
	if (retval == EXT2_ET_DIR_NO_SPACE) {
		retval = ext2fs_expand_dir(fs, cwd);
		if (retval) {
			com_err(__func__, retval, "while expanding directory");
			close(fd);
			return retval;
		}
		retval = ext2fs_link(fs, cwd, dest, newfile,
					EXT2_FT_REG_FILE);
	}
	if (retval) {
		com_err(dest, retval, 0);
		close(fd);
		return errno;
	}
	if (ext2fs_test_inode_bitmap2(fs->inode_map, newfile))
		com_err(__func__, 0, "Warning: inode already set");
	ext2fs_inode_alloc_stats2(fs, newfile, +1, 0);
	memset(&inode, 0, sizeof(inode));
	inode.i_mode = (statbuf.st_mode & ~LINUX_S_IFMT) | LINUX_S_IFREG;
	inode.i_atime = inode.i_ctime = inode.i_mtime =
		fs->now ? fs->now : time(0);
	inode.i_links_count = 1;
	retval = ext2fs_inode_size_set(fs, &inode, statbuf.st_size);
	if (retval) {
		com_err(dest, retval, 0);
		close(fd);
		return retval;
	}
	if (EXT2_HAS_INCOMPAT_FEATURE(fs->super,
				      EXT4_FEATURE_INCOMPAT_INLINE_DATA)) {
		inode.i_flags |= EXT4_INLINE_DATA_FL;
	} else if (fs->super->s_feature_incompat &
		   EXT3_FEATURE_INCOMPAT_EXTENTS) {
		int i;
		struct ext3_extent_header *eh;

		eh = (struct ext3_extent_header *) &inode.i_block[0];
		eh->eh_depth = 0;
		eh->eh_entries = 0;
		eh->eh_magic = ext2fs_cpu_to_le16(EXT3_EXT_MAGIC);
		i = (sizeof(inode.i_block) - sizeof(*eh)) /
			sizeof(struct ext3_extent);
		eh->eh_max = ext2fs_cpu_to_le16(i);
		inode.i_flags |= EXT4_EXTENTS_FL;
	}

	retval = ext2fs_write_new_inode(fs, newfile, &inode);
	if (retval) {
		com_err(__func__, retval, "while creating inode %u", newfile);
		close(fd);
		return retval;
	}
	if (inode.i_flags & EXT4_INLINE_DATA_FL) {
		retval = ext2fs_inline_data_init(fs, newfile);
		if (retval) {
			com_err("copy_file", retval, 0);
			close(fd);
			return retval;
		}
	}
	if (LINUX_S_ISREG(inode.i_mode)) {
		if (statbuf.st_blocks < statbuf.st_size / S_BLKSIZE) {
			make_holes = 1;
			/*
			 * Use I/O blocksize as buffer size when
			 * copying sparse files.
			 */
			bufsize = statbuf.st_blksize;
		}
		retval = copy_file(fs, fd, newfile, bufsize, make_holes);
		if (retval)
			com_err("copy_file", retval, 0);
	}
	close(fd);

	return retval;
}