Merge tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso...
[sfrench/cifs-2.6.git] / fs / ext4 / namei.c
index a37a19fabee4ee61a60cab592d4bb3e78d4d2f51..e8100a9a22fe1d05853e4d2c318788637315afb0 100644 (file)
@@ -280,9 +280,11 @@ static int dx_make_map(struct inode *dir, struct ext4_dir_entry_2 *de,
                       unsigned blocksize, struct dx_hash_info *hinfo,
                       struct dx_map_entry map[]);
 static void dx_sort_map(struct dx_map_entry *map, unsigned count);
-static struct ext4_dir_entry_2 *dx_move_dirents(char *from, char *to,
-               struct dx_map_entry *offsets, int count, unsigned blocksize);
-static struct ext4_dir_entry_2* dx_pack_dirents(char *base, unsigned blocksize);
+static struct ext4_dir_entry_2 *dx_move_dirents(struct inode *dir, char *from,
+                                       char *to, struct dx_map_entry *offsets,
+                                       int count, unsigned int blocksize);
+static struct ext4_dir_entry_2 *dx_pack_dirents(struct inode *dir, char *base,
+                                               unsigned int blocksize);
 static void dx_insert_block(struct dx_frame *frame,
                                        u32 hash, ext4_lblk_t block);
 static int ext4_htree_next_block(struct inode *dir, __u32 hash,
@@ -574,8 +576,9 @@ static inline void dx_set_limit(struct dx_entry *entries, unsigned value)
 
 static inline unsigned dx_root_limit(struct inode *dir, unsigned infosize)
 {
-       unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(1) -
-               EXT4_DIR_REC_LEN(2) - infosize;
+       unsigned int entry_space = dir->i_sb->s_blocksize -
+                       ext4_dir_rec_len(1, NULL) -
+                       ext4_dir_rec_len(2, NULL) - infosize;
 
        if (ext4_has_metadata_csum(dir->i_sb))
                entry_space -= sizeof(struct dx_tail);
@@ -584,7 +587,8 @@ static inline unsigned dx_root_limit(struct inode *dir, unsigned infosize)
 
 static inline unsigned dx_node_limit(struct inode *dir)
 {
-       unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(0);
+       unsigned int entry_space = dir->i_sb->s_blocksize -
+                       ext4_dir_rec_len(0, dir);
 
        if (ext4_has_metadata_csum(dir->i_sb))
                entry_space -= sizeof(struct dx_tail);
@@ -673,7 +677,10 @@ static struct stats dx_show_leaf(struct inode *dir,
                                                name = fname_crypto_str.name;
                                                len = fname_crypto_str.len;
                                        }
-                                       ext4fs_dirhash(dir, de->name,
+                                       if (IS_CASEFOLDED(dir))
+                                               h.hash = EXT4_DIRENT_HASH(de);
+                                       else
+                                               ext4fs_dirhash(dir, de->name,
                                                       de->name_len, &h);
                                        printk("%*.s:(E)%x.%u ", len, name,
                                               h.hash, (unsigned) ((char *) de
@@ -689,7 +696,7 @@ static struct stats dx_show_leaf(struct inode *dir,
                                       (unsigned) ((char *) de - base));
 #endif
                        }
-                       space += EXT4_DIR_REC_LEN(de->name_len);
+                       space += ext4_dir_rec_len(de->name_len, dir);
                        names++;
                }
                de = ext4_next_entry(de, size);
@@ -784,18 +791,34 @@ dx_probe(struct ext4_filename *fname, struct inode *dir,
        root = (struct dx_root *) frame->bh->b_data;
        if (root->info.hash_version != DX_HASH_TEA &&
            root->info.hash_version != DX_HASH_HALF_MD4 &&
-           root->info.hash_version != DX_HASH_LEGACY) {
+           root->info.hash_version != DX_HASH_LEGACY &&
+           root->info.hash_version != DX_HASH_SIPHASH) {
                ext4_warning_inode(dir, "Unrecognised inode hash code %u",
                                   root->info.hash_version);
                goto fail;
        }
+       if (ext4_hash_in_dirent(dir)) {
+               if (root->info.hash_version != DX_HASH_SIPHASH) {
+                       ext4_warning_inode(dir,
+                               "Hash in dirent, but hash is not SIPHASH");
+                       goto fail;
+               }
+       } else {
+               if (root->info.hash_version == DX_HASH_SIPHASH) {
+                       ext4_warning_inode(dir,
+                               "Hash code is SIPHASH, but hash not in dirent");
+                       goto fail;
+               }
+       }
        if (fname)
                hinfo = &fname->hinfo;
        hinfo->hash_version = root->info.hash_version;
        if (hinfo->hash_version <= DX_HASH_TEA)
                hinfo->hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned;
        hinfo->seed = EXT4_SB(dir->i_sb)->s_hash_seed;
-       if (fname && fname_name(fname))
+       /* hash is already computed for encrypted casefolded directory */
+       if (fname && fname_name(fname) &&
+                               !(IS_ENCRYPTED(dir) && IS_CASEFOLDED(dir)))
                ext4fs_dirhash(dir, fname_name(fname), fname_len(fname), hinfo);
        hash = hinfo->hash;
 
@@ -956,7 +979,7 @@ static int ext4_htree_next_block(struct inode *dir, __u32 hash,
         * If the hash is 1, then continue only if the next page has a
         * continuation hash of any value.  This is used for readdir
         * handling.  Otherwise, check to see if the hash matches the
-        * desired contiuation hash.  If it doesn't, return since
+        * desired continuation hash.  If it doesn't, return since
         * there's no point to read in the successive index pages.
         */
        bhash = dx_get_hash(p->at);
@@ -997,6 +1020,7 @@ static int htree_dirblock_to_tree(struct file *dir_file,
        struct ext4_dir_entry_2 *de, *top;
        int err = 0, count = 0;
        struct fscrypt_str fname_crypto_str = FSTR_INIT(NULL, 0), tmp_str;
+       int csum = ext4_has_metadata_csum(dir->i_sb);
 
        dxtrace(printk(KERN_INFO "In htree dirblock_to_tree: block %lu\n",
                                                        (unsigned long)block));
@@ -1005,9 +1029,11 @@ static int htree_dirblock_to_tree(struct file *dir_file,
                return PTR_ERR(bh);
 
        de = (struct ext4_dir_entry_2 *) bh->b_data;
+       /* csum entries are not larger in the casefolded encrypted case */
        top = (struct ext4_dir_entry_2 *) ((char *) de +
                                           dir->i_sb->s_blocksize -
-                                          EXT4_DIR_REC_LEN(0));
+                                          ext4_dir_rec_len(0,
+                                                          csum ? NULL : dir));
        /* Check if the directory is encrypted */
        if (IS_ENCRYPTED(dir)) {
                err = fscrypt_prepare_readdir(dir);
@@ -1031,7 +1057,17 @@ static int htree_dirblock_to_tree(struct file *dir_file,
                        /* silently ignore the rest of the block */
                        break;
                }
-               ext4fs_dirhash(dir, de->name, de->name_len, hinfo);
+               if (ext4_hash_in_dirent(dir)) {
+                       if (de->name_len && de->inode) {
+                               hinfo->hash = EXT4_DIRENT_HASH(de);
+                               hinfo->minor_hash = EXT4_DIRENT_MINOR_HASH(de);
+                       } else {
+                               hinfo->hash = 0;
+                               hinfo->minor_hash = 0;
+                       }
+               } else {
+                       ext4fs_dirhash(dir, de->name, de->name_len, hinfo);
+               }
                if ((hinfo->hash < start_hash) ||
                    ((hinfo->hash == start_hash) &&
                     (hinfo->minor_hash < start_minor_hash)))
@@ -1100,7 +1136,11 @@ int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
                       start_hash, start_minor_hash));
        dir = file_inode(dir_file);
        if (!(ext4_test_inode_flag(dir, EXT4_INODE_INDEX))) {
-               hinfo.hash_version = EXT4_SB(dir->i_sb)->s_def_hash_version;
+               if (ext4_hash_in_dirent(dir))
+                       hinfo.hash_version = DX_HASH_SIPHASH;
+               else
+                       hinfo.hash_version =
+                                       EXT4_SB(dir->i_sb)->s_def_hash_version;
                if (hinfo.hash_version <= DX_HASH_TEA)
                        hinfo.hash_version +=
                                EXT4_SB(dir->i_sb)->s_hash_unsigned;
@@ -1218,7 +1258,10 @@ static int dx_make_map(struct inode *dir, struct ext4_dir_entry_2 *de,
 
        while ((char *) de < base + blocksize) {
                if (de->name_len && de->inode) {
-                       ext4fs_dirhash(dir, de->name, de->name_len, &h);
+                       if (ext4_hash_in_dirent(dir))
+                               h.hash = EXT4_DIRENT_HASH(de);
+                       else
+                               ext4fs_dirhash(dir, de->name, de->name_len, &h);
                        map_tail--;
                        map_tail->hash = h.hash;
                        map_tail->offs = ((char *) de - base)>>2;
@@ -1282,47 +1325,65 @@ static void dx_insert_block(struct dx_frame *frame, u32 hash, ext4_lblk_t block)
  * Returns: 0 if the directory entry matches, more than 0 if it
  * doesn't match or less than zero on error.
  */
-int ext4_ci_compare(const struct inode *parent, const struct qstr *name,
-                   const struct qstr *entry, bool quick)
+static int ext4_ci_compare(const struct inode *parent, const struct qstr *name,
+                          u8 *de_name, size_t de_name_len, bool quick)
 {
        const struct super_block *sb = parent->i_sb;
        const struct unicode_map *um = sb->s_encoding;
+       struct fscrypt_str decrypted_name = FSTR_INIT(NULL, de_name_len);
+       struct qstr entry = QSTR_INIT(de_name, de_name_len);
        int ret;
 
+       if (IS_ENCRYPTED(parent)) {
+               const struct fscrypt_str encrypted_name =
+                               FSTR_INIT(de_name, de_name_len);
+
+               decrypted_name.name = kmalloc(de_name_len, GFP_KERNEL);
+               if (!decrypted_name.name)
+                       return -ENOMEM;
+               ret = fscrypt_fname_disk_to_usr(parent, 0, 0, &encrypted_name,
+                                               &decrypted_name);
+               if (ret < 0)
+                       goto out;
+               entry.name = decrypted_name.name;
+               entry.len = decrypted_name.len;
+       }
+
        if (quick)
-               ret = utf8_strncasecmp_folded(um, name, entry);
+               ret = utf8_strncasecmp_folded(um, name, &entry);
        else
-               ret = utf8_strncasecmp(um, name, entry);
-
+               ret = utf8_strncasecmp(um, name, &entry);
        if (ret < 0) {
                /* Handle invalid character sequence as either an error
                 * or as an opaque byte sequence.
                 */
                if (sb_has_strict_encoding(sb))
-                       return -EINVAL;
-
-               if (name->len != entry->len)
-                       return 1;
-
-               return !!memcmp(name->name, entry->name, name->len);
+                       ret = -EINVAL;
+               else if (name->len != entry.len)
+                       ret = 1;
+               else
+                       ret = !!memcmp(name->name, entry.name, entry.len);
        }
-
+out:
+       kfree(decrypted_name.name);
        return ret;
 }
 
-void ext4_fname_setup_ci_filename(struct inode *dir, const struct qstr *iname,
-                                 struct fscrypt_str *cf_name)
+int ext4_fname_setup_ci_filename(struct inode *dir, const struct qstr *iname,
+                                 struct ext4_filename *name)
 {
+       struct fscrypt_str *cf_name = &name->cf_name;
+       struct dx_hash_info *hinfo = &name->hinfo;
        int len;
 
        if (!IS_CASEFOLDED(dir) || !dir->i_sb->s_encoding) {
                cf_name->name = NULL;
-               return;
+               return 0;
        }
 
        cf_name->name = kmalloc(EXT4_NAME_LEN, GFP_NOFS);
        if (!cf_name->name)
-               return;
+               return -ENOMEM;
 
        len = utf8_casefold(dir->i_sb->s_encoding,
                            iname, cf_name->name,
@@ -1330,10 +1391,18 @@ void ext4_fname_setup_ci_filename(struct inode *dir, const struct qstr *iname,
        if (len <= 0) {
                kfree(cf_name->name);
                cf_name->name = NULL;
-               return;
        }
        cf_name->len = (unsigned) len;
+       if (!IS_ENCRYPTED(dir))
+               return 0;
 
+       hinfo->hash_version = DX_HASH_SIPHASH;
+       hinfo->seed = NULL;
+       if (cf_name->name)
+               ext4fs_dirhash(dir, cf_name->name, cf_name->len, hinfo);
+       else
+               ext4fs_dirhash(dir, iname->name, iname->len, hinfo);
+       return 0;
 }
 #endif
 
@@ -1342,14 +1411,11 @@ void ext4_fname_setup_ci_filename(struct inode *dir, const struct qstr *iname,
  *
  * Return: %true if the directory entry matches, otherwise %false.
  */
-static inline bool ext4_match(const struct inode *parent,
+static bool ext4_match(struct inode *parent,
                              const struct ext4_filename *fname,
-                             const struct ext4_dir_entry_2 *de)
+                             struct ext4_dir_entry_2 *de)
 {
        struct fscrypt_name f;
-#ifdef CONFIG_UNICODE
-       const struct qstr entry = {.name = de->name, .len = de->name_len};
-#endif
 
        if (!de->inode)
                return false;
@@ -1365,10 +1431,19 @@ static inline bool ext4_match(const struct inode *parent,
                if (fname->cf_name.name) {
                        struct qstr cf = {.name = fname->cf_name.name,
                                          .len = fname->cf_name.len};
-                       return !ext4_ci_compare(parent, &cf, &entry, true);
+                       if (IS_ENCRYPTED(parent)) {
+                               if (fname->hinfo.hash != EXT4_DIRENT_HASH(de) ||
+                                       fname->hinfo.minor_hash !=
+                                               EXT4_DIRENT_MINOR_HASH(de)) {
+
+                                       return 0;
+                               }
+                       }
+                       return !ext4_ci_compare(parent, &cf, de->name,
+                                                       de->name_len, true);
                }
-               return !ext4_ci_compare(parent, fname->usr_fname, &entry,
-                                       false);
+               return !ext4_ci_compare(parent, fname->usr_fname, de->name,
+                                               de->name_len, false);
        }
 #endif
 
@@ -1765,7 +1840,8 @@ struct dentry *ext4_get_parent(struct dentry *child)
  * Returns pointer to last entry moved.
  */
 static struct ext4_dir_entry_2 *
-dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count,
+dx_move_dirents(struct inode *dir, char *from, char *to,
+               struct dx_map_entry *map, int count,
                unsigned blocksize)
 {
        unsigned rec_len = 0;
@@ -1773,11 +1849,19 @@ dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count,
        while (count--) {
                struct ext4_dir_entry_2 *de = (struct ext4_dir_entry_2 *)
                                                (from + (map->offs<<2));
-               rec_len = EXT4_DIR_REC_LEN(de->name_len);
+               rec_len = ext4_dir_rec_len(de->name_len, dir);
+
                memcpy (to, de, rec_len);
                ((struct ext4_dir_entry_2 *) to)->rec_len =
                                ext4_rec_len_to_disk(rec_len, blocksize);
+
+               /* wipe dir_entry excluding the rec_len field */
                de->inode = 0;
+               memset(&de->name_len, 0, ext4_rec_len_from_disk(de->rec_len,
+                                                               blocksize) -
+                                        offsetof(struct ext4_dir_entry_2,
+                                                               name_len));
+
                map++;
                to += rec_len;
        }
@@ -1788,7 +1872,8 @@ dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count,
  * Compact each dir entry in the range to the minimal rec_len.
  * Returns pointer to last entry in range.
  */
-static struct ext4_dir_entry_2* dx_pack_dirents(char *base, unsigned blocksize)
+static struct ext4_dir_entry_2 *dx_pack_dirents(struct inode *dir, char *base,
+                                                       unsigned int blocksize)
 {
        struct ext4_dir_entry_2 *next, *to, *prev, *de = (struct ext4_dir_entry_2 *) base;
        unsigned rec_len = 0;
@@ -1797,7 +1882,7 @@ static struct ext4_dir_entry_2* dx_pack_dirents(char *base, unsigned blocksize)
        while ((char*)de < base + blocksize) {
                next = ext4_next_entry(de, blocksize);
                if (de->inode && de->name_len) {
-                       rec_len = EXT4_DIR_REC_LEN(de->name_len);
+                       rec_len = ext4_dir_rec_len(de->name_len, dir);
                        if (de > to)
                                memmove(to, de, rec_len);
                        to->rec_len = ext4_rec_len_to_disk(rec_len, blocksize);
@@ -1887,9 +1972,9 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
                                        hash2, split, count-split));
 
        /* Fancy dance to stay within two buffers */
-       de2 = dx_move_dirents(data1, data2, map + split, count - split,
+       de2 = dx_move_dirents(dir, data1, data2, map + split, count - split,
                              blocksize);
-       de = dx_pack_dirents(data1, blocksize);
+       de = dx_pack_dirents(dir, data1, blocksize);
        de->rec_len = ext4_rec_len_to_disk(data1 + (blocksize - csum_size) -
                                           (char *) de,
                                           blocksize);
@@ -1937,7 +2022,7 @@ int ext4_find_dest_de(struct inode *dir, struct inode *inode,
                      struct ext4_dir_entry_2 **dest_de)
 {
        struct ext4_dir_entry_2 *de;
-       unsigned short reclen = EXT4_DIR_REC_LEN(fname_len(fname));
+       unsigned short reclen = ext4_dir_rec_len(fname_len(fname), dir);
        int nlen, rlen;
        unsigned int offset = 0;
        char *top;
@@ -1950,7 +2035,7 @@ int ext4_find_dest_de(struct inode *dir, struct inode *inode,
                        return -EFSCORRUPTED;
                if (ext4_match(dir, fname, de))
                        return -EEXIST;
-               nlen = EXT4_DIR_REC_LEN(de->name_len);
+               nlen = ext4_dir_rec_len(de->name_len, dir);
                rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
                if ((de->inode ? rlen - nlen : rlen) >= reclen)
                        break;
@@ -1964,7 +2049,8 @@ int ext4_find_dest_de(struct inode *dir, struct inode *inode,
        return 0;
 }
 
-void ext4_insert_dentry(struct inode *inode,
+void ext4_insert_dentry(struct inode *dir,
+                       struct inode *inode,
                        struct ext4_dir_entry_2 *de,
                        int buf_size,
                        struct ext4_filename *fname)
@@ -1972,7 +2058,7 @@ void ext4_insert_dentry(struct inode *inode,
 
        int nlen, rlen;
 
-       nlen = EXT4_DIR_REC_LEN(de->name_len);
+       nlen = ext4_dir_rec_len(de->name_len, dir);
        rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
        if (de->inode) {
                struct ext4_dir_entry_2 *de1 =
@@ -1986,6 +2072,13 @@ void ext4_insert_dentry(struct inode *inode,
        ext4_set_de_type(inode->i_sb, de, inode->i_mode);
        de->name_len = fname_len(fname);
        memcpy(de->name, fname_name(fname), fname_len(fname));
+       if (ext4_hash_in_dirent(dir)) {
+               struct dx_hash_info *hinfo = &fname->hinfo;
+
+               EXT4_DIRENT_HASHES(de)->hash = cpu_to_le32(hinfo->hash);
+               EXT4_DIRENT_HASHES(de)->minor_hash =
+                                               cpu_to_le32(hinfo->minor_hash);
+       }
 }
 
 /*
@@ -2022,7 +2115,7 @@ static int add_dirent_to_buf(handle_t *handle, struct ext4_filename *fname,
        }
 
        /* By now the buffer is marked for journaling */
-       ext4_insert_dentry(inode, de, blocksize, fname);
+       ext4_insert_dentry(dir, inode, de, blocksize, fname);
 
        /*
         * XXX shouldn't update any times until successful
@@ -2102,6 +2195,7 @@ static int make_indexed_dir(handle_t *handle, struct ext4_filename *fname,
        data2 = bh2->b_data;
 
        memcpy(data2, de, len);
+       memset(de, 0, len); /* wipe old data */
        de = (struct ext4_dir_entry_2 *) data2;
        top = data2 + len;
        while ((char *)(de2 = ext4_next_entry(de, blocksize)) < top)
@@ -2114,11 +2208,16 @@ static int make_indexed_dir(handle_t *handle, struct ext4_filename *fname,
 
        /* Initialize the root; the dot dirents already exist */
        de = (struct ext4_dir_entry_2 *) (&root->dotdot);
-       de->rec_len = ext4_rec_len_to_disk(blocksize - EXT4_DIR_REC_LEN(2),
-                                          blocksize);
+       de->rec_len = ext4_rec_len_to_disk(
+                       blocksize - ext4_dir_rec_len(2, NULL), blocksize);
        memset (&root->info, 0, sizeof(root->info));
        root->info.info_length = sizeof(root->info);
-       root->info.hash_version = EXT4_SB(dir->i_sb)->s_def_hash_version;
+       if (ext4_hash_in_dirent(dir))
+               root->info.hash_version = DX_HASH_SIPHASH;
+       else
+               root->info.hash_version =
+                               EXT4_SB(dir->i_sb)->s_def_hash_version;
+
        entries = root->entries;
        dx_set_block(entries, 1);
        dx_set_count(entries, 1);
@@ -2129,7 +2228,11 @@ static int make_indexed_dir(handle_t *handle, struct ext4_filename *fname,
        if (fname->hinfo.hash_version <= DX_HASH_TEA)
                fname->hinfo.hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned;
        fname->hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed;
-       ext4fs_dirhash(dir, fname_name(fname), fname_len(fname), &fname->hinfo);
+
+       /* casefolded encrypted hashes are computed on fname setup */
+       if (!ext4_hash_in_dirent(dir))
+               ext4fs_dirhash(dir, fname_name(fname),
+                               fname_len(fname), &fname->hinfo);
 
        memset(frames, 0, sizeof(frames));
        frame = frames;
@@ -2139,10 +2242,10 @@ static int make_indexed_dir(handle_t *handle, struct ext4_filename *fname,
 
        retval = ext4_handle_dirty_dx_node(handle, dir, frame->bh);
        if (retval)
-               goto out_frames;        
+               goto out_frames;
        retval = ext4_handle_dirty_dirblock(handle, dir, bh2);
        if (retval)
-               goto out_frames;        
+               goto out_frames;
 
        de = do_split(handle,dir, &bh2, frame, &fname->hinfo);
        if (IS_ERR(de)) {
@@ -2482,15 +2585,27 @@ int ext4_generic_delete_entry(struct inode *dir,
                                         entry_buf, buf_size, i))
                        return -EFSCORRUPTED;
                if (de == de_del)  {
-                       if (pde)
+                       if (pde) {
                                pde->rec_len = ext4_rec_len_to_disk(
                                        ext4_rec_len_from_disk(pde->rec_len,
                                                               blocksize) +
                                        ext4_rec_len_from_disk(de->rec_len,
                                                               blocksize),
                                        blocksize);
-                       else
+
+                               /* wipe entire dir_entry */
+                               memset(de, 0, ext4_rec_len_from_disk(de->rec_len,
+                                                               blocksize));
+                       } else {
+                               /* wipe dir_entry excluding the rec_len field */
                                de->inode = 0;
+                               memset(&de->name_len, 0,
+                                       ext4_rec_len_from_disk(de->rec_len,
+                                                               blocksize) -
+                                       offsetof(struct ext4_dir_entry_2,
+                                                               name_len));
+                       }
+
                        inode_inc_iversion(dir);
                        return 0;
                }
@@ -2722,7 +2837,7 @@ struct ext4_dir_entry_2 *ext4_init_dot_dotdot(struct inode *inode,
 {
        de->inode = cpu_to_le32(inode->i_ino);
        de->name_len = 1;
-       de->rec_len = ext4_rec_len_to_disk(EXT4_DIR_REC_LEN(de->name_len),
+       de->rec_len = ext4_rec_len_to_disk(ext4_dir_rec_len(de->name_len, NULL),
                                           blocksize);
        strcpy(de->name, ".");
        ext4_set_de_type(inode->i_sb, de, S_IFDIR);
@@ -2732,11 +2847,12 @@ struct ext4_dir_entry_2 *ext4_init_dot_dotdot(struct inode *inode,
        de->name_len = 2;
        if (!dotdot_real_len)
                de->rec_len = ext4_rec_len_to_disk(blocksize -
-                                       (csum_size + EXT4_DIR_REC_LEN(1)),
+                                       (csum_size + ext4_dir_rec_len(1, NULL)),
                                        blocksize);
        else
                de->rec_len = ext4_rec_len_to_disk(
-                               EXT4_DIR_REC_LEN(de->name_len), blocksize);
+                                       ext4_dir_rec_len(de->name_len, NULL),
+                                       blocksize);
        strcpy(de->name, "..");
        ext4_set_de_type(inode->i_sb, de, S_IFDIR);
 
@@ -2869,7 +2985,8 @@ bool ext4_empty_dir(struct inode *inode)
        }
 
        sb = inode->i_sb;
-       if (inode->i_size < EXT4_DIR_REC_LEN(1) + EXT4_DIR_REC_LEN(2)) {
+       if (inode->i_size < ext4_dir_rec_len(1, NULL) +
+                                       ext4_dir_rec_len(2, NULL)) {
                EXT4_ERROR_INODE(inode, "invalid size");
                return true;
        }
@@ -3372,7 +3489,7 @@ static int ext4_symlink(struct user_namespace *mnt_userns, struct inode *dir,
                 * for transaction commit if we are running out of space
                 * and thus we deadlock. So we have to stop transaction now
                 * and restart it when symlink contents is written.
-                * 
+                *
                 * To keep fs consistent in case of crash, we have to put inode
                 * to orphan list in the mean time.
                 */