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


 329 
 330         (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
 331         return (ioctl(g_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0);
 332 }
 333 
 334 /*
 335  * Create "user holds" on snapshots.  If there is a hold on a snapshot,
 336  * the snapshot can not be destroyed.  (However, it can be marked for deletion
 337  * by lzc_destroy_snaps(defer=B_TRUE).)
 338  *
 339  * The keys in the nvlist are snapshot names.
 340  * The snapshots must all be in the same pool.
 341  * The value is the name of the hold (string type).
 342  *
 343  * If cleanup_fd is not -1, it must be the result of open("/dev/zfs", O_EXCL).
 344  * In this case, when the cleanup_fd is closed (including on process
 345  * termination), the holds will be released.  If the system is shut down
 346  * uncleanly, the holds will be released when the pool is next opened
 347  * or imported.
 348  *
 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).











 354  */
 355 int
 356 lzc_hold(nvlist_t *holds, int cleanup_fd, nvlist_t **errlist)
 357 {
 358         char pool[MAXNAMELEN];
 359         nvlist_t *args;
 360         nvpair_t *elem;
 361         int error;
 362 
 363         /* determine the pool name */
 364         elem = nvlist_next_nvpair(holds, NULL);
 365         if (elem == NULL)
 366                 return (0);
 367         (void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
 368         pool[strcspn(pool, "/@")] = '\0';
 369 
 370         args = fnvlist_alloc();
 371         fnvlist_add_nvlist(args, "holds", holds);
 372         if (cleanup_fd != -1)
 373                 fnvlist_add_int32(args, "cleanup_fd", cleanup_fd);
 374 
 375         error = lzc_ioctl(ZFS_IOC_HOLD, pool, args, errlist);
 376         nvlist_free(args);
 377         return (error);
 378 }
 379 
 380 /*
 381  * Release "user holds" on snapshots.  If the snapshot has been marked for
 382  * deferred destroy (by lzc_destroy_snaps(defer=B_TRUE)), it does not have
 383  * any clones, and all the user holds are removed, then the snapshot will be
 384  * destroyed.
 385  *
 386  * The keys in the nvlist are snapshot names.
 387  * The snapshots must all be in the same pool.
 388  * The value is a nvlist whose keys are the holds to remove.
 389  *
 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.








 395  */
 396 int
 397 lzc_release(nvlist_t *holds, nvlist_t **errlist)
 398 {
 399         char pool[MAXNAMELEN];
 400         nvpair_t *elem;
 401 
 402         /* determine the pool name */
 403         elem = nvlist_next_nvpair(holds, NULL);
 404         if (elem == NULL)
 405                 return (0);
 406         (void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
 407         pool[strcspn(pool, "/@")] = '\0';
 408 
 409         return (lzc_ioctl(ZFS_IOC_RELEASE, pool, holds, errlist));
 410 }
 411 
 412 /*
 413  * Retrieve list of user holds on the specified snapshot.
 414  *




 329 
 330         (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
 331         return (ioctl(g_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0);
 332 }
 333 
 334 /*
 335  * Create "user holds" on snapshots.  If there is a hold on a snapshot,
 336  * the snapshot can not be destroyed.  (However, it can be marked for deletion
 337  * by lzc_destroy_snaps(defer=B_TRUE).)
 338  *
 339  * The keys in the nvlist are snapshot names.
 340  * The snapshots must all be in the same pool.
 341  * The value is the name of the hold (string type).
 342  *
 343  * If cleanup_fd is not -1, it must be the result of open("/dev/zfs", O_EXCL).
 344  * In this case, when the cleanup_fd is closed (including on process
 345  * termination), the holds will be released.  If the system is shut down
 346  * uncleanly, the holds will be released when the pool is next opened
 347  * or imported.
 348  *
 349  * Holds for snapshots which don't exist will be skipped and have an entry
 350  * added to errlist, but will not cause an overall failure, except in the
 351  * case that all holds where skipped.
 352  *
 353  * The return value will be 0 if the nvl holds was empty or all holds, for
 354  * snapshots that existed, were succesfully created and at least one hold
 355  * was created.
 356  *
 357  * If none of the snapshots for the requested holds existed ENOENT will be
 358  * returned.
 359  *
 360  * Otherwise the return value will be the errno of a (unspecified) hold that
 361  * failed, no holds will be created.
 362  *
 363  * In all cases the errlist will have an entry for each hold that failed
 364  * (name = snapshot), with its value being the error code (int32).
 365  */
 366 int
 367 lzc_hold(nvlist_t *holds, int cleanup_fd, nvlist_t **errlist)
 368 {
 369         char pool[MAXNAMELEN];
 370         nvlist_t *args;
 371         nvpair_t *elem;
 372         int error;
 373 
 374         /* determine the pool name */
 375         elem = nvlist_next_nvpair(holds, NULL);
 376         if (elem == NULL)
 377                 return (0);
 378         (void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
 379         pool[strcspn(pool, "/@")] = '\0';
 380 
 381         args = fnvlist_alloc();
 382         fnvlist_add_nvlist(args, "holds", holds);
 383         if (cleanup_fd != -1)
 384                 fnvlist_add_int32(args, "cleanup_fd", cleanup_fd);
 385 
 386         error = lzc_ioctl(ZFS_IOC_HOLD, pool, args, errlist);
 387         nvlist_free(args);
 388         return (error);
 389 }
 390 
 391 /*
 392  * Release "user holds" on snapshots.  If the snapshot has been marked for
 393  * deferred destroy (by lzc_destroy_snaps(defer=B_TRUE)), it does not have
 394  * any clones, and all the user holds are removed, then the snapshot will be
 395  * destroyed.
 396  *
 397  * The keys in the nvlist are snapshot names.
 398  * The snapshots must all be in the same pool.
 399  * The value is a nvlist whose keys are the holds to remove.
 400  *
 401  * Holds which failed to release because they didn't exist will have an entry
 402  * added to errlist, but will not cause an overall failure.
 403  *
 404  * The return value will be 0 if the nvl holds was empty or all holds, that
 405  * existed, were succesfully removed and at least one hold was removed.
 406  *
 407  * If none of the holds specified existed ENOENT will be returned.
 408  *
 409  * Otherwise the return value will be the errno of a (unspecified) hold that
 410  * failed to release and no holds will be released.
 411  *
 412  * In all cases the errlist will have an entry for each hold that failed to
 413  * to release.
 414  */
 415 int
 416 lzc_release(nvlist_t *holds, nvlist_t **errlist)
 417 {
 418         char pool[MAXNAMELEN];
 419         nvpair_t *elem;
 420 
 421         /* determine the pool name */
 422         elem = nvlist_next_nvpair(holds, NULL);
 423         if (elem == NULL)
 424                 return (0);
 425         (void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
 426         pool[strcspn(pool, "/@")] = '\0';
 427 
 428         return (lzc_ioctl(ZFS_IOC_RELEASE, pool, holds, errlist));
 429 }
 430 
 431 /*
 432  * Retrieve list of user holds on the specified snapshot.
 433  *