lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Fri, 4 May 2018 11:35:18 +0300
From:   Artem Blagodarenko <artem.blagodarenko@...il.com>
To:     linux-ext4@...r.kernel.org
Cc:     adilger.kernel@...ger.ca,
        Andreas Dilger <andreas.dilger@...el.com>,
        Bobi Jam <bobijam.xu@...el.com>,
        Manisha Salve <msalve@....com>,
        Pravin Shelar <pravin@...sterfs.com>
Subject: Re: [PATCH v4 1/7] e2fsck: add support for dirdata feature

Hello,

Just noticed I introduced error while was fixing warnings from checkpatch.pl

This fix is need for f_dir_optimize to be passed.

diff --git a/debugfs/ls.c b/debugfs/ls.c
index 082c14b9..5668d018 100644
--- a/debugfs/ls.c
+++ b/debugfs/ls.c
@@ -27,8 +27,8 @@ extern char *optarg;
 
 #ifndef DFID
 #define DFID "[%#llx:0x%x:0x%x]"
-#define PFID(fid) ((unsigned long long)fid_seq(fid),\
-               fid_oid(fid), fid_ver(fid))
+#define PFID(fid) (unsigned long long)fid_seq(fid),\
+               fid_oid(fid), fid_ver(fid)
 struct lu_fid {
        __u64   f_seq;
        __u32   f_oid;


Best regards,

> On 4 May 2018, at 10:09, c17828 <artem.blagodarenko@...il.com> wrote:
> 
> From: Andreas Dilger <andreas.dilger@...el.com>
> 
> 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.
> 
> Include this patches:
> 
> e2fsck: e2fsck -D does not change dirdata content
> 
> Fix dir optimization to preserve dirdata content for dot
> and dotdot entries.
> 
> Lustre-bug: https://jira.hpdd.intel.com/browse/LU-1774
> Signed-off-by: Bobi Jam <bobijam.xu@...el.com>
> Change-Id: Iae190794da75a2080a8e5cc5b95a49e0c894f72f
> 
> e2fsprogs: Consider DIRENT_LUFID flag in link_proc().
> 
> 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.
> 
> Lustre-bug: https://jira.hpdd.intel.com/browse/LU-2462
> Signed-off-by: Manisha Salve <msalve@....com>
> Change-Id: Ic593c558c47a78183143ec8e99d8385ac94d06f7
> 
> libext2fs, e2fsck: don't use ext2_dir_entry_2
> 
> Due to endian issues, do not use ext2_dir_entry_2 because it will
> have the wrong byte order on directory entries that are swabbed.
> Instead, use the standard practice of mask-and-shift to access the
> file_type and dirdata flags.
> 
> Lustre-bug: https://jira.hpdd.intel.com/browse/LU-4677
> Signed-off-by: Pravin Shelar <pravin@...sterfs.com>
> Signed-off-by: Andreas Dilger <andreas.dilger@...el.com>
> Signed-off-by: Artem Blagodarenko <artem.blagodarenko@...il.com>
> ---
> debugfs/htree.c          |   2 +-
> debugfs/ls.c             |  67 ++++++++++++++++++++++-
> e2fsck/pass1.c           |   4 +-
> e2fsck/pass2.c           | 139 ++++++++++++++++++++++++++++++++++++++---------
> e2fsck/pass3.c           |   7 +++
> e2fsck/problem.c         |   5 ++
> e2fsck/problem.h         |   3 +
> e2fsck/rehash.c          |  82 ++++++++++++++++------------
> lib/ext2fs/dirblock.c    |  33 +++++++++++
> lib/ext2fs/ext2_fs.h     |  18 +++++-
> lib/ext2fs/ext2fs.h      |  22 +++++++-
> lib/ext2fs/inline_data.c |  14 ++---
> lib/ext2fs/link.c        |  10 ++--
> lib/ext2fs/newdir.c      |   4 +-
> misc/mke2fs.c            |   8 +++
> misc/tune2fs.c           |   2 +
> 16 files changed, 338 insertions(+), 82 deletions(-)
> 
> diff --git a/debugfs/htree.c b/debugfs/htree.c
> index cf7d78aa..b7f1add0 100644
> --- a/debugfs/htree.c
> +++ b/debugfs/htree.c
> @@ -278,7 +278,7 @@ void do_htree_dump(int argc, char *argv[])
> 		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);
> diff --git a/debugfs/ls.c b/debugfs/ls.c
> index 61b63196..082c14b9 100644
> --- a/debugfs/ls.c
> +++ b/debugfs/ls.c
> @@ -25,6 +25,30 @@ extern char *optarg;
> 
> #include "debugfs.h"
> 
> +#ifndef DFID
> +#define DFID "[%#llx:0x%x:0x%x]"
> +#define PFID(fid) ((unsigned long long)fid_seq(fid),\
> +		fid_oid(fid), fid_ver(fid))
> +struct lu_fid {
> +	__u64   f_seq;
> +	__u32   f_oid;
> +	__u32   f_ver;
> +};
> +#endif /* !DFID */
> +
> +#ifndef HAVE_LUSTRE_LUSTRE_IDL_H
> +#define fid_seq(fid) ((fid)->f_seq)
> +#define fid_oid(fid) ((fid)->f_oid)
> +#define fid_ver(fid) ((fid)->f_ver)
> +
> +static inline void fid_be_to_cpu(struct lu_fid *dst, struct lu_fid *src)
> +{
> +	dst->f_seq = ext2fs_be64_to_cpu(src->f_seq);
> +	dst->f_oid = ext2fs_be32_to_cpu(src->f_oid);
> +	dst->f_ver = ext2fs_be32_to_cpu(src->f_ver);
> +}
> +#endif
> +
> /*
>  * list directory
>  */
> @@ -32,6 +56,7 @@ extern char *optarg;
> #define LONG_OPT	0x0001
> #define PARSE_OPT	0x0002
> #define RAW_OPT		0x0004
> +#define DIRDATA_OPT	0x0008
> #define ENCRYPT_OPT	0x8000
> 
> struct list_dir_struct {
> @@ -44,6 +69,41 @@ struct list_dir_struct {
> static const char *monstr[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
> 				"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
> 
> +static void list_dirdata(struct list_dir_struct *ls,
> +			 struct ext2_dir_entry *dirent)
> +{
> +	unsigned char	*data;
> +	int		dlen;
> +	__u8		dirdata_mask;
> +	__u8		file_type = dirent->name_len >> 8;
> +
> +	data = (unsigned char *)dirent->name +
> +		(dirent->name_len & EXT2_NAME_LEN) + 1;
> +
> +	for (dirdata_mask = EXT2_FT_MASK + 1;
> +	     dirdata_mask != 0; dirdata_mask <<= 1) {
> +		if ((dirdata_mask & file_type) == 0)
> +			continue;
> +
> +		dlen = data[0];
> +
> +		if (dirdata_mask == EXT2_DIRENT_LUFID) {
> +			struct lu_fid *fid = (struct lu_fid *)(data + 1);
> +
> +			fid_be_to_cpu(fid, fid);
> +			fprintf(ls->f, "fid:"DFID, PFID(fid));
> +		} else {
> +			int i;
> +
> +			for (i = 1; i < dlen; i++)
> +				fprintf(ls->f, "%02x", data[i]);
> +		}
> +
> +		fprintf(ls->f, " ");
> +		data += dlen;
> +	}
> +}
> +
> static int print_filename(FILE *f, struct ext2_dir_entry *dirent, int options)
> {
> 	unsigned char	ch;
> @@ -157,6 +217,8 @@ static int list_dir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)),
> 		else
> 			fprintf(ls->f, "%5llu", EXT2_I_SIZE(&inode));
> 		fprintf(ls->f, " %s ", datestr);
> +		if ((ls->options & DIRDATA_OPT) != 0)
> +			list_dirdata(ls, dirent);
> 		print_filename(ls->f, dirent, options);
> 		fputc('\n', ls->f);
> 	} else {
> @@ -204,7 +266,7 @@ void do_list_dir(int argc, char *argv[])
> 		return;
> 
> 	reset_getopt();
> -	while ((c = getopt (argc, argv, "cdlpr")) != EOF) {
> +	while ((c = getopt(argc, argv, "cdDlpr")) != EOF) {
> 		switch (c) {
> 		case 'c':
> 			flags |= DIRENT_FLAG_INCLUDE_CSUM;
> @@ -212,6 +274,9 @@ void do_list_dir(int argc, char *argv[])
> 		case 'l':
> 			ls.options |= LONG_OPT;
> 			break;
> +		case 'D':
> +			ls.options |= DIRDATA_OPT;
> +			break;
> 		case 'd':
> 			flags |= DIRENT_FLAG_INCLUDE_REMOVED;
> 			break;
> diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
> index 5015d938..d39086d2 100644
> --- a/e2fsck/pass1.c
> +++ b/e2fsck/pass1.c
> @@ -719,7 +719,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);
> @@ -2646,7 +2646,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))
> diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
> index 1b0504c8..c419a016 100644
> --- a/e2fsck/pass2.c
> +++ b/e2fsck/pass2.c
> @@ -366,13 +366,88 @@ static EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b)
> 	return (int) (db_a->blockcnt - db_b->blockcnt);
> }
> 
> +void ext2_fix_dirent_dirdata(struct ext2_dir_entry *de)
> +{
> +	__u16 file_type = de->name_len & (EXT2_FT_MASK << 8);
> +	__u8 de_flags = (de->name_len >> 8) & ~EXT2_FT_MASK;
> +	__u8 name_len = de->name_len & EXT2_NAME_LEN;
> +	__u8 new_flag = 0;
> +	int i;
> +
> +	for (i = 0; i < 4; i++) {
> +		__u8 flags = new_flag | (1 << i) << 4;
> +
> +		/* new_flag is accumulating flags that are set in de_flags
> +		 * and still fit inside rec_len. ext2_get_dirent_dirdata_size()
> +		 * returns the size of all the dirdata entries in flags, and
> +		 * chops off any that are beyond rec_len.
> +		 */
> +		if ((de_flags & flags) == flags) {
> +			int dirdatalen = ext2_get_dirdata_field_size(de,
> +								      flags);
> +			int rlen = EXT2_DIR_NAME_LEN(name_len + dirdatalen);
> +
> +			if (rlen > de->rec_len)
> +				break;
> +
> +			new_flag |= flags;
> +		}
> +	}
> +
> +	de->name_len = name_len | file_type | (new_flag << 8);
> +}
> +
> +/*
> + * check for dirent data in ext3 dirent.
> + * return 0 if dirent data is ok.
> + * return 1 if dirent data does not exist.
> + * return 2 if dirent was modified due to error.
> + */
> +int e2fsck_check_dirent_data(e2fsck_t ctx, struct ext2_dir_entry *de,
> +			     unsigned int offset, struct problem_context *pctx)
> +{
> +	if (!(ctx->fs->super->s_feature_incompat &
> +			EXT4_FEATURE_INCOMPAT_DIRDATA)) {
> +		if ((de->name_len >> 8) & ~EXT2_FT_MASK) {
> +			/* clear dirent extra data flags. */
> +			if (fix_problem(ctx, PR_2_CLEAR_DIRDATA, pctx)) {
> +				de->name_len &= (EXT2_FT_MASK << 8) |
> +						EXT2_NAME_LEN;
> +				return 2;
> +			}
> +		}
> +		return 1;
> +	}
> +	if ((de->name_len >> 8) & ~EXT2_FT_MASK) {
> +		if (de->rec_len >= EXT2_DIR_REC_LEN(de) ||
> +		    de->rec_len + offset == EXT2_BLOCK_SIZE(ctx->fs->super)) {
> +			if (ext2_get_dirdata_field_size(de,
> +							 EXT2_DIRENT_LUFID) %
> +			    EXT2_DIRENT_LUFID_SIZE == 1 /*size*/ + 1 /*NULL*/)
> +				return 0;
> +		}
> +		/* just clear dirent data flags for now, we should fix FID data
> +		 * in lustre specific pass.
> +		 */
> +		if (fix_problem(ctx, PR_2_CLEAR_DIRDATA, pctx)) {
> +			ext2_fix_dirent_dirdata(de);
> +			if (ext2_get_dirdata_field_size(de,
> +							 EXT2_DIRENT_LUFID) !=
> +			    EXT2_DIRENT_LUFID_SIZE)
> +				de->name_len &= ~(EXT2_DIRENT_LUFID << 8);
> +
> +			return 2;
> +		}
> +	}
> +	return 1;
> +}
> 
> /*
>  * Make sure the first entry in the directory is '.', and that the
>  * directory entry is sane.
>  */
> static int check_dot(e2fsck_t ctx,
> -		     struct ext2_dir_entry *dirent,
> +		     struct ext2_dir_entry *dirent, unsigned int offset,
> 		     ext2_ino_t ino, struct problem_context *pctx)
> {
> 	struct ext2_dir_entry *nextdir;
> @@ -380,6 +455,7 @@ static int check_dot(e2fsck_t ctx,
> 	int		status = 0;
> 	int		created = 0;
> 	problem_t	problem = 0;
> +	int		dir_data_error;
> 
> 	if (!dirent->inode)
> 		problem = PR_2_MISSING_DOT;
> @@ -389,10 +465,12 @@ static int check_dot(e2fsck_t ctx,
> 	else if (dirent->name[1] != '\0')
> 		problem = PR_2_DOT_NULL_TERM;
> 
> +	dir_data_error = e2fsck_check_dirent_data(ctx, dirent, offset, pctx);
> +
> 	(void) ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
> 	if (problem) {
> 		if (fix_problem(ctx, problem, pctx)) {
> -			if (rec_len < 12)
> +			if (rec_len < 12 && dir_data_error)
> 				rec_len = dirent->rec_len = 12;
> 			dirent->inode = ino;
> 			ext2fs_dirent_set_name_len(dirent, 1);
> @@ -411,7 +489,7 @@ static int check_dot(e2fsck_t ctx,
> 	}
> 	if (rec_len > 12) {
> 		new_len = rec_len - 12;
> -		if (new_len > 12) {
> +		if (new_len > 12 && dir_data_error) {
> 			if (created ||
> 			    fix_problem(ctx, PR_2_SPLIT_DOT, pctx)) {
> 				nextdir = (struct ext2_dir_entry *)
> @@ -436,11 +514,12 @@ static int check_dot(e2fsck_t ctx,
>  * here; this gets done in pass 3.
>  */
> static int check_dotdot(e2fsck_t ctx,
> -			struct ext2_dir_entry *dirent,
> +			struct ext2_dir_entry *dirent, unsigned int offset,
> 			ext2_ino_t ino, struct problem_context *pctx)
> {
> 	problem_t	problem = 0;
> 	unsigned int	rec_len;
> +	int		dir_data_error;
> 
> 	if (!dirent->inode)
> 		problem = PR_2_MISSING_DOT_DOT;
> @@ -451,10 +530,12 @@ static int check_dotdot(e2fsck_t ctx,
> 	else if (dirent->name[2] != '\0')
> 		problem = PR_2_DOT_DOT_NULL_TERM;
> 
> +	dir_data_error = e2fsck_check_dirent_data(ctx, dirent, offset, pctx);
> +
> 	(void) ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
> 	if (problem) {
> 		if (fix_problem(ctx, problem, pctx)) {
> -			if (rec_len < 12)
> +			if (rec_len < 12 && dir_data_error)
> 				dirent->rec_len = 12;
> 			/*
> 			 * Note: we don't have the parent inode just
> @@ -528,6 +609,12 @@ static _INLINE_ int check_filetype(e2fsck_t ctx,
> 	int	filetype = ext2fs_dirent_file_type(dirent);
> 	int	should_be = EXT2_FT_UNKNOWN;
> 	struct ext2_inode	inode;
> +	__u8    dirdata = 0;
> +
> +	if (ext2fs_has_feature_dirdata(ctx->fs->super)) {
> +		dirdata = filetype & ~EXT2_FT_MASK;
> +		filetype = filetype & EXT2_FT_MASK;
> +	}
> 
> 	if (!ext2fs_has_feature_filetype(ctx->fs->super)) {
> 		if (filetype == 0 ||
> @@ -558,8 +645,7 @@ static _INLINE_ int check_filetype(e2fsck_t ctx,
> 	if (fix_problem(ctx, filetype ? PR_2_BAD_FILETYPE : PR_2_SET_FILETYPE,
> 			pctx) == 0)
> 		return 0;
> -
> -	ext2fs_dirent_set_file_type(dirent, should_be);
> +	ext2fs_dirent_set_file_type(dirent, should_be | dirdata);
> 	return 1;
> }
> 
> @@ -581,7 +667,7 @@ static void parse_int_node(ext2_filsys fs,
> 	int		csum_size = 0;
> 
> 	if (db->blockcnt == 0) {
> -		root = (struct ext2_dx_root_info *) (block_buf + 24);
> +		root = get_ext2_dx_root_info(fs, block_buf);
> 
> #ifdef DX_DEBUG
> 		printf("Root node dump:\n");
> @@ -591,8 +677,8 @@ static void parse_int_node(ext2_filsys fs,
> 		printf("\t Indirect levels: %d\n", root->indirect_levels);
> 		printf("\t Flags: %d\n", root->unused_flags);
> #endif
> -
> -		ent = (struct ext2_dx_entry *) (block_buf + 24 + root->info_length);
> +		ent = (struct ext2_dx_entry *)((char *)root +
> +					       root->info_length);
> 
> 		if (failed_csum &&
> 		    (e2fsck_dir_will_be_rehashed(cd->ctx, cd->pctx.ino) ||
> @@ -600,7 +686,7 @@ static void parse_int_node(ext2_filsys fs,
> 				&cd->pctx)))
> 			goto clear_and_exit;
> 	} else {
> -		ent = (struct ext2_dx_entry *) (block_buf+8);
> +		ent = (struct ext2_dx_entry *)(block_buf + 8);
> 
> 		if (failed_csum &&
> 		    (e2fsck_dir_will_be_rehashed(cd->ctx, cd->pctx.ino) ||
> @@ -608,8 +694,7 @@ static void parse_int_node(ext2_filsys fs,
> 				&cd->pctx)))
> 			goto clear_and_exit;
> 	}
> -
> -	limit = (struct ext2_dx_countlimit *) ent;
> +	limit = (struct ext2_dx_countlimit *)ent;
> 
> #ifdef DX_DEBUG
> 	printf("Number of entries (count): %d\n",
> @@ -780,7 +865,6 @@ static void salvage_directory(ext2_filsys fs,
> 	}
> }
> 
> -#define NEXT_DIRENT(d)	((void *)((char *)(d) + (d)->rec_len))
> static errcode_t insert_dirent_tail(ext2_filsys fs, void *dirbuf)
> {
> 	struct ext2_dir_entry *d;
> @@ -790,11 +874,11 @@ static errcode_t insert_dirent_tail(ext2_filsys fs, void *dirbuf)
> 	d = dirbuf;
> 	top = EXT2_DIRENT_TAIL(dirbuf, fs->blocksize);
> 
> -	while (d->rec_len && !(d->rec_len & 0x3) && NEXT_DIRENT(d) <= top)
> -		d = NEXT_DIRENT(d);
> +	while (d->rec_len && !(d->rec_len & 0x3) && EXT2_NEXT_DIRENT(d) <= top)
> +		d = EXT2_NEXT_DIRENT(d);
> 
> 	if (d != top) {
> -		unsigned int min_size = EXT2_DIR_REC_LEN(
> +		unsigned int min_size = EXT2_DIR_NAME_LEN(
> 				ext2fs_dirent_name_len(dirbuf));
> 		if (min_size > (char *)top - (char *)d)
> 			return EXT2_ET_DIR_NO_SPACE_FOR_CSUM;
> @@ -809,7 +893,6 @@ static errcode_t insert_dirent_tail(ext2_filsys fs, void *dirbuf)
> 
> 	return 0;
> }
> -#undef NEXT_DIRENT
> 
> static errcode_t fix_inline_dir_size(e2fsck_t ctx, ext2_ino_t ino,
> 				     size_t *inline_data_size,
> @@ -828,7 +911,7 @@ static errcode_t fix_inline_dir_size(e2fsck_t ctx, ext2_ino_t ino,
> 	 */
> 	if (old_size > EXT4_MIN_INLINE_DATA_SIZE &&
> 	    old_size < EXT4_MIN_INLINE_DATA_SIZE +
> -		       EXT2_DIR_REC_LEN(1)) {
> +		       EXT2_DIR_NAME_LEN(1)) {
> 		old_size = EXT4_MIN_INLINE_DATA_SIZE;
> 		new_size = old_size;
> 	} else
> @@ -1035,7 +1118,7 @@ inline_read_fail:
> 	if (((inline_data_size & 3) ||
> 	     (inline_data_size > EXT4_MIN_INLINE_DATA_SIZE &&
> 	      inline_data_size < EXT4_MIN_INLINE_DATA_SIZE +
> -				 EXT2_DIR_REC_LEN(1))) &&
> +				 EXT2_DIR_NAME_LEN(1))) &&
> 	    fix_problem(ctx, PR_2_BAD_INLINE_DIR_SIZE, &pctx)) {
> 		errcode_t err = fix_inline_dir_size(ctx, ino,
> 						    &inline_data_size, &pctx,
> @@ -1085,7 +1168,7 @@ inline_read_fail:
> 		(void) ext2fs_get_rec_len(fs, dirent, &rec_len);
> 		limit = (struct ext2_dx_countlimit *) (buf+8);
> 		if (db->blockcnt == 0) {
> -			root = (struct ext2_dx_root_info *) (buf + 24);
> +			root = get_ext2_dx_root_info(fs, buf);
> 			dx_db->type = DX_DIRBLOCK_ROOT;
> 			dx_db->flags |= DX_FLAG_FIRST | DX_FLAG_LAST;
> 			if ((root->reserved_zero ||
> @@ -1165,7 +1248,7 @@ skip_checksum:
> 			 * force salvaging this dir.
> 			 */
> 			if (max_block_size - offset < EXT2_DIR_ENTRY_HEADER_LEN)
> -				rec_len = EXT2_DIR_REC_LEN(1);
> +				rec_len = EXT2_DIR_NAME_LEN(1);
> 			else
> 				(void) ext2fs_get_rec_len(fs, dirent, &rec_len);
> 			cd->pctx.dirent = dirent;
> @@ -1227,7 +1310,7 @@ skip_checksum:
> 				memset(&dot, 0, sizeof(dot));
> 				dirent = &dot;
> 				dirent->inode = ino;
> -				dirent->rec_len = EXT2_DIR_REC_LEN(1);
> +				dirent->rec_len = EXT2_DIR_NAME_LEN(1);
> 				dirent->name_len = 1 | filetype;
> 				dirent->name[0] = '.';
> 			} else if (dot_state == 1) {
> @@ -1235,7 +1318,7 @@ skip_checksum:
> 				dirent = &dotdot;
> 				dirent->inode =
> 					((struct ext2_dir_entry *)buf)->inode;
> -				dirent->rec_len = EXT2_DIR_REC_LEN(2);
> +				dirent->rec_len = EXT2_DIR_NAME_LEN(2);
> 				dirent->name_len = 2 | filetype;
> 				dirent->name[0] = '.';
> 				dirent->name[1] = '.';
> @@ -1247,10 +1330,10 @@ skip_checksum:
> 		}
> 
> 		if (dot_state == 0) {
> -			if (check_dot(ctx, dirent, ino, &cd->pctx))
> +			if (check_dot(ctx, dirent, offset, ino, &cd->pctx))
> 				dir_modified++;
> 		} else if (dot_state == 1) {
> -			ret = check_dotdot(ctx, dirent, ino, &cd->pctx);
> +			ret = check_dotdot(ctx, dirent, offset, ino, &cd->pctx);
> 			if (ret < 0)
> 				goto abort_free_dict;
> 			if (ret)
> @@ -1266,6 +1349,10 @@ skip_checksum:
> 		if (!dirent->inode)
> 			goto next;
> 
> +		ret = e2fsck_check_dirent_data(ctx, dirent, offset, &cd->pctx);
> +		if (ret == 2)
> +			dir_modified++;
> +
> 		/*
> 		 * Make sure the inode listed is a legal one.
> 		 */
> diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c
> index 6a975b36..4a777213 100644
> --- a/e2fsck/pass3.c
> +++ b/e2fsck/pass3.c
> @@ -698,6 +698,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;
> @@ -717,11 +718,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 & (~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;
> }
> diff --git a/e2fsck/problem.c b/e2fsck/problem.c
> index edc9d51f..2a86d528 100644
> --- a/e2fsck/problem.c
> +++ b/e2fsck/problem.c
> @@ -1671,6 +1671,11 @@ static struct e2fsck_problem problem_table[] = {
> 	  N_("Encrypted @E is too short.\n"),
> 	  PROMPT_CLEAR, 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 */
> diff --git a/e2fsck/problem.h b/e2fsck/problem.h
> index 482d111a..05214840 100644
> --- a/e2fsck/problem.h
> +++ b/e2fsck/problem.h
> @@ -1004,6 +1004,9 @@ struct problem_context {
> /* Encrypted directory entry is too short */
> #define PR_2_BAD_ENCRYPTED_NAME		0x020050
> 
> +/* Entry dirdata length set incorrectly */
> +#define PR_2_CLEAR_DIRDATA		0x020051
> +
> /*
>  * Pass 3 errors
>  */
> diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c
> index 486e1f21..546b073c 100644
> --- a/e2fsck/rehash.c
> +++ b/e2fsck/rehash.c
> @@ -85,6 +85,8 @@ struct fill_dir_struct {
> 	int compress;
> 	ino_t parent;
> 	ext2_ino_t dir;
> +	struct ext2_dir_entry *dot_de;
> +	struct ext2_dir_entry *dotdot_de;
> };
> 
> struct hash_entry {
> @@ -160,11 +162,14 @@ static int fill_dir_block(ext2_filsys fs,
> 		if (dirent->inode == 0)
> 			continue;
> 		if (!fd->compress && (name_len == 1) &&
> -		    (dirent->name[0] == '.'))
> +		    (dirent->name[0] == '.')) {
> +			fd->dot_de = dirent;
> 			continue;
> +		}
> 		if (!fd->compress && (name_len == 2) &&
> 		    (dirent->name[0] == '.') && (dirent->name[1] == '.')) {
> 			fd->parent = dirent->inode;
> +			fd->dotdot_de = dirent;
> 			continue;
> 		}
> 		if (fd->num_array >= fd->max_array) {
> @@ -179,7 +184,7 @@ static int fill_dir_block(ext2_filsys fs,
> 		}
> 		ent = fd->harray + fd->num_array++;
> 		ent->dir = dirent;
> -		fd->dir_size += EXT2_DIR_REC_LEN(name_len);
> +		fd->dir_size += EXT2_DIR_REC_LEN(dirent);
> 		ent->ino = dirent->inode;
> 		if (fd->compress)
> 			ent->hash = ent->minor_hash = 0;
> @@ -475,7 +480,7 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
> 		ent = fd->harray + i;
> 		if (ent->dir->inode == 0)
> 			continue;
> -		rec_len = EXT2_DIR_REC_LEN(ext2fs_dirent_name_len(ent->dir));
> +		rec_len = EXT2_DIR_REC_LEN(ent->dir);
> 		if (rec_len > left) {
> 			if (left) {
> 				left += prev_rec_len;
> @@ -510,8 +515,7 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
> 		if (retval)
> 			return retval;
> 		prev_rec_len = rec_len;
> -		memcpy(dirent->name, ent->dir->name,
> -		       ext2fs_dirent_name_len(dirent));
> +		memcpy(dirent->name, ent->dir->name, rec_len);
> 		offset += rec_len;
> 		left -= rec_len;
> 		if (left < slack) {
> @@ -536,44 +540,49 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
> 
> 
> static struct ext2_dx_root_info *set_root_node(ext2_filsys fs, char *buf,
> -				    ext2_ino_t ino, ext2_ino_t parent)
> +					ext2_ino_t ino, ext2_ino_t parent,
> +					struct ext2_dir_entry *dot_de,
> +					struct ext2_dir_entry *dotdot_de)
> {
> -	struct ext2_dir_entry 		*dir;
> -	struct ext2_dx_root_info  	*root;
> +	struct ext2_dir_entry		*dirent;
> +	struct ext2_dx_root_info	*root;
> 	struct ext2_dx_countlimit	*limits;
> -	int				filetype = 0;
> 	int				csum_size = 0;
> -
> -	if (ext2fs_has_feature_filetype(fs->super))
> -		filetype = EXT2_FT_DIR;
> +	int				offset;
> +	int				rec_len;
> 
> 	memset(buf, 0, fs->blocksize);
> -	dir = (struct ext2_dir_entry *) buf;
> -	dir->inode = ino;
> -	dir->name[0] = '.';
> -	ext2fs_dirent_set_name_len(dir, 1);
> -	ext2fs_dirent_set_file_type(dir, filetype);
> -	dir->rec_len = 12;
> -	dir = (struct ext2_dir_entry *) (buf + 12);
> -	dir->inode = parent;
> -	dir->name[0] = '.';
> -	dir->name[1] = '.';
> -	ext2fs_dirent_set_name_len(dir, 2);
> -	ext2fs_dirent_set_file_type(dir, filetype);
> -	dir->rec_len = fs->blocksize - 12;
> -
> -	root = (struct ext2_dx_root_info *) (buf+24);
> +	dirent = (struct ext2_dir_entry *) buf;
> +	dirent->inode = ino;
> +
> +	dirent->name_len = dot_de->name_len;
> +	offset = rec_len = dirent->rec_len = dot_de->rec_len;
> +	memcpy(dirent->name, dot_de->name, rec_len);
> +
> +	dirent = EXT2_NEXT_DIRENT(dirent);
> +	/* set to jump over the index block */
> +
> +	dirent->inode = parent;
> +
> +	dirent->name_len = dotdot_de->name_len;
> +	dirent->rec_len = fs->blocksize - rec_len;
> +	rec_len = EXT2_DIR_REC_LEN(dotdot_de);
> +	memcpy(dirent->name, dotdot_de->name, rec_len);
> +	offset += rec_len;
> +
> +	root = (struct ext2_dx_root_info *)(buf + offset);
> 	root->reserved_zero = 0;
> 	root->hash_version = fs->super->s_def_hash_version;
> -	root->info_length = 8;
> +	root->info_length = sizeof(*root);
> 	root->indirect_levels = 0;
> 	root->unused_flags = 0;
> +	offset += root->info_length;
> 
> 	if (ext2fs_has_feature_metadata_csum(fs->super))
> 		csum_size = sizeof(struct ext2_dx_tail);
> 
> -	limits = (struct ext2_dx_countlimit *) (buf+32);
> -	limits->limit = (fs->blocksize - (32 + csum_size)) /
> +	limits = (struct ext2_dx_countlimit *) (buf + offset);
> +	limits->limit = (fs->blocksize - (offset + csum_size)) /
> 			sizeof(struct ext2_dx_entry);
> 	limits->count = 0;
> 
> @@ -647,7 +656,9 @@ static int alloc_blocks(ext2_filsys fs,
> static errcode_t calculate_tree(ext2_filsys fs,
> 				struct out_dir *outdir,
> 				ext2_ino_t ino,
> -				ext2_ino_t parent)
> +				ext2_ino_t parent,
> +				struct ext2_dir_entry *dot_de,
> +				struct ext2_dir_entry *dotdot_de)
> {
> 	struct ext2_dx_root_info	*root_info;
> 	struct ext2_dx_entry		*root, *int_ent, *dx_ent = 0;
> @@ -657,7 +668,9 @@ static errcode_t calculate_tree(ext2_filsys fs,
> 	int				i, c1, c2, c3, nblks;
> 	int				limit_offset, int_offset, root_offset;
> 
> -	root_info = set_root_node(fs, outdir->buf, ino, parent);
> +	root_info = set_root_node(fs, outdir->buf, ino, parent, dot_de,
> +				  dotdot_de);
> +
> 	root_offset = limit_offset = ((char *) root_info - outdir->buf) +
> 		root_info->info_length;
> 	root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset);
> @@ -944,11 +957,10 @@ resort:
> 	if (retval)
> 		goto errout;
> 
> -	free(dir_buf); dir_buf = 0;
> -
> 	if (!fd.compress) {
> 		/* Calculate the interior nodes */
> -		retval = calculate_tree(fs, &outdir, ino, fd.parent);
> +		retval = calculate_tree(fs, &outdir, ino, fd.parent,
> +					fd.dot_de, fd.dotdot_de);
> 		if (retval)
> 			goto errout;
> 	}
> diff --git a/lib/ext2fs/dirblock.c b/lib/ext2fs/dirblock.c
> index 54b27772..3563138d 100644
> --- a/lib/ext2fs/dirblock.c
> +++ b/lib/ext2fs/dirblock.c
> @@ -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,
> +				 char 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)))
> {
> diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
> index 2496d16d..4919f946 100644
> --- a/lib/ext2fs/ext2_fs.h
> +++ b/lib/ext2fs/ext2_fs.h
> @@ -923,7 +923,8 @@ EXT4_FEATURE_INCOMPAT_FUNCS(encrypt,		4, ENCRYPT)
> #define EXT2_FEATURE_INCOMPAT_SUPP    (EXT2_FEATURE_INCOMPAT_FILETYPE| \
> 				       EXT4_FEATURE_INCOMPAT_MMP| \
> 				       EXT4_FEATURE_INCOMPAT_LARGEDIR| \
> -				       EXT4_FEATURE_INCOMPAT_EA_INODE)
> +				       EXT4_FEATURE_INCOMPAT_EA_INODE| \
> +				       EXT4_FEATURE_INCOMPAT_DIRDATA)
> #define EXT2_FEATURE_RO_COMPAT_SUPP	(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
> 					 EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
> 					 EXT4_FEATURE_RO_COMPAT_DIR_NLINK| \
> @@ -1011,6 +1012,7 @@ struct ext2_dir_entry_tail {
> #define EXT2_FT_SYMLINK		7
> 
> #define EXT2_FT_MAX		8
> +#define EXT2_FT_MASK		0x0f
> 
> /*
>  * Annoyingly, e2fsprogs always swab16s ext2_dir_entry.name_len, so we
> @@ -1028,11 +1030,18 @@ struct ext2_dir_entry_tail {
> #define EXT2_DIR_ENTRY_HEADER_LEN	8
> #define EXT2_DIR_PAD			4
> #define EXT2_DIR_ROUND			(EXT2_DIR_PAD - 1)
> -#define EXT2_DIR_REC_LEN(name_len)	(((name_len) + \
> +#define EXT2_DIR_NAME_LEN(name_len)	(((name_len) + \
> 					  EXT2_DIR_ENTRY_HEADER_LEN + \
> 					  EXT2_DIR_ROUND) & \
> 					 ~EXT2_DIR_ROUND)
> 
> +#define EXT2_DIR_REC_LEN(de)	(EXT2_DIR_NAME_LEN(((de)->name_len &         \
> +						     EXT2_NAME_LEN) +         \
> +						    ext2_get_dirdata_size(de)))
> +/* lu_fid size and NUL char */
> +#define EXT2_DIRENT_LUFID_SIZE		16
> +#define EXT2_DIRENT_LUFID		0x10
> +
> /*
>  * Constants for ext4's extended time encoding
>  */
> @@ -1091,6 +1100,9 @@ struct mmp_struct {
>  */
> #define EXT4_MMP_MIN_CHECK_INTERVAL     5
> 
> +int ext2_get_dirdata_field_size(struct ext2_dir_entry *de, char dirdata_flags);
> +int ext2_get_dirent_size(struct ext2_dir_entry *de);
> +
> /*
>  * Minimum size of inline data.
>  */
> @@ -1101,4 +1113,6 @@ struct mmp_struct {
>  */
> #define EXT4_INLINE_DATA_DOTDOT_SIZE	(4)
> 
> +#define EXT2_NEXT_DIRENT(d)	((void *)((char *)(d) + (d)->rec_len))
> +
> #endif	/* _LINUX_EXT2_FS_H */
> diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
> index 6774e32c..fbe4398f 100644
> --- a/lib/ext2fs/ext2fs.h
> +++ b/lib/ext2fs/ext2fs.h
> @@ -600,6 +600,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|\
> @@ -1978,6 +1979,25 @@ _INLINE_ int ext2fs_htree_intnode_maxrecs(ext2_filsys fs, int blocks)
> 	return blocks * ((fs->blocksize - 8) / 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;
> +}
> +
> /*
>  * This is an efficient, overflow safe way of calculating ceil((1.0 * a) / b)
>  */
> @@ -1997,7 +2017,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)
> diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
> index 7215c517..684972b3 100644
> --- a/lib/ext2fs/inline_data.c
> +++ b/lib/ext2fs/inline_data.c
> @@ -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 {
> diff --git a/lib/ext2fs/link.c b/lib/ext2fs/link.c
> index 65dc8877..a038a104 100644
> --- a/lib/ext2fs/link.c
> +++ b/lib/ext2fs/link.c
> @@ -47,7 +47,7 @@ static int link_proc(struct ext2_dir_entry *dirent,
> 	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)
> @@ -92,8 +92,8 @@ static int link_proc(struct ext2_dir_entry *dirent,
> 
> 	/* De-convert a dx_root block */
> 	if (csum_size &&
> -	    curr_rec_len == ls->fs->blocksize - EXT2_DIR_REC_LEN(1) &&
> -	    offset == EXT2_DIR_REC_LEN(1) &&
> +	    curr_rec_len == ls->fs->blocksize - EXT2_DIR_NAME_LEN(1) &&
> +	    offset == EXT2_DIR_NAME_LEN(1) &&
> 	    dirent->name[0] == '.' && dirent->name[1] == '.') {
> 		curr_rec_len -= csum_size;
> 		ls->err = ext2fs_set_rec_len(ls->fs, curr_rec_len, dirent);
> @@ -110,7 +110,7 @@ static int link_proc(struct ext2_dir_entry *dirent,
> 	 * 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;
> @@ -138,7 +138,7 @@ static int link_proc(struct ext2_dir_entry *dirent,
> 	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 & 0x7);
> +		ext2fs_dirent_set_file_type(dirent, ls->flags & EXT2_FT_MASK);
> 
> 	ls->done++;
> 	return DIRENT_ABORT|DIRENT_CHANGED;
> diff --git a/lib/ext2fs/newdir.c b/lib/ext2fs/newdir.c
> index 7f472850..f168d668 100644
> --- a/lib/ext2fs/newdir.c
> +++ b/lib/ext2fs/newdir.c
> @@ -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 '..'
> diff --git a/misc/mke2fs.c b/misc/mke2fs.c
> index cfb10bc4..4d8593f7 100644
> --- a/misc/mke2fs.c
> +++ b/misc/mke2fs.c
> @@ -1084,6 +1084,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 |
> @@ -2900,6 +2901,13 @@ int main (int argc, char *argv[])
> 		exit(1);
> 	}
> 
> +	if (ext2fs_has_feature_inline_data(fs->super) &&
> +	    ext2fs_has_feature_dirdata(fs->super)) {
> +		printf("%s", _("The dirdata feature can not enabled "
> +			       "with inline data feature.\n"));
> +		exit(1);
> +	}
> +
> 	/* Calculate journal blocks */
> 	if (!journal_device && ((journal_size) ||
> 	    ext2fs_has_feature_journal(&fs_param)))
> diff --git a/misc/tune2fs.c b/misc/tune2fs.c
> index d0a18a18..44dd41a5 100644
> --- a/misc/tune2fs.c
> +++ b/misc/tune2fs.c
> @@ -157,6 +157,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 |
> @@ -183,6 +184,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,
> 	/* R/O compat */
> -- 
> 2.14.3 (Apple Git-98)
> 

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