aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config/kernel-blkdev.m457
-rw-r--r--include/os/linux/kernel/linux/blkdev_compat.h36
-rw-r--r--module/os/linux/zfs/vdev_disk.c2
-rw-r--r--module/os/linux/zfs/zvol_os.c2
4 files changed, 95 insertions, 2 deletions
diff --git a/config/kernel-blkdev.m4 b/config/kernel-blkdev.m4
index 2644555f5..530b49f48 100644
--- a/config/kernel-blkdev.m4
+++ b/config/kernel-blkdev.m4
@@ -78,6 +78,59 @@ AC_DEFUN([ZFS_AC_KERNEL_BLKDEV_REREAD_PART], [
])
dnl #
+dnl # check_disk_change() was removed in 5.10
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_SRC_BLKDEV_CHECK_DISK_CHANGE], [
+ ZFS_LINUX_TEST_SRC([check_disk_change], [
+ #include <linux/fs.h>
+ #include <linux/blkdev.h>
+ ], [
+ struct block_device *bdev = NULL;
+ bool error;
+
+ error = check_disk_change(bdev);
+ ])
+])
+
+AC_DEFUN([ZFS_AC_KERNEL_BLKDEV_CHECK_DISK_CHANGE], [
+ AC_MSG_CHECKING([whether check_disk_change() exists])
+ ZFS_LINUX_TEST_RESULT([check_disk_change], [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_CHECK_DISK_CHANGE, 1,
+ [check_disk_change() exists])
+ ], [
+ AC_MSG_RESULT(no)
+ ])
+])
+
+dnl #
+dnl # 5.10 API, check_disk_change() is removed, in favor of
+dnl # bdev_check_media_change(), which doesn't force revalidation
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_SRC_BLKDEV_BDEV_CHECK_MEDIA_CHANGE], [
+ ZFS_LINUX_TEST_SRC([bdev_check_media_change], [
+ #include <linux/fs.h>
+ #include <linux/blkdev.h>
+ ], [
+ struct block_device *bdev = NULL;
+ int error;
+
+ error = bdev_check_media_change(bdev);
+ ])
+])
+
+AC_DEFUN([ZFS_AC_KERNEL_BLKDEV_BDEV_CHECK_MEDIA_CHANGE], [
+ AC_MSG_CHECKING([whether bdev_disk_changed() exists])
+ ZFS_LINUX_TEST_RESULT([bdev_check_media_change], [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_BDEV_CHECK_MEDIA_CHANGE, 1,
+ [bdev_check_media_change() exists])
+ ], [
+ AC_MSG_RESULT(no)
+ ])
+])
+
+dnl #
dnl # 2.6.22 API change
dnl # Single argument invalidate_bdev()
dnl #
@@ -199,6 +252,8 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLKDEV], [
ZFS_AC_KERNEL_SRC_BLKDEV_LOOKUP_BDEV
ZFS_AC_KERNEL_SRC_BLKDEV_BDEV_LOGICAL_BLOCK_SIZE
ZFS_AC_KERNEL_SRC_BLKDEV_BDEV_PHYSICAL_BLOCK_SIZE
+ ZFS_AC_KERNEL_SRC_BLKDEV_CHECK_DISK_CHANGE
+ ZFS_AC_KERNEL_SRC_BLKDEV_BDEV_CHECK_MEDIA_CHANGE
])
AC_DEFUN([ZFS_AC_KERNEL_BLKDEV], [
@@ -209,4 +264,6 @@ AC_DEFUN([ZFS_AC_KERNEL_BLKDEV], [
ZFS_AC_KERNEL_BLKDEV_LOOKUP_BDEV
ZFS_AC_KERNEL_BLKDEV_BDEV_LOGICAL_BLOCK_SIZE
ZFS_AC_KERNEL_BLKDEV_BDEV_PHYSICAL_BLOCK_SIZE
+ ZFS_AC_KERNEL_BLKDEV_CHECK_DISK_CHANGE
+ ZFS_AC_KERNEL_BLKDEV_BDEV_CHECK_MEDIA_CHANGE
])
diff --git a/include/os/linux/kernel/linux/blkdev_compat.h b/include/os/linux/kernel/linux/blkdev_compat.h
index 1cdc300a6..35b775633 100644
--- a/include/os/linux/kernel/linux/blkdev_compat.h
+++ b/include/os/linux/kernel/linux/blkdev_compat.h
@@ -268,12 +268,48 @@ bio_set_bi_error(struct bio *bio, int error)
*
* For older kernels trigger a re-reading of the partition table by calling
* check_disk_change() which calls flush_disk() to invalidate the device.
+ *
+ * For newer kernels (as of 5.10), bdev_check_media_chage is used, in favor of
+ * check_disk_change(), with the modification that invalidation is no longer
+ * forced.
*/
+#ifdef HAVE_CHECK_DISK_CHANGE
+#define zfs_check_media_change(bdev) check_disk_change(bdev)
#ifdef HAVE_BLKDEV_REREAD_PART
#define vdev_bdev_reread_part(bdev) blkdev_reread_part(bdev)
#else
#define vdev_bdev_reread_part(bdev) check_disk_change(bdev)
#endif /* HAVE_BLKDEV_REREAD_PART */
+#else
+#ifdef HAVE_BDEV_CHECK_MEDIA_CHANGE
+static inline int
+zfs_check_media_change(struct block_device *bdev)
+{
+ struct gendisk *gd = bdev->bd_disk;
+ const struct block_device_operations *bdo = gd->fops;
+
+ if (!bdev_check_media_change(bdev))
+ return (0);
+
+ /*
+ * Force revalidation, to mimic the old behavior of
+ * check_disk_change()
+ */
+ if (bdo->revalidate_disk)
+ bdo->revalidate_disk(gd);
+
+ return (0);
+}
+#define vdev_bdev_reread_part(bdev) zfs_check_media_change(bdev)
+#else
+/*
+ * This is encountered if check_disk_change() and bdev_check_media_change()
+ * are not available in the kernel - likely due to an API change that needs
+ * to be chased down.
+ */
+#error "Unsupported kernel: no usable disk change check"
+#endif /* HAVE_BDEV_CHECK_MEDIA_CHANGE */
+#endif /* HAVE_CHECK_DISK_CHANGE */
/*
* 2.6.27 API change
diff --git a/module/os/linux/zfs/vdev_disk.c b/module/os/linux/zfs/vdev_disk.c
index 858edc63b..7de5c30f7 100644
--- a/module/os/linux/zfs/vdev_disk.c
+++ b/module/os/linux/zfs/vdev_disk.c
@@ -791,7 +791,7 @@ vdev_disk_io_done(zio_t *zio)
vdev_t *v = zio->io_vd;
vdev_disk_t *vd = v->vdev_tsd;
- if (check_disk_change(vd->vd_bdev)) {
+ if (zfs_check_media_change(vd->vd_bdev)) {
invalidate_bdev(vd->vd_bdev);
v->vdev_remove_wanted = B_TRUE;
spa_async_request(zio->io_spa, SPA_ASYNC_REMOVE);
diff --git a/module/os/linux/zfs/zvol_os.c b/module/os/linux/zfs/zvol_os.c
index 2422b331b..0cd2d415c 100644
--- a/module/os/linux/zfs/zvol_os.c
+++ b/module/os/linux/zfs/zvol_os.c
@@ -503,7 +503,7 @@ zvol_open(struct block_device *bdev, fmode_t flag)
if (drop_suspend)
rw_exit(&zv->zv_suspend_lock);
- check_disk_change(bdev);
+ zfs_check_media_change(bdev);
return (0);