Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

fscrypt: add support for info in fs-specific part of inode

Add an inode_info_offs field to struct fscrypt_operations, and update
fs/crypto/ to support it. When set to a nonzero value, it specifies the
offset to the fscrypt_inode_info pointer within the filesystem-specific
part of the inode structure, to be used instead of inode::i_crypt_info.

Since this makes inode::i_crypt_info no longer necessarily used, update
comments that mentioned it.

This is a prerequisite for a later commit that removes
inode::i_crypt_info, saving memory and improving cache efficiency with
filesystems that don't support fscrypt.

Co-developed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
Link: https://lore.kernel.org/20250810075706.172910-3-ebiggers@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>

authored by

Eric Biggers and committed by
Christian Brauner
93221de3 6c9468aa

+46 -23
+2 -2
fs/crypto/fscrypt_private.h
··· 249 249 * fscrypt_inode_info - the "encryption key" for an inode 250 250 * 251 251 * When an encrypted file's key is made available, an instance of this struct is 252 - * allocated and stored in ->i_crypt_info. Once created, it remains until the 253 - * inode is evicted. 252 + * allocated and a pointer to it is stored in the file's in-memory inode. Once 253 + * created, it remains until the inode is evicted. 254 254 */ 255 255 struct fscrypt_inode_info { 256 256
+26 -17
fs/crypto/keysetup.c
··· 642 642 goto out; 643 643 644 644 /* 645 - * For existing inodes, multiple tasks may race to set ->i_crypt_info. 646 - * So use cmpxchg_release(). This pairs with the smp_load_acquire() in 647 - * fscrypt_get_inode_info(). I.e., here we publish ->i_crypt_info with 648 - * a RELEASE barrier so that other tasks can ACQUIRE it. 645 + * For existing inodes, multiple tasks may race to set the inode's 646 + * fscrypt info pointer. So use cmpxchg_release(). This pairs with the 647 + * smp_load_acquire() in fscrypt_get_inode_info(). I.e., publish the 648 + * pointer with a RELEASE barrier so that other tasks can ACQUIRE it. 649 649 */ 650 - if (cmpxchg_release(&inode->i_crypt_info, NULL, crypt_info) == NULL) { 650 + if (cmpxchg_release(fscrypt_inode_info_addr(inode), NULL, crypt_info) == 651 + NULL) { 651 652 /* 652 - * We won the race and set ->i_crypt_info to our crypt_info. 653 - * Now link it into the master key's inode list. 653 + * We won the race and set the inode's fscrypt info to our 654 + * crypt_info. Now link it into the master key's inode list. 654 655 */ 655 656 if (mk) { 656 657 crypt_info->ci_master_key = mk; ··· 682 681 * %false unless the operation being performed is needed in 683 682 * order for files (or directories) to be deleted. 684 683 * 685 - * Set up ->i_crypt_info, if it hasn't already been done. 684 + * Set up the inode's encryption key, if it hasn't already been done. 686 685 * 687 - * Note: unless ->i_crypt_info is already set, this isn't %GFP_NOFS-safe. So 686 + * Note: unless the key setup was already done, this isn't %GFP_NOFS-safe. So 688 687 * generally this shouldn't be called from within a filesystem transaction. 689 688 * 690 - * Return: 0 if ->i_crypt_info was set or was already set, *or* if the 691 - * encryption key is unavailable. (Use fscrypt_has_encryption_key() to 689 + * Return: 0 if the key is now set up, *or* if it couldn't be set up because the 690 + * needed master key is absent. (Use fscrypt_has_encryption_key() to 692 691 * distinguish these cases.) Also can return another -errno code. 693 692 */ 694 693 int fscrypt_get_encryption_info(struct inode *inode, bool allow_unsupported) ··· 742 741 * ->i_ino doesn't need to be set yet. 743 742 * @encrypt_ret: (output) set to %true if the new inode will be encrypted 744 743 * 745 - * If the directory is encrypted, set up its ->i_crypt_info in preparation for 744 + * If the directory is encrypted, set up its encryption key in preparation for 746 745 * encrypting the name of the new file. Also, if the new inode will be 747 - * encrypted, set up its ->i_crypt_info and set *encrypt_ret=true. 746 + * encrypted, set up its encryption key too and set *encrypt_ret=true. 748 747 * 749 748 * This isn't %GFP_NOFS-safe, and therefore it should be called before starting 750 749 * any filesystem transaction to create the inode. For this reason, ->i_ino ··· 753 752 * This doesn't persist the new inode's encryption context. That still needs to 754 753 * be done later by calling fscrypt_set_context(). 755 754 * 756 - * Return: 0 on success, -ENOKEY if the encryption key is missing, or another 757 - * -errno code 755 + * Return: 0 on success, -ENOKEY if a key needs to be set up for @dir or @inode 756 + * but the needed master key is absent, or another -errno code 758 757 */ 759 758 int fscrypt_prepare_new_inode(struct inode *dir, struct inode *inode, 760 759 bool *encrypt_ret) ··· 801 800 */ 802 801 void fscrypt_put_encryption_info(struct inode *inode) 803 802 { 804 - put_crypt_info(inode->i_crypt_info); 805 - inode->i_crypt_info = NULL; 803 + /* 804 + * Ideally we'd start with a lightweight IS_ENCRYPTED() check here 805 + * before proceeding to retrieve and check the pointer. However, during 806 + * inode creation, the fscrypt_inode_info is set before S_ENCRYPTED. If 807 + * an error occurs, it needs to be cleaned up regardless. 808 + */ 809 + struct fscrypt_inode_info **ci_addr = fscrypt_inode_info_addr(inode); 810 + 811 + put_crypt_info(*ci_addr); 812 + *ci_addr = NULL; 806 813 } 807 814 EXPORT_SYMBOL(fscrypt_put_encryption_info); 808 815
+18 -4
include/linux/fscrypt.h
··· 61 61 62 62 /* Crypto operations for filesystems */ 63 63 struct fscrypt_operations { 64 + /* 65 + * The offset of the pointer to struct fscrypt_inode_info in the 66 + * filesystem-specific part of the inode, relative to the beginning of 67 + * the common part of the inode (the 'struct inode'). 68 + */ 69 + ptrdiff_t inode_info_offs; 64 70 65 71 /* 66 72 * If set, then fs/crypto/ will allocate a global bounce page pool the ··· 201 195 int fscrypt_d_revalidate(struct inode *dir, const struct qstr *name, 202 196 struct dentry *dentry, unsigned int flags); 203 197 198 + static inline struct fscrypt_inode_info ** 199 + fscrypt_inode_info_addr(const struct inode *inode) 200 + { 201 + if (inode->i_sb->s_cop->inode_info_offs == 0) 202 + return (struct fscrypt_inode_info **)&inode->i_crypt_info; 203 + return (void *)inode + inode->i_sb->s_cop->inode_info_offs; 204 + } 205 + 204 206 /* 205 207 * Load the inode's fscrypt info pointer, using a raw dereference. Since this 206 208 * uses a raw dereference with no memory barrier, it is appropriate to use only ··· 219 205 static inline struct fscrypt_inode_info * 220 206 fscrypt_get_inode_info_raw(const struct inode *inode) 221 207 { 222 - struct fscrypt_inode_info *ci = inode->i_crypt_info; 208 + struct fscrypt_inode_info *ci = *fscrypt_inode_info_addr(inode); 223 209 224 210 VFS_WARN_ON_ONCE(ci == NULL); 225 211 return ci; ··· 230 216 { 231 217 /* 232 218 * Pairs with the cmpxchg_release() in fscrypt_setup_encryption_info(). 233 - * I.e., another task may publish ->i_crypt_info concurrently, executing 234 - * a RELEASE barrier. We need to use smp_load_acquire() here to safely 219 + * I.e., another task may publish the fscrypt info concurrently, 220 + * executing a RELEASE barrier. Use smp_load_acquire() here to safely 235 221 * ACQUIRE the memory the other task published. 236 222 */ 237 - return smp_load_acquire(&inode->i_crypt_info); 223 + return smp_load_acquire(fscrypt_inode_info_addr(inode)); 238 224 } 239 225 240 226 /**