summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sys/zfs_rlock.h1
-rw-r--r--module/zfs/zfs_rlock.c21
2 files changed, 16 insertions, 6 deletions
diff --git a/include/sys/zfs_rlock.h b/include/sys/zfs_rlock.h
index 722c341e2..da18b1f18 100644
--- a/include/sys/zfs_rlock.h
+++ b/include/sys/zfs_rlock.h
@@ -54,6 +54,7 @@ typedef struct rl {
uint8_t r_proxy; /* acting for original range */
uint8_t r_write_wanted; /* writer wants to lock this range */
uint8_t r_read_wanted; /* reader wants to lock this range */
+ list_node_t rl_node; /* used for deferred release */
} rl_t;
/*
diff --git a/module/zfs/zfs_rlock.c b/module/zfs/zfs_rlock.c
index 26ad58de8..f3ada1706 100644
--- a/module/zfs/zfs_rlock.c
+++ b/module/zfs/zfs_rlock.c
@@ -471,7 +471,7 @@ zfs_range_free(void *arg)
* Unlock a reader lock
*/
static void
-zfs_range_unlock_reader(znode_t *zp, rl_t *remove)
+zfs_range_unlock_reader(znode_t *zp, rl_t *remove, list_t *free_list)
{
avl_tree_t *tree = &zp->z_range_avl;
rl_t *rl, *next = NULL;
@@ -493,7 +493,7 @@ zfs_range_unlock_reader(znode_t *zp, rl_t *remove)
if (remove->r_read_wanted)
cv_broadcast(&remove->r_rd_cv);
- taskq_dispatch(system_taskq, zfs_range_free, remove, 0);
+ list_insert_tail(free_list, remove);
} else {
ASSERT3U(remove->r_cnt, ==, 0);
ASSERT3U(remove->r_write_wanted, ==, 0);
@@ -526,8 +526,7 @@ zfs_range_unlock_reader(znode_t *zp, rl_t *remove)
if (rl->r_read_wanted)
cv_broadcast(&rl->r_rd_cv);
- taskq_dispatch(system_taskq,
- zfs_range_free, rl, 0);
+ list_insert_tail(free_list, rl);
}
}
@@ -543,10 +542,13 @@ void
zfs_range_unlock(rl_t *rl)
{
znode_t *zp = rl->r_zp;
+ list_t free_list;
+ rl_t *free_rl;
ASSERT(rl->r_type == RL_WRITER || rl->r_type == RL_READER);
ASSERT(rl->r_cnt == 1 || rl->r_cnt == 0);
ASSERT(!rl->r_proxy);
+ list_create(&free_list, sizeof(rl_t), offsetof(rl_t, rl_node));
mutex_enter(&zp->z_range_lock);
if (rl->r_type == RL_WRITER) {
@@ -559,14 +561,21 @@ zfs_range_unlock(rl_t *rl)
if (rl->r_read_wanted)
cv_broadcast(&rl->r_rd_cv);
- taskq_dispatch(system_taskq, zfs_range_free, rl, 0);
+ list_insert_tail(&free_list, rl);
} else {
/*
* lock may be shared, let zfs_range_unlock_reader()
* release the zp->z_range_lock lock and free the rl_t
*/
- zfs_range_unlock_reader(zp, rl);
+ zfs_range_unlock_reader(zp, rl, &free_list);
}
+
+ while ((free_rl = list_head(&free_list)) != NULL) {
+ list_remove(&free_list, free_rl);
+ zfs_range_free(free_rl);
+ }
+
+ list_destroy(&free_list);
}
/*