void e2fsck_pass3(e2fsck_t ctx)
{
ext2_filsys fs = ctx->fs;
- struct dir_info_iter *iter;
+ struct dir_info_iter *iter = NULL;
#ifdef RESOURCE_TRACK
struct resource_track rtrack;
#endif
if (check_directory(ctx, dir->ino, &pctx))
goto abort_exit;
}
- e2fsck_dir_info_iter_end(ctx, iter);
/*
* Force the creation of /lost+found if not present
e2fsck_rehash_directories(ctx);
abort_exit:
+ if (iter)
+ e2fsck_dir_info_iter_end(ctx, iter);
e2fsck_free_dir_info(ctx);
if (inode_loop_detect) {
ext2fs_free_inode_bitmap(inode_loop_detect);
return;
}
- pctx.errcode = ext2fs_write_dir_block(fs, blk, block);
+ pctx.errcode = ext2fs_write_dir_block3(fs, blk, block, 0);
if (pctx.errcode) {
- pctx.str = "ext2fs_write_dir_block";
+ pctx.str = "ext2fs_write_dir_block3";
fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
ctx->flags |= E2F_FLAG_ABORT;
return;
return 0;
}
- retval = ext2fs_write_dir_block(fs, blk, block);
+ retval = ext2fs_write_dir_block3(fs, blk, block, 0);
ext2fs_free_mem(&block);
if (retval) {
pctx.errcode = retval;
return BLOCK_ABORT;
}
es->num--;
- retval = ext2fs_write_dir_block(fs, new_blk, block);
+ retval = ext2fs_write_dir_block3(fs, new_blk, block, 0);
} else {
retval = ext2fs_get_mem(fs->blocksize, &block);
if (retval) {
return BLOCK_CHANGED;
}
+/*
+ * Ensure that all blocks are marked in the block_found_map, since it's
+ * possible that the library allocated an extent node block or a block map
+ * block during the directory rebuilding; these new allocations are not
+ * captured in block_found_map. This is bad since we could later use
+ * block_found_map to allocate more blocks.
+ */
+static int find_new_blocks_proc(ext2_filsys fs,
+ blk64_t *blocknr,
+ e2_blkcnt_t blockcnt,
+ blk64_t ref_block EXT2FS_ATTR((unused)),
+ int ref_offset EXT2FS_ATTR((unused)),
+ void *priv_data)
+{
+ struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data;
+ e2fsck_t ctx = es->ctx;
+
+ ext2fs_mark_block_bitmap2(ctx->block_found_map, *blocknr);
+ return 0;
+}
+
errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
int num, int guaranteed_size)
{
errcode_t retval;
struct expand_dir_struct es;
struct ext2_inode inode;
+ blk64_t sz, before, after;
if (!(fs->flags & EXT2_FLAG_RW))
return EXT2_ET_RO_FILSYS;
es.newblocks = 0;
es.ctx = ctx;
+ before = ext2fs_free_blocks_count(fs->super);
retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
0, expand_dir_proc, &es);
if (es.err)
return es.err;
+ after = ext2fs_free_blocks_count(fs->super);
+
+ /*
+ * If the free block count has dropped by more than the blocks we
+ * allocated ourselves, then we must've allocated some extent/map
+ * blocks. Therefore, we must iterate this dir's blocks again to
+ * ensure that all newly allocated blocks are captured in
+ * block_found_map.
+ */
+ if ((before - after) > es.newblocks) {
+ retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_READ_ONLY,
+ 0, find_new_blocks_proc, &es);
+ if (es.err)
+ return es.err;
+ }
/*
* Update the size and block count fields in the inode.
if (retval)
return retval;
- inode.i_size = (es.last_block + 1) * fs->blocksize;
+ sz = (es.last_block + 1) * fs->blocksize;
+ inode.i_size = sz;
+ inode.i_size_high = sz >> 32;
ext2fs_iblk_add_blocks(fs, &inode, es.newblocks);
quota_data_add(ctx->qctx, &inode, dir, es.newblocks * fs->blocksize);