Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 138 additions & 1 deletion cmd/zfs/zfs_iter.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,15 @@ zfs_callback(zfs_handle_t *zhp, void *data)

if (((zfs_get_type(zhp) & (ZFS_TYPE_SNAPSHOT |
ZFS_TYPE_BOOKMARK)) == 0) && include_snaps) {
(void) zfs_iter_snapshots_v2(zhp, cb->cb_flags,
int snapshot_flags = cb->cb_flags;

/*
* Default sorting and tie breaks require the
* creation TXG.
*/
if (snapshot_flags & ZFS_ITER_BATCHED)
snapshot_flags |= ZFS_ITER_BATCHED_CREATETXG;
(void) zfs_iter_snapshots_v2(zhp, snapshot_flags,
zfs_callback, data, 0, 0);
}

Expand Down Expand Up @@ -265,6 +273,135 @@ zfs_list_only_by_fast(const zprop_list_t *p)
return (B_TRUE);
}

static boolean_t
zfs_list_batch_inapplicable_prop(int prop)
{
return (prop >= ZFS_PROP_TYPE && prop < ZFS_NUM_PROPS &&
!zfs_prop_valid_for_type(prop,
ZFS_TYPE_SNAPSHOT | ZFS_TYPE_BOOKMARK, B_FALSE));
}

/*
* Select the projected snapshot iterator only when it can populate every
* displayed and sorted property. Optional flags keep unrequested values out
* of the kernel calculation and returned nvlist.
*/
int
zfs_list_batch_flags(const zprop_list_t *p, const zfs_sort_column_t *sc)
{
int flags = ZFS_ITER_BATCHED;

if (p == NULL)
return (0);

for (; p != NULL; p = p->pl_next) {
if (p->pl_all)
return (0);

switch (p->pl_prop) {
case ZFS_PROP_NAME:
case ZFS_PROP_TYPE:
break;
case ZFS_PROP_USED:
flags |= ZFS_ITER_BATCHED_USED;
break;
case ZFS_PROP_REFERENCED:
flags |= ZFS_ITER_BATCHED_REFERENCED;
break;
case ZFS_PROP_LOGICALREFERENCED:
flags |= ZFS_ITER_BATCHED_LOGICALREFERENCED;
break;
case ZFS_PROP_DEFER_DESTROY:
flags |= ZFS_ITER_BATCHED_DEFER_DESTROY;
break;
case ZFS_PROP_WRITTEN:
flags |= ZFS_ITER_BATCHED_WRITTEN;
break;
case ZFS_PROP_OBJSETID:
flags |= ZFS_ITER_BATCHED_OBJSETID;
break;
case ZFS_PROP_GUID:
flags |= ZFS_ITER_BATCHED_GUID;
break;
case ZFS_PROP_CREATETXG:
flags |= ZFS_ITER_BATCHED_CREATETXG;
break;
case ZFS_PROP_CREATION:
flags |= ZFS_ITER_BATCHED_CREATION;
break;
case ZFS_PROP_USERREFS:
flags |= ZFS_ITER_BATCHED_USERREFS;
break;
case ZFS_PROP_NUMCLONES:
flags |= ZFS_ITER_BATCHED_NUMCLONES;
break;
case ZFS_PROP_INCONSISTENT:
flags |= ZFS_ITER_BATCHED_INCONSISTENT;
break;
case ZFS_PROP_REDACTED:
flags |= ZFS_ITER_BATCHED_REDACTED;
break;
default:
if (!zfs_list_batch_inapplicable_prop(p->pl_prop))
return (0);
break;
}
}

for (; sc != NULL; sc = sc->sc_next) {
switch (sc->sc_prop) {
case ZFS_PROP_NAME:
case ZFS_PROP_TYPE:
break;
case ZFS_PROP_USED:
flags |= ZFS_ITER_BATCHED_USED;
break;
case ZFS_PROP_REFERENCED:
flags |= ZFS_ITER_BATCHED_REFERENCED;
break;
case ZFS_PROP_LOGICALREFERENCED:
flags |= ZFS_ITER_BATCHED_LOGICALREFERENCED;
break;
case ZFS_PROP_DEFER_DESTROY:
flags |= ZFS_ITER_BATCHED_DEFER_DESTROY;
break;
case ZFS_PROP_WRITTEN:
flags |= ZFS_ITER_BATCHED_WRITTEN;
break;
case ZFS_PROP_OBJSETID:
flags |= ZFS_ITER_BATCHED_OBJSETID;
break;
case ZFS_PROP_GUID:
flags |= ZFS_ITER_BATCHED_GUID;
break;
case ZFS_PROP_CREATETXG:
flags |= ZFS_ITER_BATCHED_CREATETXG;
break;
case ZFS_PROP_CREATION:
flags |= ZFS_ITER_BATCHED_CREATION;
break;
case ZFS_PROP_USERREFS:
flags |= ZFS_ITER_BATCHED_USERREFS;
break;
case ZFS_PROP_NUMCLONES:
flags |= ZFS_ITER_BATCHED_NUMCLONES;
break;
case ZFS_PROP_INCONSISTENT:
flags |= ZFS_ITER_BATCHED_INCONSISTENT;
break;
case ZFS_PROP_REDACTED:
flags |= ZFS_ITER_BATCHED_REDACTED;
break;
default:
if (!zfs_list_batch_inapplicable_prop(sc->sc_prop))
return (0);
break;
}
}

return (flags);
}

static int
zfs_compare(const void *larg, const void *rarg)
{
Expand Down
1 change: 1 addition & 0 deletions cmd/zfs/zfs_iter.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ int zfs_add_sort_column(zfs_sort_column_t **, const char *, boolean_t);
void zfs_free_sort_columns(zfs_sort_column_t *);
boolean_t zfs_sort_only_by_fast(const zfs_sort_column_t *);
boolean_t zfs_list_only_by_fast(const zprop_list_t *);
int zfs_list_batch_flags(const zprop_list_t *, const zfs_sort_column_t *);

#ifdef __cplusplus
}
Expand Down
32 changes: 29 additions & 3 deletions cmd/zfs/zfs_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -3894,6 +3894,17 @@ list_callback(zfs_handle_t *zhp, void *data)
return (0);
}

static boolean_t
zfs_list_has_prop(const zprop_list_t *pl, zfs_prop_t prop)
{
for (; pl != NULL; pl = pl->pl_next) {
if (pl->pl_prop == prop)
return (B_TRUE);
}

return (B_FALSE);
}

static int
zfs_do_list(int argc, char **argv)
{
Expand Down Expand Up @@ -4051,10 +4062,25 @@ found3:;
cb.cb_first = B_TRUE;

/*
* If we are only going to list and sort by properties that are "fast"
* then we can use "simple" mode and avoid populating the properties
* nvlist.
* Use projected batches when they contain every displayed and sorted
* property. Keep simple mode available for fallback to a kernel that
* predates the batch ioctl.
*/
int batch_flags = zfs_list_batch_flags(cb.cb_proplist, sortcol);
/*
* Although AVAILABLE prints "-" for snapshots, its full-stat value is
* used with USED to color the field. Projected handles omit it.
*/
if (batch_flags != 0 && !cb.cb_json && use_color() &&
(types & ZFS_TYPE_SNAPSHOT) != 0 &&
zfs_list_has_prop(cb.cb_proplist, ZFS_PROP_USED) &&
zfs_list_has_prop(cb.cb_proplist, ZFS_PROP_AVAILABLE))
batch_flags = 0;
if (batch_flags != 0) {
if (cb.cb_json)
batch_flags |= ZFS_ITER_BATCHED_CREATETXG;
flags |= batch_flags;
}
if (zfs_list_only_by_fast(cb.cb_proplist) &&
zfs_sort_only_by_fast(sortcol))
flags |= ZFS_ITER_SIMPLE;
Expand Down
15 changes: 15 additions & 0 deletions include/libzfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,21 @@ _LIBZFS_H int zprop_collect_property(const char *, zprop_get_cbdata_t *,
#define ZFS_ITER_RECVD_PROPS (1 << 4)
#define ZFS_ITER_LITERAL_PROPS (1 << 5)
#define ZFS_ITER_SIMPLE (1 << 6)
/* Projected snapshot and bookmark fields requested by zfs list. */
#define ZFS_ITER_BATCHED (1 << 7)
#define ZFS_ITER_BATCHED_CREATION (1 << 8)
#define ZFS_ITER_BATCHED_USERREFS (1 << 9)
#define ZFS_ITER_BATCHED_GUID (1 << 10)
#define ZFS_ITER_BATCHED_CREATETXG (1 << 11)
#define ZFS_ITER_BATCHED_NUMCLONES (1 << 12)
#define ZFS_ITER_BATCHED_INCONSISTENT (1 << 13)
#define ZFS_ITER_BATCHED_REDACTED (1 << 14)
#define ZFS_ITER_BATCHED_USED (1 << 15)
#define ZFS_ITER_BATCHED_REFERENCED (1 << 16)
#define ZFS_ITER_BATCHED_LOGICALREFERENCED (1 << 17)
#define ZFS_ITER_BATCHED_DEFER_DESTROY (1 << 18)
#define ZFS_ITER_BATCHED_OBJSETID (1 << 19)
#define ZFS_ITER_BATCHED_WRITTEN (1 << 20)

typedef int (*zfs_iter_f)(zfs_handle_t *, void *);
_LIBZFS_H int zfs_iter_root(libzfs_handle_t *, zfs_iter_f, void *);
Expand Down
6 changes: 6 additions & 0 deletions include/os/freebsd/spl/sys/mod.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@
#define param_set_max_auto_ashift_args(var) \
CTLTYPE_UINT, NULL, 0, param_set_max_auto_ashift, "IU"

#define param_set_snapshot_list_batch_size_args(var) \
CTLTYPE_UINT, NULL, 0, param_set_snapshot_list_batch_size, "IU"

#define param_set_snapshot_list_batch_time_us_args(var) \
CTLTYPE_UINT, NULL, 0, param_set_snapshot_list_batch_time_us, "IU"

#define param_set_raidz_impl_args(var) \
CTLTYPE_STRING, NULL, 0, param_set_raidz_impl, "A"

Expand Down
20 changes: 20 additions & 0 deletions include/sys/dsl_dataset.h
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,26 @@ uint64_t dsl_get_inconsistent(dsl_dataset_t *ds);
uint64_t dsl_get_redacted(dsl_dataset_t *ds);
uint64_t dsl_get_available(dsl_dataset_t *ds);
int dsl_get_written(dsl_dataset_t *ds, uint64_t *written);

typedef struct dsl_dataset_snapshot_stats {
uint64_t dss_creation_txg;
uint64_t dss_creation_time;
uint64_t dss_guid;
uint64_t dss_userrefs;
uint64_t dss_num_clones;
uint64_t dss_used;
uint64_t dss_referenced;
uint64_t dss_logicalreferenced;
uint64_t dss_written;
uint8_t dss_inconsistent;
uint8_t dss_redacted;
uint8_t dss_defer_destroy;
uint8_t dss_written_valid;
} dsl_dataset_snapshot_stats_t;

int dsl_dataset_snapshot_stats(struct dsl_pool *dp, uint64_t dsobj,
boolean_t want_userrefs, boolean_t want_redacted, boolean_t want_written,
uint64_t min_txg, uint64_t max_txg, dsl_dataset_snapshot_stats_t *stats);
int dsl_get_prev_snap(dsl_dataset_t *ds, char *snap);
void dsl_get_redact_snaps(dsl_dataset_t *ds, nvlist_t *propval);
int dsl_get_mountpoint(dsl_dataset_t *ds, const char *dsname, char *value,
Expand Down
25 changes: 24 additions & 1 deletion include/sys/fs/zfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1608,6 +1608,28 @@ typedef enum {
*/
#define SNAP_ITER_MIN_TXG "snap_iter_min_txg"
#define SNAP_ITER_MAX_TXG "snap_iter_max_txg"
#define SNAP_ITER_BATCH_CURSOR "snap_iter_batch_cursor"
#define SNAP_ITER_BATCH_MAX_RESULTS "snap_iter_batch_max_results"
#define SNAP_ITER_BATCH_PROPS "snap_iter_batch_props"
#define SNAP_ITER_BATCH_NAMES "snap_iter_batch_names"
#define SNAP_ITER_BATCH_CREATETXGS "snap_iter_batch_createtxgs"
#define SNAP_ITER_BATCH_GUIDS "snap_iter_batch_guids"
#define SNAP_ITER_BATCH_CREATIONS "snap_iter_batch_creations"
#define SNAP_ITER_BATCH_USERREF_COUNTS "snap_iter_batch_userref_counts"
#define SNAP_ITER_BATCH_NUMCLONES "snap_iter_batch_numclones"
#define SNAP_ITER_BATCH_INCONSISTENT "snap_iter_batch_inconsistent"
#define SNAP_ITER_BATCH_REDACTED "snap_iter_batch_redacted"
#define SNAP_ITER_BATCH_USED "snap_iter_batch_used"
#define SNAP_ITER_BATCH_REFERENCED "snap_iter_batch_referenced"
#define SNAP_ITER_BATCH_LOGICALREFERENCED \
"snap_iter_batch_logicalreferenced"
#define SNAP_ITER_BATCH_DEFER_DESTROY "snap_iter_batch_defer_destroy"
#define SNAP_ITER_BATCH_WRITTENS "snap_iter_batch_writtens"
#define SNAP_ITER_BATCH_WRITTEN_VALID "snap_iter_batch_written_valid"
#define SNAP_ITER_BATCH_OBJSETIDS "snap_iter_batch_objsetids"
#define SNAP_ITER_BATCH_DMU_TYPE "snap_iter_batch_dmu_type"
#define SNAP_ITER_BATCH_DDS_FLAGS "snap_iter_batch_dds_flags"
#define SNAP_ITER_BATCH_EOF "snap_iter_batch_eof"

/*
* /dev/zfs ioctl numbers.
Expand All @@ -1616,7 +1638,7 @@ typedef enum {
*/
typedef enum zfs_ioc {
/*
* Core features - 89/128 numbers reserved.
* Core features - 92/128 numbers reserved.
*/
#ifdef __FreeBSD__
ZFS_IOC_FIRST = 0,
Expand Down Expand Up @@ -1715,6 +1737,7 @@ typedef enum zfs_ioc {
ZFS_IOC_POOL_PREFETCH, /* 0x5a58 */
ZFS_IOC_DDT_PRUNE, /* 0x5a59 */
ZFS_IOC_POOL_CONDENSE, /* 0x5a5a */
ZFS_IOC_SNAPSHOT_LIST_BATCH, /* 0x5a5b */

/*
* Per-platform (Optional) - 8/128 numbers reserved.
Expand Down
10 changes: 10 additions & 0 deletions include/sys/zfs_ioctl_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@
extern kmutex_t zfsdev_state_lock;
extern uint64_t zfs_max_nvlist_src_size;

#define ZFS_SNAPSHOT_LIST_BATCH_SIZE_DEFAULT 1024
#define ZFS_SNAPSHOT_LIST_BATCH_SIZE_MAX 4096
#define ZFS_SNAPSHOT_LIST_BATCH_TIME_US_DEFAULT 10000
#define ZFS_SNAPSHOT_LIST_BATCH_TIME_US_MAX 100000

extern uint_t zfs_snapshot_list_batch_size;
extern uint_t zfs_snapshot_list_batch_time_us;

typedef int zfs_ioc_legacy_func_t(zfs_cmd_t *);
typedef int zfs_ioc_func_t(const char *, nvlist_t *, nvlist_t *);
typedef int zfs_secpolicy_func_t(zfs_cmd_t *, nvlist_t *, cred_t *);
Expand Down Expand Up @@ -82,6 +90,8 @@ void zfs_ioctl_register(const char *, zfs_ioc_t, zfs_ioc_func_t *,
boolean_t, boolean_t, const zfs_ioc_key_t *, size_t);

uint64_t zfs_max_nvlist_src_size_os(void);
int param_set_snapshot_list_batch_size(ZFS_MODULE_PARAM_ARGS);
int param_set_snapshot_list_batch_time_us(ZFS_MODULE_PARAM_ARGS);
void zfs_ioctl_update_mount_cache(const char *dsname);
void zfs_ioctl_init_os(void);

Expand Down
1 change: 1 addition & 0 deletions lib/libzfs/libzfs.abi
Original file line number Diff line number Diff line change
Expand Up @@ -6616,6 +6616,7 @@
<enumerator name='ZFS_IOC_POOL_PREFETCH' value='23128'/>
<enumerator name='ZFS_IOC_DDT_PRUNE' value='23129'/>
<enumerator name='ZFS_IOC_POOL_CONDENSE' value='23130'/>
<enumerator name='ZFS_IOC_SNAPSHOT_LIST_BATCH' value='23131'/>
<enumerator name='ZFS_IOC_PLATFORM' value='23168'/>
<enumerator name='ZFS_IOC_EVENTS_NEXT' value='23169'/>
<enumerator name='ZFS_IOC_EVENTS_CLEAR' value='23170'/>
Expand Down
Loading
Loading