aboutsummaryrefslogtreecommitdiff
path: root/e2fsck
diff options
context:
space:
mode:
authorAndreas Dilger <adilger@dilger.ca>2018-06-22 18:08:54 -0400
committerTheodore Ts'o <tytso@mit.edu>2018-06-22 18:08:54 -0400
commit1a8015773a9316ee90f713c275fb3a38731735e4 (patch)
tree0cf0538120d4faca5a099463d82f946532aedd78 /e2fsck
parentc759616b8740a25e3e51e4add8df140514ff32ba (diff)
downloade2fsprogs-1a8015773a9316ee90f713c275fb3a38731735e4.tar.gz
e2fsck: set dir_nlink feature if large dir exists
If there is a directory with more than EXT2_LINK_MAX (65000) subdirectories, but the DIR_NLINK feature is not set in the superblock, the feature should be set before continuing on to change the on-disk directory link count to 1. While most filesystems should have DIR_NLINK set (it was set by default for all ext4 filesystems, and all kernels between 2.6.23 and 4.12 automatically set it if the directory link count grew too large), it is possible that this flag is lost due to disk corruption or for an upgraded filesystem. We no longer want kernels to automatically enable features. Addresses: https://bugzilla.kernel.org/show_bug.cgi?id=196405 Signed-off-by: Andreas Dilger <adilger@dilger.ca> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Diffstat (limited to 'e2fsck')
-rw-r--r--e2fsck/pass4.c12
-rw-r--r--e2fsck/problem.c5
-rw-r--r--e2fsck/problem.h3
3 files changed, 19 insertions, 1 deletions
diff --git a/e2fsck/pass4.c b/e2fsck/pass4.c
index 9a491b13..10be7f87 100644
--- a/e2fsck/pass4.c
+++ b/e2fsck/pass4.c
@@ -145,6 +145,7 @@ void e2fsck_pass4(e2fsck_t ctx)
#endif
struct problem_context pctx;
__u16 link_count, link_counted;
+ int dir_nlink_fs;
char *buf = 0;
dgrp_t group, maxgroup;
@@ -168,6 +169,8 @@ void e2fsck_pass4(e2fsck_t ctx)
if (!(ctx->options & E2F_OPT_PREEN))
fix_problem(ctx, PR_4_PASS_HEADER, &pctx);
+ dir_nlink_fs = ext2fs_has_feature_dir_nlink(fs->super);
+
group = 0;
maxgroup = fs->group_desc_count;
if (ctx->progress)
@@ -224,8 +227,15 @@ void e2fsck_pass4(e2fsck_t ctx)
&link_counted);
}
isdir = ext2fs_test_inode_bitmap2(ctx->inode_dir_map, i);
- if (isdir && (link_counted > EXT2_LINK_MAX))
+ if (isdir && (link_counted > EXT2_LINK_MAX)) {
+ if (!dir_nlink_fs &&
+ fix_problem(ctx, PR_4_DIR_NLINK_FEATURE, &pctx)) {
+ ext2fs_set_feature_dir_nlink(fs->super);
+ ext2fs_mark_super_dirty(fs);
+ dir_nlink_fs = 1;
+ }
link_counted = 1;
+ }
if (link_counted != link_count) {
e2fsck_read_inode_full(ctx, i, EXT2_INODE(inode),
inode_size, "pass4");
diff --git a/e2fsck/problem.c b/e2fsck/problem.c
index efe98c92..a98bf8c8 100644
--- a/e2fsck/problem.c
+++ b/e2fsck/problem.c
@@ -1883,6 +1883,11 @@ static struct e2fsck_problem problem_table[] = {
N_("@a @i %i ref count is %N, @s %n. "),
PROMPT_FIX, PR_PREEN_OK },
+ /* directory exceeds max links, but no DIR_NLINK feature in superblock*/
+ { PR_4_DIR_NLINK_FEATURE,
+ N_("@d exceeds max links, but no DIR_NLINK feature in @S.\n"),
+ PROMPT_FIX, 0 },
+
/* Pass 5 errors */
/* Pass 5: Checking group summary information */
diff --git a/e2fsck/problem.h b/e2fsck/problem.h
index b6bca668..7db122ab 100644
--- a/e2fsck/problem.h
+++ b/e2fsck/problem.h
@@ -1139,6 +1139,9 @@ struct problem_context {
/* Extended attribute inode ref count wrong */
#define PR_4_EA_INODE_REF_COUNT 0x040005
+/* directory exceeds max links, but no DIR_NLINK feature in superblock */
+#define PR_4_DIR_NLINK_FEATURE 0x040006
+
/*
* Pass 5 errors
*/