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