aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorColeman Kane <[email protected]>2023-08-01 11:37:20 -0400
committerBrian Behlendorf <[email protected]>2023-09-19 08:50:01 -0700
commitd76de9fb170d58f81edac5729c365fc3fd60a22f (patch)
treed3b20f48bd9d5950a8d2898f454882a74493b101
parentc0f075c06b914b02e175f8de670b7b440630c7bc (diff)
Linux 6.5 compat: blkdev changes
Multiple changes to the blkdev API were introduced in Linux 6.5. This includes passing (void* holder) to blkdev_put, adding a new blk_holder_ops* arg to blkdev_get_by_path, adding a new blk_mode_t type that replaces uses of fmode_t, and removing an argument from the release handler on block_device_operations that we weren't using. The open function definition has also changed to take gendisk* and blk_mode_t, so update it accordingly, too. Implement local wrappers for blkdev_get_by_path() and vdev_blkdev_put() so that the in-line calls are cleaner, and place the conditionally-compiled implementation details inside of both of these local wrappers. Both calls are exclusively used within vdev_disk.c, at this time. Add blk_mode_is_open_write() to test FMODE_WRITE / BLK_OPEN_WRITE The wrapper function is now used for testing using the appropriate method for the kernel, whether the open mode is writable or not. Emphasize fmode_t arg in zvol_release is not used Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Coleman Kane <[email protected]> Closes #15099
-rw-r--r--config/kernel-blkdev.m484
-rw-r--r--config/kernel-block-device-operations.m435
-rw-r--r--include/os/linux/kernel/linux/blkdev_compat.h6
-rw-r--r--module/os/linux/zfs/vdev_disk.c65
-rw-r--r--module/os/linux/zfs/zfs_vnops_os.c2
-rw-r--r--module/os/linux/zfs/zpl_ctldir.c2
-rw-r--r--module/os/linux/zfs/zvol_os.c28
7 files changed, 203 insertions, 19 deletions
diff --git a/config/kernel-blkdev.m4 b/config/kernel-blkdev.m4
index 887acee67..e04a2bd2c 100644
--- a/config/kernel-blkdev.m4
+++ b/config/kernel-blkdev.m4
@@ -16,12 +16,63 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLKDEV_GET_BY_PATH], [
])
])
+dnl #
+dnl # 6.5.x API change,
+dnl # blkdev_get_by_path() takes 4 args
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_SRC_BLKDEV_GET_BY_PATH_4ARG], [
+ ZFS_LINUX_TEST_SRC([blkdev_get_by_path_4arg], [
+ #include <linux/fs.h>
+ #include <linux/blkdev.h>
+ ], [
+ struct block_device *bdev __attribute__ ((unused)) = NULL;
+ const char *path = "path";
+ fmode_t mode = 0;
+ void *holder = NULL;
+ struct blk_holder_ops h;
+
+ bdev = blkdev_get_by_path(path, mode, holder, &h);
+ ])
+])
+
AC_DEFUN([ZFS_AC_KERNEL_BLKDEV_GET_BY_PATH], [
- AC_MSG_CHECKING([whether blkdev_get_by_path() exists])
+ AC_MSG_CHECKING([whether blkdev_get_by_path() exists and takes 3 args])
ZFS_LINUX_TEST_RESULT([blkdev_get_by_path], [
AC_MSG_RESULT(yes)
], [
- ZFS_LINUX_TEST_ERROR([blkdev_get_by_path()])
+ AC_MSG_RESULT(no)
+ AC_MSG_CHECKING([whether blkdev_get_by_path() exists and takes 4 args])
+ ZFS_LINUX_TEST_RESULT([blkdev_get_by_path_4arg], [
+ AC_DEFINE(HAVE_BLKDEV_GET_BY_PATH_4ARG, 1,
+ [blkdev_get_by_path() exists and takes 4 args])
+ AC_MSG_RESULT(yes)
+ ], [
+ ZFS_LINUX_TEST_ERROR([blkdev_get_by_path()])
+ ])
+ ])
+])
+
+dnl #
+dnl # 6.5.x API change
+dnl # blk_mode_t was added as a type to supercede some places where fmode_t
+dnl # is used
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_SRC_BLKDEV_BLK_MODE_T], [
+ ZFS_LINUX_TEST_SRC([blk_mode_t], [
+ #include <linux/fs.h>
+ #include <linux/blkdev.h>
+ ], [
+ blk_mode_t m __attribute((unused)) = (blk_mode_t)0;
+ ])
+])
+
+AC_DEFUN([ZFS_AC_KERNEL_BLKDEV_BLK_MODE_T], [
+ AC_MSG_CHECKING([whether blk_mode_t is defined])
+ ZFS_LINUX_TEST_RESULT([blk_mode_t], [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_BLK_MODE_T, 1, [blk_mode_t is defined])
+ ], [
+ AC_MSG_RESULT(no)
])
])
@@ -41,12 +92,35 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLKDEV_PUT], [
])
])
+dnl #
+dnl # 6.5.x API change.
+dnl # blkdev_put() takes (void* holder) as arg 2
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_SRC_BLKDEV_PUT_HOLDER], [
+ ZFS_LINUX_TEST_SRC([blkdev_put_holder], [
+ #include <linux/fs.h>
+ #include <linux/blkdev.h>
+ ], [
+ struct block_device *bdev = NULL;
+ void *holder = NULL;
+
+ blkdev_put(bdev, holder);
+ ])
+])
+
AC_DEFUN([ZFS_AC_KERNEL_BLKDEV_PUT], [
AC_MSG_CHECKING([whether blkdev_put() exists])
ZFS_LINUX_TEST_RESULT([blkdev_put], [
AC_MSG_RESULT(yes)
], [
- ZFS_LINUX_TEST_ERROR([blkdev_put()])
+ AC_MSG_CHECKING([whether blkdev_put() accepts void* as arg 2])
+ ZFS_LINUX_TEST_RESULT([blkdev_put_holder], [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_BLKDEV_PUT_HOLDER, 1,
+ [blkdev_put() accepts void* as arg 2])
+ ], [
+ ZFS_LINUX_TEST_ERROR([blkdev_put()])
+ ])
])
])
@@ -495,7 +569,9 @@ AC_DEFUN([ZFS_AC_KERNEL_BLKDEV_BLK_STS_RESV_CONFLICT], [
AC_DEFUN([ZFS_AC_KERNEL_SRC_BLKDEV], [
ZFS_AC_KERNEL_SRC_BLKDEV_GET_BY_PATH
+ ZFS_AC_KERNEL_SRC_BLKDEV_GET_BY_PATH_4ARG
ZFS_AC_KERNEL_SRC_BLKDEV_PUT
+ ZFS_AC_KERNEL_SRC_BLKDEV_PUT_HOLDER
ZFS_AC_KERNEL_SRC_BLKDEV_REREAD_PART
ZFS_AC_KERNEL_SRC_BLKDEV_INVALIDATE_BDEV
ZFS_AC_KERNEL_SRC_BLKDEV_LOOKUP_BDEV
@@ -510,6 +586,7 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLKDEV], [
ZFS_AC_KERNEL_SRC_BLKDEV_PART_TO_DEV
ZFS_AC_KERNEL_SRC_BLKDEV_DISK_CHECK_MEDIA_CHANGE
ZFS_AC_KERNEL_SRC_BLKDEV_BLK_STS_RESV_CONFLICT
+ ZFS_AC_KERNEL_SRC_BLKDEV_BLK_MODE_T
])
AC_DEFUN([ZFS_AC_KERNEL_BLKDEV], [
@@ -530,4 +607,5 @@ AC_DEFUN([ZFS_AC_KERNEL_BLKDEV], [
ZFS_AC_KERNEL_BLKDEV_PART_TO_DEV
ZFS_AC_KERNEL_BLKDEV_DISK_CHECK_MEDIA_CHANGE
ZFS_AC_KERNEL_BLKDEV_BLK_STS_RESV_CONFLICT
+ ZFS_AC_KERNEL_BLKDEV_BLK_MODE_T
])
diff --git a/config/kernel-block-device-operations.m4 b/config/kernel-block-device-operations.m4
index 84e39dc8a..d13c1337b 100644
--- a/config/kernel-block-device-operations.m4
+++ b/config/kernel-block-device-operations.m4
@@ -49,12 +49,42 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID], [
], [], [])
])
+dnl #
+dnl # 5.9.x API change
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_RELEASE_1ARG], [
+ ZFS_LINUX_TEST_SRC([block_device_operations_release_void_1arg], [
+ #include <linux/blkdev.h>
+
+ void blk_release(struct gendisk *g) {
+ (void) g;
+ return;
+ }
+
+ static const struct block_device_operations
+ bops __attribute__ ((unused)) = {
+ .open = NULL,
+ .release = blk_release,
+ .ioctl = NULL,
+ .compat_ioctl = NULL,
+ };
+ ], [], [])
+])
+
AC_DEFUN([ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID], [
- AC_MSG_CHECKING([whether bops->release() is void])
+ AC_MSG_CHECKING([whether bops->release() is void and takes 2 args])
ZFS_LINUX_TEST_RESULT([block_device_operations_release_void], [
AC_MSG_RESULT(yes)
],[
- ZFS_LINUX_TEST_ERROR([bops->release()])
+ AC_MSG_RESULT(no)
+ AC_MSG_CHECKING([whether bops->release() is void and takes 1 arg])
+ ZFS_LINUX_TEST_RESULT([block_device_operations_release_void_1arg], [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE([HAVE_BLOCK_DEVICE_OPERATIONS_RELEASE_1ARG], [1],
+ [Define if release() in block_device_operations takes 1 arg])
+ ],[
+ ZFS_LINUX_TEST_ERROR([bops->release()])
+ ])
])
])
@@ -92,6 +122,7 @@ AC_DEFUN([ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_REVALIDATE_DISK], [
AC_DEFUN([ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS], [
ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_CHECK_EVENTS
ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID
+ ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_RELEASE_1ARG
ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_REVALIDATE_DISK
])
diff --git a/include/os/linux/kernel/linux/blkdev_compat.h b/include/os/linux/kernel/linux/blkdev_compat.h
index 1641dd92a..f111e648c 100644
--- a/include/os/linux/kernel/linux/blkdev_compat.h
+++ b/include/os/linux/kernel/linux/blkdev_compat.h
@@ -398,6 +398,12 @@ vdev_lookup_bdev(const char *path, dev_t *dev)
#endif
}
+#if defined(HAVE_BLK_MODE_T)
+#define blk_mode_is_open_write(flag) ((flag) & BLK_OPEN_WRITE)
+#else
+#define blk_mode_is_open_write(flag) ((flag) & FMODE_WRITE)
+#endif
+
/*
* Kernels without bio_set_op_attrs use bi_rw for the bio flags.
*/
diff --git a/module/os/linux/zfs/vdev_disk.c b/module/os/linux/zfs/vdev_disk.c
index 925ee9d9f..48ac55f07 100644
--- a/module/os/linux/zfs/vdev_disk.c
+++ b/module/os/linux/zfs/vdev_disk.c
@@ -80,9 +80,22 @@ typedef struct dio_request {
static unsigned int zfs_vdev_failfast_mask = 1;
+#ifdef HAVE_BLK_MODE_T
+static blk_mode_t
+#else
static fmode_t
+#endif
vdev_bdev_mode(spa_mode_t spa_mode)
{
+#ifdef HAVE_BLK_MODE_T
+ blk_mode_t mode = 0;
+
+ if (spa_mode & SPA_MODE_READ)
+ mode |= BLK_OPEN_READ;
+
+ if (spa_mode & SPA_MODE_WRITE)
+ mode |= BLK_OPEN_WRITE;
+#else
fmode_t mode = 0;
if (spa_mode & SPA_MODE_READ)
@@ -90,6 +103,7 @@ vdev_bdev_mode(spa_mode_t spa_mode)
if (spa_mode & SPA_MODE_WRITE)
mode |= FMODE_WRITE;
+#endif
return (mode);
}
@@ -197,12 +211,47 @@ vdev_disk_kobj_evt_post(vdev_t *v)
}
}
+#if !defined(HAVE_BLKDEV_GET_BY_PATH_4ARG)
+/*
+ * Define a dummy struct blk_holder_ops for kernel versions
+ * prior to 6.5.
+ */
+struct blk_holder_ops {};
+#endif
+
+static struct block_device *
+vdev_blkdev_get_by_path(const char *path, spa_mode_t mode, void *holder,
+ const struct blk_holder_ops *hops)
+{
+#ifdef HAVE_BLKDEV_GET_BY_PATH_4ARG
+ return (blkdev_get_by_path(path,
+ vdev_bdev_mode(mode) | BLK_OPEN_EXCL, holder, hops));
+#else
+ return (blkdev_get_by_path(path,
+ vdev_bdev_mode(mode) | FMODE_EXCL, holder));
+#endif
+}
+
+static void
+vdev_blkdev_put(struct block_device *bdev, spa_mode_t mode, void *holder)
+{
+#ifdef HAVE_BLKDEV_PUT_HOLDER
+ return (blkdev_put(bdev, holder));
+#else
+ return (blkdev_put(bdev, vdev_bdev_mode(mode) | FMODE_EXCL));
+#endif
+}
+
static int
vdev_disk_open(vdev_t *v, uint64_t *psize, uint64_t *max_psize,
uint64_t *logical_ashift, uint64_t *physical_ashift)
{
struct block_device *bdev;
+#ifdef HAVE_BLK_MODE_T
+ blk_mode_t mode = vdev_bdev_mode(spa_mode(v->vdev_spa));
+#else
fmode_t mode = vdev_bdev_mode(spa_mode(v->vdev_spa));
+#endif
hrtime_t timeout = MSEC2NSEC(zfs_vdev_open_timeout_ms);
vdev_disk_t *vd;
@@ -252,15 +301,15 @@ vdev_disk_open(vdev_t *v, uint64_t *psize, uint64_t *max_psize,
reread_part = B_TRUE;
}
- blkdev_put(bdev, mode | FMODE_EXCL);
+ vdev_blkdev_put(bdev, mode, zfs_vdev_holder);
}
if (reread_part) {
- bdev = blkdev_get_by_path(disk_name, mode | FMODE_EXCL,
- zfs_vdev_holder);
+ bdev = vdev_blkdev_get_by_path(disk_name, mode,
+ zfs_vdev_holder, NULL);
if (!IS_ERR(bdev)) {
int error = vdev_bdev_reread_part(bdev);
- blkdev_put(bdev, mode | FMODE_EXCL);
+ vdev_blkdev_put(bdev, mode, zfs_vdev_holder);
if (error == 0) {
timeout = MSEC2NSEC(
zfs_vdev_open_timeout_ms * 2);
@@ -305,8 +354,8 @@ vdev_disk_open(vdev_t *v, uint64_t *psize, uint64_t *max_psize,
hrtime_t start = gethrtime();
bdev = ERR_PTR(-ENXIO);
while (IS_ERR(bdev) && ((gethrtime() - start) < timeout)) {
- bdev = blkdev_get_by_path(v->vdev_path, mode | FMODE_EXCL,
- zfs_vdev_holder);
+ bdev = vdev_blkdev_get_by_path(v->vdev_path, mode,
+ zfs_vdev_holder, NULL);
if (unlikely(PTR_ERR(bdev) == -ENOENT)) {
/*
* There is no point of waiting since device is removed
@@ -382,8 +431,8 @@ vdev_disk_close(vdev_t *v)
return;
if (vd->vd_bdev != NULL) {
- blkdev_put(vd->vd_bdev,
- vdev_bdev_mode(spa_mode(v->vdev_spa)) | FMODE_EXCL);
+ vdev_blkdev_put(vd->vd_bdev, spa_mode(v->vdev_spa),
+ zfs_vdev_holder);
}
rw_destroy(&vd->vd_lock);
diff --git a/module/os/linux/zfs/zfs_vnops_os.c b/module/os/linux/zfs/zfs_vnops_os.c
index 234c4d5ef..33baac9db 100644
--- a/module/os/linux/zfs/zfs_vnops_os.c
+++ b/module/os/linux/zfs/zfs_vnops_os.c
@@ -186,7 +186,7 @@ zfs_open(struct inode *ip, int mode, int flag, cred_t *cr)
return (error);
/* Honor ZFS_APPENDONLY file attribute */
- if ((mode & FMODE_WRITE) && (zp->z_pflags & ZFS_APPENDONLY) &&
+ if (blk_mode_is_open_write(mode) && (zp->z_pflags & ZFS_APPENDONLY) &&
((flag & O_APPEND) == 0)) {
zfs_exit(zfsvfs, FTAG);
return (SET_ERROR(EPERM));
diff --git a/module/os/linux/zfs/zpl_ctldir.c b/module/os/linux/zfs/zpl_ctldir.c
index 68a7de78f..7786444fe 100644
--- a/module/os/linux/zfs/zpl_ctldir.c
+++ b/module/os/linux/zfs/zpl_ctldir.c
@@ -42,7 +42,7 @@
static int
zpl_common_open(struct inode *ip, struct file *filp)
{
- if (filp->f_mode & FMODE_WRITE)
+ if (blk_mode_is_open_write(filp->f_mode))
return (-EACCES);
return (generic_file_open(ip, filp));
diff --git a/module/os/linux/zfs/zvol_os.c b/module/os/linux/zfs/zvol_os.c
index 38bc8e2c4..7a95b54bd 100644
--- a/module/os/linux/zfs/zvol_os.c
+++ b/module/os/linux/zfs/zvol_os.c
@@ -671,7 +671,11 @@ zvol_request(struct request_queue *q, struct bio *bio)
}
static int
+#ifdef HAVE_BLK_MODE_T
+zvol_open(struct gendisk *disk, blk_mode_t flag)
+#else
zvol_open(struct block_device *bdev, fmode_t flag)
+#endif
{
zvol_state_t *zv;
int error = 0;
@@ -686,10 +690,14 @@ retry:
/*
* Obtain a copy of private_data under the zvol_state_lock to make
* sure that either the result of zvol free code path setting
- * bdev->bd_disk->private_data to NULL is observed, or zvol_os_free()
+ * disk->private_data to NULL is observed, or zvol_os_free()
* is not called on this zv because of the positive zv_open_count.
*/
+#ifdef HAVE_BLK_MODE_T
+ zv = disk->private_data;
+#else
zv = bdev->bd_disk->private_data;
+#endif
if (zv == NULL) {
rw_exit(&zvol_state_lock);
return (SET_ERROR(-ENXIO));
@@ -769,14 +777,15 @@ retry:
}
}
- error = -zvol_first_open(zv, !(flag & FMODE_WRITE));
+ error = -zvol_first_open(zv, !(blk_mode_is_open_write(flag)));
if (drop_namespace)
mutex_exit(&spa_namespace_lock);
}
if (error == 0) {
- if ((flag & FMODE_WRITE) && (zv->zv_flags & ZVOL_RDONLY)) {
+ if ((blk_mode_is_open_write(flag)) &&
+ (zv->zv_flags & ZVOL_RDONLY)) {
if (zv->zv_open_count == 0)
zvol_last_close(zv);
@@ -791,14 +800,25 @@ retry:
rw_exit(&zv->zv_suspend_lock);
if (error == 0)
+#ifdef HAVE_BLK_MODE_T
+ disk_check_media_change(disk);
+#else
zfs_check_media_change(bdev);
+#endif
return (error);
}
static void
-zvol_release(struct gendisk *disk, fmode_t mode)
+#ifdef HAVE_BLOCK_DEVICE_OPERATIONS_RELEASE_1ARG
+zvol_release(struct gendisk *disk)
+#else
+zvol_release(struct gendisk *disk, fmode_t unused)
+#endif
{
+#if !defined(HAVE_BLOCK_DEVICE_OPERATIONS_RELEASE_1ARG)
+ (void) unused;
+#endif
zvol_state_t *zv;
boolean_t drop_suspend = B_TRUE;