Print this page
6536 zfs send: want a way to disable sending of free records
Reviewed by: Alexander Stetsenko <astetsenko@racktopsystems.com>
Reviewed by: Kim Shrier <kshrier@racktopsystems.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 ↓ 16 lines elided ↑ open up ↑
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  23   23   * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
  24   24   * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  25   25   * Copyright (c) 2014, Joyent, Inc. All rights reserved.
  26   26   * Copyright 2014 HybridCluster. All rights reserved.
       27 + * Copyright 2015 RackTop Systems.
  27   28   */
  28   29  
  29   30  #include <sys/dmu.h>
  30   31  #include <sys/dmu_impl.h>
  31   32  #include <sys/dmu_tx.h>
  32   33  #include <sys/dbuf.h>
  33   34  #include <sys/dnode.h>
  34   35  #include <sys/zfs_context.h>
  35   36  #include <sys/dmu_objset.h>
  36   37  #include <sys/dmu_traverse.h>
↓ open down ↓ 108 lines elided ↑ open up ↑
 145  146   * able to receive a full send as a clone, which requires a list of all the free
 146  147   * and freeobject records that were generated on the source.
 147  148   */
 148  149  static int
 149  150  dump_free(dmu_sendarg_t *dsp, uint64_t object, uint64_t offset,
 150  151      uint64_t length)
 151  152  {
 152  153          struct drr_free *drrf = &(dsp->dsa_drr->drr_u.drr_free);
 153  154  
 154  155          /*
      156 +         * Skip free records if asked not to send them.  The resulting
      157 +         * stream cannot be received as a clone.
      158 +         */
      159 +        if (dsp->dsa_skip_free)
      160 +                return (0);
      161 +
      162 +        /*
 155  163           * When we receive a free record, dbuf_free_range() assumes
 156  164           * that the receiving system doesn't have any dbufs in the range
 157  165           * being freed.  This is always true because there is a one-record
 158  166           * constraint: we only send one WRITE record for any given
 159  167           * object,offset.  We know that the one-record constraint is
 160  168           * true because we always send data in increasing order by
 161  169           * object,offset.
 162  170           *
 163  171           * If the increasing-order constraint ever changes, we should find
 164  172           * another way to assert that the one-record constraint is still
↓ open down ↓ 174 lines elided ↑ open up ↑
 339  347          if (dump_record(dsp, data, blksz) != 0)
 340  348                  return (SET_ERROR(EINTR));
 341  349          return (0);
 342  350  }
 343  351  
 344  352  static int
 345  353  dump_freeobjects(dmu_sendarg_t *dsp, uint64_t firstobj, uint64_t numobjs)
 346  354  {
 347  355          struct drr_freeobjects *drrfo = &(dsp->dsa_drr->drr_u.drr_freeobjects);
 348  356  
      357 +        /* See comment in dump_free(). */
      358 +        if (dsp->dsa_skip_free)
      359 +                return (0);
      360 +
 349  361          /*
 350  362           * If there is a pending op, but it's not PENDING_FREEOBJECTS,
 351  363           * push it out, since free block aggregation can only be done for
 352  364           * blocks of the same type (i.e., DRR_FREE records can only be
 353  365           * aggregated with other DRR_FREE records.  DRR_FREEOBJECTS records
 354  366           * can only be aggregated with other DRR_FREEOBJECTS records.
 355  367           */
 356  368          if (dsp->dsa_pending_op != PENDING_NONE &&
 357  369              dsp->dsa_pending_op != PENDING_FREEOBJECTS) {
 358  370                  if (dump_record(dsp, NULL, 0) != 0)
↓ open down ↓ 317 lines elided ↑ open up ↑
 676  688  }
 677  689  
 678  690  /*
 679  691   * Actually do the bulk of the work in a zfs send.
 680  692   *
 681  693   * Note: Releases dp using the specified tag.
 682  694   */
 683  695  static int
 684  696  dmu_send_impl(void *tag, dsl_pool_t *dp, dsl_dataset_t *to_ds,
 685  697      zfs_bookmark_phys_t *ancestor_zb,
 686      -    boolean_t is_clone, boolean_t embedok, boolean_t large_block_ok, int outfd,
 687      -    uint64_t resumeobj, uint64_t resumeoff,
      698 +    boolean_t is_clone, boolean_t embedok, boolean_t large_block_ok,
      699 +    boolean_t skip_free, int outfd, uint64_t resumeobj, uint64_t resumeoff,
 688  700      vnode_t *vp, offset_t *off)
 689  701  {
 690  702          objset_t *os;
 691  703          dmu_replay_record_t *drr;
 692  704          dmu_sendarg_t *dsp;
 693  705          int err;
 694  706          uint64_t fromtxg = 0;
 695  707          uint64_t featureflags = 0;
 696  708          struct send_thread_arg to_arg = { 0 };
 697  709  
↓ open down ↓ 40 lines elided ↑ open up ↑
 738  750              featureflags);
 739  751  
 740  752          drr->drr_u.drr_begin.drr_creation_time =
 741  753              dsl_dataset_phys(to_ds)->ds_creation_time;
 742  754          drr->drr_u.drr_begin.drr_type = dmu_objset_type(os);
 743  755          if (is_clone)
 744  756                  drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CLONE;
 745  757          drr->drr_u.drr_begin.drr_toguid = dsl_dataset_phys(to_ds)->ds_guid;
 746  758          if (dsl_dataset_phys(to_ds)->ds_flags & DS_FLAG_CI_DATASET)
 747  759                  drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CI_DATA;
 748      -        drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_FREERECORDS;
      760 +        if (!skip_free)
      761 +                drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_FREERECORDS;
 749  762  
 750  763          if (ancestor_zb != NULL) {
 751  764                  drr->drr_u.drr_begin.drr_fromguid =
 752  765                      ancestor_zb->zbm_guid;
 753  766                  fromtxg = ancestor_zb->zbm_creation_txg;
 754  767          }
 755  768          dsl_dataset_name(to_ds, drr->drr_u.drr_begin.drr_toname);
 756  769          if (!to_ds->ds_is_snapshot) {
 757  770                  (void) strlcat(drr->drr_u.drr_begin.drr_toname, "@--head--",
 758  771                      sizeof (drr->drr_u.drr_begin.drr_toname));
↓ open down ↓ 5 lines elided ↑ open up ↑
 764  777          dsp->dsa_vp = vp;
 765  778          dsp->dsa_outfd = outfd;
 766  779          dsp->dsa_proc = curproc;
 767  780          dsp->dsa_os = os;
 768  781          dsp->dsa_off = off;
 769  782          dsp->dsa_toguid = dsl_dataset_phys(to_ds)->ds_guid;
 770  783          dsp->dsa_pending_op = PENDING_NONE;
 771  784          dsp->dsa_featureflags = featureflags;
 772  785          dsp->dsa_resume_object = resumeobj;
 773  786          dsp->dsa_resume_offset = resumeoff;
      787 +        dsp->dsa_skip_free = skip_free;
 774  788  
 775  789          mutex_enter(&to_ds->ds_sendstream_lock);
 776  790          list_insert_head(&to_ds->ds_sendstreams, dsp);
 777  791          mutex_exit(&to_ds->ds_sendstream_lock);
 778  792  
 779  793          dsl_dataset_long_hold(to_ds, FTAG);
 780  794          dsl_pool_rele(dp, tag);
 781  795  
 782  796          void *payload = NULL;
 783  797          size_t payload_len = 0;
↓ open down ↓ 82 lines elided ↑ open up ↑
 866  880          kmem_free(drr, sizeof (dmu_replay_record_t));
 867  881          kmem_free(dsp, sizeof (dmu_sendarg_t));
 868  882  
 869  883          dsl_dataset_long_rele(to_ds, FTAG);
 870  884  
 871  885          return (err);
 872  886  }
 873  887  
 874  888  int
 875  889  dmu_send_obj(const char *pool, uint64_t tosnap, uint64_t fromsnap,
 876      -    boolean_t embedok, boolean_t large_block_ok,
      890 +    boolean_t embedok, boolean_t large_block_ok, boolean_t skip_free,
 877  891      int outfd, vnode_t *vp, offset_t *off)
 878  892  {
 879  893          dsl_pool_t *dp;
 880  894          dsl_dataset_t *ds;
 881  895          dsl_dataset_t *fromds = NULL;
 882  896          int err;
 883  897  
 884  898          err = dsl_pool_hold(pool, FTAG, &dp);
 885  899          if (err != 0)
 886  900                  return (err);
↓ open down ↓ 16 lines elided ↑ open up ↑
 903  917                  }
 904  918                  if (!dsl_dataset_is_before(ds, fromds, 0))
 905  919                          err = SET_ERROR(EXDEV);
 906  920                  zb.zbm_creation_time =
 907  921                      dsl_dataset_phys(fromds)->ds_creation_time;
 908  922                  zb.zbm_creation_txg = dsl_dataset_phys(fromds)->ds_creation_txg;
 909  923                  zb.zbm_guid = dsl_dataset_phys(fromds)->ds_guid;
 910  924                  is_clone = (fromds->ds_dir != ds->ds_dir);
 911  925                  dsl_dataset_rele(fromds, FTAG);
 912  926                  err = dmu_send_impl(FTAG, dp, ds, &zb, is_clone,
 913      -                    embedok, large_block_ok, outfd, 0, 0, vp, off);
      927 +                    embedok, large_block_ok, skip_free, outfd, 0, 0, vp, off);
 914  928          } else {
 915  929                  err = dmu_send_impl(FTAG, dp, ds, NULL, B_FALSE,
 916      -                    embedok, large_block_ok, outfd, 0, 0, vp, off);
      930 +                    embedok, large_block_ok, skip_free, outfd, 0, 0, vp, off);
 917  931          }
 918  932          dsl_dataset_rele(ds, FTAG);
 919  933          return (err);
 920  934  }
 921  935  
 922  936  int
 923  937  dmu_send(const char *tosnap, const char *fromsnap, boolean_t embedok,
 924      -    boolean_t large_block_ok, int outfd, uint64_t resumeobj, uint64_t resumeoff,
 925      -    vnode_t *vp, offset_t *off)
      938 +    boolean_t large_block_ok, boolean_t skip_free, int outfd,
      939 +    uint64_t resumeobj, uint64_t resumeoff, vnode_t *vp, offset_t *off)
 926  940  {
 927  941          dsl_pool_t *dp;
 928  942          dsl_dataset_t *ds;
 929  943          int err;
 930  944          boolean_t owned = B_FALSE;
 931  945  
 932  946          if (fromsnap != NULL && strpbrk(fromsnap, "@#") == NULL)
 933  947                  return (SET_ERROR(EINVAL));
 934  948  
 935  949          err = dsl_pool_hold(tosnap, FTAG, &dp);
↓ open down ↓ 46 lines elided ↑ open up ↑
 982  996                          }
 983  997                  } else {
 984  998                          err = dsl_bookmark_lookup(dp, fromsnap, ds, &zb);
 985  999                  }
 986 1000                  if (err != 0) {
 987 1001                          dsl_dataset_rele(ds, FTAG);
 988 1002                          dsl_pool_rele(dp, FTAG);
 989 1003                          return (err);
 990 1004                  }
 991 1005                  err = dmu_send_impl(FTAG, dp, ds, &zb, is_clone,
 992      -                    embedok, large_block_ok,
     1006 +                    embedok, large_block_ok, skip_free,
 993 1007                      outfd, resumeobj, resumeoff, vp, off);
 994 1008          } else {
 995 1009                  err = dmu_send_impl(FTAG, dp, ds, NULL, B_FALSE,
 996      -                    embedok, large_block_ok,
     1010 +                    embedok, large_block_ok, skip_free,
 997 1011                      outfd, resumeobj, resumeoff, vp, off);
 998 1012          }
 999 1013          if (owned)
1000 1014                  dsl_dataset_disown(ds, FTAG);
1001 1015          else
1002 1016                  dsl_dataset_rele(ds, FTAG);
1003 1017          return (err);
1004 1018  }
1005 1019  
1006 1020  static int
↓ open down ↓ 2152 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX