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

*** 830,860 **** * and release them. */ void dsl_pool_clean_tmp_userrefs(dsl_pool_t *dp) { zap_attribute_t za; zap_cursor_t zc; objset_t *mos = dp->dp_meta_objset; uint64_t zapobj = dp->dp_tmp_userrefs_obj; if (zapobj == 0) return; ASSERT(spa_version(dp->dp_spa) >= SPA_VERSION_USERREFS); for (zap_cursor_init(&zc, mos, zapobj); zap_cursor_retrieve(&zc, &za) == 0; zap_cursor_advance(&zc)) { - char *htag; - uint64_t dsobj; - htag = strchr(za.za_name, '-'); *htag = '\0'; ++htag; dsobj = strtonum(za.za_name, NULL); ! dsl_dataset_user_release_tmp(dp, dsobj, htag); } zap_cursor_fini(&zc); } /* * Create the pool-wide zap object for storing temporary snapshot holds. --- 830,879 ---- * and release them. */ void dsl_pool_clean_tmp_userrefs(dsl_pool_t *dp) { + char *htag; zap_attribute_t za; zap_cursor_t zc; objset_t *mos = dp->dp_meta_objset; uint64_t zapobj = dp->dp_tmp_userrefs_obj; + uint64_t dsobj; + nvlist_t *holds, *tags; + dsl_dataset_t *ds; + char name[MAXNAMELEN]; if (zapobj == 0) return; ASSERT(spa_version(dp->dp_spa) >= SPA_VERSION_USERREFS); + holds = fnvlist_alloc(); + + dsl_pool_config_enter(dp, FTAG); for (zap_cursor_init(&zc, mos, zapobj); zap_cursor_retrieve(&zc, &za) == 0; zap_cursor_advance(&zc)) { htag = strchr(za.za_name, '-'); *htag = '\0'; ++htag; dsobj = strtonum(za.za_name, NULL); ! if (dsl_dataset_hold_obj(dp, dsobj, FTAG, &ds) == 0) { ! dsl_dataset_name(ds, name); ! if (nvlist_lookup_nvlist(holds, name, &tags) != 0) { ! tags = fnvlist_alloc(); ! fnvlist_add_boolean(tags, htag); ! fnvlist_add_nvlist(holds, name, tags); ! fnvlist_free(tags); ! } else { ! fnvlist_add_boolean(tags, htag); ! } ! dsl_dataset_rele(ds, FTAG); ! } } + dsl_pool_config_exit(dp, FTAG); + dsl_dataset_user_release(holds, NULL); + fnvlist_free(holds); zap_cursor_fini(&zc); } /* * Create the pool-wide zap object for storing temporary snapshot holds.