mirror of https://github.com/archzfs/zfs-dkms
parent
6bb4ed18a9
commit
76360b3ca9
@ -1,835 +0,0 @@ |
|||||||
From 9161ace4a02ea37b45f7ae613ea1d095a65d588d Mon Sep 17 00:00:00 2001
|
|
||||||
From: Brian Behlendorf <behlendorf1@llnl.gov>
|
|
||||||
Date: Fri, 15 Jun 2018 15:05:21 -0700
|
|
||||||
Subject: [PATCH] Linux compat 4.18: check_disk_size_change()
|
|
||||||
|
|
||||||
Added support for the bops->check_events() interface which was
|
|
||||||
added in the 2.6.38 kernel to replace bops->media_changed().
|
|
||||||
Fully implementing this functionality allows the volume resize
|
|
||||||
code to rely on revalidate_disk(), which is the preferred
|
|
||||||
mechanism, and removes the need to use check_disk_size_change().
|
|
||||||
|
|
||||||
In order for bops->check_events() to lookup the zvol_state_t
|
|
||||||
stored in the disk->private_data the zvol_state_lock needs to
|
|
||||||
be held. Since the check events interface may poll the mutex
|
|
||||||
has been converted to a rwlock for better concurrently. The
|
|
||||||
rwlock need only be taken as a writer in the zvol_free() path
|
|
||||||
when disk->private_data is set to NULL.
|
|
||||||
|
|
||||||
The configure checks for the block_device_operations structure
|
|
||||||
were consolidated in a single kernel-block-device-operations.m4
|
|
||||||
file.
|
|
||||||
|
|
||||||
The ZFS_AC_KERNEL_BDEV_BLOCK_DEVICE_OPERATIONS configure checks
|
|
||||||
and assoicated dead code was removed. This interface was added
|
|
||||||
to the 2.6.28 kernel which predates the oldest supported 2.6.32
|
|
||||||
kernel and will therefore always be available.
|
|
||||||
|
|
||||||
Updated maximum Linux version in META file. The 4.17 kernel
|
|
||||||
was released on 2018-06-03 and ZoL is compatible with the
|
|
||||||
finalized kernel.
|
|
||||||
|
|
||||||
Reviewed-by: Boris Protopopov <boris.protopopov@actifio.com>
|
|
||||||
Reviewed-by: Sara Hartse <sara.hartse@delphix.com>
|
|
||||||
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
|
|
||||||
Closes #7611
|
|
||||||
Backported-by: Richard Yao <ryao@gentoo.org>
|
|
||||||
---
|
|
||||||
config/kernel-bdev-block-device-operations.m4 | 34 ---
|
|
||||||
...el-block-device-operations-release-void.m4 | 29 --
|
|
||||||
config/kernel-block-device-operations.m4 | 57 ++++
|
|
||||||
config/kernel.m4 | 2 +-
|
|
||||||
include/linux/blkdev_compat.h | 1 +
|
|
||||||
module/zfs/zvol.c | 286 ++++++++----------
|
|
||||||
6 files changed, 192 insertions(+), 217 deletions(-)
|
|
||||||
delete mode 100644 config/kernel-bdev-block-device-operations.m4
|
|
||||||
delete mode 100644 config/kernel-block-device-operations-release-void.m4
|
|
||||||
create mode 100644 config/kernel-block-device-operations.m4
|
|
||||||
|
|
||||||
diff --git a/config/kernel-bdev-block-device-operations.m4 b/config/kernel-bdev-block-device-operations.m4
|
|
||||||
deleted file mode 100644
|
|
||||||
index faacc195da9..00000000000
|
|
||||||
--- a/config/kernel-bdev-block-device-operations.m4
|
|
||||||
+++ /dev/null
|
|
||||||
@@ -1,34 +0,0 @@
|
|
||||||
-dnl #
|
|
||||||
-dnl # 2.6.x API change
|
|
||||||
-dnl #
|
|
||||||
-AC_DEFUN([ZFS_AC_KERNEL_BDEV_BLOCK_DEVICE_OPERATIONS], [
|
|
||||||
- AC_MSG_CHECKING([block device operation prototypes])
|
|
||||||
- tmp_flags="$EXTRA_KCFLAGS"
|
|
||||||
- EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
|
|
||||||
- ZFS_LINUX_TRY_COMPILE([
|
|
||||||
- #include <linux/blkdev.h>
|
|
||||||
-
|
|
||||||
- int blk_open(struct block_device *bdev, fmode_t mode)
|
|
||||||
- { return 0; }
|
|
||||||
- int blk_ioctl(struct block_device *bdev, fmode_t mode,
|
|
||||||
- unsigned x, unsigned long y) { return 0; }
|
|
||||||
- int blk_compat_ioctl(struct block_device * bdev, fmode_t mode,
|
|
||||||
- unsigned x, unsigned long y) { return 0; }
|
|
||||||
-
|
|
||||||
- static const struct block_device_operations
|
|
||||||
- bops __attribute__ ((unused)) = {
|
|
||||||
- .open = blk_open,
|
|
||||||
- .release = NULL,
|
|
||||||
- .ioctl = blk_ioctl,
|
|
||||||
- .compat_ioctl = blk_compat_ioctl,
|
|
||||||
- };
|
|
||||||
- ],[
|
|
||||||
- ],[
|
|
||||||
- AC_MSG_RESULT(struct block_device)
|
|
||||||
- AC_DEFINE(HAVE_BDEV_BLOCK_DEVICE_OPERATIONS, 1,
|
|
||||||
- [struct block_device_operations use bdevs])
|
|
||||||
- ],[
|
|
||||||
- AC_MSG_RESULT(struct inode)
|
|
||||||
- ])
|
|
||||||
- EXTRA_KCFLAGS="$tmp_flags"
|
|
||||||
-])
|
|
||||||
diff --git a/config/kernel-block-device-operations-release-void.m4 b/config/kernel-block-device-operations-release-void.m4
|
|
||||||
deleted file mode 100644
|
|
||||||
index a73f858722a..00000000000
|
|
||||||
--- a/config/kernel-block-device-operations-release-void.m4
|
|
||||||
+++ /dev/null
|
|
||||||
@@ -1,29 +0,0 @@
|
|
||||||
-dnl #
|
|
||||||
-dnl # 3.10.x API change
|
|
||||||
-dnl #
|
|
||||||
-AC_DEFUN([ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID], [
|
|
||||||
- AC_MSG_CHECKING([whether block_device_operations.release is void])
|
|
||||||
- tmp_flags="$EXTRA_KCFLAGS"
|
|
||||||
- EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
|
|
||||||
- ZFS_LINUX_TRY_COMPILE([
|
|
||||||
- #include <linux/blkdev.h>
|
|
||||||
-
|
|
||||||
- void blk_release(struct gendisk *g, fmode_t mode) { return; }
|
|
||||||
-
|
|
||||||
- static const struct block_device_operations
|
|
||||||
- bops __attribute__ ((unused)) = {
|
|
||||||
- .open = NULL,
|
|
||||||
- .release = blk_release,
|
|
||||||
- .ioctl = NULL,
|
|
||||||
- .compat_ioctl = NULL,
|
|
||||||
- };
|
|
||||||
- ],[
|
|
||||||
- ],[
|
|
||||||
- AC_MSG_RESULT(void)
|
|
||||||
- AC_DEFINE(HAVE_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID, 1,
|
|
||||||
- [struct block_device_operations.release returns void])
|
|
||||||
- ],[
|
|
||||||
- AC_MSG_RESULT(int)
|
|
||||||
- ])
|
|
||||||
- EXTRA_KCFLAGS="$tmp_flags"
|
|
||||||
-])
|
|
||||||
diff --git a/config/kernel-block-device-operations.m4 b/config/kernel-block-device-operations.m4
|
|
||||||
new file mode 100644
|
|
||||||
index 00000000000..5f2811c1534
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/config/kernel-block-device-operations.m4
|
|
||||||
@@ -0,0 +1,57 @@
|
|
||||||
+dnl #
|
|
||||||
+dnl # 2.6.38 API change
|
|
||||||
+dnl #
|
|
||||||
+AC_DEFUN([ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_CHECK_EVENTS], [
|
|
||||||
+ AC_MSG_CHECKING([whether bops->check_events() exists])
|
|
||||||
+ tmp_flags="$EXTRA_KCFLAGS"
|
|
||||||
+ EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
|
|
||||||
+ ZFS_LINUX_TRY_COMPILE([
|
|
||||||
+ #include <linux/blkdev.h>
|
|
||||||
+
|
|
||||||
+ unsigned int blk_check_events(struct gendisk *disk,
|
|
||||||
+ unsigned int clearing) { return (0); }
|
|
||||||
+
|
|
||||||
+ static const struct block_device_operations
|
|
||||||
+ bops __attribute__ ((unused)) = {
|
|
||||||
+ .check_events = blk_check_events,
|
|
||||||
+ };
|
|
||||||
+ ],[
|
|
||||||
+ ],[
|
|
||||||
+ AC_MSG_RESULT(yes)
|
|
||||||
+ AC_DEFINE(HAVE_BLOCK_DEVICE_OPERATIONS_CHECK_EVENTS, 1,
|
|
||||||
+ [bops->check_events() exists])
|
|
||||||
+ ],[
|
|
||||||
+ AC_MSG_RESULT(no)
|
|
||||||
+ ])
|
|
||||||
+ EXTRA_KCFLAGS="$tmp_flags"
|
|
||||||
+])
|
|
||||||
+
|
|
||||||
+dnl #
|
|
||||||
+dnl # 3.10.x API change
|
|
||||||
+dnl #
|
|
||||||
+AC_DEFUN([ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID], [
|
|
||||||
+ AC_MSG_CHECKING([whether bops->release() is void])
|
|
||||||
+ tmp_flags="$EXTRA_KCFLAGS"
|
|
||||||
+ EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
|
|
||||||
+ ZFS_LINUX_TRY_COMPILE([
|
|
||||||
+ #include <linux/blkdev.h>
|
|
||||||
+
|
|
||||||
+ void blk_release(struct gendisk *g, fmode_t mode) { return; }
|
|
||||||
+
|
|
||||||
+ static const struct block_device_operations
|
|
||||||
+ bops __attribute__ ((unused)) = {
|
|
||||||
+ .open = NULL,
|
|
||||||
+ .release = blk_release,
|
|
||||||
+ .ioctl = NULL,
|
|
||||||
+ .compat_ioctl = NULL,
|
|
||||||
+ };
|
|
||||||
+ ],[
|
|
||||||
+ ],[
|
|
||||||
+ AC_MSG_RESULT(void)
|
|
||||||
+ AC_DEFINE(HAVE_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID, 1,
|
|
||||||
+ [bops->release() returns void])
|
|
||||||
+ ],[
|
|
||||||
+ AC_MSG_RESULT(int)
|
|
||||||
+ ])
|
|
||||||
+ EXTRA_KCFLAGS="$tmp_flags"
|
|
||||||
+])
|
|
||||||
diff --git a/config/kernel.m4 b/config/kernel.m4
|
|
||||||
index 375e4b79ae6..c7ca260c5f0 100644
|
|
||||||
--- a/config/kernel.m4
|
|
||||||
+++ b/config/kernel.m4
|
|
||||||
@@ -12,7 +12,7 @@ AC_DEFUN([ZFS_AC_CONFIG_KERNEL], [
|
|
||||||
ZFS_AC_KERNEL_CURRENT_BIO_TAIL
|
|
||||||
ZFS_AC_KERNEL_SUPER_USER_NS
|
|
||||||
ZFS_AC_KERNEL_SUBMIT_BIO
|
|
||||||
- ZFS_AC_KERNEL_BDEV_BLOCK_DEVICE_OPERATIONS
|
|
||||||
+ ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_CHECK_EVENTS
|
|
||||||
ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID
|
|
||||||
ZFS_AC_KERNEL_TYPE_FMODE_T
|
|
||||||
ZFS_AC_KERNEL_3ARG_BLKDEV_GET
|
|
||||||
diff --git a/include/linux/blkdev_compat.h b/include/linux/blkdev_compat.h
|
|
||||||
index f99980ab3e0..27f05662662 100644
|
|
||||||
--- a/include/linux/blkdev_compat.h
|
|
||||||
+++ b/include/linux/blkdev_compat.h
|
|
||||||
@@ -32,6 +32,7 @@
|
|
||||||
#include <linux/blkdev.h>
|
|
||||||
#include <linux/elevator.h>
|
|
||||||
#include <linux/backing-dev.h>
|
|
||||||
+#include <linux/msdos_fs.h> /* for SECTOR_* */
|
|
||||||
|
|
||||||
#ifndef HAVE_FMODE_T
|
|
||||||
typedef unsigned __bitwise__ fmode_t;
|
|
||||||
diff --git a/module/zfs/zvol.c b/module/zfs/zvol.c
|
|
||||||
index 3e7059b340b..e57d2e70332 100644
|
|
||||||
--- a/module/zfs/zvol.c
|
|
||||||
+++ b/module/zfs/zvol.c
|
|
||||||
@@ -99,7 +99,7 @@ unsigned long zvol_max_discard_blocks = 16384;
|
|
||||||
unsigned int zvol_volmode = ZFS_VOLMODE_GEOM;
|
|
||||||
|
|
||||||
static taskq_t *zvol_taskq;
|
|
||||||
-static kmutex_t zvol_state_lock;
|
|
||||||
+static krwlock_t zvol_state_lock;
|
|
||||||
static list_t zvol_state_list;
|
|
||||||
|
|
||||||
#define ZVOL_HT_SIZE 1024
|
|
||||||
@@ -176,17 +176,17 @@ zvol_find_by_dev(dev_t dev)
|
|
||||||
{
|
|
||||||
zvol_state_t *zv;
|
|
||||||
|
|
||||||
- mutex_enter(&zvol_state_lock);
|
|
||||||
+ rw_enter(&zvol_state_lock, RW_READER);
|
|
||||||
for (zv = list_head(&zvol_state_list); zv != NULL;
|
|
||||||
zv = list_next(&zvol_state_list, zv)) {
|
|
||||||
mutex_enter(&zv->zv_state_lock);
|
|
||||||
if (zv->zv_dev == dev) {
|
|
||||||
- mutex_exit(&zvol_state_lock);
|
|
||||||
+ rw_exit(&zvol_state_lock);
|
|
||||||
return (zv);
|
|
||||||
}
|
|
||||||
mutex_exit(&zv->zv_state_lock);
|
|
||||||
}
|
|
||||||
- mutex_exit(&zvol_state_lock);
|
|
||||||
+ rw_exit(&zvol_state_lock);
|
|
||||||
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
@@ -204,7 +204,7 @@ zvol_find_by_name_hash(const char *name, uint64_t hash, int mode)
|
|
||||||
zvol_state_t *zv;
|
|
||||||
struct hlist_node *p = NULL;
|
|
||||||
|
|
||||||
- mutex_enter(&zvol_state_lock);
|
|
||||||
+ rw_enter(&zvol_state_lock, RW_READER);
|
|
||||||
hlist_for_each(p, ZVOL_HT_HEAD(hash)) {
|
|
||||||
zv = hlist_entry(p, zvol_state_t, zv_hlink);
|
|
||||||
mutex_enter(&zv->zv_state_lock);
|
|
||||||
@@ -227,12 +227,12 @@ zvol_find_by_name_hash(const char *name, uint64_t hash, int mode)
|
|
||||||
strncmp(zv->zv_name, name, MAXNAMELEN)
|
|
||||||
== 0);
|
|
||||||
}
|
|
||||||
- mutex_exit(&zvol_state_lock);
|
|
||||||
+ rw_exit(&zvol_state_lock);
|
|
||||||
return (zv);
|
|
||||||
}
|
|
||||||
mutex_exit(&zv->zv_state_lock);
|
|
||||||
}
|
|
||||||
- mutex_exit(&zvol_state_lock);
|
|
||||||
+ rw_exit(&zvol_state_lock);
|
|
||||||
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
@@ -339,24 +339,6 @@ zvol_get_stats(objset_t *os, nvlist_t *nv)
|
|
||||||
return (SET_ERROR(error));
|
|
||||||
}
|
|
||||||
|
|
||||||
-static void
|
|
||||||
-zvol_size_changed(zvol_state_t *zv, uint64_t volsize)
|
|
||||||
-{
|
|
||||||
- struct block_device *bdev;
|
|
||||||
-
|
|
||||||
- ASSERT(MUTEX_HELD(&zv->zv_state_lock));
|
|
||||||
-
|
|
||||||
- bdev = bdget_disk(zv->zv_disk, 0);
|
|
||||||
- if (bdev == NULL)
|
|
||||||
- return;
|
|
||||||
-
|
|
||||||
- set_capacity(zv->zv_disk, volsize >> 9);
|
|
||||||
- zv->zv_volsize = volsize;
|
|
||||||
- check_disk_size_change(zv->zv_disk, bdev);
|
|
||||||
-
|
|
||||||
- bdput(bdev);
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
/*
|
|
||||||
* Sanity check volume size.
|
|
||||||
*/
|
|
||||||
@@ -409,31 +391,17 @@ zvol_update_volsize(uint64_t volsize, objset_t *os)
|
|
||||||
return (error);
|
|
||||||
}
|
|
||||||
|
|
||||||
-static int
|
|
||||||
-zvol_update_live_volsize(zvol_state_t *zv, uint64_t volsize)
|
|
||||||
-{
|
|
||||||
- zvol_size_changed(zv, volsize);
|
|
||||||
-
|
|
||||||
- /*
|
|
||||||
- * We should post a event here describing the expansion. However,
|
|
||||||
- * the zfs_ereport_post() interface doesn't nicely support posting
|
|
||||||
- * events for zvols, it assumes events relate to vdevs or zios.
|
|
||||||
- */
|
|
||||||
-
|
|
||||||
- return (0);
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
/*
|
|
||||||
- * Set ZFS_PROP_VOLSIZE set entry point.
|
|
||||||
+ * Set ZFS_PROP_VOLSIZE set entry point. Note that modifying the volume
|
|
||||||
+ * size will result in a udev "change" event being generated.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
zvol_set_volsize(const char *name, uint64_t volsize)
|
|
||||||
{
|
|
||||||
- zvol_state_t *zv = NULL;
|
|
||||||
objset_t *os = NULL;
|
|
||||||
- int error;
|
|
||||||
- dmu_object_info_t *doi;
|
|
||||||
+ struct gendisk *disk = NULL;
|
|
||||||
uint64_t readonly;
|
|
||||||
+ int error;
|
|
||||||
boolean_t owned = B_FALSE;
|
|
||||||
|
|
||||||
error = dsl_prop_get_integer(name,
|
|
||||||
@@ -443,7 +411,7 @@ zvol_set_volsize(const char *name, uint64_t volsize)
|
|
||||||
if (readonly)
|
|
||||||
return (SET_ERROR(EROFS));
|
|
||||||
|
|
||||||
- zv = zvol_find_by_name(name, RW_READER);
|
|
||||||
+ zvol_state_t *zv = zvol_find_by_name(name, RW_READER);
|
|
||||||
|
|
||||||
ASSERT(zv == NULL || (MUTEX_HELD(&zv->zv_state_lock) &&
|
|
||||||
RW_READ_HELD(&zv->zv_suspend_lock)));
|
|
||||||
@@ -464,16 +432,18 @@ zvol_set_volsize(const char *name, uint64_t volsize)
|
|
||||||
os = zv->zv_objset;
|
|
||||||
}
|
|
||||||
|
|
||||||
- doi = kmem_alloc(sizeof (dmu_object_info_t), KM_SLEEP);
|
|
||||||
+ dmu_object_info_t *doi = kmem_alloc(sizeof (*doi), KM_SLEEP);
|
|
||||||
|
|
||||||
if ((error = dmu_object_info(os, ZVOL_OBJ, doi)) ||
|
|
||||||
(error = zvol_check_volsize(volsize, doi->doi_data_block_size)))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
error = zvol_update_volsize(volsize, os);
|
|
||||||
-
|
|
||||||
- if (error == 0 && zv != NULL)
|
|
||||||
- error = zvol_update_live_volsize(zv, volsize);
|
|
||||||
+ if (error == 0 && zv != NULL) {
|
|
||||||
+ zv->zv_volsize = volsize;
|
|
||||||
+ zv->zv_changed = 1;
|
|
||||||
+ disk = zv->zv_disk;
|
|
||||||
+ }
|
|
||||||
out:
|
|
||||||
kmem_free(doi, sizeof (dmu_object_info_t));
|
|
||||||
|
|
||||||
@@ -488,6 +458,9 @@ zvol_set_volsize(const char *name, uint64_t volsize)
|
|
||||||
if (zv != NULL)
|
|
||||||
mutex_exit(&zv->zv_state_lock);
|
|
||||||
|
|
||||||
+ if (disk != NULL)
|
|
||||||
+ revalidate_disk(disk);
|
|
||||||
+
|
|
||||||
return (SET_ERROR(error));
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -543,8 +516,8 @@ zvol_set_volblocksize(const char *name, uint64_t volblocksize)
|
|
||||||
if (zv == NULL)
|
|
||||||
return (SET_ERROR(ENXIO));
|
|
||||||
|
|
||||||
- ASSERT(MUTEX_HELD(&zv->zv_state_lock) &&
|
|
||||||
- RW_READ_HELD(&zv->zv_suspend_lock));
|
|
||||||
+ ASSERT(MUTEX_HELD(&zv->zv_state_lock));
|
|
||||||
+ ASSERT(RW_READ_HELD(&zv->zv_suspend_lock));
|
|
||||||
|
|
||||||
if (zv->zv_flags & ZVOL_RDONLY) {
|
|
||||||
mutex_exit(&zv->zv_state_lock);
|
|
||||||
@@ -1120,7 +1093,7 @@ zvol_get_data(void *arg, lr_write_t *lr, char *buf, zio_t *zio)
|
|
||||||
static void
|
|
||||||
zvol_insert(zvol_state_t *zv)
|
|
||||||
{
|
|
||||||
- ASSERT(MUTEX_HELD(&zvol_state_lock));
|
|
||||||
+ ASSERT(RW_WRITE_HELD(&zvol_state_lock));
|
|
||||||
ASSERT3U(MINOR(zv->zv_dev) & ZVOL_MINOR_MASK, ==, 0);
|
|
||||||
list_insert_head(&zvol_state_list, zv);
|
|
||||||
hlist_add_head(&zv->zv_hlink, ZVOL_HT_HEAD(zv->zv_hash));
|
|
||||||
@@ -1132,7 +1105,7 @@ zvol_insert(zvol_state_t *zv)
|
|
||||||
static void
|
|
||||||
zvol_remove(zvol_state_t *zv)
|
|
||||||
{
|
|
||||||
- ASSERT(MUTEX_HELD(&zvol_state_lock));
|
|
||||||
+ ASSERT(RW_WRITE_HELD(&zvol_state_lock));
|
|
||||||
list_remove(&zvol_state_list, zv);
|
|
||||||
hlist_del(&zv->zv_hlink);
|
|
||||||
}
|
|
||||||
@@ -1148,8 +1121,8 @@ zvol_setup_zv(zvol_state_t *zv)
|
|
||||||
uint64_t ro;
|
|
||||||
objset_t *os = zv->zv_objset;
|
|
||||||
|
|
||||||
- ASSERT(MUTEX_HELD(&zv->zv_state_lock) &&
|
|
||||||
- RW_LOCK_HELD(&zv->zv_suspend_lock));
|
|
||||||
+ ASSERT(MUTEX_HELD(&zv->zv_state_lock));
|
|
||||||
+ ASSERT(RW_LOCK_HELD(&zv->zv_suspend_lock));
|
|
||||||
|
|
||||||
error = dsl_prop_get_integer(zv->zv_name, "readonly", &ro, NULL);
|
|
||||||
if (error)
|
|
||||||
@@ -1227,8 +1200,8 @@ zvol_suspend(const char *name)
|
|
||||||
return (NULL);
|
|
||||||
|
|
||||||
/* block all I/O, release in zvol_resume. */
|
|
||||||
- ASSERT(MUTEX_HELD(&zv->zv_state_lock) &&
|
|
||||||
- RW_WRITE_HELD(&zv->zv_suspend_lock));
|
|
||||||
+ ASSERT(MUTEX_HELD(&zv->zv_state_lock));
|
|
||||||
+ ASSERT(RW_WRITE_HELD(&zv->zv_suspend_lock));
|
|
||||||
|
|
||||||
atomic_inc(&zv->zv_suspend_ref);
|
|
||||||
|
|
||||||
@@ -1349,9 +1322,7 @@ zvol_open(struct block_device *bdev, fmode_t flag)
|
|
||||||
int error = 0;
|
|
||||||
boolean_t drop_suspend = B_FALSE;
|
|
||||||
|
|
||||||
- ASSERT(!mutex_owned(&zvol_state_lock));
|
|
||||||
-
|
|
||||||
- mutex_enter(&zvol_state_lock);
|
|
||||||
+ rw_enter(&zvol_state_lock, RW_READER);
|
|
||||||
/*
|
|
||||||
* Obtain a copy of private_data under the zvol_state_lock to make
|
|
||||||
* sure that either the result of zvol free code path setting
|
|
||||||
@@ -1360,7 +1331,7 @@ zvol_open(struct block_device *bdev, fmode_t flag)
|
|
||||||
*/
|
|
||||||
zv = bdev->bd_disk->private_data;
|
|
||||||
if (zv == NULL) {
|
|
||||||
- mutex_exit(&zvol_state_lock);
|
|
||||||
+ rw_exit(&zvol_state_lock);
|
|
||||||
return (SET_ERROR(-ENXIO));
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1378,8 +1349,7 @@ zvol_open(struct block_device *bdev, fmode_t flag)
|
|
||||||
} else {
|
|
||||||
rw_exit(&zv->zv_suspend_lock);
|
|
||||||
}
|
|
||||||
-
|
|
||||||
- mutex_exit(&zvol_state_lock);
|
|
||||||
+ rw_exit(&zvol_state_lock);
|
|
||||||
|
|
||||||
if (zv->zv_open_count == 0) {
|
|
||||||
error = zvol_first_open(zv);
|
|
||||||
@@ -1394,11 +1364,18 @@ zvol_open(struct block_device *bdev, fmode_t flag)
|
|
||||||
|
|
||||||
zv->zv_open_count++;
|
|
||||||
|
|
||||||
+ mutex_exit(&zv->zv_state_lock);
|
|
||||||
+ if (drop_suspend)
|
|
||||||
+ rw_exit(&zv->zv_suspend_lock);
|
|
||||||
+
|
|
||||||
check_disk_change(bdev);
|
|
||||||
|
|
||||||
+ return (0);
|
|
||||||
+
|
|
||||||
out_open_count:
|
|
||||||
if (zv->zv_open_count == 0)
|
|
||||||
zvol_last_close(zv);
|
|
||||||
+
|
|
||||||
out_mutex:
|
|
||||||
mutex_exit(&zv->zv_state_lock);
|
|
||||||
if (drop_suspend)
|
|
||||||
@@ -1419,26 +1396,34 @@ zvol_release(struct gendisk *disk, fmode_t mode)
|
|
||||||
zvol_state_t *zv;
|
|
||||||
boolean_t drop_suspend = B_FALSE;
|
|
||||||
|
|
||||||
- ASSERT(!mutex_owned(&zvol_state_lock));
|
|
||||||
-
|
|
||||||
- mutex_enter(&zvol_state_lock);
|
|
||||||
+ rw_enter(&zvol_state_lock, RW_READER);
|
|
||||||
zv = disk->private_data;
|
|
||||||
- ASSERT(zv && zv->zv_open_count > 0);
|
|
||||||
-
|
|
||||||
- /* take zv_suspend_lock before zv_state_lock */
|
|
||||||
- rw_enter(&zv->zv_suspend_lock, RW_READER);
|
|
||||||
|
|
||||||
mutex_enter(&zv->zv_state_lock);
|
|
||||||
- mutex_exit(&zvol_state_lock);
|
|
||||||
+ ASSERT(zv && zv->zv_open_count > 0);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* make sure zvol is not suspended during last close
|
|
||||||
* (hold zv_suspend_lock), otherwise, drop the lock
|
|
||||||
*/
|
|
||||||
- if (zv->zv_open_count == 1)
|
|
||||||
- drop_suspend = B_TRUE;
|
|
||||||
- else
|
|
||||||
- rw_exit(&zv->zv_suspend_lock);
|
|
||||||
+ if (zv->zv_open_count == 1) {
|
|
||||||
+ if (!rw_tryenter(&zv->zv_suspend_lock, RW_READER)) {
|
|
||||||
+ mutex_exit(&zv->zv_state_lock);
|
|
||||||
+ rw_enter(&zv->zv_suspend_lock, RW_READER);
|
|
||||||
+ mutex_enter(&zv->zv_state_lock);
|
|
||||||
+ /* check to see if zv_suspend_lock is needed */
|
|
||||||
+ if (zv->zv_open_count != 1) {
|
|
||||||
+ rw_exit(&zv->zv_suspend_lock);
|
|
||||||
+ drop_suspend = B_FALSE;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ } else {
|
|
||||||
+ drop_suspend = B_FALSE;
|
|
||||||
+ }
|
|
||||||
+ rw_exit(&zvol_state_lock);
|
|
||||||
+
|
|
||||||
+ ASSERT(MUTEX_HELD(&zv->zv_state_lock));
|
|
||||||
+ ASSERT(zv->zv_open_count != 1 || RW_READ_HELD(&zv->zv_suspend_lock));
|
|
||||||
|
|
||||||
zv->zv_open_count--;
|
|
||||||
if (zv->zv_open_count == 0)
|
|
||||||
@@ -1461,7 +1446,7 @@ zvol_ioctl(struct block_device *bdev, fmode_t mode,
|
|
||||||
zvol_state_t *zv = bdev->bd_disk->private_data;
|
|
||||||
int error = 0;
|
|
||||||
|
|
||||||
- ASSERT(zv && zv->zv_open_count > 0);
|
|
||||||
+ ASSERT3U(zv->zv_open_count, >, 0);
|
|
||||||
|
|
||||||
switch (cmd) {
|
|
||||||
case BLKFLSBUF:
|
|
||||||
@@ -1501,23 +1486,62 @@ zvol_compat_ioctl(struct block_device *bdev, fmode_t mode,
|
|
||||||
#define zvol_compat_ioctl NULL
|
|
||||||
#endif
|
|
||||||
|
|
||||||
+/*
|
|
||||||
+ * Linux 2.6.38 preferred interface.
|
|
||||||
+ */
|
|
||||||
+#ifdef HAVE_BLOCK_DEVICE_OPERATIONS_CHECK_EVENTS
|
|
||||||
+static unsigned int
|
|
||||||
+zvol_check_events(struct gendisk *disk, unsigned int clearing)
|
|
||||||
+{
|
|
||||||
+ unsigned int mask = 0;
|
|
||||||
+
|
|
||||||
+ rw_enter(&zvol_state_lock, RW_READER);
|
|
||||||
+
|
|
||||||
+ zvol_state_t *zv = disk->private_data;
|
|
||||||
+ if (zv != NULL) {
|
|
||||||
+ mutex_enter(&zv->zv_state_lock);
|
|
||||||
+ mask = zv->zv_changed ? DISK_EVENT_MEDIA_CHANGE : 0;
|
|
||||||
+ zv->zv_changed = 0;
|
|
||||||
+ mutex_exit(&zv->zv_state_lock);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ rw_exit(&zvol_state_lock);
|
|
||||||
+
|
|
||||||
+ return (mask);
|
|
||||||
+}
|
|
||||||
+#else
|
|
||||||
static int zvol_media_changed(struct gendisk *disk)
|
|
||||||
{
|
|
||||||
+ int changed = 0;
|
|
||||||
+
|
|
||||||
+ rw_enter(&zvol_state_lock, RW_READER);
|
|
||||||
+
|
|
||||||
zvol_state_t *zv = disk->private_data;
|
|
||||||
+ if (zv != NULL) {
|
|
||||||
+ mutex_enter(&zv->zv_state_lock);
|
|
||||||
+ changed = zv->zv_changed;
|
|
||||||
+ zv->zv_changed = 0;
|
|
||||||
+ mutex_exit(&zv->zv_state_lock);
|
|
||||||
+ }
|
|
||||||
|
|
||||||
- ASSERT(zv && zv->zv_open_count > 0);
|
|
||||||
+ rw_exit(&zvol_state_lock);
|
|
||||||
|
|
||||||
- return (zv->zv_changed);
|
|
||||||
+ return (changed);
|
|
||||||
}
|
|
||||||
+#endif
|
|
||||||
|
|
||||||
static int zvol_revalidate_disk(struct gendisk *disk)
|
|
||||||
{
|
|
||||||
- zvol_state_t *zv = disk->private_data;
|
|
||||||
+ rw_enter(&zvol_state_lock, RW_READER);
|
|
||||||
|
|
||||||
- ASSERT(zv && zv->zv_open_count > 0);
|
|
||||||
+ zvol_state_t *zv = disk->private_data;
|
|
||||||
+ if (zv != NULL) {
|
|
||||||
+ mutex_enter(&zv->zv_state_lock);
|
|
||||||
+ set_capacity(zv->zv_disk, zv->zv_volsize >> SECTOR_BITS);
|
|
||||||
+ mutex_exit(&zv->zv_state_lock);
|
|
||||||
+ }
|
|
||||||
|
|
||||||
- zv->zv_changed = 0;
|
|
||||||
- set_capacity(zv->zv_disk, zv->zv_volsize >> 9);
|
|
||||||
+ rw_exit(&zvol_state_lock);
|
|
||||||
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
@@ -1534,7 +1558,7 @@ zvol_getgeo(struct block_device *bdev, struct hd_geometry *geo)
|
|
||||||
zvol_state_t *zv = bdev->bd_disk->private_data;
|
|
||||||
sector_t sectors;
|
|
||||||
|
|
||||||
- ASSERT(zv && zv->zv_open_count > 0);
|
|
||||||
+ ASSERT3U(zv->zv_open_count, >, 0);
|
|
||||||
|
|
||||||
sectors = get_capacity(zv->zv_disk);
|
|
||||||
|
|
||||||
@@ -1567,68 +1591,20 @@ zvol_probe(dev_t dev, int *part, void *arg)
|
|
||||||
return (kobj);
|
|
||||||
}
|
|
||||||
|
|
||||||
-#ifdef HAVE_BDEV_BLOCK_DEVICE_OPERATIONS
|
|
||||||
static struct block_device_operations zvol_ops = {
|
|
||||||
.open = zvol_open,
|
|
||||||
.release = zvol_release,
|
|
||||||
.ioctl = zvol_ioctl,
|
|
||||||
.compat_ioctl = zvol_compat_ioctl,
|
|
||||||
- .media_changed = zvol_media_changed,
|
|
||||||
- .revalidate_disk = zvol_revalidate_disk,
|
|
||||||
- .getgeo = zvol_getgeo,
|
|
||||||
- .owner = THIS_MODULE,
|
|
||||||
-};
|
|
||||||
-
|
|
||||||
-#else /* HAVE_BDEV_BLOCK_DEVICE_OPERATIONS */
|
|
||||||
-
|
|
||||||
-static int
|
|
||||||
-zvol_open_by_inode(struct inode *inode, struct file *file)
|
|
||||||
-{
|
|
||||||
- return (zvol_open(inode->i_bdev, file->f_mode));
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
-static int
|
|
||||||
-zvol_release_by_inode(struct inode *inode, struct file *file)
|
|
||||||
-{
|
|
||||||
- return (zvol_release(inode->i_bdev->bd_disk, file->f_mode));
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
-static int
|
|
||||||
-zvol_ioctl_by_inode(struct inode *inode, struct file *file,
|
|
||||||
- unsigned int cmd, unsigned long arg)
|
|
||||||
-{
|
|
||||||
- if (file == NULL || inode == NULL)
|
|
||||||
- return (SET_ERROR(-EINVAL));
|
|
||||||
-
|
|
||||||
- return (zvol_ioctl(inode->i_bdev, file->f_mode, cmd, arg));
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
-#ifdef CONFIG_COMPAT
|
|
||||||
-static long
|
|
||||||
-zvol_compat_ioctl_by_inode(struct file *file,
|
|
||||||
- unsigned int cmd, unsigned long arg)
|
|
||||||
-{
|
|
||||||
- if (file == NULL)
|
|
||||||
- return (SET_ERROR(-EINVAL));
|
|
||||||
-
|
|
||||||
- return (zvol_compat_ioctl(file->f_dentry->d_inode->i_bdev,
|
|
||||||
- file->f_mode, cmd, arg));
|
|
||||||
-}
|
|
||||||
+#ifdef HAVE_BLOCK_DEVICE_OPERATIONS_CHECK_EVENTS
|
|
||||||
+ .check_events = zvol_check_events,
|
|
||||||
#else
|
|
||||||
-#define zvol_compat_ioctl_by_inode NULL
|
|
||||||
-#endif
|
|
||||||
-
|
|
||||||
-static struct block_device_operations zvol_ops = {
|
|
||||||
- .open = zvol_open_by_inode,
|
|
||||||
- .release = zvol_release_by_inode,
|
|
||||||
- .ioctl = zvol_ioctl_by_inode,
|
|
||||||
- .compat_ioctl = zvol_compat_ioctl_by_inode,
|
|
||||||
.media_changed = zvol_media_changed,
|
|
||||||
+#endif
|
|
||||||
.revalidate_disk = zvol_revalidate_disk,
|
|
||||||
.getgeo = zvol_getgeo,
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
};
|
|
||||||
-#endif /* HAVE_BDEV_BLOCK_DEVICE_OPERATIONS */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Allocate memory for a new zvol_state_t and setup the required
|
|
||||||
@@ -1681,6 +1657,10 @@ zvol_alloc(dev_t dev, const char *name)
|
|
||||||
rw_init(&zv->zv_suspend_lock, NULL, RW_DEFAULT, NULL);
|
|
||||||
|
|
||||||
zv->zv_disk->major = zvol_major;
|
|
||||||
+#ifdef HAVE_BLOCK_DEVICE_OPERATIONS_CHECK_EVENTS
|
|
||||||
+ zv->zv_disk->events = DISK_EVENT_MEDIA_CHANGE;
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
if (volmode == ZFS_VOLMODE_DEV) {
|
|
||||||
/*
|
|
||||||
* ZFS_VOLMODE_DEV disable partitioning on ZVOL devices: set
|
|
||||||
@@ -1725,7 +1705,6 @@ zvol_free(void *arg)
|
|
||||||
{
|
|
||||||
zvol_state_t *zv = arg;
|
|
||||||
|
|
||||||
- ASSERT(!MUTEX_HELD(&zvol_state_lock));
|
|
||||||
ASSERT(!RW_LOCK_HELD(&zv->zv_suspend_lock));
|
|
||||||
ASSERT(!MUTEX_HELD(&zv->zv_state_lock));
|
|
||||||
ASSERT(zv->zv_open_count == 0);
|
|
||||||
@@ -1852,9 +1831,9 @@ zvol_create_minor_impl(const char *name)
|
|
||||||
kmem_free(doi, sizeof (dmu_object_info_t));
|
|
||||||
|
|
||||||
if (error == 0) {
|
|
||||||
- mutex_enter(&zvol_state_lock);
|
|
||||||
+ rw_enter(&zvol_state_lock, RW_WRITER);
|
|
||||||
zvol_insert(zv);
|
|
||||||
- mutex_exit(&zvol_state_lock);
|
|
||||||
+ rw_exit(&zvol_state_lock);
|
|
||||||
add_disk(zv->zv_disk);
|
|
||||||
} else {
|
|
||||||
ida_simple_remove(&zvol_ida, idx);
|
|
||||||
@@ -1871,7 +1850,7 @@ zvol_rename_minor(zvol_state_t *zv, const char *newname)
|
|
||||||
{
|
|
||||||
int readonly = get_disk_ro(zv->zv_disk);
|
|
||||||
|
|
||||||
- ASSERT(MUTEX_HELD(&zvol_state_lock));
|
|
||||||
+ ASSERT(RW_LOCK_HELD(&zvol_state_lock));
|
|
||||||
ASSERT(MUTEX_HELD(&zv->zv_state_lock));
|
|
||||||
|
|
||||||
strlcpy(zv->zv_name, newname, sizeof (zv->zv_name));
|
|
||||||
@@ -2111,7 +2090,7 @@ zvol_remove_minors_impl(const char *name)
|
|
||||||
list_create(&free_list, sizeof (zvol_state_t),
|
|
||||||
offsetof(zvol_state_t, zv_next));
|
|
||||||
|
|
||||||
- mutex_enter(&zvol_state_lock);
|
|
||||||
+ rw_enter(&zvol_state_lock, RW_WRITER);
|
|
||||||
|
|
||||||
for (zv = list_head(&zvol_state_list); zv != NULL; zv = zv_next) {
|
|
||||||
zv_next = list_next(&zvol_state_list, zv);
|
|
||||||
@@ -2136,15 +2115,15 @@ zvol_remove_minors_impl(const char *name)
|
|
||||||
zvol_remove(zv);
|
|
||||||
|
|
||||||
/*
|
|
||||||
- * clear this while holding zvol_state_lock so
|
|
||||||
- * zvol_open won't open it
|
|
||||||
+ * Cleared while holding zvol_state_lock as a writer
|
|
||||||
+ * which will prevent zvol_open() from opening it.
|
|
||||||
*/
|
|
||||||
zv->zv_disk->private_data = NULL;
|
|
||||||
|
|
||||||
/* Drop zv_state_lock before zvol_free() */
|
|
||||||
mutex_exit(&zv->zv_state_lock);
|
|
||||||
|
|
||||||
- /* try parallel zv_free, if failed do it in place */
|
|
||||||
+ /* Try parallel zv_free, if failed do it in place */
|
|
||||||
t = taskq_dispatch(system_taskq, zvol_free, zv,
|
|
||||||
TQ_SLEEP);
|
|
||||||
if (t == TASKQID_INVALID)
|
|
||||||
@@ -2155,11 +2134,9 @@ zvol_remove_minors_impl(const char *name)
|
|
||||||
mutex_exit(&zv->zv_state_lock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
- mutex_exit(&zvol_state_lock);
|
|
||||||
+ rw_exit(&zvol_state_lock);
|
|
||||||
|
|
||||||
- /*
|
|
||||||
- * Drop zvol_state_lock before calling zvol_free()
|
|
||||||
- */
|
|
||||||
+ /* Drop zvol_state_lock before calling zvol_free() */
|
|
||||||
while ((zv = list_head(&free_list)) != NULL) {
|
|
||||||
list_remove(&free_list, zv);
|
|
||||||
zvol_free(zv);
|
|
||||||
@@ -2178,7 +2155,7 @@ zvol_remove_minor_impl(const char *name)
|
|
||||||
if (zvol_inhibit_dev)
|
|
||||||
return;
|
|
||||||
|
|
||||||
- mutex_enter(&zvol_state_lock);
|
|
||||||
+ rw_enter(&zvol_state_lock, RW_WRITER);
|
|
||||||
|
|
||||||
for (zv = list_head(&zvol_state_list); zv != NULL; zv = zv_next) {
|
|
||||||
zv_next = list_next(&zvol_state_list, zv);
|
|
||||||
@@ -2198,7 +2175,10 @@ zvol_remove_minor_impl(const char *name)
|
|
||||||
}
|
|
||||||
zvol_remove(zv);
|
|
||||||
|
|
||||||
- /* clear this so zvol_open won't open it */
|
|
||||||
+ /*
|
|
||||||
+ * Cleared while holding zvol_state_lock as a writer
|
|
||||||
+ * which will prevent zvol_open() from opening it.
|
|
||||||
+ */
|
|
||||||
zv->zv_disk->private_data = NULL;
|
|
||||||
|
|
||||||
mutex_exit(&zv->zv_state_lock);
|
|
||||||
@@ -2209,7 +2189,7 @@ zvol_remove_minor_impl(const char *name)
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drop zvol_state_lock before calling zvol_free() */
|
|
||||||
- mutex_exit(&zvol_state_lock);
|
|
||||||
+ rw_exit(&zvol_state_lock);
|
|
||||||
|
|
||||||
if (zv != NULL)
|
|
||||||
zvol_free(zv);
|
|
||||||
@@ -2230,7 +2210,7 @@ zvol_rename_minors_impl(const char *oldname, const char *newname)
|
|
||||||
oldnamelen = strlen(oldname);
|
|
||||||
newnamelen = strlen(newname);
|
|
||||||
|
|
||||||
- mutex_enter(&zvol_state_lock);
|
|
||||||
+ rw_enter(&zvol_state_lock, RW_READER);
|
|
||||||
|
|
||||||
for (zv = list_head(&zvol_state_list); zv != NULL; zv = zv_next) {
|
|
||||||
zv_next = list_next(&zvol_state_list, zv);
|
|
||||||
@@ -2258,7 +2238,7 @@ zvol_rename_minors_impl(const char *oldname, const char *newname)
|
|
||||||
mutex_exit(&zv->zv_state_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
- mutex_exit(&zvol_state_lock);
|
|
||||||
+ rw_exit(&zvol_state_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct zvol_snapdev_cb_arg {
|
|
||||||
@@ -2635,7 +2615,7 @@ zvol_init(void)
|
|
||||||
|
|
||||||
list_create(&zvol_state_list, sizeof (zvol_state_t),
|
|
||||||
offsetof(zvol_state_t, zv_next));
|
|
||||||
- mutex_init(&zvol_state_lock, NULL, MUTEX_DEFAULT, NULL);
|
|
||||||
+ rw_init(&zvol_state_lock, NULL, RW_DEFAULT, NULL);
|
|
||||||
ida_init(&zvol_ida);
|
|
||||||
|
|
||||||
zvol_taskq = taskq_create(ZVOL_DRIVER, threads, maxclsyspri,
|
|
||||||
@@ -2672,7 +2652,7 @@ zvol_init(void)
|
|
||||||
taskq_destroy(zvol_taskq);
|
|
||||||
out:
|
|
||||||
ida_destroy(&zvol_ida);
|
|
||||||
- mutex_destroy(&zvol_state_lock);
|
|
||||||
+ rw_destroy(&zvol_state_lock);
|
|
||||||
list_destroy(&zvol_state_list);
|
|
||||||
|
|
||||||
return (SET_ERROR(error));
|
|
||||||
@@ -2689,7 +2669,7 @@ zvol_fini(void)
|
|
||||||
|
|
||||||
taskq_destroy(zvol_taskq);
|
|
||||||
list_destroy(&zvol_state_list);
|
|
||||||
- mutex_destroy(&zvol_state_lock);
|
|
||||||
+ rw_destroy(&zvol_state_lock);
|
|
||||||
|
|
||||||
ida_destroy(&zvol_ida);
|
|
||||||
}
|
|
@ -1,558 +0,0 @@ |
|||||||
From 9f64c1e8890fb4cd69c39a768afc633df404cd63 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Brian Behlendorf <behlendorf1@llnl.gov>
|
|
||||||
Date: Sun, 12 Aug 2018 18:22:03 -0400
|
|
||||||
Subject: [PATCH] Linux 4.18 compat: inode timespec -> timespec64
|
|
||||||
|
|
||||||
Commit torvalds/linux@95582b0 changes the inode i_atime, i_mtime,
|
|
||||||
and i_ctime members form timespec's to timespec64's to make them
|
|
||||||
2038 safe. As part of this change the current_time() function was
|
|
||||||
also updated to return the timespec64 type.
|
|
||||||
|
|
||||||
Resolve this issue by introducing a new inode_timespec_t type which
|
|
||||||
is defined to match the timespec type used by the inode. It should
|
|
||||||
be used when working with inode timestamps to ensure matching types.
|
|
||||||
|
|
||||||
The timestruc_t type under Illumos was used in a similar fashion but
|
|
||||||
was specified to always be a timespec_t. Rather than incorrectly
|
|
||||||
define this type all timespec_t types have been replaced by the new
|
|
||||||
inode_timespec_t type.
|
|
||||||
|
|
||||||
Finally, the kernel and user space 'sys/time.h' headers were aligned
|
|
||||||
with each other. They define as appropriate for the context several
|
|
||||||
constants as macros and include static inline implementation of
|
|
||||||
gethrestime(), gethrestime_sec(), and gethrtime().
|
|
||||||
|
|
||||||
Reviewed-by: Chunwei Chen <tuxoko@gmail.com>
|
|
||||||
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
|
|
||||||
Closes #7643
|
|
||||||
Backported-by: Richard Yao <ryao@gentoo.org>
|
|
||||||
---
|
|
||||||
config/kernel-current-time.m4 | 7 +++---
|
|
||||||
include/sys/dmu.h | 2 +-
|
|
||||||
include/sys/dmu_objset.h | 2 +-
|
|
||||||
include/sys/dsl_dir.h | 4 ++--
|
|
||||||
include/sys/spa_impl.h | 2 +-
|
|
||||||
include/sys/xvattr.h | 2 +-
|
|
||||||
include/sys/zfs_context.h | 9 +------
|
|
||||||
include/sys/zfs_znode.h | 33 ++++++++++++++++++-------
|
|
||||||
include/sys/zpl.h | 9 +++++++
|
|
||||||
lib/libspl/Makefile.am | 2 --
|
|
||||||
lib/libspl/gethrestime.c | 38 -----------------------------
|
|
||||||
lib/libspl/gethrtime.c | 45 -----------------------------------
|
|
||||||
lib/libspl/include/sys/time.h | 37 +++++++++++++++++++++-------
|
|
||||||
lib/libzpool/kernel.c | 4 ++--
|
|
||||||
module/zfs/dmu_objset.c | 2 +-
|
|
||||||
module/zfs/dsl_dir.c | 6 ++---
|
|
||||||
module/zfs/fm.c | 2 +-
|
|
||||||
module/zfs/zfs_ctldir.c | 2 +-
|
|
||||||
module/zfs/zfs_vnops.c | 4 ++--
|
|
||||||
module/zfs/zfs_znode.c | 4 ++--
|
|
||||||
module/zfs/zpl_inode.c | 5 ++--
|
|
||||||
21 files changed, 88 insertions(+), 133 deletions(-)
|
|
||||||
delete mode 100644 lib/libspl/gethrestime.c
|
|
||||||
delete mode 100644 lib/libspl/gethrtime.c
|
|
||||||
|
|
||||||
diff --git a/config/kernel-current-time.m4 b/config/kernel-current-time.m4
|
|
||||||
index 2ede9ff38c4..c7d5c9b5200 100644
|
|
||||||
--- a/config/kernel-current-time.m4
|
|
||||||
+++ b/config/kernel-current-time.m4
|
|
||||||
@@ -1,15 +1,14 @@
|
|
||||||
dnl #
|
|
||||||
dnl # 4.9, current_time() added
|
|
||||||
+dnl # 4.18, return type changed from timespec to timespec64
|
|
||||||
dnl #
|
|
||||||
AC_DEFUN([ZFS_AC_KERNEL_CURRENT_TIME],
|
|
||||||
[AC_MSG_CHECKING([whether current_time() exists])
|
|
||||||
ZFS_LINUX_TRY_COMPILE_SYMBOL([
|
|
||||||
#include <linux/fs.h>
|
|
||||||
], [
|
|
||||||
- struct inode ip;
|
|
||||||
- struct timespec now __attribute__ ((unused));
|
|
||||||
-
|
|
||||||
- now = current_time(&ip);
|
|
||||||
+ struct inode ip __attribute__ ((unused));
|
|
||||||
+ ip.i_atime = current_time(&ip);
|
|
||||||
], [current_time], [fs/inode.c], [
|
|
||||||
AC_MSG_RESULT(yes)
|
|
||||||
AC_DEFINE(HAVE_CURRENT_TIME, 1, [current_time() exists])
|
|
||||||
diff --git a/include/sys/dmu.h b/include/sys/dmu.h
|
|
||||||
index bcdf7d646fb..755a90561ae 100644
|
|
||||||
--- a/include/sys/dmu.h
|
|
||||||
+++ b/include/sys/dmu.h
|
|
||||||
@@ -891,7 +891,7 @@ uint64_t dmu_objset_fsid_guid(objset_t *os);
|
|
||||||
/*
|
|
||||||
* Get the [cm]time for an objset's snapshot dir
|
|
||||||
*/
|
|
||||||
-timestruc_t dmu_objset_snap_cmtime(objset_t *os);
|
|
||||||
+inode_timespec_t dmu_objset_snap_cmtime(objset_t *os);
|
|
||||||
|
|
||||||
int dmu_objset_is_snapshot(objset_t *os);
|
|
||||||
|
|
||||||
diff --git a/include/sys/dmu_objset.h b/include/sys/dmu_objset.h
|
|
||||||
index a836e03722c..531e81d4d88 100644
|
|
||||||
--- a/include/sys/dmu_objset.h
|
|
||||||
+++ b/include/sys/dmu_objset.h
|
|
||||||
@@ -179,7 +179,7 @@ int dmu_objset_find_dp(struct dsl_pool *dp, uint64_t ddobj,
|
|
||||||
int func(struct dsl_pool *, struct dsl_dataset *, void *),
|
|
||||||
void *arg, int flags);
|
|
||||||
void dmu_objset_evict_dbufs(objset_t *os);
|
|
||||||
-timestruc_t dmu_objset_snap_cmtime(objset_t *os);
|
|
||||||
+inode_timespec_t dmu_objset_snap_cmtime(objset_t *os);
|
|
||||||
|
|
||||||
/* called from dsl */
|
|
||||||
void dmu_objset_sync(objset_t *os, zio_t *zio, dmu_tx_t *tx);
|
|
||||||
diff --git a/include/sys/dsl_dir.h b/include/sys/dsl_dir.h
|
|
||||||
index 69b0b6a5355..80e83fdc4d3 100644
|
|
||||||
--- a/include/sys/dsl_dir.h
|
|
||||||
+++ b/include/sys/dsl_dir.h
|
|
||||||
@@ -103,7 +103,7 @@ struct dsl_dir {
|
|
||||||
/* Protected by dd_lock */
|
|
||||||
kmutex_t dd_lock;
|
|
||||||
list_t dd_props; /* list of dsl_prop_record_t's */
|
|
||||||
- timestruc_t dd_snap_cmtime; /* last time snapshot namespace changed */
|
|
||||||
+ inode_timespec_t dd_snap_cmtime; /* last snapshot namespace change */
|
|
||||||
uint64_t dd_origin_txg;
|
|
||||||
|
|
||||||
/* gross estimate of space used by in-flight tx's */
|
|
||||||
@@ -159,7 +159,7 @@ boolean_t dsl_dir_is_clone(dsl_dir_t *dd);
|
|
||||||
void dsl_dir_new_refreservation(dsl_dir_t *dd, struct dsl_dataset *ds,
|
|
||||||
uint64_t reservation, cred_t *cr, dmu_tx_t *tx);
|
|
||||||
void dsl_dir_snap_cmtime_update(dsl_dir_t *dd);
|
|
||||||
-timestruc_t dsl_dir_snap_cmtime(dsl_dir_t *dd);
|
|
||||||
+inode_timespec_t dsl_dir_snap_cmtime(dsl_dir_t *dd);
|
|
||||||
void dsl_dir_set_reservation_sync_impl(dsl_dir_t *dd, uint64_t value,
|
|
||||||
dmu_tx_t *tx);
|
|
||||||
void dsl_dir_zapify(dsl_dir_t *dd, dmu_tx_t *tx);
|
|
||||||
diff --git a/include/sys/spa_impl.h b/include/sys/spa_impl.h
|
|
||||||
index b1e78c1d592..fa7490ace67 100644
|
|
||||||
--- a/include/sys/spa_impl.h
|
|
||||||
+++ b/include/sys/spa_impl.h
|
|
||||||
@@ -153,7 +153,7 @@ struct spa {
|
|
||||||
uint64_t spa_freeze_txg; /* freeze pool at this txg */
|
|
||||||
uint64_t spa_load_max_txg; /* best initial ub_txg */
|
|
||||||
uint64_t spa_claim_max_txg; /* highest claimed birth txg */
|
|
||||||
- timespec_t spa_loaded_ts; /* 1st successful open time */
|
|
||||||
+ inode_timespec_t spa_loaded_ts; /* 1st successful open time */
|
|
||||||
objset_t *spa_meta_objset; /* copy of dp->dp_meta_objset */
|
|
||||||
kmutex_t spa_evicting_os_lock; /* Evicting objset list lock */
|
|
||||||
list_t spa_evicting_os_list; /* Objsets being evicted. */
|
|
||||||
diff --git a/include/sys/xvattr.h b/include/sys/xvattr.h
|
|
||||||
index 4779b632163..5d38927cd4b 100644
|
|
||||||
--- a/include/sys/xvattr.h
|
|
||||||
+++ b/include/sys/xvattr.h
|
|
||||||
@@ -47,7 +47,7 @@
|
|
||||||
* Structure of all optional attributes.
|
|
||||||
*/
|
|
||||||
typedef struct xoptattr {
|
|
||||||
- timestruc_t xoa_createtime; /* Create time of file */
|
|
||||||
+ inode_timespec_t xoa_createtime; /* Create time of file */
|
|
||||||
uint8_t xoa_archive;
|
|
||||||
uint8_t xoa_system;
|
|
||||||
uint8_t xoa_readonly;
|
|
||||||
diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h
|
|
||||||
index 4fe35342dee..68c58f95531 100644
|
|
||||||
--- a/include/sys/zfs_context.h
|
|
||||||
+++ b/include/sys/zfs_context.h
|
|
||||||
@@ -527,7 +527,7 @@ extern char *vn_dumpdir;
|
|
||||||
#define AV_SCANSTAMP_SZ 32 /* length of anti-virus scanstamp */
|
|
||||||
|
|
||||||
typedef struct xoptattr {
|
|
||||||
- timestruc_t xoa_createtime; /* Create time of file */
|
|
||||||
+ inode_timespec_t xoa_createtime; /* Create time of file */
|
|
||||||
uint8_t xoa_archive;
|
|
||||||
uint8_t xoa_system;
|
|
||||||
uint8_t xoa_readonly;
|
|
||||||
@@ -640,13 +640,6 @@ extern void delay(clock_t ticks);
|
|
||||||
#define USEC_TO_TICK(usec) ((usec) / (MICROSEC / hz))
|
|
||||||
#define NSEC_TO_TICK(usec) ((usec) / (NANOSEC / hz))
|
|
||||||
|
|
||||||
-#define gethrestime_sec() time(NULL)
|
|
||||||
-#define gethrestime(t) \
|
|
||||||
- do {\
|
|
||||||
- (t)->tv_sec = gethrestime_sec();\
|
|
||||||
- (t)->tv_nsec = 0;\
|
|
||||||
- } while (0);
|
|
||||||
-
|
|
||||||
#define max_ncpus 64
|
|
||||||
#define boot_ncpus (sysconf(_SC_NPROCESSORS_ONLN))
|
|
||||||
|
|
||||||
diff --git a/include/sys/zfs_znode.h b/include/sys/zfs_znode.h
|
|
||||||
index c292f03739e..26d1eb37557 100644
|
|
||||||
--- a/include/sys/zfs_znode.h
|
|
||||||
+++ b/include/sys/zfs_znode.h
|
|
||||||
@@ -270,19 +270,36 @@ typedef struct znode_hold {
|
|
||||||
|
|
||||||
extern unsigned int zfs_object_mutex_size;
|
|
||||||
|
|
||||||
-/* Encode ZFS stored time values from a struct timespec */
|
|
||||||
+/*
|
|
||||||
+ * Encode ZFS stored time values from a struct timespec / struct timespec64.
|
|
||||||
+ */
|
|
||||||
#define ZFS_TIME_ENCODE(tp, stmp) \
|
|
||||||
-{ \
|
|
||||||
+do { \
|
|
||||||
(stmp)[0] = (uint64_t)(tp)->tv_sec; \
|
|
||||||
(stmp)[1] = (uint64_t)(tp)->tv_nsec; \
|
|
||||||
-}
|
|
||||||
+} while (0)
|
|
||||||
|
|
||||||
-/* Decode ZFS stored time values to a struct timespec */
|
|
||||||
+#if defined(HAVE_INODE_TIMESPEC64_TIMES)
|
|
||||||
+/*
|
|
||||||
+ * Decode ZFS stored time values to a struct timespec64
|
|
||||||
+ * 4.18 and newer kernels.
|
|
||||||
+ */
|
|
||||||
#define ZFS_TIME_DECODE(tp, stmp) \
|
|
||||||
-{ \
|
|
||||||
- (tp)->tv_sec = (time_t)(stmp)[0]; \
|
|
||||||
- (tp)->tv_nsec = (long)(stmp)[1]; \
|
|
||||||
-}
|
|
||||||
+do { \
|
|
||||||
+ (tp)->tv_sec = (time64_t)(stmp)[0]; \
|
|
||||||
+ (tp)->tv_nsec = (long)(stmp)[1]; \
|
|
||||||
+} while (0)
|
|
||||||
+#else
|
|
||||||
+/*
|
|
||||||
+ * Decode ZFS stored time values to a struct timespec
|
|
||||||
+ * 4.17 and older kernels.
|
|
||||||
+ */
|
|
||||||
+#define ZFS_TIME_DECODE(tp, stmp) \
|
|
||||||
+do { \
|
|
||||||
+ (tp)->tv_sec = (time_t)(stmp)[0]; \
|
|
||||||
+ (tp)->tv_nsec = (long)(stmp)[1]; \
|
|
||||||
+} while (0)
|
|
||||||
+#endif /* HAVE_INODE_TIMESPEC64_TIMES */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Timestamp defines
|
|
||||||
diff --git a/include/sys/zpl.h b/include/sys/zpl.h
|
|
||||||
index 65ed4313603..e433fbc64ea 100644
|
|
||||||
--- a/include/sys/zpl.h
|
|
||||||
+++ b/include/sys/zpl.h
|
|
||||||
@@ -189,4 +189,13 @@ zpl_dir_emit_dots(struct file *file, zpl_dir_context_t *ctx)
|
|
||||||
}
|
|
||||||
#endif /* HAVE_VFS_ITERATE */
|
|
||||||
|
|
||||||
+/*
|
|
||||||
+ * Linux 4.18, inode times converted from timespec to timespec64.
|
|
||||||
+ */
|
|
||||||
+#if defined(HAVE_INODE_TIMESPEC64_TIMES)
|
|
||||||
+#define zpl_inode_timespec_trunc(ts, gran) timespec64_trunc(ts, gran)
|
|
||||||
+#else
|
|
||||||
+#define zpl_inode_timespec_trunc(ts, gran) timespec_trunc(ts, gran)
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
#endif /* _SYS_ZPL_H */
|
|
||||||
diff --git a/lib/libspl/Makefile.am b/lib/libspl/Makefile.am
|
|
||||||
index 59bc8ffb42f..a6e63cb8868 100644
|
|
||||||
--- a/lib/libspl/Makefile.am
|
|
||||||
+++ b/lib/libspl/Makefile.am
|
|
||||||
@@ -19,8 +19,6 @@ noinst_LTLIBRARIES = libspl.la
|
|
||||||
|
|
||||||
USER_C = \
|
|
||||||
getexecname.c \
|
|
||||||
- gethrtime.c \
|
|
||||||
- gethrestime.c \
|
|
||||||
getmntany.c \
|
|
||||||
list.c \
|
|
||||||
mkdirp.c \
|
|
||||||
diff --git a/lib/libspl/gethrestime.c b/lib/libspl/gethrestime.c
|
|
||||||
deleted file mode 100644
|
|
||||||
index d37cc2d5994..00000000000
|
|
||||||
--- a/lib/libspl/gethrestime.c
|
|
||||||
+++ /dev/null
|
|
||||||
@@ -1,38 +0,0 @@
|
|
||||||
-/*
|
|
||||||
- * CDDL HEADER START
|
|
||||||
- *
|
|
||||||
- * The contents of this file are subject to the terms of the
|
|
||||||
- * Common Development and Distribution License (the "License").
|
|
||||||
- * You may not use this file except in compliance with the License.
|
|
||||||
- *
|
|
||||||
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
|
||||||
- * or http://www.opensolaris.org/os/licensing.
|
|
||||||
- * See the License for the specific language governing permissions
|
|
||||||
- * and limitations under the License.
|
|
||||||
- *
|
|
||||||
- * When distributing Covered Code, include this CDDL HEADER in each
|
|
||||||
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
|
||||||
- * If applicable, add the following below this CDDL HEADER, with the
|
|
||||||
- * fields enclosed by brackets "[]" replaced with your own identifying
|
|
||||||
- * information: Portions Copyright [yyyy] [name of copyright owner]
|
|
||||||
- *
|
|
||||||
- * CDDL HEADER END
|
|
||||||
- */
|
|
||||||
-
|
|
||||||
-/*
|
|
||||||
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
|
|
||||||
- * Use is subject to license terms.
|
|
||||||
- */
|
|
||||||
-
|
|
||||||
-#include <time.h>
|
|
||||||
-#include <sys/time.h>
|
|
||||||
-
|
|
||||||
-void
|
|
||||||
-gethrestime(timestruc_t *ts)
|
|
||||||
-{
|
|
||||||
- struct timeval tv;
|
|
||||||
-
|
|
||||||
- gettimeofday(&tv, NULL);
|
|
||||||
- ts->tv_sec = tv.tv_sec;
|
|
||||||
- ts->tv_nsec = tv.tv_usec * NSEC_PER_USEC;
|
|
||||||
-}
|
|
||||||
diff --git a/lib/libspl/gethrtime.c b/lib/libspl/gethrtime.c
|
|
||||||
deleted file mode 100644
|
|
||||||
index 95ceb18e119..00000000000
|
|
||||||
--- a/lib/libspl/gethrtime.c
|
|
||||||
+++ /dev/null
|
|
||||||
@@ -1,45 +0,0 @@
|
|
||||||
-/*
|
|
||||||
- * CDDL HEADER START
|
|
||||||
- *
|
|
||||||
- * The contents of this file are subject to the terms of the
|
|
||||||
- * Common Development and Distribution License (the "License").
|
|
||||||
- * You may not use this file except in compliance with the License.
|
|
||||||
- *
|
|
||||||
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
|
||||||
- * or http://www.opensolaris.org/os/licensing.
|
|
||||||
- * See the License for the specific language governing permissions
|
|
||||||
- * and limitations under the License.
|
|
||||||
- *
|
|
||||||
- * When distributing Covered Code, include this CDDL HEADER in each
|
|
||||||
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
|
||||||
- * If applicable, add the following below this CDDL HEADER, with the
|
|
||||||
- * fields enclosed by brackets "[]" replaced with your own identifying
|
|
||||||
- * information: Portions Copyright [yyyy] [name of copyright owner]
|
|
||||||
- *
|
|
||||||
- * CDDL HEADER END
|
|
||||||
- */
|
|
||||||
-
|
|
||||||
-/*
|
|
||||||
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
|
|
||||||
- * Use is subject to license terms.
|
|
||||||
- */
|
|
||||||
-
|
|
||||||
-#include <time.h>
|
|
||||||
-#include <sys/time.h>
|
|
||||||
-#include <stdlib.h>
|
|
||||||
-#include <stdio.h>
|
|
||||||
-
|
|
||||||
-hrtime_t
|
|
||||||
-gethrtime(void)
|
|
||||||
-{
|
|
||||||
- struct timespec ts;
|
|
||||||
- int rc;
|
|
||||||
-
|
|
||||||
- rc = clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
||||||
- if (rc) {
|
|
||||||
- fprintf(stderr, "Error: clock_gettime() = %d\n", rc);
|
|
||||||
- abort();
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- return ((((u_int64_t)ts.tv_sec) * NANOSEC) + ts.tv_nsec);
|
|
||||||
-}
|
|
||||||
diff --git a/lib/libspl/include/sys/time.h b/lib/libspl/include/sys/time.h
|
|
||||||
index dc645fa5c37..04b3ba87bd3 100644
|
|
||||||
--- a/lib/libspl/include/sys/time.h
|
|
||||||
+++ b/lib/libspl/include/sys/time.h
|
|
||||||
@@ -27,8 +27,9 @@
|
|
||||||
#ifndef _LIBSPL_SYS_TIME_H
|
|
||||||
#define _LIBSPL_SYS_TIME_H
|
|
||||||
|
|
||||||
-#include_next <sys/time.h>
|
|
||||||
+#include <time.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
+#include_next <sys/time.h>
|
|
||||||
|
|
||||||
#ifndef SEC
|
|
||||||
#define SEC 1
|
|
||||||
@@ -70,13 +71,33 @@
|
|
||||||
#define SEC2NSEC(m) ((hrtime_t)(m) * (NANOSEC / SEC))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
-
|
|
||||||
typedef long long hrtime_t;
|
|
||||||
-typedef struct timespec timestruc_t;
|
|
||||||
-typedef struct timespec timespec_t;
|
|
||||||
-
|
|
||||||
-
|
|
||||||
-extern hrtime_t gethrtime(void);
|
|
||||||
-extern void gethrestime(timestruc_t *);
|
|
||||||
+typedef struct timespec timespec_t;
|
|
||||||
+typedef struct timespec inode_timespec_t;
|
|
||||||
+
|
|
||||||
+static inline void
|
|
||||||
+gethrestime(inode_timespec_t *ts)
|
|
||||||
+{
|
|
||||||
+ struct timeval tv;
|
|
||||||
+ (void) gettimeofday(&tv, NULL);
|
|
||||||
+ ts->tv_sec = tv.tv_sec;
|
|
||||||
+ ts->tv_nsec = tv.tv_usec * NSEC_PER_USEC;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static inline time_t
|
|
||||||
+gethrestime_sec(void)
|
|
||||||
+{
|
|
||||||
+ struct timeval tv;
|
|
||||||
+ (void) gettimeofday(&tv, NULL);
|
|
||||||
+ return (tv.tv_sec);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static inline hrtime_t
|
|
||||||
+gethrtime(void)
|
|
||||||
+{
|
|
||||||
+ struct timespec ts;
|
|
||||||
+ (void) clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
||||||
+ return ((((u_int64_t)ts.tv_sec) * NANOSEC) + ts.tv_nsec);
|
|
||||||
+}
|
|
||||||
|
|
||||||
#endif /* _LIBSPL_SYS_TIME_H */
|
|
||||||
diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c
|
|
||||||
index e67d13c9265..3ea8778b1dc 100644
|
|
||||||
--- a/lib/libzpool/kernel.c
|
|
||||||
+++ b/lib/libzpool/kernel.c
|
|
||||||
@@ -498,7 +498,7 @@ cv_timedwait(kcondvar_t *cv, kmutex_t *mp, clock_t abstime)
|
|
||||||
{
|
|
||||||
int error;
|
|
||||||
struct timeval tv;
|
|
||||||
- timestruc_t ts;
|
|
||||||
+ struct timespec ts;
|
|
||||||
clock_t delta;
|
|
||||||
|
|
||||||
ASSERT3U(cv->cv_magic, ==, CV_MAGIC);
|
|
||||||
@@ -536,7 +536,7 @@ cv_timedwait_hires(kcondvar_t *cv, kmutex_t *mp, hrtime_t tim, hrtime_t res,
|
|
||||||
{
|
|
||||||
int error;
|
|
||||||
struct timeval tv;
|
|
||||||
- timestruc_t ts;
|
|
||||||
+ struct timespec ts;
|
|
||||||
hrtime_t delta;
|
|
||||||
|
|
||||||
ASSERT(flag == 0 || flag == CALLOUT_FLAG_ABSOLUTE);
|
|
||||||
diff --git a/module/zfs/dmu_objset.c b/module/zfs/dmu_objset.c
|
|
||||||
index 3425d542f98..449ebedfa16 100644
|
|
||||||
--- a/module/zfs/dmu_objset.c
|
|
||||||
+++ b/module/zfs/dmu_objset.c
|
|
||||||
@@ -860,7 +860,7 @@ dmu_objset_evict_done(objset_t *os)
|
|
||||||
kmem_free(os, sizeof (objset_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
-timestruc_t
|
|
||||||
+inode_timespec_t
|
|
||||||
dmu_objset_snap_cmtime(objset_t *os)
|
|
||||||
{
|
|
||||||
return (dsl_dir_snap_cmtime(os->os_dsl_dataset->ds_dir));
|
|
||||||
diff --git a/module/zfs/dsl_dir.c b/module/zfs/dsl_dir.c
|
|
||||||
index a3ef5896a3f..deecf6bc53e 100644
|
|
||||||
--- a/module/zfs/dsl_dir.c
|
|
||||||
+++ b/module/zfs/dsl_dir.c
|
|
||||||
@@ -1975,10 +1975,10 @@ dsl_dir_transfer_possible(dsl_dir_t *sdd, dsl_dir_t *tdd,
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
-timestruc_t
|
|
||||||
+inode_timespec_t
|
|
||||||
dsl_dir_snap_cmtime(dsl_dir_t *dd)
|
|
||||||
{
|
|
||||||
- timestruc_t t;
|
|
||||||
+ inode_timespec_t t;
|
|
||||||
|
|
||||||
mutex_enter(&dd->dd_lock);
|
|
||||||
t = dd->dd_snap_cmtime;
|
|
||||||
@@ -1990,7 +1990,7 @@ dsl_dir_snap_cmtime(dsl_dir_t *dd)
|
|
||||||
void
|
|
||||||
dsl_dir_snap_cmtime_update(dsl_dir_t *dd)
|
|
||||||
{
|
|
||||||
- timestruc_t t;
|
|
||||||
+ inode_timespec_t t;
|
|
||||||
|
|
||||||
gethrestime(&t);
|
|
||||||
mutex_enter(&dd->dd_lock);
|
|
||||||
diff --git a/module/zfs/fm.c b/module/zfs/fm.c
|
|
||||||
index cb148149376..9d26cc99eeb 100644
|
|
||||||
--- a/module/zfs/fm.c
|
|
||||||
+++ b/module/zfs/fm.c
|
|
||||||
@@ -508,8 +508,8 @@ zfs_zevent_insert(zevent_t *ev)
|
|
||||||
int
|
|
||||||
zfs_zevent_post(nvlist_t *nvl, nvlist_t *detector, zevent_cb_t *cb)
|
|
||||||
{
|
|
||||||
+ inode_timespec_t tv;
|
|
||||||
int64_t tv_array[2];
|
|
||||||
- timestruc_t tv;
|
|
||||||
uint64_t eid;
|
|
||||||
size_t nvl_size = 0;
|
|
||||||
zevent_t *ev;
|
|
||||||
diff --git a/module/zfs/zfs_ctldir.c b/module/zfs/zfs_ctldir.c
|
|
||||||
index 3b5fb196f1d..3ff2c101b67 100644
|
|
||||||
--- a/module/zfs/zfs_ctldir.c
|
|
||||||
+++ b/module/zfs/zfs_ctldir.c
|
|
||||||
@@ -451,7 +451,7 @@ static struct inode *
|
|
||||||
zfsctl_inode_alloc(zfsvfs_t *zfsvfs, uint64_t id,
|
|
||||||
const struct file_operations *fops, const struct inode_operations *ops)
|
|
||||||
{
|
|
||||||
- struct timespec now;
|
|
||||||
+ inode_timespec_t now;
|
|
||||||
struct inode *ip;
|
|
||||||
znode_t *zp;
|
|
||||||
|
|
||||||
diff --git a/module/zfs/zfs_vnops.c b/module/zfs/zfs_vnops.c
|
|
||||||
index 0d2b61a1c31..34ea751c320 100644
|
|
||||||
--- a/module/zfs/zfs_vnops.c
|
|
||||||
+++ b/module/zfs/zfs_vnops.c
|
|
||||||
@@ -3158,7 +3158,7 @@ zfs_setattr(struct inode *ip, vattr_t *vap, int flags, cred_t *cr)
|
|
||||||
|
|
||||||
if (mask & (ATTR_MTIME | ATTR_SIZE)) {
|
|
||||||
ZFS_TIME_ENCODE(&vap->va_mtime, mtime);
|
|
||||||
- ZTOI(zp)->i_mtime = timespec_trunc(vap->va_mtime,
|
|
||||||
+ ZTOI(zp)->i_mtime = zpl_inode_timespec_trunc(vap->va_mtime,
|
|
||||||
ZTOI(zp)->i_sb->s_time_gran);
|
|
||||||
|
|
||||||
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MTIME(zfsvfs), NULL,
|
|
||||||
@@ -3167,7 +3167,7 @@ zfs_setattr(struct inode *ip, vattr_t *vap, int flags, cred_t *cr)
|
|
||||||
|
|
||||||
if (mask & (ATTR_CTIME | ATTR_SIZE)) {
|
|
||||||
ZFS_TIME_ENCODE(&vap->va_ctime, ctime);
|
|
||||||
- ZTOI(zp)->i_ctime = timespec_trunc(vap->va_ctime,
|
|
||||||
+ ZTOI(zp)->i_ctime = zpl_inode_timespec_trunc(vap->va_ctime,
|
|
||||||
ZTOI(zp)->i_sb->s_time_gran);
|
|
||||||
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs), NULL,
|
|
||||||
ctime, sizeof (ctime));
|
|
||||||
diff --git a/module/zfs/zfs_znode.c b/module/zfs/zfs_znode.c
|
|
||||||
index f508a248f0f..e222c791183 100644
|
|
||||||
--- a/module/zfs/zfs_znode.c
|
|
||||||
+++ b/module/zfs/zfs_znode.c
|
|
||||||
@@ -700,7 +700,7 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, dmu_tx_t *tx, cred_t *cr,
|
|
||||||
uint64_t rdev = 0;
|
|
||||||
zfsvfs_t *zfsvfs = ZTOZSB(dzp);
|
|
||||||
dmu_buf_t *db;
|
|
||||||
- timestruc_t now;
|
|
||||||
+ inode_timespec_t now;
|
|
||||||
uint64_t gen, obj;
|
|
||||||
int bonuslen;
|
|
||||||
int dnodesize;
|
|
||||||
@@ -1349,7 +1349,7 @@ void
|
|
||||||
zfs_tstamp_update_setup(znode_t *zp, uint_t flag, uint64_t mtime[2],
|
|
||||||
uint64_t ctime[2])
|
|
||||||
{
|
|
||||||
- timestruc_t now;
|
|
||||||
+ inode_timespec_t now;
|
|
||||||
|
|
||||||
gethrestime(&now);
|
|
||||||
|
|
||||||
diff --git a/module/zfs/zpl_inode.c b/module/zfs/zpl_inode.c
|
|
||||||
index 3b5643d0917..41b91cabcb9 100644
|
|
||||||
--- a/module/zfs/zpl_inode.c
|
|
||||||
+++ b/module/zfs/zpl_inode.c
|
|
||||||
@@ -384,9 +384,10 @@ zpl_setattr(struct dentry *dentry, struct iattr *ia)
|
|
||||||
vap->va_mtime = ia->ia_mtime;
|
|
||||||
vap->va_ctime = ia->ia_ctime;
|
|
||||||
|
|
||||||
- if (vap->va_mask & ATTR_ATIME)
|
|
||||||
- ip->i_atime = timespec_trunc(ia->ia_atime,
|
|
||||||
+ if (vap->va_mask & ATTR_ATIME) {
|
|
||||||
+ ip->i_atime = zpl_inode_timespec_trunc(ia->ia_atime,
|
|
||||||
ip->i_sb->s_time_gran);
|
|
||||||
+ }
|
|
||||||
|
|
||||||
cookie = spl_fstrans_mark();
|
|
||||||
error = -zfs_setattr(ip, vap, 0, cr);
|
|
@ -1,89 +0,0 @@ |
|||||||
From ac09630d8b0bf6c92084a30fdaefd03fd0adbdc1 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Brian Behlendorf <behlendorf1@llnl.gov>
|
|
||||||
Date: Wed, 11 Jul 2018 15:49:10 -0700
|
|
||||||
Subject: [PATCH] Fix zpl_mount() deadlock
|
|
||||||
|
|
||||||
Commit 93b43af10 inadvertently introduced the following scenario which
|
|
||||||
can result in a deadlock. This issue was most easily reproduced by
|
|
||||||
LXD containers using a ZFS storage backend but should be reproducible
|
|
||||||
under any workload which is frequently mounting and unmounting.
|
|
||||||
|
|
||||||
-- THREAD A --
|
|
||||||
spa_sync()
|
|
||||||
spa_sync_upgrades()
|
|
||||||
rrw_enter(&dp->dp_config_rwlock, RW_WRITER, FTAG); <- Waiting on B
|
|
||||||
|
|
||||||
-- THREAD B --
|
|
||||||
mount_fs()
|
|
||||||
zpl_mount()
|
|
||||||
zpl_mount_impl()
|
|
||||||
dmu_objset_hold()
|
|
||||||
dmu_objset_hold_flags()
|
|
||||||
dsl_pool_hold()
|
|
||||||
dsl_pool_config_enter()
|
|
||||||
rrw_enter(&dp->dp_config_rwlock, RW_READER, tag);
|
|
||||||
sget()
|
|
||||||
sget_userns()
|
|
||||||
grab_super()
|
|
||||||
down_write(&s->s_umount); <- Waiting on C
|
|
||||||
|
|
||||||
-- THREAD C --
|
|
||||||
cleanup_mnt()
|
|
||||||
deactivate_super()
|
|
||||||
down_write(&s->s_umount);
|
|
||||||
deactivate_locked_super()
|
|
||||||
zpl_kill_sb()
|
|
||||||
kill_anon_super()
|
|
||||||
generic_shutdown_super()
|
|
||||||
sync_filesystem()
|
|
||||||
zpl_sync_fs()
|
|
||||||
zfs_sync()
|
|
||||||
zil_commit()
|
|
||||||
txg_wait_synced() <- Waiting on A
|
|
||||||
|
|
||||||
Reviewed by: Alek Pinchuk <apinchuk@datto.com>
|
|
||||||
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
|
|
||||||
Closes #7598
|
|
||||||
Closes #7659
|
|
||||||
Closes #7691
|
|
||||||
Closes #7693
|
|
||||||
---
|
|
||||||
include/sys/zfs_vfsops.h | 1 +
|
|
||||||
module/zfs/zpl_super.c | 11 ++++++++++-
|
|
||||||
2 files changed, 11 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/include/sys/zfs_vfsops.h b/include/sys/zfs_vfsops.h
|
|
||||||
index febfdff97f2..31c9c6d7f74 100644
|
|
||||||
--- a/include/sys/zfs_vfsops.h
|
|
||||||
+++ b/include/sys/zfs_vfsops.h
|
|
||||||
@@ -32,6 +32,7 @@
|
|
||||||
#include <sys/zil.h>
|
|
||||||
#include <sys/sa.h>
|
|
||||||
#include <sys/rrwlock.h>
|
|
||||||
+#include <sys/dsl_dataset.h>
|
|
||||||
#include <sys/zfs_ioctl.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
diff --git a/module/zfs/zpl_super.c b/module/zfs/zpl_super.c
|
|
||||||
index fc10271b787..5c426b0a9fb 100644
|
|
||||||
--- a/module/zfs/zpl_super.c
|
|
||||||
+++ b/module/zfs/zpl_super.c
|
|
||||||
@@ -271,8 +271,17 @@ zpl_mount_impl(struct file_system_type *fs_type, int flags, zfs_mnt_t *zm)
|
|
||||||
if (err)
|
|
||||||
return (ERR_PTR(-err));
|
|
||||||
|
|
||||||
+ /*
|
|
||||||
+ * The dsl pool lock must be released prior to calling sget().
|
|
||||||
+ * It is possible sget() may block on the lock in grab_super()
|
|
||||||
+ * while deactivate_super() holds that same lock and waits for
|
|
||||||
+ * a txg sync. If the dsl_pool lock is held over over sget()
|
|
||||||
+ * this can prevent the pool sync and cause a deadlock.
|
|
||||||
+ */
|
|
||||||
+ dsl_pool_rele(dmu_objset_pool(os), FTAG);
|
|
||||||
s = zpl_sget(fs_type, zpl_test_super, set_anon_super, flags, os);
|
|
||||||
- dmu_objset_rele(os, FTAG);
|
|
||||||
+ dsl_dataset_rele(dmu_objset_ds(os), FTAG);
|
|
||||||
+
|
|
||||||
if (IS_ERR(s))
|
|
||||||
return (ERR_CAST(s));
|
|
||||||
|
|
Loading…
Reference in new issue