Notable upstream pull request merges:
 #16938 2aa3fbe76 zinject: count matches and injections for each handler
 #16947 -multiple zinject: add "probe" device injection type
 #16976 34205715e FreeBSD: Add setting of the VFCF_FILEREV flag

Obtained from:	OpenZFS
OpenZFS commit:	34205715e1
This commit is contained in:
Martin Matuska 2025-01-27 08:21:29 +01:00
commit c6767dc1f2
53 changed files with 1061 additions and 302 deletions

View file

@ -28,7 +28,7 @@ Two release branches are maintained for OpenZFS, they are:
Minor changes to support these distribution kernels will be applied as
needed. New kernel versions released after the OpenZFS LTS release are
not supported. LTS releases will receive patches for at least 2 years.
The current LTS release is OpenZFS 2.1.
The current LTS release is OpenZFS 2.2.
* OpenZFS current - Tracks the newest MAJOR.MINOR release. This branch
includes support for the latest OpenZFS features and recently releases

View file

@ -22,7 +22,7 @@
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015 by Delphix. All rights reserved.
* Copyright (c) 2017, Intel Corporation.
* Copyright (c) 2023-2024, Klara Inc.
* Copyright (c) 2023-2025, Klara, Inc.
*/
/*
@ -242,6 +242,36 @@ err_to_str(int err)
return ("[unknown]");
}
static const char *const iotypestrtable[ZINJECT_IOTYPES] = {
[ZINJECT_IOTYPE_NULL] = "null",
[ZINJECT_IOTYPE_READ] = "read",
[ZINJECT_IOTYPE_WRITE] = "write",
[ZINJECT_IOTYPE_FREE] = "free",
[ZINJECT_IOTYPE_CLAIM] = "claim",
[ZINJECT_IOTYPE_FLUSH] = "flush",
[ZINJECT_IOTYPE_TRIM] = "trim",
[ZINJECT_IOTYPE_ALL] = "all",
[ZINJECT_IOTYPE_PROBE] = "probe",
};
static zinject_iotype_t
str_to_iotype(const char *arg)
{
for (uint_t iotype = 0; iotype < ZINJECT_IOTYPES; iotype++)
if (iotypestrtable[iotype] != NULL &&
strcasecmp(iotypestrtable[iotype], arg) == 0)
return (iotype);
return (ZINJECT_IOTYPES);
}
static const char *
iotype_to_str(zinject_iotype_t iotype)
{
if (iotype >= ZINJECT_IOTYPES || iotypestrtable[iotype] == NULL)
return ("[unknown]");
return (iotypestrtable[iotype]);
}
/*
* Print usage message.
*/
@ -404,27 +434,30 @@ print_data_handler(int id, const char *pool, zinject_record_t *record,
if (*count == 0) {
(void) printf("%3s %-15s %-6s %-6s %-8s %3s %-4s "
"%-15s\n", "ID", "POOL", "OBJSET", "OBJECT", "TYPE",
"LVL", "DVAs", "RANGE");
"%-15s %-6s %-15s\n", "ID", "POOL", "OBJSET", "OBJECT",
"TYPE", "LVL", "DVAs", "RANGE", "MATCH", "INJECT");
(void) printf("--- --------------- ------ "
"------ -------- --- ---- ---------------\n");
"------ -------- --- ---- --------------- "
"------ ------\n");
}
*count += 1;
(void) printf("%3d %-15s %-6llu %-6llu %-8s %-3d 0x%02x ",
id, pool, (u_longlong_t)record->zi_objset,
(u_longlong_t)record->zi_object, type_to_name(record->zi_type),
record->zi_level, record->zi_dvas);
if (record->zi_start == 0 &&
record->zi_end == -1ULL)
(void) printf("all\n");
char rangebuf[32];
if (record->zi_start == 0 && record->zi_end == -1ULL)
snprintf(rangebuf, sizeof (rangebuf), "all");
else
(void) printf("[%llu, %llu]\n", (u_longlong_t)record->zi_start,
snprintf(rangebuf, sizeof (rangebuf), "[%llu, %llu]",
(u_longlong_t)record->zi_start,
(u_longlong_t)record->zi_end);
(void) printf("%3d %-15s %-6llu %-6llu %-8s %-3d 0x%02x %-15s "
"%6lu %6lu\n", id, pool, (u_longlong_t)record->zi_objset,
(u_longlong_t)record->zi_object, type_to_name(record->zi_type),
record->zi_level, record->zi_dvas, rangebuf,
record->zi_match_count, record->zi_inject_count);
return (0);
}
@ -432,10 +465,6 @@ static int
print_device_handler(int id, const char *pool, zinject_record_t *record,
void *data)
{
static const char *iotypestr[] = {
"null", "read", "write", "free", "claim", "flush", "trim", "all",
};
int *count = data;
if (record->zi_guid == 0 || record->zi_func[0] != '\0')
@ -445,11 +474,14 @@ print_device_handler(int id, const char *pool, zinject_record_t *record,
return (0);
if (*count == 0) {
(void) printf("%3s %-15s %-16s %-5s %-10s %-9s\n",
"ID", "POOL", "GUID", "TYPE", "ERROR", "FREQ");
(void) printf("%3s %-15s %-16s %-5s %-10s %-9s "
"%-6s %-6s\n",
"ID", "POOL", "GUID", "TYPE", "ERROR", "FREQ",
"MATCH", "INJECT");
(void) printf(
"--- --------------- ---------------- "
"----- ---------- ---------\n");
"----- ---------- --------- "
"------ ------\n");
}
*count += 1;
@ -457,9 +489,10 @@ print_device_handler(int id, const char *pool, zinject_record_t *record,
double freq = record->zi_freq == 0 ? 100.0f :
(((double)record->zi_freq) / ZI_PERCENTAGE_MAX) * 100.0f;
(void) printf("%3d %-15s %llx %-5s %-10s %8.4f%%\n", id, pool,
(u_longlong_t)record->zi_guid, iotypestr[record->zi_iotype],
err_to_str(record->zi_error), freq);
(void) printf("%3d %-15s %llx %-5s %-10s %8.4f%% "
"%6lu %6lu\n", id, pool, (u_longlong_t)record->zi_guid,
iotype_to_str(record->zi_iotype), err_to_str(record->zi_error),
freq, record->zi_match_count, record->zi_inject_count);
return (0);
}
@ -477,18 +510,25 @@ print_delay_handler(int id, const char *pool, zinject_record_t *record,
return (0);
if (*count == 0) {
(void) printf("%3s %-15s %-15s %-15s %s\n",
"ID", "POOL", "DELAY (ms)", "LANES", "GUID");
(void) printf("--- --------------- --------------- "
"--------------- ----------------\n");
(void) printf("%3s %-15s %-16s %-10s %-5s %-9s "
"%-6s %-6s\n",
"ID", "POOL", "GUID", "DELAY (ms)", "LANES", "FREQ",
"MATCH", "INJECT");
(void) printf("--- --------------- ---------------- "
"---------- ----- --------- "
"------ ------\n");
}
*count += 1;
(void) printf("%3d %-15s %-15llu %-15llu %llx\n", id, pool,
double freq = record->zi_freq == 0 ? 100.0f :
(((double)record->zi_freq) / ZI_PERCENTAGE_MAX) * 100.0f;
(void) printf("%3d %-15s %llx %10llu %5llu %8.4f%% "
"%6lu %6lu\n", id, pool, (u_longlong_t)record->zi_guid,
(u_longlong_t)NSEC2MSEC(record->zi_timer),
(u_longlong_t)record->zi_nlanes,
(u_longlong_t)record->zi_guid);
freq, record->zi_match_count, record->zi_inject_count);
return (0);
}
@ -852,7 +892,7 @@ main(int argc, char **argv)
int quiet = 0;
int error = 0;
int domount = 0;
int io_type = ZIO_TYPES;
int io_type = ZINJECT_IOTYPE_ALL;
int action = VDEV_STATE_UNKNOWN;
err_type_t type = TYPE_INVAL;
err_type_t label = TYPE_INVAL;
@ -1046,19 +1086,8 @@ main(int argc, char **argv)
}
break;
case 'T':
if (strcasecmp(optarg, "read") == 0) {
io_type = ZIO_TYPE_READ;
} else if (strcasecmp(optarg, "write") == 0) {
io_type = ZIO_TYPE_WRITE;
} else if (strcasecmp(optarg, "free") == 0) {
io_type = ZIO_TYPE_FREE;
} else if (strcasecmp(optarg, "claim") == 0) {
io_type = ZIO_TYPE_CLAIM;
} else if (strcasecmp(optarg, "flush") == 0) {
io_type = ZIO_TYPE_FLUSH;
} else if (strcasecmp(optarg, "all") == 0) {
io_type = ZIO_TYPES;
} else {
io_type = str_to_iotype(optarg);
if (io_type == ZINJECT_IOTYPES) {
(void) fprintf(stderr, "invalid I/O type "
"'%s': must be 'read', 'write', 'free', "
"'claim', 'flush' or 'all'\n", optarg);
@ -1180,7 +1209,7 @@ main(int argc, char **argv)
}
if (error == EILSEQ &&
(record.zi_freq == 0 || io_type != ZIO_TYPE_READ)) {
(record.zi_freq == 0 || io_type != ZINJECT_IOTYPE_READ)) {
(void) fprintf(stderr, "device corrupt errors require "
"io type read and a frequency value\n");
libzfs_fini(g_zfs);
@ -1195,9 +1224,9 @@ main(int argc, char **argv)
if (record.zi_nlanes) {
switch (io_type) {
case ZIO_TYPE_READ:
case ZIO_TYPE_WRITE:
case ZIO_TYPES:
case ZINJECT_IOTYPE_READ:
case ZINJECT_IOTYPE_WRITE:
case ZINJECT_IOTYPE_ALL:
break;
default:
(void) fprintf(stderr, "I/O type for a delay "

View file

@ -49,10 +49,10 @@ typedef uint16_t sa_attr_type_t;
* Attribute to register support for.
*/
typedef struct sa_attr_reg {
const char *sa_name; /* attribute name */
uint16_t sa_length;
const char *sa_name; /* attribute name */
uint16_t sa_length;
sa_bswap_type_t sa_byteswap; /* bswap function enum */
sa_attr_type_t sa_attr; /* filled in during registration */
sa_attr_type_t sa_attr; /* filled in during registration */
} sa_attr_reg_t;
@ -77,7 +77,7 @@ typedef struct sa_bulk_attr {
uint16_t sa_length;
sa_attr_type_t sa_attr;
/* the following are private to the sa framework */
void *sa_addr;
void *sa_addr;
uint16_t sa_buftype;
uint16_t sa_size;
} sa_bulk_attr_t;

View file

@ -23,7 +23,7 @@
* Copyright (c) 2012, 2024 by Delphix. All rights reserved.
* Copyright 2016 RackTop Systems.
* Copyright (c) 2017, Intel Corporation.
* Copyright (c) 2024, Klara, Inc.
* Copyright (c) 2024-2025, Klara, Inc.
*/
#ifndef _SYS_ZFS_IOCTL_H
@ -421,6 +421,8 @@ typedef struct zinject_record {
uint64_t zi_nlanes;
uint32_t zi_cmd;
uint32_t zi_dvas;
uint64_t zi_match_count; /* count of times matched */
uint64_t zi_inject_count; /* count of times injected */
} zinject_record_t;
#define ZINJECT_NULL 0x1
@ -454,6 +456,25 @@ typedef enum zinject_type {
ZINJECT_DELAY_EXPORT,
} zinject_type_t;
typedef enum zinject_iotype {
/*
* Compatibility: zi_iotype used to be set to ZIO_TYPE_, so make sure
* the corresponding ZINJECT_IOTYPE_ matches. Note that existing here
* does not mean that injections are possible for all these types.
*/
ZINJECT_IOTYPE_NULL = ZIO_TYPE_NULL,
ZINJECT_IOTYPE_READ = ZIO_TYPE_READ,
ZINJECT_IOTYPE_WRITE = ZIO_TYPE_WRITE,
ZINJECT_IOTYPE_FREE = ZIO_TYPE_FREE,
ZINJECT_IOTYPE_CLAIM = ZIO_TYPE_CLAIM,
ZINJECT_IOTYPE_FLUSH = ZIO_TYPE_FLUSH,
ZINJECT_IOTYPE_TRIM = ZIO_TYPE_TRIM,
ZINJECT_IOTYPE_ALL = ZIO_TYPES,
/* Room for future expansion for ZIO_TYPE_* */
ZINJECT_IOTYPE_PROBE = 16,
ZINJECT_IOTYPES,
} zinject_iotype_t;
typedef struct zfs_share {
uint64_t z_exportdata;
uint64_t z_sharedata;

View file

@ -428,7 +428,7 @@ but this may negatively impact pool space efficiency.
.
.It Sy zfs_vdev_direct_write_verify Ns = Ns Sy Linux 1 | FreeBSD 0 Pq uint
If non-zero, then a Direct I/O write's checksum will be verified every
time the write is issued and before it is commited to the block pointer.
time the write is issued and before it is committed to the block pointer.
In the event the checksum is not valid then the I/O operation will return EIO.
This module parameter can be used to detect if the
contents of the users buffer have changed in the process of doing a Direct I/O
@ -438,7 +438,7 @@ writes.
Each verify error causes a
.Sy dio_verify_wr
zevent.
Direct Write I/O checkum verify errors can be seen with
Direct Write I/O checksum verify errors can be seen with
.Nm zpool Cm status Fl d .
The default value for this is 1 on Linux, but is 0 for
.Fx
@ -1612,7 +1612,7 @@ _
.
.It Sy zfs_btree_verify_intensity Ns = Ns Sy 0 Pq uint
Enables btree verification.
The following settings are culminative:
The following settings are cumulative:
.TS
box;
lbz r l l .
@ -2525,7 +2525,7 @@ generate a system-dependent value close to 6 threads per taskq.
Set value only applies to pools imported/created after that.
.
.It Sy zio_taskq_write_tpq Ns = Ns Sy 16 Pq uint
Determines the minumum number of threads per write issue taskq.
Determines the minimum number of threads per write issue taskq.
Higher values improve CPU utilization on high throughput,
while lower reduce taskq locks contention on high IOPS.
Set value only applies to pools imported/created after that.

View file

@ -147,7 +147,7 @@ A text comment up to 8192 characters long
.It Sy bootsize
The amount of space to reserve for the EFI system partition
.It Sy failfast
If this device should propage BIO errors back to ZFS, used to disable
If this device should propagate BIO errors back to ZFS, used to disable
failfast.
.It Sy path
The path to the device for this vdev

View file

@ -245,11 +245,11 @@ zpool_checkpoint
.No example# Nm cat Pa /usr/share/zfs/compatibility.d/grub2-2.06
# Features which are supported by GRUB2 versions prior to v2.12.
#
# GRUB is not able to detect ZFS pool if snaphsot of top level boot pool
# GRUB is not able to detect ZFS pool if snapshot of top level boot pool
# is created. This issue is observed with GRUB versions before v2.12 if
# extensible_dataset feature is enabled on ZFS boot pool.
#
# This file lists all read-only comaptible features except
# This file lists all read-only compatible features except
# extensible_dataset and any other feature that depends on it.
#
allocation_classes

View file

@ -157,6 +157,7 @@ Destroy
all snapshots with this name in descendent file systems.
.It Fl v
Print verbose information about the deleted data.
.El
.Pp
Extreme care should be taken when applying either the
.Fl r
@ -164,7 +165,6 @@ or the
.Fl R
options, as they can destroy large portions of a pool and cause unexpected
behavior for mounted file systems in use.
.El
.It Xo
.Nm zfs
.Cm destroy

View file

@ -759,7 +759,7 @@ This option is provided for backwards compatibility with older ZFS versions.
.It Sy ZFS_SET_PIPE_MAX
Tells
.Nm zfs
to set the maximum pipe size for sends/recieves.
to set the maximum pipe size for sends/receives.
Disabled by default on Linux
due to an unfixed deadlock in Linux's pipe size handling code.
.

View file

@ -19,11 +19,11 @@
.\" CDDL HEADER END
.\"
.\" Copyright 2013 Darik Horn <dajhorn@vanadac.com>. All rights reserved.
.\" Copyright (c) 2024, Klara Inc.
.\" Copyright (c) 2024, 2025, Klara, Inc.
.\"
.\" lint-ok: WARNING: sections out of conventional order: Sh SYNOPSIS
.\"
.Dd December 2, 2024
.Dd January 14, 2025
.Dt ZINJECT 8
.Os
.
@ -265,15 +265,16 @@ will be translated to the appropriate blkid range according to the
object's properties.
.It Fl s Ar seconds
Run for this many seconds before reporting failure.
.It Fl T Ar failure
Set the failure type to one of
.Sy all ,
.Sy flush ,
.Sy claim ,
.Sy free ,
.Sy read ,
or
.Sy write .
.It Fl T Ar type
Inject the error into I/O of this type.
.Bl -tag -compact -width "read, write, flush, claim, free"
.It Sy read , Sy write , Sy flush , Sy claim , Sy free
Fundamental I/O types
.It Sy all
All fundamental I/O types
.It Sy probe
Device probe I/O
.El
.It Fl t Ar mos_type
Set this to
.Bl -tag -compact -width "spacemap"

View file

@ -66,7 +66,7 @@ devices if none are specified.
If the devices are being actively initialized the command will fail.
After being cleared
.Nm zpool Cm initialize
with no flags can be used to re-initialize all unallocoated regions on
with no flags can be used to re-initialize all unallocated regions on
the relevant target devices.
.It Fl w , -wait
Wait until the devices have finished initializing before returning.

View file

@ -83,7 +83,7 @@ Specify
to set pool GUID as key for pool objects instead of pool names.
.It Fl d
Display the number of Direct I/O read/write checksum verify errors that have
occured on a top-level VDEV.
occurred on a top-level VDEV.
See
.Sx zfs_vdev_direct_write_verify
in

View file

@ -90,6 +90,7 @@ modules_install-Linux: modules_uninstall-Linux-legacy
$(MAKE) -C @LINUX_OBJ@ M="$$PWD" modules_install \
INSTALL_MOD_PATH=$(INSTALL_MOD_PATH) \
INSTALL_MOD_DIR=$(INSTALL_MOD_DIR) \
$(if @KERNEL_ARCH@,ARCH=@KERNEL_ARCH@) \
KERNELRELEASE=@LINUX_VERSION@
@# Remove extraneous build products when packaging
if [ -n "$(DESTDIR)" ]; then \

View file

@ -144,12 +144,14 @@ struct vfsops zfs_vfsops = {
.vfs_quotactl = zfs_quotactl,
};
VFS_SET(zfs_vfsops, zfs, VFCF_DELEGADMIN | VFCF_JAIL
#ifdef VFCF_CROSS_COPY_FILE_RANGE
VFS_SET(zfs_vfsops, zfs,
VFCF_DELEGADMIN | VFCF_JAIL | VFCF_CROSS_COPY_FILE_RANGE);
#else
VFS_SET(zfs_vfsops, zfs, VFCF_DELEGADMIN | VFCF_JAIL);
| VFCF_CROSS_COPY_FILE_RANGE
#endif
#ifdef VFCF_FILEREVINC
| VFCF_FILEREVINC
#endif
);
/*
* We need to keep a count of active fs's.

View file

@ -22,7 +22,7 @@
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015 by Delphix. All rights reserved.
* Copyright (c) 2017, Intel Corporation.
* Copyright (c) 2024, Klara Inc.
* Copyright (c) 2024-2025, Klara, Inc.
*/
/*
@ -129,6 +129,9 @@ static boolean_t
zio_match_handler(const zbookmark_phys_t *zb, uint64_t type, int dva,
zinject_record_t *record, int error)
{
boolean_t matched = B_FALSE;
boolean_t injected = B_FALSE;
/*
* Check for a match against the MOS, which is based on type
*/
@ -137,9 +140,8 @@ zio_match_handler(const zbookmark_phys_t *zb, uint64_t type, int dva,
record->zi_object == DMU_META_DNODE_OBJECT) {
if (record->zi_type == DMU_OT_NONE ||
type == record->zi_type)
return (freq_triggered(record->zi_freq));
else
return (B_FALSE);
matched = B_TRUE;
goto done;
}
/*
@ -153,10 +155,20 @@ zio_match_handler(const zbookmark_phys_t *zb, uint64_t type, int dva,
(record->zi_dvas == 0 ||
(dva != ZI_NO_DVA && (record->zi_dvas & (1ULL << dva)))) &&
error == record->zi_error) {
return (freq_triggered(record->zi_freq));
matched = B_TRUE;
goto done;
}
return (B_FALSE);
done:
if (matched) {
record->zi_match_count++;
injected = freq_triggered(record->zi_freq);
}
if (injected)
record->zi_inject_count++;
return (injected);
}
/*
@ -177,8 +189,11 @@ zio_handle_panic_injection(spa_t *spa, const char *tag, uint64_t type)
continue;
if (handler->zi_record.zi_type == type &&
strcmp(tag, handler->zi_record.zi_func) == 0)
strcmp(tag, handler->zi_record.zi_func) == 0) {
handler->zi_record.zi_match_count++;
handler->zi_record.zi_inject_count++;
panic("Panic requested in function %s\n", tag);
}
}
rw_exit(&inject_lock);
@ -336,6 +351,8 @@ zio_handle_label_injection(zio_t *zio, int error)
if (zio->io_vd->vdev_guid == handler->zi_record.zi_guid &&
(offset >= start && offset <= end)) {
handler->zi_record.zi_match_count++;
handler->zi_record.zi_inject_count++;
ret = error;
break;
}
@ -359,6 +376,31 @@ zio_inject_bitflip_cb(void *data, size_t len, void *private)
return (1); /* stop after first flip */
}
/* Test if this zio matches the iotype from the injection record. */
static boolean_t
zio_match_iotype(zio_t *zio, uint32_t iotype)
{
ASSERT3P(zio, !=, NULL);
/* Unknown iotype, maybe from a newer version of zinject. Reject it. */
if (iotype >= ZINJECT_IOTYPES)
return (B_FALSE);
/* Probe IOs only match IOTYPE_PROBE, regardless of their type. */
if (zio->io_flags & ZIO_FLAG_PROBE)
return (iotype == ZINJECT_IOTYPE_PROBE);
/* Standard IO types, match against ZIO type. */
if (iotype < ZINJECT_IOTYPE_ALL)
return (iotype == zio->io_type);
/* Match any standard IO type. */
if (iotype == ZINJECT_IOTYPE_ALL)
return (B_TRUE);
return (B_FALSE);
}
static int
zio_handle_device_injection_impl(vdev_t *vd, zio_t *zio, int err1, int err2)
{
@ -367,9 +409,11 @@ zio_handle_device_injection_impl(vdev_t *vd, zio_t *zio, int err1, int err2)
/*
* We skip over faults in the labels unless it's during device open
* (i.e. zio == NULL) or a device flush (offset is meaningless)
* (i.e. zio == NULL) or a device flush (offset is meaningless). We let
* probe IOs through so we can match them to probe inject records.
*/
if (zio != NULL && zio->io_type != ZIO_TYPE_FLUSH) {
if (zio != NULL && zio->io_type != ZIO_TYPE_FLUSH &&
!(zio->io_flags & ZIO_FLAG_PROBE)) {
uint64_t offset = zio->io_offset;
if (offset < VDEV_LABEL_START_SIZE ||
@ -393,19 +437,22 @@ zio_handle_device_injection_impl(vdev_t *vd, zio_t *zio, int err1, int err2)
}
/* Handle type specific I/O failures */
if (zio != NULL &&
handler->zi_record.zi_iotype != ZIO_TYPES &&
handler->zi_record.zi_iotype != zio->io_type)
if (zio != NULL && !zio_match_iotype(zio,
handler->zi_record.zi_iotype))
continue;
if (handler->zi_record.zi_error == err1 ||
handler->zi_record.zi_error == err2) {
handler->zi_record.zi_match_count++;
/*
* limit error injection if requested
*/
if (!freq_triggered(handler->zi_record.zi_freq))
continue;
handler->zi_record.zi_inject_count++;
/*
* For a failed open, pretend like the device
* has gone away.
@ -441,6 +488,8 @@ zio_handle_device_injection_impl(vdev_t *vd, zio_t *zio, int err1, int err2)
break;
}
if (handler->zi_record.zi_error == ENXIO) {
handler->zi_record.zi_match_count++;
handler->zi_record.zi_inject_count++;
ret = SET_ERROR(EIO);
break;
}
@ -483,6 +532,8 @@ zio_handle_ignored_writes(zio_t *zio)
handler->zi_record.zi_cmd != ZINJECT_IGNORED_WRITES)
continue;
handler->zi_record.zi_match_count++;
/*
* Positive duration implies # of seconds, negative
* a number of txgs
@ -495,8 +546,10 @@ zio_handle_ignored_writes(zio_t *zio)
}
/* Have a "problem" writing 60% of the time */
if (random_in_range(100) < 60)
if (random_in_range(100) < 60) {
handler->zi_record.zi_inject_count++;
zio->io_pipeline &= ~ZIO_VDEV_IO_STAGES;
}
break;
}
@ -520,6 +573,9 @@ spa_handle_ignored_writes(spa_t *spa)
handler->zi_record.zi_cmd != ZINJECT_IGNORED_WRITES)
continue;
handler->zi_record.zi_match_count++;
handler->zi_record.zi_inject_count++;
if (handler->zi_record.zi_duration > 0) {
VERIFY(handler->zi_record.zi_timer == 0 ||
ddi_time_after64(
@ -601,17 +657,12 @@ zio_handle_io_delay(zio_t *zio)
if (handler->zi_record.zi_cmd != ZINJECT_DELAY_IO)
continue;
if (!freq_triggered(handler->zi_record.zi_freq))
continue;
if (vd->vdev_guid != handler->zi_record.zi_guid)
continue;
/* also match on I/O type (e.g., -T read) */
if (handler->zi_record.zi_iotype != ZIO_TYPES &&
handler->zi_record.zi_iotype != zio->io_type) {
if (!zio_match_iotype(zio, handler->zi_record.zi_iotype))
continue;
}
/*
* Defensive; should never happen as the array allocation
@ -628,6 +679,12 @@ zio_handle_io_delay(zio_t *zio)
ASSERT3U(handler->zi_record.zi_nlanes, >,
handler->zi_next_lane);
handler->zi_record.zi_match_count++;
/* Limit the use of this handler if requested */
if (!freq_triggered(handler->zi_record.zi_freq))
continue;
/*
* We want to issue this IO to the lane that will become
* idle the soonest, so we compare the soonest this
@ -699,6 +756,9 @@ zio_handle_io_delay(zio_t *zio)
*/
min_handler->zi_next_lane = (min_handler->zi_next_lane + 1) %
min_handler->zi_record.zi_nlanes;
min_handler->zi_record.zi_inject_count++;
}
mutex_exit(&inject_delay_mtx);
@ -721,9 +781,11 @@ zio_handle_pool_delay(spa_t *spa, hrtime_t elapsed, zinject_type_t command)
handler = list_next(&inject_handlers, handler)) {
ASSERT3P(handler->zi_spa_name, !=, NULL);
if (strcmp(spa_name(spa), handler->zi_spa_name) == 0) {
handler->zi_record.zi_match_count++;
uint64_t pause =
SEC2NSEC(handler->zi_record.zi_duration);
if (pause > elapsed) {
handler->zi_record.zi_inject_count++;
delay = pause - elapsed;
}
id = handler->zi_id;

View file

@ -159,7 +159,7 @@ tests = ['json_sanity']
tags = ['functional', 'cli_root', 'json']
[tests/functional/cli_root/zinject]
tests = ['zinject_args']
tests = ['zinject_args', 'zinject_counts', 'zinject_probe']
pre =
post =
tags = ['functional', 'cli_root', 'zinject']

View file

@ -42,6 +42,7 @@ scripts_zfs_tests_includedir = $(datadir)/$(PACKAGE)/zfs-tests/include
dist_scripts_zfs_tests_include_DATA = \
%D%/include/blkdev.shlib \
%D%/include/commands.cfg \
%D%/include/kstat.shlib \
%D%/include/libtest.shlib \
%D%/include/math.shlib \
%D%/include/properties.shlib \

View file

@ -0,0 +1,516 @@
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or https://opensource.org/licenses/CDDL-1.0.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright (c) 2025, Klara, Inc.
#
#
# This file provides the following helpers to read kstats from tests.
#
# kstat [-g] <stat>
# kstat_pool [-g] <pool> <stat>
# kstat_dataset [-N] <dataset | pool/objsetid> <stat>
#
# `kstat` and `kstat_pool` return the value of of the given <stat>, either
# a global or pool-specific state.
#
# $ kstat dbgmsg
# timestamp message
# 1736848201 spa_history.c:304:spa_history_log_sync(): txg 14734896 ...
# 1736848201 spa_history.c:330:spa_history_log_sync(): ioctl ...
# ...
#
# $ kstat_pool garden state
# ONLINE
#
# To get a single stat within a group or collection, separate the name with
# '.' characters.
#
# $ kstat dbufstats.cache_target_bytes
# 3215780693
#
# $ kstat_pool crayon iostats.arc_read_bytes
# 253671670784
#
# -g is "group" mode. If the kstat is a group or collection, all stats in that
# group are returned, one stat per line, key and value separated by a space.
#
# $ kstat -g dbufstats
# cache_count 1792
# cache_size_bytes 87720376
# cache_size_bytes_max 305187768
# cache_target_bytes 97668555
# ...
#
# $ kstat_pool -g crayon iostats
# trim_extents_written 0
# trim_bytes_written 0
# trim_extents_skipped 0
# trim_bytes_skipped 0
# ...
#
# `kstat_dataset` accesses the per-dataset group kstat. The dataset can be
# specified by name:
#
# $ kstat_dataset crayon/home/robn nunlinks
# 2628514
#
# or, with the -N switch, as <pool>/<objsetID>:
#
# $ kstat_dataset -N crayon/7 writes
# 125135
#
####################
# Public interface
#
# kstat [-g] <stat>
#
function kstat
{
typeset -i want_group=0
OPTIND=1
while getopts "g" opt ; do
case $opt in
'g') want_group=1 ;;
*) log_fail "kstat: invalid option '$opt'" ;;
esac
done
shift $(expr $OPTIND - 1)
typeset stat=$1
$_kstat_os 'global' '' "$stat" $want_group
}
#
# kstat_pool [-g] <pool> <stat>
#
function kstat_pool
{
typeset -i want_group=0
OPTIND=1
while getopts "g" opt ; do
case $opt in
'g') want_group=1 ;;
*) log_fail "kstat_pool: invalid option '$opt'" ;;
esac
done
shift $(expr $OPTIND - 1)
typeset pool=$1
typeset stat=$2
$_kstat_os 'pool' "$pool" "$stat" $want_group
}
#
# kstat_dataset [-N] <dataset | pool/objsetid> <stat>
#
function kstat_dataset
{
typeset -i opt_objsetid=0
OPTIND=1
while getopts "N" opt ; do
case $opt in
'N') opt_objsetid=1 ;;
*) log_fail "kstat_dataset: invalid option '$opt'" ;;
esac
done
shift $(expr $OPTIND - 1)
typeset dsarg=$1
typeset stat=$2
if [[ $opt_objsetid == 0 ]] ; then
typeset pool="${dsarg%%/*}" # clear first / -> end
typeset objsetid=$($_resolve_dsname_os "$pool" "$dsarg")
if [[ -z "$objsetid" ]] ; then
log_fail "kstat_dataset: dataset not found: $dsarg"
fi
dsarg="$pool/$objsetid"
fi
$_kstat_os 'dataset' "$dsarg" "$stat" 0
}
####################
# Platform-specific interface
#
# Implementation notes
#
# There's not a lot of uniformity between platforms, so I've written to a rough
# imagined model that seems to fit the majority of OpenZFS kstats.
#
# The main platform entry points look like this:
#
# _kstat_freebsd <scope> <object> <stat> <want_group>
# _kstat_linux <scope> <object> <stat> <want_group>
#
# - scope: one of 'global', 'pool', 'dataset'. The "kind" of object the kstat
# is attached to.
# - object: name of the scoped object
# global: empty string
# pool: pool name
# dataset: <pool>/<objsetId> pair
# - stat: kstat name to get
# - want_group: 0 to get the single value for the kstat, 1 to treat the kstat
# as a group and get all the stat names+values under it. group
# kstats cannot have values, and stat kstats cannot have
# children (by definition)
#
# Stat values can have multiple lines, so be prepared for those.
#
# These functions either succeed and produce the requested output, or call
# log_fail. They should never output empty, or 0, or anything else.
#
# Output:
#
# - want_group=0: the single stat value, followed by newline
# - want_group=1: One stat per line, <name><SP><value><newline>
#
#
# To support kstat_dataset(), platforms also need to provide a dataset
# name->object id resolver function.
#
# _resolve_dsname_freebsd <pool> <dsname>
# _resolve_dsname_linux <pool> <dsname>
#
# - pool: pool name. always the first part of the dataset name
# - dsname: dataset name, in the standard <pool>/<some>/<dataset> format.
#
# Output is <objsetID>. objsetID is a decimal integer, > 0
#
####################
# FreeBSD
#
# All kstats are accessed through sysctl. We model "groups" as interior nodes
# in the stat tree, which are normally opaque. Because sysctl has no filtering
# options, and requesting any node produces all nodes below it, we have to
# always get the name and value, and then consider the output to understand
# if we got a group or a single stat, and post-process accordingly.
#
# Scopes are mostly mapped directly to known locations in the tree, but there
# are a handful of stats that are out of position, so we need to adjust.
#
#
# _kstat_freebsd <scope> <object> <stat> <want_group>
#
function _kstat_freebsd
{
typeset scope=$1
typeset obj=$2
typeset stat=$3
typeset -i want_group=$4
typeset oid=""
case "$scope" in
global)
oid="kstat.zfs.misc.$stat"
;;
pool)
# For reasons unknown, the "multihost", "txgs" and "reads"
# pool-specific kstats are directly under kstat.zfs.<pool>,
# rather than kstat.zfs.<pool>.misc like the other pool kstats.
# Adjust for that here.
case "$stat" in
multihost|txgs|reads)
oid="kstat.zfs.$obj.$stat"
;;
*)
oid="kstat.zfs.$obj.misc.$stat"
;;
esac
;;
dataset)
typeset pool=""
typeset -i objsetid=0
_split_pool_objsetid $obj pool objsetid
oid=$(printf 'kstat.zfs.%s.dataset.objset-0x%x.%s' \
$pool $objsetid $stat)
;;
esac
# Calling sysctl on a "group" node will return everything under that
# node, so we have to inspect the first line to make sure we are
# getting back what we expect. For a single value, the key will have
# the name we requested, while for a group, the key will not have the
# name (group nodes are "opaque", not returned by sysctl by default.
if [[ $want_group == 0 ]] ; then
sysctl -e "$oid" | awk -v oid="$oid" -v oidre="^$oid=" '
NR == 1 && $0 !~ oidre { exit 1 }
NR == 1 { print substr($0, length(oid)+2) ; next }
{ print }
'
else
sysctl -e "$oid" | awk -v oid="$oid" -v oidre="^$oid=" '
NR == 1 && $0 ~ oidre { exit 2 }
{
sub("^" oid "\.", "")
sub("=", " ")
print
}
'
fi
typeset -i err=$?
case $err in
0) return ;;
1) log_fail "kstat: can't get value for group kstat: $oid" ;;
2) log_fail "kstat: not a group kstat: $oid" ;;
esac
log_fail "kstat: unknown error: $oid"
}
#
# _resolve_dsname_freebsd <pool> <dsname>
#
function _resolve_dsname_freebsd
{
# we're searching for:
#
# kstat.zfs.shed.dataset.objset-0x8087.dataset_name: shed/poudriere
#
# We split on '.', then get the hex objsetid from field 5.
#
# We convert hex to decimal in the shell because there isn't a _simple_
# portable way to do it in awk and this code is already too intense to
# do it a complicated way.
typeset pool=$1
typeset dsname=$2
sysctl -e kstat.zfs.$pool | \
awk -F '.' -v dsnamere="=$dsname$" '
/\.objset-0x[0-9a-f]+\.dataset_name=/ && $6 ~ dsnamere {
print substr($5, 8)
exit
}
' | xargs printf %d
}
####################
# Linux
#
# kstats all live under /proc/spl/kstat/zfs. They have a flat structure: global
# at top-level, pool in a directory, and dataset in a objset- file inside the
# pool dir.
#
# Groups are challenge. A single stat can be the entire text of a file, or
# a single line that must be extracted from a "group" file. The only way to
# recognise a group from the outside is to look for its header. This naturally
# breaks if a raw file had a matching header, or if a group file chooses to
# hid its header. Fortunately OpenZFS does none of these things at the moment.
#
#
# _kstat_linux <scope> <object> <stat> <want_group>
#
function _kstat_linux
{
typeset scope=$1
typeset obj=$2
typeset stat=$3
typeset -i want_group=$4
typeset singlestat=""
if [[ $scope == 'dataset' ]] ; then
typeset pool=""
typeset -i objsetid=0
_split_pool_objsetid $obj pool objsetid
stat=$(printf 'objset-0x%x.%s' $objsetid $stat)
obj=$pool
scope='pool'
fi
typeset path=""
if [[ $scope == 'global' ]] ; then
path="/proc/spl/kstat/zfs/$stat"
else
path="/proc/spl/kstat/zfs/$obj/$stat"
fi
if [[ ! -e "$path" && $want_group -eq 0 ]] ; then
# This single stat doesn't have its own file, but the wanted
# stat could be in a group kstat file, which we now need to
# find. To do this, we split a single stat name into two parts:
# the file that would contain the stat, and the key within that
# file to match on. This works by converting all bar the last
# '.' separator to '/', then splitting on the remaining '.'
# separator. If there are no '.' separators, the second arg
# returned will be empty.
#
# foo -> (foo)
# foo.bar -> (foo, bar)
# foo.bar.baz -> (foo/bar, baz)
# foo.bar.baz.quux -> (foo/bar/baz, quux)
#
# This is how we will target single stats within a larger NAMED
# kstat file, eg dbufstats.cache_target_bytes.
typeset -a split=($(echo "$stat" | \
sed -E 's/^(.+)\.([^\.]+)$/\1 \2/ ; s/\./\//g'))
typeset statfile=${split[0]}
singlestat=${split[1]:-""}
if [[ $scope == 'global' ]] ; then
path="/proc/spl/kstat/zfs/$statfile"
else
path="/proc/spl/kstat/zfs/$obj/$statfile"
fi
fi
if [[ ! -r "$path" ]] ; then
log_fail "kstat: can't read $path"
fi
if [[ $want_group == 1 ]] ; then
# "group" (NAMED) kstats on Linux start:
#
# $ cat /proc/spl/kstat/zfs/crayon/iostats
# 70 1 0x01 26 7072 8577844978 661416318663496
# name type data
# trim_extents_written 4 0
# trim_bytes_written 4 0
#
# The second value on the first row is the ks_type. Group
# mode only works for type 1, KSTAT_TYPE_NAMED. So we check
# for that, and eject if it's the wrong type. Otherwise, we
# skip the header row and process the values.
awk '
NR == 1 && ! /^[0-9]+ 1 / { exit 2 }
NR < 3 { next }
{ print $1 " " $NF }
' "$path"
elif [[ -n $singlestat ]] ; then
# single stat. must be a single line within a group stat, so
# we look for the header again as above.
awk -v singlestat="$singlestat" \
-v singlestatre="^$singlestat " '
NR == 1 && /^[0-9]+ [^1] / { exit 2 }
NR < 3 { next }
$0 ~ singlestatre { print $NF ; exit 0 }
ENDFILE { exit 3 }
' "$path"
else
# raw stat. dump contents, exclude group stats
awk '
NR == 1 && /^[0-9]+ 1 / { exit 1 }
{ print }
' "$path"
fi
typeset -i err=$?
case $err in
0) return ;;
1) log_fail "kstat: can't get value for group kstat: $path" ;;
2) log_fail "kstat: not a group kstat: $path" ;;
3) log_fail "kstat: stat not found in group: $path $singlestat" ;;
esac
log_fail "kstat: unknown error: $path"
}
#
# _resolve_dsname_linux <pool> <dsname>
#
function _resolve_dsname_linux
{
# We look inside all:
#
# /proc/spl/kstat/zfs/crayon/objset-0x113
#
# and check the dataset_name field inside. If we get a match, we split
# the filename on /, then extract the hex objsetid.
#
# We convert hex to decimal in the shell because there isn't a _simple_
# portable way to do it in awk and this code is already too intense to
# do it a complicated way.
typeset pool=$1
typeset dsname=$2
awk -v dsname="$dsname" '
$1 == "dataset_name" && $3 == dsname {
split(FILENAME, a, "/")
print substr(a[7], 8)
exit
}
' /proc/spl/kstat/zfs/$pool/objset-0x* | xargs printf %d
}
####################
#
# _split_pool_objsetid <obj> <*pool> <*objsetid>
#
# Splits pool/objsetId string in <obj> and fills <pool> and <objsetid>.
#
function _split_pool_objsetid
{
typeset obj=$1
typeset -n pool=$2
typeset -n objsetid=$3
pool="${obj%%/*}" # clear first / -> end
typeset osidarg="${obj#*/}" # clear start -> first /
# ensure objsetid arg does not contain a /. we're about to convert it,
# but ksh will treat it as an expression, and a / will give a
# divide-by-zero
if [[ "${osidarg%%/*}" != "$osidarg" ]] ; then
log_fail "kstat: invalid objsetid: $osidarg"
fi
typeset -i id=$osidarg
if [[ $id -le 0 ]] ; then
log_fail "kstat: invalid objsetid: $osidarg"
fi
objsetid=$id
}
####################
#
# Per-platform function selection.
#
# To avoid needing platform check throughout, we store the names of the
# platform functions and call through them.
#
if is_freebsd ; then
_kstat_os='_kstat_freebsd'
_resolve_dsname_os='_resolve_dsname_freebsd'
elif is_linux ; then
_kstat_os='_kstat_linux'
_resolve_dsname_os='_resolve_dsname_linux'
else
_kstat_os='_kstat_unknown_platform_implement_me'
_resolve_dsname_os='_resolve_dsname_unknown_platform_implement_me'
fi

View file

@ -28,6 +28,7 @@
# Copyright (c) 2017, Datto Inc. All rights reserved.
# Copyright (c) 2017, Open-E Inc. All rights reserved.
# Copyright (c) 2021, The FreeBSD Foundation.
# Copyright (c) 2025, Klara, Inc.
# Use is subject to license terms.
#
@ -37,6 +38,7 @@
. ${STF_SUITE}/include/math.shlib
. ${STF_SUITE}/include/blkdev.shlib
# On AlmaLinux 9 we will see $PWD = '.' instead of the full path. This causes
# some tests to fail. Fix it up here.
if [ "$PWD" = "." ] ; then
@ -3662,41 +3664,6 @@ function ls_xattr # path
esac
}
function kstat # stat flags?
{
typeset stat=$1
typeset flags=${2-"-n"}
case "$UNAME" in
FreeBSD)
sysctl $flags kstat.zfs.misc.$stat
;;
Linux)
cat "/proc/spl/kstat/zfs/$stat" 2>/dev/null
;;
*)
false
;;
esac
}
function get_arcstat # stat
{
typeset stat=$1
case "$UNAME" in
FreeBSD)
kstat arcstats.$stat
;;
Linux)
kstat arcstats | awk "/$stat/"' { print $3 }'
;;
*)
false
;;
esac
}
function punch_hole # offset length file
{
typeset offset=$1
@ -3748,9 +3715,9 @@ function arcstat_quiescence # stat echo
fi
while $do_once || [ $stat1 -ne $stat2 ] || [ $stat2 -eq 0 ]; do
typeset stat1=$(get_arcstat $stat)
typeset stat1=$(kstat arcstats.$stat)
sleep 0.5
typeset stat2=$(get_arcstat $stat)
typeset stat2=$(kstat arcstats.$stat)
do_once=false
done
@ -3916,3 +3883,5 @@ function pop_coredump_pattern
;;
esac
}
. ${STF_SUITE}/include/kstat.shlib

View file

@ -615,6 +615,8 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/cli_root/json/setup.ksh \
functional/cli_root/json/json_sanity.ksh \
functional/cli_root/zinject/zinject_args.ksh \
functional/cli_root/zinject/zinject_counts.ksh \
functional/cli_root/zinject/zinject_probe.ksh \
functional/cli_root/zdb/zdb_002_pos.ksh \
functional/cli_root/zdb/zdb_003_pos.ksh \
functional/cli_root/zdb/zdb_004_pos.ksh \

View file

@ -29,8 +29,8 @@
#
# DESCRIPTION:
# Ensure stats presented in /proc/spl/kstat/zfs/dbufstats are correct
# based on /proc/spl/kstat/zfs/dbufs.
# Ensure stats presented in the dbufstats kstat are correct based on the
# dbufs kstat.
#
# STRATEGY:
# 1. Generate a file with random data in it
@ -55,12 +55,7 @@ function testdbufstat # stat_name dbufstat_filter
[[ -n "$2" ]] && filter="-F $2"
if is_linux; then
read -r _ _ from_dbufstat _ < <(grep -w "$name" "$DBUFSTATS_FILE")
else
from_dbufstat=$(awk "/dbufstats\.$name:/ { print \$2 }" \
"$DBUFSTATS_FILE")
fi
from_dbufstat=$(grep "^$name " "$DBUFSTATS_FILE" | cut -f2 -d' ')
from_dbufs=$(dbufstat -bxn -i "$DBUFS_FILE" "$filter" | wc -l)
within_tolerance $from_dbufstat $from_dbufs 15 \
@ -77,7 +72,7 @@ log_must file_write -o create -f "$TESTDIR/file" -b 1048576 -c 20 -d R
sync_all_pools
log_must eval "kstat dbufs > $DBUFS_FILE"
log_must eval "kstat dbufstats '' > $DBUFSTATS_FILE"
log_must eval "kstat -g dbufstats > $DBUFSTATS_FILE"
for level in {0..11}; do
testdbufstat "cache_level_$level" "dbc=1,level=$level"

View file

@ -96,9 +96,9 @@ export RUNTIME=1
typeset do_once=true
while $do_once || [[ $l2_size1 -le $l2_size2 ]]; do
typeset l2_size1=$(get_arcstat l2_size)
typeset l2_size1=$(kstat arcstats.l2_size)
log_must fio $FIO_SCRIPTS/random_reads.fio
typeset l2_size2=$(get_arcstat l2_size)
typeset l2_size2=$(kstat arcstats.l2_size)
do_once=false
done

View file

@ -31,10 +31,9 @@
# 7. Run zdb -dddddd pool/objsetID objectID (hex)
# 8. Confirm names
# 9. Repeat with zdb -NNNNNN pool/objsetID objectID
# 10. Obtain objsetID from /proc/spl/kstat/zfs/testpool/obset-0x<ID>
# (linux only)
# 10. Obtain dataset name from testpool.objset-0x<objsetID>.dataset_name kstat
# 11. Run zdb -dddddd pool/objsetID (hex)
# 12. Match name from zdb against proc entry
# 12. Match name from zdb against kstat
# 13. Create dataset with hex numeric name
# 14. Create dataset with decimal numeric name
# 15. zdb -d for numeric datasets succeeds
@ -68,7 +67,7 @@ log_note "file $init_data has object number $obj"
sync_pool $TESTPOOL
IFS=", " read -r _ _ _ _ objset_id _ < <(zdb -d $TESTPOOL/$TESTFS)
objset_hex=$(printf "0x%X" $objset_id)
objset_hex=$(printf "0x%x" $objset_id)
log_note "objset $TESTPOOL/$TESTFS has objset ID $objset_id ($objset_hex)"
for id in "$objset_id" "$objset_hex"
@ -89,13 +88,9 @@ do
log_fail "zdb -NNNNNN $TESTPOOL/$id $obj failed (file1 not in zdb output)"
done
if is_linux; then
output=$(ls -1 /proc/spl/kstat/zfs/$TESTPOOL | grep objset- | tail -1)
objset_hex=${output#*-}
name_from_proc=$(grep dataset_name /proc/spl/kstat/zfs/$TESTPOOL/$output | cut -d' ' -f3)
log_note "checking zdb output for $name_from_proc"
log_must eval "zdb -dddddd $TESTPOOL/$objset_hex | grep -q \"$name_from_proc\""
fi
name_from_proc=$(kstat_dataset -N $TESTPOOL/$objset_id dataset_name)
log_note "checking zdb output for $name_from_proc"
log_must eval "zdb -dddddd $TESTPOOL/$objset_hex | grep -q \"$name_from_proc\""
log_must zfs create $hex_ds
log_must zfs create $num_ds

View file

@ -0,0 +1,142 @@
#!/bin/ksh -p
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or https://opensource.org/licenses/CDDL-1.0.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright (c) 2025, Klara, Inc.
#
#
# This test sets various injections, does some IO to trigger them. and then
# checks the "match" and "inject" counters on the injection records to ensure
# that they're being counted properly.
#
# Note that this is a test of the counters, not injection generally. We're
# usually only looking for the counters moving at all, not caring too much
# about their actual values.
. $STF_SUITE/include/libtest.shlib
verify_runnable "global"
log_assert "Check zinject counts are displayed and advanced as expected."
DISK1=${DISKS%% *}
function cleanup
{
zinject -c all
default_cleanup_noexit
}
log_onexit cleanup
default_mirror_setup_noexit $DISKS
# Call zinject, get the match and inject counts, and make sure they look
# plausible for the requested frequency.
function check_count_freq
{
typeset -i freq=$1
# assuming a single rule, with the match and inject counts in the
# last two columns
typeset rule=$(zinject | grep -m 1 -oE '^ *[0-9].*[0-9]$')
log_note "check_count_freq: using rule: $rule"
typeset -a record=($(echo $rule | grep -oE ' [0-9]+ +[0-9]+$'))
typeset -i match=${record[0]}
typeset -i inject=${record[1]}
log_note "check_count_freq: freq=$freq match=$match inject=$inject"
# equality check, for 100% frequency, or if we've never matched the rule
if [[ $match -eq 0 || $freq -eq 100 ]] ; then
return [[ $match -eq 0 $inject ]]
fi
# Compute the expected injection count, and compare. Because we're
# not testing the fine details here, it's considered good-enough for
# the injection account to be within +/- 10% of the expected count.
typeset -i expect=$(($match * $freq / 100))
typeset -i diff=$((($expect - $inject) / 10))
return [[ $diff -ge -1 && $diff -le 1 ]]
}
# Test device IO injections by injecting write errors, doing some writes,
# and making sure the count moved
function test_device_injection
{
for freq in 100 50 ; do
log_must zinject -d $DISK1 -e io -T write -f $freq $TESTPOOL
log_must dd if=/dev/urandom of=/$TESTPOOL/file bs=1M count=1
log_must zpool sync
log_must check_count_freq $freq
log_must zinject -c all
done
}
# Test object injections by writing a file, injecting checksum errors and
# trying to read it back
function test_object_injection
{
log_must dd if=/dev/urandom of=/$TESTPOOL/file bs=1M count=1
zpool sync
for freq in 100 50 ; do
log_must zinject -t data -e checksum -f $freq /$TESTPOOL/file
cat /tank/file > /dev/null || true
log_must check_count_freq $freq
log_must zinject -c all
done
}
# Test delay injections, by injecting delays and writing
function test_delay_injection
{
for freq in 100 50 ; do
log_must zinject -d $DISK1 -D 50:1 -f $freq $TESTPOOL
log_must dd if=/dev/urandom of=/$TESTPOOL/file bs=1M count=1
zpool sync
log_must check_count_freq $freq
log_must zinject -c all
done
}
# Disable cache, to ensure reads induce IO
log_must zfs set primarycache=none $TESTPOOL
# Test 'em all.
log_must test_device_injection
log_must test_object_injection
log_must test_delay_injection
log_pass "zinject counts are displayed and advanced as expected."

View file

@ -0,0 +1,75 @@
#!/bin/ksh -p
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or https://opensource.org/licenses/CDDL-1.0.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright (c) 2025, Klara, Inc.
#
. $STF_SUITE/include/libtest.shlib
verify_runnable "global"
log_assert "Check zinject can correctly inject a probe failure."
DISK1=${DISKS%% *}
function cleanup
{
log_pos zinject -c all
log_pos zpool clear $TESTPOOL
log_pos zpool destroy -f $TESTPOOL
log_pos restore_tunable TXG_TIMEOUT
}
log_onexit cleanup
log_must zpool create $TESTPOOL $DISK1
# set the txg timeout a long way out, to try and avoid the pool syncing
# between error injection and writing
save_tunable TXG_TIMEOUT
log_must set_tunable32 TXG_TIMEOUT 600
# force a sync now
log_must zpool sync -f
# write stuff. this should go into memory, not written yet
log_must dd if=/dev/urandom of=/$TESTPOOL/file bs=1M count=1
# inject faults
log_must zinject -d $DISK1 -e io -T probe $TESTPOOL
log_must zinject -d $DISK1 -e io -T write $TESTPOOL
# force the sync now. backgrounded, because the pool will suspend and we don't
# want to block.
log_pos zpool sync &
log_note "waiting for pool to suspend"
typeset -i tries=30
until [[ $(kstat_pool $TESTPOOL state) == "SUSPENDED" ]] ; do
if ((tries-- == 0)); then
log_fail "pool didn't suspend"
fi
sleep 1
done
log_pass "zinject can correctly inject a probe failure."

View file

@ -83,12 +83,12 @@ log_must truncate -s ${cache_sz}M $VDEV_CACHE
log_must zpool create -O compression=lz4 -f $TESTPOOL-l2arc $VDEV cache $VDEV_CACHE
l2_cksum_bad_start=$(get_arcstat l2_cksum_bad)
l2_cksum_bad_start=$(kstat arcstats.l2_cksum_bad)
log_must fio $FIO_SCRIPTS/mkfiles.fio
log_must fio $FIO_SCRIPTS/random_reads.fio
l2_cksum_bad_end=$(get_arcstat l2_cksum_bad)
l2_cksum_bad_end=$(kstat arcstats.l2_cksum_bad)
log_note "L2ARC Failed Checksums before: $l2_cksum_bad_start After:"\
"$l2_cksum_bad_end"

View file

@ -83,12 +83,12 @@ log_must truncate -s ${cache_sz}M $VDEV_CACHE
log_must zpool create -O compression=lz4 -f $TESTPOOL-l2arc $VDEV cache $VDEV_CACHE
l2_cksum_bad_start=$(get_arcstat l2_cksum_bad)
l2_cksum_bad_start=$(kstat arcstats.l2_cksum_bad)
log_must fio $FIO_SCRIPTS/mkfiles.fio
log_must fio $FIO_SCRIPTS/random_reads.fio
l2_cksum_bad_end=$(get_arcstat l2_cksum_bad)
l2_cksum_bad_end=$(kstat arcstats.l2_cksum_bad)
log_note "L2ARC Failed Checksums before: $l2_cksum_bad_start After:"\
"$l2_cksum_bad_end"

View file

@ -88,12 +88,12 @@ log_must eval "echo $PASSPHRASE | zfs create -o compression=zstd " \
"-o encryption=on -o keyformat=passphrase -o keylocation=prompt " \
"$TESTPOOL-l2arc/encrypted"
l2_cksum_bad_start=$(get_arcstat l2_cksum_bad)
l2_cksum_bad_start=$(kstat arcstats.l2_cksum_bad)
log_must fio $FIO_SCRIPTS/mkfiles.fio
log_must fio $FIO_SCRIPTS/random_reads.fio
l2_cksum_bad_end=$(get_arcstat l2_cksum_bad)
l2_cksum_bad_end=$(kstat arcstats.l2_cksum_bad)
log_note "L2ARC Failed Checksums before: $l2_cksum_bad_start After:"\
"$l2_cksum_bad_end"

View file

@ -88,12 +88,12 @@ log_must eval "echo $PASSPHRASE | zfs create -o compression=zstd " \
"-o encryption=on -o keyformat=passphrase -o keylocation=prompt " \
"$TESTPOOL-l2arc/encrypted"
l2_cksum_bad_start=$(get_arcstat l2_cksum_bad)
l2_cksum_bad_start=$(kstat arcstats.l2_cksum_bad)
log_must fio $FIO_SCRIPTS/mkfiles.fio
log_must fio $FIO_SCRIPTS/random_reads.fio
l2_cksum_bad_end=$(get_arcstat l2_cksum_bad)
l2_cksum_bad_end=$(kstat arcstats.l2_cksum_bad)
log_note "L2ARC Failed Checksums before: $l2_cksum_bad_start After:"\
"$l2_cksum_bad_end"

View file

@ -73,11 +73,7 @@ log_must zinject -c all
sync_all_pools
# Log txg sync times for reference and the zpool event summary.
if is_freebsd; then
log_must sysctl -n kstat.zfs.$TESTPOOL.txgs
else
log_must cat /proc/spl/kstat/zfs/$TESTPOOL/txgs
fi
log_must kstat_pool $TESTPOOL txgs
log_must zpool events
# Verify at least 3 deadman events were logged. The first after 5 seconds,

View file

@ -140,29 +140,6 @@ function check_dio_chksum_verify_failures # pool vdev_type op expect_errors
}
#
# Get the value of a counter from
# Linux: /proc/spl/kstat/zfs/$pool/iostats file.
# FreeBSD: kstat.zfs.$pool.msic.iostats.$stat
#
function get_iostats_stat # pool stat
{
typeset pool=$1
typeset stat=$2
if is_linux; then
iostats_file=/proc/spl/kstat/zfs/$pool/iostats
val=$(grep -m1 "$stat" $iostats_file | awk '{ print $3 }')
else
val=$(sysctl -n kstat.zfs.$pool.misc.iostats.$stat)
fi
if [[ -z "$val" ]]; then
log_fail "Unable to read $stat counter"
fi
echo "$val"
}
#
# Evict any buffered blocks by overwritting them using an O_DIRECT request.
#
@ -190,17 +167,13 @@ function verify_dio_write_count #pool bs size mnpnt
log_note "Checking for $dio_wr_expected Direct I/O writes"
prev_dio_wr=$(get_iostats_stat $pool direct_write_count)
prev_dio_wr=$(kstat_pool $pool iostats.direct_write_count)
dio_and_verify write $size $bs $mntpnt "sync"
curr_dio_wr=$(get_iostats_stat $pool direct_write_count)
curr_dio_wr=$(kstat_pool $pool iostats.direct_write_count)
dio_wr_actual=$((curr_dio_wr - prev_dio_wr))
if [[ $dio_wr_actual -lt $dio_wr_expected ]]; then
if is_linux; then
cat /proc/spl/kstat/zfs/$pool/iostats
else
sysctl kstat.zfs.$pool.misc.iostats
fi
kstat_pool -g $pool iostats
log_fail "Direct writes $dio_wr_actual of $dio_wr_expected"
fi
}
@ -223,33 +196,25 @@ function check_write # pool file bs count seek flags buf_wr dio_wr
log_note "Checking $count * $bs write(s) at offset $seek, $flags"
prev_buf_wr=$(get_iostats_stat $pool arc_write_count)
prev_dio_wr=$(get_iostats_stat $pool direct_write_count)
prev_buf_wr=$(kstat_pool $pool iostats.arc_write_count)
prev_dio_wr=$(kstat_pool $pool iostats.direct_write_count)
log_must stride_dd -i /dev/urandom -o $file -b $bs -c $count \
-k $seek $flags
curr_buf_wr=$(get_iostats_stat $pool arc_write_count)
curr_buf_wr=$(kstat_pool $pool iostats.arc_write_count)
buf_wr_actual=$((curr_buf_wr - prev_buf_wr))
curr_dio_wr=$(get_iostats_stat $pool direct_write_count)
curr_dio_wr=$(kstat_pool $pool iostats.direct_write_count)
dio_wr_actual=$((curr_dio_wr - prev_dio_wr))
if [[ $buf_wr_actual -lt $buf_wr_expect ]]; then
if is_linux; then
cat /proc/spl/kstat/zfs/$pool/iostats
else
sysctl kstat.zfs.$pool.misc.iostats
fi
kstat_pool -g $pool iostats
log_fail "Buffered writes $buf_wr_actual of $buf_wr_expect"
fi
if [[ $dio_wr_actual -lt $dio_wr_expect ]]; then
if is_linux; then
cat /proc/spl/kstat/zfs/$pool/iostats
else
sysctl kstat.zfs.$pool.misc.iostats
fi
kstat_pool -g $pool iostats
log_fail "Direct writes $dio_wr_actual of $dio_wr_expect"
fi
}
@ -272,33 +237,25 @@ function check_read # pool file bs count skip flags buf_rd dio_rd
log_note "Checking $count * $bs read(s) at offset $skip, $flags"
prev_buf_rd=$(get_iostats_stat $pool arc_read_count)
prev_dio_rd=$(get_iostats_stat $pool direct_read_count)
prev_buf_rd=$(kstat_pool $pool iostats.arc_read_count)
prev_dio_rd=$(kstat_pool $pool iostats.direct_read_count)
log_must stride_dd -i $file -o /dev/null -b $bs -c $count \
-p $skip $flags
curr_buf_rd=$(get_iostats_stat $pool arc_read_count)
curr_buf_rd=$(kstat_pool $pool iostats.arc_read_count)
buf_rd_actual=$((curr_buf_rd - prev_buf_rd))
curr_dio_rd=$(get_iostats_stat $pool direct_read_count)
curr_dio_rd=$(kstat_pool $pool iostats.direct_read_count)
dio_rd_actual=$((curr_dio_rd - prev_dio_rd))
if [[ $buf_rd_actual -lt $buf_rd_expect ]]; then
if is_linux; then
cat /proc/spl/kstat/zfs/$pool/iostats
else
sysctl kstat.zfs.$pool.misc.iostats
fi
kstat_pool -g $pool iostats
log_fail "Buffered reads $buf_rd_actual of $buf_rd_expect"
fi
if [[ $dio_rd_actual -lt $dio_rd_expect ]]; then
if is_linux; then
cat /proc/spl/kstat/zfs/$pool/iostats
else
sysctl kstat.zfs.$pool.misc.iostats
fi
kstat_pool -g $pool iostats
log_fail "Direct reads $dio_rd_actual of $dio_rd_expect"
fi
}

View file

@ -72,8 +72,8 @@ for type in "" "mirror" "raidz" "draid"; do
$TESTPOOL1/$TESTFS1"
mntpnt=$(get_prop mountpoint $TESTPOOL1/$TESTFS1)
prev_dio_rd=$(get_iostats_stat $TESTPOOL1 direct_read_count)
prev_arc_rd=$(get_iostats_stat $TESTPOOL1 arc_read_count)
prev_dio_rd=$(kstat_pool $TESTPOOL1 iostats.direct_read_count)
prev_arc_rd=$(kstat_pool $TESTPOOL1 iostats.arc_read_count)
# Create the file before trying to manipulate the contents
log_must stride_dd -o "$mntpnt/direct-write.iso" -i /dev/urandom \
@ -83,8 +83,8 @@ for type in "" "mirror" "raidz" "draid"; do
-n $NUMBLOCKS -b $BS -r
# Getting new Direct I/O and ARC Write counts.
curr_dio_rd=$(get_iostats_stat $TESTPOOL1 direct_read_count)
curr_arc_rd=$(get_iostats_stat $TESTPOOL1 arc_read_count)
curr_dio_rd=$(kstat_pool $TESTPOOL1 iostats.direct_read_count)
curr_arc_rd=$(kstat_pool $TESTPOOL1 iostats.arc_read_count)
total_dio_rd=$((curr_dio_rd - prev_dio_rd))
total_arc_rd=$((curr_arc_rd - prev_arc_rd))

View file

@ -73,11 +73,11 @@ log_must zpool export $TESTPOOL
log_must zpool import $TESTPOOL
# Reading the file back using Direct I/O
prev_dio_read=$(get_iostats_stat $TESTPOOL direct_read_count)
prev_arc_read=$(get_iostats_stat $TESTPOOL arc_read_count)
prev_dio_read=$(kstat_pool $TESTPOOL iostats.direct_read_count)
prev_arc_read=$(kstat_pool $TESTPOOL iostats.arc_read_count)
log_must stride_dd -i $filename -o /dev/null -b $bs -e -d
curr_dio_read=$(get_iostats_stat $TESTPOOL direct_read_count)
curr_arc_read=$(get_iostats_stat $TESTPOOL arc_read_count)
curr_dio_read=$(kstat_pool $TESTPOOL iostats.direct_read_count)
curr_arc_read=$(kstat_pool $TESTPOOL iostats.arc_read_count)
total_dio_read=$((curr_dio_read - prev_dio_read))
total_arc_read=$((curr_arc_read - prev_arc_read))

View file

@ -72,7 +72,7 @@ do
log_note "Verifying stable pages for Direct I/O writes \
iteration $i of $ITERATIONS"
prev_dio_wr=$(get_iostats_stat $TESTPOOL direct_write_count)
prev_dio_wr=$(kstat_pool $TESTPOOL iostats.direct_write_count)
# Manipulate the user's buffer while running O_DIRECT write
# workload with the buffer.
@ -83,7 +83,7 @@ do
log_must stride_dd -i $mntpnt/direct-write.iso -o /dev/null \
-b $BS -c $NUMBLOCKS
curr_dio_wr=$(get_iostats_stat $TESTPOOL direct_write_count)
curr_dio_wr=$(kstat_pool $TESTPOOL iostats.direct_write_count)
total_dio_wr=$((curr_dio_wr - prev_dio_wr))
log_note "Making sure we have Direct I/O writes logged"

View file

@ -90,10 +90,10 @@ log_must set_tunable32 VDEV_DIRECT_WR_VERIFY 0
# failures
log_note "Verifying no panics for Direct I/O writes with compression"
log_must zfs set compression=on $TESTPOOL/$TESTFS
prev_dio_wr=$(get_iostats_stat $TESTPOOL direct_write_count)
prev_dio_wr=$(kstat_pool $TESTPOOL iostats.direct_write_count)
log_must manipulate_user_buffer -f "$mntpnt/direct-write.iso" -n $NUMBLOCKS \
-b $BS -w
curr_dio_wr=$(get_iostats_stat $TESTPOOL direct_write_count)
curr_dio_wr=$(kstat_pool $TESTPOOL iostats.direct_write_count)
total_dio_wr=$((curr_dio_wr - prev_dio_wr))
log_note "Making sure we have Direct I/O writes logged"
@ -115,7 +115,7 @@ for i in $(seq 1 $ITERATIONS); do
log_note "Verifying Direct I/O write checksums iteration \
$i of $ITERATIONS with zfs_vdev_direct_write_verify=0"
prev_dio_wr=$(get_iostats_stat $TESTPOOL direct_write_count)
prev_dio_wr=$(kstat_pool $TESTPOOL iostats.direct_write_count)
log_must manipulate_user_buffer -f "$mntpnt/direct-write.iso" \
-n $NUMBLOCKS -b $BS -w
@ -126,7 +126,7 @@ for i in $(seq 1 $ITERATIONS); do
-c $num_blocks
# Getting new Direct I/O and ARC write counts.
curr_dio_wr=$(get_iostats_stat $TESTPOOL direct_write_count)
curr_dio_wr=$(kstat_pool $TESTPOOL iostats.direct_write_count)
total_dio_wr=$((curr_dio_wr - prev_dio_wr))
# Verifying there are checksum errors
@ -165,7 +165,7 @@ for i in $(seq 1 $ITERATIONS); do
log_note "Verifying every Direct I/O write checksums iteration $i of \
$ITERATIONS with zfs_vdev_direct_write_verify=1"
prev_dio_wr=$(get_iostats_stat $TESTPOOL direct_write_count)
prev_dio_wr=$(kstat_pool $TESTPOOL iostats.direct_write_count)
log_must manipulate_user_buffer -f "$mntpnt/direct-write.iso" \
-n $NUMBLOCKS -b $BS -e -w
@ -176,7 +176,7 @@ for i in $(seq 1 $ITERATIONS); do
-c $num_blocks
# Getting new Direct I/O write counts.
curr_dio_wr=$(get_iostats_stat $TESTPOOL direct_write_count)
curr_dio_wr=$(kstat_pool $TESTPOOL iostats.direct_write_count)
total_dio_wr=$((curr_dio_wr - prev_dio_wr))
log_note "Making sure there are no checksum errors with the ZPool"

View file

@ -54,10 +54,6 @@ function cleanup
[[ -e $TESTDIR ]] && log_must rm -Rf $TESTDIR/*
}
getstat() {
awk -v c="$1" '$1 == c {print $3; exit}' /proc/spl/kstat/zfs/arcstats
}
log_assert "Ensure fadvise prefetch data"
log_onexit cleanup
@ -67,12 +63,12 @@ log_must zfs set primarycache=metadata $TESTPOOL
log_must file_write -o create -f $FILE -b $BLKSZ -c 1000
sync_pool $TESTPOOL
data_size1=$(getstat data_size)
data_size1=$(kstat arcstats.data_size)
log_must file_fadvise -f $FILE -a 2
sleep 10
data_size2=$(getstat data_size)
data_size2=$(kstat arcstats.data_size)
log_note "original data_size is $data_size1, final data_size is $data_size2"
log_must [ $data_size1 -le $data_size2 ]

View file

@ -119,14 +119,14 @@ log_must dd if=/dev/urandom of=$MNTPOINT/writes bs=1M count=1
# Wait until sync starts, and the pool suspends
log_note "waiting for pool to suspend"
typeset -i tries=30
until [[ $(cat /proc/spl/kstat/zfs/$TESTPOOL/state) == "SUSPENDED" ]] ; do
until [[ $(kstat_pool $TESTPOOL state) == "SUSPENDED" ]] ; do
if ((tries-- == 0)); then
zpool status -s
log_fail "UNEXPECTED -- pool did not suspend"
fi
sleep 1
done
log_note $(cat /proc/spl/kstat/zfs/$TESTPOOL/state)
log_note $(kstat_pool $TESTPOOL state)
# Put the missing disks back into service
log_must eval "echo running > /sys/block/$sd/device/state"
@ -137,7 +137,7 @@ log_must zpool clear $TESTPOOL
# Wait until the pool resumes
log_note "waiting for pool to resume"
tries=30
until [[ $(cat /proc/spl/kstat/zfs/$TESTPOOL/state) != "SUSPENDED" ]] ; do
until [[ $(kstat_pool $TESTPOOL state) != "SUSPENDED" ]] ; do
if ((tries-- == 0)); then
log_fail "pool did not resume"
fi

View file

@ -26,8 +26,6 @@
. $STF_SUITE/include/libtest.shlib
set -x
DATAFILE="$TMPDIR/datafile"
function cleanup
@ -62,7 +60,7 @@ log_must cp $DATAFILE /$TESTPOOL/file
# wait until sync starts, and the pool suspends
log_note "waiting for pool to suspend"
typeset -i tries=10
until [[ $(cat /proc/spl/kstat/zfs/$TESTPOOL/state) == "SUSPENDED" ]] ; do
until [[ $(kstat_pool $TESTPOOL state) == "SUSPENDED" ]] ; do
if ((tries-- == 0)); then
log_fail "pool didn't suspend"
fi
@ -82,7 +80,7 @@ log_note "giving pool time to settle and complete txg"
sleep 7
# if the pool suspended, then everything is bad
if [[ $(cat /proc/spl/kstat/zfs/$TESTPOOL/state) == "SUSPENDED" ]] ; then
if [[ $(kstat_pool $TESTPOOL state) == "SUSPENDED" ]] ; then
log_fail "pool suspended"
fi

View file

@ -73,18 +73,18 @@ arcstat_quiescence_noecho l2_size
log_must zpool offline $TESTPOOL $VDEV_CACHE
arcstat_quiescence_noecho l2_size
typeset l2_mfu_init=$(get_arcstat l2_mfu_asize)
typeset l2_mru_init=$(get_arcstat l2_mru_asize)
typeset l2_prefetch_init=$(get_arcstat l2_prefetch_asize)
typeset l2_asize_init=$(get_arcstat l2_asize)
typeset l2_mfu_init=$(kstat arcstats.l2_mfu_asize)
typeset l2_mru_init=$(kstat arcstats.l2_mru_asize)
typeset l2_prefetch_init=$(kstat arcstats.l2_prefetch_asize)
typeset l2_asize_init=$(kstat arcstats.l2_asize)
log_must zpool online $TESTPOOL $VDEV_CACHE
arcstat_quiescence_noecho l2_size
log_must zpool export $TESTPOOL
arcstat_quiescence_noecho l2_feeds
log_must test $(get_arcstat l2_mfu_asize) -eq 0
log_must test $(get_arcstat l2_mru_asize) -eq 0
log_must test $(kstat arcstats.l2_mfu_asize) -eq 0
log_must test $(kstat arcstats.l2_mru_asize) -eq 0
log_must zpool import -d $VDIR $TESTPOOL
arcstat_quiescence_noecho l2_size
@ -93,10 +93,10 @@ arcstat_quiescence_noecho l2_size
log_must zpool offline $TESTPOOL $VDEV_CACHE
arcstat_quiescence_noecho l2_size
typeset l2_mfu_end=$(get_arcstat l2_mfu_asize)
typeset l2_mru_end=$(get_arcstat l2_mru_asize)
typeset l2_prefetch_end=$(get_arcstat l2_prefetch_asize)
typeset l2_asize_end=$(get_arcstat l2_asize)
typeset l2_mfu_end=$(kstat arcstats.l2_mfu_asize)
typeset l2_mru_end=$(kstat arcstats.l2_mru_asize)
typeset l2_prefetch_end=$(kstat arcstats.l2_prefetch_asize)
typeset l2_asize_end=$(kstat arcstats.l2_asize)
log_must test $(( $l2_mru_end + $l2_mfu_end + $l2_prefetch_end - \
$l2_asize_end )) -eq 0

View file

@ -71,10 +71,10 @@ log_must fio $FIO_SCRIPTS/random_reads.fio
log_must zpool export $TESTPOOL1
log_must zpool import $TESTPOOL1 -d $VDEV1
typeset starting_miss_count=$(get_arcstat l2_misses)
typeset starting_miss_count=$(kstat arcstats.l2_misses)
log_must fio $FIO_SCRIPTS/random_reads.fio
log_must test $(get_arcstat l2_misses) -eq $starting_miss_count
log_must test $(kstat arcstats.l2_misses) -eq $starting_miss_count
# I/O to pool with l2arc - expect that l2_misses rises
export DIRECTORY=/$TESTPOOL
@ -88,7 +88,7 @@ log_must zpool export $TESTPOOL
log_must zpool import $TESTPOOL -d $VDEV
log_must fio $FIO_SCRIPTS/random_reads.fio
log_must test $(get_arcstat l2_misses) -gt $starting_miss_count
log_must test $(kstat arcstats.l2_misses) -gt $starting_miss_count
log_must zpool destroy -f $TESTPOOL
log_must zpool destroy -f $TESTPOOL1

View file

@ -72,7 +72,7 @@ export FILE_SIZE=$(( floor($fill_mb / $NUMJOBS) ))M
log_must truncate -s ${cache_sz}M $VDEV_CACHE
typeset log_blk_start=$(get_arcstat l2_log_blk_writes)
typeset log_blk_start=$(kstat arcstats.l2_log_blk_writes)
log_must zpool create -f $TESTPOOL $VDEV cache $VDEV_CACHE
@ -89,7 +89,7 @@ log_must zpool import -N -d $VDIR $TESTPOOL
# will not be 0 (mentioned also in zfs.4)
# For the purposes of this test we mitigate this by disabling (predictive)
# ZFS prefetches with zfs_prefetch_disable=1.
log_must test $(get_arcstat l2_mru_asize) -eq 0
log_must test $(kstat arcstats.l2_mru_asize) -eq 0
log_must zpool destroy -f $TESTPOOL

View file

@ -88,7 +88,7 @@ arcstat_quiescence_noecho l2_feeds
typeset l2_dh_log_blk=$(zdb -l $VDEV_CACHE | awk '/log_blk_count/ {print $2}')
typeset l2_rebuild_log_blk_start=$(get_arcstat l2_rebuild_log_blks)
typeset l2_rebuild_log_blk_start=$(kstat arcstats.l2_rebuild_log_blks)
log_must zpool import -d $VDIR $TESTPOOL
arcstat_quiescence_noecho l2_size

View file

@ -94,7 +94,7 @@ arcstat_quiescence_noecho l2_feeds
typeset l2_dh_log_blk=$(zdb -l $VDEV_CACHE | awk '/log_blk_count/ {print $2}')
typeset l2_rebuild_log_blk_start=$(get_arcstat l2_rebuild_log_blks)
typeset l2_rebuild_log_blk_start=$(kstat arcstats.l2_rebuild_log_blks)
log_must zpool import -d $VDIR $TESTPOOL
log_must eval "echo $PASSPHRASE | zfs mount -l $TESTPOOL/$TESTFS1"

View file

@ -32,8 +32,7 @@
# 4. Export pool.
# 5. Import pool.
# 6. Check in zpool iostat if the cache device has space allocated.
# 7. Read the file written in (3) and check if l2_hits in
# /proc/spl/kstat/zfs/arcstats increased.
# 7. Read the file written in (3) and check if arcstats.l2_hits increased.
#
verify_runnable "global"
@ -74,12 +73,12 @@ log_must fio $FIO_SCRIPTS/random_reads.fio
log_must zpool export $TESTPOOL
typeset l2_success_start=$(get_arcstat l2_rebuild_success)
typeset l2_success_start=$(kstat arcstats.l2_rebuild_success)
log_must zpool import -d $VDIR $TESTPOOL
log_mustnot test "$(zpool iostat -Hpv $TESTPOOL $VDEV_CACHE | awk '{print $2}')" -gt 80000000
typeset l2_success_end=$(get_arcstat l2_rebuild_success)
typeset l2_success_end=$(kstat arcstats.l2_rebuild_success)
log_mustnot test $l2_success_end -gt $l2_success_start

View file

@ -79,7 +79,7 @@ arcstat_quiescence_noecho l2_size
log_must zpool export $TESTPOOL
arcstat_quiescence_noecho l2_feeds
typeset l2_rebuild_log_blk_start=$(get_arcstat l2_rebuild_log_blks)
typeset l2_rebuild_log_blk_start=$(kstat arcstats.l2_rebuild_log_blks)
typeset l2_dh_log_blk=$(zdb -l $VDEV_CACHE | awk '/log_blk_count/ {print $2}')
log_must zpool import -d $VDIR $TESTPOOL

View file

@ -76,7 +76,7 @@ arcstat_quiescence_noecho l2_size
log_must zpool offline $TESTPOOL $VDEV_CACHE
arcstat_quiescence_noecho l2_size
typeset l2_rebuild_log_blk_start=$(get_arcstat l2_rebuild_log_blks)
typeset l2_rebuild_log_blk_start=$(kstat arcstats.l2_rebuild_log_blks)
typeset l2_dh_log_blk=$(zdb -l $VDEV_CACHE | awk '/log_blk_count/ {print $2}')
log_must zpool online $TESTPOOL $VDEV_CACHE

View file

@ -199,20 +199,20 @@ function count_skipped_mmp_writes # pool duration
{
typeset pool=$1
typeset -i duration=$2
typeset hist_path="/proc/spl/kstat/zfs/$pool/multihost"
sleep $duration
awk 'BEGIN {count=0}; $NF == "-" {count++}; END {print count};' "$hist_path"
kstat_pool $pool multihost | \
awk 'BEGIN {count=0}; $NF == "-" {count++}; END {print count};'
}
function count_mmp_writes # pool duration
{
typeset pool=$1
typeset -i duration=$2
typeset hist_path="/proc/spl/kstat/zfs/$pool/multihost"
sleep $duration
awk 'BEGIN {count=0}; $NF != "-" {count++}; END {print count};' "$hist_path"
kstat_pool $pool multihost | \
awk 'BEGIN {count=0}; $NF != "-" {count++}; END {print count};'
}
function summarize_uberblock_mmp # device

View file

@ -47,7 +47,6 @@ log_assert "mmp writes are evenly distributed across leaf vdevs"
log_onexit cleanup
MMP_HISTORY_TMP=$MMP_DIR/history
MMP_HISTORY=/proc/spl/kstat/zfs/$MMP_POOL/multihost
# Step 1
log_must mkdir -p $MMP_DIR
@ -69,7 +68,7 @@ typeset -i min_writes=999
typeset -i max_writes=0
typeset -i write_count
# copy to get as close to a consistent view as possible
cp $MMP_HISTORY $MMP_HISTORY_TMP
kstat_pool $MMP_POOL multihost > $MMP_HISTORY_TMP
for x in {0..7}; do
write_count=$(grep -c file.${x} $MMP_HISTORY_TMP)
if [ $write_count -lt $min_writes ]; then

View file

@ -58,7 +58,7 @@ function cleanup
log_assert "A long VDEV probe doesn't cause a MMP check suspend"
log_onexit cleanup
MMP_HISTORY_URL=/proc/spl/kstat/zfs/$MMP_POOL/multihost
MMP_HISTORY_TMP=$MMP_DIR/history
# Create a multiple drive pool
log_must zpool events -c
@ -83,8 +83,9 @@ sleep 10
sync_pool $MMP_POOL
# Confirm mmp writes to the non-slow disks have taken place
kstat_pool $MMP_POOL multihost > $MMP_HISTORY_TMP
for x in {0,1,2,4}; do
write_count=$(grep -c file.${x} $MMP_HISTORY_URL)
write_count=$(grep -c file.${x} $MMP_HISTORY_TMP)
[[ $write_count -gt 0 ]] || log_fail "expecting mmp writes"
done

View file

@ -42,13 +42,15 @@ function cleanup
function unlinked_size_is
{
typeset -i expect=$1
typeset dataset=$2
MAX_ITERS=5 # iteration to do before we consider reported number stable
iters=0
last_usize=0
while [[ $iters -le $MAX_ITERS ]]; do
kstat_file=$(grep -nrwl /proc/spl/kstat/zfs/$2/objset-0x* -e $3)
nunlinks=$(awk '/nunlinks/ {print $3}' $kstat_file)
nunlinked=$(awk '/nunlinked/ {print $3}' $kstat_file)
nunlinks=$(kstat_dataset $dataset nunlinks)
nunlinked=$(kstat_dataset $dataset nunlinked)
usize=$(($nunlinks - $nunlinked))
if [[ $iters == $MAX_ITERS && $usize == $1 ]]; then
return 0
@ -89,20 +91,20 @@ for fs in 1 2 3; do
fi
log_must set_tunable32 UNLINK_SUSPEND_PROGRESS 1
log_must unlinked_size_is 0 $TESTPOOL $TESTPOOL/$TESTFS.$fs
log_must unlinked_size_is 0 $TESTPOOL/$TESTFS.$fs
# build up unlinked set
for fn in $(seq 1 100); do
log_must eval "rm $TESTDIR.$fs/file-$fn &"
done
log_must unlinked_size_is 100 $TESTPOOL $TESTPOOL/$TESTFS.$fs
log_must unlinked_size_is 100 $TESTPOOL/$TESTFS.$fs
# test that we can mount fs without emptying the unlinked list
log_must zfs umount $TESTPOOL/$TESTFS.$fs
log_must unmounted $TESTDIR.$fs
log_must zfs mount $TESTPOOL/$TESTFS.$fs
log_must mounted $TESTDIR.$fs
log_must unlinked_size_is 100 $TESTPOOL $TESTPOOL/$TESTFS.$fs
log_must unlinked_size_is 100 $TESTPOOL/$TESTFS.$fs
# confirm we can drain and add to unlinked set at the same time
log_must set_tunable32 UNLINK_SUSPEND_PROGRESS 0
@ -111,7 +113,7 @@ for fs in 1 2 3; do
for fn in $(seq 101 175); do
log_must eval "rm $TESTDIR.$fs/file-$fn &"
done
log_must unlinked_size_is 0 $TESTPOOL $TESTPOOL/$TESTFS.$fs
log_must unlinked_size_is 0 $TESTPOOL/$TESTFS.$fs
done
done

View file

@ -89,9 +89,9 @@ log_must fio $FIO_SCRIPTS/random_reads.fio
export RUNTIME=1
typeset do_once=true
while $do_once || [[ $l2_size1 -le $l2_size2 ]]; do
typeset l2_size1=$(get_arcstat l2_size)
typeset l2_size1=$(kstat arcstats.l2_size)
log_must fio $FIO_SCRIPTS/random_reads.fio
typeset l2_size2=$(get_arcstat l2_size)
typeset l2_size2=$(kstat arcstats.l2_size)
do_once=false
done

View file

@ -787,7 +787,7 @@
/* #undef ZFS_DEVICE_MINOR */
/* Define the project alias string. */
#define ZFS_META_ALIAS "zfs-2.3.99-158-FreeBSD_gfae4c664a"
#define ZFS_META_ALIAS "zfs-2.3.99-170-FreeBSD_g34205715e"
/* Define the project author. */
#define ZFS_META_AUTHOR "OpenZFS"
@ -817,7 +817,7 @@
#define ZFS_META_NAME "zfs"
/* Define the project release. */
#define ZFS_META_RELEASE "158-FreeBSD_gfae4c664a"
#define ZFS_META_RELEASE "170-FreeBSD_g34205715e"
/* Define the project version. */
#define ZFS_META_VERSION "2.3.99"

View file

@ -1 +1 @@
#define ZFS_META_GITREV "zfs-2.3.99-158-gfae4c664a"
#define ZFS_META_GITREV "zfs-2.3.99-170-g34205715e"