Print this page
3996 want a libzfs_core API to rollback to latest snapshot
Reviewed by: Christopher Siden <christopher.siden@delphix.com>
Reviewed by: Adam Leventhal <ahl@delphix.com>
Reviewed by: George Wilson <george.wilson@delphix.com>


3501                 (void) changelist_postfix(clp);
3502                 changelist_free(clp);
3503         }
3504 
3505         zfs_close(zhp);
3506         return (0);
3507 }
3508 
3509 /*
3510  * Given a dataset, rollback to a specific snapshot, discarding any
3511  * data changes since then and making it the active dataset.
3512  *
3513  * Any snapshots more recent than the target are destroyed, along with
3514  * their dependents.
3515  */
3516 int
3517 zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force)
3518 {
3519         rollback_data_t cb = { 0 };
3520         int err;
3521         zfs_cmd_t zc = { 0 };
3522         boolean_t restore_resv = 0;
3523         uint64_t old_volsize, new_volsize;
3524         zfs_prop_t resv_prop;
3525 
3526         assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM ||
3527             zhp->zfs_type == ZFS_TYPE_VOLUME);
3528 
3529         /*
3530          * Destroy all recent snapshots and their dependents.
3531          */
3532         cb.cb_force = force;
3533         cb.cb_target = snap->zfs_name;
3534         cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG);
3535         (void) zfs_iter_children(zhp, rollback_destroy, &cb);
3536 
3537         if (cb.cb_error)
3538                 return (-1);
3539 
3540         /*
3541          * Now that we have verified that the snapshot is the latest,
3542          * rollback to the given snapshot.
3543          */
3544 
3545         if (zhp->zfs_type == ZFS_TYPE_VOLUME) {
3546                 if (zfs_which_resv_prop(zhp, &resv_prop) < 0)
3547                         return (-1);
3548                 old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
3549                 restore_resv =
3550                     (old_volsize == zfs_prop_get_int(zhp, resv_prop));
3551         }
3552 
3553         (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
3554 
3555         if (ZFS_IS_VOLUME(zhp))
3556                 zc.zc_objset_type = DMU_OST_ZVOL;
3557         else
3558                 zc.zc_objset_type = DMU_OST_ZFS;
3559 
3560         /*
3561          * We rely on zfs_iter_children() to verify that there are no
3562          * newer snapshots for the given dataset.  Therefore, we can
3563          * simply pass the name on to the ioctl() call.  There is still
3564          * an unlikely race condition where the user has taken a
3565          * snapshot since we verified that this was the most recent.
3566          *
3567          */
3568         if ((err = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_ROLLBACK, &zc)) != 0) {

3569                 (void) zfs_standard_error_fmt(zhp->zfs_hdl, errno,
3570                     dgettext(TEXT_DOMAIN, "cannot rollback '%s'"),
3571                     zhp->zfs_name);
3572                 return (err);
3573         }
3574 
3575         /*
3576          * For volumes, if the pre-rollback volsize matched the pre-
3577          * rollback reservation and the volsize has changed then set
3578          * the reservation property to the post-rollback volsize.
3579          * Make a new handle since the rollback closed the dataset.
3580          */
3581         if ((zhp->zfs_type == ZFS_TYPE_VOLUME) &&
3582             (zhp = make_dataset_handle(zhp->zfs_hdl, zhp->zfs_name))) {
3583                 if (restore_resv) {
3584                         new_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
3585                         if (old_volsize != new_volsize)
3586                                 err = zfs_prop_set_int(zhp, resv_prop,
3587                                     new_volsize);
3588                 }




3501                 (void) changelist_postfix(clp);
3502                 changelist_free(clp);
3503         }
3504 
3505         zfs_close(zhp);
3506         return (0);
3507 }
3508 
3509 /*
3510  * Given a dataset, rollback to a specific snapshot, discarding any
3511  * data changes since then and making it the active dataset.
3512  *
3513  * Any snapshots more recent than the target are destroyed, along with
3514  * their dependents.
3515  */
3516 int
3517 zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force)
3518 {
3519         rollback_data_t cb = { 0 };
3520         int err;

3521         boolean_t restore_resv = 0;
3522         uint64_t old_volsize, new_volsize;
3523         zfs_prop_t resv_prop;
3524 
3525         assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM ||
3526             zhp->zfs_type == ZFS_TYPE_VOLUME);
3527 
3528         /*
3529          * Destroy all recent snapshots and their dependents.
3530          */
3531         cb.cb_force = force;
3532         cb.cb_target = snap->zfs_name;
3533         cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG);
3534         (void) zfs_iter_children(zhp, rollback_destroy, &cb);
3535 
3536         if (cb.cb_error)
3537                 return (-1);
3538 
3539         /*
3540          * Now that we have verified that the snapshot is the latest,
3541          * rollback to the given snapshot.
3542          */
3543 
3544         if (zhp->zfs_type == ZFS_TYPE_VOLUME) {
3545                 if (zfs_which_resv_prop(zhp, &resv_prop) < 0)
3546                         return (-1);
3547                 old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
3548                 restore_resv =
3549                     (old_volsize == zfs_prop_get_int(zhp, resv_prop));
3550         }
3551 







3552         /*
3553          * We rely on zfs_iter_children() to verify that there are no
3554          * newer snapshots for the given dataset.  Therefore, we can
3555          * simply pass the name on to the ioctl() call.  There is still
3556          * an unlikely race condition where the user has taken a
3557          * snapshot since we verified that this was the most recent.

3558          */
3559         err = lzc_rollback(zhp->zfs_name, NULL, 0);
3560         if (err != 0) {
3561                 (void) zfs_standard_error_fmt(zhp->zfs_hdl, errno,
3562                     dgettext(TEXT_DOMAIN, "cannot rollback '%s'"),
3563                     zhp->zfs_name);
3564                 return (err);
3565         }
3566 
3567         /*
3568          * For volumes, if the pre-rollback volsize matched the pre-
3569          * rollback reservation and the volsize has changed then set
3570          * the reservation property to the post-rollback volsize.
3571          * Make a new handle since the rollback closed the dataset.
3572          */
3573         if ((zhp->zfs_type == ZFS_TYPE_VOLUME) &&
3574             (zhp = make_dataset_handle(zhp->zfs_hdl, zhp->zfs_name))) {
3575                 if (restore_resv) {
3576                         new_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
3577                         if (old_volsize != new_volsize)
3578                                 err = zfs_prop_set_int(zhp, resv_prop,
3579                                     new_volsize);
3580                 }