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 <linux/fs.h>
+
+		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 6536296d0453..ccffdd51f6da 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);
 }
 
@@ -384,7 +393,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,