Skip to contentSkip to conversation

e2fsck: add support for dirdata feature

PATCH New Artem Blagodarenko 1 participant 1 message Apr 17

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 e2fsck: add support for dirdata feature

From: Andreas Dilger <[email protected]>

Add support for the INCOMPAT_DIRDATA feature, which allows storing extra data in the directory entry beyond the name. This allows the Lustre File IDentifier to be accessed in an efficient manner, and would be useful for expanding a filesystem to allow more than 2^32 inodes in the future.

While adding the new file entry in directory block, link_proc() calculates minimum record length of the existing directory entry without considering the dirent data size and which leads to corruption. Changed the code to use EXT2_DIR_REC_LEN() which will return correct record length including dirent data size.

LU-19105 e2fsck: support duplicate dentry rename with dirdata

mutate_name() is used to generate a new name in case of duplicate dir entries. The rename is done in-place without modifying the record length. The record length is 4 bytes aligned. So mutate_name() uses the padding bytes to expand the name length.

If dirdata is present in the record, the rename operation may overwrite the dirdata saved after dir entry name.

If the name length needs to be expanded, this change moves the dirdata before renaming.

Add the regression test f_dirdata_dup_de to verify duplicate entries fix with dirdata.

Fixes c06619d91 ("e2fsck: add support for dirdata feature")
Change-Id I2fcd93a0460bab1371d0621279a80d1994b26d2a

Reviewed-on: https://review.whamcloud.com/c/tools/e2fsprogs/+/59821

Change-Id: I1b81948b5bf114822ab140cb989c3a7e81fdc6f5
Lustre-bug-id: https://jira.hpdd.intel.com/browse/LU-4677

---
 debugfs/debugfs.8.in              |   7 +-
 debugfs/htree.c                   |   2 +-
 debugfs/ls.c                      |  59 +++-
 debugfs/ncheck.c                  |   3 +
 e2fsck/message.c                  |  37 ++-
 e2fsck/pass1.c                    |   4 +-
 e2fsck/pass2.c                    | 146 +++++++--
 e2fsck/pass3.c                    |   7 +
 e2fsck/problem.c                  |   5 +
 e2fsck/problem.h                  |   3 +
 e2fsck/rehash.c                   | 235 +++++++++-----
 lib/ext2fs/dirblock.c             |  33 ++
 lib/ext2fs/ext2_fs.h              |  43 ++-
 lib/ext2fs/ext2fs.h               |  22 +-
 lib/ext2fs/inline_data.c          |  14 +-
 lib/ext2fs/lfsck.h                |  60 ++++
 lib/ext2fs/link.c                 |  11 +-
 lib/ext2fs/newdir.c               |   4 +-
 misc/mke2fs.c                     |   1 +
 misc/tune2fs.c                    |   7 +
 tests/f_dir_optimize/expect.1     | 511 ++++++++++++++++++++++++++++++
 tests/f_dir_optimize/expect.2     | 511 ++++++++++++++++++++++++++++++
 tests/f_dir_optimize/image.gz     | Bin 0 -> 102520 bytes
 tests/f_dir_optimize/name         |   1 +
 tests/f_dir_optimize/script       |  36 +++
 tests/f_dirdata_dup_de/expect.1   |  37 +++
 tests/f_dirdata_dup_de/expect.2   |   7 +
 tests/f_dirdata_dup_de/image.gz   | Bin 0 -> 79307 bytes
 tests/f_dirdata_dup_de/name       |   1 +
 tests/f_dirdata_optimize/expect.1 |  10 +
 tests/f_dirdata_optimize/expect.2 |   7 +
 tests/f_dirdata_optimize/image.gz | Bin 0 -> 32121 bytes
 tests/f_dirdata_optimize/name     |   1 +
 tests/f_dirdata_optimize/script   |   3 +
 34 files changed, 1699 insertions(+), 129 deletions(-)
 create mode 100644 lib/ext2fs/lfsck.h
 create mode 100644 tests/f_dir_optimize/expect.1
 create mode 100644 tests/f_dir_optimize/expect.2
 create mode 100644 tests/f_dir_optimize/image.gz
 create mode 100644 tests/f_dir_optimize/name
 create mode 100644 tests/f_dir_optimize/script
 create mode 100644 tests/f_dirdata_dup_de/expect.1
 create mode 100644 tests/f_dirdata_dup_de/expect.2
 create mode 100644 tests/f_dirdata_dup_de/image.gz
 create mode 100644 tests/f_dirdata_dup_de/name
 create mode 100644 tests/f_dirdata_optimize/expect.1
 create mode 100644 tests/f_dirdata_optimize/expect.2
 create mode 100644 tests/f_dirdata_optimize/image.gz
 create mode 100644 tests/f_dirdata_optimize/name
 create mode 100644 tests/f_dirdata_optimize/script
debugfs/debugfs.8.in +6 -1
index 08f41fdfa..5a5dd32b0 100644
@@ -575,7 +575,7 @@ Instead, it will stop only when the entire log is printed or after
 .I num_trans
 transactions.
 .TP
-.BI ls " [\-l] [\-c] [\-d] [\-p] [\-r] filespec"
+.BI ls " [\-l] [\-c] [\-d] [\-p] [\-r] [\-D] filespec"
 Print a listing of the files in the directory
 .IR filespec .
 The
@@ -595,6 +595,11 @@ non-printing characters at the end of filenames.
 The
 .I \-r
 flag will force the printing of the filename, even if it is encrypted.
+The
+.I \-D
+flag will print the extra data found inside each entry when the
+.I \-l
+flag is used.
 .TP
 .BI list_deleted_inodes " [limit]"
 List deleted inodes, optionally limited to those deleted within
debugfs/htree.c +1 -1
index 4ea8f30b3..65b0ff908 100644
@@ -298,7 +298,7 @@ void do_htree_dump(int argc, ss_argv_t argv, int sci_idx EXT2FS_ATTR((unused)),
 		goto errout;
 	}
 
-	rootnode = (struct ext2_dx_root_info *) (buf + 24);
+	rootnode = get_ext2_dx_root_info(current_fs, buf);
 
 	fprintf(pager, "Root node dump:\n");
 	fprintf(pager, "\t Reserved zero: %u\n", rootnode->reserved_zero);
debugfs/ls.c +57 -2

101 lines not on this page · raw message

debugfs/ncheck.c +3 -0
index 1410e7c6d..03d1e49cf 100644
@@ -51,6 +51,9 @@ static int ncheck_proc(struct ext2_dir_entry *dirent,
 	iw->position++;
 	if (iw->position <= 2)
 		return 0;
+	if (current_fs->super->s_feature_incompat &
+	    EXT4_FEATURE_INCOMPAT_DIRDATA)
+		filetype &= EXT2_FT_MASK;
 	for (i=0; i < iw->num_inodes; i++) {
 		if (iw->iarray[i] == dirent->inode) {
 			if (!iw->parent && !iw->get_pathname_failed) {
e2fsck/message.c +36 -1
index 9c42b13fb..da71fd2f5 100644
@@ -99,6 +99,7 @@
 
 #include "e2fsck.h"
 #include "problem.h"
+#include "ext2fs/lfsck.h"
 
 #ifdef __GNUC__
 #define _INLINE_ __inline__
@@ -346,6 +347,33 @@ static _INLINE_ void expand_inode_expression(FILE *f, ext2_filsys fs, char ch,
 	}
 }
 
+int get_dirent_fid(struct ext2_dir_entry *dirent,
+				    struct lu_fid *fid)
+{
+	unsigned char *data = (unsigned char *)dirent->name +
+			      (dirent->name_len & EXT2_NAME_LEN) + 1;
+	__u8 file_type = dirent->name_len >> 8;
+	__u8 dirdata_mask;
+
+	for (dirdata_mask = EXT2_FT_MASK + 1;
+	     dirdata_mask != 0; dirdata_mask <<= 1) {
+		int dlen;
+
+		if ((dirdata_mask & file_type) == 0)
+			continue;
+
+		dlen = data[0];
+		if (dirdata_mask == EXT2_DIRENT_LUFID) {
+			memcpy(fid, data + 1, sizeof(*fid));
+			fid_be_to_cpu(fid, fid);
+			return 0;
+		}
+		data += dlen;
+	}
+
+	return -1;
+}
+
 /*
  * This function expands '%dX' expressions
  */
@@ -361,9 +389,16 @@ static _INLINE_ void expand_dirent_expression(FILE *f, ext2_filsys fs, char ch,
 	dirent = ctx->dirent;
 
 	switch (ch) {
-	case 'i':
+	case 'i': {
+		struct lu_fid fid;
+
 		fprintf(f, "%u", dirent->inode);
+
+		if (!get_dirent_fid(dirent, &fid))
+			fprintf(f, " fid="DFID, PFID(&fid));
+
 		break;
+	}
 	case 'n':
 		len = ext2fs_dirent_name_len(dirent);
 		if ((ext2fs_get_rec_len(fs, dirent, &rec_len) == 0) &&
e2fsck/pass1.c +2 -2
index e7d5d0ae9..7e2b81c1d 100644
@@ -764,7 +764,7 @@ static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx,
 		 */
 		memcpy(&dotdot, inode->i_block, sizeof(dotdot));
 		memcpy(&de, ((char *)inode->i_block) + EXT4_INLINE_DATA_DOTDOT_SIZE,
-		       EXT2_DIR_REC_LEN(0));
+		       EXT2_DIR_NAME_LEN(0));
 		dotdot = ext2fs_le32_to_cpu(dotdot);
 		de.inode = ext2fs_le32_to_cpu(de.inode);
 		de.rec_len = ext2fs_le16_to_cpu(de.rec_len);
@@ -2795,7 +2795,7 @@ static int handle_htree(e2fsck_t ctx, struct problem_context *pctx,
 		return 1;
 
 	/* XXX should check that beginning matches a directory */
-	root = (struct ext2_dx_root_info *) (block_buf + 24);
+	root = get_ext2_dx_root_info(fs, block_buf);
 
 	if ((root->reserved_zero || root->info_length < 8) &&
 	    fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
e2fsck/pass2.c +121 -25

303 lines not on this page · raw message

e2fsck/pass3.c +7 -0
index 56798b1bc..343609832 100644
@@ -706,6 +706,7 @@ static int fix_dotdot_proc(struct ext2_dir_entry *dirent,
 	struct fix_dotdot_struct *fp = (struct fix_dotdot_struct *) priv_data;
 	errcode_t	retval;
 	struct problem_context pctx;
+	__u16 dirdata = 0;
 
 	if (ext2fs_dirent_name_len(dirent) != 2)
 		return 0;
@@ -725,11 +726,17 @@ static int fix_dotdot_proc(struct ext2_dir_entry *dirent,
 		fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
 	}
 	dirent->inode = fp->parent;
+
+	dirdata  = dirent->name_len & ((__u16)~EXT2_FT_MASK << 8);
+
 	if (ext2fs_has_feature_filetype(fp->ctx->fs->super))
 		ext2fs_dirent_set_file_type(dirent, EXT2_FT_DIR);
 	else
 		ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN);
 
+	if (ext2fs_has_feature_dirdata(fp->ctx->fs->super))
+		dirent->name_len |= dirdata;
+
 	fp->done++;
 	return DIRENT_ABORT | DIRENT_CHANGED;
 }
e2fsck/problem.c +5 -0
index e433281fa..afa3d517a 100644
@@ -1875,6 +1875,11 @@ static struct e2fsck_problem problem_table[] = {
 	  N_("@E references EA @i %Di.\n"),
 	  PROMPT_CLEAR, 0, 0, 0, 0 },
 
+	/* Directory entry dirdata length set incorrectly */
+	{ PR_2_CLEAR_DIRDATA,
+	  N_("@E dirdata length set incorrectly.\n"),
+	  PROMPT_CLEAR, PR_PREEN_OK },
+
 	/* Pass 3 errors */
 
 	/* Pass 3: Checking directory connectivity */
e2fsck/problem.h +3 -0
index ef15b8c84..1ef519908 100644
@@ -1070,6 +1070,9 @@ struct problem_context {
 /* EA inode referenced from directory */
 #define PR_2_EA_INODE_DIR_LINK 0x020055
 
+/* Entry dirdata length set incorrectly */
+#define PR_2_CLEAR_DIRDATA		0x020057
+
 /*
  * Pass 3 errors
  */
e2fsck/rehash.c +156 -79

368 lines not on this page · raw message

lib/ext2fs/dirblock.c +33 -0
index 54b277728..d1d5a9e7f 100644
@@ -50,6 +50,39 @@ errcode_t ext2fs_read_dir_block3(ext2_filsys fs, blk64_t block,
 	return ext2fs_read_dir_block4(fs, block, buf, flags, 0);
 }
 
+/*
+ * Compute the dirdata length. This includes only optional extensions.
+ * Each extension has a bit set in the high 4 bits of
+ * de->file_type, and the extension length is the first byte in each entry.
+ */
+int ext2_get_dirdata_field_size(struct ext2_dir_entry *de,
+				 __u8 dirdata_flags)
+{
+	char *lenp = de->name + (de->name_len & EXT2_NAME_LEN) + 1 /* NUL */;
+	__u8 extra_data_flags = (de->name_len & ~(EXT2_FT_MASK << 8)) >> 12;
+	int dlen = 0;
+
+	dirdata_flags >>= 4;
+	while ((extra_data_flags & dirdata_flags) != 0) {
+		if (extra_data_flags & 1) {
+			if (dirdata_flags & 1)
+				dlen += *lenp;
+
+			lenp += *lenp;
+		}
+		extra_data_flags >>= 1;
+		dirdata_flags >>= 1;
+	}
+
+	/* add NUL terminator byte to dirdata length */
+	return dlen + (dlen != 0);
+}
+
+int ext2_get_dirdata_size(struct ext2_dir_entry *de)
+{
+	return ext2_get_dirdata_field_size(de, ~EXT2_FT_MASK);
+}
+
 errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block,
 				 void *buf, int flags EXT2FS_ATTR((unused)))
 {
lib/ext2fs/ext2_fs.h +41 -2

77 lines not on this page · raw message

lib/ext2fs/ext2fs.h +21 -1
index bb2170b78..9bb6fe96f 100644
@@ -726,6 +726,7 @@ typedef struct ext2_icount *ext2_icount_t;
 					 EXT3_FEATURE_INCOMPAT_EXTENTS|\
 					 EXT4_FEATURE_INCOMPAT_FLEX_BG|\
 					 EXT4_FEATURE_INCOMPAT_EA_INODE|\
+					 EXT4_FEATURE_INCOMPAT_DIRDATA|\
 					 EXT4_LIB_INCOMPAT_MMP|\
 					 EXT4_FEATURE_INCOMPAT_64BIT|\
 					 EXT4_FEATURE_INCOMPAT_INLINE_DATA|\
@@ -2246,6 +2247,25 @@ _INLINE_ int ext2fs_htree_intnode_maxrecs(ext2_filsys fs, int blocks)
 						sizeof(struct ext2_dx_entry));
 }
 
+_INLINE_ struct ext2_dx_root_info *get_ext2_dx_root_info(ext2_filsys fs,
+							 char *buf)
+{
+	struct ext2_dir_entry *de = (struct ext2_dir_entry *)buf;
+
+	if (!(fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_DIRDATA))
+		return (struct ext2_dx_root_info *)(buf +
+						    EXT2_DIR_NAME_LEN(1) +
+						    EXT2_DIR_NAME_LEN(2));
+
+	/* get dotdot first */
+	de = (struct ext2_dir_entry *)((char *)de + de->rec_len);
+
+	/* dx root info is after dotdot entry */
+	de = (struct ext2_dir_entry *)((char *)de + EXT2_DIR_REC_LEN(de));
+
+	return (struct ext2_dx_root_info *)de;
+}
+
 /*
  * log base 2, rounded down
  */
@@ -2325,7 +2345,7 @@ _INLINE_ __u64 ext2fs_div64_ceil(__u64 a, __u64 b)
 
 _INLINE_ int ext2fs_dirent_name_len(const struct ext2_dir_entry *entry)
 {
-	return entry->name_len & 0xff;
+	return entry->name_len & EXT2_NAME_LEN;
 }
 
 _INLINE_ void ext2fs_dirent_set_name_len(struct ext2_dir_entry *entry, int len)
lib/ext2fs/inline_data.c +7 -7
index bd52e3770..c8d2fa0ce 100644
@@ -149,7 +149,7 @@ int ext2fs_inline_data_dir_iterate(ext2_filsys fs, ext2_ino_t ino,
 	/* we first check '.' and '..' dir */
 	dirent.inode = ino;
 	dirent.name_len = 1;
-	ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(2), &dirent);
+	ext2fs_set_rec_len(fs, EXT2_DIR_NAME_LEN(2), &dirent);
 	dirent.name[0] = '.';
 	dirent.name[1] = '\0';
 	ctx->buf = (char *)&dirent;
@@ -160,7 +160,7 @@ int ext2fs_inline_data_dir_iterate(ext2_filsys fs, ext2_ino_t ino,
 
 	dirent.inode = ext2fs_le32_to_cpu(inode.i_block[0]);
 	dirent.name_len = 2;
-	ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(3), &dirent);
+	ext2fs_set_rec_len(fs, EXT2_DIR_NAME_LEN(3), &dirent);
 	dirent.name[0] = '.';
 	dirent.name[1] = '.';
 	dirent.name[2] = '\0';
@@ -296,14 +296,14 @@ static errcode_t ext2fs_inline_data_convert_dir(ext2_filsys fs, ext2_ino_t ino,
 	ext2fs_dirent_set_name_len(dir, 1);
 	ext2fs_dirent_set_file_type(dir, filetype);
 	dir->name[0] = '.';
-	rec_len = (fs->blocksize - csum_size) - EXT2_DIR_REC_LEN(1);
-	dir->rec_len = EXT2_DIR_REC_LEN(1);
+	rec_len = (fs->blocksize - csum_size) - EXT2_DIR_NAME_LEN(1);
+	dir->rec_len = EXT2_DIR_NAME_LEN(1);
 
 	/*
 	 * Set up entry for '..'
 	 */
 	dir = (struct ext2_dir_entry *) (bbuf + dir->rec_len);
-	dir->rec_len = EXT2_DIR_REC_LEN(2);
+	dir->rec_len = EXT2_DIR_NAME_LEN(2);
 	dir->inode = ext2fs_le32_to_cpu(((__u32 *)ibuf)[0]);
 	ext2fs_dirent_set_name_len(dir, 2);
 	ext2fs_dirent_set_file_type(dir, filetype);
@@ -313,11 +313,11 @@ static errcode_t ext2fs_inline_data_convert_dir(ext2_filsys fs, ext2_ino_t ino,
 	/*
 	 * Adjust the last rec_len
 	 */
-	offset = EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2);
+	offset = EXT2_DIR_NAME_LEN(1) + EXT2_DIR_NAME_LEN(2);
 	dir = (struct ext2_dir_entry *) (bbuf + offset);
 	memcpy(bbuf + offset, ibuf + EXT4_INLINE_DATA_DOTDOT_SIZE,
 	       size - EXT4_INLINE_DATA_DOTDOT_SIZE);
-	size += EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2) -
+	size += EXT2_DIR_NAME_LEN(1) + EXT2_DIR_NAME_LEN(2) -
 		EXT4_INLINE_DATA_DOTDOT_SIZE;
 
 	do {
lib/ext2fs/lfsck.h new file +60 -0

60 lines not on this page · raw message

lib/ext2fs/link.c +5 -6
index 1697da39f..615a24fe4 100644
@@ -197,7 +197,7 @@ static int link_proc(ext2_ino_t dir EXT2FS_ATTR((unused)),
 	if (ls->done)
 		return DIRENT_ABORT;
 
-	rec_len = EXT2_DIR_REC_LEN(ls->namelen);
+	rec_len = EXT2_DIR_NAME_LEN(ls->namelen);
 
 	ls->err = ext2fs_get_rec_len(ls->fs, dirent, &curr_rec_len);
 	if (ls->err)
@@ -226,7 +226,7 @@ static int link_proc(ext2_ino_t dir EXT2FS_ATTR((unused)),
 	 * truncate it and return.
 	 */
 	if (dirent->inode) {
-		min_rec_len = EXT2_DIR_REC_LEN(ext2fs_dirent_name_len(dirent));
+		min_rec_len = EXT2_DIR_REC_LEN(dirent);
 		if (curr_rec_len < (min_rec_len + rec_len))
 			return ret;
 		rec_len = curr_rec_len - min_rec_len;
@@ -254,8 +254,7 @@ static int link_proc(ext2_ino_t dir EXT2FS_ATTR((unused)),
 	ext2fs_dirent_set_name_len(dirent, ls->namelen);
 	strncpy(dirent->name, ls->name, ls->namelen);
 	if (ext2fs_has_feature_filetype(ls->sb))
-		ext2fs_dirent_set_file_type(dirent,
-					    ls->flags & EXT2FS_LINK_FT_MASK);
+		ext2fs_dirent_set_file_type(dirent, ls->flags & EXT2_FT_MASK);
 
 	ls->done++;
 	return DIRENT_ABORT|DIRENT_CHANGED;
@@ -331,8 +330,8 @@ static errcode_t dx_move_dirents(ext2_filsys fs, struct dx_hash_map *map,
 		csum_size = sizeof(struct ext2_dir_entry_tail);
 
 	for (i = 0; i < count; i++) {
-		de = (struct ext2_dir_entry *) ((char *)from + map[i].off);
-		rec_len = EXT2_DIR_REC_LEN(ext2fs_dirent_name_len(de));
+		de = from + map[i].off;
+		rec_len = EXT2_DIR_REC_LEN(de);
 		memcpy(to, de, rec_len);
 		retval = ext2fs_set_rec_len(fs, rec_len, to);
 		if (retval)
lib/ext2fs/newdir.c +2 -2
index 7f4728500..f168d6686 100644
@@ -64,8 +64,8 @@ errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
 		ext2fs_dirent_set_name_len(dir, 1);
 		ext2fs_dirent_set_file_type(dir, filetype);
 		dir->name[0] = '.';
-		rec_len = (fs->blocksize - csum_size) - EXT2_DIR_REC_LEN(1);
-		dir->rec_len = EXT2_DIR_REC_LEN(1);
+		rec_len = (fs->blocksize - csum_size) - EXT2_DIR_NAME_LEN(1);
+		dir->rec_len = EXT2_DIR_NAME_LEN(1);
 
 		/*
 		 * Set up entry for '..'
misc/mke2fs.c +1 -0
index 7f81a5137..f01b31599 100644
@@ -1232,6 +1232,7 @@ static __u32 ok_features[3] = {
 		EXT4_FEATURE_INCOMPAT_FLEX_BG|
 		EXT4_FEATURE_INCOMPAT_EA_INODE|
 		EXT4_FEATURE_INCOMPAT_MMP |
+		EXT4_FEATURE_INCOMPAT_DIRDATA|
 		EXT4_FEATURE_INCOMPAT_64BIT|
 		EXT4_FEATURE_INCOMPAT_INLINE_DATA|
 		EXT4_FEATURE_INCOMPAT_ENCRYPT |
misc/tune2fs.c +7 -0
index 3db57632c..3b7a0272f 100644
@@ -192,6 +192,7 @@ static __u32 ok_features[3] = {
 		EXT4_FEATURE_INCOMPAT_FLEX_BG |
 		EXT4_FEATURE_INCOMPAT_EA_INODE|
 		EXT4_FEATURE_INCOMPAT_MMP |
+		EXT4_FEATURE_INCOMPAT_DIRDATA |
 		EXT4_FEATURE_INCOMPAT_64BIT |
 		EXT4_FEATURE_INCOMPAT_ENCRYPT |
 		EXT4_FEATURE_INCOMPAT_CSUM_SEED |
@@ -222,6 +223,7 @@ static __u32 clear_ok_features[3] = {
 	EXT2_FEATURE_INCOMPAT_FILETYPE |
 		EXT4_FEATURE_INCOMPAT_FLEX_BG |
 		EXT4_FEATURE_INCOMPAT_MMP |
+		EXT4_FEATURE_INCOMPAT_DIRDATA |
 		EXT4_FEATURE_INCOMPAT_64BIT |
 		EXT4_FEATURE_INCOMPAT_CSUM_SEED |
 		EXT4_FEATURE_INCOMPAT_CASEFOLD,
@@ -1604,6 +1606,11 @@ mmp_error:
 	}
 
 	if (FEATURE_ON(E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_CASEFOLD)) {
+		if (ext2fs_has_feature_dirdata(sb)) {
+			fputs(_("Can not enable casefold feature on "
+				"filesystem has dirdata.\n"), stderr);
+			return 1;
+		}
 		if (mount_flags & EXT2_MF_MOUNTED) {
 			fputs(_("The casefold feature may only be enabled when "
 				"the filesystem is unmounted.\n"), stderr);
tests/f_dir_optimize/expect.1 new file +511 -0

511 lines not on this page · raw message

tests/f_dir_optimize/expect.2 new file +511 -0

511 lines not on this page · raw message

tests/f_dir_optimize/image.gz new file binary +0 -0
new file mode 100644
index 0000000000000000000000000000000000000000..d457d3b67019f0047fd626bc90ee55f2724a73c6
GIT binary patch
tests/f_dir_optimize/name new file +1 -0
new file mode 100644
index 000000000..8a059bff2
@@ -0,0 +1 @@
+optimize directories
tests/f_dir_optimize/script new file +36 -0
new file mode 100644
index 000000000..f535e7b7f
@@ -0,0 +1,36 @@
+FSCK_OPT="-fvyD"
+
+IMAGE=$test_dir/image.gz
+gunzip < $IMAGE > $TMPFILE
+
+$DEBUGFS -R 'ls -lD /ROOT/testdir' $TMPFILE 2>&1 | tail -n +2 |	\
+	sort > $test_name.1.log
+
+cmp -s $test_dir/expect.1 $test_name.1.log
+status1=$?
+
+$FSCK $FSCK_OPT -N test_filesys $TMPFILE > /dev/null 2>&1
+
+$DEBUGFS -R 'ls -lD /ROOT/testdir' $TMPFILE 2>&1 | tail -n +2 |	\
+	sort > $test_name.2.log
+cmp -s $test_dir/expect.2 $test_name.2.log
+status2=$?
+
+if [ "$status1" -eq 0 -a "$status2" -eq 0 ]; then
+	echo "$test_name: $test_description: ok"
+	touch $test_name.ok
+else
+	echo "$test_name: $test_description: failed"
+	[ $status1 -ne 0 ] &&
+		diff $DIFF_OPTS $test_dir/expect.1 $test_name.1.log	\
+			>> $test_name.failed
+	[ $status2 -ne 0 ] &&
+		diff $DIFF_OPTS $test_dir/expect.2 $test_name.2.log	\
+			>> $test_name.failed
+fi
+
+if [ "$SKIP_CLEANUP" != "true" ] ; then
+	unset IMAGE FSCK_OPT
+	unset SKIP_CLEANUP
+	unset DESCRIPTION SKIP_UNLINK
+fi
tests/f_dirdata_dup_de/expect.1 new file +37 -0
new file mode 100644
index 000000000..c064e82cc
@@ -0,0 +1,37 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Duplicate entry 'f' found.
+	Marking /ROOT/dir1 (439) to be rebuilt.
+
+Entry 'foobar1' in /ROOT/dir1 (439) dirdata length set incorrectly.
+Clear? yes
+
+Entry 'foobar1' in /ROOT/dir1 (439) dirdata length set incorrectly.
+Clear? yes
+
+Pass 3: Checking directory connectivity
+Pass 3A: Optimizing directories
+Entry 'f125' in /ROOT/dir1 (439) has a non-unique filename.
+Rename to f125~0? yes
+
+Entry 'foobar1' in /ROOT/dir1 (439) has a non-unique filename.
+Rename to foobar~0? yes
+
+Entry 'f' in /ROOT/dir1 (439) has a non-unique filename.
+Rename to f~? yes
+
+Entry 'f1442' in /ROOT/dir1 (439) has a non-unique filename.
+Rename to f144~0? yes
+
+Entry 'f125' in /ROOT/dir1 (439) has a non-unique filename.
+Rename to f125~1? yes
+
+Entry 'f1442' in /ROOT/dir1 (439) has a non-unique filename.
+Rename to f144~1? yes
+
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 543/5000 files (0.9% non-contiguous), 706/5000 blocks
+Exit status is 1
tests/f_dirdata_dup_de/expect.2 new file +7 -0
new file mode 100644
index 000000000..4ed7f5245
@@ -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: 543/5000 files (0.7% non-contiguous), 706/5000 blocks
+Exit status is 0
tests/f_dirdata_dup_de/image.gz new file binary +0 -0
new file mode 100644
index 0000000000000000000000000000000000000000..d3e240652bd1c64c8bf5b0da5dbe7c593e41b4bb
GIT binary patch
tests/f_dirdata_dup_de/name new file +1 -0
new file mode 100644
index 000000000..5d4d2c3f3
@@ -0,0 +1 @@
+ duplicate directory entries with dirdata
tests/f_dirdata_optimize/expect.1 new file +10 -0
new file mode 100644
index 000000000..52368d33d
@@ -0,0 +1,10 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 3A: Optimizing directories
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 102/4096 files (2.9% non-contiguous), 686/2048 blocks
+Exit status is 0
tests/f_dirdata_optimize/expect.2 new file +7 -0
new file mode 100644
index 000000000..3cf9314e2
@@ -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: 102/4096 files (2.9% non-contiguous), 686/2048 blocks
+Exit status is 0
tests/f_dirdata_optimize/image.gz new file binary +0 -0
new file mode 100644
index 0000000000000000000000000000000000000000..fcb7f4f866cea3160b77da4998ec69c0817afebd
GIT binary patch
tests/f_dirdata_optimize/name new file +1 -0
new file mode 100644
index 000000000..1649a3702
@@ -0,0 +1 @@
+optimize directories with dirdata
tests/f_dirdata_optimize/script new file +3 -0
new file mode 100644
index 000000000..52cf88ed2
@@ -0,0 +1,3 @@
+FSCK_OPT="-Dyf"
+SECOND_FSCK_OPT="-yf"
+. $cmd_dir/run_e2fsck
Signature · 1 line
2.43.5