From: Artem Blagodarenko Define the on-disk format for ext4 directory entry extension data. The upper four bits of de->file_type indicate the presence of optional data stored after the filename NUL terminator. This patch defines flags for LUFID, 64-bit inode numbers, and casefold hash data stored in that area. Add struct ext4_dirent_data_header to describe variable-length extension records and struct ext4_dirent_hash for hash storage used by casefold and fscrypt. Provide ext4_dirdata_next() to advance to the next extension record and ext4_dirent_get_data_len() to compute the total extension data length associated with a directory entry. No functional changes. Signed-off-by: Pravin Shelar Signed-off-by: Artem Blagodarenko Reviewed-by: Andreas Dilger --- fs/ext4/ext4.h | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 01b1222b1454..c36c3bf54590 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -2470,6 +2470,49 @@ struct ext4_dir_entry_tail { #define EXT4_FT_SYMLINK 7 #define EXT4_FT_MAX 8 +#define EXT4_FT_MASK 0xf + +#if EXT4_FT_MAX > EXT4_FT_MASK +#error "conflicting EXT4_FT_MAX and EXT4_FT_MASK" +#endif + +/* + * d_type has 4 unused bits, so it can hold four types of data. These different + * types of data (e.g. fscypt hash, high 32 bits of 64-bit inode number) can be + * stored, in flag order, after file-name in ext4 dirent. + * + * These flags are added to d_type if ext4 dirent has extra data after + * filename. This data length is variable and length is stored in first byte + * of data. Data starts after filename NUL byte. + */ +#define EXT4_DIRENT_LUFID 0x10 +#define EXT4_DIRENT_INO64 0x20 +#define EXT4_DIRENT_CFHASH 0x40 + +struct ext4_fid { + char fid[16]; /* 128-bit unique file identifier */ +}; + +struct ext4_dirent_data_header { + /* length of this header + the whole data blob */ + __u8 ddh_length; +} __packed; + +struct ext4_dirent_fid { + struct ext4_dirent_data_header df_header; + struct ext4_fid df_fid[]; +}; + +#define EXT4_LUFID_MAGIC 0xAD200907UL +struct ext4_dentry_param { + __u32 edp_magic; /* EXT4_LUFID_MAGIC */ + struct ext4_dirent_fid edp_dfid; +}; + +struct ext4_dirent_hash { + struct ext4_dirent_data_header dh_header; + struct ext4_dir_entry_hash dh_hash; +} __packed; #define EXT4_FT_DIR_CSUM 0xDE @@ -3917,6 +3960,12 @@ static inline void ext4_clear_io_unwritten_flag(ext4_io_end_t *io_end) io_end->flag &= ~EXT4_IO_END_UNWRITTEN; } +/* + * Advance to the next dirdata record header starting from @ddh. + */ +#define ext4_dirdata_next(ddh) \ + ((struct ext4_dirent_data_header *)((char *)(ddh) + (ddh)->ddh_length)) + /* * ext4_dir_entry_is_tail() - Check if a directory entry is a tail entry. * @de: directory entry to check @@ -3933,6 +3982,40 @@ static inline bool ext4_dir_entry_is_tail(struct ext4_dir_entry_2 *de) t->det_reserved_ft == EXT4_FT_DIR_CSUM; } +/* + * ext4_dirent_get_data_len() - Compute the total dirdata length for an entry. + * @de: directory entry + * + * Computes the length of optional data stored after the filename (and its + * implicit NUL terminator). Each extension is indicated by a bit in the + * high 4 bits of de->file_type; the first byte of each extension is its + * length (including that length byte itself). + * + * Returns 0 for tail entries and for entries with no dirdata. + */ +static inline int ext4_dirent_get_data_len(struct ext4_dir_entry_2 *de) +{ + __u8 extra_data_flags; + struct ext4_dirent_data_header *ddh; + int dlen = 0; + + if (ext4_dir_entry_is_tail(de)) + return 0; + + extra_data_flags = (de->file_type & ~EXT4_FT_MASK) >> 4; + ddh = (struct ext4_dirent_data_header *)(de->name + de->name_len + + 1 /* NUL terminator */); + + while (extra_data_flags) { + if (extra_data_flags & 1) { + dlen += ddh->ddh_length + (dlen == 0); + ddh = ext4_dirdata_next(ddh); + } + extra_data_flags >>= 1; + } + return dlen; +} + extern const struct iomap_ops ext4_iomap_ops; extern const struct iomap_ops ext4_iomap_report_ops; -- 2.43.7