mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-28 19:34:43 +01:00
zfs: merge openzfs/zfs@1f380a4f3
Notable upstream pull request merges: #17864e903655c5zpool: 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 #19031994fb1703Fix metaslab count assertion in metaslab_group_alloc() for small vdevs #19093f5b2fc8e2zfs_ctldir: make .zfs/snapshot/<name> btime the snapshot creation time #190972dece2a34zstream: report invalid record context without assertions #1910278f49e1ddvdev_disk: simplify alignment checks for linear ABDs #19108 -multiple Fix permanent errors misfiled into the scrub error log #19110fa4bc4decspa_errlog: don't let one unresolvable entry hide the whole error log #19116b6dde8a17zio_crypt: free the key unwrap uios when decryption fails #19122 -multiple Fix dd_lock contention on space accounting #19126c792317f2Avoid dp_lock in the dirty space accounting #191317fd87803eMake the spa_config_lock reader fast path lockless #19137a83d96835libzfs: do not iterate snapshots for a mountpoint changelist #19152ccce78729ZIO: Order a batch arrival against the hold it releases #191559d7260c9bPropagate vdev state change on probe failure #19157946be3a33FreeBSD: remove legacy ioctl support #191651d9c32c16zpool: accept more redundant special and dedup vdevs #19167638abd22azfs_domount: fix vfs_t double-free on root setup failure Obtained from: OpenZFS OpenZFS commit:1f380a4f34
This commit is contained in:
commit
34f9f5680c
237 files changed
+6119
-5813
No files matched your search
@@ -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
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
+20
-48
@@ -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);
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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 #
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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])
|
||||
])
|
||||
])
|
||||
])
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
.
|
||||
|
||||
@@ -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
Reference in new issue
Block a user