mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-24 19:28:53 +03:00
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 <behlendorf1@llnl.gov> Signed-off-by: Chunwei Chen <david.chen@osnexus.com> Closes #4866 Closes #5609
This commit is contained in:
committed by
Brian Behlendorf
parent
76fe529b39
commit
040dab9939
@@ -3641,6 +3641,7 @@ static int
|
||||
zfs_ioc_rollback(const char *fsname, nvlist_t *args, nvlist_t *outnvl)
|
||||
{
|
||||
zfs_sb_t *zsb;
|
||||
zvol_state_t *zv;
|
||||
int error;
|
||||
|
||||
if (get_zfs_sb(fsname, &zsb) == 0) {
|
||||
@@ -3653,6 +3654,9 @@ zfs_ioc_rollback(const char *fsname, nvlist_t *args, nvlist_t *outnvl)
|
||||
error = error ? error : resume_err;
|
||||
}
|
||||
deactivate_super(zsb->z_sb);
|
||||
} else if ((zv = zvol_suspend(fsname)) != NULL) {
|
||||
error = dsl_dataset_rollback(fsname, zvol_tag(zv), outnvl);
|
||||
zvol_resume(zv);
|
||||
} else {
|
||||
error = dsl_dataset_rollback(fsname, NULL, outnvl);
|
||||
}
|
||||
@@ -4240,6 +4244,7 @@ zfs_ioc_recv_impl(char *tofs, char *tosnap, char *origin,
|
||||
|
||||
if (error == 0) {
|
||||
zfs_sb_t *zsb = NULL;
|
||||
zvol_state_t *zv = NULL;
|
||||
|
||||
if (get_zfs_sb(tofs, &zsb) == 0) {
|
||||
/* online recv */
|
||||
@@ -4255,6 +4260,9 @@ zfs_ioc_recv_impl(char *tofs, char *tosnap, char *origin,
|
||||
error = zfs_resume_fs(zsb, tofs);
|
||||
error = error ? error : end_err;
|
||||
deactivate_super(zsb->z_sb);
|
||||
} else if ((zv = zvol_suspend(tofs)) != NULL) {
|
||||
error = dmu_recv_end(&drc, zvol_tag(zv));
|
||||
zvol_resume(zv);
|
||||
} else {
|
||||
error = dmu_recv_end(&drc, NULL);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user