mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-07-23 23:32:14 +00:00
ext4: fix readdir error in the case of inline_data+dir_index
Zach reported a problem that if inline data is enabled, we don't tell the difference between the offset of '.' and '..'. And a getdents will fail if the user only want to get '.' and what's worse, if there is a conversion happens when the user calls getdents many times, he/she may get the same entry twice. In theory, a dir block would also fail if it is converted to a hashed-index based dir since f_pos will become a hash value, not the real one, but it doesn't happen. And a deep investigation shows that we uses a hash based solution even for a normal dir if the dir_index feature is enabled. So this patch just adds a new htree_inlinedir_to_tree for inline dir, and if we find that the hash index is supported, we will do like what we do for a dir block. Reported-by: Zach Brown <zab@redhat.com> Signed-off-by: Tao Ma <boyu.mt@taobao.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
This commit is contained in:
parent
28daf4fae8
commit
8af0f08227
4 changed files with 153 additions and 28 deletions
|
@ -2518,6 +2518,11 @@ extern int ext4_try_create_inline_dir(handle_t *handle,
|
|||
extern int ext4_read_inline_dir(struct file *filp,
|
||||
void *dirent, filldir_t filldir,
|
||||
int *has_inline_data);
|
||||
extern int htree_inlinedir_to_tree(struct file *dir_file,
|
||||
struct inode *dir, ext4_lblk_t block,
|
||||
struct dx_hash_info *hinfo,
|
||||
__u32 start_hash, __u32 start_minor_hash,
|
||||
int *has_inline_data);
|
||||
extern struct buffer_head *ext4_find_inline_entry(struct inode *dir,
|
||||
const struct qstr *d_name,
|
||||
struct ext4_dir_entry_2 **res_dir,
|
||||
|
@ -2554,6 +2559,24 @@ extern void initialize_dirent_tail(struct ext4_dir_entry_tail *t,
|
|||
extern int ext4_handle_dirty_dirent_node(handle_t *handle,
|
||||
struct inode *inode,
|
||||
struct buffer_head *bh);
|
||||
#define S_SHIFT 12
|
||||
static unsigned char ext4_type_by_mode[S_IFMT >> S_SHIFT] = {
|
||||
[S_IFREG >> S_SHIFT] = EXT4_FT_REG_FILE,
|
||||
[S_IFDIR >> S_SHIFT] = EXT4_FT_DIR,
|
||||
[S_IFCHR >> S_SHIFT] = EXT4_FT_CHRDEV,
|
||||
[S_IFBLK >> S_SHIFT] = EXT4_FT_BLKDEV,
|
||||
[S_IFIFO >> S_SHIFT] = EXT4_FT_FIFO,
|
||||
[S_IFSOCK >> S_SHIFT] = EXT4_FT_SOCK,
|
||||
[S_IFLNK >> S_SHIFT] = EXT4_FT_SYMLINK,
|
||||
};
|
||||
|
||||
static inline void ext4_set_de_type(struct super_block *sb,
|
||||
struct ext4_dir_entry_2 *de,
|
||||
umode_t mode) {
|
||||
if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FILETYPE))
|
||||
de->file_type = ext4_type_by_mode[(mode & S_IFMT)>>S_SHIFT];
|
||||
}
|
||||
|
||||
|
||||
/* symlink.c */
|
||||
extern const struct inode_operations ext4_symlink_inode_operations;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue