diff options
author | Theodore Ts'o <tytso@mit.edu> | 2010-11-26 19:09:43 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2010-11-26 19:09:43 -0500 |
commit | 992016c5afde0f77a9ff10c4fc5be02f83eb055c (patch) | |
tree | 35b8973cb219708478c3ee372c22fa9a34db174c /e2fsck | |
parent | 6a81b40ae7f1334dc8b3872534d2abb0646eafbd (diff) | |
download | e2fsprogs-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.c | 12 |
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"); } |