Notable upstream pull request merges:
 #17864 e903655c5 zpool: Add zpool status -vv error ranges
 #18820 -multiple zdb: account pending DDT-log frees in leak detection
 #18884 -multiple zio_crypt: establish platform interface; rework common
                  code to use it
 #19010 -multiple zfs_namecheck: reject '.' and '..' before a snapshot or
                  bookmark
 #19031 994fb1703 Fix metaslab count assertion in metaslab_group_alloc()
                  for small vdevs
 #19093 f5b2fc8e2 zfs_ctldir: make .zfs/snapshot/<name> btime the snapshot
                  creation time
 #19097 2dece2a34 zstream: report invalid record context without assertions
 #19102 78f49e1dd vdev_disk: simplify alignment checks for linear ABDs
 #19108 -multiple Fix permanent errors misfiled into the scrub error log
 #19110 fa4bc4dec spa_errlog: don't let one unresolvable entry hide the
                  whole error log
 #19116 b6dde8a17 zio_crypt: free the key unwrap uios when decryption fails
 #19122 -multiple Fix dd_lock contention on space accounting
 #19126 c792317f2 Avoid dp_lock in the dirty space accounting
 #19131 7fd87803e Make the spa_config_lock reader fast path lockless
 #19137 a83d96835 libzfs: do not iterate snapshots for a mountpoint
                  changelist
 #19152 ccce78729 ZIO: Order a batch arrival against the hold it releases
 #19155 9d7260c9b Propagate vdev state change on probe failure
 #19157 946be3a33 FreeBSD: remove legacy ioctl support
 #19165 1d9c32c16 zpool: accept more redundant special and dedup vdevs
 #19167 638abd22a zfs_domount: fix vfs_t double-free on root setup failure

Obtained from:	OpenZFS
OpenZFS commit:	1f380a4f34
This commit is contained in:
Martin Matuska committed 2026-09-29 09:25:39 +02:00
commit 34f9f5680c
237 files changed
+6119 -5813

No files matched your search

