Print this page
3740 Poor ZFS send / receive performance due to snapshot hold / release processing
Submitted by: Steven Hartland <steven.hartland@multiplay.co.uk>

Split Close
Expand all
Collapse all
          --- old/usr/src/lib/libzfs_core/common/libzfs_core.c
          +++ new/usr/src/lib/libzfs_core/common/libzfs_core.c
↓ open down ↓ 13 lines elided ↑ open up ↑
  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  /*
  23   23   * Copyright (c) 2012 by Delphix. All rights reserved.
       24 + * Copyright (c) 2013 Steven Hartland. All rights reserved.
  24   25   */
  25   26  
  26   27  /*
  27   28   * LibZFS_Core (lzc) is intended to replace most functionality in libzfs.
  28   29   * It has the following characteristics:
  29   30   *
  30   31   *  - Thread Safe.  libzfs_core is accessible concurrently from multiple
  31   32   *  threads.  This is accomplished primarily by avoiding global data
  32   33   *  (e.g. caching).  Since it's thread-safe, there is no reason for a
  33   34   *  process to have multiple libzfs "instances".  Therefore, we store
↓ open down ↓ 213 lines elided ↑ open up ↑
 247  248   * Snapshots that do not exist will be silently ignored.
 248  249   *
 249  250   * If 'defer' is not set, and a snapshot has user holds or clones, the
 250  251   * destroy operation will fail and none of the snapshots will be
 251  252   * destroyed.
 252  253   *
 253  254   * If 'defer' is set, and a snapshot has user holds or clones, it will be
 254  255   * marked for deferred destruction, and will be destroyed when the last hold
 255  256   * or clone is removed/destroyed.
 256  257   *
      258 + * The return value will be ENOENT if none of the snapshots existed.
      259 + *
 257  260   * The return value will be 0 if all snapshots were destroyed (or marked for
 258      - * later destruction if 'defer' is set) or didn't exist to begin with.
      261 + * later destruction if 'defer' is set) or didn't exist to begin with and
      262 + * at least one snapshot was destroyed.
 259  263   *
 260  264   * Otherwise the return value will be the errno of a (unspecified) snapshot
 261  265   * that failed, no snapshots will be destroyed, and the errlist will have an
 262  266   * entry for each snapshot that failed.  The value in the errlist will be
 263  267   * the (int32) error code.
 264  268   */
 265  269  int
 266  270  lzc_destroy_snaps(nvlist_t *snaps, boolean_t defer, nvlist_t **errlist)
 267  271  {
 268  272          nvpair_t *elem;
↓ open down ↓ 10 lines elided ↑ open up ↑
 279  283  
 280  284          args = fnvlist_alloc();
 281  285          fnvlist_add_nvlist(args, "snaps", snaps);
 282  286          if (defer)
 283  287                  fnvlist_add_boolean(args, "defer");
 284  288  
 285  289          error = lzc_ioctl(ZFS_IOC_DESTROY_SNAPS, pool, args, errlist);
 286  290          nvlist_free(args);
 287  291  
 288  292          return (error);
 289      -
 290  293  }
 291  294  
 292  295  int
 293  296  lzc_snaprange_space(const char *firstsnap, const char *lastsnap,
 294  297      uint64_t *usedp)
 295  298  {
 296  299          nvlist_t *args;
 297  300          nvlist_t *result;
 298  301          int err;
 299  302          char fs[MAXNAMELEN];
↓ open down ↓ 39 lines elided ↑ open up ↑
 339  342   * The keys in the nvlist are snapshot names.
 340  343   * The snapshots must all be in the same pool.
 341  344   * The value is the name of the hold (string type).
 342  345   *
 343  346   * If cleanup_fd is not -1, it must be the result of open("/dev/zfs", O_EXCL).
 344  347   * In this case, when the cleanup_fd is closed (including on process
 345  348   * termination), the holds will be released.  If the system is shut down
 346  349   * uncleanly, the holds will be released when the pool is next opened
 347  350   * or imported.
 348  351   *
 349      - * The return value will be 0 if all holds were created. Otherwise the return
 350      - * value will be the errno of a (unspecified) hold that failed, no holds will
 351      - * be created, and the errlist will have an entry for each hold that
 352      - * failed (name = snapshot).  The value in the errlist will be the error
 353      - * code (int32).
      352 + * Holds for snapshots which don't exist will be skipped and have an entry
      353 + * added to errlist, but will not cause an overall failure, except in the
      354 + * case that all holds where skipped.
      355 + *
      356 + * The return value will be ENOENT if none of the snapshots for the requested
      357 + * holds existed.
      358 + *
      359 + * The return value will be 0 if the nvl holds was empty or all holds, for
      360 + * snapshots that existed, were succesfully created and at least one hold
      361 + * was created.
      362 + *
      363 + * Otherwise the return value will be the errno of a (unspecified) hold that
      364 + * failed and no holds will be created.
      365 + *
      366 + * In all cases the errlist will have an entry for each hold that failed
      367 + * (name = snapshot), with its value being the error code (int32).
 354  368   */
 355  369  int
 356  370  lzc_hold(nvlist_t *holds, int cleanup_fd, nvlist_t **errlist)
 357  371  {
 358  372          char pool[MAXNAMELEN];
 359  373          nvlist_t *args;
 360  374          nvpair_t *elem;
 361  375          int error;
 362  376  
 363  377          /* determine the pool name */
↓ open down ↓ 16 lines elided ↑ open up ↑
 380  394  /*
 381  395   * Release "user holds" on snapshots.  If the snapshot has been marked for
 382  396   * deferred destroy (by lzc_destroy_snaps(defer=B_TRUE)), it does not have
 383  397   * any clones, and all the user holds are removed, then the snapshot will be
 384  398   * destroyed.
 385  399   *
 386  400   * The keys in the nvlist are snapshot names.
 387  401   * The snapshots must all be in the same pool.
 388  402   * The value is a nvlist whose keys are the holds to remove.
 389  403   *
 390      - * The return value will be 0 if all holds were removed.
 391      - * Otherwise the return value will be the errno of a (unspecified) release
 392      - * that failed, no holds will be released, and the errlist will have an
 393      - * entry for each snapshot that has failed releases (name = snapshot).
 394      - * The value in the errlist will be the error code (int32) of a failed release.
      404 + * Holds which failed to release because they didn't exist will have an entry
      405 + * added to errlist, but will not cause an overall failure, except in the
      406 + * case that all releases where skipped.
      407 + *
      408 + * The return value will be ENOENT if none of the specified holds existed.
      409 + *
      410 + * The return value will be 0 if the nvl holds was empty or all holds that
      411 + * existed, were successfully removed and at least one hold was removed.
      412 + *
      413 + * Otherwise the return value will be the errno of a (unspecified) hold that
      414 + * failed to release and no holds will be released.
      415 + *
      416 + * In all cases the errlist will have an entry for each hold that failed to
      417 + * to release.
 395  418   */
 396  419  int
 397  420  lzc_release(nvlist_t *holds, nvlist_t **errlist)
 398  421  {
 399  422          char pool[MAXNAMELEN];
 400  423          nvpair_t *elem;
 401  424  
 402  425          /* determine the pool name */
 403  426          elem = nvlist_next_nvpair(holds, NULL);
 404  427          if (elem == NULL)
↓ open down ↓ 167 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX