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

Christian Brauner
2025-07-17T08:32:12Z

On Wed, Jul 16, 2025 at 04:10:30PM +0200, Christoph Hellwig wrote:
> On Wed, Jul 16, 2025 at 03:08:53PM +0100, Matthew Wilcox wrote:
> > struct filemap_inode {
> > struct inode inode;
> > struct address_space i_mapping;
> > struct fscrypt_struct i_fscrypt;
> > struct fsverity_struct i_fsverity;
> > struct quota_struct i_quota;
> > };
> >
> > struct ext4_inode {
> > struct filemap_inode inode;
> > ...
> > };
> >
> > saves any messing with i_ops and offsets.
>
> I still wastest a lot of space for XFS which only needs inode
> and i_mapping of those. As would most ext4 file systems..

We can do a hybrid approach:

diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 2bc6a3ac2b8e..dda45b3f2122 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1198,9 +1198,7 @@ struct ext4_inode_info {

kprojid_t i_projid;

-#ifdef CONFIG_FS_ENCRYPTION
- struct fscrypt_inode_info *i_fscrypt_info;
-#endif
+ struct vfs_inode_adjunct i_adjunct; /* Adjunct data for inode */
};

/*
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 676d33a7d842..f257ac048f3b 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -981,17 +981,19 @@ const struct file_operations ext4_file_operations = {
};

const struct inode_operations ext4_file_inode_operations = {
- .setattr = ext4_setattr,
- .getattr = ext4_file_getattr,
- .listxattr = ext4_listxattr,
- .get_inode_acl = ext4_get_acl,
- .set_acl = ext4_set_acl,
- .fiemap = ext4_fiemap,
- .fileattr_get = ext4_fileattr_get,
- .fileattr_set = ext4_fileattr_set,
+ .i_adjunct_offset = offsetof(struct ext4_inode_info, vfs_inode) -
+ offsetof(struct ext4_inode_info, i_adjunct),
+ .setattr = ext4_setattr,
+ .getattr = ext4_file_getattr,
+ .listxattr = ext4_listxattr,
+ .get_inode_acl = ext4_get_acl,
+ .set_acl = ext4_set_acl,
+ .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,
+ .get_fscrypt = ext4_get_fscrypt,
+ .set_fscrypt = ext4_set_fscrypt,
#endif
};

diff --git a/include/linux/fs.h b/include/linux/fs.h
index d8f242a2f431..c4752c80710e 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -789,6 +789,12 @@ struct inode {
void *i_private; /* fs or device private pointer */
} __randomize_layout;

+struct vfs_inode_adjunct {
+#ifdef CONFIG_FS_ENCRYPTION
+ struct fscrypt_inode_info *i_fscrypt_info;
+#endif
+};
+
static inline void inode_set_cached_link(struct inode *inode, char *link, int linklen)
{
VFS_WARN_ON_INODE(strlen(link) != linklen, inode);
@@ -2217,6 +2223,7 @@ int wrap_directory_iterator(struct file *, struct dir_context *,
{ return wrap_directory_iterator(file, ctx, x); }

struct inode_operations {
+ ptrdiff_t i_adjunct_offset;
struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
const char * (*get_link) (struct dentry *, struct inode *, struct delayed_call *);
int (*permission) (struct mnt_idmap *, struct inode *, int);
diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h
index 1aa474232fa7..fa0080869dc1 100644
--- a/include/linux/fscrypt.h
+++ b/include/linux/fscrypt.h
@@ -195,6 +195,12 @@ 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 *CRYPT_I(struct inode *inode)
+{
+ struct vfs_inode_adjunct *p = ((void *)inode) - inode->i_op->i_adjunct_offset;
+ return p->i_fscrypt_info;
+}
+
static inline int vfs_fscrypt_inode_set(struct fscrypt_inode_info *crypt_info,
struct fscrypt_inode_info **p)
{