1 this patch implements feature which allows ext4 fs users (e.g. Lustre)
2 to store data in ext4 dirent.
3 data is stored in ext4 dirent after file-name, this space is accounted
4 in de->rec_len. flag EXT4_DIRENT_LUFID added to d_type if extra data
7 make use of dentry->d_fsdata to pass fid to ext4. so no
8 changes in ext4_add_entry() interface required.
11 fs/ext4/dir.c | 13 ++-
12 fs/ext4/ext4.h | 100 +++++++++++++++++++++++-
13 fs/ext4/fast_commit.c | 2
14 fs/ext4/inline.c | 8 -
15 fs/ext4/namei.c | 201 +++++++++++++++++++++++++++++++++++++++-----------
17 6 files changed, 270 insertions(+), 58 deletions(-)
19 diff -ur a/fs/ext4/dir.c b/fs/ext4/dir.c
20 --- a/fs/ext4/dir.c 2021-12-14 08:28:35.514373035 -0700
21 +++ b/fs/ext4/dir.c 2021-12-14 08:29:41.318242202 -0700
23 error_msg = "rec_len is smaller than minimal";
24 else if (unlikely(rlen % 4 != 0))
25 error_msg = "rec_len % 4 != 0";
26 - else if (unlikely(rlen < EXT4_DIR_REC_LEN(de->name_len)))
27 + else if (unlikely(rlen < EXT4_DIR_ENTRY_LEN(de)))
28 error_msg = "rec_len is too small for name_len";
29 else if (unlikely(next_offset > size))
30 error_msg = "directory entry overrun";
32 * failure will be detected in the
33 * dirent test below. */
34 if (ext4_rec_len_from_disk(de->rec_len,
35 - sb->s_blocksize) < EXT4_DIR_REC_LEN(1))
36 + sb->s_blocksize) < EXT4_DIR_REC_LEN(1))
38 i += ext4_rec_len_from_disk(de->rec_len,
41 struct fname *fname, *new_fn;
42 struct dir_private_info *info;
46 info = dir_file->private_data;
47 p = &info->root.rb_node;
49 /* Create and allocate the fname structure */
50 - len = sizeof(struct fname) + ent_name->len + 1;
51 + if (dirent->file_type & EXT4_DIRENT_LUFID)
52 + extra_data = ext4_get_dirent_data_len(dirent);
54 + len = sizeof(struct fname) + ent_name->len + extra_data + 1;
56 new_fn = kzalloc(len, GFP_KERNEL);
60 new_fn->inode = le32_to_cpu(dirent->inode);
61 new_fn->name_len = ent_name->len;
62 new_fn->file_type = dirent->file_type;
63 - memcpy(new_fn->name, ent_name->name, ent_name->len);
64 + memcpy(new_fn->name, ent_name->name, ent_name->len + extra_data);
68 diff -ur a/fs/ext4/ext4.h b/fs/ext4/ext4.h
69 --- a/fs/ext4/ext4.h 2021-12-14 08:28:35.622372837 -0700
70 +++ b/fs/ext4/ext4.h 2021-12-14 08:30:28.938135681 -0700
80 * Mount flags set via mount options or defaults
82 #define EXT4_MOUNT_NO_MBCACHE 0x00001 /* Do not use mbcache */
83 +#define EXT4_MOUNT_DIRDATA 0x00002 /* Data in directory entries */
84 #define EXT4_MOUNT_GRPID 0x00004 /* Create files with directory's group */
85 #define EXT4_MOUNT_DEBUG 0x00008 /* Some debugging messages */
86 #define EXT4_MOUNT_ERRORS_CONT 0x00010 /* Continue on errors */
88 EXT4_FEATURE_INCOMPAT_FLEX_BG| \
89 EXT4_FEATURE_INCOMPAT_EA_INODE| \
90 EXT4_FEATURE_INCOMPAT_MMP | \
91 + EXT4_FEATURE_INCOMPAT_DIRDATA| \
92 EXT4_FEATURE_INCOMPAT_INLINE_DATA | \
93 EXT4_FEATURE_INCOMPAT_ENCRYPT | \
94 EXT4_FEATURE_INCOMPAT_CASEFOLD | \
95 @@ -2232,6 +2235,43 @@
96 #define EXT4_FT_SYMLINK 7
99 +#define EXT4_FT_MASK 0xf
101 +#if EXT4_FT_MAX > EXT4_FT_MASK
102 +#error "conflicting EXT4_FT_MAX and EXT4_FT_MASK"
106 + * d_type has 4 unused bits, so it can hold four types data. these different
107 + * type of data (e.g. lustre data, high 32 bits of 64-bit inode number) can be
108 + * stored, in flag order, after file-name in ext4 dirent.
111 + * this flag is added to d_type if ext4 dirent has extra data after
112 + * filename. this data length is variable and length is stored in first byte
113 + * of data. data start after filename NUL byte.
114 + * This is used by Lustre FS.
116 +#define EXT4_DIRENT_LUFID 0x10
118 +#define EXT4_LUFID_MAGIC 0xAD200907UL
119 +struct ext4_dentry_param {
120 + __u32 edp_magic; /* EXT4_LUFID_MAGIC */
121 + char edp_len; /* size of edp_data in bytes */
122 + char edp_data[0]; /* packed array of data */
125 +static inline unsigned char *ext4_dentry_get_data(struct super_block *sb,
126 + struct ext4_dentry_param *p)
129 + if (!ext4_has_feature_dirdata(sb))
131 + if (p && p->edp_magic == EXT4_LUFID_MAGIC)
132 + return &p->edp_len;
137 #define EXT4_FT_DIR_CSUM 0xDE
139 @@ -2242,8 +2282,16 @@
141 #define EXT4_DIR_PAD 4
142 #define EXT4_DIR_ROUND (EXT4_DIR_PAD - 1)
143 -#define EXT4_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT4_DIR_ROUND) & \
144 +#define EXT4_DIR_REC_LEN_(name_len) (((name_len) + 8 + EXT4_DIR_ROUND) & \
146 +#define EXT4_DIR_ENTRY_LEN_(de) (EXT4_DIR_REC_LEN_((de)->name_len +\
147 + ext4_get_dirent_data_len(de)))
149 +#define EXT4_DIR_REC_LEN(name_len) EXT4_DIR_REC_LEN_((name_len))
150 +#define EXT4_DIR_ENTRY_LEN(de) EXT4_DIR_ENTRY_LEN_((de))
151 +/* lustre osd_handler compat */
152 +#define __EXT4_DIR_REC_LEN(name_len) EXT4_DIR_REC_LEN_((name_len))
154 #define EXT4_MAX_REC_LEN ((1<<16)-1)
157 @@ -2710,11 +2758,11 @@
158 struct buffer_head *bh,
159 void *buf, int buf_size,
160 struct ext4_filename *fname,
161 - struct ext4_dir_entry_2 **dest_de);
162 + struct ext4_dir_entry_2 **dest_de, int *dlen);
163 void ext4_insert_dentry(struct inode *inode,
164 struct ext4_dir_entry_2 *de,
166 - struct ext4_filename *fname);
167 + struct ext4_filename *fname, void *data);
168 static inline void ext4_update_dx_flag(struct inode *inode)
170 if (!ext4_has_feature_dir_index(inode->i_sb) &&
171 @@ -2730,10 +2778,17 @@
173 static inline unsigned char get_dtype(struct super_block *sb, int filetype)
175 - if (!ext4_has_feature_filetype(sb) || filetype >= EXT4_FT_MAX)
176 + int fl_index = filetype & EXT4_FT_MASK;
178 + if (!ext4_has_feature_filetype(sb) || fl_index >= EXT4_FT_MAX)
181 - return ext4_filetype_table[filetype];
182 + if (!test_opt(sb, DIRDATA))
183 + return ext4_filetype_table[fl_index];
185 + return (ext4_filetype_table[fl_index]) |
186 + (filetype & EXT4_DIRENT_LUFID);
189 extern int ext4_check_all_de(struct inode *dir, struct buffer_head *bh,
190 void *buf, int buf_size);
191 @@ -2922,7 +2977,8 @@
194 extern int ext4_init_new_dir(handle_t *handle, struct inode *dir,
195 - struct inode *inode);
196 + struct inode *inode,
197 + const void *data1, const void *data2);
198 extern int ext4_dirblock_csum_verify(struct inode *inode,
199 struct buffer_head *bh);
200 extern int ext4_orphan_add(handle_t *, struct inode *);
201 @@ -2933,6 +2989,8 @@
202 extern int ext4_delete_entry(handle_t *handle, struct inode * dir,
203 struct ext4_dir_entry_2 *de_del,
204 struct buffer_head *bh);
205 +extern int ext4_add_dot_dotdot(handle_t *handle, struct inode *dir,
206 + struct inode *inode, const void *, const void *);
207 extern int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
208 __u32 start_minor_hash, __u32 *next_hash);
209 extern int ext4_search_dir(struct buffer_head *bh,
210 @@ -3725,6 +3783,36 @@
211 return buffer_uptodate(bh);
215 + * Compute the total directory entry data length.
216 + * This includes the filename and an implicit NUL terminator (always present),
217 + * and optional extensions. Each extension has a bit set in the high 4 bits of
218 + * de->file_type, and the extension length is the first byte in each entry.
220 +static inline int ext4_get_dirent_data_len(struct ext4_dir_entry_2 *de)
222 + char *len = de->name + de->name_len + 1 /* NUL terminator */;
224 + __u8 extra_data_flags = (de->file_type & ~EXT4_FT_MASK) >> 4;
225 + struct ext4_dir_entry_tail *t = (struct ext4_dir_entry_tail *)de;
227 + if (!t->det_reserved_zero1 &&
228 + le16_to_cpu(t->det_rec_len) ==
229 + sizeof(struct ext4_dir_entry_tail) &&
230 + !t->det_reserved_zero2 &&
231 + t->det_reserved_ft == EXT4_FT_DIR_CSUM)
234 + while (extra_data_flags) {
235 + if (extra_data_flags & 1) {
236 + dlen += *len + (dlen == 0);
239 + extra_data_flags >>= 1;
244 #endif /* __KERNEL__ */
246 #define EFSBADCRC EBADMSG /* Bad CRC detected */
247 diff -ur a/fs/ext4/fast_commit.c b/fs/ext4/fast_commit.c
248 --- a/fs/ext4/fast_commit.c 2021-12-14 08:28:35.514373035 -0700
249 +++ b/fs/ext4/fast_commit.c 2021-12-14 08:29:41.326242185 -0700
250 @@ -1532,7 +1532,7 @@
251 jbd_debug(1, "Dir %d not found.", darg.ino);
254 - ret = ext4_init_new_dir(NULL, dir, inode);
255 + ret = ext4_init_new_dir(NULL, dir, inode, NULL, NULL);
259 diff -ur a/fs/ext4/inline.c b/fs/ext4/inline.c
260 --- a/fs/ext4/inline.c 2021-12-14 08:28:35.518373027 -0700
261 +++ b/fs/ext4/inline.c 2021-12-14 08:29:41.326242185 -0700
262 @@ -1023,7 +1023,7 @@
263 struct ext4_dir_entry_2 *de;
265 err = ext4_find_dest_de(dir, inode, iloc->bh, inline_start,
266 - inline_size, fname, &de);
267 + inline_size, fname, &de, NULL);
271 @@ -1031,7 +1031,7 @@
272 err = ext4_journal_get_write_access(handle, iloc->bh);
275 - ext4_insert_dentry(inode, de, inline_size, fname);
276 + ext4_insert_dentry(inode, de, inline_size, fname, NULL);
278 ext4_show_inline_dir(dir, iloc->bh, inline_start, inline_size);
280 @@ -1380,7 +1380,7 @@
282 strcpy(fake.name, ".");
283 fake.rec_len = ext4_rec_len_to_disk(
284 - EXT4_DIR_REC_LEN(fake.name_len),
285 + EXT4_DIR_ENTRY_LEN(&fake),
287 ext4_set_de_type(inode->i_sb, &fake, S_IFDIR);
289 @@ -1390,7 +1390,7 @@
291 strcpy(fake.name, "..");
292 fake.rec_len = ext4_rec_len_to_disk(
293 - EXT4_DIR_REC_LEN(fake.name_len),
294 + EXT4_DIR_ENTRY_LEN(&fake),
296 ext4_set_de_type(inode->i_sb, &fake, S_IFDIR);
298 diff -ur a/fs/ext4/namei.c b/fs/ext4/namei.c
299 --- a/fs/ext4/namei.c 2021-12-14 08:28:35.638372808 -0700
300 +++ b/fs/ext4/namei.c 2021-12-14 08:29:41.330242176 -0700
302 static unsigned dx_get_limit(struct dx_entry *entries);
303 static void dx_set_count(struct dx_entry *entries, unsigned value);
304 static void dx_set_limit(struct dx_entry *entries, unsigned value);
305 -static unsigned dx_root_limit(struct inode *dir, unsigned infosize);
306 +static inline unsigned dx_root_limit(struct inode *dir,
307 + struct ext4_dir_entry_2 *dot_de, unsigned infosize);
308 static unsigned dx_node_limit(struct inode *dir);
309 static struct dx_frame *dx_probe(struct ext4_filename *fname,
311 @@ -409,22 +410,23 @@
313 struct ext4_dir_entry *dp;
314 struct dx_root_info *root;
316 + int count_offset, dot_rec_len, dotdot_rec_len;
318 if (le16_to_cpu(dirent->rec_len) == EXT4_BLOCK_SIZE(inode->i_sb))
320 - else if (le16_to_cpu(dirent->rec_len) == 12) {
321 - dp = (struct ext4_dir_entry *)(((void *)dirent) + 12);
323 + dot_rec_len = le16_to_cpu(dirent->rec_len);
324 + dp = (struct ext4_dir_entry *)(((void *)dirent) + dot_rec_len);
325 if (le16_to_cpu(dp->rec_len) !=
326 - EXT4_BLOCK_SIZE(inode->i_sb) - 12)
327 + EXT4_BLOCK_SIZE(inode->i_sb) - dot_rec_len)
329 - root = (struct dx_root_info *)(((void *)dp + 12));
330 + dotdot_rec_len = EXT4_DIR_ENTRY_LEN((struct ext4_dir_entry_2 *)dp);
331 + root = (struct dx_root_info *)(((void *)dp + dotdot_rec_len));
332 if (root->reserved_zero ||
333 root->info_length != sizeof(struct dx_root_info))
338 + count_offset = 8 + dot_rec_len + dotdot_rec_len;
342 *offset = count_offset;
343 @@ -529,11 +531,12 @@
345 struct dx_root_info *dx_get_dx_info(struct ext4_dir_entry_2 *de)
347 + BUG_ON(de->name_len != 1);
348 /* get dotdot first */
349 - de = (struct ext4_dir_entry_2 *)((char *)de + EXT4_DIR_REC_LEN(1));
350 + de = (struct ext4_dir_entry_2 *)((char *)de + EXT4_DIR_ENTRY_LEN(de));
352 /* dx root info is after dotdot entry */
353 - de = (struct ext4_dir_entry_2 *)((char *)de + EXT4_DIR_REC_LEN(2));
354 + de = (struct ext4_dir_entry_2 *)((char *)de + EXT4_DIR_ENTRY_LEN(de));
356 return (struct dx_root_info *)de;
358 @@ -578,10 +581,16 @@
359 ((struct dx_countlimit *) entries)->limit = cpu_to_le16(value);
362 -static inline unsigned dx_root_limit(struct inode *dir, unsigned infosize)
363 +static inline unsigned dx_root_limit(struct inode *dir,
364 + struct ext4_dir_entry_2 *dot_de, unsigned infosize)
366 - unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(1) -
367 - EXT4_DIR_REC_LEN(2) - infosize;
368 + struct ext4_dir_entry_2 *dotdot_de;
369 + unsigned entry_space;
371 + BUG_ON(dot_de->name_len != 1);
372 + dotdot_de = ext4_next_entry(dot_de, dir->i_sb->s_blocksize);
373 + entry_space = dir->i_sb->s_blocksize - EXT4_DIR_ENTRY_LEN(dot_de) -
374 + EXT4_DIR_ENTRY_LEN(dotdot_de) - infosize;
376 if (ext4_has_metadata_csum(dir->i_sb))
377 entry_space -= sizeof(struct dx_tail);
379 (unsigned) ((char *) de - base));
382 - space += EXT4_DIR_REC_LEN(de->name_len);
383 + space += EXT4_DIR_ENTRY_LEN(de);
386 de = ext4_next_entry(de, size);
387 @@ -808,11 +817,14 @@
389 entries = (struct dx_entry *)(((char *)info) + info->info_length);
391 - if (dx_get_limit(entries) != dx_root_limit(dir,
392 - info->info_length)) {
393 + if (dx_get_limit(entries) !=
394 + dx_root_limit(dir, (struct ext4_dir_entry_2 *)frame->bh->b_data,
395 + info->info_length)) {
396 ext4_warning_inode(dir, "dx entry: limit %u != root limit %u",
397 dx_get_limit(entries),
398 - dx_root_limit(dir, info->info_length));
400 + (struct ext4_dir_entry_2 *)frame->bh->b_data,
401 + info->info_length));
405 @@ -1798,7 +1810,7 @@
407 struct ext4_dir_entry_2 *de = (struct ext4_dir_entry_2 *)
408 (from + (map->offs<<2));
409 - rec_len = EXT4_DIR_REC_LEN(de->name_len);
410 + rec_len = EXT4_DIR_ENTRY_LEN(de);
411 memcpy (to, de, rec_len);
412 ((struct ext4_dir_entry_2 *) to)->rec_len =
413 ext4_rec_len_to_disk(rec_len, blocksize);
414 @@ -1822,7 +1834,7 @@
415 while ((char*)de < base + blocksize) {
416 next = ext4_next_entry(de, blocksize);
417 if (de->inode && de->name_len) {
418 - rec_len = EXT4_DIR_REC_LEN(de->name_len);
419 + rec_len = EXT4_DIR_ENTRY_LEN(de);
421 memmove(to, de, rec_len);
422 to->rec_len = ext4_rec_len_to_disk(rec_len, blocksize);
423 @@ -1959,14 +1971,16 @@
424 struct buffer_head *bh,
425 void *buf, int buf_size,
426 struct ext4_filename *fname,
427 - struct ext4_dir_entry_2 **dest_de)
428 + struct ext4_dir_entry_2 **dest_de, int *dlen)
430 struct ext4_dir_entry_2 *de;
431 - unsigned short reclen = EXT4_DIR_REC_LEN(fname_len(fname));
432 + unsigned short reclen = EXT4_DIR_REC_LEN(fname_len(fname)) +
433 + (dlen ? *dlen : 0);
435 unsigned int offset = 0;
438 + dlen ? *dlen = 0 : 0; /* default set to 0 */
439 de = (struct ext4_dir_entry_2 *)buf;
440 top = buf + buf_size - reclen;
441 while ((char *) de <= top) {
442 @@ -1975,10 +1989,26 @@
443 return -EFSCORRUPTED;
444 if (ext4_match(dir, fname, de))
446 - nlen = EXT4_DIR_REC_LEN(de->name_len);
447 + nlen = EXT4_DIR_ENTRY_LEN(de);
448 rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
449 if ((de->inode ? rlen - nlen : rlen) >= reclen)
451 + /* Then for dotdot entries, check for the smaller space
452 + * required for just the entry, no FID */
453 + if (fname_len(fname) == 2 && memcmp(fname_name(fname), "..", 2) == 0) {
454 + if ((de->inode ? rlen - nlen : rlen) >=
455 + EXT4_DIR_REC_LEN(fname_len(fname))) {
456 + /* set dlen=1 to indicate not
457 + * enough space store fid */
458 + dlen ? *dlen = 1 : 0;
461 + /* The new ".." entry must be written over the
462 + * previous ".." entry, which is the first
463 + * entry traversed by this scan. If it doesn't
464 + * fit, something is badly wrong, so -EIO. */
467 de = (struct ext4_dir_entry_2 *)((char *)de + rlen);
470 @@ -1992,12 +2022,12 @@
471 void ext4_insert_dentry(struct inode *inode,
472 struct ext4_dir_entry_2 *de,
474 - struct ext4_filename *fname)
475 + struct ext4_filename *fname, void *data)
480 - nlen = EXT4_DIR_REC_LEN(de->name_len);
481 + nlen = EXT4_DIR_ENTRY_LEN(de);
482 rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
484 struct ext4_dir_entry_2 *de1 =
485 @@ -2011,6 +2041,11 @@
486 ext4_set_de_type(inode->i_sb, de, inode->i_mode);
487 de->name_len = fname_len(fname);
488 memcpy(de->name, fname_name(fname), fname_len(fname));
490 + de->name[fname_len(fname)] = 0;
491 + memcpy(&de->name[fname_len(fname) + 1], data, *(char *)data);
492 + de->file_type |= EXT4_DIRENT_LUFID;
497 @@ -2028,14 +2063,19 @@
499 unsigned int blocksize = dir->i_sb->s_blocksize;
502 + int err, err2, dlen = 0;
503 + unsigned char *data;
505 + data = ext4_dentry_get_data(inode->i_sb, (struct ext4_dentry_param *)
506 + EXT4_I(inode)->i_dirdata);
507 if (ext4_has_metadata_csum(inode->i_sb))
508 csum_size = sizeof(struct ext4_dir_entry_tail);
512 + dlen = (*data) + 1;
513 err = ext4_find_dest_de(dir, inode, bh, bh->b_data,
514 - blocksize - csum_size, fname, &de);
515 + blocksize - csum_size, fname, &de, &dlen);
519 @@ -2047,7 +2087,10 @@
522 /* By now the buffer is marked for journaling */
523 - ext4_insert_dentry(inode, de, blocksize, fname);
524 + /* If writing the short form of "dotdot", don't add the data section */
527 + ext4_insert_dentry(inode, de, blocksize, fname, data);
530 * XXX shouldn't update any times until successful
531 @@ -2152,7 +2195,8 @@
533 dx_set_block(entries, 1);
534 dx_set_count(entries, 1);
535 - dx_set_limit(entries, dx_root_limit(dir, sizeof(*dx_info)));
536 + dx_set_limit(entries, dx_root_limit(dir,
537 + dot_de, sizeof(*dx_info)));
539 /* Initialize as for dx_probe */
540 fname->hinfo.hash_version = dx_info->hash_version;
541 @@ -2202,6 +2246,8 @@
542 struct buffer_head *dir_block;
543 struct ext4_dir_entry_2 *de;
544 int len, journal = 0, err = 0;
549 return PTR_ERR(handle);
550 @@ -2227,11 +2273,16 @@
554 - de->rec_len = cpu_to_le16(EXT4_DIR_REC_LEN(1));
555 + de->rec_len = cpu_to_le16(EXT4_DIR_ENTRY_LEN(de));
558 - len -= EXT4_DIR_REC_LEN(1);
559 - assert(len == 0 || len >= EXT4_DIR_REC_LEN(2));
560 + len -= EXT4_DIR_ENTRY_LEN(de);
561 + data = ext4_dentry_get_data(dir->i_sb,
562 + (struct ext4_dentry_param *)dentry->d_fsdata);
565 + assert(len == 0 || len >= EXT4_DIR_REC_LEN(2 + dlen));
567 de = (struct ext4_dir_entry_2 *)
568 ((char *) de + le16_to_cpu(de->rec_len));
570 @@ -2248,7 +2299,12 @@
571 assert(le16_to_cpu(de->rec_len) >= EXT4_DIR_REC_LEN(2));
573 strcpy(de->name, "..");
574 - ext4_set_de_type(dir->i_sb, de, S_IFDIR);
575 + if (data != NULL && ext4_get_dirent_data_len(de) >= dlen) {
577 + memcpy(&de->name[2 + 1], data, *data);
578 + ext4_set_de_type(dir->i_sb, de, S_IFDIR);
579 + de->file_type |= EXT4_DIRENT_LUFID;
584 @@ -2286,6 +2342,7 @@
585 ext4_lblk_t block, blocks;
588 + EXT4_I(inode)->i_dirdata = dentry->d_fsdata;
589 if (ext4_has_metadata_csum(inode->i_sb))
590 csum_size = sizeof(struct ext4_dir_entry_tail);
592 @@ -2839,37 +2896,70 @@
597 + struct inode *inode;
602 struct ext4_dir_entry_2 *ext4_init_dot_dotdot(struct inode *inode,
603 struct ext4_dir_entry_2 *de,
604 int blocksize, int csum_size,
605 unsigned int parent_ino, int dotdot_real_len)
607 + void *data1 = NULL, *data2 = NULL;
608 + int dot_reclen = 0;
610 + if (dotdot_real_len == 10) {
611 + struct tp_block *tpb = (struct tp_block *)inode;
612 + data1 = tpb->data1;
613 + data2 = tpb->data2;
614 + inode = tpb->inode;
615 + dotdot_real_len = 0;
617 de->inode = cpu_to_le32(inode->i_ino);
619 - de->rec_len = ext4_rec_len_to_disk(EXT4_DIR_REC_LEN(de->name_len),
621 strcpy(de->name, ".");
622 ext4_set_de_type(inode->i_sb, de, S_IFDIR);
624 + /* get packed fid data*/
625 + data1 = ext4_dentry_get_data(inode->i_sb,
626 + (struct ext4_dentry_param *) data1);
629 + memcpy(&de->name[2], data1, *(char *) data1);
630 + de->file_type |= EXT4_DIRENT_LUFID;
632 + de->rec_len = cpu_to_le16(EXT4_DIR_ENTRY_LEN(de));
633 + dot_reclen = cpu_to_le16(de->rec_len);
634 de = ext4_next_entry(de, blocksize);
635 de->inode = cpu_to_le32(parent_ino);
637 + strcpy(de->name, "..");
638 + ext4_set_de_type(inode->i_sb, de, S_IFDIR);
639 + data2 = ext4_dentry_get_data(inode->i_sb,
640 + (struct ext4_dentry_param *) data2);
643 + memcpy(&de->name[3], data2, *(char *) data2);
644 + de->file_type |= EXT4_DIRENT_LUFID;
646 if (!dotdot_real_len)
647 de->rec_len = ext4_rec_len_to_disk(blocksize -
648 - (csum_size + EXT4_DIR_REC_LEN(1)),
649 + (csum_size + dot_reclen),
652 de->rec_len = ext4_rec_len_to_disk(
653 - EXT4_DIR_REC_LEN(de->name_len), blocksize);
654 - strcpy(de->name, "..");
655 - ext4_set_de_type(inode->i_sb, de, S_IFDIR);
656 + EXT4_DIR_ENTRY_LEN(de), blocksize);
658 return ext4_next_entry(de, blocksize);
661 int ext4_init_new_dir(handle_t *handle, struct inode *dir,
662 - struct inode *inode)
663 + struct inode *inode,
664 + const void *data1, const void *data2)
666 + struct tp_block param;
667 struct buffer_head *dir_block = NULL;
668 struct ext4_dir_entry_2 *de;
669 ext4_lblk_t block = 0;
670 @@ -2893,7 +2983,11 @@
671 if (IS_ERR(dir_block))
672 return PTR_ERR(dir_block);
673 de = (struct ext4_dir_entry_2 *)dir_block->b_data;
674 - ext4_init_dot_dotdot(inode, de, blocksize, csum_size, dir->i_ino, 0);
675 + param.inode = inode;
676 + param.data1 = (void *)data1;
677 + param.data2 = (void *)data2;
678 + ext4_init_dot_dotdot((struct inode *)(¶m), de, blocksize,
679 + csum_size, dir->i_ino, 10);
682 ext4_initialize_dirent_tail(dir_block, blocksize);
683 @@ -2908,6 +3002,29 @@
687 +/* Initialize @inode as a subdirectory of @dir, and add the
688 + * "." and ".." entries into the first directory block. */
689 +int ext4_add_dot_dotdot(handle_t *handle, struct inode *dir,
690 + struct inode *inode,
691 + const void *data1, const void *data2)
695 + if (IS_ERR(handle))
696 + return PTR_ERR(handle);
698 + if (IS_DIRSYNC(dir))
699 + ext4_handle_sync(handle);
701 + inode->i_op = &ext4_dir_inode_operations;
702 + inode->i_fop = &ext4_dir_operations;
703 + rc = ext4_init_new_dir(handle, dir, inode, data1, data2);
705 + rc = ext4_mark_inode_dirty(handle, inode);
708 +EXPORT_SYMBOL(ext4_add_dot_dotdot);
710 static int ext4_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
713 @@ -2934,7 +3051,7 @@
715 inode->i_op = &ext4_dir_inode_operations;
716 inode->i_fop = &ext4_dir_operations;
717 - err = ext4_init_new_dir(handle, dir, inode);
718 + err = ext4_init_new_dir(handle, dir, inode, NULL, NULL);
720 goto out_clear_inode;
721 err = ext4_mark_inode_dirty(handle, inode);
722 diff -ur a/fs/ext4/super.c b/fs/ext4/super.c
723 --- a/fs/ext4/super.c 2021-12-14 08:28:35.614372852 -0700
724 +++ b/fs/ext4/super.c 2021-12-14 08:29:41.334242168 -0700
725 @@ -1694,7 +1694,7 @@
727 Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
728 Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, Opt_quota,
729 - Opt_noquota, Opt_barrier, Opt_nobarrier, Opt_err,
730 + Opt_noquota, Opt_barrier, Opt_nobarrier, Opt_err, Opt_dirdata,
731 Opt_usrquota, Opt_grpquota, Opt_prjquota, Opt_i_version,
732 Opt_dax, Opt_dax_always, Opt_dax_inode, Opt_dax_never,
733 Opt_stripe, Opt_delalloc, Opt_nodelalloc, Opt_warn_on_error,
734 @@ -1778,6 +1778,7 @@
735 {Opt_nolazytime, "nolazytime"},
736 {Opt_debug_want_extra_isize, "debug_want_extra_isize=%u"},
737 {Opt_nodelalloc, "nodelalloc"},
738 + {Opt_dirdata, "dirdata"},
739 {Opt_removed, "mblk_io_submit"},
740 {Opt_removed, "nomblk_io_submit"},
741 {Opt_block_validity, "block_validity"},
742 @@ -2017,6 +2018,7 @@
743 {Opt_usrjquota, 0, MOPT_Q | MOPT_STRING},
744 {Opt_grpjquota, 0, MOPT_Q | MOPT_STRING},
745 {Opt_offusrjquota, 0, MOPT_Q},
746 + {Opt_dirdata, EXT4_MOUNT_DIRDATA, MOPT_SET},
747 {Opt_offgrpjquota, 0, MOPT_Q},
748 {Opt_jqfmt_vfsold, QFMT_VFS_OLD, MOPT_QFMT},
749 {Opt_jqfmt_vfsv0, QFMT_VFS_V0, MOPT_QFMT},