Print this page
*** NO COMMENTS ***

@@ -848,29 +848,23 @@
                 if (flags & DRR_FLAG_CLONE) {
                         dsl_dataset_rele(ds, dmu_recv_tag);
                         return (EINVAL);
                 }
 
-                /* must not have an incremental recv already in progress */
-                if (!mutex_tryenter(&ds->ds_recvlock)) {
-                        dsl_dataset_rele(ds, dmu_recv_tag);
-                        return (EBUSY);
-                }
-
                 /* tmp clone name is: tofs/%tosnap" */
                 (void) snprintf(rbsa.clonelastname, sizeof (rbsa.clonelastname),
                     "%%%s", tosnap);
                 rbsa.force = force;
                 err = dsl_sync_task_do(ds->ds_dir->dd_pool,
                     recv_existing_check, recv_existing_sync, ds, &rbsa, 5);
                 if (err) {
-                        mutex_exit(&ds->ds_recvlock);
                         dsl_dataset_rele(ds, dmu_recv_tag);
                         return (err);
                 }
-                drc->drc_logical_ds = ds;
+                drc->drc_logical_dsobj = ds->ds_object;
                 drc->drc_real_ds = rbsa.ds;
+                dsl_dataset_rele(ds, dmu_recv_tag);
         } else if (err == ENOENT) {
                 /* target fs does not exist; must be a full backup or clone */
                 char *cp;
 
                 /*

@@ -896,11 +890,11 @@
                 err = dsl_sync_task_do(ds->ds_dir->dd_pool,
                     recv_new_check, recv_new_sync, ds->ds_dir, &rbsa, 5);
                 dsl_dataset_rele(ds, FTAG);
                 if (err)
                         return (err);
-                drc->drc_logical_ds = drc->drc_real_ds = rbsa.ds;
+                drc->drc_real_ds = rbsa.ds;
                 drc->drc_newfs = B_TRUE;
         }
 
         return (err);
 }

@@ -1526,14 +1520,10 @@
                  */
                 txg_wait_synced(drc->drc_real_ds->ds_dir->dd_pool, 0);
 
                 (void) dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag,
                     B_FALSE);
-                if (drc->drc_real_ds != drc->drc_logical_ds) {
-                        mutex_exit(&drc->drc_logical_ds->ds_recvlock);
-                        dsl_dataset_rele(drc->drc_logical_ds, dmu_recv_tag);
-                }
         }
 
         kmem_free(ra.buf, ra.bufsize);
         *voffp = ra.voff;
         return (ra.err);

@@ -1598,32 +1588,35 @@
 
 static int
 dmu_recv_existing_end(dmu_recv_cookie_t *drc)
 {
         struct recvendsyncarg resa;
-        dsl_dataset_t *ds = drc->drc_logical_ds;
+        dsl_dataset_t *ds;
         int err, myerr;
+        dsl_pool_t *dp = drc->drc_real_ds->ds_dir->dd_pool;
+
+        rw_enter(&dp->dp_config_rwlock, RW_READER);
+        err = dsl_dataset_own_obj(dp, drc->drc_logical_dsobj, FALSE,
+            dmu_recv_tag, &ds);
+        rw_exit(&dp->dp_config_rwlock);
+
+        if (err) {
+                (void) dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag,
+                    B_FALSE);
+                return (EBUSY);
+        }
 
         /*
          * XXX hack; seems the ds is still dirty and dsl_pool_zil_clean()
          * expects it to have a ds_user_ptr (and zil), but clone_swap()
          * can close it.
          */
         txg_wait_synced(ds->ds_dir->dd_pool, 0);
 
-        if (dsl_dataset_tryown(ds, FALSE, dmu_recv_tag)) {
-                err = dsl_dataset_clone_swap(drc->drc_real_ds, ds,
-                    drc->drc_force);
+        err = dsl_dataset_clone_swap(drc->drc_real_ds, ds, drc->drc_force);
                 if (err)
                         goto out;
-        } else {
-                mutex_exit(&ds->ds_recvlock);
-                dsl_dataset_rele(ds, dmu_recv_tag);
-                (void) dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag,
-                    B_FALSE);
-                return (EBUSY);
-        }
 
         resa.creation_time = drc->drc_drrb->drr_creation_time;
         resa.toguid = drc->drc_drrb->drr_toguid;
         resa.tosnap = drc->drc_tosnap;
 

@@ -1633,11 +1626,10 @@
                 /* swap back */
                 (void) dsl_dataset_clone_swap(drc->drc_real_ds, ds, B_TRUE);
         }
 
 out:
-        mutex_exit(&ds->ds_recvlock);
         if (err == 0 && drc->drc_guid_to_ds_map != NULL)
                 (void) add_ds_to_guidmap(drc->drc_guid_to_ds_map, ds);
         dsl_dataset_disown(ds, dmu_recv_tag);
         myerr = dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag, B_FALSE);
         ASSERT3U(myerr, ==, 0);

@@ -1646,11 +1638,11 @@
 
 static int
 dmu_recv_new_end(dmu_recv_cookie_t *drc)
 {
         struct recvendsyncarg resa;
-        dsl_dataset_t *ds = drc->drc_logical_ds;
+        dsl_dataset_t *ds = drc->drc_real_ds;
         int err;
 
         /*
          * XXX hack; seems the ds is still dirty and dsl_pool_zil_clean()
          * expects it to have a ds_user_ptr (and zil), but clone_swap()

@@ -1677,10 +1669,10 @@
 }
 
 int
 dmu_recv_end(dmu_recv_cookie_t *drc)
 {
-        if (drc->drc_logical_ds != drc->drc_real_ds)
+        if (!drc->drc_newfs)
                 return (dmu_recv_existing_end(drc));
         else
                 return (dmu_recv_new_end(drc));
 }