@@ -1669,16 +1669,52 @@ dsl_dataset_rename_snapshot(const char *fsname,
1669
1669
dsl_dataset_rename_snapshot_sync , & ddrsa , 1 ));
1670
1670
}
1671
1671
1672
+ /*
1673
+ * If we're doing an ownership handoff, we need to make sure that there is
1674
+ * only one long hold on the dataset. We're not allowed to change anything here
1675
+ * so we don't permanently release the long hold or regular hold here. We want
1676
+ * to do this only when syncing to avoid the dataset unexpectedly going away
1677
+ * when we release the long hold.
1678
+ */
1679
+ static int
1680
+ dsl_dataset_handoff_check (dsl_dataset_t * ds , void * owner , dmu_tx_t * tx )
1681
+ {
1682
+ boolean_t held ;
1683
+
1684
+ if (!dmu_tx_is_syncing (tx ))
1685
+ return (0 );
1686
+
1687
+ if (owner != NULL ) {
1688
+ VERIFY3P (ds -> ds_owner , = = , owner );
1689
+ dsl_dataset_long_rele (ds , owner );
1690
+ }
1691
+
1692
+ held = dsl_dataset_long_held (ds );
1693
+
1694
+ if (owner != NULL )
1695
+ dsl_dataset_long_hold (ds , owner );
1696
+
1697
+ if (held )
1698
+ return (SET_ERROR (EBUSY ));
1699
+
1700
+ return (0 );
1701
+ }
1702
+
1703
+ typedef struct dsl_dataset_rollback_arg {
1704
+ const char * ddra_fsname ;
1705
+ void * ddra_owner ;
1706
+ } dsl_dataset_rollback_arg_t ;
1707
+
1672
1708
static int
1673
1709
dsl_dataset_rollback_check (void * arg , dmu_tx_t * tx )
1674
1710
{
1675
- const char * fsname = arg ;
1711
+ dsl_dataset_rollback_arg_t * ddra = arg ;
1676
1712
dsl_pool_t * dp = dmu_tx_pool (tx );
1677
1713
dsl_dataset_t * ds ;
1678
1714
int64_t unused_refres_delta ;
1679
1715
int error ;
1680
1716
1681
- error = dsl_dataset_hold (dp , fsname , FTAG , & ds );
1717
+ error = dsl_dataset_hold (dp , ddra -> ddra_fsname , FTAG , & ds );
1682
1718
if (error != 0 )
1683
1719
return (error );
1684
1720
@@ -1694,9 +1730,10 @@ dsl_dataset_rollback_check(void *arg, dmu_tx_t *tx)
1694
1730
return (SET_ERROR (EINVAL ));
1695
1731
}
1696
1732
1697
- if (dsl_dataset_long_held (ds )) {
1733
+ error = dsl_dataset_handoff_check (ds , ddra -> ddra_owner , tx );
1734
+ if (error != 0 ) {
1698
1735
dsl_dataset_rele (ds , FTAG );
1699
- return (SET_ERROR ( EBUSY ) );
1736
+ return (error );
1700
1737
}
1701
1738
1702
1739
/*
@@ -1733,12 +1770,12 @@ dsl_dataset_rollback_check(void *arg, dmu_tx_t *tx)
1733
1770
static void
1734
1771
dsl_dataset_rollback_sync (void * arg , dmu_tx_t * tx )
1735
1772
{
1736
- const char * fsname = arg ;
1773
+ dsl_dataset_rollback_arg_t * ddra = arg ;
1737
1774
dsl_pool_t * dp = dmu_tx_pool (tx );
1738
1775
dsl_dataset_t * ds , * clone ;
1739
1776
uint64_t cloneobj ;
1740
1777
1741
- VERIFY0 (dsl_dataset_hold (dp , fsname , FTAG , & ds ));
1778
+ VERIFY0 (dsl_dataset_hold (dp , ddra -> ddra_fsname , FTAG , & ds ));
1742
1779
1743
1780
cloneobj = dsl_dataset_create_sync (ds -> ds_dir , "%rollback" ,
1744
1781
ds -> ds_prev , DS_CREATE_FLAG_NODIRTY , kcred , tx );
@@ -1754,11 +1791,26 @@ dsl_dataset_rollback_sync(void *arg, dmu_tx_t *tx)
1754
1791
dsl_dataset_rele (ds , FTAG );
1755
1792
}
1756
1793
1794
+ /*
1795
+ * If owner != NULL:
1796
+ *
1797
+ * - The existing dataset MUST be owned by the specified owner at entry
1798
+ * - Upon return, dataset will still be held by the same owner, whether we
1799
+ * succeed or not.
1800
+ *
1801
+ * This mode is required any time the existing filesystem is mounted. See
1802
+ * notes above zfs_suspend_fs() for further details.
1803
+ */
1757
1804
int
1758
- dsl_dataset_rollback (const char * fsname )
1805
+ dsl_dataset_rollback (const char * fsname , void * owner )
1759
1806
{
1807
+ dsl_dataset_rollback_arg_t ddra ;
1808
+
1809
+ ddra .ddra_fsname = fsname ;
1810
+ ddra .ddra_owner = owner ;
1811
+
1760
1812
return (dsl_sync_task (fsname , dsl_dataset_rollback_check ,
1761
- dsl_dataset_rollback_sync , (void * )fsname , 1 ));
1813
+ dsl_dataset_rollback_sync , (void * )& ddra , 1 ));
1762
1814
}
1763
1815
1764
1816
struct promotenode {
@@ -2276,7 +2328,7 @@ dsl_dataset_promote(const char *name, char *conflsnap)
2276
2328
2277
2329
int
2278
2330
dsl_dataset_clone_swap_check_impl (dsl_dataset_t * clone ,
2279
- dsl_dataset_t * origin_head , boolean_t force )
2331
+ dsl_dataset_t * origin_head , boolean_t force , void * owner , dmu_tx_t * tx )
2280
2332
{
2281
2333
int64_t unused_refres_delta ;
2282
2334
@@ -2305,7 +2357,7 @@ dsl_dataset_clone_swap_check_impl(dsl_dataset_t *clone,
2305
2357
return (SET_ERROR (ETXTBSY ));
2306
2358
2307
2359
/* origin_head should have no long holds (e.g. is not mounted) */
2308
- if (dsl_dataset_long_held (origin_head ))
2360
+ if (dsl_dataset_handoff_check (origin_head , owner , tx ))
2309
2361
return (SET_ERROR (EBUSY ));
2310
2362
2311
2363
/* check amount of any unconsumed refreservation */
0 commit comments