Merge tag 'fscrypt_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso...
[linux-2.6-block.git] / fs / ext4 / namei.c
index 9aa1deb1a5256daf58dddf15b9c269b6c0969a9b..b1f21e3a076327df20e5218451ff1feec7e3a13f 100644 (file)
@@ -3057,39 +3057,19 @@ static int ext4_symlink(struct inode *dir,
        struct inode *inode;
        int err, len = strlen(symname);
        int credits;
-       bool encryption_required;
        struct fscrypt_str disk_link;
-       struct fscrypt_symlink_data *sd = NULL;
 
        if (unlikely(ext4_forced_shutdown(EXT4_SB(dir->i_sb))))
                return -EIO;
 
-       disk_link.len = len + 1;
-       disk_link.name = (char *) symname;
-
-       encryption_required = (ext4_encrypted_inode(dir) ||
-                              DUMMY_ENCRYPTION_ENABLED(EXT4_SB(dir->i_sb)));
-       if (encryption_required) {
-               err = fscrypt_get_encryption_info(dir);
-               if (err)
-                       return err;
-               if (!fscrypt_has_encryption_key(dir))
-                       return -ENOKEY;
-               disk_link.len = (fscrypt_fname_encrypted_size(dir, len) +
-                                sizeof(struct fscrypt_symlink_data));
-               sd = kzalloc(disk_link.len, GFP_KERNEL);
-               if (!sd)
-                       return -ENOMEM;
-       }
-
-       if (disk_link.len > dir->i_sb->s_blocksize) {
-               err = -ENAMETOOLONG;
-               goto err_free_sd;
-       }
+       err = fscrypt_prepare_symlink(dir, symname, len, dir->i_sb->s_blocksize,
+                                     &disk_link);
+       if (err)
+               return err;
 
        err = dquot_initialize(dir);
        if (err)
-               goto err_free_sd;
+               return err;
 
        if ((disk_link.len > EXT4_N_BLOCKS * 4)) {
                /*
@@ -3118,27 +3098,18 @@ static int ext4_symlink(struct inode *dir,
        if (IS_ERR(inode)) {
                if (handle)
                        ext4_journal_stop(handle);
-               err = PTR_ERR(inode);
-               goto err_free_sd;
+               return PTR_ERR(inode);
        }
 
-       if (encryption_required) {
-               struct qstr istr;
-               struct fscrypt_str ostr =
-                       FSTR_INIT(sd->encrypted_path, disk_link.len);
-
-               istr.name = (const unsigned char *) symname;
-               istr.len = len;
-               err = fscrypt_fname_usr_to_disk(inode, &istr, &ostr);
+       if (IS_ENCRYPTED(inode)) {
+               err = fscrypt_encrypt_symlink(inode, symname, len, &disk_link);
                if (err)
                        goto err_drop_inode;
-               sd->len = cpu_to_le16(ostr.len);
-               disk_link.name = (char *) sd;
                inode->i_op = &ext4_encrypted_symlink_inode_operations;
        }
 
        if ((disk_link.len > EXT4_N_BLOCKS * 4)) {
-               if (!encryption_required)
+               if (!IS_ENCRYPTED(inode))
                        inode->i_op = &ext4_symlink_inode_operations;
                inode_nohighmem(inode);
                ext4_set_aops(inode);
@@ -3180,7 +3151,7 @@ static int ext4_symlink(struct inode *dir,
        } else {
                /* clear the extent format for fast symlink */
                ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS);
-               if (!encryption_required) {
+               if (!IS_ENCRYPTED(inode)) {
                        inode->i_op = &ext4_fast_symlink_inode_operations;
                        inode->i_link = (char *)&EXT4_I(inode)->i_data;
                }
@@ -3195,16 +3166,17 @@ static int ext4_symlink(struct inode *dir,
 
        if (handle)
                ext4_journal_stop(handle);
-       kfree(sd);
-       return err;
+       goto out_free_encrypted_link;
+
 err_drop_inode:
        if (handle)
                ext4_journal_stop(handle);
        clear_nlink(inode);
        unlock_new_inode(inode);
        iput(inode);
-err_free_sd:
-       kfree(sd);
+out_free_encrypted_link:
+       if (disk_link.name != (unsigned char *)symname)
+               kfree(disk_link.name);
        return err;
 }