zfs list: Allow more fields in ZFS_ITER_SIMPLE mode

If the fields to be listed and sorted by are constrained
to those populated by dsl_dataset_fast_stat(), then
zfs list is much faster, as it does not need to open each
objset and reads its properties.

A previous optimization by Pawel Dawidek
(0cee24064a) took advantage
of this to make listing snapshot names sorted only by name
much faster.

However, it was limited to `-o name -s name`, this work
extends this optimization to work with:
  - name
  - guid
  - createtxg
  - numclones
  - inconsistent
  - redacted
  - origin
and could be further extended to any other properties
supported by dsl_dataset_fast_stat() or similar, that do
not require extra locking or reading from disk.

Reviewed-by: Mark Maybee <mark.maybee@delphix.com>
Reviewed-by: Ryan Moeller <ryan@iXsystems.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Pawel Jakub Dawidek <pawel@dawidek.net>
Signed-off-by: Allan Jude <allan@klarasystems.com>
Closes #11080
This commit is contained in:
Allan Jude
2021-12-16 14:56:22 -05:00
committed by GitHub
parent 2300621dc7
commit f6a0dac84a
14 changed files with 189 additions and 95 deletions
+29 -21
View File
@@ -39,7 +39,7 @@
#include "libzfs_impl.h"
static int
zfs_iter_clones(zfs_handle_t *zhp, zfs_iter_f func, void *data)
zfs_iter_clones(zfs_handle_t *zhp, int flags, zfs_iter_f func, void *data)
{
nvlist_t *nvl = zfs_get_clones_nvl(zhp);
nvpair_t *pair;
@@ -104,7 +104,7 @@ top:
* Iterate over all child filesystems
*/
int
zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data)
zfs_iter_filesystems(zfs_handle_t *zhp, int flags, zfs_iter_f func, void *data)
{
zfs_cmd_t zc = {"\0"};
zfs_handle_t *nzhp;
@@ -113,19 +113,24 @@ zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data)
if (zhp->zfs_type != ZFS_TYPE_FILESYSTEM)
return (0);
if ((flags & ZFS_ITER_SIMPLE) == ZFS_ITER_SIMPLE)
zc.zc_simple = B_TRUE;
if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
return (-1);
while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_DATASET_LIST_NEXT,
&zc)) == 0) {
if (zc.zc_simple)
nzhp = make_dataset_simple_handle_zc(zhp, &zc);
else
nzhp = make_dataset_handle_zc(zhp->zfs_hdl, &zc);
/*
* Silently ignore errors, as the only plausible explanation is
* that the pool has since been removed.
*/
if ((nzhp = make_dataset_handle_zc(zhp->zfs_hdl,
&zc)) == NULL) {
if (nzhp == NULL)
continue;
}
if ((ret = func(nzhp, data)) != 0) {
zcmd_free_nvlists(&zc);
@@ -140,7 +145,7 @@ zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data)
* Iterate over all snapshots
*/
int
zfs_iter_snapshots(zfs_handle_t *zhp, boolean_t simple, zfs_iter_f func,
zfs_iter_snapshots(zfs_handle_t *zhp, int flags, zfs_iter_f func,
void *data, uint64_t min_txg, uint64_t max_txg)
{
zfs_cmd_t zc = {"\0"};
@@ -152,7 +157,7 @@ zfs_iter_snapshots(zfs_handle_t *zhp, boolean_t simple, zfs_iter_f func,
zhp->zfs_type == ZFS_TYPE_BOOKMARK)
return (0);
zc.zc_simple = simple;
zc.zc_simple = (flags & ZFS_ITER_SIMPLE) != 0;
if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
return (-1);
@@ -177,7 +182,7 @@ zfs_iter_snapshots(zfs_handle_t *zhp, boolean_t simple, zfs_iter_f func,
while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_SNAPSHOT_LIST_NEXT,
&zc)) == 0) {
if (simple)
if (zc.zc_simple)
nzhp = make_dataset_simple_handle_zc(zhp, &zc);
else
nzhp = make_dataset_handle_zc(zhp->zfs_hdl, &zc);
@@ -199,7 +204,7 @@ zfs_iter_snapshots(zfs_handle_t *zhp, boolean_t simple, zfs_iter_f func,
* Iterate over all bookmarks
*/
int
zfs_iter_bookmarks(zfs_handle_t *zhp, zfs_iter_f func, void *data)
zfs_iter_bookmarks(zfs_handle_t *zhp, int flags, zfs_iter_f func, void *data)
{
zfs_handle_t *nzhp;
nvlist_t *props = NULL;
@@ -306,8 +311,8 @@ zfs_snapshot_compare(const void *larg, const void *rarg)
}
int
zfs_iter_snapshots_sorted(zfs_handle_t *zhp, zfs_iter_f callback, void *data,
uint64_t min_txg, uint64_t max_txg)
zfs_iter_snapshots_sorted(zfs_handle_t *zhp, int flags, zfs_iter_f callback,
void *data, uint64_t min_txg, uint64_t max_txg)
{
int ret = 0;
zfs_node_t *node;
@@ -317,7 +322,7 @@ zfs_iter_snapshots_sorted(zfs_handle_t *zhp, zfs_iter_f callback, void *data,
avl_create(&avl, zfs_snapshot_compare,
sizeof (zfs_node_t), offsetof(zfs_node_t, zn_avlnode));
ret = zfs_iter_snapshots(zhp, B_FALSE, zfs_sort_snaps, &avl, min_txg,
ret = zfs_iter_snapshots(zhp, flags, zfs_sort_snaps, &avl, min_txg,
max_txg);
for (node = avl_first(&avl); node != NULL; node = AVL_NEXT(&avl, node))
@@ -380,7 +385,7 @@ snapspec_cb(zfs_handle_t *zhp, void *arg)
* return ENOENT at the end.
*/
int
zfs_iter_snapspec(zfs_handle_t *fs_zhp, const char *spec_orig,
zfs_iter_snapspec(zfs_handle_t *fs_zhp, int flags, const char *spec_orig,
zfs_iter_f func, void *arg)
{
char *buf, *comma_separated, *cp;
@@ -420,7 +425,7 @@ zfs_iter_snapspec(zfs_handle_t *fs_zhp, const char *spec_orig,
}
}
err = zfs_iter_snapshots_sorted(fs_zhp,
err = zfs_iter_snapshots_sorted(fs_zhp, flags,
snapspec_cb, &ssa, 0, 0);
if (ret == 0)
ret = err;
@@ -457,14 +462,14 @@ zfs_iter_snapspec(zfs_handle_t *fs_zhp, const char *spec_orig,
* and as close as possible.
*/
int
zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data)
zfs_iter_children(zfs_handle_t *zhp, int flags, zfs_iter_f func, void *data)
{
int ret;
if ((ret = zfs_iter_snapshots(zhp, B_FALSE, func, data, 0, 0)) != 0)
if ((ret = zfs_iter_snapshots(zhp, flags, func, data, 0, 0)) != 0)
return (ret);
return (zfs_iter_filesystems(zhp, func, data));
return (zfs_iter_filesystems(zhp, flags, func, data));
}
@@ -475,6 +480,7 @@ typedef struct iter_stack_frame {
typedef struct iter_dependents_arg {
boolean_t first;
int flags;
boolean_t allowrecursion;
iter_stack_frame_t *stack;
zfs_iter_f func;
@@ -490,7 +496,7 @@ iter_dependents_cb(zfs_handle_t *zhp, void *arg)
ida->first = B_FALSE;
if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
err = zfs_iter_clones(zhp, iter_dependents_cb, ida);
err = zfs_iter_clones(zhp, ida->flags, iter_dependents_cb, ida);
} else if (zhp->zfs_type != ZFS_TYPE_BOOKMARK) {
iter_stack_frame_t isf;
iter_stack_frame_t *f;
@@ -524,9 +530,10 @@ iter_dependents_cb(zfs_handle_t *zhp, void *arg)
isf.zhp = zhp;
isf.next = ida->stack;
ida->stack = &isf;
err = zfs_iter_filesystems(zhp, iter_dependents_cb, ida);
err = zfs_iter_filesystems(zhp, ida->flags,
iter_dependents_cb, ida);
if (err == 0)
err = zfs_iter_snapshots(zhp, B_FALSE,
err = zfs_iter_snapshots(zhp, ida->flags,
iter_dependents_cb, ida, 0, 0);
ida->stack = isf.next;
}
@@ -540,10 +547,11 @@ iter_dependents_cb(zfs_handle_t *zhp, void *arg)
}
int
zfs_iter_dependents(zfs_handle_t *zhp, boolean_t allowrecursion,
zfs_iter_dependents(zfs_handle_t *zhp, int flags, boolean_t allowrecursion,
zfs_iter_f func, void *data)
{
iter_dependents_arg_t ida;
ida.flags = flags;
ida.allowrecursion = allowrecursion;
ida.stack = NULL;
ida.func = func;