Print this page
2882 implement libzfs_core
2883 changing "canmount" property to "on" should not always remount dataset
2900 "zfs snapshot" should be able to create multiple, arbitrary snapshots at once
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed by: Chris Siden <christopher.siden@delphix.com>
Reviewed by: Garrett D'Amore <garrett@damore.org>
Reviewed by: Bill Pijewski <wdp@joyent.com>
Reviewed by: Dan Kruchinin <dan.kruchinin@gmail.com>

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/zfs/dmu_send.c
          +++ new/usr/src/uts/common/fs/zfs/dmu_send.c
↓ open down ↓ 379 lines elided ↑ open up ↑
 380  380  
 381  381                  err = dump_data(dsp, type, zb->zb_object, zb->zb_blkid * blksz,
 382  382                      blksz, bp, abuf->b_data);
 383  383                  (void) arc_buf_remove_ref(abuf, &abuf);
 384  384          }
 385  385  
 386  386          ASSERT(err == 0 || err == EINTR);
 387  387          return (err);
 388  388  }
 389  389  
      390 +/*
      391 + * Return TRUE if 'earlier' is an earlier snapshot in 'later's timeline.
      392 + * For example, they could both be snapshots of the same filesystem, and
      393 + * 'earlier' is before 'later'.  Or 'earlier' could be the origin of
      394 + * 'later's filesystem.  Or 'earlier' could be an older snapshot in the origin's
      395 + * filesystem.  Or 'earlier' could be the origin's origin.
      396 + */
      397 +static boolean_t
      398 +is_before(dsl_dataset_t *later, dsl_dataset_t *earlier)
      399 +{
      400 +        dsl_pool_t *dp = later->ds_dir->dd_pool;
      401 +        int error;
      402 +        boolean_t ret;
      403 +        dsl_dataset_t *origin;
      404 +
      405 +        if (earlier->ds_phys->ds_creation_txg >=
      406 +            later->ds_phys->ds_creation_txg)
      407 +                return (B_FALSE);
      408 +
      409 +        if (later->ds_dir == earlier->ds_dir)
      410 +                return (B_TRUE);
      411 +        if (!dsl_dir_is_clone(later->ds_dir))
      412 +                return (B_FALSE);
      413 +
      414 +        rw_enter(&dp->dp_config_rwlock, RW_READER);
      415 +        if (later->ds_dir->dd_phys->dd_origin_obj == earlier->ds_object) {
      416 +                rw_exit(&dp->dp_config_rwlock);
      417 +                return (B_TRUE);
      418 +        }
      419 +        error = dsl_dataset_hold_obj(dp,
      420 +            later->ds_dir->dd_phys->dd_origin_obj, FTAG, &origin);
      421 +        rw_exit(&dp->dp_config_rwlock);
      422 +        if (error != 0)
      423 +                return (B_FALSE);
      424 +        ret = is_before(origin, earlier);
      425 +        dsl_dataset_rele(origin, FTAG);
      426 +        return (ret);
      427 +}
      428 +
 390  429  int
 391      -dmu_send(objset_t *tosnap, objset_t *fromsnap, boolean_t fromorigin,
 392      -    int outfd, vnode_t *vp, offset_t *off)
      430 +dmu_send(objset_t *tosnap, objset_t *fromsnap, int outfd, vnode_t *vp,
      431 +    offset_t *off)
 393  432  {
 394  433          dsl_dataset_t *ds = tosnap->os_dsl_dataset;
 395  434          dsl_dataset_t *fromds = fromsnap ? fromsnap->os_dsl_dataset : NULL;
 396  435          dmu_replay_record_t *drr;
 397  436          dmu_sendarg_t *dsp;
 398  437          int err;
 399  438          uint64_t fromtxg = 0;
 400  439  
 401  440          /* tosnap must be a snapshot */
 402  441          if (ds->ds_phys->ds_next_snap_obj == 0)
 403  442                  return (EINVAL);
 404  443  
 405      -        /* fromsnap must be an earlier snapshot from the same fs as tosnap */
 406      -        if (fromds && (ds->ds_dir != fromds->ds_dir ||
 407      -            fromds->ds_phys->ds_creation_txg >= ds->ds_phys->ds_creation_txg))
      444 +        /*
      445 +         * fromsnap must be an earlier snapshot from the same fs as tosnap,
      446 +         * or the origin's fs.
      447 +         */
      448 +        if (fromds != NULL && !is_before(ds, fromds))
 408  449                  return (EXDEV);
 409  450  
 410      -        if (fromorigin) {
 411      -                dsl_pool_t *dp = ds->ds_dir->dd_pool;
 412      -
 413      -                if (fromsnap)
 414      -                        return (EINVAL);
 415      -
 416      -                if (dsl_dir_is_clone(ds->ds_dir)) {
 417      -                        rw_enter(&dp->dp_config_rwlock, RW_READER);
 418      -                        err = dsl_dataset_hold_obj(dp,
 419      -                            ds->ds_dir->dd_phys->dd_origin_obj, FTAG, &fromds);
 420      -                        rw_exit(&dp->dp_config_rwlock);
 421      -                        if (err)
 422      -                                return (err);
 423      -                } else {
 424      -                        fromorigin = B_FALSE;
 425      -                }
 426      -        }
 427      -
 428      -
 429  451          drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP);
 430  452          drr->drr_type = DRR_BEGIN;
 431  453          drr->drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC;
 432  454          DMU_SET_STREAM_HDRTYPE(drr->drr_u.drr_begin.drr_versioninfo,
 433  455              DMU_SUBSTREAM);
 434  456  
 435  457  #ifdef _KERNEL
 436  458          if (dmu_objset_type(tosnap) == DMU_OST_ZFS) {
 437  459                  uint64_t version;
 438  460                  if (zfs_get_zplprop(tosnap, ZFS_PROP_VERSION, &version) != 0) {
↓ open down ↓ 4 lines elided ↑ open up ↑
 443  465                          DMU_SET_FEATUREFLAGS(
 444  466                              drr->drr_u.drr_begin.drr_versioninfo,
 445  467                              DMU_BACKUP_FEATURE_SA_SPILL);
 446  468                  }
 447  469          }
 448  470  #endif
 449  471  
 450  472          drr->drr_u.drr_begin.drr_creation_time =
 451  473              ds->ds_phys->ds_creation_time;
 452  474          drr->drr_u.drr_begin.drr_type = tosnap->os_phys->os_type;
 453      -        if (fromorigin)
      475 +        if (fromds != NULL && ds->ds_dir != fromds->ds_dir)
 454  476                  drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CLONE;
 455  477          drr->drr_u.drr_begin.drr_toguid = ds->ds_phys->ds_guid;
 456  478          if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET)
 457  479                  drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CI_DATA;
 458  480  
 459  481          if (fromds)
 460  482                  drr->drr_u.drr_begin.drr_fromguid = fromds->ds_phys->ds_guid;
 461  483          dsl_dataset_name(ds, drr->drr_u.drr_begin.drr_toname);
 462  484  
 463  485          if (fromds)
 464  486                  fromtxg = fromds->ds_phys->ds_creation_txg;
 465      -        if (fromorigin)
 466      -                dsl_dataset_rele(fromds, FTAG);
 467  487  
 468  488          dsp = kmem_zalloc(sizeof (dmu_sendarg_t), KM_SLEEP);
 469  489  
 470  490          dsp->dsa_drr = drr;
 471  491          dsp->dsa_vp = vp;
 472  492          dsp->dsa_outfd = outfd;
 473  493          dsp->dsa_proc = curproc;
 474  494          dsp->dsa_os = tosnap;
 475  495          dsp->dsa_off = off;
 476  496          dsp->dsa_toguid = ds->ds_phys->ds_guid;
↓ open down ↓ 37 lines elided ↑ open up ↑
 514  534          list_remove(&ds->ds_sendstreams, dsp);
 515  535          mutex_exit(&ds->ds_sendstream_lock);
 516  536  
 517  537          kmem_free(drr, sizeof (dmu_replay_record_t));
 518  538          kmem_free(dsp, sizeof (dmu_sendarg_t));
 519  539  
 520  540          return (err);
 521  541  }
 522  542  
 523  543  int
 524      -dmu_send_estimate(objset_t *tosnap, objset_t *fromsnap, boolean_t fromorigin,
 525      -    uint64_t *sizep)
      544 +dmu_send_estimate(objset_t *tosnap, objset_t *fromsnap, uint64_t *sizep)
 526  545  {
 527  546          dsl_dataset_t *ds = tosnap->os_dsl_dataset;
 528  547          dsl_dataset_t *fromds = fromsnap ? fromsnap->os_dsl_dataset : NULL;
 529  548          dsl_pool_t *dp = ds->ds_dir->dd_pool;
 530  549          int err;
 531  550          uint64_t size;
 532  551  
 533  552          /* tosnap must be a snapshot */
 534  553          if (ds->ds_phys->ds_next_snap_obj == 0)
 535  554                  return (EINVAL);
 536  555  
 537      -        /* fromsnap must be an earlier snapshot from the same fs as tosnap */
 538      -        if (fromds && (ds->ds_dir != fromds->ds_dir ||
 539      -            fromds->ds_phys->ds_creation_txg >= ds->ds_phys->ds_creation_txg))
      556 +        /*
      557 +         * fromsnap must be an earlier snapshot from the same fs as tosnap,
      558 +         * or the origin's fs.
      559 +         */
      560 +        if (fromds != NULL && !is_before(ds, fromds))
 540  561                  return (EXDEV);
 541  562  
 542      -        if (fromorigin) {
 543      -                if (fromsnap)
 544      -                        return (EINVAL);
 545      -
 546      -                if (dsl_dir_is_clone(ds->ds_dir)) {
 547      -                        rw_enter(&dp->dp_config_rwlock, RW_READER);
 548      -                        err = dsl_dataset_hold_obj(dp,
 549      -                            ds->ds_dir->dd_phys->dd_origin_obj, FTAG, &fromds);
 550      -                        rw_exit(&dp->dp_config_rwlock);
 551      -                        if (err)
 552      -                                return (err);
 553      -                } else {
 554      -                        fromorigin = B_FALSE;
 555      -                }
 556      -        }
 557      -
 558  563          /* Get uncompressed size estimate of changed data. */
 559  564          if (fromds == NULL) {
 560  565                  size = ds->ds_phys->ds_uncompressed_bytes;
 561  566          } else {
 562  567                  uint64_t used, comp;
 563  568                  err = dsl_dataset_space_written(fromds, ds,
 564  569                      &used, &comp, &size);
 565      -                if (fromorigin)
 566      -                        dsl_dataset_rele(fromds, FTAG);
 567  570                  if (err)
 568  571                          return (err);
 569  572          }
 570  573  
 571  574          /*
 572  575           * Assume that space (both on-disk and in-stream) is dominated by
 573  576           * data.  We will adjust for indirect blocks and the copies property,
 574  577           * but ignore per-object space used (eg, dnodes and DRR_OBJECT records).
 575  578           */
 576  579  
↓ open down ↓ 78 lines elided ↑ open up ↑
 655  658          dsobj = dsl_dataset_create_sync(dd, strrchr(rbsa->tofs, '/') + 1,
 656  659              rbsa->origin, flags, rbsa->cr, tx);
 657  660          VERIFY(0 == dsl_dataset_own_obj(dd->dd_pool, dsobj,
 658  661              B_TRUE, dmu_recv_tag, &rbsa->ds));
 659  662  
 660  663          if (rbsa->origin == NULL) {
 661  664                  (void) dmu_objset_create_impl(dd->dd_pool->dp_spa,
 662  665                      rbsa->ds, &rbsa->ds->ds_phys->ds_bp, rbsa->type, tx);
 663  666          }
 664  667  
 665      -        spa_history_log_internal(LOG_DS_REPLAY_FULL_SYNC,
 666      -            dd->dd_pool->dp_spa, tx, "dataset = %lld", dsobj);
      668 +        spa_history_log_internal_ds(rbsa->ds, "receive new", tx, "");
 667  669  }
 668  670  
 669  671  /* ARGSUSED */
 670  672  static int
 671  673  recv_existing_check(void *arg1, void *arg2, dmu_tx_t *tx)
 672  674  {
 673  675          dsl_dataset_t *ds = arg1;
 674  676          struct recvbeginsyncarg *rbsa = arg2;
 675  677          int err;
 676  678          uint64_t val;
↓ open down ↓ 80 lines elided ↑ open up ↑
 757  759           * If we actually created a non-clone, we need to create the
 758  760           * objset in our new dataset.
 759  761           */
 760  762          if (BP_IS_HOLE(dsl_dataset_get_blkptr(cds))) {
 761  763                  (void) dmu_objset_create_impl(dp->dp_spa,
 762  764                      cds, dsl_dataset_get_blkptr(cds), rbsa->type, tx);
 763  765          }
 764  766  
 765  767          rbsa->ds = cds;
 766  768  
 767      -        spa_history_log_internal(LOG_DS_REPLAY_INC_SYNC,
 768      -            dp->dp_spa, tx, "dataset = %lld", dsobj);
      769 +        spa_history_log_internal_ds(cds, "receive over existing", tx, "");
 769  770  }
 770  771  
 771  772  static boolean_t
 772  773  dmu_recv_verify_features(dsl_dataset_t *ds, struct drr_begin *drrb)
 773  774  {
 774  775          int featureflags;
 775  776  
 776  777          featureflags = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo);
 777  778  
 778  779          /* Verify pool version supports SA if SA_SPILL feature set */
↓ open down ↓ 787 lines elided ↑ open up ↑
1566 1567          dsl_dataset_snapshot_sync(ds, resa->tosnap, tx);
1567 1568  
1568 1569          /* set snapshot's creation time and guid */
1569 1570          dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx);
1570 1571          ds->ds_prev->ds_phys->ds_creation_time = resa->creation_time;
1571 1572          ds->ds_prev->ds_phys->ds_guid = resa->toguid;
1572 1573          ds->ds_prev->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT;
1573 1574  
1574 1575          dmu_buf_will_dirty(ds->ds_dbuf, tx);
1575 1576          ds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT;
     1577 +        spa_history_log_internal_ds(ds, "finished receiving", tx, "");
1576 1578  }
1577 1579  
1578 1580  static int
1579 1581  add_ds_to_guidmap(avl_tree_t *guid_map, dsl_dataset_t *ds)
1580 1582  {
1581 1583          dsl_pool_t *dp = ds->ds_dir->dd_pool;
1582 1584          uint64_t snapobj = ds->ds_phys->ds_prev_snap_obj;
1583 1585          dsl_dataset_t *snapds;
1584 1586          guid_map_entry_t *gmep;
1585 1587          int err;
↓ open down ↓ 104 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX