diff options
author | Chunwei Chen <[email protected]> | 2017-01-19 13:56:36 -0800 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2017-01-19 13:56:36 -0800 |
commit | 040dab993936d832df4c7624bbcdb71c3fb9b34b (patch) | |
tree | 0261aedba3c5e6fdda94a0a10388d065f0802924 /module/zfs/dsl_dataset.c | |
parent | 76fe529b392068dfb7575739542cd4f69d2d4343 (diff) |
Suspend/resume zvol for recv and rollback
When doing recv and rollback, dsl_dataset_clone_swap_sync_impl will be
called to swap out the ds_objset and do dmu_objset_evict on the old one.
However, currently zv->zv_objset will not be swapped out accordingly, so
if anyone currently holds a fd on the zvol, we risk hitting a use-after-free.
We fix this by introducing the suspend and resume mechanism of zsb to
zv. Before recv or rollback, we use zvol_suspend to block all access to
zv_objset and shut it down. After the recv or rollback, we use zvol_resume
to swap in zv_objset with the new ds_objset and unblock the access.
Reviewed-by: Brian Behlendorf <[email protected]>
Signed-off-by: Chunwei Chen <[email protected]>
Closes #4866
Closes #5609
Diffstat (limited to 'module/zfs/dsl_dataset.c')
-rw-r--r-- | module/zfs/dsl_dataset.c | 5 |
1 files changed, 2 insertions, 3 deletions
diff --git a/module/zfs/dsl_dataset.c b/module/zfs/dsl_dataset.c index 43fecf28b..ddab3eddb 100644 --- a/module/zfs/dsl_dataset.c +++ b/module/zfs/dsl_dataset.c @@ -2124,8 +2124,7 @@ dsl_dataset_rename_snapshot(const char *fsname, * only one long hold on the dataset. We're not allowed to change anything here * so we don't permanently release the long hold or regular hold here. We want * to do this only when syncing to avoid the dataset unexpectedly going away - * when we release the long hold. Allow a long hold to exist for volumes, this - * may occur when asynchronously registering the minor with the kernel. + * when we release the long hold. */ static int dsl_dataset_handoff_check(dsl_dataset_t *ds, void *owner, dmu_tx_t *tx) @@ -2140,7 +2139,7 @@ dsl_dataset_handoff_check(dsl_dataset_t *ds, void *owner, dmu_tx_t *tx) dsl_dataset_long_rele(ds, owner); } - held = (dsl_dataset_long_held(ds) && (ds->ds_owner != zvol_tag)); + held = dsl_dataset_long_held(ds); if (owner != NULL) dsl_dataset_long_hold(ds, owner); |