1 Index: linux-4.15.0/fs/ext4/namei.c
2 ===================================================================
3 --- linux-4.15.0.orig/fs/ext4/namei.c
4 +++ linux-4.15.0/fs/ext4/namei.c
5 @@ -196,22 +196,13 @@ struct dx_entry
6 * hash version mod 4 should never be 0. Sincerely, the paranoia department.
12 - struct fake_dirent dot;
14 - struct fake_dirent dotdot;
15 - char dotdot_name[4];
18 - __le32 reserved_zero;
20 - u8 info_length; /* 8 */
25 - struct dx_entry entries[0];
26 + __le32 reserved_zero;
28 + u8 info_length; /* 8 */
34 @@ -512,6 +503,16 @@ ext4_next_entry(struct ext4_dir_entry_2
35 * Future: use high four bits of block for coalesce-on-delete flags
36 * Mask them off for now.
38 +struct dx_root_info *dx_get_dx_info(struct ext4_dir_entry_2 *de)
40 + /* get dotdot first */
41 + de = (struct ext4_dir_entry_2 *)((char *)de + EXT4_DIR_REC_LEN(1));
43 + /* dx root info is after dotdot entry */
44 + de = (struct ext4_dir_entry_2 *)((char *)de + EXT4_DIR_REC_LEN(2));
46 + return (struct dx_root_info *)de;
49 static inline ext4_lblk_t dx_get_block(struct dx_entry *entry)
51 @@ -736,7 +737,7 @@ dx_probe(struct ext4_filename *fname, st
53 unsigned count, indirect;
54 struct dx_entry *at, *entries, *p, *q, *m;
55 - struct dx_root *root;
56 + struct dx_root_info *info;
57 struct dx_frame *frame = frame_in;
58 struct dx_frame *ret_err = ERR_PTR(ERR_BAD_DX_DIR);
60 @@ -745,18 +746,17 @@ dx_probe(struct ext4_filename *fname, st
61 frame->bh = ext4_read_dirblock(dir, 0, INDEX);
62 if (IS_ERR(frame->bh))
63 return (struct dx_frame *) frame->bh;
65 - root = (struct dx_root *) frame->bh->b_data;
66 - if (root->info.hash_version != DX_HASH_TEA &&
67 - root->info.hash_version != DX_HASH_HALF_MD4 &&
68 - root->info.hash_version != DX_HASH_LEGACY) {
69 - ext4_warning_inode(dir, "Unrecognised inode hash code %u for directory "
70 - "%lu", root->info.hash_version, dir->i_ino);
71 + info = dx_get_dx_info((struct ext4_dir_entry_2 *)frame->bh->b_data);
72 + if (info->hash_version != DX_HASH_TEA &&
73 + info->hash_version != DX_HASH_HALF_MD4 &&
74 + info->hash_version != DX_HASH_LEGACY) {
75 + ext4_warning(dir->i_sb, "Unrecognised inode hash code %d for directory "
76 + "#%lu", info->hash_version, dir->i_ino);
80 hinfo = &fname->hinfo;
81 - hinfo->hash_version = root->info.hash_version;
82 + hinfo->hash_version = info->hash_version;
83 if (hinfo->hash_version <= DX_HASH_TEA)
84 hinfo->hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned;
85 hinfo->seed = EXT4_SB(dir->i_sb)->s_hash_seed;
86 @@ -764,13 +764,13 @@ dx_probe(struct ext4_filename *fname, st
87 ext4fs_dirhash(fname_name(fname), fname_len(fname), hinfo);
90 - if (root->info.unused_flags & 1) {
91 + if (info->unused_flags & 1) {
92 ext4_warning_inode(dir, "Unimplemented hash flags: %#06x",
93 - root->info.unused_flags);
94 + info->unused_flags);
98 - indirect = root->info.indirect_levels;
99 + indirect = info->indirect_levels;
100 if (indirect >= ext4_dir_htree_level(dir->i_sb)) {
101 ext4_warning(dir->i_sb,
102 "Directory (ino: %lu) htree depth %#06x exceed"
103 @@ -783,14 +783,13 @@ dx_probe(struct ext4_filename *fname, st
107 - entries = (struct dx_entry *)(((char *)&root->info) +
108 - root->info.info_length);
109 + entries = (struct dx_entry *)(((char *)info) + info->info_length);
111 if (dx_get_limit(entries) != dx_root_limit(dir,
112 - root->info.info_length)) {
113 + info->info_length)) {
114 ext4_warning_inode(dir, "dx entry: limit %u != root limit %u",
115 dx_get_limit(entries),
116 - dx_root_limit(dir, root->info.info_length));
117 + dx_root_limit(dir, info->info_length));
121 @@ -874,7 +873,7 @@ static void dx_release(struct dx_frame *
122 if (frames[0].bh == NULL)
125 - info = &((struct dx_root *)frames[0].bh->b_data)->info;
126 + info = dx_get_dx_info((struct ext4_dir_entry_2 *)frames[0].bh->b_data);
127 for (i = 0; i <= info->indirect_levels; i++) {
128 if (frames[i].bh == NULL)
130 @@ -1930,17 +1929,16 @@ static int make_indexed_dir(handle_t *ha
131 struct inode *inode, struct buffer_head *bh)
133 struct buffer_head *bh2;
134 - struct dx_root *root;
135 struct dx_frame frames[EXT4_HTREE_LEVEL], *frame;
136 struct dx_entry *entries;
137 - struct ext4_dir_entry_2 *de, *de2;
138 + struct ext4_dir_entry_2 *de, *de2, *dot_de, *dotdot_de;
139 struct ext4_dir_entry_tail *t;
145 - struct fake_dirent *fde;
146 + struct dx_root_info *dx_info;
149 if (ext4_has_metadata_csum(inode->i_sb))
150 @@ -1955,18 +1953,19 @@ static int make_indexed_dir(handle_t *ha
154 - root = (struct dx_root *) bh->b_data;
156 + dot_de = (struct ext4_dir_entry_2 *)bh->b_data;
157 + dotdot_de = ext4_next_entry(dot_de, blocksize);
159 /* The 0th block becomes the root, move the dirents out */
160 - fde = &root->dotdot;
161 - de = (struct ext4_dir_entry_2 *)((char *)fde +
162 - ext4_rec_len_from_disk(fde->rec_len, blocksize));
163 - if ((char *) de >= (((char *) root) + blocksize)) {
164 + de = (struct ext4_dir_entry_2 *)((char *)dotdot_de +
165 + ext4_rec_len_from_disk(dotdot_de->rec_len, blocksize));
166 + if ((char *)de >= (((char *)dot_de) + blocksize)) {
167 EXT4_ERROR_INODE(dir, "invalid rec_len for '..'");
169 return -EFSCORRUPTED;
171 - len = ((char *) root) + (blocksize - csum_size) - (char *) de;
172 + len = ((char *)dot_de) + (blocksize - csum_size) - (char *)de;
174 /* Allocate new block for the 0th block's dirents */
175 bh2 = ext4_append(handle, dir, &block);
176 @@ -1992,19 +1991,24 @@ static int make_indexed_dir(handle_t *ha
179 /* Initialize the root; the dot dirents already exist */
180 - de = (struct ext4_dir_entry_2 *) (&root->dotdot);
181 - de->rec_len = ext4_rec_len_to_disk(blocksize - EXT4_DIR_REC_LEN(2),
183 - memset (&root->info, 0, sizeof(root->info));
184 - root->info.info_length = sizeof(root->info);
185 - root->info.hash_version = EXT4_SB(dir->i_sb)->s_def_hash_version;
186 - entries = root->entries;
187 + dotdot_de->rec_len =
188 + ext4_rec_len_to_disk(blocksize - le16_to_cpu(dot_de->rec_len),
191 + /* initialize hashing info */
192 + dx_info = dx_get_dx_info(dot_de);
193 + memset(dx_info, 0, sizeof(*dx_info));
194 + dx_info->info_length = sizeof(*dx_info);
195 + dx_info->hash_version = EXT4_SB(dir->i_sb)->s_def_hash_version;
197 + entries = (void *)dx_info + sizeof(*dx_info);
199 dx_set_block(entries, 1);
200 dx_set_count(entries, 1);
201 - dx_set_limit(entries, dx_root_limit(dir, sizeof(root->info)));
202 + dx_set_limit(entries, dx_root_limit(dir, sizeof(*dx_info)));
204 /* Initialize as for dx_probe */
205 - fname->hinfo.hash_version = root->info.hash_version;
206 + fname->hinfo.hash_version = dx_info->hash_version;
207 if (fname->hinfo.hash_version <= DX_HASH_TEA)
208 fname->hinfo.hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned;
209 fname->hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed;
210 @@ -2346,7 +2350,7 @@ again:
214 - struct dx_root *dxroot;
215 + struct dx_root_info *info;
216 memcpy((char *) entries2, (char *) entries,
217 icount * sizeof(struct dx_entry));
218 dx_set_limit(entries2, dx_node_limit(dir));
219 @@ -2354,8 +2358,9 @@ again:
221 dx_set_count(entries, 1);
222 dx_set_block(entries + 0, newblock);
223 - dxroot = (struct dx_root *)frames[0].bh->b_data;
224 - dxroot->info.indirect_levels += 1;
225 + info = dx_get_dx_info((struct ext4_dir_entry_2 *)
226 + frames[0].bh->b_data);
227 + info->indirect_levels = 1;
228 dxtrace(printk(KERN_DEBUG
229 "Creating %d level index...\n",
230 info->indirect_levels));