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_objset.c
          +++ new/usr/src/uts/common/fs/zfs/dmu_objset.c
↓ open down ↓ 12 lines elided ↑ open up ↑
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  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 + * Copyright (c) 2012 by Delphix. All rights reserved.
  23   24   */
  24   25  
  25   26  /* Portions Copyright 2010 Robert Milkowski */
  26   27  
  27   28  #include <sys/cred.h>
  28   29  #include <sys/zfs_context.h>
  29   30  #include <sys/dmu_objset.h>
  30   31  #include <sys/dsl_dir.h>
  31   32  #include <sys/dsl_dataset.h>
  32   33  #include <sys/dsl_prop.h>
↓ open down ↓ 659 lines elided ↑ open up ↑
 692  693          return (0);
 693  694  }
 694  695  
 695  696  static void
 696  697  dmu_objset_create_sync(void *arg1, void *arg2, dmu_tx_t *tx)
 697  698  {
 698  699          dsl_dir_t *dd = arg1;
 699  700          spa_t *spa = dd->dd_pool->dp_spa;
 700  701          struct oscarg *oa = arg2;
 701  702          uint64_t obj;
      703 +        dsl_dataset_t *ds;
      704 +        blkptr_t *bp;
 702  705  
 703  706          ASSERT(dmu_tx_is_syncing(tx));
 704  707  
 705  708          obj = dsl_dataset_create_sync(dd, oa->lastname,
 706  709              oa->clone_origin, oa->flags, oa->cr, tx);
 707  710  
 708      -        if (oa->clone_origin == NULL) {
 709      -                dsl_pool_t *dp = dd->dd_pool;
 710      -                dsl_dataset_t *ds;
 711      -                blkptr_t *bp;
 712      -                objset_t *os;
 713      -
 714      -                VERIFY3U(0, ==, dsl_dataset_hold_obj(dp, obj, FTAG, &ds));
 715      -                bp = dsl_dataset_get_blkptr(ds);
 716      -                ASSERT(BP_IS_HOLE(bp));
 717      -
 718      -                os = dmu_objset_create_impl(spa, ds, bp, oa->type, tx);
      711 +        VERIFY3U(0, ==, dsl_dataset_hold_obj(dd->dd_pool, obj, FTAG, &ds));
      712 +        bp = dsl_dataset_get_blkptr(ds);
      713 +        if (BP_IS_HOLE(bp)) {
      714 +                objset_t *os =
      715 +                    dmu_objset_create_impl(spa, ds, bp, oa->type, tx);
 719  716  
 720  717                  if (oa->userfunc)
 721  718                          oa->userfunc(os, oa->userarg, oa->cr, tx);
 722      -                dsl_dataset_rele(ds, FTAG);
 723  719          }
 724  720  
 725      -        spa_history_log_internal(LOG_DS_CREATE, spa, tx, "dataset = %llu", obj);
      721 +        if (oa->clone_origin == NULL) {
      722 +                spa_history_log_internal_ds(ds, "create", tx, "");
      723 +        } else {
      724 +                char namebuf[MAXNAMELEN];
      725 +                dsl_dataset_name(oa->clone_origin, namebuf);
      726 +                spa_history_log_internal_ds(ds, "clone", tx,
      727 +                    "origin=%s (%llu)", namebuf, oa->clone_origin->ds_object);
      728 +        }
      729 +        dsl_dataset_rele(ds, FTAG);
 726  730  }
 727  731  
 728  732  int
 729  733  dmu_objset_create(const char *name, dmu_objset_type_t type, uint64_t flags,
 730  734      void (*func)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx), void *arg)
 731  735  {
 732  736          dsl_dir_t *pdd;
 733  737          const char *tail;
 734  738          int err = 0;
 735  739          struct oscarg oa = { 0 };
↓ open down ↓ 56 lines elided ↑ open up ↑
 792  796  
 793  797          error = dsl_dataset_own(name, B_TRUE, FTAG, &ds);
 794  798          if (error == 0) {
 795  799                  error = dsl_dataset_destroy(ds, FTAG, defer);
 796  800                  /* dsl_dataset_destroy() closes the ds. */
 797  801          }
 798  802  
 799  803          return (error);
 800  804  }
 801  805  
 802      -struct snaparg {
 803      -        dsl_sync_task_group_t *dstg;
 804      -        char *snapname;
 805      -        char *htag;
 806      -        char failed[MAXPATHLEN];
 807      -        boolean_t recursive;
 808      -        boolean_t needsuspend;
 809      -        boolean_t temporary;
 810      -        nvlist_t *props;
 811      -        struct dsl_ds_holdarg *ha;      /* only needed in the temporary case */
 812      -        dsl_dataset_t *newds;
 813      -};
      806 +typedef struct snapallarg {
      807 +        dsl_sync_task_group_t *saa_dstg;
      808 +        boolean_t saa_needsuspend;
      809 +        nvlist_t *saa_props;
      810 +
      811 +        /* the following are used only if 'temporary' is set: */
      812 +        boolean_t saa_temporary;
      813 +        const char *saa_htag;
      814 +        struct dsl_ds_holdarg *saa_ha;
      815 +        dsl_dataset_t *saa_newds;
      816 +} snapallarg_t;
      817 +
      818 +typedef struct snaponearg {
      819 +        const char *soa_longname; /* long snap name */
      820 +        const char *soa_snapname; /* short snap name */
      821 +        snapallarg_t *soa_saa;
      822 +} snaponearg_t;
 814  823  
 815  824  static int
 816  825  snapshot_check(void *arg1, void *arg2, dmu_tx_t *tx)
 817  826  {
 818  827          objset_t *os = arg1;
 819      -        struct snaparg *sn = arg2;
      828 +        snaponearg_t *soa = arg2;
      829 +        snapallarg_t *saa = soa->soa_saa;
 820  830          int error;
 821  831  
 822  832          /* The props have already been checked by zfs_check_userprops(). */
 823  833  
 824  834          error = dsl_dataset_snapshot_check(os->os_dsl_dataset,
 825      -            sn->snapname, tx);
      835 +            soa->soa_snapname, tx);
 826  836          if (error)
 827  837                  return (error);
 828  838  
 829      -        if (sn->temporary) {
      839 +        if (saa->saa_temporary) {
 830  840                  /*
 831  841                   * Ideally we would just call
 832  842                   * dsl_dataset_user_hold_check() and
 833  843                   * dsl_dataset_destroy_check() here.  However the
 834  844                   * dataset we want to hold and destroy is the snapshot
 835  845                   * that we just confirmed we can create, but it won't
 836  846                   * exist until after these checks are run.  Do any
 837  847                   * checks we can here and if more checks are added to
 838  848                   * those routines in the future, similar checks may be
 839  849                   * necessary here.
 840  850                   */
 841  851                  if (spa_version(os->os_spa) < SPA_VERSION_USERREFS)
 842  852                          return (ENOTSUP);
 843  853                  /*
 844  854                   * Not checking number of tags because the tag will be
 845  855                   * unique, as it will be the only tag.
 846  856                   */
 847      -                if (strlen(sn->htag) + MAX_TAG_PREFIX_LEN >= MAXNAMELEN)
      857 +                if (strlen(saa->saa_htag) + MAX_TAG_PREFIX_LEN >= MAXNAMELEN)
 848  858                          return (E2BIG);
 849  859  
 850      -                sn->ha = kmem_alloc(sizeof (struct dsl_ds_holdarg), KM_SLEEP);
 851      -                sn->ha->temphold = B_TRUE;
 852      -                sn->ha->htag = sn->htag;
      860 +                saa->saa_ha = kmem_alloc(sizeof (struct dsl_ds_holdarg),
      861 +                    KM_SLEEP);
      862 +                saa->saa_ha->temphold = B_TRUE;
      863 +                saa->saa_ha->htag = saa->saa_htag;
 853  864          }
 854  865          return (error);
 855  866  }
 856  867  
 857  868  static void
 858  869  snapshot_sync(void *arg1, void *arg2, dmu_tx_t *tx)
 859  870  {
 860  871          objset_t *os = arg1;
 861  872          dsl_dataset_t *ds = os->os_dsl_dataset;
 862      -        struct snaparg *sn = arg2;
      873 +        snaponearg_t *soa = arg2;
      874 +        snapallarg_t *saa = soa->soa_saa;
 863  875  
 864      -        dsl_dataset_snapshot_sync(ds, sn->snapname, tx);
      876 +        dsl_dataset_snapshot_sync(ds, soa->soa_snapname, tx);
 865  877  
 866      -        if (sn->props) {
      878 +        if (saa->saa_props != NULL) {
 867  879                  dsl_props_arg_t pa;
 868      -                pa.pa_props = sn->props;
      880 +                pa.pa_props = saa->saa_props;
 869  881                  pa.pa_source = ZPROP_SRC_LOCAL;
 870  882                  dsl_props_set_sync(ds->ds_prev, &pa, tx);
 871  883          }
 872  884  
 873      -        if (sn->temporary) {
      885 +        if (saa->saa_temporary) {
 874  886                  struct dsl_ds_destroyarg da;
 875  887  
 876      -                dsl_dataset_user_hold_sync(ds->ds_prev, sn->ha, tx);
 877      -                kmem_free(sn->ha, sizeof (struct dsl_ds_holdarg));
 878      -                sn->ha = NULL;
 879      -                sn->newds = ds->ds_prev;
      888 +                dsl_dataset_user_hold_sync(ds->ds_prev, saa->saa_ha, tx);
      889 +                kmem_free(saa->saa_ha, sizeof (struct dsl_ds_holdarg));
      890 +                saa->saa_ha = NULL;
      891 +                saa->saa_newds = ds->ds_prev;
 880  892  
 881  893                  da.ds = ds->ds_prev;
 882  894                  da.defer = B_TRUE;
 883  895                  dsl_dataset_destroy_sync(&da, FTAG, tx);
 884  896          }
 885  897  }
 886  898  
 887  899  static int
 888      -dmu_objset_snapshot_one(const char *name, void *arg)
      900 +snapshot_one_impl(const char *snapname, void *arg)
 889  901  {
 890      -        struct snaparg *sn = arg;
      902 +        char fsname[MAXPATHLEN];
      903 +        snapallarg_t *saa = arg;
      904 +        snaponearg_t *soa;
 891  905          objset_t *os;
 892  906          int err;
 893      -        char *cp;
 894  907  
 895      -        /*
 896      -         * If the objset starts with a '%', then ignore it unless it was
 897      -         * explicitly named (ie, not recursive).  These hidden datasets
 898      -         * are always inconsistent, and by not opening them here, we can
 899      -         * avoid a race with dsl_dir_destroy_check().
 900      -         */
 901      -        cp = strrchr(name, '/');
 902      -        if (cp && cp[1] == '%' && sn->recursive)
 903      -                return (0);
 904      -
 905      -        (void) strcpy(sn->failed, name);
 906      -
 907      -        /*
 908      -         * Check permissions if we are doing a recursive snapshot.  The
 909      -         * permission checks for the starting dataset have already been
 910      -         * performed in zfs_secpolicy_snapshot()
 911      -         */
 912      -        if (sn->recursive && (err = zfs_secpolicy_snapshot_perms(name, CRED())))
 913      -                return (err);
      908 +        (void) strlcpy(fsname, snapname, sizeof (fsname));
      909 +        strchr(fsname, '@')[0] = '\0';
 914  910  
 915      -        err = dmu_objset_hold(name, sn, &os);
      911 +        err = dmu_objset_hold(fsname, saa, &os);
 916  912          if (err != 0)
 917  913                  return (err);
 918  914  
 919  915          /*
 920  916           * If the objset is in an inconsistent state (eg, in the process
 921      -         * of being destroyed), don't snapshot it.  As with %hidden
 922      -         * datasets, we return EBUSY if this name was explicitly
 923      -         * requested (ie, not recursive), and otherwise ignore it.
      917 +         * of being destroyed), don't snapshot it.
 924  918           */
 925  919          if (os->os_dsl_dataset->ds_phys->ds_flags & DS_FLAG_INCONSISTENT) {
 926      -                dmu_objset_rele(os, sn);
 927      -                return (sn->recursive ? 0 : EBUSY);
      920 +                dmu_objset_rele(os, saa);
      921 +                return (EBUSY);
 928  922          }
 929  923  
 930      -        if (sn->needsuspend) {
      924 +        if (saa->saa_needsuspend) {
 931  925                  err = zil_suspend(dmu_objset_zil(os));
 932  926                  if (err) {
 933      -                        dmu_objset_rele(os, sn);
      927 +                        dmu_objset_rele(os, saa);
 934  928                          return (err);
 935  929                  }
 936  930          }
 937      -        dsl_sync_task_create(sn->dstg, snapshot_check, snapshot_sync,
 938      -            os, sn, 3);
      931 +
      932 +        soa = kmem_zalloc(sizeof (*soa), KM_SLEEP);
      933 +        soa->soa_saa = saa;
      934 +        soa->soa_longname = snapname;
      935 +        soa->soa_snapname = strchr(snapname, '@') + 1;
      936 +
      937 +        dsl_sync_task_create(saa->saa_dstg, snapshot_check, snapshot_sync,
      938 +            os, soa, 3);
 939  939  
 940  940          return (0);
 941  941  }
 942  942  
      943 +/*
      944 + * The snapshots must all be in the same pool.
      945 + */
 943  946  int
 944      -dmu_objset_snapshot(char *fsname, char *snapname, char *tag,
 945      -    nvlist_t *props, boolean_t recursive, boolean_t temporary, int cleanup_fd)
      947 +dmu_objset_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t *errors)
 946  948  {
 947  949          dsl_sync_task_t *dst;
 948      -        struct snaparg sn;
      950 +        snapallarg_t saa = { 0 };
 949  951          spa_t *spa;
 950      -        minor_t minor;
      952 +        int rv = 0;
 951  953          int err;
      954 +        nvpair_t *pair;
 952  955  
 953      -        (void) strcpy(sn.failed, fsname);
      956 +        pair = nvlist_next_nvpair(snaps, NULL);
      957 +        if (pair == NULL)
      958 +                return (0);
 954  959  
 955      -        err = spa_open(fsname, &spa, FTAG);
      960 +        err = spa_open(nvpair_name(pair), &spa, FTAG);
 956  961          if (err)
 957  962                  return (err);
 958      -
 959      -        if (temporary) {
 960      -                if (cleanup_fd < 0) {
 961      -                        spa_close(spa, FTAG);
 962      -                        return (EINVAL);
      963 +        saa.saa_dstg = dsl_sync_task_group_create(spa_get_dsl(spa));
      964 +        saa.saa_props = props;
      965 +        saa.saa_needsuspend = (spa_version(spa) < SPA_VERSION_FAST_SNAP);
      966 +
      967 +        for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
      968 +            pair = nvlist_next_nvpair(snaps, pair)) {
      969 +                err = snapshot_one_impl(nvpair_name(pair), &saa);
      970 +                if (err != 0) {
      971 +                        if (errors != NULL) {
      972 +                                fnvlist_add_int32(errors,
      973 +                                    nvpair_name(pair), err);
      974 +                        }
      975 +                        rv = err;
 963  976                  }
 964      -                if ((err = zfs_onexit_fd_hold(cleanup_fd, &minor)) != 0) {
 965      -                        spa_close(spa, FTAG);
 966      -                        return (err);
      977 +        }
      978 +
      979 +        /*
      980 +         * If any call to snapshot_one_impl() failed, don't execute the
      981 +         * sync task.  The error handling code below will clean up the
      982 +         * snaponearg_t from any successful calls to
      983 +         * snapshot_one_impl().
      984 +         */
      985 +        if (rv == 0)
      986 +                err = dsl_sync_task_group_wait(saa.saa_dstg);
      987 +        if (err != 0)
      988 +                rv = err;
      989 +
      990 +        for (dst = list_head(&saa.saa_dstg->dstg_tasks); dst;
      991 +            dst = list_next(&saa.saa_dstg->dstg_tasks, dst)) {
      992 +                objset_t *os = dst->dst_arg1;
      993 +                snaponearg_t *soa = dst->dst_arg2;
      994 +                if (dst->dst_err != 0) {
      995 +                        if (errors != NULL) {
      996 +                                fnvlist_add_int32(errors,
      997 +                                    soa->soa_longname, dst->dst_err);
      998 +                        }
      999 +                        rv = dst->dst_err;
 967 1000                  }
     1001 +
     1002 +                if (saa.saa_needsuspend)
     1003 +                        zil_resume(dmu_objset_zil(os));
     1004 +                dmu_objset_rele(os, &saa);
     1005 +                kmem_free(soa, sizeof (*soa));
 968 1006          }
 969 1007  
 970      -        sn.dstg = dsl_sync_task_group_create(spa_get_dsl(spa));
 971      -        sn.snapname = snapname;
 972      -        sn.htag = tag;
 973      -        sn.props = props;
 974      -        sn.recursive = recursive;
 975      -        sn.needsuspend = (spa_version(spa) < SPA_VERSION_FAST_SNAP);
 976      -        sn.temporary = temporary;
 977      -        sn.ha = NULL;
 978      -        sn.newds = NULL;
 979      -
 980      -        if (recursive) {
 981      -                err = dmu_objset_find(fsname,
 982      -                    dmu_objset_snapshot_one, &sn, DS_FIND_CHILDREN);
 983      -        } else {
 984      -                err = dmu_objset_snapshot_one(fsname, &sn);
     1008 +        dsl_sync_task_group_destroy(saa.saa_dstg);
     1009 +        spa_close(spa, FTAG);
     1010 +        return (rv);
     1011 +}
     1012 +
     1013 +int
     1014 +dmu_objset_snapshot_one(const char *fsname, const char *snapname)
     1015 +{
     1016 +        int err;
     1017 +        char *longsnap = kmem_asprintf("%s@%s", fsname, snapname);
     1018 +        nvlist_t *snaps = fnvlist_alloc();
     1019 +
     1020 +        fnvlist_add_boolean(snaps, longsnap);
     1021 +        err = dmu_objset_snapshot(snaps, NULL, NULL);
     1022 +        fnvlist_free(snaps);
     1023 +        strfree(longsnap);
     1024 +        return (err);
     1025 +}
     1026 +
     1027 +int
     1028 +dmu_objset_snapshot_tmp(const char *snapname, const char *tag, int cleanup_fd)
     1029 +{
     1030 +        dsl_sync_task_t *dst;
     1031 +        snapallarg_t saa = { 0 };
     1032 +        spa_t *spa;
     1033 +        minor_t minor;
     1034 +        int err;
     1035 +
     1036 +        err = spa_open(snapname, &spa, FTAG);
     1037 +        if (err)
     1038 +                return (err);
     1039 +        saa.saa_dstg = dsl_sync_task_group_create(spa_get_dsl(spa));
     1040 +        saa.saa_htag = tag;
     1041 +        saa.saa_needsuspend = (spa_version(spa) < SPA_VERSION_FAST_SNAP);
     1042 +        saa.saa_temporary = B_TRUE;
     1043 +
     1044 +        if (cleanup_fd < 0) {
     1045 +                spa_close(spa, FTAG);
     1046 +                return (EINVAL);
     1047 +        }
     1048 +        if ((err = zfs_onexit_fd_hold(cleanup_fd, &minor)) != 0) {
     1049 +                spa_close(spa, FTAG);
     1050 +                return (err);
 985 1051          }
 986 1052  
     1053 +        err = snapshot_one_impl(snapname, &saa);
     1054 +
 987 1055          if (err == 0)
 988      -                err = dsl_sync_task_group_wait(sn.dstg);
     1056 +                err = dsl_sync_task_group_wait(saa.saa_dstg);
 989 1057  
 990      -        for (dst = list_head(&sn.dstg->dstg_tasks); dst;
 991      -            dst = list_next(&sn.dstg->dstg_tasks, dst)) {
     1058 +        for (dst = list_head(&saa.saa_dstg->dstg_tasks); dst;
     1059 +            dst = list_next(&saa.saa_dstg->dstg_tasks, dst)) {
 992 1060                  objset_t *os = dst->dst_arg1;
 993      -                dsl_dataset_t *ds = os->os_dsl_dataset;
 994      -                if (dst->dst_err) {
 995      -                        dsl_dataset_name(ds, sn.failed);
 996      -                } else if (temporary) {
 997      -                        dsl_register_onexit_hold_cleanup(sn.newds, tag, minor);
 998      -                }
 999      -                if (sn.needsuspend)
     1061 +                dsl_register_onexit_hold_cleanup(saa.saa_newds, tag, minor);
     1062 +                if (saa.saa_needsuspend)
1000 1063                          zil_resume(dmu_objset_zil(os));
1001      -                dmu_objset_rele(os, &sn);
     1064 +                dmu_objset_rele(os, &saa);
1002 1065          }
1003 1066  
1004      -        if (err)
1005      -                (void) strcpy(fsname, sn.failed);
1006      -        if (temporary)
1007      -                zfs_onexit_fd_rele(cleanup_fd);
1008      -        dsl_sync_task_group_destroy(sn.dstg);
     1067 +        zfs_onexit_fd_rele(cleanup_fd);
     1068 +        dsl_sync_task_group_destroy(saa.saa_dstg);
1009 1069          spa_close(spa, FTAG);
1010 1070          return (err);
1011 1071  }
1012 1072  
     1073 +
1013 1074  static void
1014 1075  dmu_objset_sync_dnodes(list_t *list, list_t *newlist, dmu_tx_t *tx)
1015 1076  {
1016 1077          dnode_t *dn;
1017 1078  
1018 1079          while (dn = list_head(list)) {
1019 1080                  ASSERT(dn->dn_object != DMU_META_DNODE_OBJECT);
1020 1081                  ASSERT(dn->dn_dbuf->db_data_pending);
1021 1082                  /*
1022 1083                   * Initialize dn_zio outside dnode_sync() because the
↓ open down ↓ 767 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX