diff --git a/include/os/linux/zfs/sys/zpl.h b/include/os/linux/zfs/sys/zpl.h
index 8b0e79afb0..b62ab5eec8 100644
--- a/include/os/linux/zfs/sys/zpl.h
+++ b/include/os/linux/zfs/sys/zpl.h
@@ -193,6 +193,41 @@ extern int zpl_clone_file_range(struct file *src_file, loff_t src_off,
 extern int zpl_dedupe_file_range(struct file *src_file, loff_t src_off,
     struct file *dst_file, loff_t dst_off, uint64_t len);
 
+/* compat for FICLONE/FICLONERANGE/FIDEDUPERANGE ioctls */
+typedef struct {
+	int64_t		fcr_src_fd;
+	uint64_t	fcr_src_offset;
+	uint64_t	fcr_src_length;
+	uint64_t	fcr_dest_offset;
+} zfs_ioc_compat_file_clone_range_t;
+
+typedef struct {
+	int64_t		fdri_dest_fd;
+	uint64_t	fdri_dest_offset;
+	uint64_t	fdri_bytes_deduped;
+	int32_t		fdri_status;
+	uint32_t	fdri_reserved;
+} zfs_ioc_compat_dedupe_range_info_t;
+
+typedef struct {
+	uint64_t	fdr_src_offset;
+	uint64_t	fdr_src_length;
+	uint16_t	fdr_dest_count;
+	uint16_t	fdr_reserved1;
+	uint32_t	fdr_reserved2;
+	zfs_ioc_compat_dedupe_range_info_t	fdr_info[];
+} zfs_ioc_compat_dedupe_range_t;
+
+#define	ZFS_IOC_COMPAT_FICLONE		_IOW(0x94, 9, int)
+#define	ZFS_IOC_COMPAT_FICLONERANGE \
+    _IOW(0x94, 13, zfs_ioc_compat_file_clone_range_t)
+#define	ZFS_IOC_COMPAT_FIDEDUPERANGE \
+    _IOWR(0x94, 54, zfs_ioc_compat_dedupe_range_t)
+
+extern long zpl_ioctl_ficlone(struct file *filp, void *arg);
+extern long zpl_ioctl_ficlonerange(struct file *filp, void *arg);
+extern long zpl_ioctl_fideduperange(struct file *filp, void *arg);
+
 
 #if defined(HAVE_INODE_TIMESTAMP_TRUNCATE)
 #define	zpl_inode_timestamp_truncate(ts, ip)	timestamp_truncate(ts, ip)
diff --git a/module/os/linux/zfs/zpl_file.c b/module/os/linux/zfs/zpl_file.c
index 92b603e98a..87a248af83 100644
--- a/module/os/linux/zfs/zpl_file.c
+++ b/module/os/linux/zfs/zpl_file.c
@@ -1257,6 +1257,12 @@ zpl_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 		return (zpl_ioctl_getdosflags(filp, (void *)arg));
 	case ZFS_IOC_SETDOSFLAGS:
 		return (zpl_ioctl_setdosflags(filp, (void *)arg));
+	case ZFS_IOC_COMPAT_FICLONE:
+		return (zpl_ioctl_ficlone(filp, (void *)arg));
+	case ZFS_IOC_COMPAT_FICLONERANGE:
+		return (zpl_ioctl_ficlonerange(filp, (void *)arg));
+	case ZFS_IOC_COMPAT_FIDEDUPERANGE:
+		return (zpl_ioctl_fideduperange(filp, (void *)arg));
 	default:
 		return (-ENOTTY);
 	}
diff --git a/module/os/linux/zfs/zpl_file_range.c b/module/os/linux/zfs/zpl_file_range.c
index db387a7481..aad502a809 100644
--- a/module/os/linux/zfs/zpl_file_range.c
+++ b/module/os/linux/zfs/zpl_file_range.c
@@ -181,3 +181,82 @@ zpl_dedupe_file_range(struct file *src_file, loff_t src_off,
 	return (-EOPNOTSUPP);
 }
 #endif /* HAVE_VFS_DEDUPE_FILE_RANGE */
+
+/* Entry point for FICLONE, before Linux 4.5. */
+long
+zpl_ioctl_ficlone(struct file *dst_file, void *arg)
+{
+	unsigned long sfd = (unsigned long)arg;
+
+	struct file *src_file = fget(sfd);
+	if (src_file == NULL)
+		return (-EBADF);
+
+	if (dst_file->f_op != src_file->f_op)
+		return (-EXDEV);
+
+	size_t len = i_size_read(file_inode(src_file));
+
+	ssize_t ret =
+	    __zpl_clone_file_range(src_file, 0, dst_file, 0, len);
+
+	fput(src_file);
+
+	if (ret < 0) {
+		if (ret == -EOPNOTSUPP)
+			return (-ENOTTY);
+		return (ret);
+	}
+
+	if (ret != len)
+		return (-EINVAL);
+
+	return (0);
+}
+
+/* Entry point for FICLONERANGE, before Linux 4.5. */
+long
+zpl_ioctl_ficlonerange(struct file *dst_file, void __user *arg)
+{
+	zfs_ioc_compat_file_clone_range_t fcr;
+
+	if (copy_from_user(&fcr, arg, sizeof (fcr)))
+		return (-EFAULT);
+
+	struct file *src_file = fget(fcr.fcr_src_fd);
+	if (src_file == NULL)
+		return (-EBADF);
+
+	if (dst_file->f_op != src_file->f_op)
+		return (-EXDEV);
+
+	size_t len = fcr.fcr_src_length;
+	if (len == 0)
+		len = i_size_read(file_inode(src_file)) - fcr.fcr_src_offset;
+
+	ssize_t ret = __zpl_clone_file_range(src_file, fcr.fcr_src_offset,
+	    dst_file, fcr.fcr_dest_offset, len);
+
+	fput(src_file);
+
+	if (ret < 0) {
+		if (ret == -EOPNOTSUPP)
+			return (-ENOTTY);
+		return (ret);
+	}
+
+	if (ret != len)
+		return (-EINVAL);
+
+	return (0);
+}
+
+/* Entry point for FIDEDUPERANGE, before Linux 4.5. */
+long
+zpl_ioctl_fideduperange(struct file *filp, void *arg)
+{
+	(void) arg;
+
+	/* No support for dedup yet */
+	return (-ENOTTY);
+}