Overhaul extended attribute handling. Should now be correct with

respect to the latest V2 bestbits ACL code.
bitmap-optimize
Theodore Ts'o 2002-08-17 10:19:44 -04:00
parent 0ccd488a76
commit 0684a4f33b
37 changed files with 505 additions and 187 deletions

View File

@ -1,3 +1,71 @@
2002-08-17 Theodore Ts'o <tytso@mit.edu>
* e2fsck.h, e2fsck.c (e2fsck_allocate_context): Add new field to
the e2fsck context, ext_attr_ver, which specifies the EA
format version.
* unix.c (usage, parse_extended_opts, PRS), e2fsck.8.in: Add new
option -E, which allows the users to specify extended
options. Added ea_ver extended option.
* pass1.c (e2fsck_pass1_check_device_inode): Add ext2_filsys
argument to this function, so we can account for the
presence of extended attribute blocks attached to device
inodes.
(e2fsck_pass1_check_symlink, e2fsck_pass1): Take into
account the fact that symlinks can also have extended
attribute blocks.
(check_ext_attr): Don't be flexible about the EA format
version. Check against the version number in
ctx->ext_attr_ver.
(check_blocks): Check all inodes, so that we account for
extended attribute blocks belonging to special files.
Clean up i_size checks.
* pass1b.c (pass1b): Check all inodes, so that we account for
extended attribute blocks belonging to special files.
(delete_file_block): Use ext2fs_alloc_block_stats() to
update the filesystem statistics.
(delete_file): Attempt to decrement the extended
attribute refcount, and free the EA block if the count
hits zero.
(clone_file): Fixed bugs in EA handling. Don't call
block_iterate on inodes that don't have a valid i_block[]
array. Reread the base inode since it may have been
changed by ext2fs_block_iterate. When updating inodes as
part of cloning an EA block, write out the correct inode
structure.
* pass2.c (deallocate_inode_block, deallocate_inode): Use standard
ext2fs_alloc_*_stats functions to update the filesystem
statistics.
(deallocate_inode): Attempt to decrement the extended
attribute refcount, and free the EA block if the count
hits zero.
(e2fsck_process_bad_inode): Add extra argument to calls
to e2fsck_pass1_check_device_inode ().
* pass3.c (e2fsck_get_lost_and_found): Use standard
ext2fs_alloc_*_stats functions to update the filesystem.
statistics when creating /lost+found.
(adjust_inode_count): Remove debugging code that can never
be triggered.
* pass4.c (disconnect_inode): Add explanation about why we only
clear inodes that have no data blocks and no EA blocks.
Use ext2fs_inode_alloc_stats2 function to update the
filesystem statistics when clearing a zero-length inode.
* problem.c, problem.h (PR_1B_ADJ_EA_REFCOUNT,
PR_2_ADJ_EA_REFCOUNT): Add new problem codes.
* super.c (release_inode_block), (release_orphan_inodes): Use the
standard ext2fs_alloc_*_stats functions to update the
filesystem statistics.
(release_inode_blocks): Attempt to decrement the extended
attribute refcount, and free the EA block if the count
hits zero.
2002-08-01 Theodore Ts'o <tytso@mit.edu> 2002-08-01 Theodore Ts'o <tytso@mit.edu>
* dict.c, dict.h: New file from kazlib 1.20 which implements a * dict.c, dict.h: New file from kazlib 1.20 which implements a

View File

@ -30,6 +30,10 @@ e2fsck \- check a Linux second extended file system
@JDEV@.B \-j @JDEV@.B \-j
@JDEV@.I external-journal @JDEV@.I external-journal
@JDEV@] @JDEV@]
[
.B \-E
.I extended_options
]
.I device .I device
.SH DESCRIPTION .SH DESCRIPTION
.B e2fsck .B e2fsck
@ -122,6 +126,18 @@ filesystem supports directory indexing, or by sorting and compressing
directories for smaller directories, or for filesystems using directories for smaller directories, or for filesystems using
traditional linear directories. traditional linear directories.
.TP .TP
.BI \-E " extended_options"
Set e2fsck extended options. Extended options are comma
separated, and may take an argument using the equals ('=') sign. The
following options are supported:
.RS 1.2i
.TP
.BI ea_ver= extended_attribute_version
Assume the format of the extended attribute blocks in the filesystem is
the specified version number. The version number may be 1 or 2. The
default extended attribute version format is 2.
.RE
.TP
.B \-f .B \-f
Force checking even if the file system seems clean. Force checking even if the file system seems clean.
.TP .TP

View File

@ -30,6 +30,7 @@ errcode_t e2fsck_allocate_context(e2fsck_t *ret)
memset(context, 0, sizeof(struct e2fsck_struct)); memset(context, 0, sizeof(struct e2fsck_struct));
context->process_inode_size = 256; context->process_inode_size = 256;
context->ext_attr_ver = 2;
*ret = context; *ret = context;
return 0; return 0;

View File

@ -308,6 +308,8 @@ struct e2fsck_struct {
int fs_ext_attr_inodes; int fs_ext_attr_inodes;
int fs_ext_attr_blocks; int fs_ext_attr_blocks;
int ext_attr_ver;
/* /*
* For the use of callers of the e2fsck functions; not used by * For the use of callers of the e2fsck functions; not used by
* e2fsck functions themselves. * e2fsck functions themselves.
@ -382,7 +384,8 @@ extern void e2fsck_move_ext3_journal(e2fsck_t ctx);
/* pass1.c */ /* pass1.c */
extern void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool); extern void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool);
extern int e2fsck_pass1_check_device_inode(struct ext2_inode *inode); extern int e2fsck_pass1_check_device_inode(ext2_filsys fs,
struct ext2_inode *inode);
extern int e2fsck_pass1_check_symlink(ext2_filsys fs, extern int e2fsck_pass1_check_symlink(ext2_filsys fs,
struct ext2_inode *inode, char *buf); struct ext2_inode *inode, char *buf);

View File