+1 -2
View File
@@ -11,8 +11,7 @@ LIBADD= nvpair spl zutil
INCS= libzfs_core.h
SRCS= libzfs_core.c \
os/freebsd/libzfs_core_ioctl.c \
zfs_ioctl_compat.c
os/freebsd/libzfs_core_ioctl.c
WARNS?= 2
CSTD= c99
+1
View File
@@ -192,6 +192,7 @@ KERNEL_C = \
zio_checksum.c \
zio_compress.c \
zio_crypt.c \
zio_crypt_os_icp.c \
zio_inject.c \
zle.c \
zrlock.c \
-3
View File
@@ -21,9 +21,6 @@ SRCS += \
os/freebsd/zutil_device_path_os.c \
os/freebsd/zutil_import_os.c
SRCS += zfs_ioctl_compat.c
WARNS?= 2
CSTD= c99
+1 -1
View File
@@ -12,7 +12,7 @@ SRCS= \
zstream_byteswap.c \
zstream_chain.c \
zstream_decompress.c \
zstream_drop_record.c \
zstream_drop_records.c \
zstream_dump.c \
zstream_fletcher4.c \
zstream_io.c \
+2 -2
View File
@@ -214,13 +214,12 @@ contrib/openzfs/module/os/freebsd/zfs/zfs_ctldir.c optional zfs compile-with "$
contrib/openzfs/module/os/freebsd/zfs/zfs_debug.c optional zfs compile-with "${ZFS_C}"
contrib/openzfs/module/os/freebsd/zfs/zfs_dir.c optional zfs compile-with "${ZFS_C}"
contrib/openzfs/module/os/freebsd/zfs/zfs_file_os.c optional zfs compile-with "${ZFS_C}"
contrib/openzfs/module/os/freebsd/zfs/zfs_ioctl_compat.c optional zfs compile-with "${ZFS_C}"
contrib/openzfs/module/os/freebsd/zfs/zfs_ioctl_os.c optional zfs compile-with "${ZFS_C}"
contrib/openzfs/module/os/freebsd/zfs/zfs_racct.c optional zfs compile-with "${ZFS_C}"
contrib/openzfs/module/os/freebsd/zfs/zfs_vfsops.c optional zfs compile-with "${ZFS_C}"
contrib/openzfs/module/os/freebsd/zfs/zfs_vnops_os.c optional zfs compile-with "${ZFS_C}"
contrib/openzfs/module/os/freebsd/zfs/zfs_znode_os.c optional zfs compile-with "${ZFS_C}"
contrib/openzfs/module/os/freebsd/zfs/zio_crypt.c optional zfs compile-with "${ZFS_C}"
contrib/openzfs/module/os/freebsd/zfs/zio_crypt_os.c optional zfs compile-with "${ZFS_C}"
contrib/openzfs/module/os/freebsd/zfs/zvol_os.c optional zfs compile-with "${ZFS_C}"
#zfs checksums / zcommon
@@ -378,6 +377,7 @@ contrib/openzfs/module/zfs/zil.c optional zfs compile-with "${ZFS_C}"
contrib/openzfs/module/zfs/zio.c optional zfs compile-with "${ZFS_C}"
contrib/openzfs/module/zfs/zio_checksum.c optional zfs compile-with "${ZFS_C}"
contrib/openzfs/module/zfs/zio_compress.c optional zfs compile-with "${ZFS_C}"
contrib/openzfs/module/zfs/zio_crypt.c optional zfs compile-with "${ZFS_C}"
contrib/openzfs/module/zfs/zio_inject.c optional zfs compile-with "${ZFS_C}"
contrib/openzfs/module/zfs/zle.c optional zfs compile-with "${ZFS_C}"
contrib/openzfs/module/zfs/zrlock.c optional zfs compile-with "${ZFS_C}"
@@ -304,10 +304,12 @@ fi
sudo virsh net-update default add ip-dhcp-host \
"<host mac='52:54:00:83:79:00' ip='192.168.122.10'/>" --live --config
# 2026-09-20: -amx-tile works around objtool vs musl SIGSTKSZ on AMX
# hosts. Removable once a fixed objtool reaches the distro images.
sudo virt-install \
--os-variant $OSv \
--name "openzfs" \
--cpu host-passthrough \
--cpu host-passthrough,-amx-tile \
--virt-type=kvm --hvm \
--vcpus=4,sockets=1 \
--memory $((1024*12)) \
@@ -17,11 +17,11 @@ function alpine() {
echo "##[group]Install Development Tools"
sudo apk add \
acl alpine-sdk attr autoconf automake bash build-base clang22 coreutils \
cpio cryptsetup curl curl-dev dhcpcd eudev eudev-dev eudev-libs findutils \
fio gawk gdb gettext-dev git grep jq libaio libaio-dev libcap-utils \
libcurl libtirpc-dev libtool libunwind libunwind-dev linux-headers \
linux-tools linux-stable linux-stable-dev lsscsi m4 make nfs-utils \
openssl-dev parted pax procps py3-cffi py3-distlib py3-packaging \
cpio cryptsetup curl curl-dev dhcpcd diffutils eudev eudev-dev eudev-libs \
findutils fio gawk gdb gettext-dev git grep jq libaio libaio-dev \
libcap-utils libcurl libtirpc-dev libtool libunwind libunwind-dev \
linux-headers linux-tools linux-stable linux-stable-dev lsscsi m4 make \
nfs-utils openssl-dev parted pax procps py3-cffi py3-distlib py3-packaging \
py3-setuptools python3 python3-dev qemu-guest-agent rng-tools rsync samba \
samba-server sed strace sysstat tzdata util-linux util-linux-dev wget \
words xfsprogs xxhash zlib-dev pamtester@testing
@@ -281,6 +281,7 @@ case "$1" in
sudo -E rc-update add samba
sudo -E rc-update add dhcpcd
# Remove services related to cloud-init.
sudo -E rc-update del cloud-init-local boot
sudo -E rc-update del cloud-init default
sudo -E rc-update del cloud-final default
sudo -E rc-update del cloud-config default
+1 -1
View File
@@ -60,7 +60,7 @@ jobs:
;;
*)
# default list
os_selection='["almalinux8", "almalinux9", "almalinux10", "centos-stream9", "centos-stream10", "debian12", "debian13", "fedora43", "fedora44", "freebsd14-4r", "freebsd15-1r", "freebsd15-1s", "freebsd16-0c", "ubuntu22", "ubuntu24", "ubuntu26"]'
os_selection='["almalinux8", "almalinux9", "almalinux10", "debian12", "debian13", "fedora43", "fedora44", "freebsd14-4r", "freebsd15-1r", "freebsd15-1s", "freebsd16-0c", "ubuntu22", "ubuntu24", "ubuntu26"]'
;;
esac
+4 -2
View File
@@ -67,9 +67,11 @@ GITREV = include/zfs_gitrev.h
CLEANFILES += $(GITREV)
PHONY += gitrev
gitrev:
$(AM_V_GEN)$(top_srcdir)/scripts/make_gitrev.sh $(GITREV)
$(AM_V_GEN)cd "$(abs_top_builddir)"; \
$(top_srcdir)/scripts/make_gitrev.sh $(GITREV)
all: gitrev
GITREV_TARGETS := $(shell $(GREP) -rl --include="*.[ch]" $(notdir $(GITREV)) "$(abs_srcdir)"/* | sed "s|$(abs_srcdir)/||" )
$(GITREV_TARGETS): gitrev
PHONY += install-data-hook $(INSTALL_DATA_HOOKS)
install-data-hook: $(INSTALL_DATA_HOOKS)
+112 -18
View File
@@ -6248,16 +6248,19 @@ typedef struct zdb_blkstats {
} zdb_blkstats_t;
/*
* Extended object types to report deferred frees and dedup auto-ditto blocks.
* Extended object types to report deferred frees, dedup auto-ditto blocks
* and pending DDT-log frees.
*/
#define ZDB_OT_DEFERRED (DMU_OT_NUMTYPES + 0)
#define ZDB_OT_DITTO (DMU_OT_NUMTYPES + 1)
#define ZDB_OT_OTHER (DMU_OT_NUMTYPES + 2)
#define ZDB_OT_TOTAL (DMU_OT_NUMTYPES + 3)
#define ZDB_OT_DDT_PENDING (DMU_OT_NUMTYPES + 2)
#define ZDB_OT_OTHER (DMU_OT_NUMTYPES + 3)
#define ZDB_OT_TOTAL (DMU_OT_NUMTYPES + 4)
static const char *zdb_ot_extname[] = {
"deferred free",
"dedup ditto",
"DDT pending free",
"other",
"Total",
};
@@ -6764,24 +6767,54 @@ ddt_done:
uint64_t offset = DVA_GET_OFFSET(&bp->blk_dva[0]);
vdev_t *vd = vdev_lookup_top(zcb->zcb_spa, vdev);
ASSERT(vd != NULL);
metaslab_t *ms = vd->vdev_ms[offset >> vd->vdev_ms_shift];
ASSERT(ms != NULL);
metaslab_group_t *mg = ms->ms_group;
ASSERT(mg != NULL);
metaslab_class_t *mc = mg->mg_class;
ASSERT(mc != NULL);
spa_config_exit(zcb->zcb_spa, SCL_CONFIG, FTAG);
int class;
if (mc == spa_normal_class(zcb->zcb_spa)) {
class = CLASS_NORMAL;
} else if (mc == spa_special_class(zcb->zcb_spa)) {
class = CLASS_SPECIAL;
} else if (mc == spa_dedup_class(zcb->zcb_spa)) {
class = CLASS_DEDUP;
if (vd->vdev_ops == &vdev_indirect_ops) {
/*
* A removed vdev has no metaslabs of its own. Without
* -L we synthesize them (see
* zdb_leak_init_prepare_indirect_vdevs()), but under
* -L there is no metaslab array to index. Classify
* from the allocation bias, which determines the
* vdev's primary metaslab group, and does not depend
* on whether those synthetic metaslabs happen to
* exist.
*/
switch (vd->vdev_alloc_bias) {
case VDEV_BIAS_SPECIAL:
class = CLASS_SPECIAL;
break;
case VDEV_BIAS_DEDUP:
class = CLASS_DEDUP;
break;
case VDEV_BIAS_LOG:
class = CLASS_OTHER;
break;
default:
class = CLASS_NORMAL;
break;
}
spa_config_exit(zcb->zcb_spa, SCL_CONFIG, FTAG);
} else {
class = CLASS_OTHER;
metaslab_t *ms =
vd->vdev_ms[offset >> vd->vdev_ms_shift];
ASSERT(ms != NULL);
metaslab_group_t *mg = ms->ms_group;
ASSERT(mg != NULL);
metaslab_class_t *mc = mg->mg_class;
ASSERT(mc != NULL);
spa_config_exit(zcb->zcb_spa, SCL_CONFIG, FTAG);
if (mc == spa_normal_class(zcb->zcb_spa)) {
class = CLASS_NORMAL;
} else if (mc == spa_special_class(zcb->zcb_spa)) {
class = CLASS_SPECIAL;
} else if (mc == spa_dedup_class(zcb->zcb_spa)) {
class = CLASS_DEDUP;
} else {
class = CLASS_OTHER;
}
}
if (!(block_classes & class)) {
@@ -7789,6 +7822,65 @@ bpobj_count_block_cb(void *arg, const blkptr_t *bp, boolean_t bp_freed,
return (count_block_cb(arg, bp, tx));
}
/*
* With fast dedup, the last decref of a block lands in the DDT log, and
* the physical free happens only when the log entry is flushed back into
* the DDT (see ddt_sync_flush_entry()). Until then the block is not
* referenced by any block pointer but is still allocated, so the
* traversal would misreport it as leaked. Count the phys that the flush
* will free here, the same way as the deferred-free bplist: they are
* frees in flight. Entries behind the log checkpoint are already flushed
* and are not loaded into the in-memory log trees, so everything found
* here is genuinely pending. ddt_log_load() merge-normalizes duplicate
* keys across the active and flushing logs, and ddt_lookup() searches the
* logs before stored DDT objects, so these trees need no DDT ZAP replay.
*/
static void
zdb_count_ddt_log_frees(spa_t *spa, zdb_cb_t *zcb)
{
for (enum zio_checksum c = 0; c < ZIO_CHECKSUM_FUNCTIONS; c++) {
ddt_t *ddt = spa->spa_ddt[c];
if (ddt == NULL || !(ddt->ddt_flags & DDT_FLAG_LOG))
continue;
for (int n = 0; n < 2; n++) {
ddt_log_t *ddl = &ddt->ddt_log[n];
for (ddt_log_entry_t *ddle = avl_first(&ddl->ddl_tree);
ddle; ddle = AVL_NEXT(&ddl->ddl_tree, ddle)) {
ddt_lightweight_entry_t ddlwe;
DDT_LOG_ENTRY_TO_LIGHTWEIGHT(ddt, ddle,
&ddlwe);
for (int p = 0; p < DDT_NPHYS(ddt); p++) {
ddt_phys_variant_t v =
DDT_PHYS_VARIANT(ddt, p);
/*
* Mirror ddt_sync_flush_entry(): an
* unborn phys owns nothing, an
* obsolete ditto slot is freed
* whatever its refcount, and any
* other slot is freed once its last
* reference is gone.
*/
if (ddt_phys_birth(&ddlwe.ddlwe_phys,
v) == 0)
continue;
if (!DDT_PHYS_IS_DITTO(ddt, p) &&
ddt_phys_refcnt(&ddlwe.ddlwe_phys,
v) != 0)
continue;
blkptr_t blk;
ddt_bp_create(ddt->ddt_checksum,
&ddlwe.ddlwe_key, &ddlwe.ddlwe_phys,
v, &blk);
/* As ddt_phys_free() does at flush. */
BP_SET_DEDUP(&blk, 0);
zdb_count_block(zcb, NULL, &blk,
ZDB_OT_DDT_PENDING);
}
}
}
}
}
static int
livelist_entry_count_blocks_cb(void *args, dsl_deadlist_entry_t *dle)
{
@@ -7914,6 +8006,8 @@ dump_block_stats(spa_t *spa)
bpobj_count_block_cb, zcb, NULL);
}
zdb_count_ddt_log_frees(spa, zcb);
zdb_claim_removing(spa, zcb);
if (spa_feature_is_active(spa, SPA_FEATURE_ASYNC_DESTROY)) {
@@ -818,6 +818,14 @@ zfs_retire_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl,
fault_device ? "fault" : "degrade", vdev_guid,
zpool_get_name(zhp));
/*
* Resilvering domain failures can take a lot of computing and
* I/O bandwidth resources, only to be wasted when the failed
* domain component (for example enclosure) is replaced.
*/
if (is_draid_fdomain_failure(hdl, zhdl, pool_guid, vdev_guid))
return;
/*
* Attempt to substitute a hot spare.
*/
+75 -4
View File
@@ -15,6 +15,7 @@
*/
#include <libzfs.h>
#include <libzutil.h>
#include <errno.h>
#include <fcntl.h>
@@ -33,6 +34,7 @@
#include <sys/dmu_objset.h>
#include <sys/dnode.h>
#include <sys/vdev_impl.h>
#include <sys/zvol.h>
#include <sys/mkdev.h>
@@ -66,10 +68,46 @@ compress_slashes(const char *src, char *dest)
}
/*
* Given a full path to a file, translate into a dataset name and a relative
* path within the dataset. 'dataset' must be at least MAXNAMELEN characters,
* and 'relpath' must be at least MAXPATHLEN characters. We also pass a stat64
* buffer, which we need later to get the object ID.
* If 'inpath' points to a zvol block device, copy the zvol dataset path to 'ds'
* (like "tank/vol"), and return true. If 'inpath' does not point to a zvol
* block device, then return false.
*/
static boolean_t
get_zvol_dataset(const char *inpath, char *ds)
{
boolean_t rc = B_FALSE;
char *buf = realpath(inpath, NULL);
if (buf == NULL)
return (B_FALSE);
int fd = open(buf, O_RDONLY | O_CLOEXEC);
free(buf);
if (fd == -1)
return (B_FALSE);
/*
* We want to determine if 'inpath' is a zvol device. There's no
* universal way to do that, so we use OS-specific zvol ioctls.
*/
#if defined(__FreeBSD__)
if (ioctl(fd, DIOCGPHYSPATH, ds) == 0)
rc = B_TRUE;
#else
if (ioctl(fd, BLKZNAME, ds) == 0)
rc = B_TRUE;
#endif
close(fd);
return (rc);
}
/*
* Given a full path to a file or zvol device, translate into a dataset name and
* a relative path within the dataset. 'dataset' must be at least MAXNAMELEN
* characters, and 'relpath' must be at least MAXPATHLEN characters. We also
* pass a stat64 buffer, which we need later to get the object ID.
*/
static int
parse_pathname(const char *inpath, char *dataset, char *relpath,
@@ -88,6 +126,39 @@ parse_pathname(const char *inpath, char *dataset, char *relpath,
return (-1);
}
/* special case: inject errors into zvol */
if (get_zvol_dataset(inpath, fullpath)) {
char *slash;
/*
* The zvol's inode does not contain its object number.
* However, it has long been the case that the zvol data is
* object number 1 (ZVOL_OBJ):
*
* Object lvl iblk dblk dsize lsize %full type
* 0 6 128K 16K 11K 16K 6.25 DMU dnode
* 1 2 128K 16K 20.1M 20M 100.00 zvol object
* 2 1 128K 512 0 512 100.00 zvol prop
*
* So we hardcode that in the statbuf inode field as workaround.
*/
statbuf->st_ino = ZVOL_OBJ;
(void) strlcpy(dataset, fullpath, MAXNAMELEN);
/*
* fullpath contains string like 'tank/zvol'. Strip off the
* 'tank' and 'zvol' parts.
*/
slash = strchr(fullpath, '/');
if (slash == NULL) {
(void) fprintf(stderr, "invalid volume name: '%s'\n",
fullpath);
return (-1);
}
(void) strlcpy(relpath, slash + 1, MAXPATHLEN);
return (0);
}
if (getextmntent(fullpath, &mp, statbuf) != 0) {
(void) fprintf(stderr, "cannot find mountpoint for '%s'\n",
fullpath);
+195 -56
View File
@@ -527,7 +527,7 @@ get_usage(zpool_help_t idx)
return (gettext("\ttrim [-dw] [-r <rate>] [-c | -s] "
"<-a | <pool> [<device> ...]>\n"));
case HELP_STATUS:
return (gettext("\tstatus [-DdegiLPpstvx] "
return (gettext("\tstatus [-DdegiLPpstx] [-v|-vv] "
"[-c script1[,script2,...]] ...\n"
"\t [-j|--json [--json-flat-vdevs] [--json-int] "
"[--json-pool-key-guid]] ...\n"
@@ -1075,6 +1075,9 @@ nice_num_str_nvlist(nvlist_t *item, const char *key, uint64_t value,
case ZFS_NICENUM_BYTES:
zfs_nicenum_format(value, buf, 256, ZFS_NICENUM_BYTES);
break;
case ZFS_NICENUM_RAW:
zfs_nicenum_format(value, buf, 256, ZFS_NICENUM_RAW);
break;
case ZFS_NICENUM_TIME:
zfs_nicenum_format(value, buf, 256, ZFS_NICENUM_TIME);
break;
@@ -2616,8 +2619,8 @@ typedef struct status_cbdata {
int cb_count;
int cb_name_flags;
int cb_namewidth;
int cb_verbosity;
boolean_t cb_allpools;
boolean_t cb_verbose;
boolean_t cb_literal;
boolean_t cb_explain;
boolean_t cb_first;
@@ -3349,7 +3352,7 @@ print_class_vdevs(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t *nv,
nvlist_t **child;
boolean_t printed = B_FALSE;
assert(zhp != NULL || !cb->cb_verbose);
assert(zhp != NULL || cb->cb_verbosity == 0);
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
&children) != 0)
@@ -9794,7 +9797,7 @@ class_vdevs_nvlist(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t *nv,
if (!cb->cb_flat_vdevs)
class_obj = fnvlist_alloc();
assert(zhp != NULL || !cb->cb_verbose);
assert(zhp != NULL || cb->cb_verbosity == 0);
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
&children) != 0)
@@ -9898,57 +9901,133 @@ spares_nvlist(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t *nv,
}
}
/*
* Take a uint64 nvpair named 'name' from nverrlist, nicenum-ify it, and
* put it back in 'nverrlist', possibly as a string, with the same 'name'.
*/
static void
convert_nvlist_uint64_to_nicenum(status_cbdata_t *cb, nvlist_t *parent,
const char *name, enum zfs_nicenum_format format)
{
uint64_t val;
nvpair_t *nvp;
if (nvlist_lookup_nvpair(parent, name, &nvp) != 0)
return; /* nothing by that name, ignore */
val = fnvpair_value_uint64(nvp);
nvlist_remove_nvpair(parent, nvp);
nice_num_str_nvlist(parent, name, val,
cb->cb_literal, cb->cb_json_as_int, format);
}
static void
errors_nvlist(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t *item)
{
int verbosity = cb->cb_verbosity;
nvlist_t *nverrlist = NULL;
nvpair_t *elem;
char *pathname;
size_t len = MAXPATHLEN * 2;
nvlist_t **ranges;
uint_t count;
uint_t objs = 0, i;
nvlist_t **nv_arr = NULL;
char **str_arr = NULL;
uint64_t nerr;
nvlist_t *config = zpool_get_config(zhp, NULL);
if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
&nerr) == 0) {
nice_num_str_nvlist(item, ZPOOL_CONFIG_ERRCOUNT, nerr,
if (zpool_get_errlog(zhp, &nverrlist) != 0) {
/* We're expected to always return an error count */
nice_num_str_nvlist(item, ZPOOL_CONFIG_ERRCOUNT, 0,
cb->cb_literal, cb->cb_json_as_int, ZFS_NICENUM_1024);
if (nerr != 0 && cb->cb_verbose) {
nvlist_t *nverrlist = NULL;
if (zpool_get_errlog(zhp, &nverrlist) == 0) {
int i = 0;
int count = 0;
size_t len = MAXPATHLEN * 2;
nvpair_t *elem = NULL;
for (nvpair_t *pair =
nvlist_next_nvpair(nverrlist, NULL);
pair != NULL;
pair = nvlist_next_nvpair(nverrlist, pair))
count++;
char **errl = (char **)malloc(
count * sizeof (char *));
while ((elem = nvlist_next_nvpair(nverrlist,
elem)) != NULL) {
nvlist_t *nv;
uint64_t dsobj, obj;
verify(nvpair_value_nvlist(elem,
&nv) == 0);
verify(nvlist_lookup_uint64(nv,
ZPOOL_ERR_DATASET, &dsobj) == 0);
verify(nvlist_lookup_uint64(nv,
ZPOOL_ERR_OBJECT, &obj) == 0);
errl[i] = safe_malloc(len);
zpool_obj_to_path(zhp, dsobj, obj,
errl[i++], len);
}
nvlist_free(nverrlist);
fnvlist_add_string_array(item, "errlist",
(const char **)errl, count);
for (int i = 0; i < count; ++i)
free(errl[i]);
free(errl);
} else
fnvlist_add_string(item, "errlist",
strerror(errno));
}
return;
}
/*
* This 'error_count' entry is just the full error log block count.
* This includes duplicate and overlapping entries so it can be
* inaccurate. It's only included for historical reasons.
*/
nvlist_t *config = zpool_get_config(zhp, NULL);
nerr = fnvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT);
nice_num_str_nvlist(item, ZPOOL_CONFIG_ERRCOUNT, nerr,
cb->cb_literal, cb->cb_json_as_int, ZFS_NICENUM_1024);
pathname = safe_malloc(len);
/* Get an initial count of all the objects (files) with errors */
elem = NULL;
while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL)
objs++;
if (verbosity <= 1)
str_arr = safe_malloc(objs * sizeof (*str_arr));
else
nv_arr = safe_malloc(objs * sizeof (*nv_arr));
elem = NULL;
for (i = 0; i < objs; i++) {
nvlist_t *nv;
uint64_t dsobj, obj;
elem = nvlist_next_nvpair(nverrlist, elem);
nv = fnvpair_value_nvlist(elem);
dsobj = fnvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET);
obj = fnvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT);
zpool_obj_to_path(zhp, dsobj, obj, pathname, len);
/*
* Each JSON entry is a different file/zvol. If user has
* verbosity = 1, then just we're just constructing an array
* of strings.
*/
if (str_arr != NULL) {
str_arr[i] = strdup(pathname);
continue;
}
fnvlist_add_string(nv, ZPOOL_ERR_NAME, pathname);
/* nicenum-ify our nvlist */
convert_nvlist_uint64_to_nicenum(cb, nv, ZPOOL_ERR_OBJECT,
ZFS_NICENUM_RAW);
convert_nvlist_uint64_to_nicenum(cb, nv, ZPOOL_ERR_DATASET,
ZFS_NICENUM_RAW);
convert_nvlist_uint64_to_nicenum(cb, nv, ZPOOL_ERR_BLOCK_SIZE,
ZFS_NICENUM_1024);
if (nvlist_lookup_nvlist_array(nv, ZPOOL_ERR_RANGES, &ranges,
&count) == 0) {
for (uint_t i = 0; i < count; i++) {
convert_nvlist_uint64_to_nicenum(cb, ranges[i],
ZPOOL_ERR_START_BYTE, ZFS_NICENUM_1024);
convert_nvlist_uint64_to_nicenum(cb, ranges[i],
ZPOOL_ERR_END_BYTE, ZFS_NICENUM_1024);
}
}
nv_arr[i] = fnvlist_alloc();
fnvlist_add_nvlist(nv_arr[i], pathname, nv);
}
/* Place our error list in a top level "errlist" JSON array object. */
if (str_arr != NULL) {
fnvlist_add_string_array(item, ZPOOL_ERR_JSON,
(const char **) str_arr, objs);
for (i = 0; i < objs; i++)
free(str_arr[i]);
free(str_arr);
} else {
fnvlist_add_nvlist_array(item, ZPOOL_ERR_JSON,
(const nvlist_t **) nv_arr, objs);
for (i = 0; i < objs; i++)
nvlist_free(nv_arr[i]);
free(nv_arr);
}
free(pathname);
nvlist_free(nverrlist);
}
static void
@@ -10714,16 +10793,26 @@ print_condense_status(nvlist_t *nv)
}
static void
print_error_log(zpool_handle_t *zhp)
print_error_log(zpool_handle_t *zhp, int verbosity, boolean_t literal)
{
nvlist_t *nverrlist = NULL;
nvpair_t *elem;
char *pathname;
size_t len = MAXPATHLEN * 2;
boolean_t started = B_FALSE;
char last_pathname[MAXPATHLEN] = "";
if (zpool_get_errlog(zhp, &nverrlist) != 0)
return;
if (nvlist_empty(nverrlist)) {
(void) printf(gettext("errors: Permanent errors have been "
"detected, but none of the affected\n\tblocks could be "
"resolved to a file.\n"));
nvlist_free(nverrlist);
return;
}
(void) printf("errors: Permanent errors have been "
"detected in the following files:\n\n");
@@ -10739,8 +10828,51 @@ print_error_log(zpool_handle_t *zhp)
verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT,
&obj) == 0);
zpool_obj_to_path(zhp, dsobj, obj, pathname, len);
(void) printf("%7s %s\n", "", pathname);
if (last_pathname[0] == '\0' ||
strncmp(pathname, last_pathname, sizeof (last_pathname))
!= 0) {
strlcpy(last_pathname, pathname,
sizeof (last_pathname));
if (started)
(void) printf("\n");
else
started = B_TRUE;
(void) printf("%7s %s ", "", pathname);
} else if (verbosity > 1) {
(void) printf(",");
}
if (verbosity > 1) {
nvlist_t **arr;
uint_t count;
if (nvlist_lookup_nvlist_array(nv, ZPOOL_ERR_RANGES,
&arr, &count) != 0) {
(void) printf("(no ranges)");
continue;
}
for (uint_t i = 0; i < count; i++) {
uint64_t start;
uint64_t end;
start = fnvlist_lookup_uint64(arr[i],
ZPOOL_ERR_START_BYTE);
end = fnvlist_lookup_uint64(arr[i],
ZPOOL_ERR_END_BYTE);
if (literal) {
(void) printf("%llu-%llu",
(u_longlong_t)start,
(u_longlong_t)end);
} else {
char s1[32], s2[32];
zfs_nicenum(start, s1, sizeof (s1));
zfs_nicenum(end, s2, sizeof (s2));
(void) printf("%s-%s", s1, s2);
}
if (i != count - 1)
(void) printf(",");
}
}
}
(void) printf("\n");
free(pathname);
nvlist_free(nverrlist);
}
@@ -11322,7 +11454,13 @@ status_callback_json(zpool_handle_t *zhp, void *data)
spares_nvlist(zhp, cbp, nvroot, item);
}
dedup_stats_nvlist(zhp, cbp, item);
errors_nvlist(zhp, cbp, item);
/*
* Historically, -j would always print the number of errors
* so check for that in addition to verbosity.
*/
if (cbp->cb_verbosity > 0 || cbp->cb_json)
errors_nvlist(zhp, cbp, item);
}
if (cbp->cb_json_pool_key_guid) {
fnvlist_add_nvlist(d, pool_guid, item);
@@ -11496,14 +11634,15 @@ status_callback(zpool_handle_t *zhp, void *data)
if (nerr == 0) {
(void) printf(gettext(
"errors: No known data errors\n"));
} else if (!cbp->cb_verbose) {
} else if (cbp->cb_verbosity == 0) {
color_start(ANSI_RED);
(void) printf(gettext("errors: %llu data "
"errors, use '-v' for a list\n"),
"errors, use '-v' for details\n"),
(u_longlong_t)nerr);
color_end();
} else {
print_error_log(zhp);
print_error_log(zhp, cbp->cb_verbosity,
cbp->cb_literal);
}
}
@@ -11630,7 +11769,7 @@ zpool_do_status(int argc, char **argv)
get_timestamp_arg(*optarg);
break;
case 'v':
cb.cb_verbose = B_TRUE;
cb.cb_verbosity++;
break;
case 'j':
cb.cb_json = B_TRUE;
+144 -107
View File
@@ -407,6 +407,7 @@ typedef struct replication_level {
const char *zprl_type;
uint64_t zprl_children;
uint64_t zprl_parity;
boolean_t zprl_bias;
} replication_level_t;
#define ZPOOL_FUZZ (16 * 1024 * 1024)
@@ -445,6 +446,123 @@ is_raidz_draid(replication_level_t *a, replication_level_t *b)
return (B_FALSE);
}
/*
* Number of device failures a toplevel vdev can tolerate.
*/
static uint64_t
rep_failures(const replication_level_t *rep)
{
if (strcmp(rep->zprl_type, VDEV_TYPE_MIRROR) == 0)
return (rep->zprl_children - 1);
return (rep->zprl_parity);
}
/*
* A special or dedup vdev need not match the layout of the normal vdevs in
* a redundant pool, provided it can tolerate at least as many device
* failures. Returns B_TRUE if one of 'a' and 'b' is such a vdev and the
* other is a normal vdev which it satisfies.
*/
static boolean_t
is_bias_more_redundant(const replication_level_t *a,
const replication_level_t *b)
{
const replication_level_t *bias, *normal;
if (a->zprl_bias == b->zprl_bias)
return (B_FALSE);
bias = a->zprl_bias ? a : b;
normal = a->zprl_bias ? b : a;
return (rep_failures(normal) > 0 &&
rep_failures(bias) >= rep_failures(normal));
}
/*
* Compare the replication levels of two toplevel vdevs. Returns B_TRUE if
* they are consistent. Otherwise, if 'fatal' is set, an error message is
* displayed describing the mismatch.
*/
static boolean_t
rep_consistent(replication_level_t *lastrep, replication_level_t *rep,
boolean_t fatal)
{
replication_level_t *raidz, *mirror;
if (is_bias_more_redundant(lastrep, rep))
return (B_TRUE);
if (is_raidz_mirror(lastrep, rep, &raidz, &mirror) ||
is_raidz_mirror(rep, lastrep, &raidz, &mirror)) {
/*
* Accepted raidz and mirror when they can
* handle the same number of disk failures.
*/
if (raidz->zprl_parity != mirror->zprl_children - 1) {
if (fatal)
vdev_error(gettext(
"mismatched replication level: "
"%s and %s vdevs with different "
"redundancy, %llu vs. %llu (%llu-way) "
"are present\n"),
raidz->zprl_type,
mirror->zprl_type,
(u_longlong_t)raidz->zprl_parity,
(u_longlong_t)mirror->zprl_children - 1,
(u_longlong_t)mirror->zprl_children);
return (B_FALSE);
}
} else if (is_raidz_draid(lastrep, rep)) {
/*
* Accepted raidz and draid when they can
* handle the same number of disk failures.
*/
if (lastrep->zprl_parity != rep->zprl_parity) {
if (fatal)
vdev_error(gettext(
"mismatched replication level: "
"%s and %s vdevs with different "
"redundancy, %llu vs. %llu are present\n"),
lastrep->zprl_type,
rep->zprl_type,
(u_longlong_t)lastrep->zprl_parity,
(u_longlong_t)rep->zprl_parity);
return (B_FALSE);
}
} else if (strcmp(lastrep->zprl_type, rep->zprl_type) != 0) {
if (fatal)
vdev_error(gettext(
"mismatched replication level: "
"both %s and %s vdevs are present\n"),
lastrep->zprl_type, rep->zprl_type);
return (B_FALSE);
} else if (lastrep->zprl_parity != rep->zprl_parity) {
if (fatal)
vdev_error(gettext(
"mismatched replication level: "
"both %llu and %llu device parity "
"%s vdevs are present\n"),
(u_longlong_t)lastrep->zprl_parity,
(u_longlong_t)rep->zprl_parity,
rep->zprl_type);
return (B_FALSE);
} else if (lastrep->zprl_children != rep->zprl_children) {
if (fatal)
vdev_error(gettext(
"mismatched replication level: "
"both %llu-way and %llu-way %s "
"vdevs are present\n"),
(u_longlong_t)lastrep->zprl_children,
(u_longlong_t)rep->zprl_children,
rep->zprl_type);
return (B_FALSE);
}
return (B_TRUE);
}
/*
* Given a list of toplevel vdevs, return the current replication level. If
* the config is inconsistent, then NULL is returned. If 'fatal' is set, then
@@ -460,9 +578,10 @@ get_replication(nvlist_t *nvroot, boolean_t fatal)
nvlist_t *nv;
const char *type;
replication_level_t lastrep = {0};
replication_level_t lastbias = {0};
replication_level_t rep;
replication_level_t *ret;
replication_level_t *raidz, *mirror;
replication_level_t *same, *other;
boolean_t dontreport;
ret = safe_malloc(sizeof (replication_level_t));
@@ -657,116 +776,34 @@ get_replication(nvlist_t *nvroot, boolean_t fatal)
/*
* At this point, we have the replication of the last toplevel
* vdev in 'rep'. Compare it to 'lastrep' to see if it is
* different.
* vdev in 'rep'. Compare it to the last vdev of the same class
* (normal, or special and dedup), and to the last vdev of the
* other class.
*/
if (lastrep.zprl_type != NULL) {
if (is_raidz_mirror(&lastrep, &rep, &raidz, &mirror) ||
is_raidz_mirror(&rep, &lastrep, &raidz, &mirror)) {
/*
* Accepted raidz and mirror when they can
* handle the same number of disk failures.
*/
if (raidz->zprl_parity !=
mirror->zprl_children - 1) {
if (ret != NULL)
free(ret);
ret = NULL;
if (fatal)
vdev_error(gettext(
"mismatched replication "
"level: "
"%s and %s vdevs with "
"different redundancy, "
"%llu vs. %llu (%llu-way) "
"are present\n"),
raidz->zprl_type,
mirror->zprl_type,
(u_longlong_t)
raidz->zprl_parity,
(u_longlong_t)
mirror->zprl_children - 1,
(u_longlong_t)
mirror->zprl_children);
else
return (NULL);
}
} else if (is_raidz_draid(&lastrep, &rep)) {
/*
* Accepted raidz and draid when they can
* handle the same number of disk failures.
*/
if (lastrep.zprl_parity != rep.zprl_parity) {
if (ret != NULL)
free(ret);
ret = NULL;
if (fatal)
vdev_error(gettext(
"mismatched replication "
"level: %s and %s vdevs "
"with different "
"redundancy, %llu vs. "
"%llu are present\n"),
lastrep.zprl_type,
rep.zprl_type,
(u_longlong_t)
lastrep.zprl_parity,
(u_longlong_t)
rep.zprl_parity);
else
return (NULL);
}
} else if (strcmp(lastrep.zprl_type, rep.zprl_type) !=
0) {
if (ret != NULL)
free(ret);
ret = NULL;
if (fatal)
vdev_error(gettext(
"mismatched replication level: "
"both %s and %s vdevs are "
"present\n"),
lastrep.zprl_type, rep.zprl_type);
else
return (NULL);
} else if (lastrep.zprl_parity != rep.zprl_parity) {
if (ret)
free(ret);
ret = NULL;
if (fatal)
vdev_error(gettext(
"mismatched replication level: "
"both %llu and %llu device parity "
"%s vdevs are present\n"),
(u_longlong_t)
lastrep.zprl_parity,
(u_longlong_t)rep.zprl_parity,
rep.zprl_type);
else
return (NULL);
} else if (lastrep.zprl_children != rep.zprl_children) {
if (ret)
free(ret);
ret = NULL;
if (fatal)
vdev_error(gettext(
"mismatched replication level: "
"both %llu-way and %llu-way %s "
"vdevs are present\n"),
(u_longlong_t)
lastrep.zprl_children,
(u_longlong_t)
rep.zprl_children,
rep.zprl_type);
else
return (NULL);
}
rep.zprl_bias = nvlist_exists(nv,
ZPOOL_CONFIG_ALLOCATION_BIAS);
same = rep.zprl_bias ? &lastbias : &lastrep;
other = rep.zprl_bias ? &lastrep : &lastbias;
if ((same->zprl_type != NULL &&
!rep_consistent(same, &rep, fatal)) ||
(other->zprl_type != NULL &&
!rep_consistent(other, &rep, fatal))) {
free(ret);
ret = NULL;
if (!fatal)
return (NULL);
}
lastrep = rep;
*same = rep;
}
/*
* Report the replication level of the normal vdevs, since that is
* what any special or dedup vdevs were required to satisfy.
*/
if (ret != NULL)
*ret = rep;
*ret = (lastrep.zprl_type != NULL) ? lastrep :
(lastbias.zprl_type != NULL) ? lastbias : rep;
return (ret);
}
@@ -830,7 +867,7 @@ check_replication(nvlist_t *config, nvlist_t *newroot)
* the current pool.
*/
ret = 0;
if (current != NULL) {
if (current != NULL && !is_bias_more_redundant(current, new)) {
if (is_raidz_mirror(current, new, &raidz, &mirror) ||
is_raidz_mirror(new, current, &raidz, &mirror)) {
if (raidz->zprl_parity != mirror->zprl_children - 1) {
+1 -1
View File
@@ -14,7 +14,7 @@ zstream_SOURCES = \
%D%/zstream_chain.c \
%D%/zstream_chain.h \
%D%/zstream_decompress.c \
%D%/zstream_drop_record.c \
%D%/zstream_drop_records.c \
%D%/zstream_dump.c \
%D%/zstream_dump.h \
%D%/zstream_fletcher4.c \
+18 -17
View File
@@ -30,21 +30,21 @@ zstream_usage(void)
"usage: zstream command args ...\n"
"Available commands are:\n"
"\n"
"\tzstream dump [-vCd] FILE\n"
"\t... | zstream dump [-vCd]\n"
"\tzstream decompress [-v] [object,offset[,compress_type]...] "
"[file]\n"
"\n"
"\tzstream decompress [-v] [OBJECT,OFFSET[,TYPE]] ...\n"
"\tzstream drop_records [-v] [object,offset...] [file]\n"
"\n"
"\tzstream drop_record [-v] [OBJECT,OFFSET] ...\n"
"\tzstream dump [-Cvd] [file]\n"
"\n"
"\tzstream raw [-v] [-b blocks] [-g guid] IMAGE|DEVICE FILE\n"
"\t... | zstream raw [-v] [-b blocks] [-g guid] IMAGE|DEVICE\n"
"\tzstream raw [-v] [-b max_buffers] [-g fromguid] "
"image|device [file]\n"
"\n"
"\tzstream recompress [-t num_threads] [-l level] TYPE\n"
"\tzstream recompress [-t num_threads] compress_type [file]\n"
"\n"
"\tzstream token resume_token\n"
"\tzstream redup [-v] file\n"
"\n"
"\tzstream redup [-v] FILE | ...\n");
"\tzstream token resume_token\n");
exit(1);
}
@@ -76,26 +76,27 @@ main(int argc, char *argv[])
if (argc < 2)
zstream_usage();
char *subcommand = argv[1];
if (strcmp(subcommand, "dump") == 0) {
return (zstream_do_dump(argc - 1, argv + 1));
} else if (strcmp(subcommand, "decompress") == 0) {
if (strcmp(subcommand, "decompress") == 0) {
return (zstream_do_decompress(argc - 1, argv + 1));
} else if (strcmp(subcommand, "drop_record") == 0) {
return (zstream_do_drop_record(argc - 1, argv + 1));
} else if (strcmp(subcommand, "drop_records") == 0 ||
strcmp(subcommand, "drop_record") == 0) {
/* "drop_record" is the original name, kept for compatibility */
return (zstream_do_drop_records(argc - 1, argv + 1));
} else if (strcmp(subcommand, "dump") == 0) {
return (zstream_do_dump(argc - 1, argv + 1));
} else if (strcmp(subcommand, "raw") == 0) {
return (zstream_do_raw(argc - 1, argv + 1));
} else if (strcmp(subcommand, "recompress") == 0) {
return (zstream_do_recompress(argc - 1, argv + 1));
} else if (strcmp(subcommand, "token") == 0) {
return (zstream_do_token(argc - 1, argv + 1));
} else if (strcmp(subcommand, "redup") == 0) {
return (zstream_do_redup(argc - 1, argv + 1));
} else if (strcmp(subcommand, "selftest") == 0) {
/* Undocumented; used by the ZFS test suite */
return (zstream_do_selftest(argc - 1, argv + 1));
} else if (strcmp(subcommand, "token") == 0) {
return (zstream_do_token(argc - 1, argv + 1));
} else {
zstream_usage();
}
+6 -6
View File
@@ -30,14 +30,14 @@ extern "C" {
#define WATCHDOG_SIGNAL SIGALRM
#define THREAD_BACKTRACE_SIGNAL SIGRTMIN
extern int zstream_do_redup(int, char *[]);
extern int zstream_do_dump(int, char *[]);
extern int zstream_do_decompress(int argc, char *argv[]);
extern int zstream_do_drop_record(int argc, char *argv[]);
extern int zstream_do_drop_records(int argc, char *argv[]);
extern int zstream_do_dump(int argc, char *argv[]);
extern int zstream_do_raw(int argc, char *argv[]);
extern int zstream_do_recompress(int argc, char *argv[]);
extern int zstream_do_token(int, char *[]);
extern int zstream_do_raw(int, char *[]);
extern int zstream_do_selftest(int, char *[]);
extern int zstream_do_redup(int argc, char *argv[]);
extern int zstream_do_selftest(int argc, char *argv[]);
extern int zstream_do_token(int argc, char *argv[]);
extern void zstream_usage(void) __attribute__((noreturn));
#ifdef __cplusplus
@@ -19,12 +19,9 @@
*/
#include <err.h>
#include <errno.h>
#include <search.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/stdtypes.h>
#include <sys/zfs_ioctl.h>
#include <sys/zio_compress.h>
@@ -34,8 +31,6 @@
#include "zstream_modules.h"
#include "zstream_util.h"
#define KEYSIZE 64
static disposition_t
chain_decompress_named_writes(void *item_in, void *context)
{
@@ -48,22 +43,17 @@ chain_decompress_named_writes(void *item_in, void *context)
dmu_replay_record_t *drr = &item->dp_drr;
struct drr_write *drrw = &drr->drr_u.drr_write;
char key[KEYSIZE];
uint8_t *dcbuff;
if (drr->drr_type != DRR_WRITE) {
return (D_OK);
}
snprintf(key, KEYSIZE, "%llu,%llu",
(u_longlong_t)drrw->drr_object, (u_longlong_t)drrw->drr_offset);
ENTRY e = { .key = key };
ENTRY *p = hsearch(e, FIND);
if (p == NULL) {
enum zio_compress ctype;
boolean_t found = lookup_record_specifier(drrw->drr_object,
drrw->drr_offset, &ctype);
if (!found)
return (D_OK);
}
enum zio_compress ctype = (enum zio_compress)(intptr_t)p->data;
if (ctype == ZIO_COMPRESS_INHERIT) {
/* Unspecified */
ctype = drrw->drr_compressiontype;
@@ -134,6 +124,8 @@ int
zstream_do_decompress(int argc, char *argv[])
{
chain_attrs_t attrs = {0};
struct stat statbuf;
char *stream_file = NULL;
int c;
while ((c = getopt(argc, argv, "v")) != -1) {
@@ -150,71 +142,30 @@ zstream_do_decompress(int argc, char *argv[])
argc -= optind;
argv += optind;
if (argc < 0)
zstream_usage();
if (hcreate(argc) == 0)
errx(1, "hcreate failed");
int num_specifiers = parse_record_specifiers(argc, argv, B_TRUE);
argc -= num_specifiers;
argv += num_specifiers;
for (int i = 0; i < argc; i++) {
uint64_t object, offset;
char *obj_str;
char *offset_str;
char *key;
char *end;
enum zio_compress type = ZIO_COMPRESS_INHERIT;
obj_str = strsep(&argv[i], ",");
if (argv[i] == NULL)
zstream_usage();
errno = 0;
object = strtoull(obj_str, &end, 0);
if (errno || *end != '\0')
errx(1, "invalid value for object");
offset_str = strsep(&argv[i], ",");
offset = strtoull(offset_str, &end, 0);
if (errno || *end != '\0')
errx(1, "invalid value for offset");
if (argv[i]) {
if (0 == strcmp("off", argv[i]))
type = ZIO_COMPRESS_OFF;
else if (0 == strcmp("lz4", argv[i]))
type = ZIO_COMPRESS_LZ4;
else if (0 == strcmp("lzjb", argv[i]))
type = ZIO_COMPRESS_LZJB;
else if (0 == strcmp("gzip", argv[i]))
type = ZIO_COMPRESS_GZIP_1;
else if (0 == strcmp("zle", argv[i]))
type = ZIO_COMPRESS_ZLE;
else if (0 == strcmp("zstd", argv[i]))
type = ZIO_COMPRESS_ZSTD;
else {
errx(2, "invalid compression type %s. "
"Supported types are off, lz4, lzjb, gzip, "
"zle, and zstd", argv[i]);
}
if (argc > 1) {
errx(1, "invalid record specifier '%s'", argv[0]);
} else if (argc == 1) {
if (stat(argv[0], &statbuf) == 0) {
stream_file = argv[0];
} else {
errx(1, "invalid record specifier or input file '%s'",
argv[0]);
}
int n_chars = asprintf(&key, "%llu,%llu", (u_longlong_t)object,
(u_longlong_t)offset);
if (n_chars < 0)
err(1, "asprintf");
ENTRY e = { .key = key };
ENTRY *p;
p = hsearch(e, ENTER);
if (p == NULL)
errx(1, "hsearch failed");
p->data = (void *)(intptr_t)type;
}
ENABLE_OPTION(&attrs, CA_FORBID_DEDUP);
zstream_chain_t decompress_chain = {
STANDARD_INPUT_STACK(NULL),
STANDARD_INPUT_STACK(stream_file),
serial_decompress_named_writes(),
STANDARD_OUTPUT_STACK(NULL)
};
zstream_chain_exec(decompress_chain, &attrs);
hdestroy();
destroy_record_specifier_hash();
return (0);
}
@@ -16,20 +16,14 @@
*/
#include <err.h>
#include <errno.h>
#include <search.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/stdtypes.h>
#include <sys/zfs_ioctl.h>
#include <unistd.h>
#include "zstream.h"
#include "zstream_modules.h"
#define KEYSIZE 64
#include "zstream_util.h"
static disposition_t
chain_drop_records(void *item_in, void *context)
@@ -43,10 +37,8 @@ chain_drop_records(void *item_in, void *context)
dmu_replay_record_t *drr = &item->dp_drr;
struct drr_write *drrw = &drr->drr_u.drr_write;
struct drr_write_embedded *drrwe = &drr->drr_u.drr_write_embedded;
char key[KEYSIZE];
u_longlong_t object, offset;
const char *record_type;
ENTRY e = {.key = key};
if (drr->drr_type == DRR_WRITE) {
object = drrw->drr_object;
@@ -60,8 +52,8 @@ chain_drop_records(void *item_in, void *context)
return (D_OK);
}
snprintf(key, KEYSIZE, "%llu,%llu", object, offset);
if (hsearch(e, FIND) != NULL) {
enum zio_compress ctype;
if (lookup_record_specifier(object, offset, &ctype)) {
if (OPTION_ENABLED(CA_VERBOSE)) {
warnx("dropping %s record for object %llu "
"offset %llu", record_type, object, offset);
@@ -89,10 +81,12 @@ serial_drop_records(void)
}
int
zstream_do_drop_record(int argc, char *argv[])
zstream_do_drop_records(int argc, char *argv[])
{
int c;
chain_attrs_t attrs = {0};
struct stat statbuf;
char *stream_file = NULL;
while ((c = getopt(argc, argv, "v")) != -1) {
switch (c) {
@@ -108,52 +102,30 @@ zstream_do_drop_record(int argc, char *argv[])
argc -= optind;
argv += optind;
if (argc < 0)
zstream_usage();
if (hcreate(argc) == 0)
errx(1, "hcreate failed");
int num_specifiers = parse_record_specifiers(argc, argv, B_FALSE);
argc -= num_specifiers;
argv += num_specifiers;
for (int i = 0; i < argc; i++) {
uint64_t object, offset;
char *obj_str;
char *offset_str;
char *key;
char *end;
obj_str = strsep(&argv[i], ",");
if (argv[i] == NULL)
zstream_usage();
errno = 0;
object = strtoull(obj_str, &end, 0);
if (errno || *end != '\0')
errx(1, "invalid value for object");
offset_str = strsep(&argv[i], ",");
offset = strtoull(offset_str, &end, 0);
if (errno || *end != '\0')
errx(1, "invalid value for offset");
if (asprintf(&key, "%llu,%llu", (u_longlong_t)object,
(u_longlong_t)offset) < 0) {
err(1, "asprintf");
if (argc > 1) {
errx(1, "invalid record specifier '%s'", argv[0]);
} else if (argc == 1) {
if (stat(argv[0], &statbuf) == 0) {
stream_file = argv[0];
} else {
errx(1, "invalid record specifier or input file '%s'",
argv[0]);
}
ENTRY e = {.key = key};
ENTRY *p;
p = hsearch(e, ENTER);
if (p == NULL)
errx(1, "hsearch");
p->data = (void *)(intptr_t)B_TRUE;
}
ENABLE_OPTION(&attrs, CA_FORBID_DEDUP);
zstream_chain_t drop_chain = {
STANDARD_INPUT_STACK(NULL),
STANDARD_INPUT_STACK(stream_file),
serial_drop_records(),
STANDARD_OUTPUT_STACK(NULL)
};
zstream_chain_exec(drop_chain, &attrs);
hdestroy();
destroy_record_specifier_hash();
return (0);
}
+7 -3
View File
@@ -45,6 +45,7 @@
#define MEMORY_BASE_CUTOFF (4ULL << 30) /* 4GB */
#define MEMORY_PCT 10 /* % beyond the base region */
#define MEMORY_HYSTERESIS (128 << 20) /* 128MB */
#define BEGIN_PAYLOAD_MAX (1UL << 28)
/*
* Init only the filename; chain functions will prepare the FILE *
@@ -372,8 +373,13 @@ chain_read(void *item_in, void *context_in)
if (context->ic_offset == 0)
set_stream_attributes(item);
uint32_t drr_type = ATTR_IS_SET(CA_BYTESWAPPED) ?
BSWAP_32(drr->drr_type) : drr->drr_type;
size_t payload_size = calc_payload_size(drr);
if (payload_size > UINT32_MAX) {
if (drr_type == DRR_BEGIN && payload_size > BEGIN_PAYLOAD_MAX) {
errx(1, "DRR_BEGIN payload too large at offset %llu",
(u_longlong_t)context->ic_offset);
} else if (payload_size > UINT32_MAX) {
errx(1, "stated packet size is greater than uint32_t "
"at offset %llu", (u_longlong_t)context->ic_offset);
} else if (payload_size > 0) {
@@ -383,8 +389,6 @@ chain_read(void *item_in, void *context_in)
set_payload(item, buff, payload_size);
}
uint32_t drr_type = ATTR_IS_SET(CA_BYTESWAPPED) ?
BSWAP_32(drr->drr_type) : drr->drr_type;
if (drr_type >= DRR_NUMTYPES) {
err(1, "invalid record type %llu found at offset %llu",
(u_longlong_t)drr_type, (u_longlong_t)context->ic_offset);
@@ -33,10 +33,10 @@
#include <sys/stdtypes.h>
#include "zstream.h"
#include "zstream_chain.h"
#include "zstream_modules.h"
#include "zstream_queue.h"
#include "zstream_recompress.h"
#include "zstream_util.h"
#define MAX_COMPRESSION_STEPS 4
@@ -351,6 +351,7 @@ zstream_do_recompress(int argc, char *argv[])
int c;
int level = ZIO_COMPLEVEL_DEFAULT;
int num_threads = 0;
compression_spec_t spec;
chain_attrs_t attrs = { .ca_command_opts = CA_FORBID_DEDUP };
@@ -364,7 +365,7 @@ zstream_do_recompress(int argc, char *argv[])
break;
case 't':
if (sscanf(optarg, "%d", &num_threads) != 1) {
warnx("failed to parse num_threads '%s'",
warnx("failed to parse number of threads '%s'",
optarg);
zstream_usage();
}
@@ -379,27 +380,34 @@ zstream_do_recompress(int argc, char *argv[])
argc -= optind;
argv += optind;
if (argc != 1)
if (argc < 1 || argc > 2)
zstream_usage();
compression_spec_t spec = { .cs_level = level };
if (strcmp(argv[0], "off") == 0) {
spec.cs_type = ZIO_COMPRESS_OFF;
} else {
enum zio_compress ct;
for (ct = 0; ct < ZIO_COMPRESS_FUNCTIONS; ct++) {
const char *ci_name = zio_compress_table[ct].ci_name;
if (strcmp(argv[0], ci_name) == 0)
break;
if (parse_compression_specifier(argv[0], &spec) != 0)
errx(1, "invalid compression type '%s'", argv[0]);
release_libzfs();
boolean_t is_off = spec.cs_type == ZIO_COMPRESS_OFF;
boolean_t is_uncompressed = ctype_is_uncompressed(spec.cs_type);
if (is_uncompressed && !is_off)
errx(1, "invalid compression type '%s'; use 'off'", argv[0]);
if (level != ZIO_COMPLEVEL_DEFAULT) {
if (spec.cs_type != ZIO_COMPRESS_ZSTD) {
errx(1, "use -l only with compression type 'zstd'");
} else if (spec.cs_level != ZIO_COMPLEVEL_DEFAULT &&
spec.cs_level != level) {
errx(1, "conflicting compression levels -l %d "
"vs. zstd-%d", level, spec.cs_level);
} else {
warnx("-l is deprecated; use a composite specifier "
"such as zstd-%d", level);
}
if (ct == ZIO_COMPRESS_FUNCTIONS || ctype_is_uncompressed(ct)) {
errx(2, "invalid compression type %s", argv[0]);
}
spec.cs_type = ct;
spec.cs_level = level;
}
zstream_chain_t recompress_chain = {
STANDARD_INPUT_STACK(NULL),
STANDARD_INPUT_STACK((argc == 2) ? argv[1] : NULL),
parallel_decompress_writes(&spec),
parallel_compress_writes(&spec),
serial_update_compress_features(&spec),
@@ -21,19 +21,18 @@
* Copyright (c) 2020 by Datto Inc. All rights reserved.
*/
#include <errno.h>
#include <libnvpair.h>
#include <libzfs.h>
#include <stdio.h>
#include <sys/nvpair.h>
#include "zstream.h"
#include "zstream_util.h"
int
zstream_do_token(int argc, char *argv[])
{
char *resume_token = NULL;
libzfs_handle_t *hdl;
if (argc < 2) {
(void) fprintf(stderr, "Need to pass the resume token\n");
@@ -41,26 +40,21 @@ zstream_do_token(int argc, char *argv[])
}
resume_token = argv[1];
if ((hdl = libzfs_init()) == NULL) {
(void) fprintf(stderr, "%s\n", libzfs_error_init(errno));
return (1);
}
require_libzfs();
nvlist_t *resume_nvl =
zfs_send_resume_token_to_nvlist(hdl, resume_token);
zfs_send_resume_token_to_nvlist(libzfs_handle, resume_token);
if (resume_nvl == NULL) {
(void) fprintf(stderr,
"Unable to parse resume token: %s\n",
libzfs_error_description(hdl));
libzfs_fini(hdl);
libzfs_error_description(libzfs_handle));
release_libzfs();
return (1);
}
dump_nvlist(resume_nvl, 5);
nvlist_free(resume_nvl);
libzfs_fini(hdl);
release_libzfs();
return (0);
}
@@ -27,12 +27,16 @@
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <libzfs.h>
#include <pthread.h>
#include <search.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/abd.h>
#include <sys/fs/zfs.h>
#include <sys/spa_checksum.h>
#include <sys/stdtypes.h>
#include <sys/sysmacros.h>
#include <sys/zfs_ioctl.h>
@@ -42,6 +46,10 @@
#include "zstream_util.h"
#define KEYSIZE 128
libzfs_handle_t *libzfs_handle = NULL;
void *
safe_malloc(size_t size)
{
@@ -147,6 +155,191 @@ validate_checksum(zio_cksum_t *expected, zio_cksum_t *actual,
return (B_FALSE);
}
/*
* Initialize and deinitialize libzfs idempotently. libzfs has some external
* dependencies, so it shouldn't be initialized as a matter of course.
*/
void
require_libzfs(void)
{
if (libzfs_handle == NULL) {
if ((libzfs_handle = libzfs_init()) == NULL) {
errx(1, "%s", libzfs_error_init(errno));
}
}
}
void
release_libzfs(void)
{
if (libzfs_handle != NULL) {
libzfs_fini(libzfs_handle);
libzfs_handle = NULL;
}
}
int
parse_compression_specifier(const char *str, compression_spec_t *spec)
{
uint64_t val;
int rc;
require_libzfs();
rc = zfs_prop_string_to_index(ZFS_PROP_COMPRESSION, str, &val);
if (rc == 0) {
*spec = (compression_spec_t) {
.cs_type = ZIO_COMPRESS_ALGO(val),
.cs_level = ZIO_COMPRESS_LEVEL(val)
};
if (spec->cs_type == ZIO_COMPRESS_ON)
errx(1, "the meaning of compression type 'on' varies "
"among systems - use a more specific type "
"such as 'lz4'");
boolean_t is_zstd = spec->cs_type == ZIO_COMPRESS_ZSTD;
boolean_t inherited = spec->cs_level == ZIO_COMPLEVEL_INHERIT;
if (is_zstd && inherited)
spec->cs_level = ZIO_COMPLEVEL_DEFAULT;
}
return (rc);
}
/*
* Parse a string of the form "OBJECT,OFFSET" or "OBJECT,OFFSET,COMPRESSION"
* (with accept_compression == B_TRUE) and fill out a corresponding
* record_specifier_t. Returns 0 if the string was successfully parsed.
*
* The rs_compression field of the record specifier struct is always
* initialized to ZIO_COMPRESS_INHERIT, whether accept_compression is true
* or not. If accept_compression is B_TRUE but the input string does not
* specify compression, the value remains at ZIO_COMPRESS_INHERIT.
*/
static int
parse_record_specifier(const char *str, record_specifier_t *rec,
boolean_t accept_compression)
{
char static_buff[256];
char *buff = static_buff;
char *loc;
char *obj_str, *offset_str, *end;
boolean_t bad = B_TRUE;
size_t in_size = strlen(str) + 1;
if (in_size > sizeof (static_buff)) {
buff = safe_malloc(in_size);
}
strcpy(buff, str);
loc = buff;
errno = 0;
rec->rs_compression = (compression_spec_t) {
.cs_type = ZIO_COMPRESS_INHERIT
};
obj_str = strsep(&loc, ",");
if (loc == NULL)
goto bail;
rec->rs_object = strtoull(obj_str, &end, 0);
if (errno != 0 || *end != '\0' || obj_str == end)
goto bail;
offset_str = strsep(&loc, ",");
rec->rs_offset = strtoull(offset_str, &end, 0);
if (errno != 0 || *end != '\0' || offset_str == end)
goto bail;
if (loc != NULL) {
if (accept_compression) {
int rc = parse_compression_specifier(loc,
&rec->rs_compression);
if (rc != 0)
goto bail;
} else {
goto bail;
}
}
bad = B_FALSE;
bail: if (buff != static_buff)
free(buff);
return (bad ? -1 : 0);
}
/*
* Reads as many OBJECT,OFFSET[,COMPRESSION] record specifiers from the
* command line as possible, entering them into an hcreate() hash table. The
* OBJECT/OFFSET pairs become the keys and the compression types become the
* values. If accept_compression is B_FALSE, ZIO_COMPRESS_INHERIT is used as
* a placeholder value. This is also the default when accept_compression
* is B_TRUE but no compression is specified.
*
* Stops at the first unparseable specifier and returns the number of
* specifiers successfully parsed. Checks a few return codes that should
* never fail and exits with a message if they do.
*/
int
parse_record_specifiers(int argc, char *argv[], boolean_t accept_compression)
{
int num_parsed = 0;
char *key;
if (hcreate(argc) == 0)
errx(1, "hcreate failed");
for (int i = 0; i < argc; i++) {
record_specifier_t spec;
int rc = parse_record_specifier(argv[i], &spec,
accept_compression);
if (rc != 0) {
break;
}
int n_chars = asprintf(&key, "%llu,%llu",
(u_longlong_t)spec.rs_object,
(u_longlong_t)spec.rs_offset);
if (n_chars < 0)
err(1, "asprintf");
ENTRY e = { .key = key };
ENTRY *p = hsearch(e, ENTER);
if (p == NULL)
errx(1, "hsearch failed");
p->data = (void *)(intptr_t)spec.rs_compression.cs_type;
num_parsed++;
}
/*
* require_libzfs() will not have been called if accept_compression
* is B_FALSE, but it's still fine to call release_libzfs(). In that
* case it's a no-op.
*/
release_libzfs();
return (num_parsed);
}
/*
* Returns a raw zio_compress value rather than a compression_spec_t because
* no clients are interested in compression levels. They just need to know
* compression type.
*/
boolean_t
lookup_record_specifier(uint64_t object, uint64_t offset,
enum zio_compress *ctype)
{
char key[KEYSIZE];
boolean_t found = B_FALSE;
int n_chars = snprintf(key, sizeof (key), "%llu,%llu",
(u_longlong_t)object, (u_longlong_t)offset);
if (n_chars < 0 || (size_t)n_chars >= sizeof (key))
errx(1, "snprintf");
ENTRY e = { .key = key };
ENTRY *p = hsearch(e, FIND);
if (p != NULL) {
*ctype = (enum zio_compress)(intptr_t)p->data;
found = B_TRUE;
}
return (found);
}
void
destroy_record_specifier_hash(void)
{
hdestroy();
}
boolean_t
write_is_encrypted(struct drr_write *drrw)
{
@@ -22,6 +22,7 @@ extern "C" {
#endif
#include <assert.h>
#include <libzfs.h>
#include <pthread.h>
#include <signal.h>
#include <stddef.h>
@@ -34,14 +35,27 @@ extern "C" {
#include <sys/zio_checksum.h>
#include <sys/zio_compress.h>
/*
* As with the libzfs-native ZIO_* encodings, only zstd compression has a
* separately-defined level. gzip levels are bundled into the compression
* type.
*/
typedef struct {
enum zio_compress cs_type;
int cs_level;
} compression_spec_t;
typedef struct {
uint64_t rs_object;
uint64_t rs_offset;
compression_spec_t rs_compression;
} record_specifier_t;
typedef void *
thread_f(void *);
extern libzfs_handle_t *libzfs_handle;
/*
* The safe_ versions of the functions below terminate the process if the
* operation doesn't succeed instead of returning an error.
@@ -89,6 +103,57 @@ ctype_is_uncompressed(enum zio_compress ct)
return (zio_compress_table[(int)(ct)].ci_compress == NULL);
}
/*
* Initialize and deinitialize libzfs idempotently. libzfs has some external
* dependencies, so it should not be initialized as a matter of course.
*/
void
require_libzfs(void);
void
release_libzfs(void);
/*
* NOTE: This function calls require_libzfs(). Call release_libzfs() at some
* point after use.
*
* Converts a string such as "zstd-12" to a compression_spec_t. Returns 0
* for successful parsing, nonzero if parsing failed. In the case of
* failure, the original compression_spec_t remains unmodified. This parser
* rejects compression type "on" as being insufficiently specific.
*/
int
parse_compression_specifier(const char *str, compression_spec_t *spec);
/*
* Reads as many OBJECT,OFFSET[,COMPRESSION] record specifiers from the
* command line as possible, entering them into an hcreate() hash table. The
* OBJECT/OFFSET pairs become the keys and the compression types become the
* values. If accept_compression is B_FALSE, ZIO_COMPRESS_INHERIT is used as
* a placeholder value. This is also the default when accept_compression is
* B_TRUE but no compression is specified.
*
* Stops at the first unparseable specifier and returns the number of
* specifiers successfully parsed. Checks a few return codes that should
* never fail and exits with a message if they do.
*/
int
parse_record_specifiers(int argc, char *argv[], boolean_t accept_compression);
/*
* Looks up record specifiers in an hcreate() hash table by object and
* offset. Returns B_TRUE and sets the ctype if found.
*/
boolean_t
lookup_record_specifier(uint64_t object, uint64_t offset,
enum zio_compress *ctype);
/*
* Frees the hash table used by lookup_record_specifier().
*/
void
destroy_record_specifier_hash(void);
boolean_t
write_is_encrypted(struct drr_write *drrw);
@@ -34,6 +34,8 @@ typedef struct {
int nesting;
uint64_t featureflags;
boolean_t begin_spill;
boolean_t compound;
boolean_t concluded;
} validate_context_t;
static validate_context_t contexts[MAX_VALIDATIONS];
@@ -84,35 +86,55 @@ chain_validate_records(void *item_in, void *context_in)
if (OPTION_ENABLED(CA_DO_NOT_VALIDATE))
return (D_OK);
if (context->concluded) {
errx(1, "record after compound stream conclusion "
"at offset %llu", (u_longlong_t)item->dp_stream_offset);
}
if (item->dp_stream_offset == 0 && drr->drr_type != DRR_BEGIN) {
warnx("warning - first record is not DRR_BEGIN");
}
if (drr->drr_type == DRR_BEGIN) {
VERIFY0(context->nesting);
if (context->nesting != 0) {
errx(1, "nested DRR_BEGIN record at offset %llu",
(u_longlong_t)item->dp_stream_offset);
}
context->nesting++;
if (item->dp_stream_offset == 0) {
context->compound = DMU_GET_STREAM_HDRTYPE(
drr->drr_u.drr_begin.drr_versioninfo) ==
DMU_COMPOUNDSTREAM;
}
context->featureflags = DMU_GET_FEATUREFLAGS(
drr->drr_u.drr_begin.drr_versioninfo);
context->begin_spill = !!(drr->drr_u.drr_begin.drr_flags &
DRR_FLAG_SPILL_BLOCK);
} else if (drr->drr_type == DRR_END) {
VERIFY3S(context->nesting, >=, 0);
if (context->nesting > 0)
if (context->nesting > 0) {
context->nesting--;
} else if (context->compound &&
IS_CONCLUSION(drr, DRR_END)) {
context->concluded = B_TRUE;
} else {
errx(1, "DRR_END record outside a stream "
"at offset %llu",
(u_longlong_t)item->dp_stream_offset);
}
} else if (drr->drr_type >= DRR_NUMTYPES) {
errx(1, "unknown record type: %d", drr->drr_type);
} else {
VERIFY3S(context->nesting, ==, 1);
if (context->nesting != 1) {
errx(1, "record outside a stream at offset %llu",
(u_longlong_t)item->dp_stream_offset);
}
}
is_raw = validate_stream_has_feature(context, DMU_BACKUP_FEATURE_RAW);
switch (drr->drr_type) {
case DRR_BEGIN:
VERIFY3U(item->dp_payload_size, <=, 1UL << 28);
break;
case DRR_OBJECT:
err = recv_check_drr_object(drro, NULL, is_raw,
context->begin_spill, context->featureflags, errbuf,
@@ -171,6 +193,8 @@ serial_validate_records(void)
context->nesting = 0;
context->featureflags = 0;
context->begin_spill = B_FALSE;
context->compound = B_FALSE;
context->concluded = B_FALSE;
chain_step_t step = {
.cs_type = CS_SERIAL,
+36 -7
View File
@@ -1,8 +1,11 @@
# SPDX-License-Identifier: CDDL-1.0
PHONY += deb-kmod deb-dkms deb-utils deb deb-local native-deb-local \
native-deb-utils native-deb-kmod native-deb
PHONY += deb-kmod deb-dkms deb-utils deb deb-local deb-local-common \
native-deb-local native-deb-utils native-deb-kmod native-deb \
native-deb-check-build-dep
native-deb-local:
native-deb-local: native-deb-check-build-dep deb-local-common
deb-local-common:
@(if test "${HAVE_DPKGBUILD}" = "no"; then \
echo -e "\n" \
"*** Required util ${DPKGBUILD} missing. Please install the\n" \
@@ -11,7 +14,7 @@ native-deb-local:
exit 1; \
fi)
deb-local: native-deb-local
deb-local: deb-local-common
@(if test "${HAVE_ALIEN}" = "no"; then \
echo -e "\n" \
"*** Required util ${ALIEN} missing. Please install the\n" \
@@ -31,6 +34,10 @@ deb-local: native-deb-local
exit 1; \
fi; \
fi)
if test "$(RPM_DBPATH)"; then \
mkdir -p "$(RPM_DBPATH)" "$(abs_builddir)/.config/rpm"; \
echo "%_dbpath $(RPM_DBPATH)" >"$(abs_builddir)/.config/rpm/macros"; \
fi
deb-kmod: deb-local rpm-kmod
name=${PACKAGE}; \
@@ -38,6 +45,7 @@ deb-kmod: deb-local rpm-kmod
arch=`$(RPM) -qp $${name}-kmod-$${version}.src.rpm --qf %{arch} | tail -1`; \
debarch=`$(DPKG) --print-architecture`; \
pkg1=kmod-$${name}*$${version}.$${arch}.rpm; \
HOME=`test "$(RPM_DBPATH)" && echo "$(abs_builddir)" || echo "$${HOME}"` \
fakeroot $(ALIEN) -k --scripts --to-deb --target=$$debarch $$pkg1 || exit 1; \
$(RM) $$pkg1
@@ -48,6 +56,7 @@ deb-dkms: deb-local rpm-dkms
arch=`$(RPM) -qp $${name}-dkms-$${version}.src.rpm --qf %{arch} | tail -1`; \
debarch=`$(DPKG) --print-architecture`; \
pkg1=$${name}-dkms-$${version}.$${arch}.rpm; \
HOME=`test "$(RPM_DBPATH)" && echo "$(abs_builddir)" || echo "$${HOME}"` \
fakeroot $(ALIEN) -k --scripts --to-deb --target=$$debarch $$pkg1 || exit 1; \
$(RM) $$pkg1
@@ -79,6 +88,7 @@ deb-utils: deb-local rpm-utils-initramfs
## which should NOT be mixed with the alien-generated debs created here
chmod +x $${path_prepend}/dh_shlibdeps; \
env "PATH=$${path_prepend}:$${PATH}" \
HOME=`test "$(RPM_DBPATH)" && echo "$(abs_builddir)" || echo "$${HOME}"` \
fakeroot $(ALIEN) -k --scripts --to-deb --target=$$debarch \
$$pkg1 $$pkg2 $$pkg3 $$pkg4 $$pkg5 $$pkg6 $$pkg7 \
$$pkg8 $$pkg9 $$pkg10 $$pkg11 || exit 1; \
@@ -90,20 +100,39 @@ deb-utils: deb-local rpm-utils-initramfs
deb: deb-kmod deb-dkms deb-utils
debian:
cp -r contrib/debian debian; chmod +x debian/rules;
cp -r $(srcdir)/contrib/debian debian; chmod +x debian/rules;
native-deb-check-build-dep:
exec <$(srcdir)/contrib/debian/control; \
while read LINE; do \
if [ -z "$${LINE##Build-Depends:*}" ]; then \
BDEP="$${LINE#Build-Depends: }"; \
while read LINE; do \
[ "$${LINE%%*,}" ] && break; \
BDEP="$${BDEP%%,},$${LINE%%,}"; \
done; break; \
fi ; \
done; \
if apt -s satisfy "$${BDEP}" 2>/dev/null | grep -q "^Inst"; then \
/bin/echo -e "\n" \
"*** Dependencies needed to build native debian package have\n" \
"*** not been met. To install them, run:\n" \
"*** apt satisfy \"$${BDEP}\"\n"; \
exit 1; \
fi
native-deb-utils: native-deb-local debian
while [ -f debian/deb-build.lock ]; do sleep 1; done && \
echo "native-deb-utils" > debian/deb-build.lock && \
trap '$(RM) -f debian/deb-build.lock' EXIT && \
cp contrib/debian/control debian/control && \
cp $(srcdir)/contrib/debian/control debian/control && \
$(DPKGBUILD) -b -rfakeroot -us -uc
native-deb-kmod: native-deb-local debian
while [ -f debian/deb-build.lock ]; do sleep 1; done && \
echo "native-deb-kmod" > debian/deb-build.lock && \
trap '$(RM) -f debian/deb-build.lock' EXIT && \
sh scripts/make_gitrev.sh && \
sh $(srcdir)/scripts/make_gitrev.sh && \
fakeroot debian/rules override_dh_binary-modules
native-deb: native-deb-utils native-deb-kmod
@@ -62,7 +62,7 @@ dnl # Since we plan to pursue making mutex_lock_nested() a non-GPL symbol
dnl # with the upstream community we add a check to detect this case.
dnl #
AC_DEFUN([ZFS_AC_KERNEL_SRC_CONFIG_DEBUG_LOCK_ALLOC], [
ZFS_LINUX_TEST_SRC([config_debug_lock_alloc], [
ZFS_LINUX_TEST_SRC([config_debug_lock_alloc_license], [
#include <linux/mutex.h>
],[
struct mutex lock;
@@ -5,7 +5,7 @@ dnl # functions to reference the GPL-only symbol 'kasan_flag_enabled',
dnl # breaking the build. Detect this and work
dnl # around it.
AC_DEFUN([ZFS_AC_KERNEL_SRC_KASAN_ENABLED], [
ZFS_LINUX_TEST_SRC([kasan_enabled], [
ZFS_LINUX_TEST_SRC([kasan_enabled_license], [
#include <linux/kasan.h>
], [
kasan_enabled();
@@ -0,0 +1,29 @@
dnl # SPDX-License-Identifier: CDDL-1.0
dnl #
dnl # 5.1 API change adds rq_for_each_bvec(), which iterates multi-page
dnl # bvecs rather than splitting every segment at a page boundary.
dnl #
AC_DEFUN([ZFS_AC_KERNEL_SRC_RQ_FOR_EACH_BVEC], [
ZFS_LINUX_TEST_SRC([rq_for_each_bvec], [
#include <linux/blkdev.h>
#include <linux/blk-mq.h>
],[
struct request *rq = NULL;
struct bio_vec bv;
struct req_iterator iter;
rq_for_each_bvec(bv, rq, iter) { (void) bv; }
])
])
AC_DEFUN([ZFS_AC_KERNEL_RQ_FOR_EACH_BVEC], [
AC_MSG_CHECKING([whether rq_for_each_bvec() exists])
ZFS_LINUX_TEST_RESULT([rq_for_each_bvec], [
AC_MSG_RESULT(yes)
AC_DEFINE([HAVE_RQ_FOR_EACH_BVEC], 1,
[rq_for_each_bvec() is available])
],[
AC_MSG_RESULT(no)
])
])
@@ -0,0 +1,30 @@
dnl # SPDX-License-Identifier: CDDL-1.0
dnl #
dnl # 6.9 API change
dnl # super_set_uuid() was added to set sb->s_uuid and sb->s_uuid_len.
dnl # The VFS serves the FS_IOC_GETFSUUID ioctl on all filesystems that
dnl # have a non-zero sb->s_uuid_len, before it calls the ioctl handler
dnl # of the filesystem. On older kernels ZFS sets sb->s_uuid directly
dnl # and serves the ioctl itself, in zpl_ioctl().
dnl #
AC_DEFUN([ZFS_AC_KERNEL_SRC_SUPER_SET_UUID], [
ZFS_LINUX_TEST_SRC([super_set_uuid], [
#include <linux/fs.h>
], [
static struct super_block sb;
static const u8 uuid[16];
super_set_uuid(&sb, uuid, sizeof (uuid));
])
])
AC_DEFUN([ZFS_AC_KERNEL_SUPER_SET_UUID], [
AC_MSG_CHECKING([whether super_set_uuid() is available])
ZFS_LINUX_TEST_RESULT([super_set_uuid], [
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_SUPER_SET_UUID, 1,
[Define if super_set_uuid() is available])
], [
AC_MSG_RESULT(no)
])
])
@@ -8,7 +8,7 @@ dnl #
dnl # Checking if ZERO_PAGE is exported GPL-only
dnl #
AC_DEFUN([ZFS_AC_KERNEL_SRC_ZERO_PAGE], [
ZFS_LINUX_TEST_SRC([zero_page], [
ZFS_LINUX_TEST_SRC([zero_page_license], [
#include <asm/pgtable.h>
], [
struct page *p __attribute__ ((unused));
+37 -1
View File
@@ -77,6 +77,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
ZFS_AC_KERNEL_SRC_FS_PARSE
ZFS_AC_KERNEL_SRC_VFS_PARSE_FS_STRING_3ARGS
ZFS_AC_KERNEL_SRC_SB_DYING
ZFS_AC_KERNEL_SRC_SUPER_SET_UUID
ZFS_AC_KERNEL_SRC_SET_NLINK
ZFS_AC_KERNEL_SRC_VFS_FILEMAP_DIRTY_FOLIO
ZFS_AC_KERNEL_SRC_VFS_READ_FOLIO
@@ -107,6 +108,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
ZFS_AC_KERNEL_SRC_PERCPU
ZFS_AC_KERNEL_SRC_GENERIC_FILLATTR
ZFS_AC_KERNEL_SRC_BIO_MAX_SEGS
ZFS_AC_KERNEL_SRC_RQ_FOR_EACH_BVEC
ZFS_AC_KERNEL_SRC_SIGINFO
ZFS_AC_KERNEL_SRC_SYSFS
ZFS_AC_KERNEL_SRC_STANDALONE_LINUX_STDARG
@@ -195,6 +197,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
ZFS_AC_KERNEL_FS_PARSE
ZFS_AC_KERNEL_VFS_PARSE_FS_STRING_3ARGS
ZFS_AC_KERNEL_SB_DYING
ZFS_AC_KERNEL_SUPER_SET_UUID
ZFS_AC_KERNEL_SET_NLINK
ZFS_AC_KERNEL_VFS_FILEMAP_DIRTY_FOLIO
ZFS_AC_KERNEL_VFS_READ_FOLIO
@@ -225,6 +228,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
ZFS_AC_KERNEL_PERCPU
ZFS_AC_KERNEL_GENERIC_FILLATTR
ZFS_AC_KERNEL_BIO_MAX_SEGS
ZFS_AC_KERNEL_RQ_FOR_EACH_BVEC
ZFS_AC_KERNEL_SIGINFO
ZFS_AC_KERNEL_SYSFS
ZFS_AC_KERNEL_STANDALONE_LINUX_STDARG
@@ -266,6 +270,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
ZFS_AC_KERNEL_FLUSH_DCACHE_PAGE
;;
esac
ZFS_AC_KERNEL_CACHE_UNUSED_RESULTS
])
dnl #
@@ -624,7 +629,6 @@ dnl # $2 - add to top-level Makefile
dnl # $3 - additional build flags
dnl #
AC_DEFUN([ZFS_LINUX_CONFTEST_MAKEFILE], [
test -d build || mkdir -p build
test -d build/$1 || mkdir -p build/$1
file=build/$1/Makefile
@@ -700,6 +704,7 @@ AC_DEFUN([ZFS_LINUX_COMPILE], [
for kernel module builds])
AC_ARG_VAR([KERNEL_ARCH], [Architecture to build kernel modules for])
AC_TRY_COMMAND([
test -d "$1" || mkdir -p "$1";
KBUILD_MODPOST_NOFINAL="$5" KBUILD_MODPOST_WARN="$6"
make modules -k -j$TEST_JOBS ${KERNEL_CC:+CC=$KERNEL_CC}
${KERNEL_LD:+LD=$KERNEL_LD} ${KERNEL_LLVM:+LLVM=$KERNEL_LLVM}
@@ -861,6 +866,14 @@ dnl # The maximum allowed parallelism can be controlled by setting the
dnl # TEST_JOBS environment variable. Otherwise, it default to $(nproc).
dnl #
AC_DEFUN([ZFS_LINUX_TEST_COMPILE_ALL], [
dnl # It may be that no Makefile has been generated because no
dnl # build tests were needed, eg. in the case where the test
dnl # results have all been cached. However, subsequent code
dnl # assumes a file named Makefile exists. So create an empty
dnl # one if needed.
test -d build || mkdir build
touch build/Makefile
AS_IF([test "x$2" != "x"], [
_ZFS_LINUX_TEST_COMPILE_PROGRESS_START([build], [$2])
])
@@ -886,6 +899,7 @@ AC_DEFUN([ZFS_LINUX_TEST_COMPILE_ALL], [
dnl # not yet been built.
dnl #
AS_IF([test "x$enable_linux_builtin" = "xno"], [
touch build/Makefile
for dir in $(awk '/^obj-m/ { print [$]3 }' \
build/Makefile.compile.$1); do
name=${dir%/}
@@ -937,6 +951,7 @@ dnl #
AC_DEFUN([ZFS_LINUX_TEST_SRC], [
cachevar="zfs_cv_kernel_[$1]_$_zfs_linux_cache_checksum"
eval "cacheval=\$$cachevar"
eval "zfs_cv_kernel_cachevarlist=$zfs_cv_kernel_cachevarlist:$cachevar"
AS_IF([test "x$cacheval" = "x"], [
ZFS_LINUX_CONFTEST_C([ZFS_LINUX_TEST_PROGRAM([[$2]], [[$3]],
[["Dual BSD/GPL"]])], [$1])
@@ -977,6 +992,27 @@ AC_DEFUN([ZFS_LINUX_TEST_RESULT], [
AS_IF([test "x$cacheval" = "xyes"], [$2], [$3])
])
dnl #
dnl # ZFS_AC_KERNEL_CACHE_UNUSED_RESULTS
dnl #
dnl # Kernel build tests are run unconditionally, but the results are
dnl # conditionally checked. Cache the build results of all unchecked
dnl # tests so that they are not rebuilt everytime when caching is enabled.
dnl #
AC_DEFUN([ZFS_AC_KERNEL_CACHE_UNUSED_RESULTS], [
AC_MSG_CHECKING([for unchecked kernel build results to cache])
for cachevar in $(echo "${zfs_cv_kernel_cachevarlist}" | tr : ' '); do
eval "cacheval=\$$cachevar"
if test "x${cacheval}" = "x"; then
testname=${cachevar#zfs_cv_kernel_}
testname=${testname%_*}
ZFS_LINUX_TEST_RESULT([${testname}])
fi
done
unset zfs_cv_kernel_cachevarlist
AC_MSG_RESULT([done])
])
dnl #
dnl # ZFS_LINUX_TEST_ERROR
dnl #
+15 -5
View File
@@ -7,15 +7,15 @@
# Build targets for RPM packages.
###############################################################################
PHONY += srpm srpms srpm-kmod srpm-dkms srpm-utils
PHONY += rpm rpms rpm-kmod rpm-dkms rpm-utils rpm-utils-initramfs
PHONY += srpm srpms srpm-kmod srpm-dkms srpm-utils srpm-akmod
PHONY += rpm rpms rpm-kmod rpm-dkms rpm-utils rpm-utils-initramfs rpm-akmod
PHONY += srpm-common rpm-common rpm-local
srpm-kmod srpm-dkms srpm-utils: dist
srpm-kmod srpm-dkms srpm-utils srpm-akmod: dist
srpm-kmod:
$(MAKE) $(AM_MAKEFLAGS) pkg="${PACKAGE}-kmod" \
def='${SRPM_DEFINE_COMMON} ${SRPM_DEFINE_KMOD}' srpm-common
def='${SRPM_DEFINE_COMMON} ${SRPM_DEFINE_KMOD} --with devel' srpm-common
srpm-dkms:
$(MAKE) $(AM_MAKEFLAGS) pkg="${PACKAGE}-dkms" \
@@ -25,12 +25,17 @@ srpm-utils:
$(MAKE) $(AM_MAKEFLAGS) pkg="${PACKAGE}" \
def='${SRPM_DEFINE_COMMON} ${SRPM_DEFINE_UTIL}' srpm-common
srpm-akmod:
$(MAKE) $(AM_MAKEFLAGS) pkg="${PACKAGE}-kmod" \
def='${SRPM_DEFINE_COMMON} --define "_wrong_version_format_terminate_build 0" --define "_enable_akmod 1"' \
RPM_SPEC_DIR="rpm/generic" srpm-common
srpm: srpm-kmod srpm-dkms srpm-utils
srpms: srpm-kmod srpm-dkms srpm-utils
rpm-kmod: srpm-kmod
$(MAKE) $(AM_MAKEFLAGS) pkg="${PACKAGE}-kmod" \
def='${RPM_DEFINE_COMMON} ${RPM_DEFINE_KMOD}' rpm-common
def='${RPM_DEFINE_COMMON} ${RPM_DEFINE_KMOD} --with devel' rpm-common
rpm-dkms: srpm-dkms
$(MAKE) $(AM_MAKEFLAGS) pkg="${PACKAGE}-dkms" \
@@ -52,6 +57,11 @@ rpm-utils-initramfs: srpm-utils
$(MAKE) $(AM_MAKEFLAGS) pkg="${PACKAGE}" \
def='${RPM_DEFINE_COMMON} ${RPM_DEFINE_UTIL} ${RPM_DEFINE_INITRAMFS}' rpm-common
rpm-akmod: srpm-akmod
$(MAKE) $(AM_MAKEFLAGS) pkg="${PACKAGE}-kmod" \
def='${RPM_DEFINE_COMMON} --define "_wrong_version_format_terminate_build 0" --define "_enable_akmod 1"' \
RPM_SPEC_DIR="rpm/generic" rpm-common
rpm: rpm-kmod rpm-dkms rpm-utils
rpms: rpm-kmod rpm-dkms rpm-utils
+2 -2
View File
@@ -22,9 +22,9 @@ AC_DEFUN([ZFS_AC_CONFIG_USER_LIBTIRPC], [
AS_IF([test "x$have_xdr" = "x"], [
ZFS_AC_FIND_SYSTEM_LIBRARY(LIBTIRPC, [libtirpc], [rpc/xdr.h], [tirpc], [tirpc], [xdrmem_create], [], [
AS_IF([test "x$with_tirpc" = "xyes"], [
AC_MSG_FAILURE([--with-tirpc was given, but libtirpc is not available, try installing libtirpc-devel])
AC_MSG_FAILURE([--with-tirpc was given, but libtirpc is not available, try installing libtirpc-devel or libtirpc-dev])
],[dnl ELSE
AC_MSG_FAILURE([neither libc sunrpc support nor libtirpc is available, try installing libtirpc-devel])
AC_MSG_FAILURE([neither libc sunrpc support nor libtirpc is available, try installing libtirpc-devel or libtirpc-dev])
])
])
])
+35 -3
View File
@@ -413,6 +413,23 @@ AC_DEFUN([ZFS_AC_RPM], [
AS_IF([test "x$enable_debuginfo" = xyes], [
RPM_DEFINE_COMMON=${RPM_DEFINE_COMMON}' --define "__strip /bin/true"'
], [
RPM_DEFINE_COMMON=${RPM_DEFINE_COMMON}' --nodebuginfo'
])
AC_MSG_CHECKING([whether to use $RPM configure caching])
AS_IF([test "x$cache_file" != x/dev/null], [
# Cannot use the main cache file because it can have
# different build/host/target (and usually does). So
# treat the presence of a cache file as an indicator
# that caching should be enabled and use a new cache
# file.
CONFCACHE_FILE="${ac_pwd}/config.rpm.cache"
RPM_DEFINE_COMMON=${RPM_DEFINE_COMMON}' --define "confcache --cache-file=$(CONFCACHE_FILE)"'
AC_SUBST([CONFCACHE_FILE])
AC_MSG_RESULT([yes (${CONFCACHE_FILE})])
],[
AC_MSG_RESULT([no])
])
RPM_DEFINE_UTIL=' --define "_initconfdir $(initconfdir)"'
@@ -454,9 +471,9 @@ AC_DEFUN([ZFS_AC_RPM], [
AC_SUBST(MULTIARCH_LIBDIR)
])
dnl # Make RPM_DEFINE_KMOD additions conditional on CONFIG_KERNEL,
dnl # since the values will not be set otherwise. The spec files
dnl # provide defaults for them.
dnl # For akmod builds, we don't need to define kernel build parameters
dnl # since akmods handles this automatically. For regular kmod builds,
dnl # we need all the kernel build parameters.
dnl #
RPM_DEFINE_KMOD='--define "_wrong_version_format_terminate_build 0"'
AM_COND_IF([CONFIG_KERNEL], [
@@ -486,6 +503,20 @@ AC_DEFUN([ZFS_AC_RPM], [
AC_MSG_CHECKING([whether spec files are available])
AC_MSG_RESULT([yes ($RPM_SPEC_DIR/*.spec.in)])
AC_MSG_CHECKING([whether rpm database is readable])
AS_IF([test -r "$($RPM --eval '%{_dbpath}')/rpmdb.sqlite"], [
AC_MSG_RESULT([yes ($($RPM --eval '%{_dbpath}')/rpmdb.sqlite)])
],[
AS_IF([test -r "$($RPM --eval '%{_dbpath}')/Packages"], [
AC_MSG_RESULT([yes ($($RPM --eval '%{_dbpath}')/Packages)])
],[
RPM_DBPATH="${ac_pwd}/.rpmdb"
RPM="$RPM --dbpath=\$(RPM_DBPATH)"
RPMBUILD="$RPMBUILD --dbpath=\$(RPM_DBPATH)"
AC_MSG_RESULT([no (using directory ${RPM_DBPATH})])
])
])
AC_SUBST(HAVE_RPM)
AC_SUBST(RPM)
AC_SUBST(RPM_VERSION)
@@ -494,6 +525,7 @@ AC_DEFUN([ZFS_AC_RPM], [
AC_SUBST(RPMBUILD)
AC_SUBST(RPMBUILD_VERSION)
AC_SUBST(RPM_DBPATH)
AC_SUBST(RPM_SPEC_DIR)
AC_SUBST(RPM_DEFINE_UTIL)
AC_SUBST(RPM_DEFINE_KMOD)
+4 -4
View File
@@ -73,17 +73,17 @@ AC_DEFUN([ZFS_AC_META], [
ZFS_META_RELEASE=_ZFS_AC_META_GETVAL([Release]);
if test ! -f "$srcdir/.nogitrelease" && git -C "$srcdir" rev-parse --git-dir > /dev/null 2>&1; then
_match="${ZFS_META_NAME}-${ZFS_META_VERSION}"
_alias=$(git -C "$srcdir" describe --match=${_match} 2>/dev/null)
_alias=$(git -C "$srcdir" describe --dirty --match=${_match} 2>/dev/null)
_release=$(echo ${_alias}|sed "s/${ZFS_META_NAME}//"|cut -f3- -d'-'|tr - .)
if test -n "${_release}"; then
ZFS_META_RELEASE=${_release}
ZFS_META_RELEASE="${ZFS_META_RELEASE}.${_release}"
_zfs_ac_meta_type="git describe"
else
_match="${ZFS_META_NAME}-${ZFS_META_VERSION}-${ZFS_META_RELEASE}"
_alias=$(git -C "$srcdir" describe --match=${_match} 2>/dev/null)
_alias=$(git -C "$srcdir" describe --dirty --match=${_match} 2>/dev/null)
_release=$(echo ${_alias}|sed 's/${ZFS_META_NAME}//'|cut -f3- -d'-'|tr - .)
if test -n "${_release}"; then
ZFS_META_RELEASE=${_release}
ZFS_META_RELEASE="${ZFS_META_RELEASE}.${_release}"
_zfs_ac_meta_type="git describe"
fi
fi
@@ -1,4 +1,4 @@
openzfs-linux (@VERSION@-1) unstable; urgency=low
openzfs-linux (@VERSION@-@RELEASE@) unstable; urgency=low
* OpenZFS @VERSION@ is tagged.
+1 -1
View File
@@ -102,7 +102,7 @@ override_dh_auto_install:
'$(CURDIR)/$(NAME)-$(DEB_VERSION_UPSTREAM)/configure.ac' | sed '/ZFS_AC_PACKAGE/d' > '$(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/configure.ac'
@# Set "SUBDIRS = module include" for CONFIG_KERNEL and remove SUBDIRS for all other configs.
@# Do not regenerate zfs_gitrev.h during dkms build
sed '1,/CONFIG_KERNEL/s/SUBDIRS.*=.*//g;s/SUBDIRS.*=.*/SUBDIRS = module include/g;/make_gitrev.sh/d' \
sed '1,/CONFIG_KERNEL/s/SUBDIRS.*=.*//g;s/SUBDIRS.*=.*/SUBDIRS = module include/g;s/\([^\t]*make_gitrev.sh\)/: \1/' \
'$(CURDIR)/$(NAME)-$(DEB_VERSION_UPSTREAM)/Makefile.am' > '$(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/Makefile.am'
@# Sanity test
grep -q 'SUBDIRS = module include' '$(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/Makefile.am'
+1
View File
@@ -146,6 +146,7 @@ COMMON_H = \
sys/zio_checksum.h \
sys/zio_compress.h \
sys/zio_crypt.h \
sys/zio_crypt_os_icp.h \
sys/zio_impl.h \
sys/zrlock.h \
sys/zthr.h \
@@ -93,5 +93,6 @@ noinst_HEADERS = \
%D%/zfs/sys/zfs_vfsops_os.h \
%D%/zfs/sys/zfs_vnops_os.h \
%D%/zfs/sys/zfs_znode_impl.h \
%D%/zfs/sys/zio_crypt_os.h \
%D%/zfs/sys/zpl.h
@@ -54,6 +54,10 @@ extern void atomic_dec_64(volatile uint64_t *target);
extern uint64_t atomic_swap_64(volatile uint64_t *a, uint64_t value);
extern uint64_t atomic_load_64(volatile uint64_t *a);
extern uint64_t atomic_add_64_nv(volatile uint64_t *target, int64_t delta);
extern void atomic_or_64(volatile uint64_t *target, uint64_t bits);
extern void atomic_and_64(volatile uint64_t *target, uint64_t bits);
extern uint64_t atomic_or_64_nv(volatile uint64_t *target, uint64_t bits);
extern uint64_t atomic_and_64_nv(volatile uint64_t *target, uint64_t bits);
extern uint64_t atomic_cas_64(volatile uint64_t *target, uint64_t cmp,
uint64_t newval);
#endif
@@ -98,6 +102,38 @@ atomic_dec_32_nv(volatile uint32_t *target)
return (atomic_add_32_nv(target, -1));
}
static __inline void
atomic_or_32(volatile uint32_t *target, uint32_t bits)
{
atomic_set_32(target, bits);
}
static __inline void
atomic_and_32(volatile uint32_t *target, uint32_t bits)
{
atomic_clear_32(target, ~bits);
}
static __inline uint32_t
atomic_or_32_nv(volatile uint32_t *target, uint32_t bits)
{
uint32_t old = *target;
while (!atomic_fcmpset_32(target, &old, old | bits))
continue;
return (old | bits);
}
static __inline uint32_t
atomic_and_32_nv(volatile uint32_t *target, uint32_t bits)
{
uint32_t old = *target;
while (!atomic_fcmpset_32(target, &old, old & bits))
continue;
return (old & bits);
}
#ifndef __sparc64__
static inline uint32_t
atomic_cas_32(volatile uint32_t *target, uint32_t cmp, uint32_t newval)
@@ -131,6 +167,38 @@ atomic_add_64_nv(volatile uint64_t *target, int64_t delta)
return (atomic_fetchadd_64(target, delta) + delta);
}
static __inline void
atomic_or_64(volatile uint64_t *target, uint64_t bits)
{
atomic_set_64(target, bits);
}
static __inline void
atomic_and_64(volatile uint64_t *target, uint64_t bits)
{
atomic_clear_64(target, ~bits);
}
static __inline uint64_t
atomic_or_64_nv(volatile uint64_t *target, uint64_t bits)
{
uint64_t old = *target;
while (!atomic_fcmpset_64(target, &old, old | bits))
continue;
return (old | bits);
}
static __inline uint64_t
atomic_and_64_nv(volatile uint64_t *target, uint64_t bits)
{
uint64_t old = *target;
while (!atomic_fcmpset_64(target, &old, old & bits))
continue;
return (old & bits);
}
#ifndef __sparc64__
static inline uint64_t
atomic_cas_64(volatile uint64_t *target, uint64_t cmp, uint64_t newval)
@@ -73,6 +73,7 @@ typedef struct zfs_uio {
#define zfs_uio_segflg(u) GET_UIO_STRUCT(u)->uio_segflg
#define zfs_uio_offset(u) GET_UIO_STRUCT(u)->uio_offset
#define zfs_uio_resid(u) GET_UIO_STRUCT(u)->uio_resid
#define zfs_uio_iov(u) GET_UIO_STRUCT(u)->uio_iov
#define zfs_uio_iovcnt(u) GET_UIO_STRUCT(u)->uio_iovcnt
#define zfs_uio_iovlen(u, idx) GET_UIO_STRUCT(u)->uio_iov[(idx)].iov_len
#define zfs_uio_iovbase(u, idx) GET_UIO_STRUCT(u)->uio_iov[(idx)].iov_base
@@ -13,149 +13,35 @@
* Copyright 2014 Xin Li <delphij@FreeBSD.org>. All rights reserved.
* Copyright 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2026, TrueNAS.
*/
#ifndef _SYS_ZFS_IOCTL_COMPAT_H
#define _SYS_ZFS_IOCTL_COMPAT_H
#include <sys/cred.h>
#include <sys/dmu.h>
#include <sys/zio.h>
#include <sys/dsl_deleg.h>
#include <sys/zfs_ioctl.h>
#ifdef _KERNEL
#include <sys/nvpair.h>
#endif /* _KERNEL */
/*
* Legacy ioctl support allows compatibility with pre-OpenZFS tools on
* FreeBSD. The need for it will eventually pass (perhaps after FreeBSD
* 12 is well out of support), at which point this code can be removed.
* For now, downstream consumers may choose to disable this code by
* removing the following define.
*/
#define ZFS_LEGACY_SUPPORT
#ifdef __cplusplus
extern "C" {
#endif
/*
* Backwards ioctl compatibility
* FreeBSD used to have its own ZFS port descended from the illumos code,
* before switching to OpenZFS in 13. The original port had its own versioned
* ioctl structure, zfs_iocparm_t, which for OpenZFS wraps zfs_cmd_t and uses a
* special version number ZFS_IOCVER_OZFS. The compatibility layer is now gone
* but there's no particular reason to switch to using zfs_cmd_t directly for
* its own sake, so the version number and wrapping struct are retained.
*/
/* ioctl versions for vfs.zfs.version.ioctl */
#define ZFS_IOCVER_UNDEF -1
#define ZFS_IOCVER_NONE 0
#define ZFS_IOCVER_DEADMAN 1
#define ZFS_IOCVER_LZC 2
#define ZFS_IOCVER_ZCMD 3
#define ZFS_IOCVER_EDBP 4
#define ZFS_IOCVER_RESUME 5
#define ZFS_IOCVER_INLANES 6
#define ZFS_IOCVER_PAD 7
#define ZFS_IOCVER_LEGACY ZFS_IOCVER_PAD
#define ZFS_IOCVER_OZFS 15
/* compatibility conversion flag */
#define ZFS_CMD_COMPAT_NONE 0
#define ZFS_CMD_COMPAT_V15 1
#define ZFS_CMD_COMPAT_V28 2
#define ZFS_CMD_COMPAT_DEADMAN 3
#define ZFS_CMD_COMPAT_LZC 4
#define ZFS_CMD_COMPAT_ZCMD 5
#define ZFS_CMD_COMPAT_EDBP 6
#define ZFS_CMD_COMPAT_RESUME 7
#define ZFS_CMD_COMPAT_INLANES 8
#define ZFS_CMD_COMPAT_LEGACY 9
#define ZFS_IOC_COMPAT_PASS 254
#define ZFS_IOC_COMPAT_FAIL 255
#define ZFS_IOCREQ(ioreq) ((ioreq) & 0xff)
typedef struct zfs_iocparm {
uint32_t zfs_ioctl_version;
uint64_t zfs_cmd;
uint64_t zfs_cmd_size;
} zfs_iocparm_t;
#ifdef ZFS_LEGACY_SUPPORT
#define LEGACY_MAXPATHLEN 1024
#define LEGACY_MAXNAMELEN 256
/*
* Note: this struct must have the same layout in 32-bit and 64-bit, so
* that 32-bit processes (like /sbin/zfs) can pass it to the 64-bit
* kernel. Therefore, we add padding to it so that no "hidden" padding
* is automatically added on 64-bit (but not on 32-bit).
*/
typedef struct zfs_cmd_legacy {
char zc_name[LEGACY_MAXPATHLEN]; /* pool|dataset name */
uint64_t zc_nvlist_src; /* really (char *) */
uint64_t zc_nvlist_src_size;
uint64_t zc_nvlist_dst; /* really (char *) */
uint64_t zc_nvlist_dst_size;
boolean_t zc_nvlist_dst_filled; /* put an nvlist in dst? */
int zc_pad2;
/*
* The following members are for legacy ioctls which haven't been
* converted to the new method.
*/
uint64_t zc_history; /* really (char *) */
char zc_value[LEGACY_MAXPATHLEN * 2];
char zc_string[LEGACY_MAXNAMELEN];
uint64_t zc_guid;
uint64_t zc_nvlist_conf; /* really (char *) */
uint64_t zc_nvlist_conf_size;
uint64_t zc_cookie;
uint64_t zc_objset_type;
uint64_t zc_perm_action;
uint64_t zc_history_len;
uint64_t zc_history_offset;
uint64_t zc_obj;
uint64_t zc_iflags; /* internal to zfs(7fs) */
zfs_share_t zc_share;
uint64_t zc_jailid;
dmu_objset_stats_t zc_objset_stats;
dmu_replay_record_t zc_begin_record;
zinject_record_t zc_inject_record;
uint32_t zc_defer_destroy;
uint32_t zc_flags;
uint64_t zc_action_handle;
int zc_cleanup_fd;
uint8_t zc_simple;
uint8_t zc_pad3[3];
boolean_t zc_resumable;
uint32_t zc_pad4;
uint64_t zc_sendobj;
uint64_t zc_fromobj;
uint64_t zc_createtxg;
zfs_stat_t zc_stat;
} zfs_cmd_legacy_t;
#endif
#ifdef _KERNEL
int zfs_ioctl_compat_pre(zfs_cmd_t *, int *, const int);
void zfs_ioctl_compat_post(zfs_cmd_t *, const int, const int);
nvlist_t *zfs_ioctl_compat_innvl(zfs_cmd_t *, nvlist_t *, const int,
const int);
nvlist_t *zfs_ioctl_compat_outnvl(zfs_cmd_t *, nvlist_t *, const int,
const int);
#endif /* _KERNEL */
#ifdef ZFS_LEGACY_SUPPORT
int zfs_ioctl_legacy_to_ozfs(int request);
int zfs_ioctl_ozfs_to_legacy(int request);
void zfs_cmd_legacy_to_ozfs(zfs_cmd_legacy_t *src, zfs_cmd_t *dst);
void zfs_cmd_ozfs_to_legacy(zfs_cmd_t *src, zfs_cmd_legacy_t *dst);
#endif
void zfs_cmd_compat_put(zfs_cmd_t *, caddr_t, const int, const int);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: CDDL-1.0
/*
* This file and its contents are supplied under the terms of the
* Common Development and Distribution License ("CDDL"), version 1.0.
* You may only use this file in accordance with the terms of version
* 1.0 of the CDDL.
*
* A full copy of the text of the CDDL should have accompanied this
* source. A copy of the CDDL is also available via the Internet at
* https://opensource.org/license/CDDL-1.0.
*/
/*
* Copyright (c) 2017, Datto, Inc. All rights reserved.
* Copyright (c) 2026, TrueNAS.
*/
#ifndef _SYS_ZIO_CRYPT_OS_H
#define _SYS_ZIO_CRYPT_OS_H
#include <sys/freebsd_crypto.h>
typedef struct zio_crypt_session {
freebsd_crypt_session_t zs_sess;
} zio_crypt_session_t;
typedef struct zio_crypt_hmac {
struct hmac_ctx zh_ctx;
} zio_crypt_hmac_t;
#endif
@@ -51,6 +51,7 @@ kernel_sys_HEADERS = \
%D%/zfs/sys/zfs_vfsops_os.h \
%D%/zfs/sys/zfs_vnops_os.h \
%D%/zfs/sys/zfs_znode_impl.h \
%D%/zfs/sys/zio_crypt_os.h \
%D%/zfs/sys/zpl.h
kernel_spl_rpcdir = $(kerneldir)/spl/rpc
@@ -32,6 +32,23 @@
#define zfs_kmap(page) kmap(page)
#define zfs_kunmap(page) kunmap(page)
/*
* Does zfs_kmap_local() give access to only the one page it was passed?
* If not, a run of physically contiguous pages can be mapped once and
* accessed as a whole.
*
* Only CONFIG_HIGHMEM kernels ever set up a single page temporary
* mapping; everywhere else zfs_kmap_local() is just page_address(). We
* deliberately do not narrow this to PageHighMem(), because a HIGHMEM
* kernel built with CONFIG_DEBUG_KMAP_LOCAL_FORCE_MAP maps lowmem pages
* one at a time as well. Compare folio_test_partial_kmap() upstream.
*/
static inline int
zfs_kmap_partial(void)
{
return (IS_ENABLED(CONFIG_HIGHMEM));
}
/* 5.0 API change - no more 'type' argument for access_ok() */
#ifdef HAVE_ACCESS_OK_TYPE
#define zfs_access_ok(type, addr, size) access_ok(type, addr, size)
@@ -47,6 +47,8 @@
#define atomic_dec_32_nv(v) atomic_dec_return((atomic_t *)(v))
#define atomic_add_32_nv(v, i) atomic_add_return((i), (atomic_t *)(v))
#define atomic_sub_32_nv(v, i) atomic_sub_return((i), (atomic_t *)(v))
#define atomic_or_32(v, i) atomic_or((i), (atomic_t *)(v))
#define atomic_and_32(v, i) atomic_and((i), (atomic_t *)(v))
#define atomic_cas_32(v, x, y) atomic_cmpxchg((atomic_t *)(v), x, y)
#define atomic_swap_32(v, x) atomic_xchg((atomic_t *)(v), x)
#define atomic_load_32(v) atomic_read((atomic_t *)(v))
@@ -59,11 +61,37 @@
#define atomic_dec_64_nv(v) atomic64_dec_return((atomic64_t *)(v))
#define atomic_add_64_nv(v, i) atomic64_add_return((i), (atomic64_t *)(v))
#define atomic_sub_64_nv(v, i) atomic64_sub_return((i), (atomic64_t *)(v))
#define atomic_or_64(v, i) atomic64_or((i), (atomic64_t *)(v))
#define atomic_and_64(v, i) atomic64_and((i), (atomic64_t *)(v))
#define atomic_cas_64(v, x, y) atomic64_cmpxchg((atomic64_t *)(v), x, y)
#define atomic_swap_64(v, x) atomic64_xchg((atomic64_t *)(v), x)
#define atomic_load_64(v) atomic64_read((atomic64_t *)(v))
#define atomic_store_64(v, x) atomic64_set((atomic64_t *)(v), x)
static __inline__ uint32_t
atomic_or_32_nv(volatile uint32_t *target, uint32_t bits)
{
return (atomic_fetch_or(bits, (atomic_t *)target) | bits);
}
static __inline__ uint32_t
atomic_and_32_nv(volatile uint32_t *target, uint32_t bits)
{
return (atomic_fetch_and(bits, (atomic_t *)target) & bits);
}
static __inline__ uint64_t
atomic_or_64_nv(volatile uint64_t *target, uint64_t bits)
{
return (atomic64_fetch_or(bits, (atomic64_t *)target) | bits);
}
static __inline__ uint64_t
atomic_and_64_nv(volatile uint64_t *target, uint64_t bits)
{
return (atomic64_fetch_and(bits, (atomic64_t *)target) & bits);
}
#ifdef _LP64
static __inline__ void *
atomic_cas_ptr(volatile void *target, void *cmp, void *newval)
@@ -25,7 +25,7 @@
#ifndef _SPL_CMN_ERR_H
#define _SPL_CMN_ERR_H
#if defined(_KERNEL) && defined(HAVE_STANDALONE_LINUX_STDARG)
#if defined(HAVE_STANDALONE_LINUX_STDARG)
#include <linux/stdarg.h>
#else
#include <stdarg.h>
@@ -57,10 +57,6 @@
/*
* Common DEBUG functionality.
*/
#ifdef __FreeBSD__
#include <linux/compiler.h>
#endif
#ifndef __printflike
#define __printflike(a, b) __printf(a, b)
#endif
@@ -100,10 +96,6 @@ spl_assert(const char *buf, const char *file, const char *func, int line)
#ifndef expect
#define expect(expr, value) (__builtin_expect((expr), (value)))
#endif
#ifndef __linux__
#define likely(expr) expect((expr) != 0, 1)
#define unlikely(expr) expect((expr) != 0, 0)
#endif
#define PANIC(fmt, a...) \
spl_panic(__FILE__, __FUNCTION__, __LINE__, fmt, ## a)
@@ -18,9 +18,7 @@
#ifndef _IA32_SYS_ASM_LINKAGE_H
#define _IA32_SYS_ASM_LINKAGE_H
#if defined(_KERNEL) && defined(__linux__)
#include <linux/linkage.h>
#endif
#ifndef ENDBR
#if defined(__ELF__) && defined(__CET__) && defined(__has_include)
@@ -10,8 +10,6 @@
* https://opensource.org/license/CDDL-1.0.
*/
#if defined(_KERNEL)
/*
* Calls to DTRACE_PROBE* are mapped to standard Linux kernel trace points
* when they are available(when HAVE_DECLARE_EVENT_CLASS is defined). The
@@ -163,4 +161,3 @@ EXPORT_SYMBOL(trace_zfs_##name)
#endif /* CREATE_TRACE_POINTS */
#endif /* HAVE_DECLARE_EVENT_CLASS */
#endif /* _KERNEL */
@@ -10,7 +10,6 @@
* https://opensource.org/license/CDDL-1.0.
*/
#if defined(_KERNEL)
#if defined(HAVE_DECLARE_EVENT_CLASS)
#undef TRACE_SYSTEM
@@ -71,4 +70,3 @@ DEFINE_DTRACE_PROBE1(taskq_ent__start);
DEFINE_DTRACE_PROBE1(taskq_ent__finish);
#endif /* HAVE_DECLARE_EVENT_CLASS */
#endif /* _KERNEL */
@@ -79,8 +79,8 @@ typedef struct {
typedef struct zfs_uio {
union {
const struct iovec *uio_iov;
const struct bio_vec *uio_bvec;
struct iovec *uio_iov;
struct bio_vec *uio_bvec;
struct iov_iter *uio_iter;
};
int uio_iovcnt; /* Number of iovecs */
@@ -101,6 +101,7 @@ typedef struct zfs_uio {
#define zfs_uio_segflg(u) (u)->uio_segflg
#define zfs_uio_offset(u) (u)->uio_loffset
#define zfs_uio_resid(u) (u)->uio_resid
#define zfs_uio_iov(u) (u)->uio_iov
#define zfs_uio_iovcnt(u) (u)->uio_iovcnt
#define zfs_uio_iovlen(u, idx) (u)->uio_iov[(idx)].iov_len
#define zfs_uio_iovbase(u, idx) (u)->uio_iov[(idx)].iov_base
@@ -132,7 +133,7 @@ zfs_uio_advance(zfs_uio_t *uio, ssize_t size)
}
static inline void
zfs_uio_iovec_init(zfs_uio_t *uio, const struct iovec *iov,
zfs_uio_iovec_init(zfs_uio_t *uio, struct iovec *iov,
unsigned long nr_segs, offset_t offset, zfs_uio_seg_t seg, ssize_t resid,
size_t skip)
{
@@ -19,8 +19,6 @@
#ifndef _SYS_POLICY_H
#define _SYS_POLICY_H
#ifdef _KERNEL
#include <sys/cred.h>
#include <sys/types.h>
#include <sys/xvattr.h>
@@ -49,5 +47,4 @@ int secpolicy_vnode_setattr(cred_t *, struct inode *, struct vattr *,
const struct vattr *, int, int (void *, int, cred_t *), void *);
int secpolicy_basic_link(const cred_t *);
#endif /* _KERNEL */
#endif /* _SYS_POLICY_H */
@@ -10,7 +10,6 @@
* https://opensource.org/license/CDDL-1.0.
*/
#if defined(_KERNEL)
#if defined(HAVE_DECLARE_EVENT_CLASS)
#undef TRACE_SYSTEM
@@ -143,4 +142,3 @@ DEFINE_DTRACE_PROBE3(zfs__ace__allows);
DEFINE_DTRACE_PROBE(zfs__fastpath__execute__access__miss);
#endif /* HAVE_DECLARE_EVENT_CLASS */
#endif /* _KERNEL */
@@ -12,7 +12,6 @@
#include <sys/list.h>
#if defined(_KERNEL)
#if defined(HAVE_DECLARE_EVENT_CLASS)
#undef TRACE_SYSTEM
@@ -392,4 +391,3 @@ DEFINE_DTRACE_PROBE4(arc__miss);
DEFINE_DTRACE_PROBE4(l2arc__evict);
#endif /* HAVE_DECLARE_EVENT_CLASS */
#endif /* _KERNEL */
@@ -10,7 +10,6 @@
* https://opensource.org/license/CDDL-1.0.
*/
#if defined(_KERNEL)
#if defined(HAVE_DECLARE_EVENT_CLASS)
#undef TRACE_SYSTEM
@@ -76,4 +75,3 @@ DEFINE_DPRINTF_EVENT(zfs_zfs__dprintf);
DEFINE_DTRACE_PROBE1(zfs__dprintf);
#endif /* HAVE_DECLARE_EVENT_CLASS */
#endif /* _KERNEL */
@@ -10,7 +10,6 @@
* https://opensource.org/license/CDDL-1.0.
*/
#if defined(_KERNEL)
#if defined(HAVE_DECLARE_EVENT_CLASS)
#undef TRACE_SYSTEM
@@ -148,4 +147,3 @@ DEFINE_DTRACE_PROBE2(dbuf__evict__one);
DEFINE_DTRACE_PROBE2(dbuf__state_change);
#endif /* HAVE_DECLARE_EVENT_CLASS */
#endif /* _KERNEL */
@@ -10,7 +10,6 @@
* https://opensource.org/license/CDDL-1.0.
*/
#if defined(_KERNEL)
#if defined(HAVE_DECLARE_EVENT_CLASS)
#undef TRACE_SYSTEM
@@ -120,4 +119,3 @@ DEFINE_DTRACE_PROBE3(delay__mintime);
DEFINE_DTRACE_PROBE3(free__long__range);
#endif /* HAVE_DECLARE_EVENT_CLASS */
#endif /* _KERNEL */
@@ -10,7 +10,6 @@
* https://opensource.org/license/CDDL-1.0.
*/
#if defined(_KERNEL)
#if defined(HAVE_DECLARE_EVENT_CLASS)
#undef TRACE_SYSTEM
@@ -115,4 +114,3 @@ DEFINE_DNODE_MOVE_EVENT(zfs_dnode__move);
DEFINE_DTRACE_PROBE3(dnode__move);
#endif /* HAVE_DECLARE_EVENT_CLASS */
#endif /* _KERNEL */
@@ -10,7 +10,6 @@
* https://opensource.org/license/CDDL-1.0.
*/
#if defined(_KERNEL)
#if defined(HAVE_DECLARE_EVENT_CLASS)
#undef TRACE_SYSTEM
@@ -75,4 +74,3 @@ DEFINE_DTRACE_PROBE3(multilist__insert);
DEFINE_DTRACE_PROBE3(multilist__remove);
#endif /* HAVE_DECLARE_EVENT_CLASS */
#endif /* _KERNEL */
@@ -10,7 +10,6 @@
* https://opensource.org/license/CDDL-1.0.
*/
#if defined(_KERNEL)
#if defined(HAVE_DECLARE_EVENT_CLASS)
#else
@@ -19,4 +18,3 @@ DEFINE_DTRACE_PROBE(zfs__rrwfastpath__rdmiss);
DEFINE_DTRACE_PROBE(zfs__rrwfastpath__exitmiss);
#endif /* HAVE_DECLARE_EVENT_CLASS */
#endif /* _KERNEL */
@@ -10,7 +10,6 @@
* https://opensource.org/license/CDDL-1.0.
*/
#if defined(_KERNEL)
#if defined(HAVE_DECLARE_EVENT_CLASS)
#undef TRACE_SYSTEM
@@ -75,4 +74,3 @@ DEFINE_DTRACE_PROBE2(txg__synced);
DEFINE_DTRACE_PROBE2(txg__quiesced);
#endif /* HAVE_DECLARE_EVENT_CLASS */
#endif /* _KERNEL */
@@ -10,7 +10,6 @@
* https://opensource.org/license/CDDL-1.0.
*/
#if defined(_KERNEL)
#if defined(HAVE_DECLARE_EVENT_CLASS)
/*
@@ -124,4 +123,3 @@ DEFINE_DTRACE_PROBE3(remove__free__unvisited);
DEFINE_DTRACE_PROBE4(remove__free__inflight);
#endif /* HAVE_DECLARE_EVENT_CLASS */
#endif /* _KERNEL */
@@ -10,7 +10,6 @@
* https://opensource.org/license/CDDL-1.0.
*/
#if defined(_KERNEL)
#if defined(HAVE_DECLARE_EVENT_CLASS)
#undef TRACE_SYSTEM
@@ -261,4 +260,3 @@ DEFINE_DTRACE_PROBE2(zil__commit__io__error);
DEFINE_DTRACE_PROBE3(zil__block__size);
#endif /* HAVE_DECLARE_EVENT_CLASS */
#endif /* _KERNEL */
@@ -12,7 +12,6 @@
#include <sys/list.h>
#if defined(_KERNEL)
#if defined(HAVE_DECLARE_EVENT_CLASS)
#undef TRACE_SYSTEM
@@ -85,4 +84,3 @@ DEFINE_DTRACE_PROBE3(zio__delay__hit);
DEFINE_DTRACE_PROBE1(zio__delay__skip);
#endif /* HAVE_DECLARE_EVENT_CLASS */
#endif /* _KERNEL */
@@ -10,7 +10,6 @@
* https://opensource.org/license/CDDL-1.0.
*/
#if defined(_KERNEL)
#if defined(HAVE_DECLARE_EVENT_CLASS)
#undef TRACE_SYSTEM
@@ -82,4 +81,3 @@ DEFINE_ZRLOCK_EVENT(zfs_zrlock__reentry);
DEFINE_DTRACE_PROBE3(zrlock__reentry);
#endif /* HAVE_DECLARE_EVENT_CLASS */
#endif /* _KERNEL */
@@ -47,6 +47,7 @@ extern void zfsctl_destroy(zfsvfs_t *);
extern struct inode *zfsctl_root(znode_t *);
extern boolean_t zfsctl_is_node(struct inode *ip);
extern boolean_t zfsctl_is_snapdir(struct inode *ip);
extern int zfsctl_snapdir_fsid(struct inode *ip, uint64_t *fsidp);
extern int zfsctl_fid(struct inode *ip, fid_t *fidp);
/* zfsctl '.zfs' functions */
@@ -18,10 +18,6 @@
#ifndef _SYS_ZFS_ZNODE_IMPL_H
#define _SYS_ZFS_ZNODE_IMPL_H
#ifndef _KERNEL
#error "no user serviceable parts within"
#endif
#include <sys/isa_defs.h>
#include <sys/types32.h>
#include <sys/list.h>
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: CDDL-1.0
/*
* This file and its contents are supplied under the terms of the
* Common Development and Distribution License ("CDDL"), version 1.0.
* You may only use this file in accordance with the terms of version
* 1.0 of the CDDL.
*
* A full copy of the text of the CDDL should have accompanied this
* source. A copy of the CDDL is also available via the Internet at
* https://opensource.org/license/CDDL-1.0.
*/
/*
* Copyright (c) 2017, Datto, Inc. All rights reserved.
* Copyright (c) 2026, TrueNAS.
*/
#ifndef _SYS_ZIO_CRYPT_OS_H
#define _SYS_ZIO_CRYPT_OS_H
/* Linux always uses the ICP backend. */
#include <sys/zio_crypt_os_icp.h>
#endif
@@ -86,6 +86,8 @@ extern const struct inode_operations zpl_ops_root;
extern const struct file_operations zpl_fops_snapdir;
extern const struct inode_operations zpl_ops_snapdir;
extern const struct inode_operations zpl_ops_snapdirs;
extern const struct file_operations zpl_fops_shares;
extern const struct inode_operations zpl_ops_shares;
@@ -30,6 +30,7 @@
#include <sys/zfs_refcount.h>
#include <sys/rrwlock.h>
#include <sys/dsl_crypt.h>
#include <sys/wmsum.h>
#include <zfeature_common.h>
#ifdef __cplusplus
@@ -213,6 +214,21 @@ typedef struct dsl_dataset {
txg_node_t ds_dirty_link;
list_node_t ds_synced_link;
/*
* Space accounting deltas of this txg, applied by
* dsl_dataset_apply_deltas(). The first group counts blocks
* referenced only by this dataset, the second blocks moved to the
* deadlist, i.e. now owned by ds_prev. Non-snapshots only.
*/
wmsum_t ds_unique_delta;
wmsum_t ds_unique_comp_delta;
wmsum_t ds_unique_uncomp_delta;
wmsum_t ds_dead_delta;
wmsum_t ds_dead_comp_delta;
wmsum_t ds_dead_uncomp_delta;
wmsum_t ds_snap_xfer_delta;
wmsum_t ds_prev_unique_delta;
/*
* ds_phys->ds_<accounting> is also protected by ds_lock.
* Protected by ds_lock:
@@ -394,6 +410,7 @@ void dsl_dataset_block_born(dsl_dataset_t *ds, const blkptr_t *bp,
dmu_tx_t *tx);
int dsl_dataset_block_kill(dsl_dataset_t *ds, const blkptr_t *bp,
dmu_tx_t *tx, boolean_t async);
void dsl_dataset_apply_deltas(dsl_dataset_t *ds, dmu_tx_t *tx);
void dsl_dataset_block_remapped(dsl_dataset_t *ds, uint64_t vdev,
uint64_t offset, uint64_t size, uint64_t birth, dmu_tx_t *tx);
int dsl_dataset_snap_lookup(dsl_dataset_t *ds, const char *name,
+6 -3
View File
@@ -103,13 +103,16 @@ typedef struct dsl_pool {
struct dsl_scan *dp_scan;
/* Uses dp_lock */
kmutex_t dp_lock;
kcondvar_t dp_spaceavail_cv;
/* Updated with atomics, read without a lock */
uint64_t dp_dirty_pertxg[TXG_SIZE];
uint64_t dp_dirty_total;
uint64_t dp_sync_reserve_pertxg[TXG_SIZE];
uint64_t dp_sync_reserve_total;
/* Uses dp_lock */
kmutex_t dp_lock;
kcondvar_t dp_spaceavail_cv;
uint64_t dp_dirty_waiters; /* also read unlocked */
uint64_t dp_long_free_dirty_pertxg[TXG_SIZE];
aggsum_t dp_wrlog_pertxg[TXG_SIZE];
+18
View File
@@ -1875,6 +1875,24 @@ typedef enum {
#define ZPOOL_ERR_LIST "error list"
#define ZPOOL_ERR_DATASET "dataset"
#define ZPOOL_ERR_OBJECT "object"
#define ZPOOL_ERR_LEVEL "level"
#define ZPOOL_ERR_BLKID "blkid" /* unused */
/* Additional nvpairs from zpool_get_errlog() nvlist */
#define ZPOOL_ERR_BLOCK_SIZE "block_size"
#define ZPOOL_ERR_OBJECT_TYPE "object_type"
#define ZPOOL_ERR_RANGES "ranges"
#define ZPOOL_ERR_START_BYTE "start_byte"
#define ZPOOL_ERR_END_BYTE "end_byte"
#define ZPOOL_ERR_NAME "name"
/*
* For the zpool status JSON output, we collect all the error lists and put
* them in a separate top level element so they're easier to iterate over.
* That way the error lists don't get interspersed with the zpool status
* objects.
*/
#define ZPOOL_ERR_JSON "errlist"
#define HIS_MAX_RECORD_LEN (MAXPATHLEN + MAXPATHLEN + 1)
+23
View File
@@ -354,6 +354,29 @@ typedef enum bp_embedded_type {
#define SPA_DVAS_PER_BP 3 /* Number of DVAs in a bp */
#define SPA_SYNC_MIN_VDEVS 3 /* min vdevs to update during sync */
/*
* Get number of data block pointers an indirect block could point to (given
* the block level and block size shift).
*
* For example, an L1 block with a blocksize of 128kb could point to:
*
* BP_SPANB(17, 1) = 1024 L0 block pointers
*/
#define BP_SPANB(indblkshift, level) \
(((uint64_t)1) << ((level) * ((indblkshift) - SPA_BLKPTRSHIFT)))
/*
* Helper function to lookup the byte range covered by a block pointer of any
* level (L0, L1, L2 ... etc).
*
* For example if you have an L1 block, and your blocksize is 128kb (shift 17),
* then your block can cover this many bytes:
*
* BP_BYTE_RANGE(17, 1) = 134217728 bytes
*/
#define BP_BYTE_RANGE(indblkshift, level) \
(BP_SPANB(indblkshift, level) * ((uint64_t)1 << indblkshift))
/*
* A block is a hole when it has either 1) never been written to, or
* 2) is zero-filled. In both cases, ZFS can return all zeroes for all reads
+5 -1
View File
@@ -142,11 +142,15 @@ struct spa_aux_vdev {
uint_t sav_npending; /* # pending devices */
};
/*
* scl_count holds the reference count plus SCL_COUNT_WRITER, so that a reader
* can take a reference and check for a writer in one atomic operation.
*/
typedef struct spa_config_lock {
kmutex_t scl_lock;
kthread_t *scl_writer;
int scl_write_wanted;
int scl_count;
uint32_t scl_count;
kcondvar_t scl_cv;
} ____cacheline_aligned spa_config_lock_t;
+22 -1
View File
@@ -38,7 +38,28 @@ typedef struct zfs_stat {
} zfs_stat_t;
extern int zfs_obj_to_stats(objset_t *osp, uint64_t obj, zfs_stat_t *sb,
char *buf, int len);
char *buf, int len, nvlist_t *nv);
/*
* The legacy behavior of ZFS_IOC_OBJ_TO_STATS is to return a zfs_stat_t struct.
* However, if the user passes in a nvlist dst buffer, we also return
* "extended" object stats. Currently, these extended stats are handpicked
* fields from dmu_object_info_t, but they could be expanded to include
* anything.
*/
#define ZFS_OBJ_STAT_DATA_BLOCK_SIZE "data_block_size"
#define ZFS_OBJ_STAT_METADATA_BLOCK_SIZE "metadata_block_size"
#define ZFS_OBJ_STAT_DNODE_SIZE "dnode_size"
#define ZFS_OBJ_STAT_TYPE "type"
#define ZFS_OBJ_STAT_TYPE_STR "type_str"
#define ZFS_OBJ_STAT_BONUS_TYPE "bonus_type"
#define ZFS_OBJ_STAT_BONUS_TYPE_STR "bonus_type_str"
#define ZFS_OBJ_STAT_BONUS_SIZE "bonus_size"
#define ZFS_OBJ_STAT_CHECKSUM "checksum"
#define ZFS_OBJ_STAT_COMPRESS "compress"
#define ZFS_OBJ_STAT_PHYSICAL_BLOCKS_512 "physical_blocks_512"
#define ZFS_OBJ_STAT_MAX_OFFSET "max_offset"
#define ZFS_OBJ_STAT_FILL_COUNT "fill_count"
#ifdef __cplusplus
}
+66 -32
View File
@@ -12,30 +12,22 @@
/*
* Copyright (c) 2017, Datto, Inc. All rights reserved.
* Copyright (c) 2026, TrueNAS.
*/
#ifndef _SYS_ZIO_CRYPT_H
#define _SYS_ZIO_CRYPT_H
#include <sys/dmu.h>
#include <sys/zfs_refcount.h>
#if defined(__FreeBSD__) && defined(_KERNEL)
#include <sys/freebsd_crypto.h>
#else
#include <sys/crypto/api.h>
#endif /* __FreeBSD__ */
#include <sys/nvpair.h>
#include <sys/avl.h>
#include <sys/zio.h>
/* forward declarations */
struct zbookmark_phys;
#include <sys/zio_crypt_os.h>
#define WRAPPING_KEY_LEN 32
#define WRAPPING_IV_LEN ZIO_DATA_IV_LEN
#define WRAPPING_MAC_LEN ZIO_DATA_MAC_LEN
#define MASTER_KEY_MAX_LEN 32
#define SHA512_HMAC_KEYLEN 64
#define SHA512_HMAC_LEN 64
#define ZIO_CRYPT_KEY_CURRENT_VERSION 1ULL
@@ -47,16 +39,9 @@ typedef enum zio_crypt_type {
/* table of supported crypto algorithms, modes and keylengths. */
typedef struct zio_crypt_info {
/* mechanism name, needed by ICP */
#if defined(__FreeBSD__) && defined(_KERNEL)
/*
* I've deliberately used a different name here, to catch
* ICP-using code.
*/
const char *ci_algname;
#else
crypto_mech_name_t ci_mechname;
#endif
/* mechanism/algorithm name for backend to select implementation */
const char *ci_mechname;
/* cipher mode type (GCM, CCM) */
zio_crypt_type_t ci_crypt_type;
@@ -95,22 +80,17 @@ typedef struct zio_crypt_key {
/* count of how many times the current salt has been used */
uint64_t zk_salt_count;
/* illumos crypto api current encryption key */
/* current raw encryption key for backend */
crypto_key_t zk_current_key;
#if defined(__FreeBSD__) && defined(_KERNEL)
/* Session for current encryption key. Must always be set */
freebsd_crypt_session_t zk_session;
#else
/* template of current encryption key for illumos crypto api */
crypto_ctx_template_t zk_current_tmpl;
#endif
/* backend template (session) for current encryption key */
zio_crypt_session_t zk_current_sess;
/* illumos crypto api current hmac key */
/* current raw hmac key for backend */
crypto_key_t zk_hmac_key;
/* template of hmac key for illumos crypto api */
crypto_ctx_template_t zk_hmac_tmpl;
/* backend template (session) for current hmac key */
zio_crypt_session_t zk_hmac_sess;
/* lock for changing the salt and dependent values */
krwlock_t zk_salt_lock;
@@ -154,4 +134,58 @@ int zio_do_crypt_abd(boolean_t encrypt, zio_crypt_key_t *key,
uint8_t *mac, uint_t datalen, abd_t *pabd, abd_t *cabd,
boolean_t *no_crypt);
/*
* Platform/backend interface to an arbitrary crypto suite.
*/
/*
* A key must be opened before use, so the backend can initialise the wanted
* algorithm and set up the backend crypto suite/hardware.
*
* Reopen should be done after any of the keys internal properties change,
* eg the salt is changed. It is logically equivalent to close+open, but the
* backend may be able to do it more efficiently.
*/
int zio_crypt_key_open_os(zio_crypt_key_t *key, const zio_crypt_info_t *ci);
void zio_crypt_key_close_os(zio_crypt_key_t *key);
int zio_crypt_key_reopen_os(zio_crypt_key_t *key, const zio_crypt_info_t *ci);
/*
* Initialise/free a pair of UIOs with space for iovcnt data elements. This
* will allocate/free zfs_uio_iov(u1)/zfs_uio_iov(u2) with at least iovcnt
* elements. All other uio fields are private to the backend.
*
* The backend may allocate more elements than requested; the first
* one available for caller data is returned in *idx, and the caller should
* not try to use beyond the *idx+iovcnt-1 element.
*/
int zio_crypt_uios_init_os(zfs_uio_t *u1, zfs_uio_t *u2, int iovcnt, int *idx);
void zio_crypt_uios_fini_os(zfs_uio_t *u1, zfs_uio_t *u2);
/* Low-level encrypt/decrypt. See zio_do_crypt_data(). */
int zio_encrypt_os(const zio_crypt_info_t *ci,
crypto_key_t *key, zio_crypt_session_t *sess,
zfs_uio_t *plaintext, zfs_uio_t *ciphertext, size_t datalen,
const uint8_t iv[ZIO_DATA_IV_LEN], const uint8_t *ad, size_t adlen,
uint8_t mac[ZIO_DATA_MAC_LEN]);
int zio_decrypt_os(const zio_crypt_info_t *ci,
crypto_key_t *key, zio_crypt_session_t *sess,
zfs_uio_t *ciphertext, zfs_uio_t *plaintext, size_t datalen,
const uint8_t iv[ZIO_DATA_IV_LEN], const uint8_t *ad, size_t adlen,
uint8_t mac[ZIO_DATA_MAC_LEN]);
/* Generate SHA512-HMAC digest of data using the given HMAC key. */
int zio_crypt_hmac_os(zio_crypt_key_t *key, const uint8_t *data,
size_t datalen, uint8_t digest[SHA512_HMAC_LEN]);
/*
* Generate SHA512-HMAC digest using given key. Data is passed incrementally,
* and the final result generated at the end.
*/
int zio_crypt_hmac_init_os(zio_crypt_hmac_t *hmac, zio_crypt_key_t *key);
int zio_crypt_hmac_update_os(zio_crypt_hmac_t *hmac, const uint8_t *data,
size_t datalen);
int zio_crypt_hmac_final_os(zio_crypt_hmac_t *hmac,
uint8_t digest[SHA512_HMAC_LEN]);
#endif
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: CDDL-1.0
/*
* This file and its contents are supplied under the terms of the
* Common Development and Distribution License ("CDDL"), version 1.0.
* You may only use this file in accordance with the terms of version
* 1.0 of the CDDL.
*
* A full copy of the text of the CDDL should have accompanied this
* source. A copy of the CDDL is also available via the Internet at
* https://opensource.org/license/CDDL-1.0.
*/
/*
* Copyright (c) 2017, Datto, Inc. All rights reserved.
* Copyright (c) 2026, TrueNAS.
*/
#ifndef _SYS_ZIO_CRYPT_OS_ICP_H
#define _SYS_ZIO_CRYPT_OS_ICP_H
#include <sys/crypto/api.h>
typedef struct zio_crypt_session {
crypto_ctx_template_t zs_tmpl;
} zio_crypt_session_t;
typedef struct zio_crypt_hmac {
crypto_context_t zh_ctx;
} zio_crypt_hmac_t;
#endif
@@ -27,7 +27,6 @@
#define MAXOFFSET_T OFF_MAX
#ifndef _KERNEL
#include <sys/disk.h>
static __inline int
@@ -42,7 +41,6 @@ fstat64(int fd, struct stat *sb)
}
return (ret);
}
#endif
/*
* Emulate Solaris' behavior of returning the block device size in fstat64().
@@ -18,10 +18,6 @@
#ifndef _IA32_SYS_ASM_LINKAGE_H
#define _IA32_SYS_ASM_LINKAGE_H
#if defined(_KERNEL) && defined(__linux__)
#include <linux/linkage.h>
#endif
#ifndef ENDBR
#if defined(__ELF__) && defined(__CET__) && defined(__has_include)
/* CSTYLED */
@@ -188,8 +188,6 @@ typedef struct ace_object {
/* minimal acl entries from GETACLCNT */
#define MIN_ACL_ENTRIES 4
#if !defined(_KERNEL)
/* acl check errors */
#define GRP_ERROR 1
#define USER_ERROR 2
@@ -272,14 +270,6 @@ extern int acl_trivial(const char *);
extern char *acl_totext(acl_t *, int);
extern int acl_fromtext(const char *, acl_t **);
extern int acl_check(acl_t *, int);
#else /* !defined(_KERNEL) */
extern void ksort(caddr_t, int, int, int (*)(void *, void *));
extern int cmp2acls(void *, void *);
#endif /* !defined(_KERNEL) */
extern int acl(const char *path, int cmd, int cnt, void *buf);
extern int facl(int fd, int cmd, int cnt, void *buf);
@@ -23,13 +23,9 @@
#endif
#if defined(_KERNEL) && defined(HAVE_KERNEL_OBJTOOL)
#include <asm/frame.h>
#else /* userspace */
#define FRAME_BEGIN
#define FRAME_END
#endif
@@ -68,6 +68,7 @@ typedef struct zfs_uio {
#define zfs_uio_segflg(uio) (uio)->uio_segflg
#define zfs_uio_offset(uio) (uio)->uio_loffset
#define zfs_uio_resid(uio) (uio)->uio_resid
#define zfs_uio_iov(uio) (uio)->uio_iov
#define zfs_uio_iovcnt(uio) (uio)->uio_iovcnt
#define zfs_uio_iovlen(uio, idx) (uio)->uio_iov[(idx)].iov_len
#define zfs_uio_iovbase(uio, idx) (uio)->uio_iov[(idx)].iov_base
@@ -589,14 +589,13 @@ change_one(zfs_handle_t *zhp, void *data)
cn = NULL;
}
/*
* The mountpoint property does not apply to snapshots, so
* there is no need to iterate over them here.
*/
if (!clp->cl_alldependents) {
if (clp->cl_prop != ZFS_PROP_MOUNTPOINT) {
ret = zfs_iter_filesystems_v2(zhp, 0,
change_one, data);
} else {
ret = zfs_iter_children_v2(zhp, 0, change_one,
data);
}
ret = zfs_iter_filesystems_v2(zhp, 0, change_one,
data);
}
/*
@@ -755,12 +754,7 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int gather_flags,
changelist_free(clp);
return (NULL);
}
} else if (clp->cl_prop != ZFS_PROP_MOUNTPOINT) {
if (zfs_iter_filesystems_v2(zhp, 0, change_one, clp) != 0) {
changelist_free(clp);
return (NULL);
}
} else if (zfs_iter_children_v2(zhp, 0, change_one, clp) != 0) {
} else if (zfs_iter_filesystems_v2(zhp, 0, change_one, clp) != 0) {
changelist_free(clp);
return (NULL);
}
+292 -25
View File
@@ -35,6 +35,7 @@
#include <zone.h>
#include <sys/stat.h>
#include <sys/efi_partition.h>
#include <sys/range_tree.h>
#include <sys/systeminfo.h>
#include <sys/zfs_ioctl.h>
#include <sys/zfs_sysfs.h>
@@ -51,6 +52,11 @@
#include "zfeature_common.h"
static boolean_t zpool_vdev_is_interior(const char *name);
static nvlist_t *zpool_get_extended_objset_stat(zpool_handle_t *zhp,
uint64_t dsobj, uint64_t obj);
static nvlist_t *
zpool_get_extended_obj_stat(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj);
typedef struct prop_flags {
unsigned int create:1; /* Validate property on creation */
@@ -4889,6 +4895,201 @@ zpool_add_propname(zpool_handle_t *zhp, const char *propname)
zhp->zpool_n_propnames++;
}
/*
* Given a properties nvlist like:
*
* refreservation:
* source: 'tank/vol'
* value: 1092616192
* recordsize:
* value: 4096
* source: 'tank'
* refcompressratio:
* value: 100
* logicalreferenced:
* value: 1076408320
* compressratio:
* value: 100
* ...
*
* Lookup the 'value' field for a uint64_t and return it into *val. For
* example, if you pass "recordsize" for the name, it will store 4096 into *val.
*/
static int
zpool_get_from_prop_nvlist_uint64(nvlist_t *nv, const char *name, uint64_t *val)
{
nvlist_t *tmp;
int rc;
rc = nvlist_lookup_nvlist(nv, name, &tmp);
if (rc != 0)
return (rc);
return (nvlist_lookup_uint64(tmp, "value", val));
}
/*
* Given a dataset object and object number, return its data blocks size
* and type string (type_str). type_str must be freed when no longer needed.
*/
static int
zpool_get_extended_obj_stat_helper(zpool_handle_t *zhp, uint64_t dsobj,
uint64_t obj, uint64_t *data_block_size, char **type_str)
{
nvlist_t *nv;
boolean_t is_zvol = B_FALSE;
uint64_t val;
int rc;
nv = zpool_get_extended_obj_stat(zhp, dsobj, obj);
if (nv == NULL) {
nv = zpool_get_extended_objset_stat(zhp, dsobj, obj);
if (nv == NULL) {
return (-1);
}
is_zvol = B_TRUE;
}
if (is_zvol) {
rc = zpool_get_from_prop_nvlist_uint64(nv,
zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), &val);
} else {
uint32_t val32 = 0;
rc = nvlist_lookup_uint32(nv, ZFS_OBJ_STAT_DATA_BLOCK_SIZE,
&val32);
val = val32;
}
if (rc != 0) {
nvlist_free(nv);
return (rc);
}
*data_block_size = val;
const char *tmp;
if (is_zvol)
tmp = "zvol";
else
tmp = fnvlist_lookup_string(nv, ZFS_OBJ_STAT_TYPE_STR);
*type_str = strdup(tmp);
nvlist_free(nv);
return (0);
}
static void zpool_get_errlog_process_file_cb(void *arg, uint64_t start,
uint64_t size) {
nvlist_t ***tmp = arg;
nvlist_t **nva_next = *tmp;
nvlist_t *nv;
nv = fnvlist_alloc();
fnvlist_add_uint64(nv, ZPOOL_ERR_START_BYTE, start);
fnvlist_add_uint64(nv, ZPOOL_ERR_END_BYTE, start + size - 1);
*nva_next = nv;
/* Advance to next array entry */
*tmp = nva_next + 1;
}
static void
zpool_get_errlog_process_file(zpool_handle_t *zhp,
nvlist_t **nverrlistp, zbookmark_phys_t *zb_start, zbookmark_phys_t *zb_end)
{
uint64_t data_block_size = 0;
char *type_str = NULL;
nvlist_t *nv, **nva, **nva_next;
uint64_t count = 0;
/* Make the linter happy */
VERIFY(zb_start != NULL);
VERIFY(zb_end != NULL);
nv = fnvlist_alloc();
fnvlist_add_uint64(nv, ZPOOL_ERR_DATASET, zb_start->zb_objset);
fnvlist_add_uint64(nv, ZPOOL_ERR_OBJECT, zb_start->zb_object);
if (zpool_get_extended_obj_stat_helper(zhp, zb_start->zb_objset,
zb_start->zb_object, &data_block_size, &type_str) != 0) {
/*
* If the kernel supports extended stats, then include them.
* If not, it's still OK.
*/
goto end;
}
fnvlist_add_string(nv, ZPOOL_ERR_OBJECT_TYPE, type_str);
fnvlist_add_uint64(nv, ZPOOL_ERR_BLOCK_SIZE, data_block_size);
free(type_str);
zfs_range_tree_t *range_tree;
range_tree = zfs_range_tree_create(NULL, ZFS_RANGE_SEG64, NULL, 0, 0);
if (range_tree == NULL)
goto end;
do {
int data_block_size_shift;
uint64_t data_block_range;
/*
* If an L1 (or higher block) is damaged, it will affect a much
* larger byte range than a simple L0 block. Calculate these
* ranges correctly.
*/
if (highbit64(data_block_size) != lowbit64(data_block_size)) {
/*
* Our data block size is not power-of-two. This is
* probably a single block file.
*/
data_block_size_shift = 0;
data_block_range = data_block_size;
} else {
data_block_size_shift = highbit64(data_block_size) - 1;
data_block_range = BP_BYTE_RANGE(data_block_size_shift,
zb_start->zb_level);
}
/*
* The range we are adding could overlap other entries. Do
* a clear first to punch a hole in any existing ranges,
* then do the add. We have to do this since our add can't
* overlap an existing range.
*/
zfs_range_tree_clear(range_tree,
zb_start->zb_blkid * data_block_range, data_block_range);
zfs_range_tree_add(range_tree,
zb_start->zb_blkid * data_block_range, data_block_range);
if (zb_start == zb_end)
break;
} while (zb_start++);
/*
* Our range tree has all our ranges. Construct an array of start/end
* entries.
*/
count = zfs_range_tree_numsegs(range_tree);
nva = zfs_alloc(zhp->zpool_hdl, sizeof (nvlist_t *) * count);
nva_next = &nva[0];
zfs_range_tree_walk(range_tree, zpool_get_errlog_process_file_cb,
&nva_next);
zfs_range_tree_vacate(range_tree, NULL, NULL);
zfs_range_tree_destroy(range_tree);
fnvlist_add_nvlist_array(nv, ZPOOL_ERR_RANGES, (const nvlist_t **) nva,
count);
for (uint64_t i = 0; i < count; i++)
nvlist_free(nva[i]);
free(nva);
end:
fnvlist_add_nvlist(*nverrlistp, "ejk", nv);
nvlist_free(nv);
}
/*
* Retrieve the persistent error log, uniquify the members, and return to the
* caller.
@@ -4900,6 +5101,7 @@ zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp)
libzfs_handle_t *hdl = zhp->zpool_hdl;
zbookmark_phys_t *buf;
uint64_t buflen = 10000; /* approx. 1MB of RAM */
uint64_t i;
if (fnvlist_lookup_uint64(zhp->zpool_config,
ZPOOL_CONFIG_ERRCOUNT) == 0)
@@ -4939,6 +5141,10 @@ zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp)
*/
zbookmark_phys_t *zb = buf + zc.zc_nvlist_dst_size;
uint64_t zblen = buflen - zc.zc_nvlist_dst_size;
if (zblen == 0) {
free(buf);
return (0); /* nothing to do */
}
qsort(zb, zblen, sizeof (zbookmark_phys_t), zbookmark_mem_compare);
@@ -4947,39 +5153,35 @@ zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp)
/*
* Fill in the nverrlistp with nvlist's of dataset and object numbers.
*/
for (uint64_t i = 0; i < zblen; i++) {
nvlist_t *nv;
zbookmark_phys_t *start = NULL;
/* ignoring zb_blkid and zb_level for now */
if (i > 0 && zb[i-1].zb_objset == zb[i].zb_objset &&
zb[i-1].zb_object == zb[i].zb_object)
for (i = 0; i < zblen; i++) {
if (start == NULL) {
start = &zb[i];
continue;
}
if (nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) != 0)
goto nomem;
if (nvlist_add_uint64(nv, ZPOOL_ERR_DATASET,
zb[i].zb_objset) != 0) {
nvlist_free(nv);
goto nomem;
/* filter out duplicate files and levels */
if (zb[i-1].zb_objset == zb[i].zb_objset &&
zb[i-1].zb_object == zb[i].zb_object) {
/* same file, new error block */
continue;
} else {
/*
* Every time we see a new object, process the
* previous one.
*/
zpool_get_errlog_process_file(zhp, nverrlistp,
start, &zb[i-1]);
start = &zb[i];
}
if (nvlist_add_uint64(nv, ZPOOL_ERR_OBJECT,
zb[i].zb_object) != 0) {
nvlist_free(nv);
goto nomem;
}
if (nvlist_add_nvlist(*nverrlistp, "ejk", nv) != 0) {
nvlist_free(nv);
goto nomem;
}
nvlist_free(nv);
}
/* Process the last entry */
zpool_get_errlog_process_file(zhp, nverrlistp, start, &zb[i-1]);
free(buf);
return (0);
nomem:
free(buf);
return (no_memory(zhp->zpool_hdl));
}
/*
@@ -5265,6 +5467,71 @@ zpool_events_seek(libzfs_handle_t *hdl, uint64_t eid, int zevent_fd)
return (error);
}
/*
* Return extended information about an object. This calls the "extended"
* variant of ZFS_IOC_OBJ_TO_STATS to return things things like block size,
* dmu type, dnone size, etc (see dmu_object_info_t).
*
* Returned nvlist must be freed by the user when they are done with it.
*/
static nvlist_t *
zpool_get_extended_obj_stat_impl(zpool_handle_t *zhp, uint64_t dsobj,
uint64_t obj, enum zfs_ioc stats_ioctl)
{
zfs_cmd_t zc = {"\0"};
char dsname[ZFS_MAX_DATASET_NAME_LEN];
nvlist_t *nv = NULL;
int error;
/* get the dataset's name */
zc.zc_obj = dsobj;
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
error = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_DSOBJ_TO_DSNAME, &zc);
if (error)
return (NULL);
(void) strlcpy(dsname, zc.zc_value, sizeof (dsname));
(void) strlcpy(zc.zc_name, dsname, sizeof (zc.zc_name));
zcmd_alloc_dst_nvlist(zhp->zpool_hdl, &zc, 1024);
zc.zc_obj = obj;
while (zfs_ioctl(zhp->zpool_hdl, stats_ioctl, &zc) != 0) {
if (errno == ENOMEM) {
zcmd_expand_dst_nvlist(zhp->zpool_hdl, &zc);
} else {
zcmd_free_nvlists(&zc);
return (NULL);
}
}
zcmd_read_dst_nvlist(zhp->zpool_hdl, &zc, &nv);
zcmd_free_nvlists(&zc);
return (nv);
}
/*
* Return extended information about an object. This calls the "extended"
* variant of ZFS_IOC_OBJ_TO_STATS to return things things like block size,
* dmu type, dnone size, etc (see dmu_object_info_t).
*
* Returned nvlist must be freed by the user when they are done with it.
*/
static nvlist_t *
zpool_get_extended_obj_stat(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj)
{
return (zpool_get_extended_obj_stat_impl(zhp, dsobj, obj,
ZFS_IOC_OBJ_TO_STATS));
}
static nvlist_t *
zpool_get_extended_objset_stat(zpool_handle_t *zhp, uint64_t dsobj,
uint64_t obj)
{
return (zpool_get_extended_obj_stat_impl(zhp, dsobj, obj,
ZFS_IOC_OBJSET_STATS));
}
static void
zpool_obj_to_path_impl(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj,
char *pathname, size_t len, boolean_t always_unmounted)
@@ -5279,8 +5279,15 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
break;
case ZFS_ERR_STREAM_LARGE_BLOCK_MISMATCH:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"incremental send stream requires -L "
"(--large-block), to match previous receive."));
"destination contains large blocks, but the\n"
"incremental stream does not carry them. Either "
"the sending side omitted -L\n(--large-block), "
"or it used -L but its copy has no large blocks, "
"which makes\n-L a no-op. In the latter case the "
"two copies have different block layouts\nand "
"this direction of replication cannot be resumed; "
"receive a full stream\ninto a new dataset "
"instead."));
(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);
break;
case ENOTSUP:
@@ -1086,6 +1086,7 @@ libzfs_init(void)
vdev_prop_init();
libzfs_mnttab_init(hdl);
fletcher_4_init();
zfs_btree_init();
if (getenv("ZFS_PROP_DEBUG") != NULL) {
hdl->libzfs_prop_debug = B_TRUE;
@@ -1130,6 +1131,7 @@ libzfs_fini(libzfs_handle_t *hdl)
libzfs_mnttab_fini(hdl);
libzfs_core_fini();
regfree(&hdl->libzfs_urire);
zfs_btree_fini();
fletcher_4_fini();
#if LIBFETCH_DYNAMIC
if (hdl->libfetch != (void *)-1 && hdl->libfetch != NULL)
@@ -22,9 +22,6 @@ libzfs_core_la_CPPFLAGS += -Iinclude/os/freebsd/zfs
libzfs_core_la_SOURCES += \
%D%/os/freebsd/libzfs_core_ioctl.c
nodist_libzfs_core_la_SOURCES = \
module/os/freebsd/zfs/zfs_ioctl_compat.c
endif
libzfs_core_la_LIBADD = \
@@ -70,6 +70,7 @@
#include <libzfs_core.h>
#include <ctype.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#ifdef ZFS_DEBUG
@@ -707,7 +708,28 @@ send_worker(void *arg)
{
struct send_worker_ctx *ctx = arg;
unsigned int bufsiz = max_pipe_buffer(ctx->from);
ssize_t rd;
sigset_t block_mask;
ssize_t rd = -1;
/*
* When users request verbose status information about the
* send progress SIGUSR1 is delivered periodically in libzfs
* to a dedicated thread.
*
* However, we get created before this progress thread is
* created and the signal mask of the parent is only modified to
* block SIGUSR1 afterwards.
*
* Block delivery of USR1 to us such that we don't get
* interrupted and the right thread gets the signal.
*/
sigemptyset(&block_mask);
sigaddset(&block_mask, SIGUSR1);
int err = pthread_sigmask(SIG_BLOCK, &block_mask, NULL);
if (err != 0) {
close(ctx->from);
return ((void *)(uintptr_t)err);
}
for (;;) {
rd = splice(ctx->from, NULL, ctx->to, NULL, bufsiz,
@@ -715,7 +737,8 @@ send_worker(void *arg)
if ((rd == -1 && errno != EINTR) || rd == 0)
break;
}
int err = (rd == -1) ? errno : 0;
err = (rd == -1) ? errno : 0;
close(ctx->from);
return ((void *)(uintptr_t)err);
}
@@ -18,104 +18,24 @@
#include <libzfs_core.h>
#include "libzfs_core_impl.h"
int zfs_ioctl_version = ZFS_IOCVER_UNDEF;
/*
* Get zfs_ioctl_version
*/
static int
get_zfs_ioctl_version(void)
{
size_t ver_size;
int ver = ZFS_IOCVER_NONE;
ver_size = sizeof (ver);
(void) sysctlbyname("vfs.zfs.version.ioctl", &ver, &ver_size, NULL, 0);
return (ver);
}
static int
zcmd_ioctl_compat(int fd, int request, zfs_cmd_t *zc, const int cflag)
{
int ret;
#ifdef ZFS_LEGACY_SUPPORT
int newrequest;
void *zc_c = NULL;
#endif
unsigned long ncmd;
zfs_iocparm_t zp;
switch (cflag) {
case ZFS_CMD_COMPAT_NONE:
ncmd = _IOWR('Z', request, zfs_iocparm_t);
zp.zfs_cmd = (uint64_t)(uintptr_t)zc;
zp.zfs_cmd_size = sizeof (zfs_cmd_t);
zp.zfs_ioctl_version = ZFS_IOCVER_OZFS;
break;
#ifdef ZFS_LEGACY_SUPPORT
case ZFS_CMD_COMPAT_LEGACY:
newrequest = zfs_ioctl_ozfs_to_legacy(request);
ncmd = _IOWR('Z', newrequest, zfs_iocparm_t);
zc_c = malloc(sizeof (zfs_cmd_legacy_t));
zfs_cmd_ozfs_to_legacy(zc, zc_c);
zp.zfs_cmd = (uint64_t)(uintptr_t)zc_c;
zp.zfs_cmd_size = sizeof (zfs_cmd_legacy_t);
zp.zfs_ioctl_version = ZFS_IOCVER_LEGACY;
break;
#endif
default:
abort();
return (EINVAL);
}
ret = ioctl(fd, ncmd, &zp);
if (ret) {
#ifdef ZFS_LEGACY_SUPPORT
if (zc_c)
free(zc_c);
#endif
return (ret);
}
#ifdef ZFS_LEGACY_SUPPORT
if (zc_c) {
zfs_cmd_legacy_to_ozfs(zc_c, zc);
free(zc_c);
}
#endif
return (ret);
}
/*
* This is FreeBSD version of ioctl, because Solaris' ioctl() updates
* zc_nvlist_dst_size even if an error is returned, on FreeBSD if an
* error is returned zc_nvlist_dst_size won't be updated.
*/
int
lzc_ioctl_fd_os(int fd, unsigned long request, zfs_cmd_t *zc)
{
size_t oldsize;
int ret, cflag = ZFS_CMD_COMPAT_NONE;
/* Wrap zfs_cmd_t in zfs_iocparm_t, see zfs_ioctl_compat.h */
zfs_iocparm_t zp = {
.zfs_cmd = (uint64_t)(uintptr_t)zc,
.zfs_cmd_size = sizeof (zfs_cmd_t),
.zfs_ioctl_version = ZFS_IOCVER_OZFS,
};
if (zfs_ioctl_version == ZFS_IOCVER_UNDEF)
zfs_ioctl_version = get_zfs_ioctl_version();
/*
* Solaris' ioctl() updates zc_nvlist_dst_size even if an error is
* returned, on FreeBSD if an error is returned zc_nvlist_dst_size
* won't be updated.
*/
size_t oldsize = zc->zc_nvlist_dst_size;
switch (zfs_ioctl_version) {
#ifdef ZFS_LEGACY_SUPPORT
case ZFS_IOCVER_LEGACY:
cflag = ZFS_CMD_COMPAT_LEGACY;
break;
#endif
case ZFS_IOCVER_OZFS:
cflag = ZFS_CMD_COMPAT_NONE;
break;
default:
errx(1, "unrecognized zfs ioctl version %d",
zfs_ioctl_version);
}
oldsize = zc->zc_nvlist_dst_size;
ret = zcmd_ioctl_compat(fd, request, zc, cflag);
int ret = ioctl(fd, _IOWR('Z', request, zfs_iocparm_t), &zp);
if (ret == 0 && oldsize < zc->zc_nvlist_dst_size) {
ret = -1;
+2 -2
View File
@@ -54,8 +54,6 @@ ZCP_SOURCES = \
module/zfs/zcp_synctask.c
nodist_libzpool_la_SOURCES = \
module/os/linux/zfs/zio_crypt.c \
\
module/zcommon/cityhash.c \
module/zcommon/simd_stat.c \
module/zcommon/zfeature_common.c \
@@ -194,6 +192,8 @@ nodist_libzpool_la_SOURCES = \
module/zfs/zio.c \
module/zfs/zio_checksum.c \
module/zfs/zio_compress.c \
module/zfs/zio_crypt.c \
module/zfs/zio_crypt_os_icp.c \
module/zfs/zio_inject.c \
module/zfs/zle.c \
module/zfs/zrlock.c \
@@ -6,4 +6,5 @@ libzpool_sys_HEADERS = \
%D%/sys/trace_zfs.h \
%D%/sys/zfs_bootenv_os.h \
%D%/sys/zfs_context_os.h \
%D%/sys/zfs_debug_os.h
%D%/sys/zfs_debug_os.h \
%D%/sys/zio_crypt_os.h
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: CDDL-1.0
/*
* This file and its contents are supplied under the terms of the
* Common Development and Distribution License ("CDDL"), version 1.0.
* You may only use this file in accordance with the terms of version
* 1.0 of the CDDL.
*
* A full copy of the text of the CDDL should have accompanied this
* source. A copy of the CDDL is also available via the Internet at
* https://opensource.org/license/CDDL-1.0.
*/
/*
* Copyright (c) 2017, Datto, Inc. All rights reserved.
* Copyright (c) 2026, TrueNAS.
*/
#ifndef _SYS_ZIO_CRYPT_OS_H
#define _SYS_ZIO_CRYPT_OS_H
/* libzpool always uses the ICP backend. */
#include <sys/zio_crypt_os_icp.h>
#endif
+9 -42
View File
@@ -274,9 +274,6 @@ pool_active(void *unused, const char *name, uint64_t guid, boolean_t *isactive)
(void) unused, (void) guid;
zfs_iocparm_t zp;
zfs_cmd_t *zc = NULL;
#ifdef ZFS_LEGACY_SUPPORT
zfs_cmd_legacy_t *zcl = NULL;
#endif
unsigned long request;
int ret;
@@ -290,48 +287,18 @@ pool_active(void *unused, const char *name, uint64_t guid, boolean_t *isactive)
* therefore we manually craft the stats command. Note that the command
* ID is identical between the openzfs and legacy ioctl() formats.
*/
int ver = ZFS_IOCVER_NONE;
size_t ver_size = sizeof (ver);
zc = umem_zalloc(sizeof (zfs_cmd_t), UMEM_NOFAIL);
sysctlbyname("vfs.zfs.version.ioctl", &ver, &ver_size, NULL, 0);
(void) strlcpy(zc->zc_name, name, sizeof (zc->zc_name));
zp.zfs_cmd = (uint64_t)(uintptr_t)zc;
zp.zfs_cmd_size = sizeof (zfs_cmd_t);
zp.zfs_ioctl_version = ZFS_IOCVER_OZFS;
switch (ver) {
case ZFS_IOCVER_OZFS:
zc = umem_zalloc(sizeof (zfs_cmd_t), UMEM_NOFAIL);
request = _IOWR('Z', ZFS_IOC_POOL_STATS, zfs_iocparm_t);
ret = ioctl(fd, request, &zp);
(void) strlcpy(zc->zc_name, name, sizeof (zc->zc_name));
zp.zfs_cmd = (uint64_t)(uintptr_t)zc;
zp.zfs_cmd_size = sizeof (zfs_cmd_t);
zp.zfs_ioctl_version = ZFS_IOCVER_OZFS;
request = _IOWR('Z', ZFS_IOC_POOL_STATS, zfs_iocparm_t);
ret = ioctl(fd, request, &zp);
free((void *)(uintptr_t)zc->zc_nvlist_dst);
umem_free(zc, sizeof (zfs_cmd_t));
break;
#ifdef ZFS_LEGACY_SUPPORT
case ZFS_IOCVER_LEGACY:
zcl = umem_zalloc(sizeof (zfs_cmd_legacy_t), UMEM_NOFAIL);
(void) strlcpy(zcl->zc_name, name, sizeof (zcl->zc_name));
zp.zfs_cmd = (uint64_t)(uintptr_t)zcl;
zp.zfs_cmd_size = sizeof (zfs_cmd_legacy_t);
zp.zfs_ioctl_version = ZFS_IOCVER_LEGACY;
request = _IOWR('Z', ZFS_IOC_POOL_STATS, zfs_iocparm_t);
ret = ioctl(fd, request, &zp);
free((void *)(uintptr_t)zcl->zc_nvlist_dst);
umem_free(zcl, sizeof (zfs_cmd_legacy_t));
break;
#endif
default:
fprintf(stderr, "unrecognized zfs ioctl version %d", ver);
exit(1);
}
free((void *)(uintptr_t)zc->zc_nvlist_dst);
umem_free(zc, sizeof (zfs_cmd_t));
(void) close(fd);
+26 -1
View File
@@ -16,7 +16,7 @@
.\" Copyright (c) 2026, Mateusz Piotrowski <[email protected]>
.\" Copyright (c) 2026, TrueNAS.
.\"
.Dd July 12, 2026
.Dd September 9, 2026
.Dt ZFS 4
.Os
.
@@ -1810,6 +1810,31 @@ directory by setting the
.Em nosuid
mount option.
.
.It Sy zfs_sb_uuid Ns = Ns Sy 1 Ns | Ns 0 Pq int
Set the filesystem UUID of a filesystem, snapshot, or clone at mount time,
from the pool GUID and the dataset GUID, as the
.Sy guid
property in
.Xr zfsprops 7
describes.
Set to
.Sy 0
to leave the UUID null, as releases without this parameter did, for example
when stale overlayfs file handles block a mount after an upgrade; see the
.Sx Filesystem UUIDs and Overlayfs
section of
.Xr zpool-reguid 8 .
A change applies to the filesystems that are mounted after the change.
For the filesystems that mount at boot, set the parameter before the first
mount, on the kernel command line as
.Sy zfs.zfs_sb_uuid=0
or in a
.Pa modprobe.d
file as
.Sy options zfs zfs_sb_uuid=0 .
When the root filesystem is on ZFS, the initramfs must include that file.
This parameter only applies on Linux.
.
.It Sy zfs_flags Ns = Ns Sy 0 Pq int
Set additional debugging flags.
The following flags may be bitwise-ored together:
@@ -62,6 +62,17 @@ File system snapshots can be accessed under the
directory in the root of the file system.
Snapshots are automatically mounted on demand and may be unmounted at regular
intervals.
On Linux, an entry under
.Pa .zfs/snapshot
reports the fsid of its snapshot from
.Xr statfs 2
whether or not the snapshot is currently mounted, so a snapshot can be
identified without mounting it by opening the entry with
.Dv O_PATH ,
which does not trigger the automount, and calling
.Xr fstatfs 2
on the descriptor, as an NFS server does to resolve a file handle whose
snapshot is not mounted.
The availability and visibility of the
.Pa .zfs
directory can be controlled by the
+43 -1
View File
@@ -29,7 +29,7 @@
.\" Copyright (c) 2019, Kjeld Schouten-Lebbing
.\" Copyright (c) 2022 Hewlett Packard Enterprise Development LP.
.\"
.Dd September 13, 2025
.Dd September 9, 2026
.Dt ZFSPROPS 7
.Os
.
@@ -190,6 +190,48 @@ GUID.
Thus, the
.Sy guid
is suitable to identify a snapshot across pools.
.Pp
On Linux, each mounted filesystem, snapshot, and clone reports a 128-bit
filesystem UUID to the kernel, which the
.Sy FS_IOC_GETFSUUID
ioctl returns.
The first half of the UUID is the GUID of the pool and the second half is
the
.Sy guid
of the dataset, so the first and the last 16 hexadecimal digits of the UUID
show the two GUIDs in hexadecimal.
The UUID is not a valid RFC 4122 UUID.
Linux overlayfs stores the UUID in its persistent file handles, and the
.Sy fsuuid Ns =
rules of IMA policies match it.
.Pp
The UUID of a mounted filesystem does not change until its next mount.
At the next mount, it shows a new pool GUID after
.Nm zpool Cm reguid
or in the new pool of
.Nm zpool Cm split ,
and a new dataset
.Sy guid
after
.Nm zfs Cm receive
re-created the filesystem.
A snapshot that
.Nm zfs Cm receive
created in the same pool has the same
.Sy guid ,
and thus the same UUID, as the snapshot that it was sent from.
Earlier OpenZFS releases reported a null UUID, so the first mount after an
upgrade changes the UUID as well.
The
.Sx Filesystem UUIDs and Overlayfs
section of
.Xr zpool-reguid 8
describes the effect of a UUID change on overlayfs and the recovery.
The
.Sy zfs_sb_uuid
module parameter of
.Xr zfs 4
restores the null UUID.
.It Sy logicalreferenced
The amount of space that is
.Qq logically
@@ -669,7 +669,7 @@ in the output of
.Nm zpool Cm status .
In case of encrypted filesystems with unloaded keys we are unable to check
their snapshots or clones for errors and these will not be reported.
An "access denied" error will be reported.
The error block itself is reported against the filesystem, without a filename.
.Pp
\*[instant-never]
.
+5 -5
View File
@@ -18,7 +18,7 @@
.\" Copyright (c) 2017 Open-E, Inc. All Rights Reserved.
.\" Copyright (c) 2026 Seagate Technology, LLC.
.\"
.Dd August 6, 2025
.Dd September 21, 2026
.Dt ZPOOLCONCEPTS 7
.Os
.
@@ -193,15 +193,15 @@ For more information, see the
section.
.It Sy dedup
A device solely dedicated for deduplication tables.
The redundancy of this device should match the redundancy of the other normal
devices in the pool.
The redundancy of this device should match or exceed the redundancy of the
other normal devices in the pool.
If more than one dedup device is specified, then
allocations are load-balanced between those devices.
.It Sy special
A device dedicated solely for allocating various kinds of internal metadata,
and optionally small file blocks.
The redundancy of this device should match the redundancy of the other normal
devices in the pool.
The redundancy of this device should match or exceed the redundancy of the
other normal devices in the pool.
If more than one special device is specified, then
allocations are load-balanced between those devices.
.Pp
Loaded 100 of 237 files, more files were not shown because too many files have changed in this diff. Show more