Re: [PATCH RFC DRAFT DOESNOTBUILD] inode: free up more space

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, 2025-07-15 at 16:35 +0200, Christian Brauner wrote:
> struct inode is bloated as everyone is aware and we should try and
> shrink it as that's potentially a lot of memory savings. I've already
> freed up around 8 bytes but we can probably do better.
> 
> There's a bunch of stuff that got shoved into struct inode that I don't
> think deserves a spot in there. There are two members I'm currently
> particularly interested in:
> 
> (1) #ifdef CONFIG_FS_ENCRYPTION
>             struct fscrypt_inode_info *i_crypt_info;
>     #endif
> 
>     ceph, ext4, f2fs, ubifs
> 
> (2) #ifdef CONFIG_FS_VERITY
>             struct fsverity_info *i_verity_info;
>     #endif
> 
>     btrfs, ext4, f2fs
> 
> So we have 4 users for fscrypt and 3 users for fsverity with both
> features having been around for a decent amount of time.
> 
> For all other filesystems the 16 bytes are just wasted bloating inodes
> for every pseudo filesystem and most other regular filesystems.
> 
> We should be able to move both of these out of struct inode by adding
> inode operations and making it the filesystem's responsibility to
> accommodate the information in their respective inodes.
> 
> Unless there are severe performance penalties for the extra pointer
> dereferences getting our hands on 16 bytes is a good reason to at least
> consider doing this.
> 
> I've drafted one way of doing this using ext4 as my victim^wexample. I'd
> like to hear some early feedback whether this is something we would want
> to pursue.
> 
> Build failures very much expected!
> 
> Not-Signed-off-by: Christian Brauner <brauner@xxxxxxxxxx>
> ---
>  fs/crypto/bio.c             |  2 +-
>  fs/crypto/crypto.c          |  8 ++++----
>  fs/crypto/fname.c           |  8 ++++----
>  fs/crypto/fscrypt_private.h |  3 +--
>  fs/crypto/hooks.c           |  2 +-
>  fs/crypto/inline_crypt.c    | 10 +++++-----
>  fs/crypto/keysetup.c        | 21 ++++----------------
>  fs/crypto/policy.c          |  8 ++++----
>  fs/ext4/ext4.h              |  9 +++++++++
>  fs/ext4/file.c              |  4 ++++
>  fs/ext4/namei.c             | 22 +++++++++++++++++++++
>  fs/ext4/super.c             |  6 +++++-
>  fs/ext4/symlink.c           | 12 ++++++++++++
>  include/linux/fs.h          |  9 +++++----
>  include/linux/fscrypt.h     | 47 ++++++++++++++++++++++++++++++---------------
>  15 files changed, 112 insertions(+), 59 deletions(-)
> 
> diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c
> index 0ad8c30b8fa5..f541e6b3a9cc 100644
> --- a/fs/crypto/bio.c
> +++ b/fs/crypto/bio.c
> @@ -111,7 +111,7 @@ static int fscrypt_zeroout_range_inline_crypt(const struct inode *inode,
>  int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk,
>  			  sector_t pblk, unsigned int len)
>  {
> -	const struct fscrypt_inode_info *ci = inode->i_crypt_info;
> +	const struct fscrypt_inode_info *ci = inode->i_op->get_fscrypt(inode);
>  	const unsigned int du_bits = ci->ci_data_unit_bits;
>  	const unsigned int du_size = 1U << du_bits;
>  	const unsigned int du_per_page_bits = PAGE_SHIFT - du_bits;
> diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c
> index b74b5937e695..c480f6867101 100644
> --- a/fs/crypto/crypto.c
> +++ b/fs/crypto/crypto.c
> @@ -181,7 +181,7 @@ struct page *fscrypt_encrypt_pagecache_blocks(struct folio *folio,
>  		size_t len, size_t offs, gfp_t gfp_flags)
>  {
>  	const struct inode *inode = folio->mapping->host;
> -	const struct fscrypt_inode_info *ci = inode->i_crypt_info;
> +	const struct fscrypt_inode_info *ci = inode->i_op->get_fscrypt(inode);
>  	const unsigned int du_bits = ci->ci_data_unit_bits;
>  	const unsigned int du_size = 1U << du_bits;
>  	struct page *ciphertext_page;
> @@ -241,7 +241,7 @@ int fscrypt_encrypt_block_inplace(const struct inode *inode, struct page *page,
>  {
>  	if (WARN_ON_ONCE(inode->i_sb->s_cop->supports_subblock_data_units))
>  		return -EOPNOTSUPP;
> -	return fscrypt_crypt_data_unit(inode->i_crypt_info, FS_ENCRYPT,
> +	return fscrypt_crypt_data_unit(inode->i_op->get_fscrypt(inode), FS_ENCRYPT,
>  				       lblk_num, page, page, len, offs,
>  				       gfp_flags);
>  }
> @@ -265,7 +265,7 @@ int fscrypt_decrypt_pagecache_blocks(struct folio *folio, size_t len,
>  				     size_t offs)
>  {
>  	const struct inode *inode = folio->mapping->host;
> -	const struct fscrypt_inode_info *ci = inode->i_crypt_info;
> +	const struct fscrypt_inode_info *ci = inode->i_op->get_fscrypt(inode);
>  	const unsigned int du_bits = ci->ci_data_unit_bits;
>  	const unsigned int du_size = 1U << du_bits;
>  	u64 index = ((u64)folio->index << (PAGE_SHIFT - du_bits)) +
> @@ -316,7 +316,7 @@ int fscrypt_decrypt_block_inplace(const struct inode *inode, struct page *page,
>  {
>  	if (WARN_ON_ONCE(inode->i_sb->s_cop->supports_subblock_data_units))
>  		return -EOPNOTSUPP;
> -	return fscrypt_crypt_data_unit(inode->i_crypt_info, FS_DECRYPT,
> +	return fscrypt_crypt_data_unit(inode->i_op->get_fscrypt(inode), FS_DECRYPT,
>  				       lblk_num, page, page, len, offs,
>  				       GFP_NOFS);
>  }
> diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c
> index 010f9c0a4c2f..a0317df113a9 100644
> --- a/fs/crypto/fname.c
> +++ b/fs/crypto/fname.c
> @@ -94,7 +94,7 @@ int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname,
>  {
>  	struct skcipher_request *req = NULL;
>  	DECLARE_CRYPTO_WAIT(wait);
> -	const struct fscrypt_inode_info *ci = inode->i_crypt_info;
> +	const struct fscrypt_inode_info *ci = inode->i_op->get_fscrypt(inode);
>  	struct crypto_skcipher *tfm = ci->ci_enc_key.tfm;
>  	union fscrypt_iv iv;
>  	struct scatterlist sg;
> @@ -151,7 +151,7 @@ static int fname_decrypt(const struct inode *inode,
>  	struct skcipher_request *req = NULL;
>  	DECLARE_CRYPTO_WAIT(wait);
>  	struct scatterlist src_sg, dst_sg;
> -	const struct fscrypt_inode_info *ci = inode->i_crypt_info;
> +	const struct fscrypt_inode_info *ci = inode->i_op->get_fscrypt(inode);
>  	struct crypto_skcipher *tfm = ci->ci_enc_key.tfm;
>  	union fscrypt_iv iv;
>  	int res;
> @@ -293,7 +293,7 @@ bool __fscrypt_fname_encrypted_size(const union fscrypt_policy *policy,
>  bool fscrypt_fname_encrypted_size(const struct inode *inode, u32 orig_len,
>  				  u32 max_len, u32 *encrypted_len_ret)
>  {
> -	return __fscrypt_fname_encrypted_size(&inode->i_crypt_info->ci_policy,
> +	return __fscrypt_fname_encrypted_size(&inode->i_op->get_fscrypt(inode)->ci_policy,
>  					      orig_len, max_len,
>  					      encrypted_len_ret);
>  }
> @@ -562,7 +562,7 @@ EXPORT_SYMBOL_GPL(fscrypt_match_name);
>   */
>  u64 fscrypt_fname_siphash(const struct inode *dir, const struct qstr *name)
>  {
> -	const struct fscrypt_inode_info *ci = dir->i_crypt_info;
> +	const struct fscrypt_inode_info *ci = dir->i_op->get_fscrypt(dir);
>  
>  	WARN_ON_ONCE(!ci->ci_dirhash_key_initialized);
>  
> diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h
> index c1d92074b65c..ddc3c86494cf 100644
> --- a/fs/crypto/fscrypt_private.h
> +++ b/fs/crypto/fscrypt_private.h
> @@ -231,8 +231,7 @@ struct fscrypt_prepared_key {
>   * fscrypt_inode_info - the "encryption key" for an inode
>   *
>   * When an encrypted file's key is made available, an instance of this struct is
> - * allocated and stored in ->i_crypt_info.  Once created, it remains until the
> - * inode is evicted.
> + * allocated and stored.  Once created, it remains until the inode is evicted.
>   */
>  struct fscrypt_inode_info {
>  
> diff --git a/fs/crypto/hooks.c b/fs/crypto/hooks.c
> index d8d5049b8fe1..a45763da352e 100644
> --- a/fs/crypto/hooks.c
> +++ b/fs/crypto/hooks.c
> @@ -197,7 +197,7 @@ int fscrypt_prepare_setflags(struct inode *inode,
>  		err = fscrypt_require_key(inode);
>  		if (err)
>  			return err;
> -		ci = inode->i_crypt_info;
> +		ci = inode->i_op->get_fscrypt(inode);
>  		if (ci->ci_policy.version != FSCRYPT_POLICY_V2)
>  			return -EINVAL;
>  		mk = ci->ci_master_key;
> diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c
> index 1d008c440cb6..f5a6560a9c2e 100644
> --- a/fs/crypto/inline_crypt.c
> +++ b/fs/crypto/inline_crypt.c
> @@ -262,7 +262,7 @@ int fscrypt_derive_sw_secret(struct super_block *sb,
>  
>  bool __fscrypt_inode_uses_inline_crypto(const struct inode *inode)
>  {
> -	return inode->i_crypt_info->ci_inlinecrypt;
> +	return inode->i_op->get_fscrypt(inode)->ci_inlinecrypt;
>  }
>  EXPORT_SYMBOL_GPL(__fscrypt_inode_uses_inline_crypto);
>  
> @@ -306,7 +306,7 @@ void fscrypt_set_bio_crypt_ctx(struct bio *bio, const struct inode *inode,
>  
>  	if (!fscrypt_inode_uses_inline_crypto(inode))
>  		return;
> -	ci = inode->i_crypt_info;
> +	ci = inode->i_op->get_fscrypt(inode);
>  
>  	fscrypt_generate_dun(ci, first_lblk, dun);
>  	bio_crypt_set_ctx(bio, ci->ci_enc_key.blk_key, dun, gfp_mask);
> @@ -396,10 +396,10 @@ bool fscrypt_mergeable_bio(struct bio *bio, const struct inode *inode,
>  	 * uses the same pointer.  I.e., there's currently no need to support
>  	 * merging requests where the keys are the same but the pointers differ.
>  	 */
> -	if (bc->bc_key != inode->i_crypt_info->ci_enc_key.blk_key)
> +	if (bc->bc_key != inode->i_op->get_fscrypt(inode)->ci_enc_key.blk_key)
>  		return false;
>  
> -	fscrypt_generate_dun(inode->i_crypt_info, next_lblk, next_dun);
> +	fscrypt_generate_dun(inode->i_op->get_fscrypt(inode), next_lblk, next_dun);
>  	return bio_crypt_dun_is_contiguous(bc, bio->bi_iter.bi_size, next_dun);
>  }
>  EXPORT_SYMBOL_GPL(fscrypt_mergeable_bio);
> @@ -501,7 +501,7 @@ u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk, u64 nr_blocks)
>  	if (nr_blocks <= 1)
>  		return nr_blocks;
>  
> -	ci = inode->i_crypt_info;
> +	ci = inode->i_op->get_fscrypt(inode);
>  	if (!(fscrypt_policy_flags(&ci->ci_policy) &
>  	      FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32))
>  		return nr_blocks;
> diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c
> index 0d71843af946..90e1ea83c573 100644
> --- a/fs/crypto/keysetup.c
> +++ b/fs/crypto/keysetup.c
> @@ -568,7 +568,7 @@ static int setup_file_encryption_key(struct fscrypt_inode_info *ci,
>  	return err;
>  }
>  
> -static void put_crypt_info(struct fscrypt_inode_info *ci)
> +void put_crypt_info(struct fscrypt_inode_info *ci)
>  {
>  	struct fscrypt_master_key *mk;
>  
> @@ -597,6 +597,7 @@ static void put_crypt_info(struct fscrypt_inode_info *ci)
>  	memzero_explicit(ci, sizeof(*ci));
>  	kmem_cache_free(fscrypt_inode_info_cachep, ci);
>  }
> +EXPORT_SYMBOL(put_crypt_info);
>  
>  static int
>  fscrypt_setup_encryption_info(struct inode *inode,
> @@ -644,7 +645,7 @@ fscrypt_setup_encryption_info(struct inode *inode,
>  	 * fscrypt_get_inode_info().  I.e., here we publish ->i_crypt_info with
>  	 * a RELEASE barrier so that other tasks can ACQUIRE it.
>  	 */
> -	if (cmpxchg_release(&inode->i_crypt_info, NULL, crypt_info) == NULL) {
> +	if (!inode->i_op->set_fscrypt(crypt_info, inode)) {
>  		/*
>  		 * We won the race and set ->i_crypt_info to our crypt_info.
>  		 * Now link it into the master key's inode list.
> @@ -788,20 +789,6 @@ int fscrypt_prepare_new_inode(struct inode *dir, struct inode *inode,
>  }
>  EXPORT_SYMBOL_GPL(fscrypt_prepare_new_inode);
>  
> -/**
> - * fscrypt_put_encryption_info() - free most of an inode's fscrypt data
> - * @inode: an inode being evicted
> - *
> - * Free the inode's fscrypt_inode_info.  Filesystems must call this when the
> - * inode is being evicted.  An RCU grace period need not have elapsed yet.
> - */
> -void fscrypt_put_encryption_info(struct inode *inode)
> -{
> -	put_crypt_info(inode->i_crypt_info);
> -	inode->i_crypt_info = NULL;
> -}
> -EXPORT_SYMBOL(fscrypt_put_encryption_info);
> -
>  /**
>   * fscrypt_free_inode() - free an inode's fscrypt data requiring RCU delay
>   * @inode: an inode being freed
> @@ -830,7 +817,7 @@ EXPORT_SYMBOL(fscrypt_free_inode);
>   */
>  int fscrypt_drop_inode(struct inode *inode)
>  {
> -	const struct fscrypt_inode_info *ci = fscrypt_get_inode_info(inode);
> +	const struct fscrypt_inode_info *ci = inode->i_op->get_fscrypt(inode);
>  
>  	/*
>  	 * If ci is NULL, then the inode doesn't have an encryption key set up
> diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c
> index 701259991277..694d1ed26eeb 100644
> --- a/fs/crypto/policy.c
> +++ b/fs/crypto/policy.c
> @@ -436,7 +436,7 @@ static int fscrypt_get_policy(struct inode *inode, union fscrypt_policy *policy)
>  	union fscrypt_context ctx;
>  	int ret;
>  
> -	ci = fscrypt_get_inode_info(inode);
> +	ci = inode->i_op->get_fscrypt(inode);
>  	if (ci) {
>  		/* key available, use the cached policy */
>  		*policy = ci->ci_policy;
> @@ -725,7 +725,7 @@ const union fscrypt_policy *fscrypt_policy_to_inherit(struct inode *dir)
>  		err = fscrypt_require_key(dir);
>  		if (err)
>  			return ERR_PTR(err);
> -		return &dir->i_crypt_info->ci_policy;
> +		return &dir->i_op->get_fscrypt(dir)->ci_policy;
>  	}
>  
>  	return fscrypt_get_dummy_policy(dir->i_sb);
> @@ -744,7 +744,7 @@ const union fscrypt_policy *fscrypt_policy_to_inherit(struct inode *dir)
>   */
>  int fscrypt_context_for_new_inode(void *ctx, struct inode *inode)
>  {
> -	struct fscrypt_inode_info *ci = inode->i_crypt_info;
> +	struct fscrypt_inode_info *ci = inode->i_op->get_fscrypt(inode);
>  
>  	BUILD_BUG_ON(sizeof(union fscrypt_context) !=
>  			FSCRYPT_SET_CONTEXT_MAX_SIZE);
> @@ -769,7 +769,7 @@ EXPORT_SYMBOL_GPL(fscrypt_context_for_new_inode);
>   */
>  int fscrypt_set_context(struct inode *inode, void *fs_data)
>  {
> -	struct fscrypt_inode_info *ci = inode->i_crypt_info;
> +	struct fscrypt_inode_info *ci = inode->i_op->get_fscrypt(inode);
>  	union fscrypt_context ctx;
>  	int ctxsize;
>  
> diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
> index 18373de980f2..34685eec6245 100644
> --- a/fs/ext4/ext4.h
> +++ b/fs/ext4/ext4.h
> @@ -1197,6 +1197,10 @@ struct ext4_inode_info {
>  	__u32 i_csum_seed;
>  
>  	kprojid_t i_projid;
> +
> +#ifdef CONFIG_FS_ENCRYPTION
> +	struct fscrypt_inode_info	*i_fscrypt_info;
> +#endif
>  };
>  
>  /*
> @@ -3904,6 +3908,11 @@ static inline bool ext4_inode_can_atomic_write(struct inode *inode)
>  extern int ext4_block_write_begin(handle_t *handle, struct folio *folio,
>  				  loff_t pos, unsigned len,
>  				  get_block_t *get_block);
> +#ifdef CONFIG_FS_ENCRYPTION
> +struct fscrypt_inode_info *ext4_get_fscrypt(const struct inode *inode);
> +int ext4_set_fscrypt(struct fscrypt_inode_info *fscrypt_info,struct inode *inode);
> +#endif
> +
>  #endif	/* __KERNEL__ */
>  
>  #define EFSBADCRC	EBADMSG		/* Bad CRC detected */
> diff --git a/fs/ext4/file.c b/fs/ext4/file.c
> index 21df81347147..676d33a7d842 100644
> --- a/fs/ext4/file.c
> +++ b/fs/ext4/file.c
> @@ -989,5 +989,9 @@ const struct inode_operations ext4_file_inode_operations = {
>  	.fiemap		= ext4_fiemap,
>  	.fileattr_get	= ext4_fileattr_get,
>  	.fileattr_set	= ext4_fileattr_set,
> +#ifdef CONFIG_FS_ENCRYPTION
> +	.get_fscrypt	= ext4_get_fscrypt,
> +	.set_fscrypt	= ext4_set_fscrypt,
> +#endif
>  };
>  
> diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
> index a178ac229489..a27c5925c836 100644
> --- a/fs/ext4/namei.c
> +++ b/fs/ext4/namei.c
> @@ -4203,6 +4203,20 @@ static int ext4_rename2(struct mnt_idmap *idmap,
>  	return ext4_rename(idmap, old_dir, old_dentry, new_dir, new_dentry, flags);
>  }
>  
> +#ifdef CONFIG_FS_ENCRYPTION
> +struct fscrypt_inode_info *ext4_get_fscrypt(const struct inode *inode)
> +{
> +	struct ext4_inode_info *ei = EXT4_I(inode);
> +	return fscrypt_inode_info_get(&ei->i_fscrypt_info);
> +}
> +
> +int ext4_set_fscrypt(struct fscrypt_inode_info *fscrypt_info, struct inode *inode)
> +{
> +	struct ext4_inode_info *ei = EXT4_I(inode);
> +	return fscrypt_inode_info_set(fscrypt_info, &ei->i_fscrypt_info);
> +}
> +#endif
> +
>  /*
>   * directories can handle most operations...
>   */
> @@ -4225,6 +4239,10 @@ const struct inode_operations ext4_dir_inode_operations = {
>  	.fiemap         = ext4_fiemap,
>  	.fileattr_get	= ext4_fileattr_get,
>  	.fileattr_set	= ext4_fileattr_set,
> +#ifdef CONFIG_FS_ENCRYPTION
> +	.get_fscrypt	= ext4_get_fscrypt,
> +	.set_fscrypt	= ext4_set_fscrypt,
> +#endif
>  };
>  
>  const struct inode_operations ext4_special_inode_operations = {
> @@ -4233,4 +4251,8 @@ const struct inode_operations ext4_special_inode_operations = {
>  	.listxattr	= ext4_listxattr,
>  	.get_inode_acl	= ext4_get_acl,
>  	.set_acl	= ext4_set_acl,
> +#ifdef CONFIG_FS_ENCRYPTION
> +	.get_fscrypt	= ext4_get_fscrypt,
> +	.set_fscrypt	= ext4_set_fscrypt,
> +#endif
>  };
> diff --git a/fs/ext4/super.c b/fs/ext4/super.c
> index c7d39da7e733..972b057b0d00 100644
> --- a/fs/ext4/super.c
> +++ b/fs/ext4/super.c
> @@ -1412,6 +1412,9 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
>  	INIT_WORK(&ei->i_rsv_conversion_work, ext4_end_io_rsv_work);
>  	ext4_fc_init_inode(&ei->vfs_inode);
>  	spin_lock_init(&ei->i_fc_lock);
> +#ifdef CONFIG_FS_ENCRYPTION
> +	ei->i_fscrypt_info = NULL;
> +#endif
>  	return &ei->vfs_inode;
>  }
>  
> @@ -1509,7 +1512,8 @@ void ext4_clear_inode(struct inode *inode)
>  		jbd2_free_inode(EXT4_I(inode)->jinode);
>  		EXT4_I(inode)->jinode = NULL;
>  	}
> -	fscrypt_put_encryption_info(inode);
> +	put_crypt_info(EXT4_I(inode)->i_fscrypt_info);
> +	EXT4_I(inode)->i_fscrypt_info = NULL;
>  	fsverity_cleanup_inode(inode);
>  }
>  
> diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c
> index 645240cc0229..ee3f71e406ce 100644
> --- a/fs/ext4/symlink.c
> +++ b/fs/ext4/symlink.c
> @@ -119,6 +119,10 @@ const struct inode_operations ext4_encrypted_symlink_inode_operations = {
>  	.setattr	= ext4_setattr,
>  	.getattr	= ext4_encrypted_symlink_getattr,
>  	.listxattr	= ext4_listxattr,
> +#ifdef CONFIG_FS_ENCRYPTION
> +	.get_fscrypt	= ext4_get_fscrypt,
> +	.set_fscrypt	= ext4_set_fscrypt,
> +#endif
>  };
>  
>  const struct inode_operations ext4_symlink_inode_operations = {
> @@ -126,6 +130,10 @@ const struct inode_operations ext4_symlink_inode_operations = {
>  	.setattr	= ext4_setattr,
>  	.getattr	= ext4_getattr,
>  	.listxattr	= ext4_listxattr,
> +#ifdef CONFIG_FS_ENCRYPTION
> +	.get_fscrypt	= ext4_get_fscrypt,
> +	.set_fscrypt	= ext4_set_fscrypt,
> +#endif
>  };
>  
>  const struct inode_operations ext4_fast_symlink_inode_operations = {
> @@ -133,4 +141,8 @@ const struct inode_operations ext4_fast_symlink_inode_operations = {
>  	.setattr	= ext4_setattr,
>  	.getattr	= ext4_getattr,
>  	.listxattr	= ext4_listxattr,
> +#ifdef CONFIG_FS_ENCRYPTION
> +	.get_fscrypt	= ext4_get_fscrypt,
> +	.set_fscrypt	= ext4_set_fscrypt,
> +#endif
>  };
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index 96c7925a6551..600b878f41ab 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -778,10 +778,6 @@ struct inode {
>  	struct fsnotify_mark_connector __rcu	*i_fsnotify_marks;
>  #endif
>  
> -#ifdef CONFIG_FS_ENCRYPTION
> -	struct fscrypt_inode_info	*i_crypt_info;
> -#endif
> -
>  #ifdef CONFIG_FS_VERITY
>  	struct fsverity_info	*i_verity_info;
>  #endif
> @@ -2257,6 +2253,11 @@ struct inode_operations {
>  			    struct dentry *dentry, struct fileattr *fa);
>  	int (*fileattr_get)(struct dentry *dentry, struct fileattr *fa);
>  	struct offset_ctx *(*get_offset_ctx)(struct inode *inode);
> +#ifdef CONFIG_FS_ENCRYPTION
> +	struct fscrypt_inode_info *(*get_fscrypt)(const struct inode *inode);
> +	int (*set_fscrypt)(struct fscrypt_inode_info *fscrypt_info,
> +			   struct inode *inode);
> +#endif
>  } ____cacheline_aligned;
>  
>  /* Did the driver provide valid mmap hook configuration? */
> diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h
> index 56fad33043d5..7ac612fec6bb 100644
> --- a/include/linux/fscrypt.h
> +++ b/include/linux/fscrypt.h
> @@ -195,18 +195,6 @@ struct fscrypt_operations {
>  int fscrypt_d_revalidate(struct inode *dir, const struct qstr *name,
>  			 struct dentry *dentry, unsigned int flags);
>  
> -static inline struct fscrypt_inode_info *
> -fscrypt_get_inode_info(const struct inode *inode)
> -{
> -	/*
> -	 * Pairs with the cmpxchg_release() in fscrypt_setup_encryption_info().
> -	 * I.e., another task may publish ->i_crypt_info concurrently, executing
> -	 * a RELEASE barrier.  We need to use smp_load_acquire() here to safely
> -	 * ACQUIRE the memory the other task published.
> -	 */
> -	return smp_load_acquire(&inode->i_crypt_info);
> -}
> -
>  /**
>   * fscrypt_needs_contents_encryption() - check whether an inode needs
>   *					 contents encryption
> @@ -385,7 +373,7 @@ int fscrypt_ioctl_get_key_status(struct file *filp, void __user *arg);
>  /* keysetup.c */
>  int fscrypt_prepare_new_inode(struct inode *dir, struct inode *inode,
>  			      bool *encrypt_ret);
> -void fscrypt_put_encryption_info(struct inode *inode);
> +void put_crypt_info(struct fscrypt_inode_info *ci);
>  void fscrypt_free_inode(struct inode *inode);
>  int fscrypt_drop_inode(struct inode *inode);
>  
> @@ -446,10 +434,37 @@ static inline void fscrypt_set_ops(struct super_block *sb,
>  {
>  	sb->s_cop = s_cop;
>  }
> +
> +static inline int fscrypt_inode_info_set(struct fscrypt_inode_info *crypt_info,
> +					 struct fscrypt_inode_info **p)
> +{
> +	if (cmpxchg_release(p, NULL, crypt_info) != NULL)
> +		return -EEXIST;
> +	return 0;
> +}
> +
> +static inline struct fscrypt_inode_info *
> +fscrypt_inode_info_get(struct fscrypt_inode_info **crypt_info)
> +{
> +	/*
> +	 * Pairs with the cmpxchg_release() in fscrypt_inode_info_set(). I.e.,
> +	 * another task may publish crypt_info concurrently, executing a
> +	 * RELEASE barrier.  We need to use smp_load_acquire() here to safely
> +	 * ACQUIRE the memory the other task published (could be a READ_ONCE()
> +	 * really).
> +	 */
> +	return smp_load_acquire(crypt_info);
> +}
>  #else  /* !CONFIG_FS_ENCRYPTION */
>  
> +static inline int fscrypt_inode_info_set(struct fscrypt_inode_info *crypt_info,
> +					 struct fscrypt_inode_info **p)
> +{
> +	return 0;
> +}
> +
>  static inline struct fscrypt_inode_info *
> -fscrypt_get_inode_info(const struct inode *inode)
> +fscrypt_inode_info_get(const struct fscrypt_inode_info **crypt_info)
>  {
>  	return NULL;
>  }
> @@ -639,7 +654,7 @@ static inline int fscrypt_prepare_new_inode(struct inode *dir,
>  	return 0;
>  }
>  
> -static inline void fscrypt_put_encryption_info(struct inode *inode)
> +static inline void put_crypt_info(struct fscrypt_inode_info *ci)
>  {
>  	return;
>  }
> @@ -930,7 +945,7 @@ static inline bool fscrypt_inode_uses_fs_layer_crypto(const struct inode *inode)
>   */
>  static inline bool fscrypt_has_encryption_key(const struct inode *inode)
>  {
> -	return fscrypt_get_inode_info(inode) != NULL;
> +	return inode->i_op->get_fscrypt(inode) != NULL;
>  }
>  
>  /**
> 
> ---
> base-commit: 19272b37aa4f83ca52bdf9c16d5d81bdd1354494
> change-id: 20250715-work-inode-fscrypt-2b63b276e793


I like the concept. Debloating struct inode is a great goal, IMO.
Fields that are not generally useful should be in the fs-specific
inodes.

I do wish it weren't quite so cumbersome with having to define
_get/_set operations, but I think it's a reasonable tradeoff to get
these fields out of struct inode.

Cheers!
-- 
Jeff Layton <jlayton@xxxxxxxxxx>





[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [NTFS 3]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [NTFS 3]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux