mirror of
https://github.com/opnsense/src.git
synced 2026-06-09 00:32:25 -04:00
zfs: merge openzfs/zfs@34205715e
Notable upstream pull request merges: #169382aa3fbe76zinject: count matches and injections for each handler #16947 -multiple zinject: add "probe" device injection type #1697634205715eFreeBSD: Add setting of the VFCF_FILEREV flag Obtained from: OpenZFS OpenZFS commit:34205715e1
This commit is contained in:
commit
c6767dc1f2
53 changed files with 1061 additions and 302 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 "
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
.
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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']
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
516
sys/contrib/openzfs/tests/zfs-tests/include/kstat.shlib
Normal file
516
sys/contrib/openzfs/tests/zfs-tests/include/kstat.shlib
Normal 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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
|
|
@ -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."
|
||||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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 ]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
#define ZFS_META_GITREV "zfs-2.3.99-158-gfae4c664a"
|
||||
#define ZFS_META_GITREV "zfs-2.3.99-170-g34205715e"
|
||||
|
|
|
|||
Loading…
Reference in a new issue