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>


1705 
1706         if (owner != NULL) {
1707                 VERIFY3P(ds->ds_owner, ==, owner);
1708                 dsl_dataset_long_rele(ds, owner);
1709         }
1710 
1711         held = dsl_dataset_long_held(ds);
1712 
1713         if (owner != NULL)
1714                 dsl_dataset_long_hold(ds, owner);
1715 
1716         if (held)
1717                 return (SET_ERROR(EBUSY));
1718 
1719         return (0);
1720 }
1721 
1722 typedef struct dsl_dataset_rollback_arg {
1723         const char *ddra_fsname;
1724         void *ddra_owner;

1725 } dsl_dataset_rollback_arg_t;
1726 
1727 static int
1728 dsl_dataset_rollback_check(void *arg, dmu_tx_t *tx)
1729 {
1730         dsl_dataset_rollback_arg_t *ddra = arg;
1731         dsl_pool_t *dp = dmu_tx_pool(tx);
1732         dsl_dataset_t *ds;
1733         int64_t unused_refres_delta;
1734         int error;
1735 
1736         error = dsl_dataset_hold(dp, ddra->ddra_fsname, FTAG, &ds);
1737         if (error != 0)
1738                 return (error);
1739 
1740         /* must not be a snapshot */
1741         if (dsl_dataset_is_snapshot(ds)) {
1742                 dsl_dataset_rele(ds, FTAG);
1743                 return (SET_ERROR(EINVAL));
1744         }


1776             ds->ds_phys->ds_unique_bytes);
1777 
1778         if (unused_refres_delta > 0 &&
1779             unused_refres_delta >
1780             dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE)) {
1781                 dsl_dataset_rele(ds, FTAG);
1782                 return (SET_ERROR(ENOSPC));
1783         }
1784 
1785         dsl_dataset_rele(ds, FTAG);
1786         return (0);
1787 }
1788 
1789 static void
1790 dsl_dataset_rollback_sync(void *arg, dmu_tx_t *tx)
1791 {
1792         dsl_dataset_rollback_arg_t *ddra = arg;
1793         dsl_pool_t *dp = dmu_tx_pool(tx);
1794         dsl_dataset_t *ds, *clone;
1795         uint64_t cloneobj;

1796 
1797         VERIFY0(dsl_dataset_hold(dp, ddra->ddra_fsname, FTAG, &ds));
1798 



1799         cloneobj = dsl_dataset_create_sync(ds->ds_dir, "%rollback",
1800             ds->ds_prev, DS_CREATE_FLAG_NODIRTY, kcred, tx);
1801 
1802         VERIFY0(dsl_dataset_hold_obj(dp, cloneobj, FTAG, &clone));
1803 
1804         dsl_dataset_clone_swap_sync_impl(clone, ds, tx);
1805         dsl_dataset_zero_zil(ds, tx);
1806 
1807         dsl_destroy_head_sync_impl(clone, tx);
1808 
1809         dsl_dataset_rele(clone, FTAG);
1810         dsl_dataset_rele(ds, FTAG);
1811 }
1812 
1813 /*
1814  * If owner != NULL:


1815  *

1816  * - The existing dataset MUST be owned by the specified owner at entry
1817  * - Upon return, dataset will still be held by the same owner, whether we
1818  *   succeed or not.
1819  *
1820  * This mode is required any time the existing filesystem is mounted.  See
1821  * notes above zfs_suspend_fs() for further details.
1822  */
1823 int
1824 dsl_dataset_rollback(const char *fsname, void *owner)
1825 {
1826         dsl_dataset_rollback_arg_t ddra;
1827 
1828         ddra.ddra_fsname = fsname;
1829         ddra.ddra_owner = owner;

1830 
1831         return (dsl_sync_task(fsname, dsl_dataset_rollback_check,
1832             dsl_dataset_rollback_sync, (void *)&ddra, 1));
1833 }
1834 
1835 struct promotenode {
1836         list_node_t link;
1837         dsl_dataset_t *ds;
1838 };
1839 
1840 typedef struct dsl_dataset_promote_arg {
1841         const char *ddpa_clonename;
1842         dsl_dataset_t *ddpa_clone;
1843         list_t shared_snaps, origin_snaps, clone_snaps;
1844         dsl_dataset_t *origin_origin; /* origin of the origin */
1845         uint64_t used, comp, uncomp, unique, cloneusedsnap, originusedsnap;
1846         char *err_ds;
1847 } dsl_dataset_promote_arg_t;
1848 
1849 static int snaplist_space(list_t *l, uint64_t mintxg, uint64_t *spacep);
1850 static int promote_hold(dsl_dataset_promote_arg_t *ddpa, dsl_pool_t *dp,
1851     void *tag);
1852 static void promote_rele(dsl_dataset_promote_arg_t *ddpa, void *tag);




1705 
1706         if (owner != NULL) {
1707                 VERIFY3P(ds->ds_owner, ==, owner);
1708                 dsl_dataset_long_rele(ds, owner);
1709         }
1710 
1711         held = dsl_dataset_long_held(ds);
1712 
1713         if (owner != NULL)
1714                 dsl_dataset_long_hold(ds, owner);
1715 
1716         if (held)
1717                 return (SET_ERROR(EBUSY));
1718 
1719         return (0);
1720 }
1721 
1722 typedef struct dsl_dataset_rollback_arg {
1723         const char *ddra_fsname;
1724         void *ddra_owner;
1725         nvlist_t *ddra_result;
1726 } dsl_dataset_rollback_arg_t;
1727 
1728 static int
1729 dsl_dataset_rollback_check(void *arg, dmu_tx_t *tx)
1730 {
1731         dsl_dataset_rollback_arg_t *ddra = arg;
1732         dsl_pool_t *dp = dmu_tx_pool(tx);
1733         dsl_dataset_t *ds;
1734         int64_t unused_refres_delta;
1735         int error;
1736 
1737         error = dsl_dataset_hold(dp, ddra->ddra_fsname, FTAG, &ds);
1738         if (error != 0)
1739                 return (error);
1740 
1741         /* must not be a snapshot */
1742         if (dsl_dataset_is_snapshot(ds)) {
1743                 dsl_dataset_rele(ds, FTAG);
1744                 return (SET_ERROR(EINVAL));
1745         }


1777             ds->ds_phys->ds_unique_bytes);
1778 
1779         if (unused_refres_delta > 0 &&
1780             unused_refres_delta >
1781             dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE)) {
1782                 dsl_dataset_rele(ds, FTAG);
1783                 return (SET_ERROR(ENOSPC));
1784         }
1785 
1786         dsl_dataset_rele(ds, FTAG);
1787         return (0);
1788 }
1789 
1790 static void
1791 dsl_dataset_rollback_sync(void *arg, dmu_tx_t *tx)
1792 {
1793         dsl_dataset_rollback_arg_t *ddra = arg;
1794         dsl_pool_t *dp = dmu_tx_pool(tx);
1795         dsl_dataset_t *ds, *clone;
1796         uint64_t cloneobj;
1797         char namebuf[ZFS_MAXNAMELEN];
1798 
1799         VERIFY0(dsl_dataset_hold(dp, ddra->ddra_fsname, FTAG, &ds));
1800 
1801         dsl_dataset_name(ds->ds_prev, namebuf);
1802         fnvlist_add_string(ddra->ddra_result, "target", namebuf);
1803 
1804         cloneobj = dsl_dataset_create_sync(ds->ds_dir, "%rollback",
1805             ds->ds_prev, DS_CREATE_FLAG_NODIRTY, kcred, tx);
1806 
1807         VERIFY0(dsl_dataset_hold_obj(dp, cloneobj, FTAG, &clone));
1808 
1809         dsl_dataset_clone_swap_sync_impl(clone, ds, tx);
1810         dsl_dataset_zero_zil(ds, tx);
1811 
1812         dsl_destroy_head_sync_impl(clone, tx);
1813 
1814         dsl_dataset_rele(clone, FTAG);
1815         dsl_dataset_rele(ds, FTAG);
1816 }
1817 
1818 /*
1819  * Rolls back the given filesystem or volume to the most recent snapshot.
1820  * The name of the most recent snapshot will be returned under key "target"
1821  * in the result nvlist.
1822  *
1823  * If owner != NULL:
1824  * - The existing dataset MUST be owned by the specified owner at entry
1825  * - Upon return, dataset will still be held by the same owner, whether we
1826  *   succeed or not.
1827  *
1828  * This mode is required any time the existing filesystem is mounted.  See
1829  * notes above zfs_suspend_fs() for further details.
1830  */
1831 int
1832 dsl_dataset_rollback(const char *fsname, void *owner, nvlist_t *result)
1833 {
1834         dsl_dataset_rollback_arg_t ddra;
1835 
1836         ddra.ddra_fsname = fsname;
1837         ddra.ddra_owner = owner;
1838         ddra.ddra_result = result;
1839 
1840         return (dsl_sync_task(fsname, dsl_dataset_rollback_check,
1841             dsl_dataset_rollback_sync, &ddra, 1));
1842 }
1843 
1844 struct promotenode {
1845         list_node_t link;
1846         dsl_dataset_t *ds;
1847 };
1848 
1849 typedef struct dsl_dataset_promote_arg {
1850         const char *ddpa_clonename;
1851         dsl_dataset_t *ddpa_clone;
1852         list_t shared_snaps, origin_snaps, clone_snaps;
1853         dsl_dataset_t *origin_origin; /* origin of the origin */
1854         uint64_t used, comp, uncomp, unique, cloneusedsnap, originusedsnap;
1855         char *err_ds;
1856 } dsl_dataset_promote_arg_t;
1857 
1858 static int snaplist_space(list_t *l, uint64_t mintxg, uint64_t *spacep);
1859 static int promote_hold(dsl_dataset_promote_arg_t *ddpa, dsl_pool_t *dp,
1860     void *tag);
1861 static void promote_rele(dsl_dataset_promote_arg_t *ddpa, void *tag);