return ext2fs_test_inode_bitmap2(ctx->inodes_to_rebuild, ino);
}
-struct extent_list {
- blk64_t blocks_freed;
- struct ext2fs_extent *extents;
- unsigned int count;
- unsigned int size;
- unsigned int ext_read;
- errcode_t retval;
- ext2_ino_t ino;
-};
-
static errcode_t load_extents(e2fsck_t ctx, struct extent_list *list)
{
ext2_filsys fs = ctx->fs;
list->count - 1;
blk64_t end = last->e_len + 1;
- if (last->e_pblk + last->e_len == *blocknr &&
+ if (last->e_lblk + last->e_len == (__u64) blockcnt &&
+ last->e_pblk + last->e_len == *blocknr &&
end < (1ULL << 32)) {
last->e_len++;
#ifdef DEBUG
return 0;
}
-static errcode_t rebuild_extent_tree(e2fsck_t ctx, struct extent_list *list,
- ext2_ino_t ino)
+static errcode_t rewrite_extent_replay(e2fsck_t ctx, struct extent_list *list,
+ struct ext2_inode_large *inode)
{
- struct ext2_inode_large inode;
errcode_t retval;
ext2_extent_handle_t handle;
unsigned int i, ext_written;
struct ext2fs_extent *ex, extent;
blk64_t start_val, delta;
- list->count = 0;
- list->blocks_freed = 0;
- list->ino = ino;
- list->ext_read = 0;
- e2fsck_read_inode_full(ctx, ino, EXT2_INODE(&inode), sizeof(inode),
- "rebuild_extents");
-
- /* Skip deleted inodes and inline data files */
- if (inode.i_links_count == 0 ||
- inode.i_flags & EXT4_INLINE_DATA_FL)
- return 0;
-
- /* Collect lblk->pblk mappings */
- if (inode.i_flags & EXT4_EXTENTS_FL) {
- retval = load_extents(ctx, list);
- if (retval)
- goto err;
- goto extents_loaded;
- }
-
- retval = ext2fs_block_iterate3(ctx->fs, ino, BLOCK_FLAG_READ_ONLY, 0,
- find_blocks, list);
- if (retval)
- goto err;
- if (list->retval) {
- retval = list->retval;
- goto err;
- }
-
-extents_loaded:
/* Reset extent tree */
- inode.i_flags &= ~EXT4_EXTENTS_FL;
- memset(inode.i_block, 0, sizeof(inode.i_block));
+ inode->i_flags &= ~EXT4_EXTENTS_FL;
+ memset(inode->i_block, 0, sizeof(inode->i_block));
/* Make a note of freed blocks */
- quota_data_sub(ctx->qctx, &inode, ino,
+ quota_data_sub(ctx->qctx, inode, list->ino,
list->blocks_freed * ctx->fs->blocksize);
- retval = ext2fs_iblk_sub_blocks(ctx->fs, EXT2_INODE(&inode),
+ retval = ext2fs_iblk_sub_blocks(ctx->fs, EXT2_INODE(inode),
list->blocks_freed);
if (retval)
- goto err;
+ return retval;
/* Now stuff extents into the file */
- retval = ext2fs_extent_open2(ctx->fs, ino, EXT2_INODE(&inode), &handle);
+ retval = ext2fs_extent_open2(ctx->fs, list->ino, EXT2_INODE(inode),
+ &handle);
if (retval)
- goto err;
+ return retval;
ext_written = 0;
- start_val = ext2fs_inode_i_blocks(ctx->fs, EXT2_INODE(&inode));
+
+ start_val = ext2fs_get_stat_i_blocks(ctx->fs, EXT2_INODE(inode));
+
for (i = 0, ex = list->extents; i < list->count; i++, ex++) {
+ if (ex->e_len == 0)
+ continue;
memcpy(&extent, ex, sizeof(struct ext2fs_extent));
extent.e_flags &= EXT2_EXTENT_FLAGS_UNINIT;
if (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) {
}
#ifdef DEBUG
- printf("W: ino=%d pblk=%llu lblk=%llu len=%u\n", ino,
+ printf("W: ino=%d pblk=%llu lblk=%llu len=%u\n", list->ino,
extent.e_pblk, extent.e_lblk, extent.e_len);
#endif
retval = ext2fs_extent_insert(handle, EXT2_EXTENT_INSERT_AFTER,
&extent);
if (retval)
- goto err2;
+ goto err;
retval = ext2fs_extent_fix_parents(handle);
if (retval)
- goto err2;
+ goto err;
ext_written++;
}
- delta = ext2fs_inode_i_blocks(ctx->fs, EXT2_INODE(&inode)) - start_val;
- if (delta) {
- if (!ext2fs_has_feature_huge_file(ctx->fs->super) ||
- !(inode.i_flags & EXT4_HUGE_FILE_FL))
- delta <<= 9;
- else
- delta *= ctx->fs->blocksize;
- quota_data_add(ctx->qctx, &inode, ino, delta);
- }
+ delta = ext2fs_get_stat_i_blocks(ctx->fs, EXT2_INODE(inode)) -
+ start_val;
+ if (delta)
+ quota_data_add(ctx->qctx, inode, list->ino, delta << 9);
#if defined(DEBUG) || defined(DEBUG_SUMMARY)
printf("rebuild: ino=%d extents=%d->%d\n", ino, list->ext_read,
ext_written);
#endif
- e2fsck_write_inode(ctx, ino, EXT2_INODE(&inode), "rebuild_extents");
+ e2fsck_write_inode(ctx, list->ino, EXT2_INODE(inode),
+ "rebuild_extents");
-err2:
- ext2fs_extent_free(handle);
err:
+ ext2fs_extent_free(handle);
return retval;
}
+errcode_t e2fsck_rewrite_extent_tree(e2fsck_t ctx, struct extent_list *list)
+{
+ struct ext2_inode_large inode;
+ blk64_t blk_count;
+ errcode_t err;
+
+ memset(&inode, 0, sizeof(inode));
+ err = ext2fs_read_inode_full(ctx->fs, list->ino, EXT2_INODE(&inode),
+ sizeof(inode));
+ if (err)
+ return err;
+
+ /* Skip deleted inodes and inline data files */
+ if (inode.i_flags & EXT4_INLINE_DATA_FL)
+ return 0;
+
+ err = rewrite_extent_replay(ctx, list, &inode);
+ if (err)
+ return err;
+
+ err = ext2fs_count_blocks(ctx->fs, list->ino, EXT2_INODE(&inode),
+ &blk_count);
+ if (err)
+ return err;
+ err = ext2fs_iblk_set(ctx->fs, EXT2_INODE(&inode), blk_count);
+ if (err)
+ return err;
+ return ext2fs_write_inode_full(ctx->fs, list->ino, EXT2_INODE(&inode),
+ sizeof(inode));
+}
+
+errcode_t e2fsck_read_extents(e2fsck_t ctx, struct extent_list *extents)
+{
+ struct ext2_inode_large inode;
+ errcode_t retval;
+
+ extents->extents = NULL;
+ extents->count = 0;
+ extents->blocks_freed = 0;
+ extents->ext_read = 0;
+ extents->size = NUM_EXTENTS;
+ retval = ext2fs_get_array(NUM_EXTENTS, sizeof(struct ext2fs_extent),
+ &extents->extents);
+ if (retval)
+ return ENOMEM;
+
+ retval = ext2fs_read_inode(ctx->fs, extents->ino, EXT2_INODE(&inode));
+ if (retval)
+ goto err_out;
+
+ retval = load_extents(ctx, extents);
+ if (!retval)
+ return 0;
+err_out:
+ ext2fs_free_mem(&extents->extents);
+ extents->size = 0;
+ extents->count = 0;
+ return retval;
+}
+
+static errcode_t rebuild_extent_tree(e2fsck_t ctx, struct extent_list *list,
+ ext2_ino_t ino)
+{
+ struct ext2_inode_large inode;
+ errcode_t retval;
+
+ list->count = 0;
+ list->blocks_freed = 0;
+ list->ino = ino;
+ list->ext_read = 0;
+ e2fsck_read_inode_full(ctx, ino, EXT2_INODE(&inode), sizeof(inode),
+ "rebuild_extents");
+
+ /* Skip deleted inodes and inline data files */
+ if (inode.i_links_count == 0 ||
+ inode.i_flags & EXT4_INLINE_DATA_FL)
+ return 0;
+
+ /* Collect lblk->pblk mappings */
+ if (inode.i_flags & EXT4_EXTENTS_FL) {
+ retval = load_extents(ctx, list);
+ if (retval)
+ return retval;
+ return rewrite_extent_replay(ctx, list, &inode);
+ }
+
+ retval = ext2fs_block_iterate3(ctx->fs, ino, BLOCK_FLAG_READ_ONLY, 0,
+ find_blocks, list);
+
+ return retval || list->retval ||
+ rewrite_extent_replay(ctx, list, &inode);
+}
+
/* Rebuild the extents immediately */
static errcode_t e2fsck_rebuild_extents(e2fsck_t ctx, ext2_ino_t ino)
{
- struct extent_list list;
+ struct extent_list list = { 0 };
errcode_t err;
if (!ext2fs_has_feature_extents(ctx->fs->super) ||
return 0;
e2fsck_read_bitmaps(ctx);
- memset(&list, 0, sizeof(list));
- err = ext2fs_get_mem(sizeof(struct ext2fs_extent) * NUM_EXTENTS,
- &list.extents);
+ err = ext2fs_get_array(NUM_EXTENTS, sizeof(struct ext2fs_extent),
+ &list.extents);
if (err)
return err;
list.size = NUM_EXTENTS;
#ifdef RESOURCE_TRACK
struct resource_track rtrack;
#endif
- struct extent_list list;
+ struct extent_list list = { 0 };
int first = 1;
ext2_ino_t ino = 0;
errcode_t retval;
clear_problem_context(&pctx);
e2fsck_read_bitmaps(ctx);
- memset(&list, 0, sizeof(list));
- retval = ext2fs_get_mem(sizeof(struct ext2fs_extent) * NUM_EXTENTS,
- &list.extents);
list.size = NUM_EXTENTS;
+ retval = ext2fs_get_array(sizeof(struct ext2fs_extent),
+ list.size, &list.extents);
+ if (retval)
+ return;
while (1) {
retval = ext2fs_find_first_set_inode_bitmap2(
ctx->inodes_to_rebuild, ino + 1,
*/
if (info.curr_entry == 1 &&
!(extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) &&
- !eti.force_rebuild) {
+ !eti.force_rebuild &&
+ info.curr_level < MAX_EXTENT_DEPTH_COUNT) {
struct extent_tree_level *etl;
etl = eti.ext_info + info.curr_level;
if (eti->force_rebuild)
goto rebuild;
+ if (ctx->options & E2F_OPT_NOOPT_EXTENTS)
+ return 0;
+
extents_per_block = (ctx->fs->blocksize -
sizeof(struct ext3_extent_header)) /
sizeof(struct ext3_extent);
+
+ /* If the extent tree is too deep, then rebuild it. */
+ if (info->max_depth > MAX_EXTENT_DEPTH_COUNT-1) {
+ pctx->blk = info->max_depth;
+ op = PR_1E_CAN_COLLAPSE_EXTENT_TREE;
+ goto rebuild;
+ }
/*
* If we can consolidate a level or shorten the tree, schedule the
* extent tree to be rebuilt.