From b7281c88bcbba0525e8b55607145956320d103f0 Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Tue, 22 Dec 2020 10:26:45 -0800 Subject: [PATCH] Linux 5.11 compat: lookup_bdev() The lookup_bdev() function has been updated to require a dev_t be passed as the second argument. This is actually pretty nice since the major number stored in the dev_t was the only part we were interested in. This allows to us avoid handling the bdev entirely. The vdev_lookup_bdev() wrapper was updated to emulate the behavior of the new lookup_bdev() for all supported kernels. Reviewed-by: Rafael Kitover Reviewed-by: Coleman Kane Signed-off-by: Brian Behlendorf Closes #11387 Closes #11390 --- config/kernel-blkdev.m4 | 55 ++++++++++++++----- include/os/linux/kernel/linux/blkdev_compat.h | 36 +++++++++--- module/os/linux/zfs/zvol_os.c | 13 ++--- 3 files changed, 74 insertions(+), 30 deletions(-) diff --git a/config/kernel-blkdev.m4 b/config/kernel-blkdev.m4 index 530b49f48c..622a1af5d0 100644 --- a/config/kernel-blkdev.m4 +++ b/config/kernel-blkdev.m4 @@ -154,42 +154,69 @@ AC_DEFUN([ZFS_AC_KERNEL_BLKDEV_INVALIDATE_BDEV], [ ]) dnl # -dnl # 2.6.27, lookup_bdev() was exported. -dnl # 4.4.0-6.21 - lookup_bdev() takes 2 arguments. +dnl # 5.11 API, lookup_bdev() takes dev_t argument. +dnl # 2.6.27 API, lookup_bdev() was first exported. +dnl # 4.4.0-6.21 API, lookup_bdev() on Ubuntu takes mode argument. dnl # AC_DEFUN([ZFS_AC_KERNEL_SRC_BLKDEV_LOOKUP_BDEV], [ + ZFS_LINUX_TEST_SRC([lookup_bdev_devt], [ + #include + ], [ + int error __attribute__ ((unused)); + const char path[] = "/example/path"; + dev_t dev; + + error = lookup_bdev(path, &dev); + ]) + ZFS_LINUX_TEST_SRC([lookup_bdev_1arg], [ #include #include ], [ - lookup_bdev(NULL); + struct block_device *bdev __attribute__ ((unused)); + const char path[] = "/example/path"; + + bdev = lookup_bdev(path); ]) - ZFS_LINUX_TEST_SRC([lookup_bdev_2args], [ + ZFS_LINUX_TEST_SRC([lookup_bdev_mode], [ #include ], [ - lookup_bdev(NULL, FMODE_READ); + struct block_device *bdev __attribute__ ((unused)); + const char path[] = "/example/path"; + + bdev = lookup_bdev(path, FMODE_READ); ]) ]) AC_DEFUN([ZFS_AC_KERNEL_BLKDEV_LOOKUP_BDEV], [ - AC_MSG_CHECKING([whether lookup_bdev() wants 1 arg]) - ZFS_LINUX_TEST_RESULT_SYMBOL([lookup_bdev_1arg], + AC_MSG_CHECKING([whether lookup_bdev() wants dev_t arg]) + ZFS_LINUX_TEST_RESULT_SYMBOL([lookup_bdev_devt], [lookup_bdev], [fs/block_dev.c], [ AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_1ARG_LOOKUP_BDEV, 1, - [lookup_bdev() wants 1 arg]) + AC_DEFINE(HAVE_DEVT_LOOKUP_BDEV, 1, + [lookup_bdev() wants dev_t arg]) ], [ AC_MSG_RESULT(no) - AC_MSG_CHECKING([whether lookup_bdev() wants 2 args]) - ZFS_LINUX_TEST_RESULT_SYMBOL([lookup_bdev_2args], + AC_MSG_CHECKING([whether lookup_bdev() wants 1 arg]) + ZFS_LINUX_TEST_RESULT_SYMBOL([lookup_bdev_1arg], [lookup_bdev], [fs/block_dev.c], [ AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_2ARGS_LOOKUP_BDEV, 1, - [lookup_bdev() wants 2 args]) + AC_DEFINE(HAVE_1ARG_LOOKUP_BDEV, 1, + [lookup_bdev() wants 1 arg]) ], [ - ZFS_LINUX_TEST_ERROR([lookup_bdev()]) + AC_MSG_RESULT(no) + + AC_MSG_CHECKING([whether lookup_bdev() wants mode arg]) + ZFS_LINUX_TEST_RESULT_SYMBOL([lookup_bdev_mode], + [lookup_bdev], [fs/block_dev.c], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_MODE_LOOKUP_BDEV, 1, + [lookup_bdev() wants mode arg]) + ], [ + ZFS_LINUX_TEST_ERROR([lookup_bdev()]) + ]) ]) ]) ]) diff --git a/include/os/linux/kernel/linux/blkdev_compat.h b/include/os/linux/kernel/linux/blkdev_compat.h index 220344c814..4d84900bec 100644 --- a/include/os/linux/kernel/linux/blkdev_compat.h +++ b/include/os/linux/kernel/linux/blkdev_compat.h @@ -318,16 +318,38 @@ zfs_check_media_change(struct block_device *bdev) * * 4.4.0-6.21 API change for Ubuntu * lookup_bdev() gained a second argument, FMODE_*, to check inode permissions. + * + * 5.11 API change + * Changed to take a dev_t argument which is set on success and return a + * non-zero error code on failure. */ -#ifdef HAVE_1ARG_LOOKUP_BDEV -#define vdev_lookup_bdev(path) lookup_bdev(path) -#else -#ifdef HAVE_2ARGS_LOOKUP_BDEV -#define vdev_lookup_bdev(path) lookup_bdev(path, 0) +static inline int +vdev_lookup_bdev(const char *path, dev_t *dev) +{ +#if defined(HAVE_DEVT_LOOKUP_BDEV) + return (lookup_bdev(path, dev)); +#elif defined(HAVE_1ARG_LOOKUP_BDEV) + struct block_device *bdev = lookup_bdev(path); + if (IS_ERR(bdev)) + return (PTR_ERR(bdev)); + + *dev = bdev->bd_dev; + bdput(bdev); + + return (0); +#elif defined(HAVE_MODE_LOOKUP_BDEV) + struct block_device *bdev = lookup_bdev(path, FMODE_READ); + if (IS_ERR(bdev)) + return (PTR_ERR(bdev)); + + *dev = bdev->bd_dev; + bdput(bdev); + + return (0); #else #error "Unsupported kernel" -#endif /* HAVE_2ARGS_LOOKUP_BDEV */ -#endif /* HAVE_1ARG_LOOKUP_BDEV */ +#endif +} /* * Kernels without bio_set_op_attrs use bi_rw for the bio flags. diff --git a/module/os/linux/zfs/zvol_os.c b/module/os/linux/zfs/zvol_os.c index 3b1d3e4f80..29ad673684 100644 --- a/module/os/linux/zfs/zvol_os.c +++ b/module/os/linux/zfs/zvol_os.c @@ -66,19 +66,14 @@ typedef struct zv_request { * Given a path, return TRUE if path is a ZVOL. */ static boolean_t -zvol_is_zvol_impl(const char *device) +zvol_is_zvol_impl(const char *path) { - struct block_device *bdev; - unsigned int major; + dev_t dev = 0; - bdev = vdev_lookup_bdev(device); - if (IS_ERR(bdev)) + if (vdev_lookup_bdev(path, &dev) != 0) return (B_FALSE); - major = MAJOR(bdev->bd_dev); - bdput(bdev); - - if (major == zvol_major) + if (MAJOR(dev) == zvol_major) return (B_TRUE); return (B_FALSE);