For regular files in filesystems using extent-based encryption, the corresponding inode does not need a fscrypt_info structure of its own as for inode-based fscrypt, as they will not be encrypting anything using it. Any new extents written to the inode will use a per-extent info structure derived from the inode's parent directory's info structure. However, it is convenient to cache that parent directory's info structure in the inode; it makes it easy to check whether the parents' info exists, so that we don't have to get and put a reference to the parent inode every time we want to get the inode info. So do that. Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@xxxxxxxxxx> --- fs/crypto/fscrypt_private.h | 18 ++++++++++++++++++ fs/crypto/keysetup.c | 27 ++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index 2df28c6fe558..e4c9c483114f 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -262,6 +262,24 @@ typedef enum { FS_ENCRYPT, } fscrypt_direction_t; +/** + * fscrypt_uses_extent_encryption() -- whether an inode uses per-extent + * encryption + * + * @param inode the inode in question + * + * Return: true if the inode uses per-extent encryption infos, false otherwise + */ +static inline bool fscrypt_uses_extent_encryption(const struct inode *inode) +{ + // Non-regular files don't have extents + if (!S_ISREG(inode->i_mode)) + return false; + + // No filesystem currently uses per-extent infos + return false; +} + /** * fscrypt_get_inode_info() - get the fscrypt_info for a particular inode * diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index 4d7ff8244c55..52244e0dd1e4 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -622,6 +622,22 @@ int fscrypt_get_encryption_info(struct inode *inode, bool allow_unsupported) if (fscrypt_has_encryption_key(inode)) return 0; + if (fscrypt_uses_extent_encryption(inode)) { + struct dentry *dentry = d_find_any_alias(inode); + struct dentry *parent_dentry = dget_parent(dentry); + struct inode *dir = parent_dentry->d_inode; + struct fscrypt_info *dir_info = fscrypt_get_inode_info(dir); + struct fscrypt_master_key *mk = NULL; + + if (dir_info) + mk = dir_info->ci_master_key; + + fscrypt_set_inode_info(inode, dir_info, mk); + dput(parent_dentry); + dput(dentry); + return 0; + } + res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx)); if (res < 0) { if (res == -ERANGE && allow_unsupported) @@ -704,6 +720,14 @@ int fscrypt_prepare_new_inode(struct inode *dir, struct inode *inode, *encrypt_ret = true; + if (fscrypt_uses_extent_encryption(inode)) { + struct fscrypt_info *dir_info = fscrypt_get_inode_info(dir); + + fscrypt_set_inode_info(inode, dir_info, + dir_info->ci_master_key); + return 0; + } + get_random_bytes(nonce, FSCRYPT_FILE_NONCE_SIZE); return fscrypt_setup_encryption_info(inode, policy, nonce, IS_CASEFOLDED(dir) && @@ -720,7 +744,8 @@ EXPORT_SYMBOL_GPL(fscrypt_prepare_new_inode); */ void fscrypt_put_encryption_info(struct inode *inode) { - put_crypt_info(fscrypt_get_inode_info(inode)); + if (!fscrypt_uses_extent_encryption(inode)) + put_crypt_info(fscrypt_get_inode_info(inode)); fscrypt_set_inode_info(inode, NULL, NULL); } EXPORT_SYMBOL(fscrypt_put_encryption_info); -- 2.38.1