@ -125,7 +125,7 @@ static void unwind_pass1(ext2_filsys fs)
* since they have the same requirement; the i_block fields should be * since they have the same requirement; the i_block fields should be
* zero. * zero.
*/ */
int e2fsck_pass1_check_device_inode(struct ext2_inode *inode) int e2fsck_pass1_check_device_inode(ext2_filsys fs, struct ext2_inode *inode)
{ {
int i; int i;
@ -133,7 +133,8 @@ int e2fsck_pass1_check_device_inode(struct ext2_inode *inode)
* If i_blocks is non-zero, or the index flag is set, then * If i_blocks is non-zero, or the index flag is set, then
* this is a bogus device/fifo/socket * this is a bogus device/fifo/socket
*/ */
if (inode->i_blocks || (inode->i_flags & EXT2_INDEX_FL)) if ((ext2fs_inode_data_blocks(fs, inode) != 0) ||
(inode->i_flags & EXT2_INDEX_FL))
return 0; return 0;
/* /*
@ -179,14 +180,16 @@ int e2fsck_pass1_check_symlink(ext2_filsys fs, struct ext2_inode *inode,
{ {
int len; int len;
int i; int i;
blk_t blocks;
if ((inode->i_size_high || inode->i_size == 0) || if ((inode->i_size_high || inode->i_size == 0) ||
(inode->i_flags & EXT2_INDEX_FL)) (inode->i_flags & EXT2_INDEX_FL))
return 0; return 0;
if (inode->i_blocks) { blocks = ext2fs_inode_data_blocks(fs, inode);
if (blocks) {
if ((inode->i_size >= fs->blocksize) || if ((inode->i_size >= fs->blocksize) ||
(inode->i_blocks != fs->blocksize >> 9) || (blocks != fs->blocksize >> 9) ||
(inode->i_block[0] < fs->super->s_first_data_block) || (inode->i_block[0] < fs->super->s_first_data_block) ||
(inode->i_block[0] >= fs->super->s_blocks_count)) (inode->i_block[0] >= fs->super->s_blocks_count))
return 0; return 0;
@ -614,12 +617,12 @@ void e2fsck_pass1(e2fsck_t ctx)
ext2fs_mark_inode_bitmap(ctx->inode_reg_map, ino); ext2fs_mark_inode_bitmap(ctx->inode_reg_map, ino);
ctx->fs_regular_count++; ctx->fs_regular_count++;
} else if (LINUX_S_ISCHR (inode.i_mode) && } else if (LINUX_S_ISCHR (inode.i_mode) &&
e2fsck_pass1_check_device_inode(&inode)) { e2fsck_pass1_check_device_inode(fs, &inode)) {
check_immutable(ctx, &pctx); check_immutable(ctx, &pctx);
check_size(ctx, &pctx); check_size(ctx, &pctx);
ctx->fs_chardev_count++; ctx->fs_chardev_count++;
} else if (LINUX_S_ISBLK (inode.i_mode) && } else if (LINUX_S_ISBLK (inode.i_mode) &&
e2fsck_pass1_check_device_inode(&inode)) { e2fsck_pass1_check_device_inode(fs, &inode)) {
check_immutable(ctx, &pctx); check_immutable(ctx, &pctx);
check_size(ctx, &pctx); check_size(ctx, &pctx);
ctx->fs_blockdev_count++; ctx->fs_blockdev_count++;
@ -627,18 +630,19 @@ void e2fsck_pass1(e2fsck_t ctx)
e2fsck_pass1_check_symlink(fs, &inode, block_buf)) { e2fsck_pass1_check_symlink(fs, &inode, block_buf)) {
check_immutable(ctx, &pctx); check_immutable(ctx, &pctx);
ctx->fs_symlinks_count++; ctx->fs_symlinks_count++;
if (!inode.i_blocks) { if (ext2fs_inode_data_blocks(fs, &inode) == 0) {
ctx->fs_fast_symlinks_count++; ctx->fs_fast_symlinks_count++;
check_blocks(ctx, &pctx, block_buf);
goto next; goto next;
} }
} }
else if (LINUX_S_ISFIFO (inode.i_mode) && else if (LINUX_S_ISFIFO (inode.i_mode) &&
e2fsck_pass1_check_device_inode(&inode)) { e2fsck_pass1_check_device_inode(fs, &inode)) {
check_immutable(ctx, &pctx); check_immutable(ctx, &pctx);
check_size(ctx, &pctx); check_size(ctx, &pctx);
ctx->fs_fifo_count++; ctx->fs_fifo_count++;
} else if ((LINUX_S_ISSOCK (inode.i_mode)) && } else if ((LINUX_S_ISSOCK (inode.i_mode)) &&
e2fsck_pass1_check_device_inode(&inode)) { e2fsck_pass1_check_device_inode(fs, &inode)) {
check_immutable(ctx, &pctx); check_immutable(ctx, &pctx);
check_size(ctx, &pctx); check_size(ctx, &pctx);
ctx->fs_sockets_count++; ctx->fs_sockets_count++;
@ -990,7 +994,6 @@ static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
struct ext2_ext_attr_entry *entry; struct ext2_ext_attr_entry *entry;
int count; int count;
region_t region; region_t region;
int ext_attr_ver;
blk = inode->i_file_acl; blk = inode->i_file_acl;
if (blk == 0) if (blk == 0)
@ -1068,12 +1071,13 @@ static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
goto clear_extattr; goto clear_extattr;
header = (struct ext2_ext_attr_header *) block_buf; header = (struct ext2_ext_attr_header *) block_buf;
pctx->blk = inode->i_file_acl; pctx->blk = inode->i_file_acl;
if (header->h_magic != EXT2_EXT_ATTR_MAGIC_v1) if (((ctx->ext_attr_ver == 1) &&
ext_attr_ver = 1; (header->h_magic != EXT2_EXT_ATTR_MAGIC_v1)) ||
if (header->h_magic != EXT2_EXT_ATTR_MAGIC) ((ctx->ext_attr_ver == 2) &&
ext_attr_ver = 2; (header->h_magic != EXT2_EXT_ATTR_MAGIC))) {
else if (fix_problem(ctx, PR_1_BAD_EA_BLOCK, pctx)) if (fix_problem(ctx, PR_1_BAD_EA_BLOCK, pctx))
goto clear_extattr; goto clear_extattr;
}
if (header->h_blocks != 1) { if (header->h_blocks != 1) {
if (fix_problem(ctx, PR_1_EA_MULTI_BLOCK, pctx)) if (fix_problem(ctx, PR_1_EA_MULTI_BLOCK, pctx))
@ -1099,9 +1103,9 @@ static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx)) if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
goto clear_extattr; goto clear_extattr;
} }
if ((ext_attr_ver == 1 && if ((ctx->ext_attr_ver == 1 &&
(entry->e_name_len == 0 || entry->e_name_index != 0)) || (entry->e_name_len == 0 || entry->e_name_index != 0)) ||
(ext_attr_ver == 2 && (ctx->ext_attr_ver == 2 &&
entry->e_name_index == 0)) { entry->e_name_index == 0)) {
if (fix_problem(ctx, PR_1_EA_BAD_NAME, pctx)) if (fix_problem(ctx, PR_1_EA_BAD_NAME, pctx))
goto clear_extattr; goto clear_extattr;
@ -1205,11 +1209,9 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
int dirty_inode = 0; int dirty_inode = 0;
__u64 size; __u64 size;
if (!ext2fs_inode_has_valid_blocks(inode))
return;
pb.ino = ino; pb.ino = ino;
pb.num_blocks = pb.last_block = 0; pb.num_blocks = 0;
pb.last_block = -1;
pb.num_illegal_blocks = 0; pb.num_illegal_blocks = 0;
pb.suppress = 0; pb.clear = 0; pb.suppress = 0; pb.clear = 0;
pb.fragmented = 0; pb.fragmented = 0;
@ -1222,6 +1224,7 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
pb.pctx = pctx; pb.pctx = pctx;
pb.ctx = ctx; pb.ctx = ctx;
pctx->ino = ino; pctx->ino = ino;
pctx->errcode = 0;
if (inode->i_flags & EXT2_COMPRBLK_FL) { if (inode->i_flags & EXT2_COMPRBLK_FL) {
if (fs->super->s_feature_incompat & if (fs->super->s_feature_incompat &
@ -1235,13 +1238,14 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
} }
} }
pctx->errcode = ext2fs_block_iterate2(fs, ino, if (ext2fs_inode_has_valid_blocks(inode))
pctx->errcode = ext2fs_block_iterate2(fs, ino,
pb.is_dir ? BLOCK_FLAG_HOLE : 0, pb.is_dir ? BLOCK_FLAG_HOLE : 0,
block_buf, process_block, &pb); block_buf, process_block, &pb);
if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
goto out;
end_problem_latch(ctx, PR_LATCH_BLOCK); end_problem_latch(ctx, PR_LATCH_BLOCK);
end_problem_latch(ctx, PR_LATCH_TOOBIG); end_problem_latch(ctx, PR_LATCH_TOOBIG);
if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
goto out;
if (pctx->errcode) if (pctx->errcode)
fix_problem(ctx, PR_1_BLOCK_ITERATE, pctx); fix_problem(ctx, PR_1_BLOCK_ITERATE, pctx);
@ -1280,15 +1284,6 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
((inode->i_size / fs->blocksize) >= 3)) ((inode->i_size / fs->blocksize) >= 3))
ext2fs_u32_list_add(ctx->dirs_to_hash, ino); ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
if (inode->i_file_acl && check_ext_attr(ctx, pctx, block_buf))
pb.num_blocks++;
pb.num_blocks *= (fs->blocksize / 512);
#if 0
printf("inode %u, i_size = %lu, last_block = %lld, i_blocks=%lu, num_blocks = %lu\n",
ino, inode->i_size, pb.last_block, inode->i_blocks,
pb.num_blocks);
#endif
if (!pb.num_blocks && pb.is_dir) { if (!pb.num_blocks && pb.is_dir) {
if (fix_problem(ctx, PR_1_ZERO_LENGTH_DIR, pctx)) { if (fix_problem(ctx, PR_1_ZERO_LENGTH_DIR, pctx)) {
inode->i_links_count = 0; inode->i_links_count = 0;
@ -1299,9 +1294,19 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino); ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino);
ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino); ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
ctx->fs_directory_count--; ctx->fs_directory_count--;
pb.is_dir = 0; goto out;
} }
} }
if (inode->i_file_acl && check_ext_attr(ctx, pctx, block_buf))
pb.num_blocks++;
pb.num_blocks *= (fs->blocksize / 512);
#if 0
printf("inode %u, i_size = %lu, last_block = %lld, i_blocks=%lu, num_blocks = %lu\n",
ino, inode->i_size, pb.last_block, inode->i_blocks,
pb.num_blocks);
#endif
if (pb.is_dir) { if (pb.is_dir) {
int nblock = inode->i_size >> EXT2_BLOCK_SIZE_BITS(fs->super); int nblock = inode->i_size >> EXT2_BLOCK_SIZE_BITS(fs->super);
if (nblock > (pb.last_block + 1)) if (nblock > (pb.last_block + 1))
@ -1312,19 +1317,19 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
bad_size = 2; bad_size = 2;
} }
} else { } else {
if (!LINUX_S_ISREG(inode->i_mode) && inode->i_size_high)
bad_size = 5;
size = inode->i_size | ((__u64) inode->i_size_high << 32); size = inode->i_size | ((__u64) inode->i_size_high << 32);
if ((size < pb.last_block * fs->blocksize)) if ((pb.last_block >= 0) &&
(size < pb.last_block * fs->blocksize))
bad_size = 3; bad_size = 3;
else if (size > ext2_max_sizes[fs->super->s_log_block_size]) else if (size > ext2_max_sizes[fs->super->s_log_block_size])
bad_size = 4; bad_size = 4;
} }
if (bad_size) { /* i_size for symlinks is checked elsewhere */
if (bad_size && !LINUX_S_ISLNK(inode->i_mode)) {
pctx->num = (pb.last_block+1) * fs->blocksize; pctx->num = (pb.last_block+1) * fs->blocksize;
if (fix_problem(ctx, PR_1_BAD_I_SIZE, pctx)) { if (fix_problem(ctx, PR_1_BAD_I_SIZE, pctx)) {
inode->i_size = pctx->num; inode->i_size = pctx->num;
if (LINUX_S_ISREG(inode->i_mode)) if (!LINUX_S_ISDIR(inode->i_mode))
inode->i_size_high = pctx->num >> 32; inode->i_size_high = pctx->num >> 32;
dirty_inode++; dirty_inode++;
} }

View File

@ -259,15 +259,17 @@ static void pass1b(e2fsck_t ctx, char *block_buf)
while (ino) { while (ino) {
pctx.ino = ctx->stashed_ino = ino; pctx.ino = ctx->stashed_ino = ino;
if ((ino != EXT2_BAD_INO) && if ((ino != EXT2_BAD_INO) &&
(!ext2fs_test_inode_bitmap(ctx->inode_used_map, ino) || !ext2fs_test_inode_bitmap(ctx->inode_used_map, ino))
!ext2fs_inode_has_valid_blocks(&inode)))
goto next; goto next;
pb.ino = ino; pb.ino = ino;
pb.dup_blocks = 0; pb.dup_blocks = 0;
pb.inode = &inode; pb.inode = &inode;
pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
process_pass1b_block, &pb); if (ext2fs_inode_has_valid_blocks(&inode) ||
(ino == EXT2_BAD_INO))
pctx.errcode = ext2fs_block_iterate2(fs, ino,
0, block_buf, process_pass1b_block, &pb);
if (inode.i_file_acl) if (inode.i_file_acl)
process_pass1b_block(fs, &inode.i_file_acl, process_pass1b_block(fs, &inode.i_file_acl,
BLOCK_COUNT_EXTATTR, 0, 0, &pb); BLOCK_COUNT_EXTATTR, 0, 0, &pb);
@ -543,7 +545,7 @@ static int delete_file_block(ext2_filsys fs,
*block_nr); *block_nr);
} else { } else {
ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr); ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr);
ext2fs_unmark_block_bitmap(fs->block_map, *block_nr); ext2fs_block_alloc_stats(fs, *block_nr, -1);
} }
return 0; return 0;
@ -556,6 +558,7 @@ static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
struct process_block_struct pb; struct process_block_struct pb;
struct ext2_inode inode; struct ext2_inode inode;
struct problem_context pctx; struct problem_context pctx;
unsigned int count;
clear_problem_context(&pctx); clear_problem_context(&pctx);
pctx.ino = pb.ino = ino; pctx.ino = pb.ino = ino;
@ -563,23 +566,47 @@ static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
pb.ctx = ctx; pb.ctx = ctx;
pctx.str = "delete_file"; pctx.str = "delete_file";
pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf, e2fsck_read_inode(ctx, ino, &inode, "delete_file");
delete_file_block, &pb); if (ext2fs_inode_has_valid_blocks(&inode))
pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
delete_file_block, &pb);
if (pctx.errcode) if (pctx.errcode)
fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx); fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino); ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino); ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
if (ctx->inode_bad_map) if (ctx->inode_bad_map)
ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino); ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
ext2fs_unmark_inode_bitmap(fs->inode_map, ino); ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
ext2fs_mark_ib_dirty(fs);
ext2fs_mark_bb_dirty(fs); /* Inode may have changed by block_iterate, so reread it */
e2fsck_read_inode(ctx, ino, &inode, "delete_file"); e2fsck_read_inode(ctx, ino, &inode, "delete_file");
inode.i_links_count = 0; inode.i_links_count = 0;
inode.i_dtime = time(0); inode.i_dtime = time(0);
if (inode.i_file_acl) if (inode.i_file_acl &&
delete_file_block(fs, &inode.i_file_acl, (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
BLOCK_COUNT_EXTATTR, 0, 0, &pb); count = 1;
pctx.errcode = ext2fs_adjust_ea_refcount(fs, inode.i_file_acl,
block_buf, -1, &count);
if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
pctx.errcode = 0;
count = 1;
}
if (pctx.errcode) {
pctx.blk = inode.i_file_acl;
fix_problem(ctx, PR_1B_ADJ_EA_REFCOUNT, &pctx);
}
/*
* If the count is zero, then arrange to have the
* block deleted. If the block is in the block_dup_map,
* also call delete_file_block since it will take care
* of keeping the accounting straight.
*/
if ((count == 0) ||
ext2fs_test_block_bitmap(ctx->block_dup_map,
inode.i_file_acl))
delete_file_block(fs, &inode.i_file_acl,
BLOCK_COUNT_EXTATTR, 0, 0, &pb);
}
e2fsck_write_inode(ctx, ino, &inode, "delete_file"); e2fsck_write_inode(ctx, ino, &inode, "delete_file");
} }
@ -683,8 +710,9 @@ static int clone_file(e2fsck_t ctx, ext2_ino_t ino,
pctx.ino = ino; pctx.ino = ino;
pctx.str = "clone_file"; pctx.str = "clone_file";
pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf, if (ext2fs_inode_has_valid_blocks(&dp->inode))
clone_file_block, &cs); pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
clone_file_block, &cs);
ext2fs_mark_bb_dirty(fs); ext2fs_mark_bb_dirty(fs);
if (pctx.errcode) { if (pctx.errcode) {
fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx); fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
@ -697,6 +725,8 @@ static int clone_file(e2fsck_t ctx, ext2_ino_t ino,
retval = cs.errcode; retval = cs.errcode;
goto errout; goto errout;
} }
/* The inode may have changed on disk, so we have to re-read it */
e2fsck_read_inode(ctx, ino, &dp->inode, "clone file EA");
blk = dp->inode.i_file_acl; blk = dp->inode.i_file_acl;
if (blk && (clone_file_block(fs, &dp->inode.i_file_acl, if (blk && (clone_file_block(fs, &dp->inode.i_file_acl,
BLOCK_COUNT_EXTATTR, 0, 0, &cs) == BLOCK_COUNT_EXTATTR, 0, 0, &cs) ==
@ -717,7 +747,7 @@ static int clone_file(e2fsck_t ctx, ext2_ino_t ino,
if (di->inode.i_file_acl == blk) { if (di->inode.i_file_acl == blk) {
di->inode.i_file_acl = dp->inode.i_file_acl; di->inode.i_file_acl = dp->inode.i_file_acl;
e2fsck_write_inode(ctx, ino_el->inode, e2fsck_write_inode(ctx, ino_el->inode,
&dp->inode, "clone file EA"); &di->inode, "clone file EA");
decrement_badcount(ctx, blk, db); decrement_badcount(ctx, blk, db);
} }
} }

View File

@ -886,7 +886,7 @@ static int deallocate_inode_block(ext2_filsys fs,
if (HOLE_BLKADDR(*block_nr)) if (HOLE_BLKADDR(*block_nr))
return 0; return 0;
ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr); ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr);
ext2fs_unmark_block_bitmap(fs->block_map, *block_nr); ext2fs_block_alloc_stats(fs, *block_nr, -1);
return 0; return 0;
} }
@ -898,6 +898,7 @@ static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
ext2_filsys fs = ctx->fs; ext2_filsys fs = ctx->fs;
struct ext2_inode inode; struct ext2_inode inode;
struct problem_context pctx; struct problem_context pctx;
__u32 count;
ext2fs_icount_store(ctx->inode_link_info, ino, 0); ext2fs_icount_store(ctx->inode_link_info, ino, 0);
e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode"); e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode");
@ -915,8 +916,29 @@ static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino); ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
if (ctx->inode_bad_map) if (ctx->inode_bad_map)
ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino); ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
ext2fs_unmark_inode_bitmap(fs->inode_map, ino); ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
ext2fs_mark_ib_dirty(fs);
if (inode.i_file_acl &&
(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
pctx.errcode = ext2fs_adjust_ea_refcount(fs, inode.i_file_acl,
block_buf, -1, &count);
if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
pctx.errcode = 0;
count = 1;
}
if (pctx.errcode) {
pctx.blk = inode.i_file_acl;
fix_problem(ctx, PR_2_ADJ_EA_REFCOUNT, &pctx);
ctx->flags |= E2F_FLAG_ABORT;
return;
}
if (count == 0) {
ext2fs_unmark_block_bitmap(ctx->block_found_map,
inode.i_file_acl);
ext2fs_block_alloc_stats(fs, inode.i_file_acl, -1);
}
inode.i_file_acl = 0;
}
if (!ext2fs_inode_has_valid_blocks(&inode)) if (!ext2fs_inode_has_valid_blocks(&inode))
return; return;
@ -925,13 +947,6 @@ static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
(inode.i_size_high || inode.i_size & 0x80000000UL)) (inode.i_size_high || inode.i_size & 0x80000000UL))
ctx->large_files--; ctx->large_files--;
if (inode.i_file_acl) {
ext2fs_unmark_block_bitmap(ctx->block_found_map,
inode.i_file_acl);
ext2fs_unmark_block_bitmap(fs->block_map, inode.i_file_acl);
}
ext2fs_mark_bb_dirty(fs);
pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf, pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
deallocate_inode_block, ctx); deallocate_inode_block, ctx);
if (pctx.errcode) { if (pctx.errcode) {
@ -947,7 +962,6 @@ static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
static void clear_htree(e2fsck_t ctx, ext2_ino_t ino) static void clear_htree(e2fsck_t ctx, ext2_ino_t ino)
{ {
struct ext2_inode inode; struct ext2_inode inode;
struct problem_context pctx;
e2fsck_read_inode(ctx, ino, &inode, "clear_htree"); e2fsck_read_inode(ctx, ino, &inode, "clear_htree");
inode.i_flags = inode.i_flags & ~EXT2_INDEX_FL; inode.i_flags = inode.i_flags & ~EXT2_INDEX_FL;
@ -980,16 +994,16 @@ extern int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
!(LINUX_S_ISSOCK(inode.i_mode))) !(LINUX_S_ISSOCK(inode.i_mode)))
problem = PR_2_BAD_MODE; problem = PR_2_BAD_MODE;
else if (LINUX_S_ISCHR(inode.i_mode) else if (LINUX_S_ISCHR(inode.i_mode)
&& !e2fsck_pass1_check_device_inode(&inode)) && !e2fsck_pass1_check_device_inode(fs, &inode))
problem = PR_2_BAD_CHAR_DEV; problem = PR_2_BAD_CHAR_DEV;
else if (LINUX_S_ISBLK(inode.i_mode) else if (LINUX_S_ISBLK(inode.i_mode)
&& !e2fsck_pass1_check_device_inode(&inode)) && !e2fsck_pass1_check_device_inode(fs, &inode))
problem = PR_2_BAD_BLOCK_DEV; problem = PR_2_BAD_BLOCK_DEV;
else if (LINUX_S_ISFIFO(inode.i_mode) else if (LINUX_S_ISFIFO(inode.i_mode)
&& !e2fsck_pass1_check_device_inode(&inode)) && !e2fsck_pass1_check_device_inode(fs, &inode))
problem = PR_2_BAD_FIFO; problem = PR_2_BAD_FIFO;
else if (LINUX_S_ISSOCK(inode.i_mode) else if (LINUX_S_ISSOCK(inode.i_mode)
&& !e2fsck_pass1_check_device_inode(&inode)) && !e2fsck_pass1_check_device_inode(fs, &inode))
problem = PR_2_BAD_SOCKET; problem = PR_2_BAD_SOCKET;
else if (LINUX_S_ISLNK(inode.i_mode) else if (LINUX_S_ISLNK(inode.i_mode)
&& !e2fsck_pass1_check_symlink(fs, &inode, buf)) { && !e2fsck_pass1_check_symlink(fs, &inode, buf)) {

View File

@ -430,8 +430,7 @@ ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix)
return 0; return 0;
} }
ext2fs_mark_block_bitmap(ctx->block_found_map, blk); ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
ext2fs_mark_block_bitmap(fs->block_map, blk); ext2fs_block_alloc_stats(fs, blk, +1);
ext2fs_mark_bb_dirty(fs);
/* /*
* Next find a free inode. * Next find a free inode.
@ -445,8 +444,7 @@ ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix)
} }
ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino); ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino); ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino);
ext2fs_mark_inode_bitmap(fs->inode_map, ino); ext2fs_inode_alloc_stats2(fs, ino, +1, 1);
ext2fs_mark_ib_dirty(fs);
/* /*
* Now let's create the actual data block for the inode * Now let's create the actual data block for the inode
@ -594,10 +592,6 @@ static errcode_t adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino, int adj)
return 0; return 0;
ext2fs_icount_decrement(ctx->inode_link_info, ino, 0); ext2fs_icount_decrement(ctx->inode_link_info, ino, 0);
inode.i_links_count--; inode.i_links_count--;
} else {
/* Should never happen */
fatal_error(ctx, _("Debug error in e2fsck adjust_inode_count, "
"should never happen.\n"));
} }
retval = ext2fs_write_inode(fs, ino, &inode); retval = ext2fs_write_inode(fs, ino, &inode);

View File

@ -34,11 +34,14 @@ static int disconnect_inode(e2fsck_t ctx, ext2_ino_t i)
pctx.ino = i; pctx.ino = i;
pctx.inode = &inode; pctx.inode = &inode;
/*
* Offer to delete any zero-length files that does not have
* blocks. If there is an EA block, it might have useful
* information, so we won't prompt to delete it, but let it be
* reconnected to lost+found.
*/
if (!inode.i_blocks && (LINUX_S_ISREG(inode.i_mode) || if (!inode.i_blocks && (LINUX_S_ISREG(inode.i_mode) ||
LINUX_S_ISDIR(inode.i_mode))) { LINUX_S_ISDIR(inode.i_mode))) {
/*
* This is a zero-length file; prompt to delete it...
*/
if (fix_problem(ctx, PR_4_ZERO_LEN_INODE, &pctx)) { if (fix_problem(ctx, PR_4_ZERO_LEN_INODE, &pctx)) {
ext2fs_icount_store(ctx->inode_link_info, i, 0); ext2fs_icount_store(ctx->inode_link_info, i, 0);
inode.i_links_count = 0; inode.i_links_count = 0;
@ -51,8 +54,8 @@ static int disconnect_inode(e2fsck_t ctx, ext2_ino_t i)
e2fsck_read_bitmaps(ctx); e2fsck_read_bitmaps(ctx);
ext2fs_unmark_inode_bitmap(ctx->inode_used_map, i); ext2fs_unmark_inode_bitmap(ctx->inode_used_map, i);
ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, i); ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, i);
ext2fs_unmark_inode_bitmap(fs->inode_map, i); ext2fs_inode_alloc_stats2(fs, i, -1,
ext2fs_mark_ib_dirty(fs); LINUX_S_ISDIR(inode.i_mode));
return 0; return 0;
} }
} }

