diff options
-rw-r--r-- | include/sys/zfs_rlock.h | 1 | ||||
-rw-r--r-- | module/zfs/zfs_rlock.c | 21 |
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); } /* |