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 }
|