mirror of https://github.com/vitalif/e2fsprogs
e2fsck: inspect inline dir data as two directory blocks
The design of inline directories (apparently) calls for the i_block[] region and the EA regions to be treated as if they were two separate blocks of dirents. Effectively this means that it is impossible for a directory entry to straddle both areas. e2fsck doesn't enforce this, so teach it to do so. e2fslib already knows to do this.... Cc: Zheng Liu <gnehzuil.liu@gmail.com> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu>crypto
parent
09282b8a0b
commit
0ac4b3973f
|
@ -2742,18 +2742,44 @@ static void check_blocks_extents(e2fsck_t ctx, struct problem_context *pctx,
|
|||
static void check_blocks_inline_data(e2fsck_t ctx, struct problem_context *pctx,
|
||||
struct process_block_struct *pb)
|
||||
{
|
||||
int flags;
|
||||
size_t inline_data_size = 0;
|
||||
|
||||
if (!pb->is_dir) {
|
||||
pctx->errcode = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Process the dirents in i_block[] as the "first" block. */
|
||||
pctx->errcode = ext2fs_add_dir_block2(ctx->fs->dblist, pb->ino, 0, 0);
|
||||
if (pctx->errcode)
|
||||
goto err;
|
||||
|
||||
/* Process the dirents in the EA as a "second" block. */
|
||||
flags = ctx->fs->flags;
|
||||
ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
|
||||
pctx->errcode = ext2fs_inline_data_size(ctx->fs, pb->ino,
|
||||
&inline_data_size);
|
||||
ctx->fs->flags = (flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) |
|
||||
(ctx->fs->flags & ~EXT2_FLAG_IGNORE_CSUM_ERRORS);
|
||||
if (pctx->errcode) {
|
||||
pctx->blk = 0;
|
||||
pctx->num = 0;
|
||||
fix_problem(ctx, PR_1_ADD_DBLOCK, pctx);
|
||||
ctx->flags |= E2F_FLAG_ABORT;
|
||||
pctx->errcode = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (inline_data_size <= EXT4_MIN_INLINE_DATA_SIZE)
|
||||
return;
|
||||
|
||||
pctx->errcode = ext2fs_add_dir_block2(ctx->fs->dblist, pb->ino, 0, 1);
|
||||
if (pctx->errcode)
|
||||
goto err;
|
||||
|
||||
return;
|
||||
err:
|
||||
pctx->blk = 0;
|
||||
pctx->num = 0;
|
||||
fix_problem(ctx, PR_1_ADD_DBLOCK, pctx);
|
||||
ctx->flags |= E2F_FLAG_ABORT;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
104
e2fsck/pass2.c
104
e2fsck/pass2.c
|
@ -732,15 +732,6 @@ static void salvage_directory(ext2_filsys fs,
|
|||
}
|
||||
}
|
||||
|
||||
static int is_last_entry(ext2_filsys fs, int inline_data_size,
|
||||
unsigned int offset, int csum_size)
|
||||
{
|
||||
if (inline_data_size)
|
||||
return (offset < inline_data_size);
|
||||
else
|
||||
return (offset < fs->blocksize - csum_size);
|
||||
}
|
||||
|
||||
#define NEXT_DIRENT(d) ((void *)((char *)(d) + (d)->rec_len))
|
||||
static errcode_t insert_dirent_tail(ext2_filsys fs, void *dirbuf)
|
||||
{
|
||||
|
@ -783,10 +774,22 @@ static errcode_t fix_inline_dir_size(e2fsck_t ctx, ext2_ino_t ino,
|
|||
errcode_t retval;
|
||||
|
||||
old_size = *inline_data_size;
|
||||
new_size = old_size + (4 - (old_size & 3));
|
||||
/*
|
||||
* If there's not enough bytes to start the "second" dir block
|
||||
* (in the EA space) then truncate everything to the first block.
|
||||
*/
|
||||
if (old_size > EXT4_MIN_INLINE_DATA_SIZE &&
|
||||
old_size < EXT4_MIN_INLINE_DATA_SIZE +
|
||||
EXT2_DIR_REC_LEN(1)) {
|
||||
old_size = EXT4_MIN_INLINE_DATA_SIZE;
|
||||
new_size = old_size;
|
||||
} else
|
||||
/* Increase to the next four-byte boundary for salvaging */
|
||||
new_size = old_size + (4 - (old_size & 3));
|
||||
memset(buf + old_size, 0, new_size - old_size);
|
||||
retval = ext2fs_inline_data_set(fs, ino, 0, buf, new_size);
|
||||
if (retval == EXT2_ET_INLINE_DATA_NO_SPACE) {
|
||||
/* Or we can't, so truncate. */
|
||||
new_size -= 4;
|
||||
retval = ext2fs_inline_data_set(fs, ino, 0, buf, new_size);
|
||||
if (retval) {
|
||||
|
@ -844,7 +847,7 @@ static int check_dir_block(ext2_filsys fs,
|
|||
ext2_ino_t subdir_parent;
|
||||
__u16 links;
|
||||
struct check_dir_struct *cd;
|
||||
char *buf;
|
||||
char *buf, *ibuf;
|
||||
e2fsck_t ctx;
|
||||
problem_t problem;
|
||||
struct ext2_dx_root_info *root;
|
||||
|
@ -858,9 +861,10 @@ static int check_dir_block(ext2_filsys fs,
|
|||
int is_leaf = 1;
|
||||
size_t inline_data_size = 0;
|
||||
int filetype = 0;
|
||||
size_t max_block_size;
|
||||
|
||||
cd = (struct check_dir_struct *) priv_data;
|
||||
buf = cd->buf;
|
||||
ibuf = buf = cd->buf;
|
||||
ctx = cd->ctx;
|
||||
|
||||
if (ctx->flags & E2F_FLAG_SIGNAL_MASK || ctx->flags & E2F_FLAG_RESTART)
|
||||
|
@ -928,10 +932,22 @@ static int check_dir_block(ext2_filsys fs,
|
|||
if (cd->pctx.errcode)
|
||||
goto inline_read_fail;
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
if (db->blockcnt)
|
||||
goto skip_first_read_swab;
|
||||
*((__u32 *)buf) = ext2fs_le32_to_cpu(*((__u32 *)buf));
|
||||
cd->pctx.errcode = ext2fs_dirent_swab_in2(fs,
|
||||
buf + EXT4_INLINE_DATA_DOTDOT_SIZE,
|
||||
inline_data_size - EXT4_INLINE_DATA_DOTDOT_SIZE,
|
||||
EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DATA_DOTDOT_SIZE,
|
||||
0);
|
||||
if (cd->pctx.errcode)
|
||||
goto inline_read_fail;
|
||||
skip_first_read_swab:
|
||||
if (inline_data_size <= EXT4_MIN_INLINE_DATA_SIZE ||
|
||||
!db->blockcnt)
|
||||
goto inline_read_fail;
|
||||
cd->pctx.errcode = ext2fs_dirent_swab_in2(fs,
|
||||
buf + EXT4_MIN_INLINE_DATA_SIZE,
|
||||
inline_data_size - EXT4_MIN_INLINE_DATA_SIZE,
|
||||
0);
|
||||
#endif
|
||||
} else
|
||||
|
@ -940,7 +956,10 @@ static int check_dir_block(ext2_filsys fs,
|
|||
inline_read_fail:
|
||||
pctx.ino = ino;
|
||||
pctx.num = inline_data_size;
|
||||
if ((inline_data_size & 3) &&
|
||||
if (((inline_data_size & 3) ||
|
||||
(inline_data_size > EXT4_MIN_INLINE_DATA_SIZE &&
|
||||
inline_data_size < EXT4_MIN_INLINE_DATA_SIZE +
|
||||
EXT2_DIR_REC_LEN(1))) &&
|
||||
fix_problem(ctx, PR_2_BAD_INLINE_DIR_SIZE, &pctx)) {
|
||||
errcode_t err = fix_inline_dir_size(ctx, ino,
|
||||
&inline_data_size, &pctx,
|
||||
|
@ -1039,6 +1058,19 @@ out_htree:
|
|||
de_csum_size = 0;
|
||||
|
||||
skip_checksum:
|
||||
if (inline_data_size) {
|
||||
if (db->blockcnt) {
|
||||
buf += EXT4_MIN_INLINE_DATA_SIZE;
|
||||
max_block_size = inline_data_size - EXT4_MIN_INLINE_DATA_SIZE;
|
||||
/* Zero-length second block, just exit */
|
||||
if (max_block_size == 0)
|
||||
return 0;
|
||||
} else {
|
||||
max_block_size = EXT4_MIN_INLINE_DATA_SIZE;
|
||||
}
|
||||
} else
|
||||
max_block_size = fs->blocksize - de_csum_size;
|
||||
|
||||
dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp);
|
||||
prev = 0;
|
||||
do {
|
||||
|
@ -1048,10 +1080,6 @@ skip_checksum:
|
|||
|
||||
problem = 0;
|
||||
if (!inline_data_size || dot_state > 1) {
|
||||
size_t max_block_size = fs->blocksize - de_csum_size;
|
||||
|
||||
if (inline_data_size)
|
||||
max_block_size = inline_data_size;
|
||||
dirent = (struct ext2_dir_entry *) (buf + offset);
|
||||
(void) ext2fs_get_rec_len(fs, dirent, &rec_len);
|
||||
cd->pctx.dirent = dirent;
|
||||
|
@ -1388,7 +1416,7 @@ skip_checksum:
|
|||
}
|
||||
}
|
||||
dot_state++;
|
||||
} while (is_last_entry(fs, inline_data_size, offset, de_csum_size));
|
||||
} while (offset < max_block_size);
|
||||
#if 0
|
||||
printf("\n");
|
||||
#endif
|
||||
|
@ -1406,22 +1434,11 @@ skip_checksum:
|
|||
}
|
||||
#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 (offset != max_block_size) {
|
||||
cd->pctx.num = rec_len + offset - max_block_size;
|
||||
if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
|
||||
dirent->rec_len = cd->pctx.num;
|
||||
dir_modified++;
|
||||
}
|
||||
}
|
||||
if (dir_modified) {
|
||||
|
@ -1444,13 +1461,28 @@ write_and_fix:
|
|||
ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
|
||||
}
|
||||
if (inline_data_size) {
|
||||
buf = ibuf;
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
if (db->blockcnt)
|
||||
goto skip_first_write_swab;
|
||||
*((__u32 *)buf) = ext2fs_le32_to_cpu(*((__u32 *)buf));
|
||||
cd->pctx.errcode = ext2fs_dirent_swab_out2(fs,
|
||||
buf + EXT4_INLINE_DATA_DOTDOT_SIZE,
|
||||
inline_data_size -
|
||||
EXT4_MIN_INLINE_DATA_SIZE -
|
||||
EXT4_INLINE_DATA_DOTDOT_SIZE,
|
||||
0);
|
||||
if (cd->pctx.errcode)
|
||||
goto skip_second_write_swab;
|
||||
skip_first_write_swab:
|
||||
if (inline_data_size <= EXT4_MIN_INLINE_DATA_SIZE ||
|
||||
!db->blockcnt)
|
||||
goto skip_second_write_swab;
|
||||
cd->pctx.errcode = ext2fs_dirent_swab_out2(fs,
|
||||
buf + EXT4_MIN_INLINE_DATA_SIZE,
|
||||
inline_data_size -
|
||||
EXT4_MIN_INLINE_DATA_SIZE,
|
||||
0);
|
||||
skip_second_write_swab:
|
||||
if (cd->pctx.errcode &&
|
||||
!fix_problem(ctx, PR_2_WRITE_DIRBLOCK, &cd->pctx))
|
||||
goto abort_free_dict;
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
Pass 1: Checking inodes, blocks, and sizes
|
||||
Pass 2: Checking directory structure
|
||||
Entry '..' in ??? (12) has invalid inode #: 1752440867.
|
||||
Clear? yes
|
||||
|
||||
Directory inode 12, block #0, offset 4: directory corrupted
|
||||
Salvage? yes
|
||||
|
||||
Directory inode 12, block #1, offset 0: directory corrupted
|
||||
Salvage? yes
|
||||
|
||||
Pass 3: Checking directory connectivity
|
||||
'..' in /aoo (12) is ??? (1752440867), should be / (2).
|
||||
Fix? yes
|
||||
|
||||
Error while adjusting inode count on inode 0
|
||||
Pass 4: Checking reference counts
|
||||
Pass 5: Checking group summary information
|
||||
Directories count wrong for group #0 (2, counted=3).
|
||||
Fix? yes
|
||||
|
||||
|
||||
test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
|
||||
test_filesys: 12/128 files (0.0% non-contiguous), 17/512 blocks
|
||||
Exit status is 1
|
|
@ -0,0 +1,7 @@
|
|||
Pass 1: Checking inodes, blocks, and sizes
|
||||
Pass 2: Checking directory structure
|
||||
Pass 3: Checking directory connectivity
|
||||
Pass 4: Checking reference counts
|
||||
Pass 5: Checking group summary information
|
||||
test_filesys: 12/128 files (0.0% non-contiguous), 17/512 blocks
|
||||
Exit status is 0
|
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
check inline dir as two dirent blocks
|
Loading…
Reference in New Issue