View File

@ -736,6 +736,12 @@ static const struct e2fsck_problem problem_table[] = {
N_("Error while iterating over @bs in @i %i (%s): %m\n"), N_("Error while iterating over @bs in @i %i (%s): %m\n"),
PROMPT_NONE, 0 }, PROMPT_NONE, 0 },
/* Error adjusting EA refcount */
{ PR_1B_ADJ_EA_REFCOUNT,
N_("Error addjusting refcount for @a @b %b (@i %i): %m\n"),
PROMPT_NONE, 0 },
/* Pass 1C: Scan directories for inodes with dup blocks. */ /* Pass 1C: Scan directories for inodes with dup blocks. */
{ PR_1C_PASS_HEADER, { PR_1C_PASS_HEADER,
N_("Pass 1C: Scan directories for @is with dup @bs.\n"), N_("Pass 1C: Scan directories for @is with dup @bs.\n"),
@ -1051,6 +1057,11 @@ static const struct e2fsck_problem problem_table[] = {
N_("@p @h %d (%q): bad @b number %b.\n"), N_("@p @h %d (%q): bad @b number %b.\n"),
PROMPT_CLEAR_HTREE, 0 }, PROMPT_CLEAR_HTREE, 0 },
/* Error adjusting EA refcount */
{ PR_2_ADJ_EA_REFCOUNT,
N_("Error addjusting refcount for @a @b %b (@i %i): %m\n"),
PROMPT_NONE, PR_FATAL },
/* Pass 3 errors */ /* Pass 3 errors */
/* Pass 3: Checking directory connectivity */ /* Pass 3: Checking directory connectivity */

View File

@ -429,6 +429,9 @@ struct problem_context {
/* Error while iterating over blocks */ /* Error while iterating over blocks */
#define PR_1B_BLOCK_ITERATE 0x0110006 #define PR_1B_BLOCK_ITERATE 0x0110006
/* Error adjusting EA refcount */
#define PR_1B_ADJ_EA_REFCOUNT 0x0110007
/* Pass 1C: Scan directories for inodes with dup blocks. */ /* Pass 1C: Scan directories for inodes with dup blocks. */
#define PR_1C_PASS_HEADER 0x012000 #define PR_1C_PASS_HEADER 0x012000
@ -624,6 +627,9 @@ struct problem_context {
/* Bad block in htree interior node */ /* Bad block in htree interior node */
#define PR_2_HTREE_BADBLK 0x02003A #define PR_2_HTREE_BADBLK 0x02003A
/* Error adjusting EA refcount */
#define PR_2_ADJ_EA_REFCOUNT 0x02003B
/* /*
* Pass 3 errors * Pass 3 errors
*/ */

View File

@ -152,10 +152,7 @@ static int release_inode_block(ext2_filsys fs,
retval |= BLOCK_CHANGED; retval |= BLOCK_CHANGED;
} }
ext2fs_unmark_block_bitmap(fs->block_map, blk); ext2fs_block_alloc_stats(fs, blk, -1);
fs->group_desc[ext2fs_group_of_blk(fs, blk)].bg_free_blocks_count++;
fs->super->s_free_blocks_count++;
return retval; return retval;
} }
@ -168,9 +165,10 @@ static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino,
struct ext2_inode *inode, char *block_buf, struct ext2_inode *inode, char *block_buf,
struct problem_context *pctx) struct problem_context *pctx)
{ {
struct process_block_struct pb;
ext2_filsys fs = ctx->fs; ext2_filsys fs = ctx->fs;
errcode_t retval; errcode_t retval;
struct process_block_struct pb; __u32 count;
if (!ext2fs_inode_has_valid_blocks(inode)) if (!ext2fs_inode_has_valid_blocks(inode))
return 0; return 0;
@ -211,7 +209,23 @@ static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino,
inode->i_blocks -= pb.truncated_blocks * inode->i_blocks -= pb.truncated_blocks *
(fs->blocksize / 512); (fs->blocksize / 512);
ext2fs_mark_bb_dirty(fs); if (inode->i_file_acl) {
retval = ext2fs_adjust_ea_refcount(fs, inode->i_file_acl,
block_buf, -1, &count);
if (retval == EXT2_ET_BAD_EA_BLOCK_NUM) {
retval = 0;
count = 1;
}
if (retval) {
com_err("release_inode_blocks", retval,
_("while calling ext2fs_adjust_ea_refocunt for inode %d"),
ino);
return 1;
}
if (count == 0)
ext2fs_block_alloc_stats(fs, inode->i_file_acl, -1);
inode->i_file_acl = 0;
}
return 0; return 0;
} }
@ -222,7 +236,6 @@ static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino,
static int release_orphan_inodes(e2fsck_t ctx) static int release_orphan_inodes(e2fsck_t ctx)
{ {
ext2_filsys fs = ctx->fs; ext2_filsys fs = ctx->fs;
int group;
ext2_ino_t ino, next_ino; ext2_ino_t ino, next_ino;
struct ext2_inode inode; struct ext2_inode inode;
struct problem_context pctx; struct problem_context pctx;
@ -281,14 +294,8 @@ static int release_orphan_inodes(e2fsck_t ctx)
goto return_abort; goto return_abort;
if (!inode.i_links_count) { if (!inode.i_links_count) {
ext2fs_unmark_inode_bitmap(fs->inode_map, ino); ext2fs_inode_alloc_stats2(fs, ino, -1,
ext2fs_mark_ib_dirty(fs); LINUX_S_ISDIR(inode.i_mode));
group = ext2fs_group_of_ino(fs, ino);
fs->group_desc[group].bg_free_inodes_count++;
fs->super->s_free_inodes_count++;
if (LINUX_S_ISDIR(inode.i_mode))
fs->group_desc[group].bg_used_dirs_count--;
inode.i_dtime = time(0); inode.i_dtime = time(0);
} else { } else {
inode.i_dtime = 0; inode.i_dtime = 0;

View File

@ -61,7 +61,8 @@ static void usage(e2fsck_t ctx)
fprintf(stderr, fprintf(stderr,
_("Usage: %s [-panyrcdfvstFSV] [-b superblock] [-B blocksize]\n" _("Usage: %s [-panyrcdfvstFSV] [-b superblock] [-B blocksize]\n"
"\t\t[-I inode_buffer_blocks] [-P process_inode_size]\n" "\t\t[-I inode_buffer_blocks] [-P process_inode_size]\n"
"\t\t[-l|-L bad_blocks_file] [-C fd] [-j ext-journal] device\n"), "\t\t[-l|-L bad_blocks_file] [-C fd] [-j ext-journal]\n"
"\t\t[-E extended-options] device\n"),
ctx->program_name); ctx->program_name);
fprintf(stderr, _("\nEmergency help:\n" fprintf(stderr, _("\nEmergency help:\n"
@ -448,6 +449,60 @@ static void signal_cancel(int sig)
} }
#endif #endif
static void parse_extended_opts(e2fsck_t ctx, const char *opts)
{
char *buf, *token, *next, *p, *arg;
int len, ea_ver;
int extended_usage = 0;
len = strlen(opts);
buf = malloc(len+1);
if (!buf) {
fprintf(stderr, _("Couldn't allocate memory to parse "
"extended options!\n"));
exit(1);
}
strcpy(buf, opts);
for (token = buf; token && *token; token = next) {
p = strchr(token, ',');
next = 0;
if (p) {
*p = 0;
next = p+1;
}
arg = strchr(token, '=');
if (arg) {
*arg = 0;
arg++;
}
if (strcmp(token, "ea_ver") == 0) {
if (!arg) {
extended_usage++;
continue;
}
ea_ver = strtoul(arg, &p, 0);
if (*p ||
((ea_ver != 1) && (ea_ver != 2))) {
fprintf(stderr,
_("Invalid EA version.\n"));
extended_usage++;
continue;
}
ctx->ext_attr_ver = ea_ver;
} else
extended_usage++;
}
if (extended_usage) {
fprintf(stderr, _("Extended options are separated by commas, "
"and may take an argument which\n"
"is set off by an equals ('=') sign. "
"Valid raid options are:\n"
"\tea_ver=<ea_version (1 or 2)\n\n"));
exit(1);
}
}
static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
{ {
int flush = 0; int flush = 0;
@ -460,6 +515,7 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
#ifdef HAVE_SIGNAL_H #ifdef HAVE_SIGNAL_H
struct sigaction sa; struct sigaction sa;
#endif #endif
char *extended_opts = 0;
retval = e2fsck_allocate_context(&ctx); retval = e2fsck_allocate_context(&ctx);
if (retval) if (retval)
@ -475,7 +531,7 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
ctx->program_name = *argv; ctx->program_name = *argv;
else else
ctx->program_name = "e2fsck"; ctx->program_name = "e2fsck";
while ((c = getopt (argc, argv, "panyrcC:B:dfvtFVM:b:I:j:P:l:L:N:SsD")) != EOF) while ((c = getopt (argc, argv, "panyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsD")) != EOF)
switch (c) { switch (c) {
case 'C': case 'C':
ctx->progress = e2fsck_update_progress; ctx->progress = e2fsck_update_progress;
@ -497,6 +553,9 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
case 'D': case 'D':
ctx->options |= E2F_OPT_COMPRESS_DIRS; ctx->options |= E2F_OPT_COMPRESS_DIRS;
break; break;
case 'E':
extended_opts = optarg;
break;
case 'p': case 'p':
case 'a': case 'a':
ctx->options |= E2F_OPT_PREEN; ctx->options |= E2F_OPT_PREEN;
@ -602,6 +661,9 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
!cflag && !swapfs && !(ctx->options & E2F_OPT_COMPRESS_DIRS)) !cflag && !swapfs && !(ctx->options & E2F_OPT_COMPRESS_DIRS))
ctx->options |= E2F_OPT_READONLY; ctx->options |= E2F_OPT_READONLY;
ctx->filesystem_name = argv[optind]; ctx->filesystem_name = argv[optind];
if (extended_opts)
parse_extended_opts(ctx, extended_opts);
if (flush) { if (flush) {
fd = open(ctx->filesystem_name, O_RDONLY, 0); fd = open(ctx->filesystem_name, O_RDONLY, 0);
if (fd < 0) { if (fd < 0) {

View File

@ -1,3 +1,18 @@
2002-08-16 Theodore Ts'o <tytso@mit.edu>
* ext2_err.et.in (EXT2_ET_BAD_EA_BLOCK_NUM): New error code
* ext2fs.h (ext2fs_inode_data_blocks): New function which returns
the number of data blocks used by an inode exclusive of
the EA block.
* ext_attr.c (ext2fs_adjust_ea_refcount): New function which
adjusts the reference count in an extended attribute block.
* valid_blk.c (ext2fs_inode_has_valid_blocks): Add code to
correctly deal with extended attribute blocks in symbolic
links.
2002-08-13 <tytso@snap.thunk.org> 2002-08-13 <tytso@snap.thunk.org>
* Makefile.in: Move dupfs.o and test_io.o from the * Makefile.in: Move dupfs.o and test_io.o from the

View File

@ -278,5 +278,8 @@ ec EXT2_ET_NO_JOURNAL,
ec EXT2_ET_DIRHASH_UNSUPP, ec EXT2_ET_DIRHASH_UNSUPP,
"Directory hash unsupported" "Directory hash unsupported"
ec EXT2_ET_BAD_EA_BLOCK_NUM,
"Illegal extended attribute block number"
end end

View File

@ -663,7 +663,12 @@ extern errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir);
/* ext_attr.c */ /* ext_attr.c */
void ext2fs_swap_ext_attr(ext2_filsys fs, char *to, char *from); void ext2fs_swap_ext_attr(ext2_filsys fs, char *to, char *from);
extern errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf); extern errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf);
extern errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block, void *buf); extern errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block,
void *buf);
extern errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
char *block_buf,
int adjust, __u32 *newcount);
/* fileio.c */ /* fileio.c */
extern errcode_t ext2fs_file_open(ext2_filsys fs, ext2_ino_t ino, extern errcode_t ext2fs_file_open(ext2_filsys fs, ext2_ino_t ino,
int flags, ext2_file_t *ret); int flags, ext2_file_t *ret);
@ -873,6 +878,8 @@ extern int ext2fs_test_ib_dirty(ext2_filsys fs);
extern int ext2fs_test_bb_dirty(ext2_filsys fs); extern int ext2fs_test_bb_dirty(ext2_filsys fs);
extern int ext2fs_group_of_blk(ext2_filsys fs, blk_t blk); extern int ext2fs_group_of_blk(ext2_filsys fs, blk_t blk);
extern int ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino); extern int ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino);
extern blk_t ext2fs_inode_data_blocks(ext2_filsys fs,
struct ext2_inode *inode);
/* /*
* The actual inlined functions definitions themselves... * The actual inlined functions definitions themselves...
@ -1025,6 +1032,13 @@ _INLINE_ int ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino)
{ {
return (ino - 1) / fs->super->s_inodes_per_group; return (ino - 1) / fs->super->s_inodes_per_group;
} }
_INLINE_ blk_t ext2fs_inode_data_blocks(ext2_filsys fs,
struct ext2_inode *inode)
{
return inode->i_blocks -
(inode->i_file_acl ? fs->blocksize >> 9 : 0);
}
#undef _INLINE_ #undef _INLINE_
#endif #endif

View File

@ -1,7 +1,9 @@
/* /*
* ext_attr.c --- extended attribute blocks * ext_attr.c --- extended attribute blocks
* *
* Copyright (C) Andreas Gruenbacher, <a.gruenbacher@computer.org> * Copyright (C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org>
*
* Copyright (C) 2002 Theodore Ts'o.
* *
* %Begin-Header% * %Begin-Header%
* This file may be redistributed under the terms of the GNU Public * This file may be redistributed under the terms of the GNU Public
@ -96,3 +98,44 @@ errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block, void *inbuf)
ext2fs_mark_changed(fs); ext2fs_mark_changed(fs);
return retval; return retval;
} }
/*
* This function adjusts the reference count of the EA block.
*/
errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
char *block_buf, int adjust,
__u32 *newcount)
{
errcode_t retval;
struct ext2_ext_attr_header *header;
char *buf = 0;
if ((blk >= fs->super->s_blocks_count) ||
(blk < fs->super->s_first_data_block))
return EXT2_ET_BAD_EA_BLOCK_NUM;
if (!block_buf) {
retval = ext2fs_get_mem(fs->blocksize, (void **) &buf);
if (retval)
return retval;
block_buf = buf;
}
retval = ext2fs_read_ext_attr(fs, blk, block_buf);
if (retval)
goto errout;
header = (struct ext2_ext_attr_header *) block_buf;
header->h_refcount += adjust;
if (newcount)
*newcount = header->h_refcount;
retval = ext2fs_write_ext_attr(fs, blk, block_buf);
if (retval)
goto errout;
errout:
if (buf)
ext2fs_free_mem((void **) &buf);
return retval;
}

View File

@ -38,8 +38,19 @@ int ext2fs_inode_has_valid_blocks(struct ext2_inode *inode)
* If the symbolic link is a "fast symlink", then the symlink * If the symbolic link is a "fast symlink", then the symlink
* target is stored in the block entries. * target is stored in the block entries.
*/ */
if (LINUX_S_ISLNK (inode->i_mode) && inode->i_blocks == 0) if (LINUX_S_ISLNK (inode->i_mode)) {
return 0; if (inode->i_file_acl == 0) {
/* With no EA block, we can rely on i_blocks */
if (inode->i_blocks == 0)
return 0;
} else {
/* With an EA block, life gets more tricky */
if (inode->i_size >= EXT2_N_BLOCKS*4)
return 1; /* definitely using i_block[] */
if (inode->i_size > 3 && inode->i_block[1] != 0)
return 1; /* probably using i_block[] */
return 0; /* Probably a fast symlink */
}
}
return 1; return 1;
} }

View File

@ -1,3 +1,17 @@
2002-08-17 Theodore Ts'o <tytso@mit.edu>
* f_badinode, f_badroot, f_badsymlinks, f_badtable, f_dupdot,
f_filetype, f_illitable, f_imagic, f_imagic_fs, f_lpf,
f_lpffile, f_mke2fs2b, f_noroot, f_recnect_bad: Update
expect files to deal with changes in the extended
attribute block processing, and in how e2fsck updates
filesystem statistics when deleting files and creating
/lost+found.
* f_special_ea: New test which checks to make sure e2fsck
correctly handles special device files with extended
attribute blocks.
2002-08-01 Theodore Ts'o <tytso@mit.edu> 2002-08-01 Theodore Ts'o <tytso@mit.edu>
* f_dup, f_dup2, f_dup3, f_bbfile, f_dupfsblks: Update expect * f_dup, f_dup2, f_dup3, f_bbfile, f_dupfsblks: Update expect

View File

@ -1,6 +1,8 @@
Filesystem did not have a UUID; generating one. Filesystem did not have a UUID; generating one.
Pass 1: Checking inodes, blocks, and sizes Pass 1: Checking inodes, blocks, and sizes
Inode 12, i_blocks is 2, should be 0. Fix? yes
Pass 2: Checking directory structure Pass 2: Checking directory structure
Inode 12 (/motd) has a bad mode (0110444). Inode 12 (/motd) has a bad mode (0110444).
Clear? yes Clear? yes
@ -32,12 +34,6 @@ Fix? yes
Free blocks count wrong (76, counted=77). Free blocks count wrong (76, counted=77).
Fix? yes Fix? yes
Free inodes count wrong for group #0 (16, counted=20).
Fix? yes
Free inodes count wrong (16, counted=20).
Fix? yes
test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
test_filesys: 12/32 files (0.0% non-contiguous), 23/100 blocks test_filesys: 12/32 files (0.0% non-contiguous), 23/100 blocks

View File

@ -23,21 +23,6 @@ Connect to /lost+found? yes
Inode 12 ref count is 2, should be 1. Fix? yes Inode 12 ref count is 2, should be 1. Fix? yes
Pass 5: Checking group summary information Pass 5: Checking group summary information
Free blocks count wrong for group #0 (77, counted=76).
Fix? yes
Free blocks count wrong (77, counted=76).
Fix? yes
Free inodes count wrong for group #0 (20, counted=19).
Fix? yes
Directories count wrong for group #0 (2, counted=3).
Fix? yes
Free inodes count wrong (20, counted=19).
Fix? yes
test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
test_filesys: 13/32 files (0.0% non-contiguous), 24/100 blocks test_filesys: 13/32 files (0.0% non-contiguous), 24/100 blocks

View File

@ -1,6 +1,4 @@
Pass 1: Checking inodes, blocks, and sizes Pass 1: Checking inodes, blocks, and sizes
Inode 16, i_size is 4294967358, should be 1024. Fix? yes
Special (device/socket/fifo/symlink) file (inode 18) has immutable Special (device/socket/fifo/symlink) file (inode 18) has immutable
or append-only flag set. Clear? yes or append-only flag set. Clear? yes
@ -51,16 +49,10 @@ Clear? yes
Pass 3: Checking directory connectivity Pass 3: Checking directory connectivity
Pass 4: Checking reference counts Pass 4: Checking reference counts
Pass 5: Checking group summary information Pass 5: Checking group summary information
Free blocks count wrong for group #0 (995, counted=1001). Free blocks count wrong for group #0 (1000, counted=1001).
Fix? yes Fix? yes
Free blocks count wrong (995, counted=1001). Free blocks count wrong (1000, counted=1001).
Fix? yes
Free inodes count wrong for group #0 (9, counted=19).
Fix? yes
Free inodes count wrong (9, counted=19).
Fix? yes Fix? yes

View File

@ -21,19 +21,22 @@ Pass 5: Checking group summary information
Block bitmap differences: -(12--20) Block bitmap differences: -(12--20)
Fix? yes Fix? yes
Free blocks count wrong for group #0 (78, counted=87). Free blocks count wrong for group #0 (77, counted=87).
Fix? yes Fix? yes
Free blocks count wrong (78, counted=87). Free blocks count wrong (77, counted=87).
Fix? yes Fix? yes
Inode bitmap differences: +(12--16) +(25--32) Inode bitmap differences: +(12--16) +(25--32)
Fix? yes Fix? yes
Free inodes count wrong for group #0 (21, counted=7). Free inodes count wrong for group #0 (20, counted=7).
Fix? yes Fix? yes
Free inodes count wrong (21, counted=7). Directories count wrong for group #0 (3, counted=2).
Fix? yes
Free inodes count wrong (20, counted=7).
Fix? yes Fix? yes

View File

@ -16,12 +16,6 @@ Inode 13 ref count is 2, should be 1. Fix? yes
Unattached zero-length inode 14. Clear? yes Unattached zero-length inode 14. Clear? yes
Pass 5: Checking group summary information Pass 5: Checking group summary information
Free inodes count wrong for group #0 (2, counted=3).
Fix? yes
Free inodes count wrong (2, counted=3).
Fix? yes
test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
test_filesys: 13/16 files (0.0% non-contiguous), 22/100 blocks test_filesys: 13/16 files (0.0% non-contiguous), 22/100 blocks

View File

@ -37,6 +37,12 @@ Setting filetype for entry '..' in /dir (13) to 2.
Pass 3: Checking directory connectivity Pass 3: Checking directory connectivity
Pass 4: Checking reference counts Pass 4: Checking reference counts
Pass 5: Checking group summary information Pass 5: Checking group summary information
Free inodes count wrong for group #0 (50, counted=47).
Fix? yes
Free inodes count wrong (50, counted=47).
Fix? yes
test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
test_filesys: 17/64 files (0.0% non-contiguous), 27/100 blocks test_filesys: 17/64 files (0.0% non-contiguous), 27/100 blocks

View File

@ -28,10 +28,19 @@ Pass 5: Checking group summary information
Block bitmap differences: -(11--21) Block bitmap differences: -(11--21)
Fix? yes Fix? yes
Free blocks count wrong for group #0 (78, counted=89). Free blocks count wrong for group #0 (77, counted=89).
Fix? yes Fix? yes
Free blocks count wrong (78, counted=89). Free blocks count wrong (77, counted=89).
Fix? yes
Free inodes count wrong for group #0 (20, counted=21).
Fix? yes
Directories count wrong for group #0 (3, counted=2).
Fix? yes
Free inodes count wrong (20, counted=21).
Fix? yes Fix? yes

View File

@ -26,10 +26,19 @@ Pass 5: Checking group summary information
Block bitmap differences: -(9--19) Block bitmap differences: -(9--19)
Fix? yes Fix? yes
Free blocks count wrong for group #0 (76, counted=87). Free blocks count wrong for group #0 (75, counted=87).
Fix? yes Fix? yes
Free blocks count wrong (76, counted=87). Free blocks count wrong (75, counted=87).
Fix? yes
Free inodes count wrong for group #0 (1, counted=2).
Fix? yes
Directories count wrong for group #0 (3, counted=2).
Fix? yes
Free inodes count wrong (1, counted=2).
Fix? yes Fix? yes

View File

@ -10,10 +10,19 @@ Pass 5: Checking group summary information
Block bitmap differences: -(9--19) Block bitmap differences: -(9--19)
Fix? yes Fix? yes
Free blocks count wrong for group #0 (76, counted=87). Free blocks count wrong for group #0 (75, counted=87).
Fix? yes Fix? yes
Free blocks count wrong (76, counted=87). Free blocks count wrong (75, counted=87).
Fix? yes
Free inodes count wrong for group #0 (1, counted=2).
Fix? yes
Directories count wrong for group #0 (3, counted=2).
Fix? yes
Free inodes count wrong (1, counted=2).
Fix? yes Fix? yes

View File

@ -27,22 +27,19 @@ Pass 5: Checking group summary information
Block bitmap differences: +(22--23) +49 +(57--58) Block bitmap differences: +(22--23) +49 +(57--58)
Fix? yes Fix? yes
Free blocks count wrong for group #0 (25, counted=33). Free blocks count wrong for group #0 (24, counted=33).
Fix? yes Fix? yes
Free blocks count wrong (39, counted=33). Free blocks count wrong (38, counted=33).
Fix? yes Fix? yes
Inode bitmap differences: +13 Inode bitmap differences: +13
Fix? yes Fix? yes
Free inodes count wrong for group #0 (2, counted=0). Free inodes count wrong for group #0 (1, counted=0).
Fix? yes Fix? yes
Directories count wrong for group #0 (1, counted=2). Free inodes count wrong (1, counted=0).
Fix? yes
Free inodes count wrong (2, counted=0).
Fix? yes Fix? yes

View File

@ -26,21 +26,6 @@ Connect to /lost+found? yes
Inode 14 ref count is 2, should be 1. Fix? yes Inode 14 ref count is 2, should be 1. Fix? yes
Pass 5: Checking group summary information Pass 5: Checking group summary information
Free blocks count wrong for group #0 (86, counted=85).
Fix? yes
Free blocks count wrong (86, counted=85).
Fix? yes
Free inodes count wrong for group #0 (18, counted=17).
Fix? yes
Directories count wrong for group #0 (1, counted=2).
Fix? yes
Free inodes count wrong (18, counted=17).
Fix? yes
test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
test_filesys: 15/32 files (0.0% non-contiguous), 15/100 blocks test_filesys: 15/32 files (0.0% non-contiguous), 15/100 blocks

View File

@ -13,6 +13,12 @@ Pass 4: Checking reference counts
Unattached zero-length inode 15. Clear? yes Unattached zero-length inode 15. Clear? yes
Pass 5: Checking group summary information Pass 5: Checking group summary information
Free inodes count wrong for group #0 (18, counted=17).
Fix? yes
Free inodes count wrong (18, counted=17).
Fix? yes
test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
test_filesys: 15/32 files (0.0% non-contiguous), 25/100 blocks test_filesys: 15/32 files (0.0% non-contiguous), 25/100 blocks

View File

@ -27,18 +27,9 @@ Inode 12 ref count is 4, should be 3. Fix? yes
Unattached zero-length inode 15. Clear? yes Unattached zero-length inode 15. Clear? yes
Pass 5: Checking group summary information Pass 5: Checking group summary information
Free blocks count wrong for group #0 (75, counted=74).
Fix? yes
Free blocks count wrong (75, counted=74).
Fix? yes
Free inodes count wrong for group #0 (17, counted=16). Free inodes count wrong for group #0 (17, counted=16).
Fix? yes Fix? yes
Directories count wrong for group #0 (4, counted=5).
Fix? yes
Free inodes count wrong (17, counted=16). Free inodes count wrong (17, counted=16).
Fix? yes Fix? yes

View File

@ -23,6 +23,12 @@ Inode 28 (...) has a bad mode (0177777).
Clear? yes Clear? yes
Pass 5: Checking group summary information Pass 5: Checking group summary information
Free inodes count wrong for group #0 (18, counted=17).
Fix? yes
Free inodes count wrong (18, counted=17).
Fix? yes
test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
test_filesys: 15/32 files (0.0% non-contiguous), 26/100 blocks test_filesys: 15/32 files (0.0% non-contiguous), 26/100 blocks

View File

@ -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: 17/1024 files (0.0% non-contiguous), 1180/4096 blocks
Exit status is 1

BIN
tests/f_special_ea/image.gz Normal file

Binary file not shown.

1
tests/f_special_ea/name Normal file
View File

@ -0,0 +1 @@
Special files with extended attributes

View File

@ -0,0 +1,2 @@
ONE_PASS_ONLY="true"
. $cmd_dir/run_e2fsck