Print this page
Optimize creation and removal of temporary "user holds" placed on
snapshots by a zfs send, by ensuring all the required holds and
releases are done in a single dsl_sync_task.
Creation now collates the required holds during a dry run and
then uses a single lzc_hold call via zfs_hold_apply instead of
processing each snapshot in turn.
Defered (on exit) cleanup by the kernel is also now done in
dsl_sync_task by reusing dsl_dataset_user_release.
On a test with 11 volumes in a tree each with 8 snapshots on a
single HDD zpool this reduces the time required to perform a full
send from 20 seconds to under 0.8 seconds.
For reference eliminating the hold entirely reduces this 0.15
seconds.
While I'm here:-
* Remove some unused structures
* Fix nvlist_t leak in zfs_release_one


4963 zfs_ioc_get_holds(const char *snapname, nvlist_t *args, nvlist_t *outnvl)
4964 {
4965         return (dsl_dataset_get_holds(snapname, outnvl));
4966 }
4967 
4968 /*
4969  * innvl: {
4970  *     snapname -> { holdname, ... }
4971  *     ...
4972  * }
4973  *
4974  * outnvl: {
4975  *     snapname -> error value (int32)
4976  *     ...
4977  * }
4978  */
4979 /* ARGSUSED */
4980 static int
4981 zfs_ioc_release(const char *pool, nvlist_t *holds, nvlist_t *errlist)
4982 {
4983         nvpair_t *pair;
4984 
4985         /*
4986          * The release may cause the snapshot to be destroyed; make sure it
4987          * is not mounted.
4988          */
4989         for (pair = nvlist_next_nvpair(holds, NULL); pair != NULL;
4990             pair = nvlist_next_nvpair(holds, pair))
4991                 zfs_unmount_snap(nvpair_name(pair));
4992 
4993         return (dsl_dataset_user_release(holds, errlist));
4994 }
4995 
4996 /*
4997  * inputs:
4998  * zc_name              name of new filesystem or snapshot
4999  * zc_value             full name of old snapshot
5000  *
5001  * outputs:
5002  * zc_cookie            space in bytes
5003  * zc_objset_type       compressed space in bytes
5004  * zc_perm_action       uncompressed space in bytes
5005  */
5006 static int
5007 zfs_ioc_space_written(zfs_cmd_t *zc)
5008 {
5009         int error;
5010         dsl_pool_t *dp;
5011         dsl_dataset_t *new, *old;
5012 




4963 zfs_ioc_get_holds(const char *snapname, nvlist_t *args, nvlist_t *outnvl)
4964 {
4965         return (dsl_dataset_get_holds(snapname, outnvl));
4966 }
4967 
4968 /*
4969  * innvl: {
4970  *     snapname -> { holdname, ... }
4971  *     ...
4972  * }
4973  *
4974  * outnvl: {
4975  *     snapname -> error value (int32)
4976  *     ...
4977  * }
4978  */
4979 /* ARGSUSED */
4980 static int
4981 zfs_ioc_release(const char *pool, nvlist_t *holds, nvlist_t *errlist)
4982 {










4983         return (dsl_dataset_user_release(holds, errlist));
4984 }
4985 
4986 /*
4987  * inputs:
4988  * zc_name              name of new filesystem or snapshot
4989  * zc_value             full name of old snapshot
4990  *
4991  * outputs:
4992  * zc_cookie            space in bytes
4993  * zc_objset_type       compressed space in bytes
4994  * zc_perm_action       uncompressed space in bytes
4995  */
4996 static int
4997 zfs_ioc_space_written(zfs_cmd_t *zc)
4998 {
4999         int error;
5000         dsl_pool_t *dp;
5001         dsl_dataset_t *new, *old;
5002