summaryrefslogtreecommitdiff
path: root/e2fsck
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2010-11-26 19:09:43 -0500
committerTheodore Ts'o <tytso@mit.edu>2010-11-26 19:09:43 -0500
commit992016c5afde0f77a9ff10c4fc5be02f83eb055c (patch)
tree35b8973cb219708478c3ee372c22fa9a34db174c /e2fsck
parent6a81b40ae7f1334dc8b3872534d2abb0646eafbd (diff)
downloade2fsprogs-992016c5afde0f77a9ff10c4fc5be02f83eb055c.tar.gz
e2fsck: Fix inode nlink accounting that could cause PROGRAMMING BUG errors
This fixes two possible causes for the error message: WARNING: PROGRAMMING BUG IN E2FSCK! OR SOME BONEHEAD (YOU) IS CHECKING A MOUNTED (LIVE) FILESYSTEM. inode_link_info[X] is Y, inode.i_links_count is Z. They should be the same! One cause which can trigger this message is when an inode has an illegal link count > 65500 --- for example, 65535. This was the case in the Debian Bug report #555456. Another cause which could trigger this message is if an ext4 directory previously had more than 65000 subdirectories (thus causing i_link_count to be set to 1), but then some of the subdirectories were deleted, such that i_link_count should now be the actual number of subdirectories. Addresses-Debian-Bug: #555456 Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'e2fsck')
-rw-r--r--e2fsck/pass4.c12
1 files changed, 7 insertions, 5 deletions
diff --git a/e2fsck/pass4.c b/e2fsck/pass4.c
index d9706cea..515cb84d 100644
--- a/e2fsck/pass4.c
+++ b/e2fsck/pass4.c
@@ -121,6 +121,8 @@ void e2fsck_pass4(e2fsck_t ctx)
/* Protect loop from wrap-around if s_inodes_count maxed */
for (i=1; i <= fs->super->s_inodes_count && i > 0; i++) {
+ int isdir = ext2fs_test_inode_bitmap(ctx->inode_dir_map, i);
+
if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
goto errout;
if ((i % fs->super->s_inodes_per_group) == 0) {
@@ -153,14 +155,14 @@ void e2fsck_pass4(e2fsck_t ctx)
ext2fs_icount_fetch(ctx->inode_count, i,
&link_counted);
}
- if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, i) &&
- (link_counted > EXT2_LINK_MAX))
+ if (isdir && (link_counted > EXT2_LINK_MAX))
link_counted = 1;
if (link_counted != link_count) {
e2fsck_read_inode(ctx, i, inode, "pass4");
pctx.ino = i;
pctx.inode = inode;
- if (link_count != inode->i_links_count) {
+ if ((link_count != inode->i_links_count) && !isdir &&
+ (inode->i_links_count <= EXT2_LINK_MAX)) {
pctx.num = link_count;
fix_problem(ctx,
PR_4_INCONSISTENT_COUNT, &pctx);
@@ -168,10 +170,10 @@ void e2fsck_pass4(e2fsck_t ctx)
pctx.num = link_counted;
/* i_link_count was previously exceeded, but no longer
* is, fix this but don't consider it an error */
- if ((LINUX_S_ISDIR(inode->i_mode) && link_counted > 1 &&
+ if ((isdir && link_counted > 1 &&
(inode->i_flags & EXT2_INDEX_FL) &&
link_count == 1 && !(ctx->options & E2F_OPT_NO)) ||
- (fix_problem(ctx, PR_4_BAD_REF_COUNT, &pctx))) {
+ fix_problem(ctx, PR_4_BAD_REF_COUNT, &pctx)) {
inode->i_links_count = link_counted;
e2fsck_write_inode(ctx, i, inode, "pass4");
}