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/cmd/zfs/zfs_main.c
          +++ new/usr/src/cmd/zfs/zfs_main.c
↓ open down ↓ 48 lines elided ↑ open up ↑
  49   49  #include <sys/mkdev.h>
  50   50  #include <sys/mntent.h>
  51   51  #include <sys/mnttab.h>
  52   52  #include <sys/mount.h>
  53   53  #include <sys/stat.h>
  54   54  #include <sys/fs/zfs.h>
  55   55  #include <sys/types.h>
  56   56  #include <time.h>
  57   57  
  58   58  #include <libzfs.h>
       59 +#include <libzfs_core.h>
  59   60  #include <zfs_prop.h>
  60   61  #include <zfs_deleg.h>
  61   62  #include <libuutil.h>
  62   63  #include <aclutils.h>
  63   64  #include <directory.h>
  64   65  
  65   66  #include "zfs_iter.h"
  66   67  #include "zfs_util.h"
  67   68  #include "zfs_comutil.h"
  68   69  
  69   70  libzfs_handle_t *g_zfs;
  70   71  
  71   72  static FILE *mnttab_file;
  72   73  static char history_str[HIS_MAX_RECORD_LEN];
       74 +static boolean_t log_history = B_TRUE;
  73   75  
  74   76  static int zfs_do_clone(int argc, char **argv);
  75   77  static int zfs_do_create(int argc, char **argv);
  76   78  static int zfs_do_destroy(int argc, char **argv);
  77   79  static int zfs_do_get(int argc, char **argv);
  78   80  static int zfs_do_inherit(int argc, char **argv);
  79   81  static int zfs_do_list(int argc, char **argv);
  80   82  static int zfs_do_mount(int argc, char **argv);
  81   83  static int zfs_do_rename(int argc, char **argv);
  82   84  static int zfs_do_rollback(int argc, char **argv);
↓ open down ↓ 169 lines elided ↑ open up ↑
 252  254          case HELP_SEND:
 253  255                  return (gettext("\tsend [-DnPpRrv] [-[iI] snapshot] "
 254  256                      "<snapshot>\n"));
 255  257          case HELP_SET:
 256  258                  return (gettext("\tset <property=value> "
 257  259                      "<filesystem|volume|snapshot> ...\n"));
 258  260          case HELP_SHARE:
 259  261                  return (gettext("\tshare <-a | filesystem>\n"));
 260  262          case HELP_SNAPSHOT:
 261  263                  return (gettext("\tsnapshot [-r] [-o property=value] ... "
 262      -                    "<filesystem@snapname|volume@snapname>\n"));
      264 +                    "<filesystem@snapname|volume@snapname> ...\n"));
 263  265          case HELP_UNMOUNT:
 264  266                  return (gettext("\tunmount [-f] "
 265  267                      "<-a | filesystem|mountpoint>\n"));
 266  268          case HELP_UNSHARE:
 267  269                  return (gettext("\tunshare "
 268  270                      "<-a | filesystem|mountpoint>\n"));
 269  271          case HELP_ALLOW:
 270  272                  return (gettext("\tallow <filesystem|volume>\n"
 271  273                      "\tallow [-ldug] "
 272  274                      "<\"everyone\"|user|group>[,...] <perm|@setname>[,...]\n"
↓ open down ↓ 608 lines elided ↑ open up ↑
 881  883          boolean_t       cb_error;
 882  884          boolean_t       cb_doclones;
 883  885          zfs_handle_t    *cb_target;
 884  886          boolean_t       cb_defer_destroy;
 885  887          boolean_t       cb_verbose;
 886  888          boolean_t       cb_parsable;
 887  889          boolean_t       cb_dryrun;
 888  890          nvlist_t        *cb_nvl;
 889  891  
 890  892          /* first snap in contiguous run */
 891      -        zfs_handle_t    *cb_firstsnap;
      893 +        char            *cb_firstsnap;
 892  894          /* previous snap in contiguous run */
 893      -        zfs_handle_t    *cb_prevsnap;
      895 +        char            *cb_prevsnap;
 894  896          int64_t         cb_snapused;
 895  897          char            *cb_snapspec;
 896  898  } destroy_cbdata_t;
 897  899  
 898  900  /*
 899  901   * Check for any dependents based on the '-r' or '-R' flags.
 900  902   */
 901  903  static int
 902  904  destroy_check_dependent(zfs_handle_t *zhp, void *data)
 903  905  {
↓ open down ↓ 93 lines elided ↑ open up ↑
 997  999  
 998 1000  static int
 999 1001  destroy_print_cb(zfs_handle_t *zhp, void *arg)
1000 1002  {
1001 1003          destroy_cbdata_t *cb = arg;
1002 1004          const char *name = zfs_get_name(zhp);
1003 1005          int err = 0;
1004 1006  
1005 1007          if (nvlist_exists(cb->cb_nvl, name)) {
1006 1008                  if (cb->cb_firstsnap == NULL)
1007      -                        cb->cb_firstsnap = zfs_handle_dup(zhp);
     1009 +                        cb->cb_firstsnap = strdup(name);
1008 1010                  if (cb->cb_prevsnap != NULL)
1009      -                        zfs_close(cb->cb_prevsnap);
     1011 +                        free(cb->cb_prevsnap);
1010 1012                  /* this snap continues the current range */
1011      -                cb->cb_prevsnap = zfs_handle_dup(zhp);
     1013 +                cb->cb_prevsnap = strdup(name);
     1014 +                if (cb->cb_firstsnap == NULL || cb->cb_prevsnap == NULL)
     1015 +                        nomem();
1012 1016                  if (cb->cb_verbose) {
1013 1017                          if (cb->cb_parsable) {
1014 1018                                  (void) printf("destroy\t%s\n", name);
1015 1019                          } else if (cb->cb_dryrun) {
1016 1020                                  (void) printf(gettext("would destroy %s\n"),
1017 1021                                      name);
1018 1022                          } else {
1019 1023                                  (void) printf(gettext("will destroy %s\n"),
1020 1024                                      name);
1021 1025                          }
1022 1026                  }
1023 1027          } else if (cb->cb_firstsnap != NULL) {
1024 1028                  /* end of this range */
1025 1029                  uint64_t used = 0;
1026      -                err = zfs_get_snapused_int(cb->cb_firstsnap,
     1030 +                err = lzc_snaprange_space(cb->cb_firstsnap,
1027 1031                      cb->cb_prevsnap, &used);
1028 1032                  cb->cb_snapused += used;
1029      -                zfs_close(cb->cb_firstsnap);
     1033 +                free(cb->cb_firstsnap);
1030 1034                  cb->cb_firstsnap = NULL;
1031      -                zfs_close(cb->cb_prevsnap);
     1035 +                free(cb->cb_prevsnap);
1032 1036                  cb->cb_prevsnap = NULL;
1033 1037          }
1034 1038          zfs_close(zhp);
1035 1039          return (err);
1036 1040  }
1037 1041  
1038 1042  static int
1039 1043  destroy_print_snapshots(zfs_handle_t *fs_zhp, destroy_cbdata_t *cb)
1040 1044  {
1041 1045          int err = 0;
1042 1046          assert(cb->cb_firstsnap == NULL);
1043 1047          assert(cb->cb_prevsnap == NULL);
1044 1048          err = zfs_iter_snapshots_sorted(fs_zhp, destroy_print_cb, cb);
1045 1049          if (cb->cb_firstsnap != NULL) {
1046 1050                  uint64_t used = 0;
1047 1051                  if (err == 0) {
1048      -                        err = zfs_get_snapused_int(cb->cb_firstsnap,
     1052 +                        err = lzc_snaprange_space(cb->cb_firstsnap,
1049 1053                              cb->cb_prevsnap, &used);
1050 1054                  }
1051 1055                  cb->cb_snapused += used;
1052      -                zfs_close(cb->cb_firstsnap);
     1056 +                free(cb->cb_firstsnap);
1053 1057                  cb->cb_firstsnap = NULL;
1054      -                zfs_close(cb->cb_prevsnap);
     1058 +                free(cb->cb_prevsnap);
1055 1059                  cb->cb_prevsnap = NULL;
1056 1060          }
1057 1061          return (err);
1058 1062  }
1059 1063  
1060 1064  static int
1061 1065  snapshot_to_nvl_cb(zfs_handle_t *zhp, void *arg)
1062 1066  {
1063 1067          destroy_cbdata_t *cb = arg;
1064 1068          int err = 0;
↓ open down ↓ 832 lines elided ↑ open up ↑
1897 1901  
1898 1902          /* upgrade */
1899 1903          if (version < cb->cb_version) {
1900 1904                  char verstr[16];
1901 1905                  (void) snprintf(verstr, sizeof (verstr),
1902 1906                      "%llu", cb->cb_version);
1903 1907                  if (cb->cb_lastfs[0] && !same_pool(zhp, cb->cb_lastfs)) {
1904 1908                          /*
1905 1909                           * If they did "zfs upgrade -a", then we could
1906 1910                           * be doing ioctls to different pools.  We need
1907      -                         * to log this history once to each pool.
     1911 +                         * to log this history once to each pool, and bypass
     1912 +                         * the normal history logging that happens in main().
1908 1913                           */
1909      -                        verify(zpool_stage_history(g_zfs, history_str) == 0);
     1914 +                        (void) zpool_log_history(g_zfs, history_str);
     1915 +                        log_history = B_FALSE;
1910 1916                  }
1911 1917                  if (zfs_prop_set(zhp, "version", verstr) == 0)
1912 1918                          cb->cb_numupgraded++;
1913 1919                  else
1914 1920                          cb->cb_numfailed++;
1915 1921                  (void) strcpy(cb->cb_lastfs, zfs_get_name(zhp));
1916 1922          } else if (version > cb->cb_version) {
1917 1923                  /* can't downgrade */
1918 1924                  (void) printf(gettext("%s: can not be downgraded; "
1919 1925                      "it is already at version %u\n"),
↓ open down ↓ 1497 lines elided ↑ open up ↑
3417 3423                      gettext("missing property in property=value argument\n"));
3418 3424                  usage(B_FALSE);
3419 3425          }
3420 3426  
3421 3427          ret = zfs_for_each(argc - 2, argv + 2, NULL,
3422 3428              ZFS_TYPE_DATASET, NULL, NULL, 0, set_callback, &cb);
3423 3429  
3424 3430          return (ret);
3425 3431  }
3426 3432  
     3433 +typedef struct snap_cbdata {
     3434 +        nvlist_t *sd_nvl;
     3435 +        boolean_t sd_recursive;
     3436 +        const char *sd_snapname;
     3437 +} snap_cbdata_t;
     3438 +
     3439 +static int
     3440 +zfs_snapshot_cb(zfs_handle_t *zhp, void *arg)
     3441 +{
     3442 +        snap_cbdata_t *sd = arg;
     3443 +        char *name;
     3444 +        int rv = 0;
     3445 +        int error;
     3446 +
     3447 +        error = asprintf(&name, "%s@%s", zfs_get_name(zhp), sd->sd_snapname);
     3448 +        if (error == -1)
     3449 +                nomem();
     3450 +        fnvlist_add_boolean(sd->sd_nvl, name);
     3451 +        free(name);
     3452 +
     3453 +        if (sd->sd_recursive)
     3454 +                rv = zfs_iter_filesystems(zhp, zfs_snapshot_cb, sd);
     3455 +        zfs_close(zhp);
     3456 +        return (rv);
     3457 +}
     3458 +
3427 3459  /*
3428 3460   * zfs snapshot [-r] [-o prop=value] ... <fs@snap>
3429 3461   *
3430 3462   * Creates a snapshot with the given name.  While functionally equivalent to
3431 3463   * 'zfs create', it is a separate command to differentiate intent.
3432 3464   */
3433 3465  static int
3434 3466  zfs_do_snapshot(int argc, char **argv)
3435 3467  {
3436      -        boolean_t recursive = B_FALSE;
3437 3468          int ret = 0;
3438 3469          char c;
3439 3470          nvlist_t *props;
     3471 +        snap_cbdata_t sd = { 0 };
     3472 +        boolean_t multiple_snaps = B_FALSE;
3440 3473  
3441 3474          if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
3442 3475                  nomem();
     3476 +        if (nvlist_alloc(&sd.sd_nvl, NV_UNIQUE_NAME, 0) != 0)
     3477 +                nomem();
3443 3478  
3444 3479          /* check options */
3445 3480          while ((c = getopt(argc, argv, "ro:")) != -1) {
3446 3481                  switch (c) {
3447 3482                  case 'o':
3448 3483                          if (parseprop(props))
3449 3484                                  return (1);
3450 3485                          break;
3451 3486                  case 'r':
3452      -                        recursive = B_TRUE;
     3487 +                        sd.sd_recursive = B_TRUE;
     3488 +                        multiple_snaps = B_TRUE;
3453 3489                          break;
3454 3490                  case '?':
3455 3491                          (void) fprintf(stderr, gettext("invalid option '%c'\n"),
3456 3492                              optopt);
3457 3493                          goto usage;
3458 3494                  }
3459 3495          }
3460 3496  
3461 3497          argc -= optind;
3462 3498          argv += optind;
3463 3499  
3464 3500          /* check number of arguments */
3465 3501          if (argc < 1) {
3466 3502                  (void) fprintf(stderr, gettext("missing snapshot argument\n"));
3467 3503                  goto usage;
3468 3504          }
3469      -        if (argc > 1) {
3470      -                (void) fprintf(stderr, gettext("too many arguments\n"));
3471      -                goto usage;
     3505 +
     3506 +        if (argc > 1)
     3507 +                multiple_snaps = B_TRUE;
     3508 +        for (; argc > 0; argc--, argv++) {
     3509 +                char *atp;
     3510 +                zfs_handle_t *zhp;
     3511 +
     3512 +                atp = strchr(argv[0], '@');
     3513 +                if (atp == NULL)
     3514 +                        goto usage;
     3515 +                *atp = '\0';
     3516 +                sd.sd_snapname = atp + 1;
     3517 +                zhp = zfs_open(g_zfs, argv[0],
     3518 +                    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
     3519 +                if (zhp == NULL)
     3520 +                        goto usage;
     3521 +                if (zfs_snapshot_cb(zhp, &sd) != 0)
     3522 +                        goto usage;
3472 3523          }
3473 3524  
3474      -        ret = zfs_snapshot(g_zfs, argv[0], recursive, props);
     3525 +        ret = zfs_snapshot_nvl(g_zfs, sd.sd_nvl, props);
     3526 +        nvlist_free(sd.sd_nvl);
3475 3527          nvlist_free(props);
3476      -        if (ret && recursive)
     3528 +        if (ret != 0 && multiple_snaps)
3477 3529                  (void) fprintf(stderr, gettext("no snapshots were created\n"));
3478 3530          return (ret != 0);
3479 3531  
3480 3532  usage:
     3533 +        nvlist_free(sd.sd_nvl);
3481 3534          nvlist_free(props);
3482 3535          usage(B_FALSE);
3483 3536          return (-1);
3484 3537  }
3485 3538  
3486 3539  /*
3487 3540   * Send a backup stream to stdout.
3488 3541   */
3489 3542  static int
3490 3543  zfs_do_send(int argc, char **argv)
↓ open down ↓ 2981 lines elided ↑ open up ↑
6472 6525          (void) textdomain(TEXT_DOMAIN);
6473 6526  
6474 6527          opterr = 0;
6475 6528  
6476 6529          if ((g_zfs = libzfs_init()) == NULL) {
6477 6530                  (void) fprintf(stderr, gettext("internal error: failed to "
6478 6531                      "initialize ZFS library\n"));
6479 6532                  return (1);
6480 6533          }
6481 6534  
6482      -        zpool_set_history_str("zfs", argc, argv, history_str);
6483      -        verify(zpool_stage_history(g_zfs, history_str) == 0);
     6535 +        zfs_save_arguments(argc, argv, history_str, sizeof (history_str));
6484 6536  
6485 6537          libzfs_print_on_error(g_zfs, B_TRUE);
6486 6538  
6487 6539          if ((mnttab_file = fopen(MNTTAB, "r")) == NULL) {
6488 6540                  (void) fprintf(stderr, gettext("internal error: unable to "
6489 6541                      "open %s\n"), MNTTAB);
6490 6542                  return (1);
6491 6543          }
6492 6544  
6493 6545          /*
↓ open down ↓ 48 lines elided ↑ open up ↑
6542 6594                  } else {
6543 6595                          (void) fprintf(stderr, gettext("unrecognized "
6544 6596                              "command '%s'\n"), cmdname);
6545 6597                          usage(B_FALSE);
6546 6598                  }
6547 6599                  libzfs_mnttab_cache(g_zfs, B_FALSE);
6548 6600          }
6549 6601  
6550 6602          (void) fclose(mnttab_file);
6551 6603  
     6604 +        if (ret == 0 && log_history)
     6605 +                (void) zpool_log_history(g_zfs, history_str);
     6606 +
6552 6607          libzfs_fini(g_zfs);
6553 6608  
6554 6609          /*
6555 6610           * The 'ZFS_ABORT' environment variable causes us to dump core on exit
6556 6611           * for the purposes of running ::findleaks.
6557 6612           */
6558 6613          if (getenv("ZFS_ABORT") != NULL) {
6559 6614                  (void) printf("dumping core by request\n");
6560 6615                  abort();
6561 6616          }
6562 6617  
6563 6618          return (ret);
6564 6619  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX