diff --git a/config/kernel-inode-free.m4 b/config/kernel-inode-free.m4 new file mode 100644 index 000000000000..ef9e6fc76b22 --- /dev/null +++ b/config/kernel-inode-free.m4 @@ -0,0 +1,25 @@ +AC_DEFUN([ZFS_AC_KERNEL_SRC_INODE_FREE], [ + ZFS_LINUX_TEST_SRC([inode_free], [ + #include + + static void inode_free(struct inode *ip) + { return; } + + static const struct super_operations + iops __attribute__ ((unused)) = { + .free_inode = inode_free, + }; + ],[]) +]) + +AC_DEFUN([ZFS_AC_KERNEL_INODE_FREE], [ + AC_MSG_CHECKING([whether inode_free() is available]) + ZFS_LINUX_TEST_RESULT([inode_free], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_INODE_FREE, 1, + [.inode_free() i_op exists]) + ],[ + AC_MSG_RESULT(no) + ]) +]) + diff --git a/config/kernel.m4 b/config/kernel.m4 index 78f178ff27ac..7d543c521ef9 100644 --- a/config/kernel.m4 +++ b/config/kernel.m4 @@ -72,6 +72,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [ ZFS_AC_KERNEL_SRC_INSERT_INODE_LOCKED ZFS_AC_KERNEL_SRC_TRUNCATE_SETSIZE ZFS_AC_KERNEL_SRC_SECURITY_INODE + ZFS_AC_KERNEL_SRC_INODE_FREE ZFS_AC_KERNEL_SRC_FST_MOUNT ZFS_AC_KERNEL_SRC_SET_NLINK ZFS_AC_KERNEL_SRC_SGET @@ -183,6 +184,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [ ZFS_AC_KERNEL_INSERT_INODE_LOCKED ZFS_AC_KERNEL_TRUNCATE_SETSIZE ZFS_AC_KERNEL_SECURITY_INODE + ZFS_AC_KERNEL_INODE_FREE ZFS_AC_KERNEL_FST_MOUNT ZFS_AC_KERNEL_SET_NLINK ZFS_AC_KERNEL_SGET diff --git a/include/os/linux/zfs/sys/zfs_znode_impl.h b/include/os/linux/zfs/sys/zfs_znode_impl.h index cc8e5150eaf1..b8f44a9b3594 100644 --- a/include/os/linux/zfs/sys/zfs_znode_impl.h +++ b/include/os/linux/zfs/sys/zfs_znode_impl.h @@ -157,6 +157,7 @@ struct znode; extern int zfs_sync(struct super_block *, int, cred_t *); extern int zfs_inode_alloc(struct super_block *, struct inode **ip); extern void zfs_inode_destroy(struct inode *); +extern void zfs_inode_free(struct inode *); extern void zfs_mark_inode_dirty(struct inode *); extern boolean_t zfs_relatime_need_update(const struct inode *); extern zil_replay_func_t *const zfs_replay_vector[TX_MAX_TYPE]; diff --git a/module/os/linux/zfs/zfs_znode_os.c b/module/os/linux/zfs/zfs_znode_os.c index bbaca2f58394..65b8ffe85957 100644 --- a/module/os/linux/zfs/zfs_znode_os.c +++ b/module/os/linux/zfs/zfs_znode_os.c @@ -370,9 +370,14 @@ zfs_inode_alloc(struct super_block *sb, struct inode **ip) return (0); } -/* - * Called in multiple places when an inode should be destroyed. - */ +void +zfs_inode_free(struct inode *ip) +{ + znode_t *zp = ITOZ(ip); + + kmem_cache_free(znode_cache, zp); +} + void zfs_inode_destroy(struct inode *ip) { @@ -395,7 +400,9 @@ zfs_inode_destroy(struct inode *ip) zp->z_xattr_cached = NULL; } - kmem_cache_free(znode_cache, zp); +#ifndef HAVE_INODE_FREE + zfs_inode_free(ip); +#endif } static void diff --git a/module/os/linux/zfs/zpl_super.c b/module/os/linux/zfs/zpl_super.c index 287f5f36f9dd..1e2a24702dc4 100644 --- a/module/os/linux/zfs/zpl_super.c +++ b/module/os/linux/zfs/zpl_super.c @@ -43,7 +43,13 @@ zpl_inode_alloc(struct super_block *sb) return (ip); } -static void +static void __maybe_unused +zpl_inode_free(struct inode *ip) +{ + zfs_inode_free(ip); +} + +static void __maybe_unused zpl_inode_destroy(struct inode *ip) { ASSERT(atomic_read(&ip->i_count) == 0); @@ -89,6 +95,9 @@ zpl_evict_inode(struct inode *ip) truncate_setsize(ip, 0); clear_inode(ip); zfs_inactive(ip); +#ifdef HAVE_INODE_FREE + zfs_inode_destroy(ip); +#endif spl_fstrans_unmark(cookie); } @@ -380,7 +389,11 @@ zpl_prune_sb(uint64_t nr_to_scan, void *arg) const struct super_operations zpl_super_operations = { .alloc_inode = zpl_inode_alloc, +#ifdef HAVE_INODE_FREE + .free_inode = zpl_inode_free, +#else .destroy_inode = zpl_inode_destroy, +#endif .dirty_inode = zpl_dirty_inode, .write_inode = NULL, .evict_inode = zpl_evict_inode,