Whamcloud - gitweb
5124beffaea806a460632e4169fb7286bbed17c1
[fs/lustre-release.git] / ldiskfs / kernel_patches / patches / sles11sp2 / ext4-data-in-dirent.patch
1 ---
2  fs/ext4/dir.c   |   26 +++++++++---
3  fs/ext4/ext4.h  |   70 ++++++++++++++++++++++++++++++++-
4  fs/ext4/namei.c |  117 ++++++++++++++++++++++++++++++++++++++++----------------
5  3 files changed, 170 insertions(+), 43 deletions(-)
6
7 Index: linux-stage/fs/ext4/dir.c
8 ===================================================================
9 --- linux-stage.orig/fs/ext4/dir.c
10 +++ linux-stage/fs/ext4/dir.c
11 @@ -53,11 +53,18 @@ const struct file_operations ext4_dir_op
12  
13  static unsigned char get_dtype(struct super_block *sb, int filetype)
14  {
15 +       int fl_index = filetype & EXT4_FT_MASK;
16 +
17         if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FILETYPE) ||
18 -           (filetype >= EXT4_FT_MAX))
19 +           (fl_index >= EXT4_FT_MAX))
20                 return DT_UNKNOWN;
21  
22 -       return (ext4_filetype_table[filetype]);
23 +       if (!test_opt(sb, DIRDATA))
24 +               return (ext4_filetype_table[fl_index]);
25 +
26 +       return (ext4_filetype_table[fl_index]) |
27 +               (filetype & EXT4_DIRENT_LUFID);
28 +
29  }
30  
31  /*
32 @@ -75,11 +82,11 @@ int __ext4_check_dir_entry(const char *f
33         const int rlen = ext4_rec_len_from_disk(de->rec_len,
34                                                 dir->i_sb->s_blocksize);
35  
36 -       if (unlikely(rlen < EXT4_DIR_REC_LEN(1)))
37 +       if (unlikely(rlen < __EXT4_DIR_REC_LEN(1)))
38                 error_msg = "rec_len is smaller than minimal";
39         else if (unlikely(rlen % 4 != 0))
40                 error_msg = "rec_len % 4 != 0";
41 -       else if (unlikely(rlen < EXT4_DIR_REC_LEN(de->name_len)))
42 +       else if (unlikely(rlen < EXT4_DIR_REC_LEN(de)))
43                 error_msg = "rec_len is too small for name_len";
44         else if (unlikely(((char *) de - bh->b_data) + rlen >
45                           dir->i_sb->s_blocksize))
46 @@ -196,7 +203,7 @@ revalidate:
47                                  * failure will be detected in the
48                                  * dirent test below. */
49                                 if (ext4_rec_len_from_disk(de->rec_len,
50 -                                       sb->s_blocksize) < EXT4_DIR_REC_LEN(1))
51 +                                       sb->s_blocksize) < __EXT4_DIR_REC_LEN(1))
52                                         break;
53                                 i += ext4_rec_len_from_disk(de->rec_len,
54                                                             sb->s_blocksize);
55 @@ -359,12 +366,17 @@ int ext4_htree_store_dirent(struct file
56         struct fname *fname, *new_fn;
57         struct dir_private_info *info;
58         int len;
59 +       int extra_data = 0;
60  
61         info = dir_file->private_data;
62         p = &info->root.rb_node;
63  
64         /* Create and allocate the fname structure */
65 -       len = sizeof(struct fname) + dirent->name_len + 1;
66 +       if (dirent->file_type & EXT4_DIRENT_LUFID)
67 +               extra_data = ext4_get_dirent_data_len(dirent);
68 +
69 +       len = sizeof(struct fname) + dirent->name_len + extra_data + 1;
70 +
71         new_fn = kzalloc(len, GFP_KERNEL);
72         if (!new_fn)
73                 return -ENOMEM;
74 @@ -373,7 +385,7 @@ int ext4_htree_store_dirent(struct file
75         new_fn->inode = le32_to_cpu(dirent->inode);
76         new_fn->name_len = dirent->name_len;
77         new_fn->file_type = dirent->file_type;
78 -       memcpy(new_fn->name, dirent->name, dirent->name_len);
79 +       memcpy(new_fn->name, dirent->name, dirent->name_len + extra_data);
80         new_fn->name[dirent->name_len] = 0;
81  
82         while (*p) {
83 Index: linux-stage/fs/ext4/ext4.h
84 ===================================================================
85 --- linux-stage.orig/fs/ext4/ext4.h
86 +++ linux-stage/fs/ext4/ext4.h
87 @@ -901,6 +901,7 @@ struct ext4_inode_info {
88  #define EXT4_MOUNT_ERRORS_PANIC                0x00040 /* Panic on errors */
89  #define EXT4_MOUNT_MINIX_DF            0x00080 /* Mimics the Minix statfs */
90  #define EXT4_MOUNT_NOLOAD              0x00100 /* Don't use existing journal*/
91 +#define EXT4_MOUNT_DIRDATA             0x00200 /* Data in directory entries */
92  #define EXT4_MOUNT_DATA_FLAGS          0x00C00 /* Mode for data writes: */
93  #define EXT4_MOUNT_JOURNAL_DATA                0x00400 /* Write data to journal */
94  #define EXT4_MOUNT_ORDERED_DATA                0x00800 /* Flush data before commit */
95 @@ -1411,7 +1412,9 @@ static inline void ext4_clear_state_flag
96                                          EXT4_FEATURE_INCOMPAT_EXTENTS| \
97                                          EXT4_FEATURE_INCOMPAT_64BIT| \
98                                          EXT4_FEATURE_INCOMPAT_FLEX_BG| \
99 -                                        EXT4_FEATURE_INCOMPAT_MMP)
100 +                                        EXT4_FEATURE_INCOMPAT_MMP| \
101 +                                        EXT4_FEATURE_INCOMPAT_DIRDATA)
102 +
103  #define EXT4_FEATURE_RO_COMPAT_SUPP    (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \
104                                          EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \
105                                          EXT4_FEATURE_RO_COMPAT_GDT_CSUM| \
106 @@ -1498,6 +1501,43 @@ struct ext4_dir_entry_2 {
107  #define EXT4_FT_SYMLINK                7
108  
109  #define EXT4_FT_MAX            8
110 +#define EXT4_FT_MASK           0xf
111 +
112 +#if EXT4_FT_MAX > EXT4_FT_MASK
113 +#error "conflicting EXT4_FT_MAX and EXT4_FT_MASK"
114 +#endif
115 +
116 +/*
117 + * d_type has 4 unused bits, so it can hold four types data. these different
118 + * type of data (e.g. lustre data, high 32 bits of 64-bit inode number) can be
119 + * stored, in flag order, after file-name in ext4 dirent.
120 +*/
121 +/*
122 + * this flag is added to d_type if ext4 dirent has extra data after
123 + * filename. this data length is variable and length is stored in first byte
124 + * of data. data start after filename NUL byte.
125 + * This is used by Lustre FS.
126 +  */
127 +#define EXT4_DIRENT_LUFID              0x10
128 +
129 +#define EXT4_LUFID_MAGIC    0xAD200907UL
130 +struct ext4_dentry_param {
131 +       __u32  edp_magic;       /* EXT4_LUFID_MAGIC */
132 +       char   edp_len;         /* size of edp_data in bytes */
133 +       char   edp_data[0];     /* packed array of data */
134 +} __attribute__((packed));
135 +
136 +static inline unsigned char *ext4_dentry_get_data(struct super_block *sb,
137 +               struct ext4_dentry_param* p)
138 +
139 +{
140 +       if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_DIRDATA))
141 +               return NULL;
142 +       if (p && p->edp_magic == EXT4_LUFID_MAGIC)
143 +               return &p->edp_len;
144 +       else
145 +               return NULL;
146 +}
147  
148  /*
149   * EXT4_DIR_PAD defines the directory entries boundaries
150 @@ -1506,8 +1546,11 @@ struct ext4_dir_entry_2 {
151   */
152  #define EXT4_DIR_PAD                   4
153  #define EXT4_DIR_ROUND                 (EXT4_DIR_PAD - 1)
154 -#define EXT4_DIR_REC_LEN(name_len)     (((name_len) + 8 + EXT4_DIR_ROUND) & \
155 +#define __EXT4_DIR_REC_LEN(name_len)   (((name_len) + 8 + EXT4_DIR_ROUND) & \
156                                          ~EXT4_DIR_ROUND)
157 +#define EXT4_DIR_REC_LEN(de)           (__EXT4_DIR_REC_LEN(de->name_len +\
158 +                                       ext4_get_dirent_data_len(de)))
159 +
160  #define EXT4_MAX_REC_LEN               ((1<<16)-1)
161  
162  /*
163 @@ -1899,7 +1942,7 @@ extern struct buffer_head * ext4_find_en
164                                             struct ext4_dir_entry_2 ** res_dir);
165  #define ll_ext4_find_entry(inode, dentry, res_dir) ext4_find_entry(inode, &(dentry)->d_name, res_dir)
166  extern int ext4_add_dot_dotdot(handle_t *handle, struct inode *dir,
167 -                              struct inode *inode);
168 +                              struct inode *inode, const void *, const void *);
169  extern struct buffer_head *ext4_append(handle_t *handle,
170                                        struct inode *inode,
171                                        ext4_lblk_t *block, int *err);
172 @@ -2299,6 +2342,28 @@ static inline void set_bitmap_uptodate(s
173  extern wait_queue_head_t ext4__ioend_wq[EXT4_WQ_HASH_SZ];
174  extern struct mutex ext4__aio_mutex[EXT4_WQ_HASH_SZ];
175  
176 +/*
177 + * Compute the total directory entry data length.
178 + * This includes the filename and an implicit NUL terminator (always present),
179 + * and optional extensions.  Each extension has a bit set in the high 4 bits of
180 + * de->file_type, and the extension length is the first byte in each entry.
181 + */
182 +static inline int ext4_get_dirent_data_len(struct ext4_dir_entry_2 *de)
183 +{
184 +       char *len = de->name + de->name_len + 1 /* NUL terminator */;
185 +       int dlen = 0;
186 +       __u8 extra_data_flags = (de->file_type & ~EXT4_FT_MASK) >> 4;
187 +
188 +       while (extra_data_flags) {
189 +               if (extra_data_flags & 1) {
190 +                       dlen += *len + (dlen == 0);
191 +                       len += *len;
192 +               }
193 +               extra_data_flags >>= 1;
194 +       }
195 +       return dlen;
196 +}
197 +
198  #endif /* __KERNEL__ */
199  
200  #endif /* _EXT4_H */
201 Index: linux-stage/fs/ext4/namei.c
202 ===================================================================
203 --- linux-stage.orig/fs/ext4/namei.c
204 +++ linux-stage/fs/ext4/namei.c
205 @@ -170,7 +170,8 @@ static unsigned dx_get_count(struct dx_e
206  static unsigned dx_get_limit(struct dx_entry *entries);
207  static void dx_set_count(struct dx_entry *entries, unsigned value);
208  static void dx_set_limit(struct dx_entry *entries, unsigned value);
209 -static unsigned dx_root_limit(struct inode *dir, unsigned infosize);
210 +static inline unsigned dx_root_limit(__u32 blocksize,
211 +               struct ext4_dir_entry_2 *dot_de, unsigned infosize);
212  static unsigned dx_node_limit(struct inode *dir);
213  static struct dx_frame *dx_probe(const struct qstr *d_name,
214                                  struct inode *dir,
215 @@ -213,11 +214,12 @@ ext4_next_entry(struct ext4_dir_entry_2
216   */
217  struct dx_root_info * dx_get_dx_info(struct ext4_dir_entry_2 *de)
218  {
219 -       /* get dotdot first */
220 -       de = (struct ext4_dir_entry_2 *)((char *)de + EXT4_DIR_REC_LEN(1));
221 +       BUG_ON(de->name_len != 1);
222 +       /* get dotdot first */
223 +       de = (struct ext4_dir_entry_2 *)((char *)de + EXT4_DIR_REC_LEN(de));
224  
225 -       /* dx root info is after dotdot entry */
226 -       de = (struct ext4_dir_entry_2 *)((char *)de + EXT4_DIR_REC_LEN(2));
227 +       /* dx root info is after dotdot entry */
228 +       de = (struct ext4_dir_entry_2 *)((char *)de + EXT4_DIR_REC_LEN(de));
229  
230         return (struct dx_root_info *) de;
231  }
232 @@ -262,16 +264,23 @@ static inline void dx_set_limit(struct d
233         ((struct dx_countlimit *) entries)->limit = cpu_to_le16(value);
234  }
235  
236 -static inline unsigned dx_root_limit(struct inode *dir, unsigned infosize)
237 +static inline unsigned dx_root_limit(__u32 blocksize,
238 +               struct ext4_dir_entry_2 *dot_de, unsigned infosize)
239  {
240 -       unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(1) -
241 -               EXT4_DIR_REC_LEN(2) - infosize;
242 +       struct ext4_dir_entry_2 *dotdot_de;
243 +       unsigned entry_space;
244 +
245 +       BUG_ON(dot_de->name_len != 1);
246 +       dotdot_de = ext4_next_entry(dot_de, blocksize);
247 +       entry_space = blocksize - EXT4_DIR_REC_LEN(dot_de) -
248 +                        EXT4_DIR_REC_LEN(dotdot_de) - infosize;
249 +
250         return entry_space / sizeof(struct dx_entry);
251  }
252  
253  static inline unsigned dx_node_limit(struct inode *dir)
254  {
255 -       unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(0);
256 +       unsigned entry_space = dir->i_sb->s_blocksize - __EXT4_DIR_REC_LEN(0);
257         return entry_space / sizeof(struct dx_entry);
258  }
259  
260 @@ -318,7 +327,7 @@ static struct stats dx_show_leaf(struct
261                                 printk(":%x.%u ", h.hash,
262                                        ((char *) de - base));
263                         }
264 -                       space += EXT4_DIR_REC_LEN(de->name_len);
265 +                       space += EXT4_DIR_REC_LEN(de);
266                         names++;
267                 }
268                 de = ext4_next_entry(de, size);
269 @@ -420,7 +429,8 @@ dx_probe(const struct qstr *d_name, stru
270  
271         entries = (struct dx_entry *) (((char *)info) + info->info_length);
272  
273 -       if (dx_get_limit(entries) != dx_root_limit(dir,
274 +       if (dx_get_limit(entries) != dx_root_limit(dir->i_sb->s_blocksize,
275 +                                                  (struct ext4_dir_entry_2*)bh->b_data,
276                                                    info->info_length)) {
277                 ext4_warning(dir->i_sb, "dx entry: limit != root limit");
278                 brelse(bh);
279 @@ -609,7 +619,7 @@ static int htree_dirblock_to_tree(struct
280         de = (struct ext4_dir_entry_2 *) bh->b_data;
281         top = (struct ext4_dir_entry_2 *) ((char *) de +
282                                            dir->i_sb->s_blocksize -
283 -                                          EXT4_DIR_REC_LEN(0));
284 +                                          __EXT4_DIR_REC_LEN(0));
285         for (; de < top; de = ext4_next_entry(de, dir->i_sb->s_blocksize)) {
286                 if (ext4_check_dir_entry(dir, NULL, de, bh,
287                                 (block<<EXT4_BLOCK_SIZE_BITS(dir->i_sb))
288 @@ -1179,7 +1189,7 @@ dx_move_dirents(char *from, char *to, st
289         while (count--) {
290                 struct ext4_dir_entry_2 *de = (struct ext4_dir_entry_2 *)
291                                                 (from + (map->offs<<2));
292 -               rec_len = EXT4_DIR_REC_LEN(de->name_len);
293 +               rec_len = EXT4_DIR_REC_LEN(de);
294                 memcpy (to, de, rec_len);
295                 ((struct ext4_dir_entry_2 *) to)->rec_len =
296                                 ext4_rec_len_to_disk(rec_len, blocksize);
297 @@ -1203,7 +1213,7 @@ static struct ext4_dir_entry_2* dx_pack_
298         while ((char*)de < base + blocksize) {
299                 next = ext4_next_entry(de, blocksize);
300                 if (de->inode && de->name_len) {
301 -                       rec_len = EXT4_DIR_REC_LEN(de->name_len);
302 +                       rec_len = EXT4_DIR_REC_LEN(de);
303                         if (de > to)
304                                 memmove(to, de, rec_len);
305                         to->rec_len = ext4_rec_len_to_disk(rec_len, blocksize);
306 @@ -1332,11 +1342,28 @@ static int add_dirent_to_buf(handle_t *h
307         int             namelen = dentry->d_name.len;
308         unsigned int    offset = 0;
309         unsigned int    blocksize = dir->i_sb->s_blocksize;
310 -       unsigned short  reclen;
311 -       int             nlen, rlen, err;
312 +       unsigned short  reclen, dotdot_reclen = 0;
313 +       int             nlen, rlen, err, dlen = 0;
314 +       int             is_dotdot = 0, write_short_dotdot = 0;
315 +       unsigned char   *data;
316         char            *top;
317  
318 -       reclen = EXT4_DIR_REC_LEN(namelen);
319 +       data = ext4_dentry_get_data(inode->i_sb, (struct ext4_dentry_param *)
320 +                                               dentry->d_fsdata);
321 +       if (data)
322 +               dlen = (*data) + 1;
323 +
324 +       is_dotdot = (dentry->d_name.len == 2 &&
325 +                    memcmp(dentry->d_name.name, "..", 2) == 0);
326 +
327 +       /* dotdot entries must be in the second place in a directory block,
328 +        * so calculate an alternate length without the FID so they can
329 +        * always be made to fit in the existing slot - LU-5626 */
330 +       if (is_dotdot)
331 +               dotdot_reclen = __EXT4_DIR_REC_LEN(namelen);
332 +
333 +       reclen = __EXT4_DIR_REC_LEN(namelen + dlen);
334 +
335         if (!de) {
336                 de = (struct ext4_dir_entry_2 *)bh->b_data;
337                 top = bh->b_data + blocksize - reclen;
338 @@ -1345,10 +1372,25 @@ static int add_dirent_to_buf(handle_t *h
339                                 return -EIO;
340                         if (ext4_match(namelen, name, de))
341                                 return -EEXIST;
342 -                       nlen = EXT4_DIR_REC_LEN(de->name_len);
343 +                       nlen = EXT4_DIR_REC_LEN(de);
344                         rlen = ext4_rec_len_from_disk(de->rec_len, blocksize);
345 -                       if ((de->inode? rlen - nlen: rlen) >= reclen)
346 +                       /* Check first for enough space for the full entry */
347 +                       if ((de->inode ? rlen - nlen : rlen) >= reclen)
348                                 break;
349 +                       /* Then for dotdot entries, check for the smaller space
350 +                        * required for just the entry, no FID */
351 +                       if (is_dotdot) {
352 +                               if ((de->inode ? rlen - nlen : rlen) >=
353 +                                   dotdot_reclen) {
354 +                                       write_short_dotdot = true;
355 +                                       break;
356 +                               }
357 +                               /* The new ".." entry mut be written over the
358 +                                * previous ".." entry, which is the first
359 +                                * entry traversed by this scan.  If it doesn't
360 +                                * fit, something is badly wrong, so -EIO. */
361 +                               return -EIO;
362 +                       }
363                         de = (struct ext4_dir_entry_2 *)((char *)de + rlen);
364                         offset += rlen;
365                 }
366 @@ -1363,7 +1405,7 @@ static int add_dirent_to_buf(handle_t *h
367         }
368  
369         /* By now the buffer is marked for journaling */
370 -       nlen = EXT4_DIR_REC_LEN(de->name_len);
371 +       nlen = EXT4_DIR_REC_LEN(de);
372         rlen = ext4_rec_len_from_disk(de->rec_len, blocksize);
373         if (de->inode) {
374                 struct ext4_dir_entry_2 *de1 = (struct ext4_dir_entry_2 *)((char *)de + nlen);
375 @@ -1379,6 +1421,13 @@ static int add_dirent_to_buf(handle_t *h
376                 de->inode = 0;
377         de->name_len = namelen;
378         memcpy(de->name, name, namelen);
379 +       /* If we're writing the short form of "dotdot", don't add the data section */
380 +       if (data && !write_short_dotdot) {
381 +               de->name[namelen] = 0;
382 +               memcpy(&de->name[namelen + 1], data, *(char *) data);
383 +               de->file_type |= EXT4_DIRENT_LUFID;
384 +       }
385 +
386         /*
387          * XXX shouldn't update any times until successful
388          * completion of syscall, but too many callers depend
389 @@ -1475,7 +1524,8 @@ static int make_indexed_dir(handle_t *ha
390  
391         dx_set_block(entries, 1);
392         dx_set_count(entries, 1);
393 -       dx_set_limit(entries, dx_root_limit(dir, sizeof(*dx_info)));
394 +       dx_set_limit(entries, dx_root_limit(dir->i_sb->s_blocksize,
395 +                                        dot_de, sizeof(*dx_info)));
396  
397         /* Initialize as for dx_probe */
398         hinfo.hash_version = dx_info->hash_version;
399 @@ -1518,6 +1568,8 @@ static int ext4_update_dotdot(handle_t *
400         struct buffer_head * dir_block;
401         struct ext4_dir_entry_2 * de;
402         int len, journal = 0, err = 0;
403 +       int dlen = 0;
404 +       char *data;
405  
406         if (IS_ERR(handle))
407                 return PTR_ERR(handle);
408 @@ -1533,19 +1585,24 @@ static int ext4_update_dotdot(handle_t *
409         /* the first item must be "." */
410         assert(de->name_len == 1 && de->name[0] == '.');
411         len = le16_to_cpu(de->rec_len);
412 -       assert(len >= EXT4_DIR_REC_LEN(1));
413 -       if (len > EXT4_DIR_REC_LEN(1)) {
414 +       assert(len >= __EXT4_DIR_REC_LEN(1));
415 +       if (len > __EXT4_DIR_REC_LEN(1)) {
416                 BUFFER_TRACE(dir_block, "get_write_access");
417                 err = ext4_journal_get_write_access(handle, dir_block);
418                 if (err)
419                         goto out_journal;
420  
421                 journal = 1;
422 -               de->rec_len = cpu_to_le16(EXT4_DIR_REC_LEN(1));
423 +               de->rec_len = cpu_to_le16(EXT4_DIR_REC_LEN(de));
424         }
425  
426 -       len -= EXT4_DIR_REC_LEN(1);
427 -       assert(len == 0 || len >= EXT4_DIR_REC_LEN(2));
428 +       len -= EXT4_DIR_REC_LEN(de);
429 +       data = ext4_dentry_get_data(dir->i_sb,
430 +                       (struct ext4_dentry_param *) dentry->d_fsdata);
431 +       if (data)
432 +               dlen = *data + 1;
433 +       assert(len == 0 || len >= __EXT4_DIR_REC_LEN(2 + dlen));
434 +
435         de = (struct ext4_dir_entry_2 *)
436                         ((char *) de + le16_to_cpu(de->rec_len));
437         if (!journal) {
438 @@ -1559,10 +1616,15 @@ static int ext4_update_dotdot(handle_t *
439         if (len > 0)
440                 de->rec_len = cpu_to_le16(len);
441         else
442 -               assert(le16_to_cpu(de->rec_len) >= EXT4_DIR_REC_LEN(2));
443 +               assert(le16_to_cpu(de->rec_len) >= __EXT4_DIR_REC_LEN(2));
444         de->name_len = 2;
445         strcpy (de->name, "..");
446 -       ext4_set_de_type(dir->i_sb, de, S_IFDIR);
447 +       if (data != NULL && ext4_get_dirent_data_len(de) >= dlen) {
448 +               de->name[2] = 0;
449 +               memcpy(&de->name[2 + 1], data, *data);
450 +               ext4_set_de_type(dir->i_sb, de, S_IFDIR);
451 +               de->file_type |= EXT4_DIRENT_LUFID;
452 +       }
453  
454  out_journal:
455         if (journal) {
456 @@ -2003,12 +2065,13 @@ retry:
457  /* Initialize @inode as a subdirectory of @dir, and add the
458   * "." and ".." entries into the first directory block. */
459  int ext4_add_dot_dotdot(handle_t *handle, struct inode * dir,
460 -                       struct inode *inode)
461 +                       struct inode *inode,
462 +                       const void *data1, const void *data2)
463  {
464         struct buffer_head *dir_block;
465         struct ext4_dir_entry_2 *de;
466         unsigned int blocksize = dir->i_sb->s_blocksize;
467 -       int err = 0;
468 +       int err = 0, dot_reclen;
469  
470         if (IS_ERR(handle))
471                 return PTR_ERR(handle);
472 @@ -2029,17 +2092,32 @@ int ext4_add_dot_dotdot(handle_t *handle
473         de = (struct ext4_dir_entry_2 *) dir_block->b_data;
474         de->inode = cpu_to_le32(inode->i_ino);
475         de->name_len = 1;
476 -       de->rec_len = ext4_rec_len_to_disk(EXT4_DIR_REC_LEN(de->name_len),
477 -                                          blocksize);
478         strcpy(de->name, ".");
479         ext4_set_de_type(dir->i_sb, de, S_IFDIR);
480 +       /* get packed fid data */
481 +       data1 = ext4_dentry_get_data(dir->i_sb,
482 +                               (struct ext4_dentry_param *) data1);
483 +       if (data1) {
484 +               de->name[1] = 0;
485 +               memcpy(&de->name[2], data1, *(char *) data1);
486 +               de->file_type |= EXT4_DIRENT_LUFID;
487 +       }
488 +       de->rec_len = cpu_to_le16(EXT4_DIR_REC_LEN(de));
489 +       dot_reclen = cpu_to_le16(de->rec_len);
490         de = ext4_next_entry(de, blocksize);
491         de->inode = cpu_to_le32(dir->i_ino);
492 -       de->rec_len = ext4_rec_len_to_disk(blocksize - EXT4_DIR_REC_LEN(1),
493 +       de->rec_len = ext4_rec_len_to_disk(blocksize - dot_reclen,
494                                            blocksize);
495         de->name_len = 2;
496         strcpy(de->name, "..");
497         ext4_set_de_type(dir->i_sb, de, S_IFDIR);
498 +       data2 = ext4_dentry_get_data(dir->i_sb,
499 +                       (struct ext4_dentry_param *) data2);
500 +       if (data2) {
501 +               de->name[2] = 0;
502 +               memcpy(&de->name[3], data2, *(char *) data2);
503 +               de->file_type |= EXT4_DIRENT_LUFID;
504 +       }
505         inode->i_nlink = 2;
506         BUFFER_TRACE(dir_block, "call ext4_handle_dirty_metadata");
507         err = ext4_handle_dirty_metadata(handle, inode, dir_block);
508 @@ -2079,7 +2157,7 @@ retry:
509         if (IS_ERR(inode))
510                 goto out_stop;
511  
512 -       err = ext4_add_dot_dotdot(handle, dir, inode);
513 +       err = ext4_add_dot_dotdot(handle, dir, inode, NULL, NULL);
514         if (err)
515                 goto out_clear_inode;
516         err = ext4_add_entry(handle, dentry, inode);
517 @@ -2117,7 +2195,7 @@ static int empty_dir(struct inode *inode
518         int err = 0;
519  
520         sb = inode->i_sb;
521 -       if (inode->i_size < EXT4_DIR_REC_LEN(1) + EXT4_DIR_REC_LEN(2) ||
522 +       if (inode->i_size < __EXT4_DIR_REC_LEN(1) + __EXT4_DIR_REC_LEN(2) ||
523             !(bh = ext4_bread(NULL, inode, 0, 0, &err))) {
524                 if (err)
525                         EXT4_ERROR_INODE(inode,
526 Index: linux-stage/fs/ext4/super.c
527 ===================================================================
528 --- linux-stage.orig/fs/ext4/super.c
529 +++ linux-stage/fs/ext4/super.c
530 @@ -1363,7 +1363,7 @@ enum {
531         Opt_data_err_abort, Opt_data_err_ignore,
532         Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
533         Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, Opt_quota,
534 -       Opt_iopen, Opt_noiopen, Opt_iopen_nopriv,
535 +       Opt_iopen, Opt_noiopen, Opt_iopen_nopriv, Opt_dirdata,
536         Opt_noquota, Opt_ignore, Opt_barrier, Opt_nobarrier, Opt_err,
537         Opt_resize, Opt_usrquota, Opt_grpquota, Opt_i_version,
538         Opt_stripe, Opt_delalloc, Opt_nodelalloc, Opt_mblk_io_submit,
539 @@ -1427,6 +1427,7 @@ static const match_table_t tokens = {
540         {Opt_iopen, "iopen"},
541         {Opt_noiopen, "noiopen"},
542         {Opt_iopen_nopriv, "iopen_nopriv"},
543 +       {Opt_dirdata, "dirdata"},
544         {Opt_barrier, "barrier=%u"},
545         {Opt_barrier, "barrier"},
546         {Opt_nobarrier, "nobarrier"},
547 @@ -1840,6 +1841,9 @@ set_qf_format:
548                 case Opt_noiopen:
549                 case Opt_iopen_nopriv:
550                         break;
551 +               case Opt_dirdata:
552 +                       set_opt(sb, DIRDATA);
553 +                       break;
554                 case Opt_ignore:
555                         break;
556                 case Opt_resize: