Merge tag 'for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 4 May 2015 01:23:53 +0000 (18:23 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 4 May 2015 01:23:53 +0000 (18:23 -0700)
Pull ext4 fixes from Ted Ts'o:
 "Some miscellaneous bug fixes and some final on-disk and ABI changes
  for ext4 encryption which provide better security and performance"

* tag 'for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4:
  ext4: fix growing of tiny filesystems
  ext4: move check under lock scope to close a race.
  ext4: fix data corruption caused by unwritten and delayed extents
  ext4 crypto: remove duplicated encryption mode definitions
  ext4 crypto: do not select from EXT4_FS_ENCRYPTION
  ext4 crypto: add padding to filenames before encrypting
  ext4 crypto: simplify and speed up filename encryption

1  2 
fs/ext4/ext4.h
fs/ext4/inode.c
fs/ext4/namei.c
fs/ext4/symlink.c

diff --combined fs/ext4/ext4.h
index ef267adce19a563d87f5708fa006db6dd3e6e393,1de8c7f0689772545dd83d2c839eafc7f50dfd9c..009a0590b20fb328c5829573ee77440dabb8e83e
@@@ -911,6 -911,7 +911,7 @@@ struct ext4_inode_info 
  
        /* on-disk additional length */
        __u16 i_extra_isize;
+       char i_crypt_policy_flags;
  
        /* Indicate the inline data space. */
        u16 i_inline_off;
@@@ -1066,12 -1067,6 +1067,6 @@@ extern void ext4_set_bits(void *bm, in
  /* Metadata checksum algorithm codes */
  #define EXT4_CRC32C_CHKSUM            1
  
- /* Encryption algorithms */
- #define EXT4_ENCRYPTION_MODE_INVALID          0
- #define EXT4_ENCRYPTION_MODE_AES_256_XTS      1
- #define EXT4_ENCRYPTION_MODE_AES_256_GCM      2
- #define EXT4_ENCRYPTION_MODE_AES_256_CBC      3
  /*
   * Structure of the super block
   */
@@@ -2093,9 -2088,11 +2088,11 @@@ u32 ext4_fname_crypto_round_up(u32 size
  int ext4_fname_crypto_alloc_buffer(struct ext4_fname_crypto_ctx *ctx,
                                   u32 ilen, struct ext4_str *crypto_str);
  int _ext4_fname_disk_to_usr(struct ext4_fname_crypto_ctx *ctx,
+                           struct dx_hash_info *hinfo,
                            const struct ext4_str *iname,
                            struct ext4_str *oname);
  int ext4_fname_disk_to_usr(struct ext4_fname_crypto_ctx *ctx,
+                          struct dx_hash_info *hinfo,
                           const struct ext4_dir_entry_2 *de,
                           struct ext4_str *oname);
  int ext4_fname_usr_to_disk(struct ext4_fname_crypto_ctx *ctx,
  int ext4_fname_usr_to_hash(struct ext4_fname_crypto_ctx *ctx,
                           const struct qstr *iname,
                           struct dx_hash_info *hinfo);
- int ext4_fname_disk_to_hash(struct ext4_fname_crypto_ctx *ctx,
-                           const struct ext4_dir_entry_2 *de,
-                           struct dx_hash_info *hinfo);
  int ext4_fname_crypto_namelen_on_disk(struct ext4_fname_crypto_ctx *ctx,
                                      u32 namelen);
+ int ext4_fname_match(struct ext4_fname_crypto_ctx *ctx, struct ext4_str *cstr,
+                    int len, const char * const name,
+                    struct ext4_dir_entry_2 *de);
  
  #ifdef CONFIG_EXT4_FS_ENCRYPTION
  void ext4_put_fname_crypto_ctx(struct ext4_fname_crypto_ctx **ctx);
@@@ -2296,8 -2294,8 +2294,8 @@@ extern void ext4_da_update_reserve_spac
  /* indirect.c */
  extern int ext4_ind_map_blocks(handle_t *handle, struct inode *inode,
                                struct ext4_map_blocks *map, int flags);
 -extern ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb,
 -                              struct iov_iter *iter, loff_t offset);
 +extern ssize_t ext4_ind_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
 +                                loff_t offset);
  extern int ext4_ind_calc_metadata_amount(struct inode *inode, sector_t lblock);
  extern int ext4_ind_trans_blocks(struct inode *inode, int nrblocks);
  extern void ext4_ind_truncate(handle_t *, struct inode *inode);
@@@ -2738,6 -2736,7 +2736,6 @@@ extern const struct file_operations ext
  /* file.c */
  extern const struct inode_operations ext4_file_inode_operations;
  extern const struct file_operations ext4_file_operations;
 -extern const struct file_operations ext4_dax_file_operations;
  extern loff_t ext4_llseek(struct file *file, loff_t offset, int origin);
  
  /* inline.c */
diff --combined fs/ext4/inode.c
index cbd0654a26750e8827f1e40b5b1ae07192bd066b,4415cea85ced1764ca6ab178a49ed9fd3e66ea89..55b187c3bac1f1626cf0267734aa805b6f9a1263
@@@ -35,6 -35,7 +35,6 @@@
  #include <linux/kernel.h>
  #include <linux/printk.h>
  #include <linux/slab.h>
 -#include <linux/aio.h>
  #include <linux/bitops.h>
  
  #include "ext4_jbd2.h"
@@@ -531,6 -532,7 +531,7 @@@ int ext4_map_blocks(handle_t *handle, s
                status = map->m_flags & EXT4_MAP_UNWRITTEN ?
                                EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN;
                if (!(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) &&
+                   !(status & EXTENT_STATUS_WRITTEN) &&
                    ext4_find_delalloc_range(inode, map->m_lblk,
                                             map->m_lblk + map->m_len - 1))
                        status |= EXTENT_STATUS_DELAYED;
@@@ -635,6 -637,7 +636,7 @@@ found
                status = map->m_flags & EXT4_MAP_UNWRITTEN ?
                                EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN;
                if (!(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) &&
+                   !(status & EXTENT_STATUS_WRITTEN) &&
                    ext4_find_delalloc_range(inode, map->m_lblk,
                                             map->m_lblk + map->m_len - 1))
                        status |= EXTENT_STATUS_DELAYED;
@@@ -3052,8 -3055,8 +3054,8 @@@ static void ext4_end_io_dio(struct kioc
   * if the machine crashes during the write.
   *
   */
 -static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb,
 -                            struct iov_iter *iter, loff_t offset)
 +static ssize_t ext4_ext_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
 +                                loff_t offset)
  {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_mapping->host;
        ext4_io_end_t *io_end = NULL;
  
        /* Use the old path for reads and writes beyond i_size. */
 -      if (rw != WRITE || final_size > inode->i_size)
 -              return ext4_ind_direct_IO(rw, iocb, iter, offset);
 +      if (iov_iter_rw(iter) != WRITE || final_size > inode->i_size)
 +              return ext4_ind_direct_IO(iocb, iter, offset);
  
        BUG_ON(iocb->private == NULL);
  
         * conversion. This also disallows race between truncate() and
         * overwrite DIO as i_dio_count needs to be incremented under i_mutex.
         */
 -      if (rw == WRITE)
 -              atomic_inc(&inode->i_dio_count);
 +      if (iov_iter_rw(iter) == WRITE)
 +              inode_dio_begin(inode);
  
        /* If we do a overwrite dio, i_mutex locking can be released */
        overwrite = *((int *)iocb->private);
        BUG_ON(ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode));
  #endif
        if (IS_DAX(inode))
 -              ret = dax_do_io(rw, iocb, inode, iter, offset, get_block_func,
 +              ret = dax_do_io(iocb, inode, iter, offset, get_block_func,
                                ext4_end_io_dio, dio_flags);
        else
 -              ret = __blockdev_direct_IO(rw, iocb, inode,
 +              ret = __blockdev_direct_IO(iocb, inode,
                                           inode->i_sb->s_bdev, iter, offset,
                                           get_block_func,
                                           ext4_end_io_dio, NULL, dio_flags);
        }
  
  retake_lock:
 -      if (rw == WRITE)
 -              inode_dio_done(inode);
 +      if (iov_iter_rw(iter) == WRITE)
 +              inode_dio_end(inode);
        /* take i_mutex locking again if we do a ovewrite dio */
        if (overwrite) {
                up_read(&EXT4_I(inode)->i_data_sem);
        return ret;
  }
  
 -static ssize_t ext4_direct_IO(int rw, struct kiocb *iocb,
 -                            struct iov_iter *iter, loff_t offset)
 +static ssize_t ext4_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
 +                            loff_t offset)
  {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_mapping->host;
        if (ext4_has_inline_data(inode))
                return 0;
  
 -      trace_ext4_direct_IO_enter(inode, offset, count, rw);
 +      trace_ext4_direct_IO_enter(inode, offset, count, iov_iter_rw(iter));
        if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
 -              ret = ext4_ext_direct_IO(rw, iocb, iter, offset);
 +              ret = ext4_ext_direct_IO(iocb, iter, offset);
        else
 -              ret = ext4_ind_direct_IO(rw, iocb, iter, offset);
 -      trace_ext4_direct_IO_exit(inode, offset, count, rw, ret);
 +              ret = ext4_ind_direct_IO(iocb, iter, offset);
 +      trace_ext4_direct_IO_exit(inode, offset, count, iov_iter_rw(iter), ret);
        return ret;
  }
  
@@@ -4205,7 -4208,10 +4207,7 @@@ struct inode *ext4_iget(struct super_bl
  
        if (S_ISREG(inode->i_mode)) {
                inode->i_op = &ext4_file_inode_operations;
 -              if (test_opt(inode->i_sb, DAX))
 -                      inode->i_fop = &ext4_dax_file_operations;
 -              else
 -                      inode->i_fop = &ext4_file_operations;
 +              inode->i_fop = &ext4_file_operations;
                ext4_set_aops(inode);
        } else if (S_ISDIR(inode->i_mode)) {
                inode->i_op = &ext4_dir_inode_operations;
@@@ -4637,7 -4643,7 +4639,7 @@@ static void ext4_wait_for_tail_page_com
   */
  int ext4_setattr(struct dentry *dentry, struct iattr *attr)
  {
 -      struct inode *inode = dentry->d_inode;
 +      struct inode *inode = d_inode(dentry);
        int error, rc = 0;
        int orphan = 0;
        const unsigned int ia_valid = attr->ia_valid;
@@@ -4785,7 -4791,7 +4787,7 @@@ int ext4_getattr(struct vfsmount *mnt, 
        struct inode *inode;
        unsigned long long delalloc_blocks;
  
 -      inode = dentry->d_inode;
 +      inode = d_inode(dentry);
        generic_fillattr(inode, stat);
  
        /*
diff --combined fs/ext4/namei.c
index 7223b0b4bc38cd0a67a8b53eadcd616396d5dce5,5ea737114716c65f150d74aff29ba9110d4cbd39..814f3beb436965f116b7555ee8cf9ac30c3f0165
@@@ -640,7 -640,7 +640,7 @@@ static struct stats dx_show_leaf(struc
                                                ext4_put_fname_crypto_ctx(&ctx);
                                                ctx = NULL;
                                        }
-                                       res = ext4_fname_disk_to_usr(ctx, de,
+                                       res = ext4_fname_disk_to_usr(ctx, NULL, de,
                                                        &fname_crypto_str);
                                        if (res < 0) {
                                                printk(KERN_WARNING "Error "
                                                name = fname_crypto_str.name;
                                                len = fname_crypto_str.len;
                                        }
-                                       res = ext4_fname_disk_to_hash(ctx, de,
-                                                                     &h);
-                                       if (res < 0) {
-                                               printk(KERN_WARNING "Error "
-                                                       "converting filename "
-                                                       "from disk to htree"
-                                                       "\n");
-                                               h.hash = 0xDEADBEEF;
-                                       }
+                                       ext4fs_dirhash(de->name, de->name_len,
+                                                      &h);
                                        printk("%*.s:(E)%x.%u ", len, name,
                                               h.hash, (unsigned) ((char *) de
                                                                   - base));
@@@ -1008,15 -1001,7 +1001,7 @@@ static int htree_dirblock_to_tree(struc
                        /* silently ignore the rest of the block */
                        break;
                }
- #ifdef CONFIG_EXT4_FS_ENCRYPTION
-               err = ext4_fname_disk_to_hash(ctx, de, hinfo);
-               if (err < 0) {
-                       count = err;
-                       goto errout;
-               }
- #else
                ext4fs_dirhash(de->name, de->name_len, hinfo);
- #endif
                if ((hinfo->hash < start_hash) ||
                    ((hinfo->hash == start_hash) &&
                     (hinfo->minor_hash < start_minor_hash)))
                                   &tmp_str);
                } else {
                        /* Directory is encrypted */
-                       err = ext4_fname_disk_to_usr(ctx, de,
+                       err = ext4_fname_disk_to_usr(ctx, hinfo, de,
                                                     &fname_crypto_str);
                        if (err < 0) {
                                count = err;
@@@ -1193,26 -1178,10 +1178,10 @@@ static int dx_make_map(struct inode *di
        int count = 0;
        char *base = (char *) de;
        struct dx_hash_info h = *hinfo;
- #ifdef CONFIG_EXT4_FS_ENCRYPTION
-       struct ext4_fname_crypto_ctx *ctx = NULL;
-       int err;
-       ctx = ext4_get_fname_crypto_ctx(dir, EXT4_NAME_LEN);
-       if (IS_ERR(ctx))
-               return PTR_ERR(ctx);
- #endif
  
        while ((char *) de < base + blocksize) {
                if (de->name_len && de->inode) {
- #ifdef CONFIG_EXT4_FS_ENCRYPTION
-                       err = ext4_fname_disk_to_hash(ctx, de, &h);
-                       if (err < 0) {
-                               ext4_put_fname_crypto_ctx(&ctx);
-                               return err;
-                       }
- #else
                        ext4fs_dirhash(de->name, de->name_len, &h);
- #endif
                        map_tail--;
                        map_tail->hash = h.hash;
                        map_tail->offs = ((char *) de - base)>>2;
                /* XXX: do we need to check rec_len == 0 case? -Chris */
                de = ext4_next_entry(de, blocksize);
        }
- #ifdef CONFIG_EXT4_FS_ENCRYPTION
-       ext4_put_fname_crypto_ctx(&ctx);
- #endif
        return count;
  }
  
@@@ -1287,16 -1253,8 +1253,8 @@@ static inline int ext4_match(struct ext
                return 0;
  
  #ifdef CONFIG_EXT4_FS_ENCRYPTION
-       if (ctx) {
-               /* Directory is encrypted */
-               res = ext4_fname_disk_to_usr(ctx, de, fname_crypto_str);
-               if (res < 0)
-                       return res;
-               if (len != res)
-                       return 0;
-               res = memcmp(name, fname_crypto_str->name, len);
-               return (res == 0) ? 1 : 0;
-       }
+       if (ctx)
+               return ext4_fname_match(ctx, fname_crypto_str, len, name, de);
  #endif
        if (len != de->name_len)
                return 0;
@@@ -1324,16 -1282,6 +1282,6 @@@ int search_dir(struct buffer_head *bh, 
        if (IS_ERR(ctx))
                return -1;
  
-       if (ctx != NULL) {
-               /* Allocate buffer to hold maximum name length */
-               res = ext4_fname_crypto_alloc_buffer(ctx, EXT4_NAME_LEN,
-                                                    &fname_crypto_str);
-               if (res < 0) {
-                       ext4_put_fname_crypto_ctx(&ctx);
-                       return -1;
-               }
-       }
        de = (struct ext4_dir_entry_2 *)search_buf;
        dlimit = search_buf + buf_size;
        while ((char *) de < dlimit) {
@@@ -1664,7 -1612,7 +1612,7 @@@ struct dentry *ext4_get_parent(struct d
        struct ext4_dir_entry_2 * de;
        struct buffer_head *bh;
  
 -      bh = ext4_find_entry(child->d_inode, &dotdot, &de, NULL);
 +      bh = ext4_find_entry(d_inode(child), &dotdot, &de, NULL);
        if (IS_ERR(bh))
                return (struct dentry *) bh;
        if (!bh)
        ino = le32_to_cpu(de->inode);
        brelse(bh);
  
 -      if (!ext4_valid_inum(child->d_inode->i_sb, ino)) {
 -              EXT4_ERROR_INODE(child->d_inode,
 +      if (!ext4_valid_inum(d_inode(child)->i_sb, ino)) {
 +              EXT4_ERROR_INODE(d_inode(child),
                                 "bad parent inode number: %u", ino);
                return ERR_PTR(-EIO);
        }
  
 -      return d_obtain_alias(ext4_iget_normal(child->d_inode->i_sb, ino));
 +      return d_obtain_alias(ext4_iget_normal(d_inode(child)->i_sb, ino));
  }
  
  /*
@@@ -1872,14 -1820,6 +1820,6 @@@ int ext4_find_dest_de(struct inode *dir
                        return res;
                }
                reclen = EXT4_DIR_REC_LEN(res);
-               /* Allocate buffer to hold maximum name length */
-               res = ext4_fname_crypto_alloc_buffer(ctx, EXT4_NAME_LEN,
-                                                    &fname_crypto_str);
-               if (res < 0) {
-                       ext4_put_fname_crypto_ctx(&ctx);
-                       return -1;
-               }
        }
  
        de = (struct ext4_dir_entry_2 *)buf;
@@@ -1988,7 -1928,7 +1928,7 @@@ static int add_dirent_to_buf(handle_t *
                             struct inode *inode, struct ext4_dir_entry_2 *de,
                             struct buffer_head *bh)
  {
 -      struct inode    *dir = dentry->d_parent->d_inode;
 +      struct inode    *dir = d_inode(dentry->d_parent);
        const char      *name = dentry->d_name.name;
        int             namelen = dentry->d_name.len;
        unsigned int    blocksize = dir->i_sb->s_blocksize;
  static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
                            struct inode *inode, struct buffer_head *bh)
  {
 -      struct inode    *dir = dentry->d_parent->d_inode;
 +      struct inode    *dir = d_inode(dentry->d_parent);
  #ifdef CONFIG_EXT4_FS_ENCRYPTION
        struct ext4_fname_crypto_ctx *ctx = NULL;
        int res;
@@@ -2202,7 -2142,7 +2142,7 @@@ out_frames
  static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
                          struct inode *inode)
  {
 -      struct inode *dir = dentry->d_parent->d_inode;
 +      struct inode *dir = d_inode(dentry->d_parent);
        struct buffer_head *bh = NULL;
        struct ext4_dir_entry_2 *de;
        struct ext4_dir_entry_tail *t;
@@@ -2287,7 -2227,7 +2227,7 @@@ static int ext4_dx_add_entry(handle_t *
        struct dx_entry *entries, *at;
        struct dx_hash_info hinfo;
        struct buffer_head *bh;
 -      struct inode *dir = dentry->d_parent->d_inode;
 +      struct inode *dir = d_inode(dentry->d_parent);
        struct super_block *sb = dir->i_sb;
        struct ext4_dir_entry_2 *de;
        int err;
@@@ -2575,7 -2515,10 +2515,7 @@@ retry
        err = PTR_ERR(inode);
        if (!IS_ERR(inode)) {
                inode->i_op = &ext4_file_inode_operations;
 -              if (test_opt(inode->i_sb, DAX))
 -                      inode->i_fop = &ext4_dax_file_operations;
 -              else
 -                      inode->i_fop = &ext4_file_operations;
 +              inode->i_fop = &ext4_file_operations;
                ext4_set_aops(inode);
                err = 0;
  #ifdef CONFIG_EXT4_FS_ENCRYPTION
@@@ -2652,7 -2595,10 +2592,7 @@@ retry
        err = PTR_ERR(inode);
        if (!IS_ERR(inode)) {
                inode->i_op = &ext4_file_inode_operations;
 -              if (test_opt(inode->i_sb, DAX))
 -                      inode->i_fop = &ext4_dax_file_operations;
 -              else
 -                      inode->i_fop = &ext4_file_operations;
 +              inode->i_fop = &ext4_file_operations;
                ext4_set_aops(inode);
                d_tmpfile(dentry, inode);
                err = ext4_orphan_add(handle, inode);
@@@ -3063,7 -3009,7 +3003,7 @@@ static int ext4_rmdir(struct inode *dir
        /* Initialize quotas before so that eventual writes go in
         * separate transaction */
        dquot_initialize(dir);
 -      dquot_initialize(dentry->d_inode);
 +      dquot_initialize(d_inode(dentry));
  
        retval = -ENOENT;
        bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL);
        if (!bh)
                goto end_rmdir;
  
 -      inode = dentry->d_inode;
 +      inode = d_inode(dentry);
  
        retval = -EIO;
        if (le32_to_cpu(de->inode) != inode->i_ino)
@@@ -3132,7 -3078,7 +3072,7 @@@ static int ext4_unlink(struct inode *di
        /* Initialize quotas before so that eventual writes go
         * in separate transaction */
        dquot_initialize(dir);
 -      dquot_initialize(dentry->d_inode);
 +      dquot_initialize(d_inode(dentry));
  
        retval = -ENOENT;
        bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL);
        if (!bh)
                goto end_unlink;
  
 -      inode = dentry->d_inode;
 +      inode = d_inode(dentry);
  
        retval = -EIO;
        if (le32_to_cpu(de->inode) != inode->i_ino)
@@@ -3339,7 -3285,7 +3279,7 @@@ static int ext4_link(struct dentry *old
                     struct inode *dir, struct dentry *dentry)
  {
        handle_t *handle;
 -      struct inode *inode = old_dentry->d_inode;
 +      struct inode *inode = d_inode(old_dentry);
        int err, retries = 0;
  
        if (inode->i_nlink >= EXT4_LINK_MAX)
@@@ -3613,12 -3559,12 +3553,12 @@@ static int ext4_rename(struct inode *ol
        struct ext4_renament old = {
                .dir = old_dir,
                .dentry = old_dentry,
 -              .inode = old_dentry->d_inode,
 +              .inode = d_inode(old_dentry),
        };
        struct ext4_renament new = {
                .dir = new_dir,
                .dentry = new_dentry,
 -              .inode = new_dentry->d_inode,
 +              .inode = d_inode(new_dentry),
        };
        int force_reread;
        int retval;
@@@ -3809,12 -3755,12 +3749,12 @@@ static int ext4_cross_rename(struct ino
        struct ext4_renament old = {
                .dir = old_dir,
                .dentry = old_dentry,
 -              .inode = old_dentry->d_inode,
 +              .inode = d_inode(old_dentry),
        };
        struct ext4_renament new = {
                .dir = new_dir,
                .dentry = new_dentry,
 -              .inode = new_dentry->d_inode,
 +              .inode = d_inode(new_dentry),
        };
        u8 new_file_type;
        int retval;
diff --combined fs/ext4/symlink.c
index 19f78f20975ea723f33e6488750f9645a7ea2d4a,ce2ed286ba086740303512d6546c0ba1b5183916..187b789203142d6b444b264acd44798427626b41
@@@ -28,7 -28,7 +28,7 @@@ static void *ext4_follow_link(struct de
        struct page *cpage = NULL;
        char *caddr, *paddr = NULL;
        struct ext4_str cstr, pstr;
 -      struct inode *inode = dentry->d_inode;
 +      struct inode *inode = d_inode(dentry);
        struct ext4_fname_crypto_ctx *ctx = NULL;
        struct ext4_encrypted_symlink_data *sd;
        loff_t size = min_t(loff_t, i_size_read(inode), PAGE_SIZE - 1);
@@@ -43,8 -43,8 +43,8 @@@
                return ctx;
  
        if (ext4_inode_is_fast_symlink(inode)) {
 -              caddr = (char *) EXT4_I(dentry->d_inode)->i_data;
 -              max_size = sizeof(EXT4_I(dentry->d_inode)->i_data);
 +              caddr = (char *) EXT4_I(inode)->i_data;
 +              max_size = sizeof(EXT4_I(inode)->i_data);
        } else {
                cpage = read_mapping_page(inode->i_mapping, 0, NULL);
                if (IS_ERR(cpage)) {
@@@ -74,7 -74,7 +74,7 @@@
                goto errout;
        }
        pstr.name = paddr;
-       res = _ext4_fname_disk_to_usr(ctx, &cstr, &pstr);
+       res = _ext4_fname_disk_to_usr(ctx, NULL, &cstr, &pstr);
        if (res < 0)
                goto errout;
        /* Null-terminate the name */
@@@ -113,7 -113,7 +113,7 @@@ static void ext4_put_link(struct dentr
  
  static void *ext4_follow_fast_link(struct dentry *dentry, struct nameidata *nd)
  {
 -      struct ext4_inode_info *ei = EXT4_I(dentry->d_inode);
 +      struct ext4_inode_info *ei = EXT4_I(d_inode(dentry));
        nd_set_link(nd, (char *) ei->i_data);
        return NULL;
  }