diff --git a/META b/META index 76e59a42074c..3fd6c578c77d 100644 --- a/META +++ b/META @@ -1,10 +1,10 @@ Meta: 1 Name: zfs Branch: 1.0 -Version: 2.1.4 +Version: 2.1.5 Release: 1 Release-Tags: relext License: CDDL Author: OpenZFS -Linux-Maximum: 5.17 +Linux-Maximum: 5.18 Linux-Minimum: 3.10 diff --git a/Makefile.am b/Makefile.am index 34fe16ce4118..7e2b10b39dee 100644 --- a/Makefile.am +++ b/Makefile.am @@ -103,7 +103,7 @@ endif endif PHONY += codecheck -codecheck: cstyle shellcheck checkbashisms flake8 mancheck testscheck vcscheck +codecheck: cstyle shellcheck checkbashisms flake8 mancheck testscheck vcscheck zstdcheck PHONY += checkstyle checkstyle: codecheck commitcheck @@ -120,6 +120,7 @@ cstyle: -o -type f -name '*.[hc]' \ ! -name 'zfs_config.*' ! -name '*.mod.c' \ ! -name 'opt_global.h' ! -name '*_if*.h' \ + ! -name 'zstd_compat_wrapper.h' \ ! -path './module/zstd/lib/*' \ -exec ${top_srcdir}/scripts/cstyle.pl -cpP {} \+ @@ -173,6 +174,10 @@ vcscheck: awk '{c++; print} END {if(c>0) exit 1}' ; \ fi +PHONY += zstdcheck +zstdcheck: + @$(MAKE) -C module/zstd checksymbols + PHONY += lint lint: cppcheck paxcheck diff --git a/cmd/zdb/zdb.c b/cmd/zdb/zdb.c index 9de41cef2003..1a6dcf82137a 100644 --- a/cmd/zdb/zdb.c +++ b/cmd/zdb/zdb.c @@ -110,6 +110,7 @@ extern int zfs_recover; extern unsigned long zfs_arc_meta_min, zfs_arc_meta_limit; extern int zfs_vdev_async_read_max_active; extern boolean_t spa_load_verify_dryrun; +extern boolean_t spa_mode_readable_spacemaps; extern int zfs_reconstruct_indirect_combinations_max; extern int zfs_btree_verify_intensity; @@ -3124,13 +3125,18 @@ dump_znode_symlink(sa_handle_t *hdl) { int sa_symlink_size = 0; char linktarget[MAXPATHLEN]; - linktarget[0] = '\0'; int error; error = sa_size(hdl, sa_attr_table[ZPL_SYMLINK], &sa_symlink_size); if (error || sa_symlink_size == 0) { return; } + if (sa_symlink_size >= sizeof (linktarget)) { + (void) printf("symlink size %d is too large\n", + sa_symlink_size); + return; + } + linktarget[sa_symlink_size] = '\0'; if (sa_lookup(hdl, sa_attr_table[ZPL_SYMLINK], &linktarget, sa_symlink_size) == 0) (void) printf("\ttarget %s\n", linktarget); @@ -8469,6 +8475,11 @@ main(int argc, char **argv) */ spa_load_verify_dryrun = B_TRUE; + /* + * ZDB should have ability to read spacemaps. + */ + spa_mode_readable_spacemaps = B_TRUE; + kernel_init(SPA_MODE_READ); if (dump_all) diff --git a/cmd/zed/agents/zfs_diagnosis.c b/cmd/zed/agents/zfs_diagnosis.c index 0b27f6702ee8..9f646f9e335c 100644 --- a/cmd/zed/agents/zfs_diagnosis.c +++ b/cmd/zed/agents/zfs_diagnosis.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "zfs_agents.h" #include "fmd_api.h" @@ -773,6 +774,8 @@ zfs_fm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class) ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_PROBE_FAILURE))) { char *failmode = NULL; boolean_t checkremove = B_FALSE; + uint32_t pri = 0; + int32_t flags = 0; /* * If this is a checksum or I/O error, then toss it into the @@ -795,6 +798,23 @@ zfs_fm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class) checkremove = B_TRUE; } else if (fmd_nvl_class_match(hdl, nvl, ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_CHECKSUM))) { + /* + * We ignore ereports for checksum errors generated by + * scrub/resilver I/O to avoid potentially further + * degrading the pool while it's being repaired. + */ + if (((nvlist_lookup_uint32(nvl, + FM_EREPORT_PAYLOAD_ZFS_ZIO_PRIORITY, &pri) == 0) && + (pri == ZIO_PRIORITY_SCRUB || + pri == ZIO_PRIORITY_REBUILD)) || + ((nvlist_lookup_int32(nvl, + FM_EREPORT_PAYLOAD_ZFS_ZIO_FLAGS, &flags) == 0) && + (flags & (ZIO_FLAG_SCRUB | ZIO_FLAG_RESILVER)))) { + fmd_hdl_debug(hdl, "ignoring '%s' for " + "scrub/resilver I/O", class); + return; + } + if (zcp->zc_data.zc_serd_checksum[0] == '\0') { zfs_serd_name(zcp->zc_data.zc_serd_checksum, pool_guid, vdev_guid, "checksum"); diff --git a/cmd/zed/zed.d/zed-functions.sh b/cmd/zed/zed.d/zed-functions.sh index 290f9150b43f..567f7ae3cb11 100644 --- a/cmd/zed/zed.d/zed-functions.sh +++ b/cmd/zed/zed.d/zed-functions.sh @@ -224,6 +224,8 @@ zed_notify() # ZED_EMAIL_OPTS. This undergoes the following keyword substitutions: # - @ADDRESS@ is replaced with the space-delimited recipient email address(es) # - @SUBJECT@ is replaced with the notification subject +# If @SUBJECT@ was omited here, a "Subject: ..." header will be added to notification +# # # Arguments # subject: notification subject @@ -241,7 +243,7 @@ zed_notify() # zed_notify_email() { - local subject="$1" + local subject="${1:-"ZED notification"}" local pathname="${2:-"/dev/null"}" : "${ZED_EMAIL_PROG:="mail"}" @@ -262,12 +264,23 @@ zed_notify_email() return 1 fi - ZED_EMAIL_OPTS="$(echo "${ZED_EMAIL_OPTS}" \ + # construct cmdline options + ZED_EMAIL_OPTS_PARSED="$(echo "${ZED_EMAIL_OPTS}" \ | sed -e "s/@ADDRESS@/${ZED_EMAIL_ADDR}/g" \ -e "s/@SUBJECT@/${subject}/g")" - # shellcheck disable=SC2086 - eval ${ZED_EMAIL_PROG} ${ZED_EMAIL_OPTS} < "${pathname}" >/dev/null 2>&1 + # pipe message to email prog + # shellcheck disable=SC2086,SC2248 + { + # no subject passed as option? + if [ "${ZED_EMAIL_OPTS%@SUBJECT@*}" = "${ZED_EMAIL_OPTS}" ] ; then + # inject subject header + printf "Subject: %s\n" "${subject}" + fi + # output message + cat "${pathname}" + } | + eval ${ZED_EMAIL_PROG} ${ZED_EMAIL_OPTS_PARSED} >/dev/null 2>&1 rv=$? if [ "${rv}" -ne 0 ]; then zed_log_err "${ZED_EMAIL_PROG##*/} exit=${rv}" diff --git a/cmd/zed/zed.d/zed.rc b/cmd/zed/zed.d/zed.rc index 9ac77f929c73..227b26c26b50 100644 --- a/cmd/zed/zed.d/zed.rc +++ b/cmd/zed/zed.d/zed.rc @@ -30,6 +30,7 @@ ZED_EMAIL_ADDR="root" # The string @SUBJECT@ will be replaced with the notification subject; # this should be protected with quotes to prevent word-splitting. # Email will only be sent if ZED_EMAIL_ADDR is defined. +# If @SUBJECT@ was omited here, a "Subject: ..." header will be added to notification # #ZED_EMAIL_OPTS="-s '@SUBJECT@' @ADDRESS@" diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c index d0bb73a72513..6f0c846fddee 100644 --- a/cmd/zfs/zfs_main.c +++ b/cmd/zfs/zfs_main.c @@ -6593,7 +6593,7 @@ zfs_do_holds(int argc, char **argv) /* * 1. collect holds data, set format options */ - ret = zfs_for_each(argc, argv, flags, types, NULL, NULL, limit, + ret = zfs_for_each(1, argv + i, flags, types, NULL, NULL, limit, holds_callback, &cb); if (ret != 0) ++errors; @@ -7672,7 +7672,7 @@ zfs_do_diff(int argc, char **argv) int c; struct sigaction sa; - while ((c = getopt(argc, argv, "FHt")) != -1) { + while ((c = getopt(argc, argv, "FHth")) != -1) { switch (c) { case 'F': flags |= ZFS_DIFF_CLASSIFY; @@ -7683,6 +7683,9 @@ zfs_do_diff(int argc, char **argv) case 't': flags |= ZFS_DIFF_TIMESTAMP; break; + case 'h': + flags |= ZFS_DIFF_NO_MANGLE; + break; default: (void) fprintf(stderr, gettext("invalid option '%c'\n"), optopt); diff --git a/cmd/zvol_wait/zvol_wait b/cmd/zvol_wait/zvol_wait index 2aa929b0ca2b..f1fa42e27dc9 100755 --- a/cmd/zvol_wait/zvol_wait +++ b/cmd/zvol_wait/zvol_wait @@ -28,15 +28,17 @@ filter_out_deleted_zvols() { list_zvols() { read -r default_volmode < /sys/module/zfs/parameters/zvol_volmode zfs list -t volume -H -o \ - name,volmode,receive_resume_token,redact_snaps | - while IFS=" " read -r name volmode token redacted; do # IFS=\t here! + name,volmode,receive_resume_token,redact_snaps,keystatus | + while IFS=" " read -r name volmode token redacted keystatus; do # IFS=\t here! - # /dev links are not created for zvols with volmode = "none" - # or for redacted zvols. + # /dev links are not created for zvols with volmode = "none", + # redacted zvols, or encrypted zvols for which the key has not + # been loaded. [ "$volmode" = "none" ] && continue [ "$volmode" = "default" ] && [ "$default_volmode" = "3" ] && continue [ "$redacted" = "-" ] || continue + [ "$keystatus" = "unavailable" ] && continue # We also ignore partially received zvols if it is # not an incremental receive, as those won't even have a block diff --git a/config/ax_python_devel.m4 b/config/ax_python_devel.m4 index fcf73dc20880..7adcf01a04cd 100644 --- a/config/ax_python_devel.m4 +++ b/config/ax_python_devel.m4 @@ -224,7 +224,7 @@ EOD` ac_python_version=$PYTHON_VERSION else ac_python_version=`$PYTHON -c "import sys; \ - print (sys.version[[:3]])"` + print ('.'.join(sys.version.split('.')[[:2]]))"` fi fi diff --git a/config/kernel-add-disk.m4 b/config/kernel-add-disk.m4 index 5d1779eb4328..44a8a5fd25b6 100644 --- a/config/kernel-add-disk.m4 +++ b/config/kernel-add-disk.m4 @@ -3,16 +3,15 @@ dnl # 5.16 API change dnl # add_disk grew a must-check return code dnl # AC_DEFUN([ZFS_AC_KERNEL_SRC_ADD_DISK], [ - ZFS_LINUX_TEST_SRC([add_disk_ret], [ - #include + #include ], [ struct gendisk *disk = NULL; int err = add_disk(disk); err = err; ]) - ]) + AC_DEFUN([ZFS_AC_KERNEL_ADD_DISK], [ AC_MSG_CHECKING([whether add_disk() returns int]) ZFS_LINUX_TEST_RESULT([add_disk_ret], diff --git a/config/kernel-bio.m4 b/config/kernel-bio.m4 index d088d7023cb0..18620ca5b7e4 100644 --- a/config/kernel-bio.m4 +++ b/config/kernel-bio.m4 @@ -464,7 +464,7 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLK_CGROUP_HEADER], [ ]) AC_DEFUN([ZFS_AC_KERNEL_BLK_CGROUP_HEADER], [ - AC_MSG_CHECKING([for existence of linux/blk-cgroup.h]) + AC_MSG_CHECKING([whether linux/blk-cgroup.h exists]) ZFS_LINUX_TEST_RESULT([blk_cgroup_header],[ AC_MSG_RESULT(yes) AC_DEFINE(HAVE_LINUX_BLK_CGROUP_HEADER, 1, @@ -474,6 +474,41 @@ AC_DEFUN([ZFS_AC_KERNEL_BLK_CGROUP_HEADER], [ ]) ]) +dnl # +dnl # Linux 5.18 API +dnl # +dnl # In 07888c665b405b1cd3577ddebfeb74f4717a84c4 ("block: pass a block_device and opf to bio_alloc") +dnl # bio_alloc(gfp_t gfp_mask, unsigned short nr_iovecs) +dnl # became +dnl # bio_alloc(struct block_device *bdev, unsigned short nr_vecs, unsigned int opf, gfp_t gfp_mask) +dnl # however +dnl # > NULL/0 can be passed, both for the +dnl # > passthrough case on a raw request_queue and to temporarily avoid +dnl # > refactoring some nasty code. +dnl # +AC_DEFUN([ZFS_AC_KERNEL_SRC_BIO_ALLOC_4ARG], [ + ZFS_LINUX_TEST_SRC([bio_alloc_4arg], [ + #include + ],[ + gfp_t gfp_mask = 0; + unsigned short nr_iovecs = 0; + struct block_device *bdev = NULL; + unsigned int opf = 0; + + struct bio *__attribute__((unused)) allocated = bio_alloc(bdev, nr_iovecs, opf, gfp_mask); + ]) +]) + +AC_DEFUN([ZFS_AC_KERNEL_BIO_ALLOC_4ARG], [ + AC_MSG_CHECKING([whether bio_alloc() wants 4 args]) + ZFS_LINUX_TEST_RESULT([bio_alloc_4arg],[ + AC_MSG_RESULT(yes) + AC_DEFINE([HAVE_BIO_ALLOC_4ARG], 1, [bio_alloc() takes 4 arguments]) + ],[ + AC_MSG_RESULT(no) + ]) +]) + AC_DEFUN([ZFS_AC_KERNEL_SRC_BIO], [ ZFS_AC_KERNEL_SRC_REQ ZFS_AC_KERNEL_SRC_BIO_OPS @@ -488,6 +523,7 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BIO], [ ZFS_AC_KERNEL_SRC_BDEV_SUBMIT_BIO_RETURNS_VOID ZFS_AC_KERNEL_SRC_BIO_SET_DEV_MACRO ZFS_AC_KERNEL_SRC_BLK_CGROUP_HEADER + ZFS_AC_KERNEL_SRC_BIO_ALLOC_4ARG ]) AC_DEFUN([ZFS_AC_KERNEL_BIO], [ @@ -512,4 +548,5 @@ AC_DEFUN([ZFS_AC_KERNEL_BIO], [ ZFS_AC_KERNEL_BIO_BDEV_DISK ZFS_AC_KERNEL_BDEV_SUBMIT_BIO_RETURNS_VOID ZFS_AC_KERNEL_BLK_CGROUP_HEADER + ZFS_AC_KERNEL_BIO_ALLOC_4ARG ]) diff --git a/config/kernel-blk-queue.m4 b/config/kernel-blk-queue.m4 index ff5d2d370e98..16251726ccfe 100644 --- a/config/kernel-blk-queue.m4 +++ b/config/kernel-blk-queue.m4 @@ -74,6 +74,8 @@ AC_DEFUN([ZFS_AC_KERNEL_BLK_QUEUE_UPDATE_READAHEAD], [ AC_DEFINE(HAVE_BLK_QUEUE_UPDATE_READAHEAD, 1, [blk_queue_update_readahead() exists]) ],[ + AC_MSG_RESULT(no) + AC_MSG_CHECKING([whether disk_update_readahead() exists]) ZFS_LINUX_TEST_RESULT([disk_update_readahead], [ AC_MSG_RESULT(yes) @@ -86,69 +88,111 @@ AC_DEFUN([ZFS_AC_KERNEL_BLK_QUEUE_UPDATE_READAHEAD], [ ]) dnl # -dnl # 2.6.32 API, -dnl # blk_queue_discard() +dnl # 5.19: bdev_max_discard_sectors() available +dnl # 2.6.32: blk_queue_discard() available dnl # AC_DEFUN([ZFS_AC_KERNEL_SRC_BLK_QUEUE_DISCARD], [ + ZFS_LINUX_TEST_SRC([bdev_max_discard_sectors], [ + #include + ],[ + struct block_device *bdev __attribute__ ((unused)) = NULL; + unsigned int error __attribute__ ((unused)); + + error = bdev_max_discard_sectors(bdev); + ]) + ZFS_LINUX_TEST_SRC([blk_queue_discard], [ #include ],[ - struct request_queue *q __attribute__ ((unused)) = NULL; + struct request_queue r; + struct request_queue *q = &r; int value __attribute__ ((unused)); + memset(q, 0, sizeof(r)); value = blk_queue_discard(q); ]) ]) AC_DEFUN([ZFS_AC_KERNEL_BLK_QUEUE_DISCARD], [ - AC_MSG_CHECKING([whether blk_queue_discard() is available]) - ZFS_LINUX_TEST_RESULT([blk_queue_discard], [ + AC_MSG_CHECKING([whether bdev_max_discard_sectors() is available]) + ZFS_LINUX_TEST_RESULT([bdev_max_discard_sectors], [ AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_BDEV_MAX_DISCARD_SECTORS, 1, + [bdev_max_discard_sectors() is available]) ],[ - ZFS_LINUX_TEST_ERROR([blk_queue_discard]) + AC_MSG_RESULT(no) + + AC_MSG_CHECKING([whether blk_queue_discard() is available]) + ZFS_LINUX_TEST_RESULT([blk_queue_discard], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_BLK_QUEUE_DISCARD, 1, + [blk_queue_discard() is available]) + ],[ + ZFS_LINUX_TEST_ERROR([blk_queue_discard]) + ]) ]) ]) dnl # -dnl # 4.8 API, -dnl # blk_queue_secure_erase() -dnl # -dnl # 2.6.36 - 4.7 API, -dnl # blk_queue_secdiscard() +dnl # 5.19: bdev_max_secure_erase_sectors() available +dnl # 4.8: blk_queue_secure_erase() available +dnl # 2.6.36: blk_queue_secdiscard() available dnl # AC_DEFUN([ZFS_AC_KERNEL_SRC_BLK_QUEUE_SECURE_ERASE], [ + ZFS_LINUX_TEST_SRC([bdev_max_secure_erase_sectors], [ + #include + ],[ + struct block_device *bdev __attribute__ ((unused)) = NULL; + unsigned int error __attribute__ ((unused)); + + error = bdev_max_secure_erase_sectors(bdev); + ]) + ZFS_LINUX_TEST_SRC([blk_queue_secure_erase], [ #include ],[ - struct request_queue *q __attribute__ ((unused)) = NULL; + struct request_queue r; + struct request_queue *q = &r; int value __attribute__ ((unused)); + memset(q, 0, sizeof(r)); value = blk_queue_secure_erase(q); ]) ZFS_LINUX_TEST_SRC([blk_queue_secdiscard], [ #include ],[ - struct request_queue *q __attribute__ ((unused)) = NULL; + struct request_queue r; + struct request_queue *q = &r; int value __attribute__ ((unused)); + memset(q, 0, sizeof(r)); value = blk_queue_secdiscard(q); ]) ]) AC_DEFUN([ZFS_AC_KERNEL_BLK_QUEUE_SECURE_ERASE], [ - AC_MSG_CHECKING([whether blk_queue_secure_erase() is available]) - ZFS_LINUX_TEST_RESULT([blk_queue_secure_erase], [ + AC_MSG_CHECKING([whether bdev_max_secure_erase_sectors() is available]) + ZFS_LINUX_TEST_RESULT([bdev_max_secure_erase_sectors], [ AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_BLK_QUEUE_SECURE_ERASE, 1, - [blk_queue_secure_erase() is available]) + AC_DEFINE(HAVE_BDEV_MAX_SECURE_ERASE_SECTORS, 1, + [bdev_max_secure_erase_sectors() is available]) ],[ AC_MSG_RESULT(no) - AC_MSG_CHECKING([whether blk_queue_secdiscard() is available]) - ZFS_LINUX_TEST_RESULT([blk_queue_secdiscard], [ + AC_MSG_CHECKING([whether blk_queue_secure_erase() is available]) + ZFS_LINUX_TEST_RESULT([blk_queue_secure_erase], [ AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_BLK_QUEUE_SECDISCARD, 1, - [blk_queue_secdiscard() is available]) + AC_DEFINE(HAVE_BLK_QUEUE_SECURE_ERASE, 1, + [blk_queue_secure_erase() is available]) ],[ - ZFS_LINUX_TEST_ERROR([blk_queue_secure_erase]) + AC_MSG_RESULT(no) + + AC_MSG_CHECKING([whether blk_queue_secdiscard() is available]) + ZFS_LINUX_TEST_RESULT([blk_queue_secdiscard], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_BLK_QUEUE_SECDISCARD, 1, + [blk_queue_secdiscard() is available]) + ],[ + ZFS_LINUX_TEST_ERROR([blk_queue_secure_erase]) + ]) ]) ]) ]) diff --git a/config/kernel-blkdev.m4 b/config/kernel-blkdev.m4 index 9c60e5dd4210..fb7b1a458638 100644 --- a/config/kernel-blkdev.m4 +++ b/config/kernel-blkdev.m4 @@ -294,6 +294,57 @@ AC_DEFUN([ZFS_AC_KERNEL_BLKDEV_BDEV_WHOLE], [ ]) ]) +dnl # +dnl # 5.19 API: blkdev_issue_secure_erase() +dnl # 3.10 API: blkdev_issue_discard(..., BLKDEV_DISCARD_SECURE) +dnl # +AC_DEFUN([ZFS_AC_KERNEL_SRC_BLKDEV_ISSUE_SECURE_ERASE], [ + ZFS_LINUX_TEST_SRC([blkdev_issue_secure_erase], [ + #include + ],[ + struct block_device *bdev = NULL; + sector_t sector = 0; + sector_t nr_sects = 0; + int error __attribute__ ((unused)); + + error = blkdev_issue_secure_erase(bdev, + sector, nr_sects, GFP_KERNEL); + ]) + + ZFS_LINUX_TEST_SRC([blkdev_issue_discard_flags], [ + #include + ],[ + struct block_device *bdev = NULL; + sector_t sector = 0; + sector_t nr_sects = 0; + unsigned long flags = 0; + int error __attribute__ ((unused)); + + error = blkdev_issue_discard(bdev, + sector, nr_sects, GFP_KERNEL, flags); + ]) +]) + +AC_DEFUN([ZFS_AC_KERNEL_BLKDEV_ISSUE_SECURE_ERASE], [ + AC_MSG_CHECKING([whether blkdev_issue_secure_erase() is available]) + ZFS_LINUX_TEST_RESULT([blkdev_issue_secure_erase], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_BLKDEV_ISSUE_SECURE_ERASE, 1, + [blkdev_issue_secure_erase() is available]) + ],[ + AC_MSG_RESULT(no) + + AC_MSG_CHECKING([whether blkdev_issue_discard() is available]) + ZFS_LINUX_TEST_RESULT([blkdev_issue_discard_flags], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_BLKDEV_ISSUE_DISCARD, 1, + [blkdev_issue_discard() is available]) + ],[ + ZFS_LINUX_TEST_ERROR([blkdev_issue_discard()]) + ]) + ]) +]) + dnl # dnl # 5.13 API change dnl # blkdev_get_by_path() no longer handles ERESTARTSYS @@ -326,6 +377,7 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLKDEV], [ ZFS_AC_KERNEL_SRC_BLKDEV_CHECK_DISK_CHANGE ZFS_AC_KERNEL_SRC_BLKDEV_BDEV_CHECK_MEDIA_CHANGE ZFS_AC_KERNEL_SRC_BLKDEV_BDEV_WHOLE + ZFS_AC_KERNEL_SRC_BLKDEV_ISSUE_SECURE_ERASE ]) AC_DEFUN([ZFS_AC_KERNEL_BLKDEV], [ @@ -340,4 +392,5 @@ AC_DEFUN([ZFS_AC_KERNEL_BLKDEV], [ ZFS_AC_KERNEL_BLKDEV_BDEV_CHECK_MEDIA_CHANGE ZFS_AC_KERNEL_BLKDEV_BDEV_WHOLE ZFS_AC_KERNEL_BLKDEV_GET_ERESTARTSYS + ZFS_AC_KERNEL_BLKDEV_ISSUE_SECURE_ERASE ]) diff --git a/config/kernel-config-defined.m4 b/config/kernel-config-defined.m4 index c7d18b49b14e..54837d728341 100644 --- a/config/kernel-config-defined.m4 +++ b/config/kernel-config-defined.m4 @@ -19,19 +19,48 @@ AC_DEFUN([ZFS_AC_KERNEL_CONFIG_DEFINED], [ ]) ]) + ZFS_AC_KERNEL_SRC_CONFIG_MODULES + ZFS_AC_KERNEL_SRC_CONFIG_BLOCK ZFS_AC_KERNEL_SRC_CONFIG_DEBUG_LOCK_ALLOC ZFS_AC_KERNEL_SRC_CONFIG_TRIM_UNUSED_KSYMS - ZFS_AC_KERNEL_SRC_CONFIG_ZLIB_INFLATE ZFS_AC_KERNEL_SRC_CONFIG_ZLIB_DEFLATE + ZFS_AC_KERNEL_SRC_CONFIG_ZLIB_INFLATE AC_MSG_CHECKING([for kernel config option compatibility]) ZFS_LINUX_TEST_COMPILE_ALL([config]) AC_MSG_RESULT([done]) + ZFS_AC_KERNEL_CONFIG_MODULES + ZFS_AC_KERNEL_CONFIG_BLOCK ZFS_AC_KERNEL_CONFIG_DEBUG_LOCK_ALLOC ZFS_AC_KERNEL_CONFIG_TRIM_UNUSED_KSYMS - ZFS_AC_KERNEL_CONFIG_ZLIB_INFLATE ZFS_AC_KERNEL_CONFIG_ZLIB_DEFLATE + ZFS_AC_KERNEL_CONFIG_ZLIB_INFLATE +]) + +dnl # +dnl # Check CONFIG_BLOCK +dnl # +dnl # Verify the kernel has CONFIG_BLOCK support enabled. +dnl # +AC_DEFUN([ZFS_AC_KERNEL_SRC_CONFIG_BLOCK], [ + ZFS_LINUX_TEST_SRC([config_block], [ + #if !defined(CONFIG_BLOCK) + #error CONFIG_BLOCK not defined + #endif + ],[]) +]) + +AC_DEFUN([ZFS_AC_KERNEL_CONFIG_BLOCK], [ + AC_MSG_CHECKING([whether CONFIG_BLOCK is defined]) + ZFS_LINUX_TEST_RESULT([config_block], [ + AC_MSG_RESULT([yes]) + ],[ + AC_MSG_RESULT([no]) + AC_MSG_ERROR([ + *** This kernel does not include the required block device support. + *** Rebuild the kernel with CONFIG_BLOCK=y set.]) + ]) ]) dnl # @@ -72,6 +101,61 @@ AC_DEFUN([ZFS_AC_KERNEL_CONFIG_DEBUG_LOCK_ALLOC], [ ]) ]) +dnl # +dnl # Check CONFIG_MODULES +dnl # +dnl # Verify the kernel has CONFIG_MODULES support enabled. +dnl # +AC_DEFUN([ZFS_AC_KERNEL_SRC_CONFIG_MODULES], [ + ZFS_LINUX_TEST_SRC([config_modules], [ + #if !defined(CONFIG_MODULES) + #error CONFIG_MODULES not defined + #endif + ],[]) +]) + +AC_DEFUN([ZFS_AC_KERNEL_CONFIG_MODULES], [ + AC_MSG_CHECKING([whether CONFIG_MODULES is defined]) + AS_IF([test "x$enable_linux_builtin" != xyes], [ + ZFS_LINUX_TEST_RESULT([config_modules], [ + AC_MSG_RESULT([yes]) + ],[ + AC_MSG_RESULT([no]) + AC_MSG_ERROR([ + *** This kernel does not include the required loadable module + *** support! + *** + *** To build OpenZFS as a loadable Linux kernel module + *** enable loadable module support by setting + *** `CONFIG_MODULES=y` in the kernel configuration and run + *** `make modules_prepare` in the Linux source tree. + *** + *** If you don't intend to enable loadable kernel module + *** support, please compile OpenZFS as a Linux kernel built-in. + *** + *** Prepare the Linux source tree by running `make prepare`, + *** use the OpenZFS `--enable-linux-builtin` configure option, + *** copy the OpenZFS sources into the Linux source tree using + *** `./copy-builtin `, + *** set `CONFIG_ZFS=y` in the kernel configuration and compile + *** kernel as usual. + ]) + ]) + ], [ + ZFS_LINUX_TRY_COMPILE([], [], [ + AC_MSG_RESULT([not needed]) + ],[ + AC_MSG_RESULT([error]) + AC_MSG_ERROR([ + *** This kernel is unable to compile object files. + *** + *** Please make sure you prepared the Linux source tree + *** by running `make prepare` there. + ]) + ]) + ]) +]) + dnl # dnl # Check CONFIG_TRIM_UNUSED_KSYMS dnl # diff --git a/config/kernel-copy-from-user-inatomic.m4 b/config/kernel-copy-from-user-inatomic.m4 new file mode 100644 index 000000000000..fec354b2f38e --- /dev/null +++ b/config/kernel-copy-from-user-inatomic.m4 @@ -0,0 +1,29 @@ +dnl # +dnl # On certain architectures `__copy_from_user_inatomic` +dnl # is a GPL exported variable and cannot be used by OpenZFS. +dnl # + +dnl # +dnl # Checking if `__copy_from_user_inatomic` is available. +dnl # +AC_DEFUN([ZFS_AC_KERNEL_SRC___COPY_FROM_USER_INATOMIC], [ + ZFS_LINUX_TEST_SRC([__copy_from_user_inatomic], [ + #include + ], [ + int result __attribute__ ((unused)) = __copy_from_user_inatomic(NULL, NULL, 0); + ], [], [ZFS_META_LICENSE]) +]) + +AC_DEFUN([ZFS_AC_KERNEL___COPY_FROM_USER_INATOMIC], [ + AC_MSG_CHECKING([whether __copy_from_user_inatomic is available]) + ZFS_LINUX_TEST_RESULT([__copy_from_user_inatomic_license], [ + AC_MSG_RESULT(yes) + ], [ + AC_MSG_RESULT(no) + AC_MSG_ERROR([ + *** The `__copy_from_user_inatomic()` Linux kernel function is + *** incompatible with the CDDL license and will prevent the module + *** linking stage from succeeding. OpenZFS cannot be compiled. + ]) + ]) +]) diff --git a/config/kernel-fpu.m4 b/config/kernel-fpu.m4 index 7f8b028d043b..e79632bf9b0c 100644 --- a/config/kernel-fpu.m4 +++ b/config/kernel-fpu.m4 @@ -2,6 +2,9 @@ dnl # dnl # Handle differences in kernel FPU code. dnl # dnl # Kernel +dnl # 5.19: The asm/fpu/internal.h header was removed, it has been +dnl # effectively empty since the 5.16 kernel. +dnl # dnl # 5.16: XCR code put into asm/fpu/xcr.h dnl # HAVE_KERNEL_FPU_XCR_HEADER dnl # @@ -33,21 +36,31 @@ AC_DEFUN([ZFS_AC_KERNEL_FPU_HEADER], [ ],[ AC_DEFINE(HAVE_KERNEL_FPU_API_HEADER, 1, [kernel has asm/fpu/api.h]) - AC_MSG_RESULT(asm/fpu/api.h) - AC_MSG_CHECKING([whether fpu/xcr header is available]) + fpu_headers="asm/fpu/api.h" + ZFS_LINUX_TRY_COMPILE([ #include #include ],[ ],[ AC_DEFINE(HAVE_KERNEL_FPU_XCR_HEADER, 1, - [kernel has asm/fpu/xcr.h]) - AC_MSG_RESULT(asm/fpu/xcr.h) + [kernel has asm/fpu/xcr.h]) + fpu_headers="$fpu_headers asm/fpu/xcr.h" + ]) + + ZFS_LINUX_TRY_COMPILE([ + #include + #include + ],[ ],[ - AC_MSG_RESULT(no asm/fpu/xcr.h) + AC_DEFINE(HAVE_KERNEL_FPU_INTERNAL_HEADER, 1, + [kernel has asm/fpu/internal.h]) + fpu_headers="$fpu_headers asm/fpu/internal.h" ]) + + AC_MSG_RESULT([$fpu_headers]) ],[ - AC_MSG_RESULT(i387.h & xcr.h) + AC_MSG_RESULT([i387.h & xcr.h]) ]) ]) @@ -93,7 +106,9 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_FPU], [ #include #ifdef HAVE_KERNEL_FPU_API_HEADER #include + #ifdef HAVE_KERNEL_FPU_INTERNAL_HEADER #include + #endif #else #include #include @@ -130,7 +145,9 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_FPU], [ #include #ifdef HAVE_KERNEL_FPU_API_HEADER #include + #ifdef HAVE_KERNEL_FPU_INTERNAL_HEADER #include + #endif #else #include #include diff --git a/config/kernel-generic_io_acct.m4 b/config/kernel-generic_io_acct.m4 index 0f4381db4c5e..a8a448c6fe96 100644 --- a/config/kernel-generic_io_acct.m4 +++ b/config/kernel-generic_io_acct.m4 @@ -2,6 +2,19 @@ dnl # dnl # Check for generic io accounting interface. dnl # AC_DEFUN([ZFS_AC_KERNEL_SRC_GENERIC_IO_ACCT], [ + ZFS_LINUX_TEST_SRC([bdev_io_acct], [ + #include + ], [ + struct block_device *bdev = NULL; + struct bio *bio = NULL; + unsigned long passed_time = 0; + unsigned long start_time; + + start_time = bdev_start_io_acct(bdev, bio_sectors(bio), + bio_op(bio), passed_time); + bdev_end_io_acct(bdev, bio_op(bio), start_time); + ]) + ZFS_LINUX_TEST_SRC([disk_io_acct], [ #include ], [ @@ -50,61 +63,75 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_GENERIC_IO_ACCT], [ AC_DEFUN([ZFS_AC_KERNEL_GENERIC_IO_ACCT], [ dnl # - dnl # 5.12 API, + dnl # 5.19 API, dnl # - dnl # bio_start_io_acct() and bio_end_io_acct() became GPL-exported - dnl # so use disk_start_io_acct() and disk_end_io_acct() instead + dnl # disk_start_io_acct() and disk_end_io_acct() have been replaced by + dnl # bdev_start_io_acct() and bdev_end_io_acct(). dnl # - AC_MSG_CHECKING([whether generic disk_*_io_acct() are available]) - ZFS_LINUX_TEST_RESULT([disk_io_acct], [ + AC_MSG_CHECKING([whether generic bdev_*_io_acct() are available]) + ZFS_LINUX_TEST_RESULT([bdev_io_acct], [ AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_DISK_IO_ACCT, 1, [disk_*_io_acct() available]) + AC_DEFINE(HAVE_BDEV_IO_ACCT, 1, [bdev_*_io_acct() available]) ], [ AC_MSG_RESULT(no) dnl # - dnl # 5.7 API, + dnl # 5.12 API, dnl # - dnl # Added bio_start_io_acct() and bio_end_io_acct() helpers. + dnl # bio_start_io_acct() and bio_end_io_acct() became GPL-exported + dnl # so use disk_start_io_acct() and disk_end_io_acct() instead dnl # - AC_MSG_CHECKING([whether generic bio_*_io_acct() are available]) - ZFS_LINUX_TEST_RESULT([bio_io_acct], [ + AC_MSG_CHECKING([whether generic disk_*_io_acct() are available]) + ZFS_LINUX_TEST_RESULT([disk_io_acct], [ AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_BIO_IO_ACCT, 1, [bio_*_io_acct() available]) + AC_DEFINE(HAVE_DISK_IO_ACCT, 1, [disk_*_io_acct() available]) ], [ AC_MSG_RESULT(no) dnl # - dnl # 4.14 API, + dnl # 5.7 API, dnl # - dnl # generic_start_io_acct/generic_end_io_acct now require - dnl # request_queue to be provided. No functional changes, - dnl # but preparation for inflight accounting. + dnl # Added bio_start_io_acct() and bio_end_io_acct() helpers. dnl # - AC_MSG_CHECKING([whether generic_*_io_acct wants 4 args]) - ZFS_LINUX_TEST_RESULT_SYMBOL([generic_acct_4args], - [generic_start_io_acct], [block/bio.c], [ + AC_MSG_CHECKING([whether generic bio_*_io_acct() are available]) + ZFS_LINUX_TEST_RESULT([bio_io_acct], [ AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_GENERIC_IO_ACCT_4ARG, 1, - [generic_*_io_acct() 4 arg available]) + AC_DEFINE(HAVE_BIO_IO_ACCT, 1, [bio_*_io_acct() available]) ], [ AC_MSG_RESULT(no) dnl # - dnl # 3.19 API addition + dnl # 4.14 API, dnl # - dnl # torvalds/linux@394ffa50 allows us to increment - dnl # iostat counters without generic_make_request(). + dnl # generic_start_io_acct/generic_end_io_acct now require + dnl # request_queue to be provided. No functional changes, + dnl # but preparation for inflight accounting. dnl # - AC_MSG_CHECKING( - [whether generic_*_io_acct wants 3 args]) - ZFS_LINUX_TEST_RESULT_SYMBOL([generic_acct_3args], + AC_MSG_CHECKING([whether generic_*_io_acct wants 4 args]) + ZFS_LINUX_TEST_RESULT_SYMBOL([generic_acct_4args], [generic_start_io_acct], [block/bio.c], [ AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_GENERIC_IO_ACCT_3ARG, 1, - [generic_*_io_acct() 3 arg available]) + AC_DEFINE(HAVE_GENERIC_IO_ACCT_4ARG, 1, + [generic_*_io_acct() 4 arg available]) ], [ AC_MSG_RESULT(no) + + dnl # + dnl # 3.19 API addition + dnl # + dnl # torvalds/linux@394ffa50 allows us to increment + dnl # iostat counters without generic_make_request(). + dnl # + AC_MSG_CHECKING( + [whether generic_*_io_acct wants 3 args]) + ZFS_LINUX_TEST_RESULT_SYMBOL([generic_acct_3args], + [generic_start_io_acct], [block/bio.c], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_GENERIC_IO_ACCT_3ARG, 1, + [generic_*_io_acct() 3 arg available]) + ], [ + AC_MSG_RESULT(no) + ]) ]) ]) ]) diff --git a/config/kernel-genhd-flags.m4 b/config/kernel-genhd-flags.m4 new file mode 100644 index 000000000000..af6a8a086bc9 --- /dev/null +++ b/config/kernel-genhd-flags.m4 @@ -0,0 +1,58 @@ +dnl # +dnl # 5.17 API change, +dnl # +dnl # GENHD_FL_EXT_DEVT flag removed +dnl # GENHD_FL_NO_PART_SCAN renamed GENHD_FL_NO_PART +dnl # +AC_DEFUN([ZFS_AC_KERNEL_SRC_GENHD_FLAGS], [ + + ZFS_LINUX_TEST_SRC([genhd_fl_ext_devt], [ + #include + ], [ + int flags __attribute__ ((unused)) = GENHD_FL_EXT_DEVT; + ]) + + ZFS_LINUX_TEST_SRC([genhd_fl_no_part], [ + #include + ], [ + int flags __attribute__ ((unused)) = GENHD_FL_NO_PART; + ]) + + ZFS_LINUX_TEST_SRC([genhd_fl_no_part_scan], [ + #include + ], [ + int flags __attribute__ ((unused)) = GENHD_FL_NO_PART_SCAN; + ]) +]) + +AC_DEFUN([ZFS_AC_KERNEL_GENHD_FLAGS], [ + + AC_MSG_CHECKING([whether GENHD_FL_EXT_DEVT flag is available]) + ZFS_LINUX_TEST_RESULT([genhd_fl_ext_devt], [ + AC_MSG_RESULT(yes) + AC_DEFINE(ZFS_GENHD_FL_EXT_DEVT, GENHD_FL_EXT_DEVT, + [GENHD_FL_EXT_DEVT flag is available]) + ], [ + AC_MSG_RESULT(no) + AC_DEFINE(ZFS_GENHD_FL_EXT_DEVT, 0, + [GENHD_FL_EXT_DEVT flag is not available]) + ]) + + AC_MSG_CHECKING([whether GENHD_FL_NO_PART flag is available]) + ZFS_LINUX_TEST_RESULT([genhd_fl_no_part], [ + AC_MSG_RESULT(yes) + AC_DEFINE(ZFS_GENHD_FL_NO_PART, GENHD_FL_NO_PART, + [GENHD_FL_NO_PART flag is available]) + ], [ + AC_MSG_RESULT(no) + + AC_MSG_CHECKING([whether GENHD_FL_NO_PART_SCAN flag is available]) + ZFS_LINUX_TEST_RESULT([genhd_fl_no_part_scan], [ + AC_MSG_RESULT(yes) + AC_DEFINE(ZFS_GENHD_FL_NO_PART, GENHD_FL_NO_PART_SCAN, + [GENHD_FL_NO_PART_SCAN flag is available]) + ], [ + ZFS_LINUX_TEST_ERROR([GENHD_FL_NO_PART|GENHD_FL_NO_PART_SCAN]) + ]) + ]) +]) diff --git a/config/kernel-group-info.m4 b/config/kernel-group-info.m4 index 0fee1d36d50d..6941d62da017 100644 --- a/config/kernel-group-info.m4 +++ b/config/kernel-group-info.m4 @@ -6,8 +6,8 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_GROUP_INFO_GID], [ ZFS_LINUX_TEST_SRC([group_info_gid], [ #include ],[ - struct group_info *gi = groups_alloc(1); - gi->gid[0] = KGIDT_INIT(0); + struct group_info gi __attribute__ ((unused)) = {}; + gi.gid[0] = KGIDT_INIT(0); ]) ]) diff --git a/config/kernel-mkdir.m4 b/config/kernel-mkdir.m4 index a162bcd880ff..6667ed04fa4c 100644 --- a/config/kernel-mkdir.m4 +++ b/config/kernel-mkdir.m4 @@ -53,6 +53,8 @@ AC_DEFUN([ZFS_AC_KERNEL_MKDIR], [ AC_DEFINE(HAVE_IOPS_MKDIR_USERNS, 1, [iops->mkdir() takes struct user_namespace*]) ],[ + AC_MSG_RESULT(no) + AC_MSG_CHECKING([whether iops->mkdir() takes umode_t]) ZFS_LINUX_TEST_RESULT([inode_operations_mkdir], [ AC_MSG_RESULT(yes) diff --git a/config/kernel-pagemap-folio_wait_bit.m4 b/config/kernel-pagemap-folio_wait_bit.m4 index e0aaa4a57411..12d8841f51e6 100644 --- a/config/kernel-pagemap-folio_wait_bit.m4 +++ b/config/kernel-pagemap-folio_wait_bit.m4 @@ -15,7 +15,7 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_PAGEMAP_FOLIO_WAIT_BIT], [ ]) AC_DEFUN([ZFS_AC_KERNEL_PAGEMAP_FOLIO_WAIT_BIT], [ - AC_MSG_CHECKING([folio_wait_bit() exists]) + AC_MSG_CHECKING([whether folio_wait_bit() exists]) ZFS_LINUX_TEST_RESULT([pagemap_has_folio_wait_bit], [ AC_MSG_RESULT([yes]) AC_DEFINE(HAVE_PAGEMAP_FOLIO_WAIT_BIT, 1, diff --git a/config/kernel-readpages.m4 b/config/kernel-readpages.m4 new file mode 100644 index 000000000000..be65a0d5e4b4 --- /dev/null +++ b/config/kernel-readpages.m4 @@ -0,0 +1,25 @@ +dnl # +dnl # Linux 5.18 removes address_space_operations ->readpages in favour of +dnl # ->readahead +dnl # +AC_DEFUN([ZFS_AC_KERNEL_SRC_VFS_READPAGES], [ + ZFS_LINUX_TEST_SRC([vfs_has_readpages], [ + #include + + static const struct address_space_operations + aops __attribute__ ((unused)) = { + .readpages = NULL, + }; + ],[]) +]) + +AC_DEFUN([ZFS_AC_KERNEL_VFS_READPAGES], [ + AC_MSG_CHECKING([whether aops->readpages exists]) + ZFS_LINUX_TEST_RESULT([vfs_has_readpages], [ + AC_MSG_RESULT([yes]) + AC_DEFINE(HAVE_VFS_READPAGES, 1, + [address_space_operations->readpages exists]) + ],[ + AC_MSG_RESULT([no]) + ]) +]) diff --git a/config/kernel-revalidate-disk-size.m4 b/config/kernel-revalidate-disk-size.m4 index a7d0cb3cdab4..13cb92a174e3 100644 --- a/config/kernel-revalidate-disk-size.m4 +++ b/config/kernel-revalidate-disk-size.m4 @@ -8,14 +8,14 @@ dnl # AC_DEFUN([ZFS_AC_KERNEL_SRC_REVALIDATE_DISK], [ ZFS_LINUX_TEST_SRC([revalidate_disk_size], [ - #include + #include ], [ struct gendisk *disk = NULL; (void) revalidate_disk_size(disk, false); ]) ZFS_LINUX_TEST_SRC([revalidate_disk], [ - #include + #include ], [ struct gendisk *disk = NULL; (void) revalidate_disk(disk); diff --git a/config/kernel-shrink.m4 b/config/kernel-shrink.m4 index a40c86d5c57f..8cf0f2761bde 100644 --- a/config/kernel-shrink.m4 +++ b/config/kernel-shrink.m4 @@ -84,7 +84,7 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_SHRINKER_CALLBACK], [ AC_DEFUN([ZFS_AC_KERNEL_SHRINKER_CALLBACK],[ dnl # dnl # 3.0 - 3.11 API change - dnl # ->shrink(struct shrinker *, struct shrink_control *sc) + dnl # cs->shrink(struct shrinker *, struct shrink_control *sc) dnl # AC_MSG_CHECKING([whether new 2-argument shrinker exists]) ZFS_LINUX_TEST_RESULT([shrinker_cb_shrink_control], [ @@ -96,14 +96,14 @@ AC_DEFUN([ZFS_AC_KERNEL_SHRINKER_CALLBACK],[ dnl # dnl # 3.12 API change, - dnl # ->shrink() is logically split in to - dnl # ->count_objects() and ->scan_objects() + dnl # cs->shrink() is logically split in to + dnl # cs->count_objects() and cs->scan_objects() dnl # - AC_MSG_CHECKING([whether ->count_objects callback exists]) + AC_MSG_CHECKING([whether cs->count_objects callback exists]) ZFS_LINUX_TEST_RESULT([shrinker_cb_shrink_control_split], [ AC_MSG_RESULT(yes) AC_DEFINE(HAVE_SPLIT_SHRINKER_CALLBACK, 1, - [->count_objects exists]) + [cs->count_objects exists]) ],[ ZFS_LINUX_TEST_ERROR([shrinker]) ]) diff --git a/config/kernel-sysfs.m4 b/config/kernel-sysfs.m4 new file mode 100644 index 000000000000..bbc77c8fc5c0 --- /dev/null +++ b/config/kernel-sysfs.m4 @@ -0,0 +1,37 @@ +dnl # +dnl # Linux 5.2/5.18 API +dnl # +dnl # In cdb4f26a63c391317e335e6e683a614358e70aeb ("kobject: kobj_type: remove default_attrs") +dnl # struct kobj_type.default_attrs +dnl # was finally removed in favour of +dnl # struct kobj_type.default_groups +dnl # +dnl # This was added in aa30f47cf666111f6bbfd15f290a27e8a7b9d854 ("kobject: Add support for default attribute groups to kobj_type"), +dnl # if both are present (5.2-5.17), we prefer default_groups; they're otherwise equivalent +dnl # +AC_DEFUN([ZFS_AC_KERNEL_SRC_SYSFS_DEFAULT_GROUPS], [ + ZFS_LINUX_TEST_SRC([sysfs_default_groups], [ + #include + ],[ + struct kobj_type __attribute__ ((unused)) kt = { + .default_groups = (const struct attribute_group **)NULL }; + ]) +]) + +AC_DEFUN([ZFS_AC_KERNEL_SYSFS_DEFAULT_GROUPS], [ + AC_MSG_CHECKING([whether struct kobj_type.default_groups exists]) + ZFS_LINUX_TEST_RESULT([sysfs_default_groups],[ + AC_MSG_RESULT(yes) + AC_DEFINE([HAVE_SYSFS_DEFAULT_GROUPS], 1, [struct kobj_type has default_groups]) + ],[ + AC_MSG_RESULT(no) + ]) +]) + +AC_DEFUN([ZFS_AC_KERNEL_SRC_SYSFS], [ + ZFS_AC_KERNEL_SRC_SYSFS_DEFAULT_GROUPS +]) + +AC_DEFUN([ZFS_AC_KERNEL_SYSFS], [ + ZFS_AC_KERNEL_SYSFS_DEFAULT_GROUPS +]) diff --git a/config/kernel-vfs-filemap_dirty_folio.m4 b/config/kernel-vfs-filemap_dirty_folio.m4 new file mode 100644 index 000000000000..729ca670da03 --- /dev/null +++ b/config/kernel-vfs-filemap_dirty_folio.m4 @@ -0,0 +1,30 @@ +dnl # +dnl # Linux 5.18 uses filemap_dirty_folio in lieu of +dnl # ___set_page_dirty_nobuffers +dnl # +AC_DEFUN([ZFS_AC_KERNEL_SRC_VFS_FILEMAP_DIRTY_FOLIO], [ + ZFS_LINUX_TEST_SRC([vfs_has_filemap_dirty_folio], [ + #include + #include + + static const struct address_space_operations + aops __attribute__ ((unused)) = { + .dirty_folio = filemap_dirty_folio, + }; + ],[]) +]) + +AC_DEFUN([ZFS_AC_KERNEL_VFS_FILEMAP_DIRTY_FOLIO], [ + dnl # + dnl # Linux 5.18 uses filemap_dirty_folio in lieu of + dnl # ___set_page_dirty_nobuffers + dnl # + AC_MSG_CHECKING([whether filemap_dirty_folio exists]) + ZFS_LINUX_TEST_RESULT([vfs_has_filemap_dirty_folio], [ + AC_MSG_RESULT([yes]) + AC_DEFINE(HAVE_VFS_FILEMAP_DIRTY_FOLIO, 1, + [filemap_dirty_folio exists]) + ],[ + AC_MSG_RESULT([no]) + ]) +]) diff --git a/config/kernel-vfs-iov_iter.m4 b/config/kernel-vfs-iov_iter.m4 index 57f78745a24b..e0617faab02c 100644 --- a/config/kernel-vfs-iov_iter.m4 +++ b/config/kernel-vfs-iov_iter.m4 @@ -134,6 +134,8 @@ AC_DEFUN([ZFS_AC_KERNEL_VFS_IOV_ITER], [ AC_DEFINE(HAVE_IOV_ITER_FAULT_IN_READABLE, 1, [iov_iter_fault_in_readable() is available]) ],[ + AC_MSG_RESULT(no) + AC_MSG_CHECKING([whether fault_in_iov_iter_readable() is available]) ZFS_LINUX_TEST_RESULT([fault_in_iov_iter_readable], [ AC_MSG_RESULT(yes) diff --git a/config/kernel-vfs-read_folio.m4 b/config/kernel-vfs-read_folio.m4 new file mode 100644 index 000000000000..9ca0faff218d --- /dev/null +++ b/config/kernel-vfs-read_folio.m4 @@ -0,0 +1,32 @@ +dnl # +dnl # Linux 5.19 uses read_folio in lieu of readpage +dnl # +AC_DEFUN([ZFS_AC_KERNEL_SRC_VFS_READ_FOLIO], [ + ZFS_LINUX_TEST_SRC([vfs_has_read_folio], [ + #include + + static int + test_read_folio(struct file *file, struct folio *folio) { + (void) file; (void) folio; + return (0); + } + + static const struct address_space_operations + aops __attribute__ ((unused)) = { + .read_folio = test_read_folio, + }; + ],[]) +]) + +AC_DEFUN([ZFS_AC_KERNEL_VFS_READ_FOLIO], [ + dnl # + dnl # Linux 5.19 uses read_folio in lieu of readpage + dnl # + AC_MSG_CHECKING([whether read_folio exists]) + ZFS_LINUX_TEST_RESULT([vfs_has_read_folio], [ + AC_MSG_RESULT([yes]) + AC_DEFINE(HAVE_VFS_READ_FOLIO, 1, [read_folio exists]) + ],[ + AC_MSG_RESULT([no]) + ]) +]) diff --git a/config/kernel-vfs-set_page_dirty.m4 b/config/kernel-vfs-set_page_dirty.m4 index a9d252e4e01e..90cb28f3682c 100644 --- a/config/kernel-vfs-set_page_dirty.m4 +++ b/config/kernel-vfs-set_page_dirty.m4 @@ -23,7 +23,7 @@ AC_DEFUN([ZFS_AC_KERNEL_VFS_SET_PAGE_DIRTY_NOBUFFERS], [ dnl # Linux 5.14 change requires set_page_dirty() to be assigned dnl # in address_space_operations() dnl # - AC_MSG_CHECKING([__set_page_dirty_nobuffers exists]) + AC_MSG_CHECKING([whether __set_page_dirty_nobuffers exists]) ZFS_LINUX_TEST_RESULT([vfs_has_set_page_dirty_nobuffers], [ AC_MSG_RESULT([yes]) AC_DEFINE(HAVE_VFS_SET_PAGE_DIRTY_NOBUFFERS, 1, diff --git a/config/kernel-zero_page.m4 b/config/kernel-zero_page.m4 new file mode 100644 index 000000000000..1461781acb41 --- /dev/null +++ b/config/kernel-zero_page.m4 @@ -0,0 +1,27 @@ +dnl # +dnl # ZERO_PAGE() is an alias for emtpy_zero_page. On certain architectures +dnl # this is a GPL exported variable. +dnl # + +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], [ + #include + ], [ + struct page *p __attribute__ ((unused)); + p = ZERO_PAGE(0); + ], [], [ZFS_META_LICENSE]) +]) + +AC_DEFUN([ZFS_AC_KERNEL_ZERO_PAGE], [ + AC_MSG_CHECKING([whether ZERO_PAGE() is GPL-only]) + ZFS_LINUX_TEST_RESULT([zero_page_license], [ + AC_MSG_RESULT(no) + ], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_ZERO_PAGE_GPL_ONLY, 1, + [ZERO_PAGE() is GPL-only]) + ]) +]) diff --git a/config/kernel.m4 b/config/kernel.m4 index 3122e9dbaa94..41492c19d8a5 100644 --- a/config/kernel.m4 +++ b/config/kernel.m4 @@ -8,8 +8,8 @@ AC_DEFUN([ZFS_AC_CONFIG_KERNEL], [ ZFS_AC_QAT dnl # Sanity checks for module building and CONFIG_* defines - ZFS_AC_KERNEL_TEST_MODULE ZFS_AC_KERNEL_CONFIG_DEFINED + ZFS_AC_MODULE_SYMVERS dnl # Sequential ZFS_LINUX_TRY_COMPILE tests ZFS_AC_KERNEL_FPU_HEADER @@ -61,6 +61,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [ ZFS_AC_KERNEL_SRC_BIO ZFS_AC_KERNEL_SRC_BLKDEV ZFS_AC_KERNEL_SRC_BLK_QUEUE + ZFS_AC_KERNEL_SRC_GENHD_FLAGS ZFS_AC_KERNEL_SRC_REVALIDATE_DISK ZFS_AC_KERNEL_SRC_GET_DISK_RO ZFS_AC_KERNEL_SRC_GENERIC_READLINK_GLOBAL @@ -99,10 +100,14 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [ ZFS_AC_KERNEL_SRC_SET_NLINK ZFS_AC_KERNEL_SRC_SGET ZFS_AC_KERNEL_SRC_LSEEK_EXECUTE + ZFS_AC_KERNEL_SRC_VFS_FILEMAP_DIRTY_FOLIO + ZFS_AC_KERNEL_SRC_VFS_READ_FOLIO ZFS_AC_KERNEL_SRC_VFS_GETATTR ZFS_AC_KERNEL_SRC_VFS_FSYNC_2ARGS ZFS_AC_KERNEL_SRC_VFS_ITERATE ZFS_AC_KERNEL_SRC_VFS_DIRECT_IO + ZFS_AC_KERNEL_SRC_VFS_READPAGES + ZFS_AC_KERNEL_SRC_VFS_SET_PAGE_DIRTY_NOBUFFERS ZFS_AC_KERNEL_SRC_VFS_RW_ITERATE ZFS_AC_KERNEL_SRC_VFS_GENERIC_WRITE_CHECKS ZFS_AC_KERNEL_SRC_VFS_IOV_ITER @@ -131,12 +136,14 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [ ZFS_AC_KERNEL_SRC_BIO_MAX_SEGS ZFS_AC_KERNEL_SRC_SIGNAL_STOP ZFS_AC_KERNEL_SRC_SIGINFO + ZFS_AC_KERNEL_SRC_SYSFS ZFS_AC_KERNEL_SRC_SET_SPECIAL_STATE - ZFS_AC_KERNEL_SRC_VFS_SET_PAGE_DIRTY_NOBUFFERS ZFS_AC_KERNEL_SRC_STANDALONE_LINUX_STDARG ZFS_AC_KERNEL_SRC_PAGEMAP_FOLIO_WAIT_BIT ZFS_AC_KERNEL_SRC_ADD_DISK ZFS_AC_KERNEL_SRC_KTHREAD + ZFS_AC_KERNEL_SRC_ZERO_PAGE + ZFS_AC_KERNEL_SRC___COPY_FROM_USER_INATOMIC AC_MSG_CHECKING([for available kernel interfaces]) ZFS_LINUX_TEST_COMPILE_ALL([kabi]) @@ -171,6 +178,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [ ZFS_AC_KERNEL_BIO ZFS_AC_KERNEL_BLKDEV ZFS_AC_KERNEL_BLK_QUEUE + ZFS_AC_KERNEL_GENHD_FLAGS ZFS_AC_KERNEL_REVALIDATE_DISK ZFS_AC_KERNEL_GET_DISK_RO ZFS_AC_KERNEL_GENERIC_READLINK_GLOBAL @@ -209,10 +217,14 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [ ZFS_AC_KERNEL_SET_NLINK ZFS_AC_KERNEL_SGET ZFS_AC_KERNEL_LSEEK_EXECUTE + ZFS_AC_KERNEL_VFS_FILEMAP_DIRTY_FOLIO + ZFS_AC_KERNEL_VFS_READ_FOLIO ZFS_AC_KERNEL_VFS_GETATTR ZFS_AC_KERNEL_VFS_FSYNC_2ARGS ZFS_AC_KERNEL_VFS_ITERATE ZFS_AC_KERNEL_VFS_DIRECT_IO + ZFS_AC_KERNEL_VFS_READPAGES + ZFS_AC_KERNEL_VFS_SET_PAGE_DIRTY_NOBUFFERS ZFS_AC_KERNEL_VFS_RW_ITERATE ZFS_AC_KERNEL_VFS_GENERIC_WRITE_CHECKS ZFS_AC_KERNEL_VFS_IOV_ITER @@ -241,12 +253,14 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [ ZFS_AC_KERNEL_BIO_MAX_SEGS ZFS_AC_KERNEL_SIGNAL_STOP ZFS_AC_KERNEL_SIGINFO + ZFS_AC_KERNEL_SYSFS ZFS_AC_KERNEL_SET_SPECIAL_STATE - ZFS_AC_KERNEL_VFS_SET_PAGE_DIRTY_NOBUFFERS ZFS_AC_KERNEL_STANDALONE_LINUX_STDARG ZFS_AC_KERNEL_PAGEMAP_FOLIO_WAIT_BIT ZFS_AC_KERNEL_ADD_DISK ZFS_AC_KERNEL_KTHREAD + ZFS_AC_KERNEL_ZERO_PAGE + ZFS_AC_KERNEL___COPY_FROM_USER_INATOMIC ]) dnl # @@ -435,8 +449,6 @@ AC_DEFUN([ZFS_AC_KERNEL], [ AC_SUBST(LINUX) AC_SUBST(LINUX_OBJ) AC_SUBST(LINUX_VERSION) - - ZFS_AC_MODULE_SYMVERS ]) dnl # @@ -531,27 +543,6 @@ AC_DEFUN([ZFS_AC_QAT], [ ]) ]) -dnl # -dnl # Basic toolchain sanity check. -dnl # -AC_DEFUN([ZFS_AC_KERNEL_TEST_MODULE], [ - AC_MSG_CHECKING([whether modules can be built]) - ZFS_LINUX_TRY_COMPILE([], [], [ - AC_MSG_RESULT([yes]) - ],[ - AC_MSG_RESULT([no]) - if test "x$enable_linux_builtin" != xyes; then - AC_MSG_ERROR([ - *** Unable to build an empty module. - ]) - else - AC_MSG_ERROR([ - *** Unable to build an empty module. - *** Please run 'make scripts' inside the kernel source tree.]) - fi - ]) -]) - dnl # dnl # ZFS_LINUX_CONFTEST_H dnl # @@ -654,8 +645,10 @@ AC_DEFUN([ZFS_LINUX_COMPILE], [ build kernel modules with LLVM/CLANG toolchain]) AC_TRY_COMMAND([ 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} -C $LINUX_OBJ $ARCH_UM - M=$PWD/$1 >$1/build.log 2>&1]) + make modules -k -j$TEST_JOBS ${KERNEL_CC:+CC=$KERNEL_CC} + ${KERNEL_LD:+LD=$KERNEL_LD} ${KERNEL_LLVM:+LLVM=$KERNEL_LLVM} + CONFIG_MODULES=y CFLAGS_MODULE=-DCONFIG_MODULES + -C $LINUX_OBJ $ARCH_UM M=$PWD/$1 >$1/build.log 2>&1]) AS_IF([AC_TRY_COMMAND([$2])], [$3], [$4]) ]) diff --git a/config/zfs-build.m4 b/config/zfs-build.m4 index 126f78476bd4..c60eb013552e 100644 --- a/config/zfs-build.m4 +++ b/config/zfs-build.m4 @@ -323,6 +323,10 @@ AC_DEFUN([ZFS_AC_RPM], [ RPM_DEFINE_COMMON=${RPM_DEFINE_COMMON}' --define "$(DEBUG_KMEM_TRACKING_ZFS) 1"' RPM_DEFINE_COMMON=${RPM_DEFINE_COMMON}' --define "$(ASAN_ZFS) 1"' + AS_IF([test "x$enable_debuginfo" = xyes], [ + RPM_DEFINE_COMMON=${RPM_DEFINE_COMMON}' --define "__strip /bin/true"' + ]) + RPM_DEFINE_UTIL=' --define "_initconfdir $(initconfdir)"' dnl # Make the next three RPM_DEFINE_UTIL additions conditional, since diff --git a/contrib/dracut/90zfs/export-zfs.sh.in b/contrib/dracut/90zfs/export-zfs.sh.in index 892650383475..9e05ee03a3b6 100755 --- a/contrib/dracut/90zfs/export-zfs.sh.in +++ b/contrib/dracut/90zfs/export-zfs.sh.in @@ -1,14 +1,12 @@ #!/bin/sh -. /lib/dracut-zfs-lib.sh - _do_zpool_export() { ret=0 errs="" final="${1}" info "ZFS: Exporting ZFS storage pools..." - errs=$(export_all -F 2>&1) + errs=$(zpool export -aF 2>&1) ret=$? [ -z "${errs}" ] || echo "${errs}" | vwarn if [ "x${ret}" != "x0" ]; then diff --git a/contrib/dracut/90zfs/module-setup.sh.in b/contrib/dracut/90zfs/module-setup.sh.in index fbf32b6588a9..178c318e0122 100755 --- a/contrib/dracut/90zfs/module-setup.sh.in +++ b/contrib/dracut/90zfs/module-setup.sh.in @@ -6,8 +6,8 @@ check() { [ "${1}" = "-d" ] && return 0 # Verify the zfs tool chain - for tool in "@sbindir@/zgenhostid" "@sbindir@/zpool" "@sbindir@/zfs" "@mounthelperdir@/mount.zfs" ; do - test -x "$tool" || return 1 + for tool in "zgenhostid" "zpool" "zfs" "mount.zfs"; do + command -v "${tool}" >/dev/null || return 1 done return 0 @@ -19,125 +19,85 @@ depends() { } installkernel() { - instmods zfs - instmods zcommon - instmods znvpair - instmods zavl - instmods zunicode - instmods zlua - instmods icp - instmods spl - instmods zlib_deflate - instmods zlib_inflate + instmods -c zfs } install() { - inst_rules @udevruledir@/90-zfs.rules - inst_rules @udevruledir@/69-vdev.rules - inst_rules @udevruledir@/60-zvol.rules - dracut_install hostid - dracut_install grep - dracut_install @sbindir@/zgenhostid - dracut_install @sbindir@/zfs - dracut_install @sbindir@/zpool - # Workaround for https://github.com/openzfs/zfs/issues/4749 by - # ensuring libgcc_s.so(.1) is included - if ldd @sbindir@/zpool | grep -qF 'libgcc_s.so'; then - # Dracut will have already tracked and included it - :; - elif command -v gcc-config >/dev/null 2>&1; then - # On systems with gcc-config (Gentoo, Funtoo, etc.): - # Use the current profile to resolve the appropriate path - s="$(gcc-config -c)" - dracut_install "/usr/lib/gcc/${s%-*}/${s##*-}/libgcc_s.so"* - elif [ "$(echo /usr/lib/libgcc_s.so*)" != "/usr/lib/libgcc_s.so*" ]; then - # Try a simple path first - dracut_install /usr/lib/libgcc_s.so* - elif [ "$(echo /lib*/libgcc_s.so*)" != "/lib*/libgcc_s.so*" ]; then - # SUSE - dracut_install /lib*/libgcc_s.so* - else - # Fallback: Guess the path and include all matches - dracut_install /usr/lib*/gcc/**/libgcc_s.so* - fi - # shellcheck disable=SC2050 - if [ @LIBFETCH_DYNAMIC@ -gt 0 ]; then - for d in $libdirs; do - [ -e "$d/@LIBFETCH_SONAME@" ] && dracut_install "$d/@LIBFETCH_SONAME@" - done + inst_rules 90-zfs.rules 69-vdev.rules 60-zvol.rules + + inst_multiple \ + zgenhostid \ + zfs \ + zpool \ + mount.zfs \ + hostid \ + grep \ + awk \ + tr \ + cut \ + head || + { dfatal "Failed to install essential binaries"; exit 1; } + + # Adapted from https://github.com/zbm-dev/zfsbootmenu + if ! ldd "$(command -v zpool)" | grep -qF 'libgcc_s.so'; then + # On systems with gcc-config (Gentoo, Funtoo, etc.), use it to find libgcc_s + if command -v gcc-config >/dev/null; then + inst_simple "/usr/lib/gcc/$(s=$(gcc-config -c); echo "${s%-*}/${s##*-}")/libgcc_s.so.1" || + { dfatal "Unable to install libgcc_s.so"; exit 1; } + # Otherwise, use dracut's library installation function to find the right one + elif ! inst_libdir_file "libgcc_s.so*"; then + # If all else fails, just try looking for some gcc arch directory + inst_simple /usr/lib/gcc/*/*/libgcc_s.so* || + { dfatal "Unable to install libgcc_s.so"; exit 1; } + fi fi - dracut_install @mounthelperdir@/mount.zfs - dracut_install @udevdir@/vdev_id - dracut_install awk - dracut_install cut - dracut_install tr - dracut_install head - dracut_install @udevdir@/zvol_id + inst_hook cmdline 95 "${moddir}/parse-zfs.sh" - if [ -n "$systemdutildir" ] ; then - inst_script "${moddir}/zfs-generator.sh" "$systemdutildir"/system-generators/dracut-zfs-generator + if [ -n "${systemdutildir}" ]; then + inst_script "${moddir}/zfs-generator.sh" "${systemdutildir}/system-generators/dracut-zfs-generator" fi inst_hook pre-mount 90 "${moddir}/zfs-load-key.sh" inst_hook mount 98 "${moddir}/mount-zfs.sh" inst_hook cleanup 99 "${moddir}/zfs-needshutdown.sh" inst_hook shutdown 20 "${moddir}/export-zfs.sh" - inst_simple "${moddir}/zfs-lib.sh" "/lib/dracut-zfs-lib.sh" - if [ -e @sysconfdir@/zfs/zpool.cache ]; then - inst @sysconfdir@/zfs/zpool.cache - type mark_hostonly >/dev/null 2>&1 && mark_hostonly @sysconfdir@/zfs/zpool.cache - fi + inst_script "${moddir}/zfs-lib.sh" "/lib/dracut-zfs-lib.sh" - if [ -e @sysconfdir@/zfs/vdev_id.conf ]; then - inst @sysconfdir@/zfs/vdev_id.conf - type mark_hostonly >/dev/null 2>&1 && mark_hostonly @sysconfdir@/zfs/vdev_id.conf - fi + # -H ensures they are marked host-only + # -o ensures there is no error upon absence of these files + inst_multiple -o -H \ + "@sysconfdir@/zfs/zpool.cache" \ + "@sysconfdir@/zfs/vdev_id.conf" # Synchronize initramfs and system hostid - if [ -f @sysconfdir@/hostid ]; then - inst @sysconfdir@/hostid - type mark_hostonly >/dev/null 2>&1 && mark_hostonly @sysconfdir@/hostid - elif HOSTID="$(hostid 2>/dev/null)" && [ "${HOSTID}" != "00000000" ]; then - zgenhostid -o "${initdir}@sysconfdir@/hostid" "${HOSTID}" - type mark_hostonly >/dev/null 2>&1 && mark_hostonly @sysconfdir@/hostid + if ! inst_simple -H @sysconfdir@/hostid; then + if HOSTID="$(hostid 2>/dev/null)" && [ "${HOSTID}" != "00000000" ]; then + zgenhostid -o "${initdir}@sysconfdir@/hostid" "${HOSTID}" + mark_hostonly @sysconfdir@/hostid + fi fi if dracut_module_included "systemd"; then - mkdir -p "${initdir}/$systemdsystemunitdir/zfs-import.target.wants" - for _service in "zfs-import-scan.service" "zfs-import-cache.service" ; do - dracut_install "@systemdunitdir@/$_service" - if ! [ -L "${initdir}/$systemdsystemunitdir/zfs-import.target.wants/$_service" ]; then - ln -sf ../$_service "${initdir}/$systemdsystemunitdir/zfs-import.target.wants/$_service" - type mark_hostonly >/dev/null 2>&1 && mark_hostonly "@systemdunitdir@/$_service" - fi - done + inst_simple "${systemdsystemunitdir}/zfs-import.target" + systemctl -q --root "${initdir}" add-wants initrd.target zfs-import.target - inst "${moddir}"/zfs-env-bootfs.service "${systemdsystemunitdir}"/zfs-env-bootfs.service - ln -s ../zfs-env-bootfs.service "${initdir}/${systemdsystemunitdir}/zfs-import.target.wants"/zfs-env-bootfs.service - type mark_hostonly >/dev/null 2>&1 && mark_hostonly @systemdunitdir@/zfs-env-bootfs.service + inst_simple "${moddir}/zfs-env-bootfs.service" "${systemdsystemunitdir}/zfs-env-bootfs.service" + systemctl -q --root "${initdir}" add-wants zfs-import.target zfs-env-bootfs.service - dracut_install systemd-ask-password - dracut_install systemd-tty-ask-password-agent - - mkdir -p "${initdir}/$systemdsystemunitdir/initrd.target.wants" - dracut_install @systemdunitdir@/zfs-import.target - if ! [ -L "${initdir}/$systemdsystemunitdir/initrd.target.wants"/zfs-import.target ]; then - ln -s ../zfs-import.target "${initdir}/$systemdsystemunitdir/initrd.target.wants"/zfs-import.target - type mark_hostonly >/dev/null 2>&1 && mark_hostonly @systemdunitdir@/zfs-import.target - fi + for _service in \ + "zfs-import-scan.service" \ + "zfs-import-cache.service"; do + inst_simple "${systemdsystemunitdir}/${_service}" + systemctl -q --root "${initdir}" add-wants zfs-import.target "${_service}" + done - for _service in zfs-snapshot-bootfs.service zfs-rollback-bootfs.service ; do - inst "${moddir}/$_service" "${systemdsystemunitdir}/$_service" - if ! [ -L "${initdir}/$systemdsystemunitdir/initrd.target.wants/$_service" ]; then - ln -s "../$_service" "${initdir}/$systemdsystemunitdir/initrd.target.wants/$_service" - fi + for _service in \ + "zfs-snapshot-bootfs.service" \ + "zfs-rollback-bootfs.service"; do + inst_simple "${moddir}/${_service}" "${systemdsystemunitdir}/${_service}" + systemctl -q --root "${initdir}" add-wants initrd.target "${_service}" done - # There isn't a pkg-config variable for this, - # and dracut doesn't automatically resolve anything this'd be next to - local systemdsystemenvironmentgeneratordir - systemdsystemenvironmentgeneratordir="$(pkg-config --variable=prefix systemd || echo "/usr")/lib/systemd/system-environment-generators" - mkdir -p "${initdir}/${systemdsystemenvironmentgeneratordir}" - inst "${moddir}"/import-opts-generator.sh "${systemdsystemenvironmentgeneratordir}"/zfs-import-opts.sh + inst_simple "${moddir}/import-opts-generator.sh" "${systemdutildir}/system-environment-generators/zfs-import-opts.sh" fi } diff --git a/contrib/dracut/90zfs/mount-zfs.sh.in b/contrib/dracut/90zfs/mount-zfs.sh.in index 68e3f0e0d60b..fa9f1bb767b8 100755 --- a/contrib/dracut/90zfs/mount-zfs.sh.in +++ b/contrib/dracut/90zfs/mount-zfs.sh.in @@ -3,48 +3,73 @@ . /lib/dracut-zfs-lib.sh -ZFS_DATASET="" -ZFS_POOL="" - -case "${root}" in - zfs:*) ;; - *) return ;; -esac +decode_root_args || return 0 GENERATOR_FILE=/run/systemd/generator/sysroot.mount GENERATOR_EXTENSION=/run/systemd/generator/sysroot.mount.d/zfs-enhancement.conf -if [ -e "$GENERATOR_FILE" ] && [ -e "$GENERATOR_EXTENSION" ] ; then - # If the ZFS sysroot.mount flag exists, the initial RAM disk configured - # it to mount ZFS on root. In that case, we bail early. This flag - # file gets created by the zfs-generator program upon successful run. - info "ZFS: There is a sysroot.mount and zfs-generator has extended it." - info "ZFS: Delegating root mount to sysroot.mount." - # Let us tell the initrd to run on shutdown. - # We have a shutdown hook to run - # because we imported the pool. +if [ -e "$GENERATOR_FILE" ] && [ -e "$GENERATOR_EXTENSION" ]; then + # We're under systemd and dracut-zfs-generator ran to completion. + info "ZFS: Delegating root mount to sysroot.mount at al." + # We now prevent Dracut from running this thing again. - for zfsmounthook in "$hookdir"/mount/*zfs* ; do - if [ -f "$zfsmounthook" ] ; then - rm -f "$zfsmounthook" - fi - done + rm -f "$hookdir"/mount/*zfs* return fi + info "ZFS: No sysroot.mount exists or zfs-generator did not extend it." info "ZFS: Mounting root with the traditional mount-zfs.sh instead." +# ask_for_password tries prompt cmd +# +# Wraps around plymouth ask-for-password and adds fallback to tty password ask +# if plymouth is not present. +ask_for_password() { + tries="$1" + prompt="$2" + cmd="$3" + + { + flock -s 9 + + # Prompt for password with plymouth, if installed and running. + if plymouth --ping 2>/dev/null; then + plymouth ask-for-password \ + --prompt "$prompt" --number-of-tries="$tries" | \ + eval "$cmd" + ret=$? + else + i=1 + while [ "$i" -le "$tries" ]; do + printf "%s [%i/%i]:" "$prompt" "$i" "$tries" >&2 + eval "$cmd" && ret=0 && break + ret=$? + i=$((i+1)) + printf '\n' >&2 + done + unset i + fi + } 9>/.console_lock + + [ "$ret" -ne 0 ] && echo "Wrong password" >&2 + return "$ret" +} + + # Delay until all required block devices are present. modprobe zfs 2>/dev/null udevadm settle +ZFS_DATASET= +ZFS_POOL= + if [ "${root}" = "zfs:AUTO" ] ; then - if ! ZFS_DATASET="$(find_bootfs)" ; then + if ! ZFS_DATASET="$(zpool get -Ho value bootfs | grep -m1 -vFx -)"; then # shellcheck disable=SC2086 zpool import -N -a ${ZPOOL_IMPORT_OPTS} - if ! ZFS_DATASET="$(find_bootfs)" ; then + if ! ZFS_DATASET="$(zpool get -Ho value bootfs | grep -m1 -vFx -)"; then warn "ZFS: No bootfs attribute found in importable pools." - export_all -F + zpool export -aF rootok=0 return 1 @@ -53,34 +78,43 @@ if [ "${root}" = "zfs:AUTO" ] ; then info "ZFS: Using ${ZFS_DATASET} as root." fi -ZFS_DATASET="${ZFS_DATASET:-${root#zfs:}}" +ZFS_DATASET="${ZFS_DATASET:-${root}}" ZFS_POOL="${ZFS_DATASET%%/*}" -if import_pool "${ZFS_POOL}" ; then - # Load keys if we can or if we need to - if [ "$(zpool list -H -o feature@encryption "${ZFS_POOL}")" = 'active' ]; then - # if the root dataset has encryption enabled - ENCRYPTIONROOT="$(zfs get -H -o value encryptionroot "${ZFS_DATASET}")" - if ! [ "${ENCRYPTIONROOT}" = "-" ]; then - KEYSTATUS="$(zfs get -H -o value keystatus "${ENCRYPTIONROOT}")" - # if the key needs to be loaded - if [ "$KEYSTATUS" = "unavailable" ]; then - # decrypt them - ask_for_password \ - --tries 5 \ - --prompt "Encrypted ZFS password for ${ENCRYPTIONROOT}: " \ - --cmd "zfs load-key '${ENCRYPTIONROOT}'" - fi + +if ! zpool get -Ho name "${ZFS_POOL}" > /dev/null 2>&1; then + info "ZFS: Importing pool ${ZFS_POOL}..." + # shellcheck disable=SC2086 + if ! zpool import -N ${ZPOOL_IMPORT_OPTS} "${ZFS_POOL}"; then + warn "ZFS: Unable to import pool ${ZFS_POOL}" + rootok=0 + return 1 + fi +fi + +# Load keys if we can or if we need to +# TODO: for_relevant_root_children like in zfs-load-key.sh.in +if [ "$(zpool get -Ho value feature@encryption "${ZFS_POOL}")" = 'active' ]; then + # if the root dataset has encryption enabled + ENCRYPTIONROOT="$(zfs get -Ho value encryptionroot "${ZFS_DATASET}")" + if ! [ "${ENCRYPTIONROOT}" = "-" ]; then + KEYSTATUS="$(zfs get -Ho value keystatus "${ENCRYPTIONROOT}")" + # if the key needs to be loaded + if [ "$KEYSTATUS" = "unavailable" ]; then + # decrypt them + ask_for_password \ + 5 \ + "Encrypted ZFS password for ${ENCRYPTIONROOT}: " \ + "zfs load-key '${ENCRYPTIONROOT}'" fi fi - # Let us tell the initrd to run on shutdown. - # We have a shutdown hook to run - # because we imported the pool. - info "ZFS: Mounting dataset ${ZFS_DATASET}..." - if mount_dataset "${ZFS_DATASET}" ; then - ROOTFS_MOUNTED=yes - return 0 - fi fi -rootok=0 +# Let us tell the initrd to run on shutdown. +# We have a shutdown hook to run +# because we imported the pool. +info "ZFS: Mounting dataset ${ZFS_DATASET}..." +if ! mount_dataset "${ZFS_DATASET}"; then + rootok=0 + return 1 +fi diff --git a/contrib/dracut/90zfs/parse-zfs.sh.in b/contrib/dracut/90zfs/parse-zfs.sh.in index 0f92f5c80cce..f7d1f1c5da9f 100755 --- a/contrib/dracut/90zfs/parse-zfs.sh.in +++ b/contrib/dracut/90zfs/parse-zfs.sh.in @@ -1,7 +1,8 @@ #!/bin/sh # shellcheck disable=SC2034,SC2154 -. /lib/dracut-lib.sh +# shellcheck source=zfs-lib.sh.in +. /lib/dracut-zfs-lib.sh # Let the command line override our host id. spl_hostid=$(getarg spl_hostid=) @@ -15,49 +16,20 @@ else warn "ZFS: Pools may not import correctly." fi -wait_for_zfs=0 -case "${root}" in - ""|zfs|zfs:) - # We'll take root unset, root=zfs, or root=zfs: - # No root set, so we want to read the bootfs attribute. We - # can't do that until udev settles so we'll set dummy values - # and hope for the best later on. - root="zfs:AUTO" - rootok=1 - wait_for_zfs=1 - - info "ZFS: Enabling autodetection of bootfs after udev settles." - ;; - - ZFS=*|zfs:*|FILESYSTEM=*) - # root is explicit ZFS root. Parse it now. We can handle - # a root=... param in any of the following formats: - # root=ZFS=rpool/ROOT - # root=zfs:rpool/ROOT - # root=zfs:FILESYSTEM=rpool/ROOT - # root=FILESYSTEM=rpool/ROOT - # root=ZFS=pool+with+space/ROOT+WITH+SPACE (translates to root=ZFS=pool with space/ROOT WITH SPACE) - - # Strip down to just the pool/fs - root="${root#zfs:}" - root="${root#FILESYSTEM=}" - root="zfs:${root#ZFS=}" - # switch + with spaces because kernel cmdline does not allow us to quote parameters - root=$(echo "$root" | tr '+' ' ') - rootok=1 - wait_for_zfs=1 - - info "ZFS: Set ${root} as bootfs." - ;; -esac - -# Make sure Dracut is happy that we have a root and will wait for ZFS -# modules to settle before mounting. -if [ ${wait_for_zfs} -eq 1 ]; then - ln -s /dev/null /dev/root 2>/dev/null - initqueuedir="${hookdir}/initqueue/finished" - test -d "${initqueuedir}" || { - initqueuedir="${hookdir}/initqueue-finished" - } - echo '[ -e /dev/zfs ]' > "${initqueuedir}/zfs.sh" +if decode_root_args; then + if [ "$root" = "zfs:AUTO" ]; then + info "ZFS: Boot dataset autodetected from bootfs=." + else + info "ZFS: Boot dataset is ${root}." + fi + + rootok=1 + # Make sure Dracut is happy that we have a root and will wait for ZFS + # modules to settle before mounting. + if [ -n "${wait_for_zfs}" ]; then + ln -s null /dev/root + echo '[ -e /dev/zfs ]' > "${hookdir}/initqueue/finished/zfs.sh" + fi +else + info "ZFS: no ZFS-on-root." fi diff --git a/contrib/dracut/90zfs/zfs-env-bootfs.service.in b/contrib/dracut/90zfs/zfs-env-bootfs.service.in index e143cb5ec1ed..34c88037cac2 100644 --- a/contrib/dracut/90zfs/zfs-env-bootfs.service.in +++ b/contrib/dracut/90zfs/zfs-env-bootfs.service.in @@ -8,7 +8,7 @@ Before=zfs-import.target [Service] Type=oneshot -ExecStart=/bin/sh -c "exec systemctl set-environment BOOTFS=$(@sbindir@/zpool list -H -o bootfs | grep -m1 -v '^-$')" +ExecStart=/bin/sh -c "exec systemctl set-environment BOOTFS=$(@sbindir@/zpool list -H -o bootfs | grep -m1 -vFx -)" [Install] WantedBy=zfs-import.target diff --git a/contrib/dracut/90zfs/zfs-generator.sh.in b/contrib/dracut/90zfs/zfs-generator.sh.in index e50b9530c4f0..56f7ca9785ba 100755 --- a/contrib/dracut/90zfs/zfs-generator.sh.in +++ b/contrib/dracut/90zfs/zfs-generator.sh.in @@ -1,5 +1,5 @@ #!/bin/sh -# shellcheck disable=SC2016,SC1004 +# shellcheck disable=SC2016,SC1004,SC2154 grep -wq debug /proc/cmdline && debug=1 [ -n "$debug" ] && echo "zfs-generator: starting" >> /dev/kmsg @@ -10,37 +10,17 @@ GENERATOR_DIR="$1" exit 1 } -[ -f /lib/dracut-lib.sh ] && dracutlib=/lib/dracut-lib.sh -[ -f /usr/lib/dracut/modules.d/99base/dracut-lib.sh ] && dracutlib=/usr/lib/dracut/modules.d/99base/dracut-lib.sh -command -v getarg >/dev/null 2>&1 || { - [ -n "$debug" ] && echo "zfs-generator: loading Dracut library from $dracutlib" >> /dev/kmsg - . "$dracutlib" -} - +# shellcheck source=zfs-lib.sh.in . /lib/dracut-zfs-lib.sh +decode_root_args || exit 0 -[ -z "$root" ] && root=$(getarg root=) -[ -z "$rootfstype" ] && rootfstype=$(getarg rootfstype=) -[ -z "$rootflags" ] && rootflags=$(getarg rootflags=) - -# If root is not ZFS= or zfs: or rootfstype is not zfs -# then we are not supposed to handle it. -[ "${root##zfs:}" = "${root}" ] && - [ "${root##ZFS=}" = "${root}" ] && - [ "$rootfstype" != "zfs" ] && - exit 0 - +[ -z "${rootflags}" ] && rootflags=$(getarg rootflags=) case ",${rootflags}," in *,zfsutil,*) ;; ,,) rootflags=zfsutil ;; *) rootflags="zfsutil,${rootflags}" ;; esac -if [ "${root}" != "zfs:AUTO" ]; then - root="${root##zfs:}" - root="${root##ZFS=}" -fi - [ -n "$debug" ] && echo "zfs-generator: writing extension for sysroot.mount to $GENERATOR_DIR/sysroot.mount.d/zfs-enhancement.conf" >> /dev/kmsg @@ -89,7 +69,7 @@ else _zfs_generator_cb() { dset="${1}" mpnt="${2}" - unit="sysroot$(echo "$mpnt" | tr '/' '-').mount" + unit="$(systemd-escape --suffix=mount -p "/sysroot${mpnt}")" { echo "[Unit]" diff --git a/contrib/dracut/90zfs/zfs-lib.sh.in b/contrib/dracut/90zfs/zfs-lib.sh.in index defc0bfc8e76..a91b56ba7f3c 100755 --- a/contrib/dracut/90zfs/zfs-lib.sh.in +++ b/contrib/dracut/90zfs/zfs-lib.sh.in @@ -1,74 +1,16 @@ #!/bin/sh +# shellcheck disable=SC2034 -command -v getarg >/dev/null || . /lib/dracut-lib.sh -command -v getargbool >/dev/null || { - # Compatibility with older Dracut versions. - # With apologies to the Dracut developers. - getargbool() { - _default="$1"; shift - ! _b=$(getarg "$@") && [ -z "$_b" ] && _b="$_default" - if [ -n "$_b" ]; then - [ "$_b" = "0" ] && return 1 - [ "$_b" = "no" ] && return 1 - [ "$_b" = "off" ] && return 1 - fi - return 0 - } -} +command -v getarg >/dev/null || . /lib/dracut-lib.sh || . /usr/lib/dracut/modules.d/99base/dracut-lib.sh -OLDIFS="${IFS}" -NEWLINE=" -" TAB=" " -ZPOOL_IMPORT_OPTS="" -if getargbool 0 zfs_force -y zfs.force -y zfsforce ; then +ZPOOL_IMPORT_OPTS= +if getargbool 0 zfs_force -y zfs.force -y zfsforce; then warn "ZFS: Will force-import pools if necessary." - ZPOOL_IMPORT_OPTS="${ZPOOL_IMPORT_OPTS} -f" + ZPOOL_IMPORT_OPTS=-f fi -# find_bootfs -# returns the first dataset with the bootfs attribute. -find_bootfs() { - IFS="${NEWLINE}" - for dataset in $(zpool list -H -o bootfs); do - case "${dataset}" in - "" | "-") - continue - ;; - "no pools available") - IFS="${OLDIFS}" - return 1 - ;; - *) - IFS="${OLDIFS}" - echo "${dataset}" - return 0 - ;; - esac - done - - IFS="${OLDIFS}" - return 1 -} - -# import_pool POOL -# imports the given zfs pool if it isn't imported already. -import_pool() { - pool="${1}" - - if ! zpool list -H "${pool}" > /dev/null 2>&1; then - info "ZFS: Importing pool ${pool}..." - # shellcheck disable=SC2086 - if ! zpool import -N ${ZPOOL_IMPORT_OPTS} "${pool}" ; then - warn "ZFS: Unable to import pool ${pool}" - return 1 - fi - fi - - return 0 -} - _mount_dataset_cb() { mount -o zfsutil -t zfs "${1}" "${NEWROOT}${2}" } @@ -121,87 +63,57 @@ for_relevant_root_children() { ) } -# export_all OPTS -# exports all imported zfs pools. -export_all() { - ret=0 - - IFS="${NEWLINE}" - for pool in $(zpool list -H -o name) ; do - if zpool list -H "${pool}" > /dev/null 2>&1; then - zpool export "${pool}" "$@" || ret=$? - fi - done - IFS="${OLDIFS}" - - return ${ret} -} - -# ask_for_password +# Parse root=, rootfstype=, return them decoded and normalised to zfs:AUTO for auto, plain dset for explicit +# +# True if ZFS-on-root, false if we shouldn't +# +# Supported values: +# root= +# root=zfs +# root=zfs: +# root=zfs:AUTO +# +# root=ZFS=data/set +# root=zfs:data/set +# root=zfs:ZFS=data/set (as a side-effect; allowed but undocumented) # -# Wraps around plymouth ask-for-password and adds fallback to tty password ask -# if plymouth is not present. +# rootfstype=zfs AND root=data/set <=> root=data/set +# rootfstype=zfs AND root= <=> root=zfs:AUTO # -# --cmd command -# Command to execute. Required. -# --prompt prompt -# Password prompt. Note that function already adds ':' at the end. -# Recommended. -# --tries n -# How many times repeat command on its failure. Default is 3. -# --ply-[cmd|prompt|tries] -# Command/prompt/tries specific for plymouth password ask only. -# --tty-[cmd|prompt|tries] -# Command/prompt/tries specific for tty password ask only. -# --tty-echo-off -# Turn off input echo before tty command is executed and turn on after. -# It's useful when password is read from stdin. -ask_for_password() { - ply_tries=3 - tty_tries=3 - while [ "$#" -gt 0 ]; do - case "$1" in - --cmd) ply_cmd="$2"; tty_cmd="$2"; shift;; - --ply-cmd) ply_cmd="$2"; shift;; - --tty-cmd) tty_cmd="$2"; shift;; - --prompt) ply_prompt="$2"; tty_prompt="$2"; shift;; - --ply-prompt) ply_prompt="$2"; shift;; - --tty-prompt) tty_prompt="$2"; shift;; - --tries) ply_tries="$2"; tty_tries="$2"; shift;; - --ply-tries) ply_tries="$2"; shift;; - --tty-tries) tty_tries="$2"; shift;; - --tty-echo-off) tty_echo_off=yes;; +# '+'es in explicit dataset decoded to ' 's. +decode_root_args() { + if [ -n "$rootfstype" ]; then + [ "$rootfstype" = zfs ] + return + fi + + root=$(getarg root=) + rootfstype=$(getarg rootfstype=) + + # shellcheck disable=SC2249 + case "$root" in + ""|zfs|zfs:|zfs:AUTO) + root=zfs:AUTO + rootfstype=zfs + return 0 + ;; + + ZFS=*|zfs:*) + root="${root#zfs:}" + root="${root#ZFS=}" + root=$(echo "$root" | tr '+' ' ') + rootfstype=zfs + return 0 + ;; + esac + + if [ "$rootfstype" = "zfs" ]; then + case "$root" in + "") root=zfs:AUTO ;; + *) root=$(echo "$root" | tr '+' ' ') ;; esac - shift - done - - { flock -s 9; - # Prompt for password with plymouth, if installed and running. - if plymouth --ping 2>/dev/null; then - plymouth ask-for-password \ - --prompt "$ply_prompt" --number-of-tries="$ply_tries" | \ - eval "$ply_cmd" - ret=$? - else - if [ "$tty_echo_off" = yes ]; then - stty_orig="$(stty -g)" - stty -echo - fi - - i=1 - while [ "$i" -le "$tty_tries" ]; do - [ -n "$tty_prompt" ] && \ - printf "%s [%i/%i]:" "$tty_prompt" "$i" "$tty_tries" >&2 - eval "$tty_cmd" && ret=0 && break - ret=$? - i=$((i+1)) - [ -n "$tty_prompt" ] && printf '\n' >&2 - done - unset i - [ "$tty_echo_off" = yes ] && stty "$stty_orig" - fi - } 9>/.console_lock + return 0 + fi - [ $ret -ne 0 ] && echo "Wrong password" >&2 - return $ret + return 1 } diff --git a/contrib/dracut/90zfs/zfs-load-key.sh.in b/contrib/dracut/90zfs/zfs-load-key.sh.in index c974b3d9ec4c..d916f43b4e95 100755 --- a/contrib/dracut/90zfs/zfs-load-key.sh.in +++ b/contrib/dracut/90zfs/zfs-load-key.sh.in @@ -4,70 +4,61 @@ # only run this on systemd systems, we handle the decrypt in mount-zfs.sh in the mount hook otherwise [ -e /bin/systemctl ] || [ -e /usr/bin/systemctl ] || return 0 -# This script only gets executed on systemd systems, see mount-zfs.sh for non-systemd systems +# shellcheck source=zfs-lib.sh.in +. /lib/dracut-zfs-lib.sh -# import the libs now that we know the pool imported -[ -f /lib/dracut-lib.sh ] && dracutlib=/lib/dracut-lib.sh -[ -f /usr/lib/dracut/modules.d/99base/dracut-lib.sh ] && dracutlib=/usr/lib/dracut/modules.d/99base/dracut-lib.sh -# shellcheck source=./lib-zfs.sh.in -. "$dracutlib" - -# load the kernel command line vars -[ -z "$root" ] && root="$(getarg root=)" -# If root is not ZFS= or zfs: or rootfstype is not zfs then we are not supposed to handle it. -[ "${root##zfs:}" = "${root}" ] && [ "${root##ZFS=}" = "${root}" ] && [ "$rootfstype" != "zfs" ] && exit 0 +decode_root_args || return 0 # There is a race between the zpool import and the pre-mount hooks, so we wait for a pool to be imported -while [ "$(zpool list -H)" = "" ]; do - systemctl is-failed --quiet zfs-import-cache.service zfs-import-scan.service && exit 1 +while ! systemctl is-active --quiet zfs-import.target; do + systemctl is-failed --quiet zfs-import-cache.service zfs-import-scan.service && return 1 sleep 0.1s done -# run this after import as zfs-import-cache/scan service is confirmed good -# we do not overwrite the ${root} variable, but create a new one, BOOTFS, to hold the dataset -if [ "${root}" = "zfs:AUTO" ] ; then - BOOTFS="$(zpool list -H -o bootfs | awk '$1 != "-" {print; exit}')" -else - BOOTFS="${root##zfs:}" - BOOTFS="${BOOTFS##ZFS=}" +BOOTFS="$root" +if [ "$BOOTFS" = "zfs:AUTO" ]; then + BOOTFS="$(zpool get -Ho value bootfs | grep -m1 -vFx -)" fi -# if pool encryption is active and the zfs command understands '-o encryption' -if [ "$(zpool list -H -o feature@encryption "${BOOTFS%%/*}")" = 'active' ]; then - # if the root dataset has encryption enabled - ENCRYPTIONROOT="$(zfs get -H -o value encryptionroot "${BOOTFS}")" - if ! [ "${ENCRYPTIONROOT}" = "-" ]; then - KEYSTATUS="$(zfs get -H -o value keystatus "${ENCRYPTIONROOT}")" - # continue only if the key needs to be loaded - [ "$KEYSTATUS" = "unavailable" ] || exit 0 +[ "$(zpool get -Ho value feature@encryption "${BOOTFS%%/*}")" = 'active' ] || return 0 + +_load_key_cb() { + dataset="$1" + + ENCRYPTIONROOT="$(zfs get -Ho value encryptionroot "${dataset}")" + [ "${ENCRYPTIONROOT}" = "-" ] && return 0 - KEYLOCATION="$(zfs get -H -o value keylocation "${ENCRYPTIONROOT}")" - case "${KEYLOCATION%%://*}" in - prompt) - for _ in 1 2 3; do - systemd-ask-password --no-tty "Encrypted ZFS password for ${BOOTFS}" | zfs load-key "${ENCRYPTIONROOT}" && break + [ "$(zfs get -Ho value keystatus "${ENCRYPTIONROOT}")" = "unavailable" ] || return 0 + + KEYLOCATION="$(zfs get -Ho value keylocation "${ENCRYPTIONROOT}")" + case "${KEYLOCATION%%://*}" in + prompt) + for _ in 1 2 3; do + systemd-ask-password --no-tty "Encrypted ZFS password for ${dataset}" | zfs load-key "${ENCRYPTIONROOT}" && break + done + ;; + http*) + systemctl start network-online.target + zfs load-key "${ENCRYPTIONROOT}" + ;; + file) + KEYFILE="${KEYLOCATION#file://}" + [ -r "${KEYFILE}" ] || udevadm settle + [ -r "${KEYFILE}" ] || { + info "ZFS: Waiting for key ${KEYFILE} for ${ENCRYPTIONROOT}..." + for _ in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; do + sleep 0.5s + [ -r "${KEYFILE}" ] && break done - ;; - http*) - systemctl start network-online.target - zfs load-key "${ENCRYPTIONROOT}" - ;; - file) - KEYFILE="${KEYLOCATION#file://}" - [ -r "${KEYFILE}" ] || udevadm settle - [ -r "${KEYFILE}" ] || { - info "Waiting for key ${KEYFILE} for ${ENCRYPTIONROOT}..." - for _ in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; do - sleep 0.5s - [ -r "${KEYFILE}" ] && break - done - } - [ -r "${KEYFILE}" ] || warn "Key ${KEYFILE} for ${ENCRYPTIONROOT} hasn't appeared. Trying anyway." - zfs load-key "${ENCRYPTIONROOT}" - ;; - *) - zfs load-key "${ENCRYPTIONROOT}" - ;; - esac - fi -fi + } + [ -r "${KEYFILE}" ] || warn "ZFS: Key ${KEYFILE} for ${ENCRYPTIONROOT} hasn't appeared. Trying anyway." + zfs load-key "${ENCRYPTIONROOT}" + ;; + *) + zfs load-key "${ENCRYPTIONROOT}" + ;; + esac +} + +_load_key_cb "$BOOTFS" +for_relevant_root_children "$BOOTFS" _load_key_cb diff --git a/contrib/dracut/90zfs/zfs-needshutdown.sh.in b/contrib/dracut/90zfs/zfs-needshutdown.sh.in index dd6de30c2704..7fb825bc95a2 100755 --- a/contrib/dracut/90zfs/zfs-needshutdown.sh.in +++ b/contrib/dracut/90zfs/zfs-needshutdown.sh.in @@ -2,7 +2,7 @@ command -v getarg >/dev/null 2>&1 || . /lib/dracut-lib.sh -if zpool list 2>&1 | grep -q 'no pools available' ; then +if [ -z "$(zpool get -Ho value name)" ]; then info "ZFS: No active pools, no need to export anything." else info "ZFS: There is an active pool, will export it." diff --git a/contrib/dracut/90zfs/zfs-rollback-bootfs.service.in b/contrib/dracut/90zfs/zfs-rollback-bootfs.service.in index bdc246943208..b4f5707516ce 100644 --- a/contrib/dracut/90zfs/zfs-rollback-bootfs.service.in +++ b/contrib/dracut/90zfs/zfs-rollback-bootfs.service.in @@ -1,14 +1,12 @@ [Unit] Description=Rollback bootfs just before it is mounted Requisite=zfs-import.target -After=zfs-import.target zfs-snapshot-bootfs.service +After=zfs-import.target dracut-pre-mount.service zfs-snapshot-bootfs.service Before=dracut-mount.service DefaultDependencies=no ConditionKernelCommandLine=bootfs.rollback [Service] -# ${BOOTFS} should have been set by zfs-env-bootfs.service Type=oneshot -ExecStartPre=/bin/sh -c 'test -n "${BOOTFS}"' -ExecStart=/bin/sh -c '. /lib/dracut-lib.sh; SNAPNAME="$(getarg bootfs.rollback)"; exec @sbindir@/zfs rollback -Rf "${BOOTFS}@${SNAPNAME:-%v}"' +ExecStart=/bin/sh -c '. /lib/dracut-zfs-lib.sh; decode_root_args || exit; [ "$root" = "zfs:AUTO" ] && root="$BOOTFS" SNAPNAME="$(getarg bootfs.rollback)"; exec @sbindir@/zfs rollback -Rf "$root@${SNAPNAME:-%v}"' RemainAfterExit=yes diff --git a/contrib/dracut/90zfs/zfs-snapshot-bootfs.service.in b/contrib/dracut/90zfs/zfs-snapshot-bootfs.service.in index 6ea13850c3a7..afdba2c9d194 100644 --- a/contrib/dracut/90zfs/zfs-snapshot-bootfs.service.in +++ b/contrib/dracut/90zfs/zfs-snapshot-bootfs.service.in @@ -1,14 +1,12 @@ [Unit] Description=Snapshot bootfs just before it is mounted Requisite=zfs-import.target -After=zfs-import.target +After=zfs-import.target dracut-pre-mount.service Before=dracut-mount.service DefaultDependencies=no ConditionKernelCommandLine=bootfs.snapshot [Service] -# ${BOOTFS} should have been set by zfs-env-bootfs.service Type=oneshot -ExecStartPre=/bin/sh -c 'test -n "${BOOTFS}"' -ExecStart=-/bin/sh -c '. /lib/dracut-lib.sh; SNAPNAME="$(getarg bootfs.snapshot)"; exec @sbindir@/zfs snapshot "${BOOTFS}@${SNAPNAME:-%v}"' +ExecStart=/bin/sh -c '. /lib/dracut-zfs-lib.sh; decode_root_args || exit; [ "$root" = "zfs:AUTO" ] && root="$BOOTFS" SNAPNAME="$(getarg bootfs.snapshot)"; exec @sbindir@/zfs snapshot "$root@${SNAPNAME:-%v}"' RemainAfterExit=yes diff --git a/contrib/dracut/README.dracut.markdown b/contrib/dracut/README.dracut.markdown index f31543c3cf6b..b7cd8c8125eb 100644 --- a/contrib/dracut/README.dracut.markdown +++ b/contrib/dracut/README.dracut.markdown @@ -1,225 +1,50 @@ -How to setup a zfs root filesystem using dracut ------------------------------------------------ +## Basic setup +1. Install `zfs-dracut` +2. Set `mountpoint=/` for your root dataset (for compatibility, `legacy` also works, but is not recommended for new installations): + ```sh + zfs set mountpoint=/ pool/dataset + ``` +3. Either (a) set `bootfs=` on the pool to the dataset: + ```sh + zpool set bootfs=pool/dataset pool + ``` +4. Or (b) append `root=zfs:pool/dataset` to your kernel cmdline. +5. Re-generate your initrd and update it in your boot bundle -1) Install the zfs-dracut package. This package adds a zfs dracut module -to the /usr/share/dracut/modules.d/ directory which allows dracut to -create an initramfs which is zfs aware. +Encrypted datasets have keys loaded automatically or prompted for. -2) Set the bootfs property for the bootable dataset in the pool. Then set -the dataset mountpoint property to '/'. +If the root dataset contains children with `mountpoint=`s of `/etc`, `/bin`, `/lib*`, or `/usr`, they're mounted too. - $ zpool set bootfs=pool/dataset pool - $ zfs set mountpoint=/ pool/dataset +For complete documentation, see `dracut.zfs(7)`. -Alternately, legacy mountpoints can be used by setting the 'root=' option -on the kernel line of your grub.conf/menu.lst configuration file. Then -set the dataset mountpoint property to 'legacy'. +## cmdline +1. `root=` | Root dataset is… | + ---------------------------|----------------------------------------------------------| + *(empty)* | the first `bootfs=` after `zpool import -aN` | + `zfs:AUTO`, `zfs:`, `zfs` | *(as above, but overriding other autoselection methods)* | + `ZFS=pool/dataset` | `pool/dataset` | + `zfs:pool/dataset` | *(as above)* | - $ grub.conf/menu.lst: kernel ... root=ZFS=pool/dataset - $ zfs set mountpoint=legacy pool/dataset + All `+`es are replaced with spaces (i.e. to boot from `root pool/data set`, pass `root=zfs:root+pool/data+set`). -3) To set zfs module options put them in /etc/modprobe.d/zfs.conf file. -The complete list of zfs module options is available by running the -_modinfo zfs_ command. Commonly set options include: zfs_arc_min, -zfs_arc_max, zfs_prefetch_disable, and zfs_vdev_max_pending. + The dataset can be at any depth, including being the pool's root dataset (i.e. `root=zfs:pool`). -4) Finally, create your new initramfs by running dracut. + `rootfstype=zfs` is equivalent to `root=zfs:AUTO`, `rootfstype=zfs root=pool/dataset` is equivalent to `root=zfs:pool/dataset`. - $ dracut --force /path/to/initramfs kernel_version +2. `spl_hostid`: passed to `zgenhostid -f`, useful to override the `/etc/hostid` file baked into the initrd. -Kernel Command Line -------------------- +3. `bootfs.snapshot`, `bootfs.snapshot=snapshot-name`: enables `zfs-snapshot-bootfs.service`, + which creates a snapshot `$root_dataset@$(uname -r)` (or, in the second form, `$root_dataset@snapshot-name`) + after pool import but before the rootfs is mounted. + Failure to create the snapshot is noted, but booting continues. -The initramfs' behavior is influenced by the following kernel command line -parameters passed in from the boot loader: +4. `bootfs.rollback`, `bootfs.rollback=snapshot-name`: enables `zfs-snapshot-bootfs.service`, + which `-Rf` rolls back to `$root_dataset@$(uname -r)` (or, in the second form, `$root_dataset@snapshot-name`) + after pool import but before the rootfs is mounted. + Failure to roll back will fall down to the rescue shell. + This has obvious potential for data loss: make sure your persistent data is not below the rootfs and you don't care about any intermediate snapshots. -* `root=...`: If not set, importable pools are searched for a bootfs -attribute. If an explicitly set root is desired, you may use -`root=ZFS:pool/dataset` +5. If both `bootfs.snapshot` and `bootfs.rollback` are set, `bootfs.rollback` is ordered *after* `bootfs.snapshot`. -* `zfs_force=0`: If set to 1, the initramfs will run `zpool import -f` when -attempting to import pools if the required pool isn't automatically imported -by the zfs module. This can save you a trip to a bootcd if hostid has -changed, but is dangerous and can lead to zpool corruption, particularly in -cases where storage is on a shared fabric such as iSCSI where multiple hosts -can access storage devices concurrently. _Please understand the implications -of force-importing a pool before enabling this option!_ - -* `spl_hostid`: By default, the hostid used by the SPL module is read from -/etc/hostid inside the initramfs. This file is placed there from the host -system when the initramfs is built which effectively ties the ramdisk to the -host which builds it. If a different hostid is desired, one may be set in -this attribute and will override any file present in the ramdisk. The -format should be hex exactly as found in the `/etc/hostid` file, IE -`spl_hostid=0x00bab10c`. - -Note that changing the hostid between boots will most likely lead to an -un-importable pool since the last importing hostid won't match. In order -to recover from this, you may use the `zfs_force` option or boot from a -different filesystem and `zpool import -f` then `zpool export` the pool -before rebooting with the new hostid. - -* `bootfs.snapshot`: If listed, enables the zfs-snapshot-bootfs service on a Dracut system. The zfs-snapshot-bootfs service simply runs `zfs snapshot $BOOTFS@%v` after the pool has been imported but before the bootfs is mounted. `$BOOTFS` is substituted with the value of the bootfs setting on the pool. `%v` is substituted with the version string of the kernel currently being booted (e.g. 5.6.6-200.fc31.x86\_64). Failure to create the snapshot (e.g. because one with the same name already exists) will be logged, but will not otherwise interrupt the boot process. - - It is safe to leave the bootfs.snapshot flag set persistently on your kernel command line so that a new snapshot of your bootfs will be created on every kernel update. If you leave bootfs.snapshot set persistently on your kernel command line, you may find the below script helpful for automatically removing old snapshots of the bootfs along with their associated kernel. - - #!/usr/bin/sh - - if [[ "$1" == "remove" ]] && grep -q "\bbootfs.snapshot\b" /proc/cmdline; then - zfs destroy $(findmnt -n -o source /)@$2 &> /dev/null - fi - - exit 0 - - To use the above script place it in a plain text file named /etc/kernel/install.d/99-zfs-cleanup.install and mark it executable with the following command: - - $ chmod +x /etc/kernel/install.d/99-zfs-cleanup.install - - On Red Hat based systems, you can change the value of `installonly_limit` in /etc/dnf/dnf.conf to adjust the number of kernels and their associated snapshots that are kept. - -* `bootfs.snapshot=`: Is identical to the bootfs.snapshot parameter explained above except that the value substituted for \ will be used when creating the snapshot instead of the version string of the kernel currently being booted. - -* `bootfs.rollback`: If listed, enables the zfs-rollback-bootfs service on a Dracut system. The zfs-rollback-bootfs service simply runs `zfs rollback -Rf $BOOTFS@%v` after the pool has been imported but before the bootfs is mounted. If the rollback operation fails, the boot process will be interrupted with a Dracut rescue shell. __Use this parameter with caution. Intermediate snapshots of the bootfs will be destroyed!__ TIP: Keep your user data (e.g. /home) on separate file systems (it can be in the same pool though). - -* `bootfs.rollback=`: Is identical to the bootfs.rollback parameter explained above except that the value substituted for \ will be used when rolling back the bootfs instead of the version string of the kernel currently being booted. If you use this form, choose a snapshot that is new enough to contain the needed kernel modules under /lib/modules or use a kernel that has all the needed modules built-in. - -How it Works -============ - -The Dracut module consists of the following files (less Makefile's): - -* `module-setup.sh`: Script run by the initramfs builder to create the -ramdisk. Contains instructions on which files are required by the modules -and z* programs. Also triggers inclusion of `/etc/hostid` and the zpool -cache. This file is not included in the initramfs. - -* `90-zfs.rules`: udev rules which trigger loading of the ZFS modules at boot. - -* `zfs-lib.sh`: Utility functions used by the other files. - -* `parse-zfs.sh`: Run early in the initramfs boot process to parse kernel -command line and determine if ZFS is the active root filesystem. - -* `mount-zfs.sh`: Run later in initramfs boot process after udev has settled -to mount the root dataset. - -* `export-zfs.sh`: Run on shutdown after dracut has restored the initramfs -and pivoted to it, allowing for a clean unmount and export of the ZFS root. - -`zfs-lib.sh` ------------- - -This file provides a few handy functions for working with ZFS. Those -functions are used by the `mount-zfs.sh` and `export-zfs.sh` files. -However, they could be used by any other file as well, as long as the file -sources `/lib/dracut-zfs-lib.sh`. - -`module-setup.sh` ------------------ - -This file is run by the Dracut script within the live system, not at boot -time. It's not included in the final initramfs. Functions in this script -describe which files are needed by ZFS at boot time. - -Currently all the various z* and spl modules are included, a dependency is -asserted on udev-rules, and the various zfs, zpool, etc. helpers are included. -Dracut provides library functions which automatically gather the shared libs -necessary to run each of these binaries, so statically built binaries are -not required. - -The zpool and zvol udev rules files are copied from where they are -installed by the ZFS build. __PACKAGERS TAKE NOTE__: If you move -`/etc/udev/rules/60-z*.rules`, you'll need to update this file to match. - -Currently this file also includes `/etc/hostid` and `/etc/zfs/zpool.cache` -which means the generated ramdisk is specific to the host system which built -it. If a generic initramfs is required, it may be preferable to omit these -files and specify the `spl_hostid` from the boot loader instead. - -`parse-zfs.sh` --------------- - -Run during the cmdline phase of the initramfs boot process, this script -performs some basic sanity checks on kernel command line parameters to -determine if booting from ZFS is likely to be what is desired. Dracut -requires this script to adjust the `root` variable if required and to set -`rootok=1` if a mountable root filesystem is available. Unfortunately this -script must run before udev is settled and kernel modules are known to be -loaded, so accessing the zpool and zfs commands is unsafe. - -If the root=ZFS... parameter is set on the command line, then it's at least -certain that ZFS is what is desired, though this script is unable to -determine if ZFS is in fact available. This script will alter the `root` -parameter to replace several historical forms of specifying the pool and -dataset name with the canonical form of `zfs:pool/dataset`. - -If no root= parameter is set, the best this script can do is guess that -ZFS is desired. At present, no other known filesystems will work with no -root= parameter, though this might possibly interfere with using the -compiled-in default root in the kernel image. It's considered unlikely -that would ever be the case when an initramfs is in use, so this script -sets `root=zfs:AUTO` and hopes for the best. - -Once the root=... (or lack thereof) parameter is parsed, a dummy symlink -is created from `/dev/root` -> `/dev/null` to satisfy parts of the Dracut -process which check for presence of a single root device node. - -Finally, an initqueue/finished hook is registered which causes the initqueue -phase of Dracut to wait for `/dev/zfs` to become available before attempting -to mount anything. - -`mount-zfs.sh` --------------- - -This script is run after udev has settled and all tasks in the initqueue -have succeeded. This ensures that `/dev/zfs` is available and that the -various ZFS modules are successfully loaded. As it is now safe to call -zpool and friends, we can proceed to find the bootfs attribute if necessary. - -If the root parameter was explicitly set on the command line, no parsing is -necessary. The list of imported pools is checked to see if the desired pool -is already imported. If it's not, and attempt is made to import the pool -explicitly, though no force is attempted. Finally the specified dataset -is mounted on `$NEWROOT`, first using the `-o zfsutil` option to handle -non-legacy mounts, then if that fails, without zfsutil to handle legacy -mount points. - -If no root parameter was specified, this script attempts to find a pool with -its bootfs attribute set. First, already-imported pools are scanned and if -an appropriate pool is found, no additional pools are imported. If no pool -with bootfs is found, any additional pools in the system are imported with -`zpool import -N -a`, and the scan for bootfs is tried again. If no bootfs -is found with all pools imported, all pools are re-exported, and boot fails. -Assuming a bootfs is found, an attempt is made to mount it to `$NEWROOT`, -first with, then without the zfsutil option as above. - -Ordinarily pools are imported _without_ the force option which may cause -boot to fail if the hostid has changed or a pool has been physically moved -between servers. The `zfs_force` kernel parameter is provided which when -set to `1` causes `zpool import` to be run with the `-f` flag. Forcing pool -import can lead to serious data corruption and loss of pools, so this option -should be used with extreme caution. Note that even with this flag set, if -the required zpool was auto-imported by the kernel module, no additional -`zpool import` commands are run, so nothing is forced. - -`export-zfs.sh` ---------------- - -Normally the zpool containing the root dataset cannot be exported on -shutdown as it is still in use by the init process. To work around this, -Dracut is able to restore the initramfs on shutdown and pivot to it. -All remaining process are then running from a ramdisk, allowing for a -clean unmount and export of the ZFS root. The theory of operation is -described in detail in the [Dracut manual](https://www.kernel.org/pub/linux/utils/boot/dracut/dracut.html#_dracut_on_shutdown). - -This script will try to export all remaining zpools after Dracut has -pivoted to the initramfs. If an initial regular export is not successful, -Dracut will call this script once more with the `final` option, -in which case a forceful export is attempted. - -Other Dracut modules include similar shutdown scripts and Dracut -invokes these scripts round-robin until they succeed. In particular, -the `90dm` module installs a script which tries to close and remove -all device mapper targets. Thus, if there are ZVOLs containing -dm-crypt volumes or if the zpool itself is backed by a dm-crypt -volume, the shutdown scripts will try to untangle this. +6. `zfs_force`, `zfs.force`, `zfsforce`: add `-f` to all `zpool import` invocations. + May be useful. Use with caution. diff --git a/etc/default/Makefile.am b/etc/default/Makefile.am index b88eb549493b..f061692c3855 100644 --- a/etc/default/Makefile.am +++ b/etc/default/Makefile.am @@ -1,9 +1,10 @@ include $(top_srcdir)/config/Substfiles.am include $(top_srcdir)/config/Shellcheck.am -initconf_SCRIPTS = zfs +initconf_DATA = zfs -SUBSTFILES += $(initconf_SCRIPTS) +SUBSTFILES += $(initconf_DATA) +SHELLCHECKSCRIPTS = $(initconf_DATA) SHELLCHECK_SHELL = sh SHELLCHECK_IGNORE = ,SC2034 diff --git a/etc/systemd/system-generators/zfs-mount-generator.c b/etc/systemd/system-generators/zfs-mount-generator.c index b806339deb2f..f4c6c26a0b34 100644 --- a/etc/systemd/system-generators/zfs-mount-generator.c +++ b/etc/systemd/system-generators/zfs-mount-generator.c @@ -27,9 +27,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -44,25 +41,16 @@ #include #include -#define STRCMP ((int(*)(const void *, const void *))&strcmp) -#define PID_T_CMP ((int(*)(const void *, const void *))&pid_t_cmp) - -static int -pid_t_cmp(const pid_t *lhs, const pid_t *rhs) -{ - /* - * This is always valid, quoth sys_types.h(7posix): - * > blksize_t, pid_t, and ssize_t shall be signed integer types. - */ - return (*lhs - *rhs); -} +/* + * For debugging only. + * + * Free statics with trivial life-times, + * but saved line filenames are replaced with a static string. + */ +#define FREE_STATICS false -#define EXIT_ENOMEM() \ - do { \ - fprintf(stderr, PROGNAME "[%d]: " \ - "not enough memory (L%d)!\n", getpid(), __LINE__); \ - _exit(1); \ - } while (0) +#define nitems(arr) (sizeof (arr) / sizeof (*arr)) +#define STRCMP ((int(*)(const void *, const void *))&strcmp) #define PROGNAME "zfs-mount-generator" @@ -80,20 +68,11 @@ pid_t_cmp(const pid_t *lhs, const pid_t *rhs) #define URI_REGEX_S "^\\([A-Za-z][A-Za-z0-9+.\\-]*\\):\\/\\/\\(.*\\)$" static regex_t uri_regex; -static char *argv0; - static const char *destdir = "/tmp"; static int destdir_fd = -1; static void *known_pools = NULL; /* tsearch() of C strings */ -static struct { - sem_t noauto_not_on_sem; - - sem_t noauto_names_sem; - size_t noauto_names_len; - size_t noauto_names_max; - char noauto_names[][NAME_MAX]; -} *noauto_files; +static void *noauto_files = NULL; /* tsearch() of C strings */ static char * @@ -103,8 +82,12 @@ systemd_escape(const char *input, const char *prepend, const char *append) size_t applen = strlen(append); size_t prelen = strlen(prepend); char *ret = malloc(4 * len + prelen + applen + 1); - if (!ret) - EXIT_ENOMEM(); + if (!ret) { + fprintf(stderr, PROGNAME "[%d]: " + "out of memory to escape \"%s%s%s\"!\n", + getpid(), prepend, input, append); + return (NULL); + } memcpy(ret, prepend, prelen); char *out = ret + prelen; @@ -166,8 +149,12 @@ systemd_escape_path(char *input, const char *prepend, const char *append) { if (strcmp(input, "/") == 0) { char *ret; - if (asprintf(&ret, "%s-%s", prepend, append) == -1) - EXIT_ENOMEM(); + if (asprintf(&ret, "%s-%s", prepend, append) == -1) { + fprintf(stderr, PROGNAME "[%d]: " + "out of memory to escape \"%s%s%s\"!\n", + getpid(), prepend, input, append); + ret = NULL; + } return (ret); } else { /* @@ -209,6 +196,10 @@ fopenat(int dirfd, const char *pathname, int flags, static int line_worker(char *line, const char *cachefile) { + int ret = 0; + void *tofree_all[8]; + void **tofree = tofree_all; + char *toktmp; /* BEGIN CSTYLED */ const char *dataset = strtok_r(line, "\t", &toktmp); @@ -240,11 +231,9 @@ line_worker(char *line, const char *cachefile) if (p_nbmand == NULL) { fprintf(stderr, PROGNAME "[%d]: %s: not enough tokens!\n", getpid(), dataset); - return (1); + goto err; } - strncpy(argv0, dataset, strlen(argv0)); - /* Minimal pre-requisites to mount a ZFS dataset */ const char *after = "zfs-import.target"; const char *wants = "zfs-import.target"; @@ -280,28 +269,31 @@ line_worker(char *line, const char *cachefile) if (strcmp(p_encroot, "-") != 0) { - char *keyloadunit = + char *keyloadunit = *(tofree++) = systemd_escape(p_encroot, "zfs-load-key@", ".service"); + if (keyloadunit == NULL) + goto err; if (strcmp(dataset, p_encroot) == 0) { const char *keymountdep = NULL; bool is_prompt = false; + bool need_network = false; regmatch_t uri_matches[3]; if (regexec(&uri_regex, p_keyloc, - sizeof (uri_matches) / sizeof (*uri_matches), - uri_matches, 0) == 0) { + nitems(uri_matches), uri_matches, 0) == 0) { + p_keyloc[uri_matches[1].rm_eo] = '\0'; p_keyloc[uri_matches[2].rm_eo] = '\0'; + const char *scheme = + &p_keyloc[uri_matches[1].rm_so]; const char *path = &p_keyloc[uri_matches[2].rm_so]; - /* - * Assumes all URI keylocations need - * the mount for their path; - * http://, for example, wouldn't - * (but it'd need network-online.target et al.) - */ - keymountdep = path; + if (strcmp(scheme, "https") == 0 || + strcmp(scheme, "http") == 0) + need_network = true; + else + keymountdep = path; } else { if (strcmp(p_keyloc, "prompt") != 0) fprintf(stderr, PROGNAME "[%d]: %s: " @@ -321,7 +313,7 @@ line_worker(char *line, const char *cachefile) "couldn't open %s under %s: %s\n", getpid(), dataset, keyloadunit, destdir, strerror(errno)); - return (1); + goto err; } fprintf(keyloadunit_f, @@ -335,20 +327,22 @@ line_worker(char *line, const char *cachefile) "After=%s\n", dataset, cachefile, wants, after); + if (need_network) + fprintf(keyloadunit_f, + "Wants=network-online.target\n" + "After=network-online.target\n"); + if (p_systemd_requires) fprintf(keyloadunit_f, "Requires=%s\n", p_systemd_requires); - if (p_systemd_requiresmountsfor || keymountdep) { - fprintf(keyloadunit_f, "RequiresMountsFor="); - if (p_systemd_requiresmountsfor) - fprintf(keyloadunit_f, - "%s ", p_systemd_requiresmountsfor); - if (keymountdep) - fprintf(keyloadunit_f, - "'%s'", keymountdep); - fprintf(keyloadunit_f, "\n"); - } + if (p_systemd_requiresmountsfor) + fprintf(keyloadunit_f, + "RequiresMountsFor=%s\n", + p_systemd_requiresmountsfor); + if (keymountdep) + fprintf(keyloadunit_f, + "RequiresMountsFor='%s'\n", keymountdep); /* BEGIN CSTYLED */ fprintf(keyloadunit_f, @@ -393,9 +387,13 @@ line_worker(char *line, const char *cachefile) if (after[0] == '\0') after = keyloadunit; else if (asprintf(&toktmp, "%s %s", after, keyloadunit) != -1) - after = toktmp; - else - EXIT_ENOMEM(); + after = *(tofree++) = toktmp; + else { + fprintf(stderr, PROGNAME "[%d]: %s: " + "out of memory to generate after=\"%s %s\"!\n", + getpid(), dataset, after, keyloadunit); + goto err; + } } @@ -404,12 +402,12 @@ line_worker(char *line, const char *cachefile) strcmp(p_systemd_ignore, "off") == 0) { /* ok */ } else if (strcmp(p_systemd_ignore, "on") == 0) - return (0); + goto end; else { fprintf(stderr, PROGNAME "[%d]: %s: " "invalid org.openzfs.systemd:ignore=%s\n", getpid(), dataset, p_systemd_ignore); - return (1); + goto err; } /* Check for canmount */ @@ -418,21 +416,21 @@ line_worker(char *line, const char *cachefile) } else if (strcmp(p_canmount, "noauto") == 0) noauto = true; else if (strcmp(p_canmount, "off") == 0) - return (0); + goto end; else { fprintf(stderr, PROGNAME "[%d]: %s: invalid canmount=%s\n", getpid(), dataset, p_canmount); - return (1); + goto err; } /* Check for legacy and blank mountpoints */ if (strcmp(p_mountpoint, "legacy") == 0 || strcmp(p_mountpoint, "none") == 0) - return (0); + goto end; else if (p_mountpoint[0] != '/') { fprintf(stderr, PROGNAME "[%d]: %s: invalid mountpoint=%s\n", getpid(), dataset, p_mountpoint); - return (1); + goto err; } /* Escape the mountpoint per systemd policy */ @@ -442,7 +440,7 @@ line_worker(char *line, const char *cachefile) fprintf(stderr, PROGNAME "[%d]: %s: abnormal simplified mountpoint: %s\n", getpid(), dataset, p_mountpoint); - return (1); + goto err; } @@ -552,8 +550,7 @@ line_worker(char *line, const char *cachefile) * files if we're sure they were created by us. (see 5.) * 2. We handle files differently based on canmount. * Units with canmount=on always have precedence over noauto. - * This is enforced by the noauto_not_on_sem semaphore, - * which is only unlocked when the last canmount=on process exits. + * This is enforced by processing these units before all others. * It is important to use p_canmount and not noauto here, * since we categorise by canmount while other properties, * e.g. org.openzfs.systemd:wanted-by, also modify noauto. @@ -561,7 +558,7 @@ line_worker(char *line, const char *cachefile) * Additionally, we use noauto_files to track the unit file names * (which are the systemd-escaped mountpoints) of all (exclusively) * noauto datasets that had a file created. - * 4. If the file to be created is found in the tracking array, + * 4. If the file to be created is found in the tracking tree, * we do NOT create it. * 5. If a file exists for a noauto dataset, * we check whether the file name is in the array. @@ -571,29 +568,14 @@ line_worker(char *line, const char *cachefile) * further noauto datasets creating a file for this path again. */ - { - sem_t *our_sem = (strcmp(p_canmount, "on") == 0) ? - &noauto_files->noauto_names_sem : - &noauto_files->noauto_not_on_sem; - while (sem_wait(our_sem) == -1 && errno == EINTR) - ; - } - struct stat stbuf; bool already_exists = fstatat(destdir_fd, mountfile, &stbuf, 0) == 0; + bool is_known = tfind(mountfile, &noauto_files, STRCMP) != NULL; - bool is_known = false; - for (size_t i = 0; i < noauto_files->noauto_names_len; ++i) { - if (strncmp( - noauto_files->noauto_names[i], mountfile, NAME_MAX) == 0) { - is_known = true; - break; - } - } - + *(tofree++) = (void *)mountfile; if (already_exists) { if (is_known) { - /* If it's in $noauto_files, we must be noauto too */ + /* If it's in noauto_files, we must be noauto too */ /* See 5 */ errno = 0; @@ -614,43 +596,31 @@ line_worker(char *line, const char *cachefile) } /* File exists: skip current dataset */ - if (strcmp(p_canmount, "on") == 0) - sem_post(&noauto_files->noauto_names_sem); - return (0); + goto end; } else { if (is_known) { /* See 4 */ - if (strcmp(p_canmount, "on") == 0) - sem_post(&noauto_files->noauto_names_sem); - return (0); + goto end; } else if (strcmp(p_canmount, "noauto") == 0) { - if (noauto_files->noauto_names_len == - noauto_files->noauto_names_max) + if (tsearch(mountfile, &noauto_files, STRCMP) == NULL) fprintf(stderr, PROGNAME "[%d]: %s: " - "noauto dataset limit (%zu) reached! " - "Not tracking %s. Please report this to " - "https://github.com/openzfs/zfs\n", - getpid(), dataset, - noauto_files->noauto_names_max, mountfile); - else { - strncpy(noauto_files->noauto_names[ - noauto_files->noauto_names_len], - mountfile, NAME_MAX); - ++noauto_files->noauto_names_len; - } + "out of memory for noauto datasets! " + "Not tracking %s.\n", + getpid(), dataset, mountfile); + else + /* mountfile escaped to noauto_files */ + *(--tofree) = NULL; } } FILE *mountfile_f = fopenat(destdir_fd, mountfile, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, "w", 0644); - if (strcmp(p_canmount, "on") == 0) - sem_post(&noauto_files->noauto_names_sem); if (!mountfile_f) { fprintf(stderr, PROGNAME "[%d]: %s: couldn't open %s under %s: %s\n", getpid(), dataset, mountfile, destdir, strerror(errno)); - return (1); + goto err; } fprintf(mountfile_f, @@ -699,12 +669,17 @@ line_worker(char *line, const char *cachefile) (void) fclose(mountfile_f); if (!requiredby && !wantedby) - return (0); + goto end; /* Finally, create the appropriate dependencies */ char *linktgt; - if (asprintf(&linktgt, "../%s", mountfile) == -1) - EXIT_ENOMEM(); + if (asprintf(&linktgt, "../%s", mountfile) == -1) { + fprintf(stderr, PROGNAME "[%d]: %s: " + "out of memory for dependents of %s!\n", + getpid(), dataset, mountfile); + goto err; + } + *(tofree++) = linktgt; char *dependencies[][2] = { {"wants", wantedby}, @@ -719,8 +694,14 @@ line_worker(char *line, const char *cachefile) reqby; reqby = strtok_r(NULL, " ", &toktmp)) { char *depdir; - if (asprintf(&depdir, "%s.%s", reqby, (*dep)[0]) == -1) - EXIT_ENOMEM(); + if (asprintf( + &depdir, "%s.%s", reqby, (*dep)[0]) == -1) { + fprintf(stderr, PROGNAME "[%d]: %s: " + "out of memory for dependent dir name " + "\"%s.%s\"!\n", + getpid(), dataset, reqby, (*dep)[0]); + continue; + } (void) mkdirat(destdir_fd, depdir, 0755); int depdir_fd = openat(destdir_fd, depdir, @@ -746,7 +727,24 @@ line_worker(char *line, const char *cachefile) } } - return (0); +end: + if (tofree >= tofree_all + nitems(tofree_all)) { + /* + * This won't happen as-is: + * we've got 8 slots and allocate 4 things at most. + */ + fprintf(stderr, + PROGNAME "[%d]: %s: need to free %zu > %zu!\n", + getpid(), dataset, tofree - tofree_all, nitems(tofree_all)); + ret = tofree - tofree_all; + } + + while (tofree-- != tofree_all) + free(*tofree); + return (ret); +err: + ret = 1; + goto end; } @@ -780,12 +778,11 @@ main(int argc, char **argv) if (kmfd >= 0) { (void) dup2(kmfd, STDERR_FILENO); (void) close(kmfd); + + setlinebuf(stderr); } } - uint8_t debug = 0; - - argv0 = argv[0]; switch (argc) { case 1: /* Use default */ @@ -844,33 +841,9 @@ main(int argc, char **argv) } } - { - /* - * We could just get a gigabyte here and Not Care, - * but if vm.overcommit_memory=2, then MAP_NORESERVE is ignored - * and we'd try (and likely fail) to rip it out of swap - */ - noauto_files = mmap(NULL, 4 * 1024 * 1024, - PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0); - if (noauto_files == MAP_FAILED) { - fprintf(stderr, - PROGNAME "[%d]: couldn't allocate IPC region: %s\n", - getpid(), strerror(errno)); - _exit(1); - } - - sem_init(&noauto_files->noauto_not_on_sem, true, 0); - sem_init(&noauto_files->noauto_names_sem, true, 1); - noauto_files->noauto_names_len = 0; - /* Works out to 16447ish, *well* enough */ - noauto_files->noauto_names_max = - (4 * 1024 * 1024 - sizeof (*noauto_files)) / NAME_MAX; - } - + bool debug = false; char *line = NULL; size_t linelen = 0; - struct timespec time_start = {}; { const char *dbgenv = getenv("ZFS_DEBUG"); if (dbgenv) @@ -879,7 +852,7 @@ main(int argc, char **argv) FILE *cmdline = fopen("/proc/cmdline", "re"); if (cmdline != NULL) { if (getline(&line, &linelen, cmdline) >= 0) - debug = strstr(line, "debug") ? 2 : 0; + debug = strstr(line, "debug"); (void) fclose(cmdline); } } @@ -888,19 +861,17 @@ main(int argc, char **argv) dup2(STDERR_FILENO, STDOUT_FILENO); } - size_t forked_canmount_on = 0; - size_t forked_canmount_not_on = 0; - size_t canmount_on_pids_len = 128; - pid_t *canmount_on_pids = - malloc(canmount_on_pids_len * sizeof (*canmount_on_pids)); - if (canmount_on_pids == NULL) - canmount_on_pids_len = 0; - + struct timespec time_start = {}; if (debug) clock_gettime(CLOCK_MONOTONIC_RAW, &time_start); - ssize_t read; - pid_t pid; + struct line { + char *line; + const char *fname; + struct line *next; + } *lines_canmount_not_on = NULL; + + int ret = 0; struct dirent *cachent; while ((cachent = readdir(fslist_dir)) != NULL) { if (strcmp(cachent->d_name, ".") == 0 || @@ -916,129 +887,67 @@ main(int argc, char **argv) continue; } + const char *filename = FREE_STATICS ? "(elided)" : NULL; + + ssize_t read; while ((read = getline(&line, &linelen, cachefile)) >= 0) { line[read - 1] = '\0'; /* newline */ - switch (pid = fork()) { - case -1: - fprintf(stderr, - PROGNAME "[%d]: couldn't fork for %s: %s\n", - getpid(), line, strerror(errno)); - break; - case 0: /* child */ - _exit(line_worker(line, cachent->d_name)); - default: { /* parent */ - char *tmp; - char *dset = strtok_r(line, "\t", &tmp); - strtok_r(NULL, "\t", &tmp); - char *canmount = strtok_r(NULL, "\t", &tmp); - bool canmount_on = - canmount && strncmp(canmount, "on", 2) == 0; - - if (debug >= 2) - printf(PROGNAME ": forked %d, " - "canmount_on=%d, dataset=%s\n", - (int)pid, canmount_on, dset); - - if (canmount_on && - forked_canmount_on == - canmount_on_pids_len) { - size_t new_len = - (canmount_on_pids_len ?: 16) * 2; - void *new_pidlist = - realloc(canmount_on_pids, - new_len * - sizeof (*canmount_on_pids)); - if (!new_pidlist) { - fprintf(stderr, - PROGNAME "[%d]: " - "out of memory! " - "Mount ordering may be " - "affected.\n", getpid()); - continue; - } - - canmount_on_pids = new_pidlist; - canmount_on_pids_len = new_len; - } + char *canmount = line; + canmount += strcspn(canmount, "\t"); + canmount += strspn(canmount, "\t"); + canmount += strcspn(canmount, "\t"); + canmount += strspn(canmount, "\t"); + bool canmount_on = strncmp(canmount, "on", 2) == 0; - if (canmount_on) { - canmount_on_pids[forked_canmount_on] = - pid; - ++forked_canmount_on; - } else - ++forked_canmount_not_on; - break; - } + if (canmount_on) + ret |= line_worker(line, cachent->d_name); + else { + if (filename == NULL) + filename = + strdup(cachent->d_name) ?: "(?)"; + + struct line *l = calloc(1, sizeof (*l)); + char *nl = strdup(line); + if (l == NULL || nl == NULL) { + fprintf(stderr, PROGNAME "[%d]: " + "out of memory for \"%s\" in %s\n", + getpid(), line, cachent->d_name); + free(l); + free(nl); + continue; + } + l->line = nl; + l->fname = filename; + l->next = lines_canmount_not_on; + lines_canmount_not_on = l; } } - (void) fclose(cachefile); + fclose(cachefile); } free(line); - if (forked_canmount_on == 0) { - /* No canmount=on processes to finish, so don't deadlock here */ - for (size_t i = 0; i < forked_canmount_not_on; ++i) - sem_post(&noauto_files->noauto_not_on_sem); - } else { - /* Likely a no-op, since we got these from a narrow fork loop */ - qsort(canmount_on_pids, forked_canmount_on, - sizeof (*canmount_on_pids), PID_T_CMP); - } + while (lines_canmount_not_on) { + struct line *l = lines_canmount_not_on; + lines_canmount_not_on = l->next; - int status, ret = 0; - struct rusage usage; - size_t forked_canmount_on_max = forked_canmount_on; - while ((pid = wait4(-1, &status, 0, &usage)) != -1) { - ret |= WEXITSTATUS(status) | WTERMSIG(status); - - if (forked_canmount_on != 0) { - if (bsearch(&pid, canmount_on_pids, - forked_canmount_on_max, sizeof (*canmount_on_pids), - PID_T_CMP)) - --forked_canmount_on; - - if (forked_canmount_on == 0) { - /* - * All canmount=on processes have finished, - * let all the lower-priority ones finish now - */ - for (size_t i = 0; - i < forked_canmount_not_on; ++i) - sem_post( - &noauto_files->noauto_not_on_sem); - } + ret |= line_worker(l->line, l->fname); + if (FREE_STATICS) { + free(l->line); + free(l); } - - if (debug >= 2) - printf(PROGNAME ": %d done, user=%llu.%06us, " - "system=%llu.%06us, maxrss=%ldB, ex=0x%x\n", - (int)pid, - (unsigned long long) usage.ru_utime.tv_sec, - (unsigned int) usage.ru_utime.tv_usec, - (unsigned long long) usage.ru_stime.tv_sec, - (unsigned int) usage.ru_stime.tv_usec, - usage.ru_maxrss * 1024, status); } if (debug) { struct timespec time_end = {}; clock_gettime(CLOCK_MONOTONIC_RAW, &time_end); + struct rusage usage; getrusage(RUSAGE_SELF, &usage); printf( "\n" - PROGNAME ": self : " - "user=%llu.%06us, system=%llu.%06us, maxrss=%ldB\n", - (unsigned long long) usage.ru_utime.tv_sec, - (unsigned int) usage.ru_utime.tv_usec, - (unsigned long long) usage.ru_stime.tv_sec, - (unsigned int) usage.ru_stime.tv_usec, - usage.ru_maxrss * 1024); - - getrusage(RUSAGE_CHILDREN, &usage); - printf(PROGNAME ": children: " + PROGNAME ": " "user=%llu.%06us, system=%llu.%06us, maxrss=%ldB\n", (unsigned long long) usage.ru_utime.tv_sec, (unsigned int) usage.ru_utime.tv_usec, @@ -1068,7 +977,7 @@ main(int argc, char **argv) time_init.tv_nsec / 1000000000; time_init.tv_nsec %= 1000000000; - printf(PROGNAME ": wall : " + printf(PROGNAME ": " "total=%llu.%09llus = " "init=%llu.%09llus + real=%llu.%09llus\n", (unsigned long long) time_init.tv_sec, @@ -1077,7 +986,15 @@ main(int argc, char **argv) (unsigned long long) time_start.tv_nsec, (unsigned long long) time_end.tv_sec, (unsigned long long) time_end.tv_nsec); + + fflush(stdout); } + if (FREE_STATICS) { + closedir(fslist_dir); + tdestroy(noauto_files, free); + tdestroy(known_pools, free); + regfree(&uri_regex); + } _exit(ret); } diff --git a/etc/zfs/Makefile.am b/etc/zfs/Makefile.am index 3dee81c75860..1fc57e15848d 100644 --- a/etc/zfs/Makefile.am +++ b/etc/zfs/Makefile.am @@ -10,9 +10,10 @@ dist_pkgsysconf_DATA = \ vdev_id.conf.multipath.example \ vdev_id.conf.scsi.example -pkgsysconf_SCRIPTS = \ +pkgsysconf_DATA = \ zfs-functions -SUBSTFILES += $(pkgsysconf_SCRIPTS) +SUBSTFILES += $(pkgsysconf_DATA) +SHELLCHECKSCRIPTS = $(pkgsysconf_DATA) SHELLCHECK_SHELL = dash # local variables diff --git a/include/libzfs.h b/include/libzfs.h index eeb4daae723b..d55e3f2e7384 100644 --- a/include/libzfs.h +++ b/include/libzfs.h @@ -795,9 +795,10 @@ extern int zfs_receive(libzfs_handle_t *, const char *, nvlist_t *, recvflags_t *, int, avl_tree_t *); typedef enum diff_flags { - ZFS_DIFF_PARSEABLE = 0x1, - ZFS_DIFF_TIMESTAMP = 0x2, - ZFS_DIFF_CLASSIFY = 0x4 + ZFS_DIFF_PARSEABLE = 1 << 0, + ZFS_DIFF_TIMESTAMP = 1 << 1, + ZFS_DIFF_CLASSIFY = 1 << 2, + ZFS_DIFF_NO_MANGLE = 1 << 3 } diff_flags_t; extern int zfs_show_diffs(zfs_handle_t *, int, const char *, const char *, diff --git a/include/libzfs_impl.h b/include/libzfs_impl.h index 96b11dad137c..043ff9cd77e4 100644 --- a/include/libzfs_impl.h +++ b/include/libzfs_impl.h @@ -234,6 +234,7 @@ typedef struct differ_info { boolean_t scripted; boolean_t classify; boolean_t timestamped; + boolean_t no_mangle; uint64_t shares; int zerr; int cleanupfd; diff --git a/include/os/freebsd/zfs/sys/zfs_znode_impl.h b/include/os/freebsd/zfs/sys/zfs_znode_impl.h index edb28d041a0c..3d93525b45ab 100644 --- a/include/os/freebsd/zfs/sys/zfs_znode_impl.h +++ b/include/os/freebsd/zfs/sys/zfs_znode_impl.h @@ -123,25 +123,29 @@ extern minor_t zfsdev_minor_alloc(void); #define zn_rlimit_fsize(zp, uio) \ vn_rlimit_fsize(ZTOV(zp), GET_UIO_STRUCT(uio), zfs_uio_td(uio)) +#define ZFS_ENTER_ERROR(zfsvfs, error) do { \ + ZFS_TEARDOWN_ENTER_READ((zfsvfs), FTAG); \ + if (__predict_false((zfsvfs)->z_unmounted)) { \ + ZFS_TEARDOWN_EXIT_READ(zfsvfs, FTAG); \ + return (error); \ + } \ +} while (0) + /* Called on entry to each ZFS vnode and vfs operation */ -#define ZFS_ENTER(zfsvfs) \ - { \ - ZFS_TEARDOWN_ENTER_READ((zfsvfs), FTAG); \ - if (__predict_false((zfsvfs)->z_unmounted)) { \ - ZFS_TEARDOWN_EXIT_READ(zfsvfs, FTAG); \ - return (EIO); \ - } \ - } +#define ZFS_ENTER(zfsvfs) ZFS_ENTER_ERROR(zfsvfs, EIO) /* Must be called before exiting the vop */ -#define ZFS_EXIT(zfsvfs) ZFS_TEARDOWN_EXIT_READ(zfsvfs, FTAG) +#define ZFS_EXIT(zfsvfs) ZFS_TEARDOWN_EXIT_READ(zfsvfs, FTAG) + +#define ZFS_VERIFY_ZP_ERROR(zp, error) do { \ + if (__predict_false((zp)->z_sa_hdl == NULL)) { \ + ZFS_EXIT((zp)->z_zfsvfs); \ + return (error); \ + } \ +} while (0) /* Verifies the znode is valid */ -#define ZFS_VERIFY_ZP(zp) \ - if (__predict_false((zp)->z_sa_hdl == NULL)) { \ - ZFS_EXIT((zp)->z_zfsvfs); \ - return (EIO); \ - } \ +#define ZFS_VERIFY_ZP(zp) ZFS_VERIFY_ZP_ERROR(zp, EIO) /* * Macros for dealing with dmu_buf_hold diff --git a/include/os/linux/kernel/linux/blkdev_compat.h b/include/os/linux/kernel/linux/blkdev_compat.h index 9fa8884bb7a1..fd91560a3cc4 100644 --- a/include/os/linux/kernel/linux/blkdev_compat.h +++ b/include/os/linux/kernel/linux/blkdev_compat.h @@ -495,21 +495,45 @@ blk_queue_discard_granularity(struct request_queue *q, unsigned int dg) } /* + * 5.19 API, + * bdev_max_discard_sectors() + * + * 2.6.32 API, + * blk_queue_discard() + */ +static inline boolean_t +bdev_discard_supported(struct block_device *bdev) +{ +#if defined(HAVE_BDEV_MAX_DISCARD_SECTORS) + return (!!bdev_max_discard_sectors(bdev)); +#elif defined(HAVE_BLK_QUEUE_DISCARD) + return (!!blk_queue_discard(bdev_get_queue(bdev))); +#else +#error "Unsupported kernel" +#endif +} + +/* + * 5.19 API, + * bdev_max_secure_erase_sectors() + * * 4.8 API, * blk_queue_secure_erase() * * 2.6.36 - 4.7 API, * blk_queue_secdiscard() */ -static inline int -blk_queue_discard_secure(struct request_queue *q) +static inline boolean_t +bdev_secure_discard_supported(struct block_device *bdev) { -#if defined(HAVE_BLK_QUEUE_SECURE_ERASE) - return (blk_queue_secure_erase(q)); +#if defined(HAVE_BDEV_MAX_SECURE_ERASE_SECTORS) + return (!!bdev_max_secure_erase_sectors(bdev)); +#elif defined(HAVE_BLK_QUEUE_SECURE_ERASE) + return (!!blk_queue_secure_erase(bdev_get_queue(bdev))); #elif defined(HAVE_BLK_QUEUE_SECDISCARD) - return (blk_queue_secdiscard(q)); + return (!!blk_queue_secdiscard(bdev_get_queue(bdev))); #else - return (0); +#error "Unsupported kernel" #endif } @@ -527,7 +551,10 @@ blk_generic_start_io_acct(struct request_queue *q __attribute__((unused)), struct gendisk *disk __attribute__((unused)), int rw __attribute__((unused)), struct bio *bio) { -#if defined(HAVE_DISK_IO_ACCT) +#if defined(HAVE_BDEV_IO_ACCT) + return (bdev_start_io_acct(bio->bi_bdev, bio_sectors(bio), + bio_op(bio), jiffies)); +#elif defined(HAVE_DISK_IO_ACCT) return (disk_start_io_acct(disk, bio_sectors(bio), bio_op(bio))); #elif defined(HAVE_BIO_IO_ACCT) return (bio_start_io_acct(bio)); @@ -550,7 +577,9 @@ blk_generic_end_io_acct(struct request_queue *q __attribute__((unused)), struct gendisk *disk __attribute__((unused)), int rw __attribute__((unused)), struct bio *bio, unsigned long start_time) { -#if defined(HAVE_DISK_IO_ACCT) +#if defined(HAVE_BDEV_IO_ACCT) + bdev_end_io_acct(bio->bi_bdev, bio_op(bio), start_time); +#elif defined(HAVE_DISK_IO_ACCT) disk_end_io_acct(disk, bio_op(bio), start_time); #elif defined(HAVE_BIO_IO_ACCT) bio_end_io_acct(bio, start_time); diff --git a/include/os/linux/kernel/linux/simd_x86.h b/include/os/linux/kernel/linux/simd_x86.h index 0f6a222ba667..660f0d42de87 100644 --- a/include/os/linux/kernel/linux/simd_x86.h +++ b/include/os/linux/kernel/linux/simd_x86.h @@ -87,7 +87,9 @@ #if defined(HAVE_KERNEL_FPU_API_HEADER) #include +#if defined(HAVE_KERNEL_FPU_INTERNAL_HEADER) #include +#endif #if defined(HAVE_KERNEL_FPU_XCR_HEADER) #include #endif diff --git a/include/sys/dbuf.h b/include/sys/dbuf.h index d2c175af649c..e7289c0fe1aa 100644 --- a/include/sys/dbuf.h +++ b/include/sys/dbuf.h @@ -321,13 +321,12 @@ typedef struct dmu_buf_impl { uint8_t db_dirtycnt; } dmu_buf_impl_t; -/* Note: the dbuf hash table is exposed only for the mdb module */ -#define DBUF_MUTEXES 2048 -#define DBUF_HASH_MUTEX(h, idx) (&(h)->hash_mutexes[(idx) & (DBUF_MUTEXES-1)]) +#define DBUF_RWLOCKS 8192 +#define DBUF_HASH_RWLOCK(h, idx) (&(h)->hash_rwlocks[(idx) & (DBUF_RWLOCKS-1)]) typedef struct dbuf_hash_table { uint64_t hash_table_mask; dmu_buf_impl_t **hash_table; - kmutex_t hash_mutexes[DBUF_MUTEXES] ____cacheline_aligned; + krwlock_t hash_rwlocks[DBUF_RWLOCKS] ____cacheline_aligned; } dbuf_hash_table_t; typedef void (*dbuf_prefetch_fn)(void *, boolean_t); diff --git a/include/sys/dnode.h b/include/sys/dnode.h index af8775b9ee00..bae393eeba0c 100644 --- a/include/sys/dnode.h +++ b/include/sys/dnode.h @@ -616,7 +616,7 @@ _NOTE(CONSTCOND) } while (0) #else #define dprintf_dnode(db, fmt, ...) -#define DNODE_VERIFY(dn) +#define DNODE_VERIFY(dn) ((void) sizeof ((uintptr_t)(dn))) #define FREE_VERIFY(db, start, end, tx) #endif diff --git a/include/sys/spa_impl.h b/include/sys/spa_impl.h index cb2c49e5852a..c8987e2e67e9 100644 --- a/include/sys/spa_impl.h +++ b/include/sys/spa_impl.h @@ -370,6 +370,7 @@ struct spa { boolean_t spa_is_root; /* pool is root */ int spa_minref; /* num refs when first opened */ spa_mode_t spa_mode; /* SPA_MODE_{READ|WRITE} */ + boolean_t spa_read_spacemaps; /* spacemaps available if ro */ spa_log_state_t spa_log_state; /* log state */ uint64_t spa_autoexpand; /* lun expansion on/off */ ddt_t *spa_ddt[ZIO_CHECKSUM_FUNCTIONS]; /* in-core DDTs */ diff --git a/include/sys/zap.h b/include/sys/zap.h index b19b4643879c..fd7a3a1599bc 100644 --- a/include/sys/zap.h +++ b/include/sys/zap.h @@ -110,7 +110,12 @@ typedef enum zap_flags { * already randomly distributed. */ ZAP_FLAG_PRE_HASHED_KEY = 1 << 2, +#if defined(__linux__) && defined(_KERNEL) +} zfs_zap_flags_t; +#define zap_flags_t zfs_zap_flags_t +#else } zap_flags_t; +#endif /* * Create a new zapobj with no attributes and return its object number. diff --git a/lib/libspl/os/freebsd/mnttab.c b/lib/libspl/os/freebsd/mnttab.c index d830257fbd16..a240ca70ba8d 100644 --- a/lib/libspl/os/freebsd/mnttab.c +++ b/lib/libspl/os/freebsd/mnttab.c @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -136,6 +137,7 @@ statfs2mnttab(struct statfs *sfs, struct mnttab *mp) mp->mnt_mntopts = gmntopts; } +static pthread_rwlock_t gsfs_lock = PTHREAD_RWLOCK_INITIALIZER; static struct statfs *gsfs = NULL; static int allfs = 0; @@ -145,6 +147,8 @@ statfs_init(void) struct statfs *sfs; int error; + (void) pthread_rwlock_wrlock(&gsfs_lock); + if (gsfs != NULL) { free(gsfs); gsfs = NULL; @@ -162,6 +166,7 @@ statfs_init(void) sfs = realloc(gsfs, allfs * sizeof (gsfs[0])); if (sfs != NULL) gsfs = sfs; + (void) pthread_rwlock_unlock(&gsfs_lock); return (0); fail: error = errno; @@ -169,6 +174,7 @@ statfs_init(void) free(gsfs); gsfs = NULL; allfs = 0; + (void) pthread_rwlock_unlock(&gsfs_lock); return (error); } @@ -181,6 +187,8 @@ getmntany(FILE *fd __unused, struct mnttab *mgetp, struct mnttab *mrefp) if (error != 0) return (error); + (void) pthread_rwlock_rdlock(&gsfs_lock); + for (i = 0; i < allfs; i++) { if (mrefp->mnt_special != NULL && strcmp(mrefp->mnt_special, gsfs[i].f_mntfromname) != 0) { @@ -195,8 +203,10 @@ getmntany(FILE *fd __unused, struct mnttab *mgetp, struct mnttab *mrefp) continue; } statfs2mnttab(&gsfs[i], mgetp); + (void) pthread_rwlock_unlock(&gsfs_lock); return (0); } + (void) pthread_rwlock_unlock(&gsfs_lock); return (-1); } @@ -214,9 +224,13 @@ getmntent(FILE *fp, struct mnttab *mp) if (error != 0) return (error); } - if (nfs >= allfs) + (void) pthread_rwlock_rdlock(&gsfs_lock); + if (nfs >= allfs) { + (void) pthread_rwlock_unlock(&gsfs_lock); return (-1); + } statfs2mnttab(&gsfs[nfs], mp); + (void) pthread_rwlock_unlock(&gsfs_lock); if (lseek(fileno(fp), 1, SEEK_CUR) == -1) return (errno); return (0); diff --git a/lib/libzfs/libzfs_dataset.c b/lib/libzfs/libzfs_dataset.c index 8251c434f81e..f2219d1c3d26 100644 --- a/lib/libzfs/libzfs_dataset.c +++ b/lib/libzfs/libzfs_dataset.c @@ -449,14 +449,19 @@ make_dataset_handle_common(zfs_handle_t *zhp, zfs_cmd_t *zc) * We've managed to open the dataset and gather statistics. Determine * the high-level type. */ - if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) + if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) { zhp->zfs_head_type = ZFS_TYPE_VOLUME; - else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) + } else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) { zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM; - else if (zhp->zfs_dmustats.dds_type == DMU_OST_OTHER) + } else if (zhp->zfs_dmustats.dds_type == DMU_OST_OTHER) { + errno = EINVAL; return (-1); - else + } else if (zhp->zfs_dmustats.dds_inconsistent) { + errno = EBUSY; + return (-1); + } else { abort(); + } if (zhp->zfs_dmustats.dds_is_snapshot) zhp->zfs_type = ZFS_TYPE_SNAPSHOT; diff --git a/lib/libzfs/libzfs_diff.c b/lib/libzfs/libzfs_diff.c index d46e23a2fc0e..57a7c1556599 100644 --- a/lib/libzfs/libzfs_diff.c +++ b/lib/libzfs/libzfs_diff.c @@ -122,9 +122,9 @@ stream_bytes(FILE *fp, const char *string) while ((c = *string++) != '\0') { if (c > ' ' && c != '\\' && c < '\177') { - (void) fprintf(fp, "%c", c); + (void) fputc(c, fp); } else { - (void) fprintf(fp, "\\%04o", (uint8_t)c); + (void) fprintf(fp, "\\%04hho", (uint8_t)c); } } } @@ -176,8 +176,13 @@ print_what(FILE *fp, mode_t what) static void print_cmn(FILE *fp, differ_info_t *di, const char *file) { - stream_bytes(fp, di->dsmnt); - stream_bytes(fp, file); + if (!di->no_mangle) { + stream_bytes(fp, di->dsmnt); + stream_bytes(fp, file); + } else { + (void) fputs(di->dsmnt, fp); + (void) fputs(file, fp); + } } static void @@ -752,6 +757,7 @@ zfs_show_diffs(zfs_handle_t *zhp, int outfd, const char *fromsnap, di.scripted = (flags & ZFS_DIFF_PARSEABLE); di.classify = (flags & ZFS_DIFF_CLASSIFY); di.timestamped = (flags & ZFS_DIFF_TIMESTAMP); + di.no_mangle = (flags & ZFS_DIFF_NO_MANGLE); di.outputfd = outfd; di.datafd = pipefd[0]; diff --git a/lib/libzfs/libzfs_import.c b/lib/libzfs/libzfs_import.c index 64fa31c67d0f..ddaa5de5db11 100644 --- a/lib/libzfs/libzfs_import.c +++ b/lib/libzfs/libzfs_import.c @@ -146,10 +146,10 @@ zpool_clear_label(int fd) struct stat64 statbuf; int l; vdev_label_t *label; - l2arc_dev_hdr_phys_t *l2dhdr; + l2arc_dev_hdr_phys_t *l2dhdr = NULL; uint64_t size; - int labels_cleared = 0, header_cleared = 0; - boolean_t clear_l2arc_header = B_FALSE; + int labels_cleared = 0; + boolean_t clear_l2arc_header = B_FALSE, header_cleared = B_FALSE; if (fstat64_blk(fd, &statbuf) == -1) return (0); @@ -219,13 +219,10 @@ zpool_clear_label(int fd) } /* Clear the L2ARC header. */ - if (clear_l2arc_header) { - memset(l2dhdr, 0, sizeof (l2arc_dev_hdr_phys_t)); - if (pwrite64(fd, l2dhdr, sizeof (l2arc_dev_hdr_phys_t), - VDEV_LABEL_START_SIZE) == sizeof (l2arc_dev_hdr_phys_t)) { - header_cleared++; - } - } + if (clear_l2arc_header && + pwrite64(fd, l2dhdr, sizeof (l2arc_dev_hdr_phys_t), + VDEV_LABEL_START_SIZE) == sizeof (l2arc_dev_hdr_phys_t)) + header_cleared = B_TRUE; free(label); free(l2dhdr); @@ -233,6 +230,9 @@ zpool_clear_label(int fd) if (labels_cleared == 0) return (-1); + if (clear_l2arc_header && !header_cleared) + return (-1); + return (0); } diff --git a/lib/libzfs/libzfs_mount.c b/lib/libzfs/libzfs_mount.c index d7c728f3fcb0..82a67ee6310b 100644 --- a/lib/libzfs/libzfs_mount.c +++ b/lib/libzfs/libzfs_mount.c @@ -1348,7 +1348,7 @@ zfs_mount_task(void *arg) sizeof (mountpoint), NULL, NULL, 0, B_FALSE) == 0); if (mp->mnt_func(handles[idx], mp->mnt_data) != 0) - return; + goto out; /* * We dispatch tasks to mount filesystems with mountpoints underneath @@ -1369,6 +1369,8 @@ zfs_mount_task(void *arg) zfs_dispatch_mount(mp->mnt_hdl, handles, num_handles, i, mp->mnt_func, mp->mnt_data, mp->mnt_tp); } + +out: free(mp); } diff --git a/lib/libzfs/libzfs_sendrecv.c b/lib/libzfs/libzfs_sendrecv.c index b67c9b30c84a..899cc84cf912 100644 --- a/lib/libzfs/libzfs_sendrecv.c +++ b/lib/libzfs/libzfs_sendrecv.c @@ -2133,7 +2133,6 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap, avl_tree_t *fsavl = NULL; static uint64_t holdseq; int spa_version; - int featureflags = 0; FILE *fout; (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, @@ -2145,17 +2144,23 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap, return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf)); } - if (zhp->zfs_type == ZFS_TYPE_FILESYSTEM) { - uint64_t version; - version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION); - if (version >= ZPL_VERSION_SA) { - featureflags |= DMU_BACKUP_FEATURE_SA_SPILL; + if (fromsnap) { + char full_fromsnap_name[ZFS_MAX_DATASET_NAME_LEN]; + if (snprintf(full_fromsnap_name, sizeof (full_fromsnap_name), + "%s@%s", zhp->zfs_name, fromsnap) >= + sizeof (full_fromsnap_name)) { + err = EINVAL; + goto stderr_out; + } + zfs_handle_t *fromsnapn = zfs_open(zhp->zfs_hdl, + full_fromsnap_name, ZFS_TYPE_SNAPSHOT); + if (fromsnapn == NULL) { + err = -1; + goto err_out; } + zfs_close(fromsnapn); } - if (flags->holds) - featureflags |= DMU_BACKUP_FEATURE_HOLDS; - if (flags->replicate || flags->doall || flags->props || flags->holds || flags->backup) { char full_tosnap_name[ZFS_MAX_DATASET_NAME_LEN]; @@ -2522,8 +2527,7 @@ zfs_send_one(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags, if (flags->progress) { void *status = NULL; - if (err != 0) - (void) pthread_cancel(ptid); + (void) pthread_cancel(ptid); (void) pthread_join(ptid, &status); int error = (int)(uintptr_t)status; if (error != 0 && status != PTHREAD_CANCELED) diff --git a/lib/libzutil/zutil_import.c b/lib/libzutil/zutil_import.c index d91953813d8c..f6f125e7a5df 100644 --- a/lib/libzutil/zutil_import.c +++ b/lib/libzutil/zutil_import.c @@ -1791,16 +1791,13 @@ zpool_find_config(void *hdl, const char *target, nvlist_t **configp, nvlist_t *match = NULL; nvlist_t *config = NULL; char *sepp = NULL; - char sep = '\0'; int count = 0; char *targetdup = strdup(target); *configp = NULL; - if ((sepp = strpbrk(targetdup, "/@")) != NULL) { - sep = *sepp; + if ((sepp = strpbrk(targetdup, "/@")) != NULL) *sepp = '\0'; - } pools = zpool_search_import(hdl, args, pco); diff --git a/man/Makefile.am b/man/Makefile.am index 8ab1b757242c..64650c2b988a 100644 --- a/man/Makefile.am +++ b/man/Makefile.am @@ -15,6 +15,7 @@ dist_man_MANS = \ man4/spl.4 \ man4/zfs.4 \ \ + man7/dracut.zfs.7 \ man7/zpool-features.7 \ man7/zfsconcepts.7 \ man7/zfsprops.7 \ diff --git a/man/man4/zfs.4 b/man/man4/zfs.4 index 657afc6169b6..3eeed8f439fa 100644 --- a/man/man4/zfs.4 +++ b/man/man4/zfs.4 @@ -1581,12 +1581,12 @@ Allow no-operation writes. The occurrence of nopwrites will further depend on other pool properties .Pq i.a. the checksumming and compression algorithms . . -.It Sy zfs_dmu_offset_next_sync Ns = Ns Sy 0 Ns | Ns 1 Pq int +.It Sy zfs_dmu_offset_next_sync Ns = Ns Sy 1 Ns | Ns 0 Pq int Enable forcing TXG sync to find holes. -When enabled forces ZFS to act like prior versions when +When enabled forces ZFS to sync data when .Sy SEEK_HOLE No or Sy SEEK_DATA -flags are used, which, when a dnode is dirty, -causes TXGs to be synced so that this data can be found. +flags are used allowing holes in a file to be accurately reported. +When disabled holes will not be reported in recently dirtied files. . .It Sy zfs_pd_bytes_max Ns = Ns Sy 52428800 Ns B Po 50MB Pc Pq int The number of bytes which should be prefetched during a pool traversal, like diff --git a/man/man7/dracut.zfs.7 b/man/man7/dracut.zfs.7 new file mode 100644 index 000000000000..0f446fe2fe3f --- /dev/null +++ b/man/man7/dracut.zfs.7 @@ -0,0 +1,278 @@ +.\" SPDX-License-Identifier: 0BSD +.\" +.Dd April 4, 2022 +.Dt DRACUT.ZFS 7 +.Os +. +.Sh NAME +.Nm dracut.zfs +.Nd overview of ZFS dracut hooks +. +.Sh SYNOPSIS +.Bd -literal -compact + parse-zfs.sh \(-> dracut-cmdline.service + | \(da + | … + | \(da + \e\(em\(em\(em\(em\(em\(em\(em\(em\(-> dracut-initqueue.service + | zfs-import-opts.sh + zfs-load-module.service \(da | | + | | sysinit.target \(da | + \(da | | zfs-import-scan.service \(da +zfs-import-scan.service \(da \(da | zfs-import-cache.service + | zfs-import-cache.service basic.target | | + \e__________________| | \(da \(da + \(da | zfs-load-key.sh + zfs-env-bootfs.service | | + \(da \(da \(da + zfs-import.target \(-> dracut-pre-mount.service + | \(ua | + | dracut-zfs-generator | + | ____________________/| + |/ \(da + | sysroot.mount \(<-\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em dracut-zfs-generator + | | \(da | + | \(da sysroot-{usr,etc,lib,&c.}.mount | + | initrd-root-fs.target \(<-\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em or \(da + | | zfs-nonroot-necessities.service + | \(da | + \(da dracut-mount.service | + zfs-snapshot-bootfs.service | | + | \(da | + \(da … | + zfs-rollback-bootfs.service | | + | \(da | + | sysroot-usr.mount \(<-\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em/ + | | + | \(da + | initrd-fs.target + \e______________________ | + \e| + \(da + export-zfs.sh initrd.target + | | + \(da \(da + dracut-shutdown.service … + | + \(da + zfs-needshutdown.sh \(-> initrd-cleanup.service +.Ed +.Pp +Compare +.Xr dracut.bootup 7 +for the full flowchart. +. +.Sh DESCRIPTION +Under dracut, booting with +.No ZFS-on- Ns Pa / +is facilitated by a number of hooks in the +.Nm 90zfs +module. +.Pp +Booting into a ZFS dataset requires +.Sy mountpoint Ns = Ns Pa / +to be set on the dataset containing the root filesystem (henceforth "the boot dataset") and at the very least either the +.Sy bootfs +property to be set to that dataset, or the +.Sy root= +kernel cmdline (or dracut drop-in) argument to specify it. +.Pp +All children of the boot dataset with +.Sy canmount Ns = Ns Sy on +with +.Sy mountpoint Ns s +matching +.Pa /etc , /bin , /lib , /lib?? , /libx32 , No and Pa /usr +globs are deemed essential and will be mounted as well. +.Pp +.Xr zfs-mount-generator 8 +is recommended for proper functioning of the system afterward (correct mount properties, remounting, &c.). +. +.Sh CMDLINE +.Ss Standard +.Bl -tag -compact -width ".Sy root=zfs:AUTO , root=zfs: , root=zfs , Op Sy root=" +.It Sy root=zfs:\& Ns Ar dataset , Sy root=ZFS= Ns Ar dataset +Use +.Ar dataset +as the boot dataset. +All pluses +.Pq Sq + +are replaced with spaces +.Pq Sq \ . +. +.It Sy root=zfs:AUTO , root=zfs:\& , root=zfs , Op Sy root= +After import, search for the first pool with the +.Sy bootfs +property set, use its value as-if specified as the +.Ar dataset +above. +. +.It Sy rootfstype=zfs root= Ns Ar dataset +Equivalent to +.Sy root=zfs:\& Ns Ar dataset . +. +.It Sy rootfstype=zfs Op Sy root= +Equivalent to +.Sy root=zfs:AUTO . +. +.It Sy rootflags= Ns Ar flags +Mount the boot dataset with +.Fl o Ar flags ; +cf.\& +.Sx Temporary Mount Point Properties +in +.Xr zfsprops 7 . +These properties will not last, since all filesystems will be re-mounted from the real root. +. +.It Sy debug +If specified, +.Nm dracut-zfs-generator +logs to the journal. +.El +.Pp +Be careful about setting neither +.Sy rootfstype=zfs +nor +.Sy root=zfs:\& Ns Ar dataset +\(em other automatic boot selection methods, like +.Nm systemd-gpt-auto-generator +and +.Nm systemd-fstab-generator +might take precedent. +. +.Ss ZFS-specific +.Bl -tag -compact -width ".Sy bootfs.snapshot Ns Op Sy = Ns Ar snapshot-name" +.It Sy bootfs.snapshot Ns Op Sy = Ns Ar snapshot-name +Execute +.Nm zfs Cm snapshot Ar boot-dataset Ns Sy @ Ns Ar snapshot-name +before pivoting to the real root. +.Ar snapshot-name +defaults to the current kernel release. +. +.It Sy bootfs.rollback Ns Op Sy = Ns Ar snapshot-name +Execute +.Nm zfs Cm snapshot Fl Rf Ar boot-dataset Ns Sy @ Ns Ar snapshot-name +before pivoting to the real root. +.Ar snapshot-name +defaults to the current kernel release. +. +.It Sy spl_hostid= Ns Ar host-id +Use +.Xr zgenhostid 8 +to set the host ID to +.Ar host-id ; +otherwise, +.Pa /etc/hostid +inherited from the real root is used. +. +.It Sy zfs_force , zfs.force , zfsforce +Appends +.Fl f +to all +.Nm zpool Cm import +invocations; primarily useful in conjunction with +.Sy spl_hostid= , +or if no host ID was inherited. +.El +. +.Sh FILES +.Bl -tag -width 0 +.It Pa parse-zfs.sh Pq Sy cmdline +Processes +.Sy spl_hostid= . +If +.Sy root= +matches a known pattern, above, provides +.Pa /dev/root +and delays the initqueue until +.Xr zfs 4 +is loaded, +. +.It Pa zfs-import-opts.sh Pq Nm systemd No environment generator +Turns +.Sy zfs_force , zfs.force , No or Sy zfsforce +into +.Ev ZPOOL_IMPORT_OPTS Ns = Ns Fl f +for +.Pa zfs-import-scan.service +or +.Pa zfs-import-cache.service . +. +.It Pa zfs-load-key.sh Pq Sy pre-mount +Loads encryption keys for the boot dataset and its essential descendants. +.Bl -tag -compact -offset 4n -width ".Sy keylocation Ns = Ns Sy https:// Ns Ar URL , Sy keylocation Ns = Ns Sy http:// Ns Ar URL" +.It Sy keylocation Ns = Ns Sy prompt +Is prompted for via +.Nm systemd-ask-password +thrice. +. +.It Sy keylocation Ns = Ns Sy https:// Ns Ar URL , Sy keylocation Ns = Ns Sy http:// Ns Ar URL +.Pa network-online.target +is started before loading. +. +.It Sy keylocation Ns = Ns Sy file:// Ns Ar path +If +.Ar path +doesn't exist, +.Nm udevadm No is Cm settle Ns d . +If it still doesn't, it's waited for for up to +.Sy 10 Ns s . +.El +. +.It Pa zfs-env-bootfs.service Pq Nm systemd No service +After pool import, sets +.Ev BOOTFS Ns = +in the systemd environment to the first non-null +.Sy bootfs +value in iteration order. +. +.It Pa dracut-zfs-generator Pq Nm systemd No generator +Generates +.Pa sysroot.mount Pq using Sy rootflags= , No if any . +If an explicit boot dataset was specified, also generates essential mountpoints +.Pq Pa sysroot-etc.mount , sysroot-bin.mount , No &c.\& , +otherwise generates +.Pa zfs-nonroot-necessities.service +which mounts them explicitly after +.Pa /sysroot +using +.Ev BOOTFS Ns = . +. +.It Pa zfs-snapshot-bootfs.service , zfs-rollback-bootfs.service Pq Nm systemd No services +Consume +.Sy bootfs.snapshot +and +.Sy bootfs.rollback +as described in +.Sx CMDLINE . +Use +.Ev BOOTFS Ns = +if no explicit boot dataset was specified. +. +.It Pa zfs-needshutdown.sh Pq Sy cleanup +If any pools were imported, signals that shutdown hooks are required. +. +.It Pa export-zfs.sh Pq Sy shutdown +Forcibly exports all pools. +. +.It Pa /etc/hostid , /etc/zfs/zpool.cache , /etc/zfs/vdev_id.conf Pq regular files +Included verbatim, hostonly. +. +.It Pa mount-zfs.sh Pq Sy mount +Does nothing on +.Nm systemd +systems +.Pq if Pa dracut-zfs-generator No succeeded . +Otherwise, loads encryption key for the boot dataset from the console or via plymouth. +It may not work at all! +.El +. +.Sh SEE ALSO +.Xr dracut.bootup 7 , +.Xr zfsprops 7 , +.Xr zpoolprops 7 , +.Xr dracut-shutdown.service 8 , +.Xr systemd-fstab-generator 8 , +.Xr systemd-gpt-auto-generator 8 , +.Xr zfs-mount-generator 8 , +.Xr zgenhostid 8 diff --git a/man/man8/zfs-diff.8 b/man/man8/zfs-diff.8 index 49443bf47d17..a347f325203e 100644 --- a/man/man8/zfs-diff.8 +++ b/man/man8/zfs-diff.8 @@ -39,7 +39,7 @@ .Sh SYNOPSIS .Nm zfs .Cm diff -.Op Fl FHt +.Op Fl FHth .Ar snapshot Ar snapshot Ns | Ns Ar filesystem . .Sh DESCRIPTION @@ -92,6 +92,10 @@ Give more parsable tab-separated output, without header lines and without arrows. .It Fl t Display the path's inode change time as the first column of output. +.It Fl h +Do not +.Sy \e0 Ns Ar ooo Ns -escape +non-ASCII paths. .El . .Sh SEE ALSO diff --git a/man/man8/zfs-mount-generator.8.in b/man/man8/zfs-mount-generator.8.in index 7aa332ba8174..ae8937038e67 100644 --- a/man/man8/zfs-mount-generator.8.in +++ b/man/man8/zfs-mount-generator.8.in @@ -142,22 +142,11 @@ ZEDLET, if enabled .Pq see Xr zed 8 . . .Sh ENVIRONMENT -The +If the .Sy ZFS_DEBUG -environment variable can either be -.Sy 0 -(default), -.Sy 1 -(print summary accounting information at the end), or at least -.Sy 2 -(print accounting information for each subprocess as it finishes). -. -If not present, -.Pa /proc/cmdline -is additionally checked for -.Qq debug , -in which case the debug level is set to -.Sy 2 . +environment variable is nonzero +.Pq or unset and Pa /proc/cmdline No contains Qq Sy debug , +print summary accounting information at the end. . .Sh EXAMPLES To begin, enable tracking for the pool: diff --git a/man/man8/zfs-set.8 b/man/man8/zfs-set.8 index a3588cc26638..ccd90f0917ea 100644 --- a/man/man8/zfs-set.8 +++ b/man/man8/zfs-set.8 @@ -170,8 +170,9 @@ inherited. .It Fl r Recursively inherit the given property for all children. .It Fl S -Revert the property to the received value if one exists; otherwise operate as -if the +Revert the property to the received value, if one exists; +otherwise, for non-inheritable properties, to the default; +otherwise, operate as if the .Fl S option was not specified. .El diff --git a/man/man8/zpool-import.8 b/man/man8/zpool-import.8 index 39b0e17ef586..5462e4ebd240 100644 --- a/man/man8/zpool-import.8 +++ b/man/man8/zpool-import.8 @@ -71,7 +71,8 @@ .Xc Lists pools available to import. If the -.Fl d or +.Fl d +or .Fl c options are not specified, this command searches for devices using libblkid on Linux and geom on diff --git a/module/Makefile.bsd b/module/Makefile.bsd index dc6cc2b74243..6bd78690fa37 100644 --- a/module/Makefile.bsd +++ b/module/Makefile.bsd @@ -320,6 +320,7 @@ beforeinstall: CFLAGS.gcc+= -Wno-pointer-to-int-cast +CFLAGS.clang+= ${NO_WUNUSED_BUT_SET_VARIABLE} CFLAGS.lapi.c= -Wno-cast-qual CFLAGS.lcompat.c= -Wno-cast-qual diff --git a/module/icp/algs/modes/gcm.c b/module/icp/algs/modes/gcm.c index 7332834cbe37..dc8dd929f68f 100644 --- a/module/icp/algs/modes/gcm.c +++ b/module/icp/algs/modes/gcm.c @@ -798,7 +798,7 @@ static gcm_impl_ops_t *gcm_supp_impl[ARRAY_SIZE(gcm_all_impl)]; * fallback to the fastest generic implementation. */ const gcm_impl_ops_t * -gcm_impl_get_ops() +gcm_impl_get_ops(void) { if (!kfpu_allowed()) return (&gcm_generic_impl); diff --git a/module/os/freebsd/zfs/abd_os.c b/module/os/freebsd/zfs/abd_os.c index 41ceed1dc54c..ddd6d68b361c 100644 --- a/module/os/freebsd/zfs/abd_os.c +++ b/module/os/freebsd/zfs/abd_os.c @@ -113,7 +113,6 @@ static kstat_t *abd_ksp; * memory by only using a single zero buffer for the scatter chunks. */ abd_t *abd_zero_scatter = NULL; -static char *abd_zero_buf = NULL; static uint_t abd_chunkcnt_for_bytes(size_t size) @@ -241,18 +240,16 @@ abd_free_struct_impl(abd_t *abd) /* * Allocate scatter ABD of size SPA_MAXBLOCKSIZE, where - * each chunk in the scatterlist will be set to abd_zero_buf. + * each chunk in the scatterlist will be set to the same area. */ +_Static_assert(ZERO_REGION_SIZE >= PAGE_SIZE, "zero_region too small"); static void abd_alloc_zero_scatter(void) { uint_t i, n; n = abd_chunkcnt_for_bytes(SPA_MAXBLOCKSIZE); - abd_zero_buf = kmem_cache_alloc(abd_chunk_cache, KM_PUSHPAGE); - bzero(abd_zero_buf, PAGE_SIZE); abd_zero_scatter = abd_alloc_struct(SPA_MAXBLOCKSIZE); - abd_zero_scatter->abd_flags |= ABD_FLAG_OWNER | ABD_FLAG_ZEROS; abd_zero_scatter->abd_size = SPA_MAXBLOCKSIZE; @@ -260,7 +257,7 @@ abd_alloc_zero_scatter(void) for (i = 0; i < n; i++) { ABD_SCATTER(abd_zero_scatter).abd_chunks[i] = - abd_zero_buf; + __DECONST(void *, zero_region); } ABDSTAT_BUMP(abdstat_scatter_cnt); @@ -275,7 +272,6 @@ abd_free_zero_scatter(void) abd_free_struct(abd_zero_scatter); abd_zero_scatter = NULL; - kmem_cache_free(abd_chunk_cache, abd_zero_buf); } static int diff --git a/module/os/freebsd/zfs/spa_os.c b/module/os/freebsd/zfs/spa_os.c index 070e7a5b9f1b..d5f851a30860 100644 --- a/module/os/freebsd/zfs/spa_os.c +++ b/module/os/freebsd/zfs/spa_os.c @@ -183,7 +183,6 @@ spa_import_rootpool(const char *name, bool checkpointrewind) spa_t *spa; vdev_t *rvd; nvlist_t *config, *nvtop; - uint64_t txg; char *pname; int error; @@ -196,7 +195,6 @@ spa_import_rootpool(const char *name, bool checkpointrewind) if (config != NULL) { pname = fnvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME); VERIFY0(strcmp(name, pname)); - txg = fnvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_TXG); if ((spa = spa_lookup(pname)) != NULL) { /* diff --git a/module/os/freebsd/zfs/vdev_geom.c b/module/os/freebsd/zfs/vdev_geom.c index 2ef4811a8a4e..5447eb922062 100644 --- a/module/os/freebsd/zfs/vdev_geom.c +++ b/module/os/freebsd/zfs/vdev_geom.c @@ -1132,8 +1132,12 @@ vdev_geom_fill_unmap_cb(void *buf, size_t len, void *priv) vm_offset_t addr = (vm_offset_t)buf; vm_offset_t end = addr + len; - if (bp->bio_ma_n == 0) + if (bp->bio_ma_n == 0) { bp->bio_ma_offset = addr & PAGE_MASK; + addr &= ~PAGE_MASK; + } else { + ASSERT0(P2PHASE(addr, PAGE_SIZE)); + } do { bp->bio_ma[bp->bio_ma_n++] = PHYS_TO_VM_PAGE(pmap_kextract(addr)); diff --git a/module/os/freebsd/zfs/zfs_vnops_os.c b/module/os/freebsd/zfs/zfs_vnops_os.c index b2cc3d063f9c..f6bc9c0c6afb 100644 --- a/module/os/freebsd/zfs/zfs_vnops_os.c +++ b/module/os/freebsd/zfs/zfs_vnops_os.c @@ -97,6 +97,10 @@ VFS_SMR_DECLARE; +#if __FreeBSD_version < 1300103 +#define NDFREE_PNBUF(ndp) NDFREE((ndp), NDF_ONLY_PNBUF) +#endif + #if __FreeBSD_version >= 1300047 #define vm_page_wire_lock(pp) #define vm_page_wire_unlock(pp) @@ -4058,8 +4062,8 @@ zfs_getpages(struct vnode *vp, vm_page_t *ma, int count, int *rbehind, int pgsin_b, pgsin_a; int error; - ZFS_ENTER(zfsvfs); - ZFS_VERIFY_ZP(zp); + ZFS_ENTER_ERROR(zfsvfs, zfs_vm_pagerret_error); + ZFS_VERIFY_ZP_ERROR(zp, zfs_vm_pagerret_error); start = IDX_TO_OFF(ma[0]->pindex); end = IDX_TO_OFF(ma[count - 1]->pindex + 1); @@ -4183,19 +4187,18 @@ zfs_putpages(struct vnode *vp, vm_page_t *ma, size_t len, int flags, int err; int i; - ZFS_ENTER(zfsvfs); - ZFS_VERIFY_ZP(zp); - object = vp->v_object; - pcount = btoc(len); - ncount = pcount; - KASSERT(ma[0]->object == object, ("mismatching object")); KASSERT(len > 0 && (len & PAGE_MASK) == 0, ("unexpected length")); + pcount = btoc(len); + ncount = pcount; for (i = 0; i < pcount; i++) rtvals[i] = zfs_vm_pagerret_error; + ZFS_ENTER_ERROR(zfsvfs, zfs_vm_pagerret_error); + ZFS_VERIFY_ZP_ERROR(zp, zfs_vm_pagerret_error); + off = IDX_TO_OFF(ma[0]->pindex); blksz = zp->z_blksz; lo_off = rounddown(off, blksz); @@ -5234,6 +5237,11 @@ zfs_freebsd_pathconf(struct vop_pathconf_args *ap) case _PC_NAME_MAX: *ap->a_retval = NAME_MAX; return (0); +#if __FreeBSD_version >= 1400032 + case _PC_DEALLOC_PRESENT: + *ap->a_retval = 1; + return (0); +#endif case _PC_PIPE_BUF: if (ap->a_vp->v_type == VDIR || ap->a_vp->v_type == VFIFO) { *ap->a_retval = PIPE_BUF; @@ -5357,7 +5365,7 @@ zfs_getextattr_dir(struct vop_getextattr_args *ap, const char *attrname) #endif error = vn_open_cred(&nd, &flags, 0, VN_OPEN_INVFS, ap->a_cred, NULL); vp = nd.ni_vp; - NDFREE(&nd, NDF_ONLY_PNBUF); + NDFREE_PNBUF(&nd); if (error != 0) return (error); @@ -5430,7 +5438,7 @@ zfs_getextattr(struct vop_getextattr_args *ap) error = ENOENT; ZFS_ENTER(zfsvfs); - ZFS_VERIFY_ZP(zp) + ZFS_VERIFY_ZP(zp); rw_enter(&zp->z_xattr_lock, RW_READER); if (zfsvfs->z_use_sa && zp->z_is_sa) error = zfs_getextattr_sa(ap, attrname); @@ -5475,12 +5483,12 @@ zfs_deleteextattr_dir(struct vop_deleteextattr_args *ap, const char *attrname) error = namei(&nd); vp = nd.ni_vp; if (error != 0) { - NDFREE(&nd, NDF_ONLY_PNBUF); + NDFREE_PNBUF(&nd); return (error); } error = VOP_REMOVE(nd.ni_dvp, vp, &nd.ni_cnd); - NDFREE(&nd, NDF_ONLY_PNBUF); + NDFREE_PNBUF(&nd); vput(nd.ni_dvp); if (vp == nd.ni_dvp) @@ -5605,7 +5613,7 @@ zfs_setextattr_dir(struct vop_setextattr_args *ap, const char *attrname) error = vn_open_cred(&nd, &flags, 0600, VN_OPEN_INVFS, ap->a_cred, NULL); vp = nd.ni_vp; - NDFREE(&nd, NDF_ONLY_PNBUF); + NDFREE_PNBUF(&nd); if (error != 0) return (error); @@ -5760,7 +5768,7 @@ zfs_listextattr_dir(struct vop_listextattr_args *ap, const char *attrprefix) #endif error = namei(&nd); vp = nd.ni_vp; - NDFREE(&nd, NDF_ONLY_PNBUF); + NDFREE_PNBUF(&nd); if (error != 0) return (error); @@ -6073,6 +6081,55 @@ zfs_vptocnp(struct vop_vptocnp_args *ap) return (error); } +#if __FreeBSD_version >= 1400032 +static int +zfs_deallocate(struct vop_deallocate_args *ap) +{ + znode_t *zp = VTOZ(ap->a_vp); + zfsvfs_t *zfsvfs = zp->z_zfsvfs; + zilog_t *zilog; + off_t off, len, file_sz; + int error; + + ZFS_ENTER(zfsvfs); + ZFS_VERIFY_ZP(zp); + + /* + * Callers might not be able to detect properly that we are read-only, + * so check it explicitly here. + */ + if (zfs_is_readonly(zfsvfs)) { + ZFS_EXIT(zfsvfs); + return (SET_ERROR(EROFS)); + } + + zilog = zfsvfs->z_log; + off = *ap->a_offset; + len = *ap->a_len; + file_sz = zp->z_size; + if (off + len > file_sz) + len = file_sz - off; + /* Fast path for out-of-range request. */ + if (len <= 0) { + *ap->a_len = 0; + ZFS_EXIT(zfsvfs); + return (0); + } + + error = zfs_freesp(zp, off, len, O_RDWR, TRUE); + if (error == 0) { + if (zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS || + (ap->a_ioflag & IO_SYNC) != 0) + zil_commit(zilog, zp->z_id); + *ap->a_offset = off + len; + *ap->a_len = 0; + } + + ZFS_EXIT(zfsvfs); + return (error); +} +#endif + struct vop_vector zfs_vnodeops; struct vop_vector zfs_fifoops; struct vop_vector zfs_shareops; @@ -6092,6 +6149,9 @@ struct vop_vector zfs_vnodeops = { #endif .vop_access = zfs_freebsd_access, .vop_allocate = VOP_EINVAL, +#if __FreeBSD_version >= 1400032 + .vop_deallocate = zfs_deallocate, +#endif .vop_lookup = zfs_cache_lookup, .vop_cachedlookup = zfs_freebsd_cachedlookup, .vop_getattr = zfs_freebsd_getattr, diff --git a/module/os/freebsd/zfs/zfs_znode.c b/module/os/freebsd/zfs/zfs_znode.c index e4a1d2db7896..bbc45fda8532 100644 --- a/module/os/freebsd/zfs/zfs_znode.c +++ b/module/os/freebsd/zfs/zfs_znode.c @@ -575,7 +575,6 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, dmu_tx_t *tx, cred_t *cr, dmu_buf_t *db; timestruc_t now; uint64_t gen, obj; - int err; int bonuslen; int dnodesize; sa_handle_t *sa_hdl; @@ -815,12 +814,11 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, dmu_tx_t *tx, cred_t *cr, VERIFY0(zfs_aclset_common(*zpp, acl_ids->z_aclp, cr, tx)); } if (!(flag & IS_ROOT_NODE)) { - vnode_t *vp; - - vp = ZTOV(*zpp); + vnode_t *vp = ZTOV(*zpp); vp->v_vflag |= VV_FORCEINSMQ; - err = insmntque(vp, zfsvfs->z_vfs); + int err = insmntque(vp, zfsvfs->z_vfs); vp->v_vflag &= ~VV_FORCEINSMQ; + (void) err; KASSERT(err == 0, ("insmntque() failed: error %d", err)); } kmem_free(sa_attrs, sizeof (sa_bulk_attr_t) * ZPL_END); @@ -934,11 +932,9 @@ zfs_zget(zfsvfs_t *zfsvfs, uint64_t obj_num, znode_t **zpp) znode_t *zp; vnode_t *vp; sa_handle_t *hdl; - struct thread *td; int locked; int err; - td = curthread; getnewvnode_reserve_(); again: *zpp = NULL; @@ -964,7 +960,7 @@ zfs_zget(zfsvfs_t *zfsvfs, uint64_t obj_num, znode_t **zpp) hdl = dmu_buf_get_user(db); if (hdl != NULL) { - zp = sa_get_userdata(hdl); + zp = sa_get_userdata(hdl); /* * Since "SA" does immediate eviction we @@ -1491,12 +1487,16 @@ zfs_free_range(znode_t *zp, uint64_t off, uint64_t len) error = dmu_free_long_range(zfsvfs->z_os, zp->z_id, off, len); if (error == 0) { +#if __FreeBSD_version >= 1400032 + vnode_pager_purge_range(ZTOV(zp), off, off + len); +#else /* - * In FreeBSD we cannot free block in the middle of a file, - * but only at the end of a file, so this code path should - * never happen. + * Before __FreeBSD_version 1400032 we cannot free block in the + * middle of a file, but only at the end of a file, so this code + * path should never happen. */ vnode_pager_setsize(ZTOV(zp), off); +#endif } zfs_rangelock_exit(lr); diff --git a/module/os/freebsd/zfs/zvol_os.c b/module/os/freebsd/zfs/zvol_os.c index 0b347e7f98fc..09c35b371920 100644 --- a/module/os/freebsd/zfs/zvol_os.c +++ b/module/os/freebsd/zfs/zvol_os.c @@ -1063,7 +1063,7 @@ zvol_cdev_ioctl(struct cdev *dev, ulong_t cmd, caddr_t data, zvol_state_t *zv; zfs_locked_range_t *lr; off_t offset, length; - int i, error; + int error; boolean_t sync; zv = dev->si_drv2; @@ -1072,7 +1072,6 @@ zvol_cdev_ioctl(struct cdev *dev, ulong_t cmd, caddr_t data, KASSERT(zv->zv_open_count > 0, ("Device with zero access count in %s", __func__)); - i = IOCPARM_LEN(cmd); switch (cmd) { case DIOCGSECTORSIZE: *(uint32_t *)data = DEV_BSIZE; diff --git a/module/os/linux/spl/spl-kmem-cache.c b/module/os/linux/spl/spl-kmem-cache.c index 2151ef008fd6..5a318e0a5391 100644 --- a/module/os/linux/spl/spl-kmem-cache.c +++ b/module/os/linux/spl/spl-kmem-cache.c @@ -1421,7 +1421,7 @@ EXPORT_SYMBOL(spl_kmem_cache_reap_now); * it should do no harm. */ int -spl_kmem_cache_reap_active() +spl_kmem_cache_reap_active(void) { return (0); } diff --git a/module/os/linux/zfs/abd_os.c b/module/os/linux/zfs/abd_os.c index d1d238a4e303..8afa222dea34 100644 --- a/module/os/linux/zfs/abd_os.c +++ b/module/os/linux/zfs/abd_os.c @@ -184,8 +184,11 @@ abd_t *abd_zero_scatter = NULL; struct page; /* - * abd_zero_page we will be an allocated zero'd PAGESIZE buffer, which is - * assigned to set each of the pages of abd_zero_scatter. + * _KERNEL - Will point to ZERO_PAGE if it is available or it will be + * an allocated zero'd PAGESIZE buffer. + * Userspace - Will be an allocated zero'ed PAGESIZE buffer. + * + * abd_zero_page is assigned to each of the pages of abd_zero_scatter. */ static struct page *abd_zero_page = NULL; @@ -465,15 +468,19 @@ abd_alloc_zero_scatter(void) struct scatterlist *sg = NULL; struct sg_table table; gfp_t gfp = __GFP_NOWARN | GFP_NOIO; - gfp_t gfp_zero_page = gfp | __GFP_ZERO; int nr_pages = abd_chunkcnt_for_bytes(SPA_MAXBLOCKSIZE); int i = 0; +#if defined(HAVE_ZERO_PAGE_GPL_ONLY) + gfp_t gfp_zero_page = gfp | __GFP_ZERO; while ((abd_zero_page = __page_cache_alloc(gfp_zero_page)) == NULL) { ABDSTAT_BUMP(abdstat_scatter_page_alloc_retry); schedule_timeout_interruptible(1); } abd_mark_zfs_page(abd_zero_page); +#else + abd_zero_page = ZERO_PAGE(0); +#endif /* HAVE_ZERO_PAGE_GPL_ONLY */ while (sg_alloc_table(&table, nr_pages, gfp)) { ABDSTAT_BUMP(abdstat_scatter_sg_table_retry); @@ -612,7 +619,6 @@ abd_alloc_zero_scatter(void) ABD_SCATTER(abd_zero_scatter).abd_offset = 0; ABD_SCATTER(abd_zero_scatter).abd_nents = nr_pages; abd_zero_scatter->abd_size = SPA_MAXBLOCKSIZE; - zfs_refcount_create(&abd_zero_scatter->abd_children); ABD_SCATTER(abd_zero_scatter).abd_sgl = vmem_alloc(nr_pages * sizeof (struct scatterlist), KM_SLEEP); @@ -694,8 +700,10 @@ abd_free_zero_scatter(void) abd_zero_scatter = NULL; ASSERT3P(abd_zero_page, !=, NULL); #if defined(_KERNEL) +#if defined(HAVE_ZERO_PAGE_GPL_ONLY) abd_unmark_zfs_page(abd_zero_page); __free_page(abd_zero_page); +#endif /* HAVE_ZERO_PAGE_GPL_ONLY */ #else umem_free(abd_zero_page, PAGESIZE); #endif /* _KERNEL */ diff --git a/module/os/linux/zfs/vdev_disk.c b/module/os/linux/zfs/vdev_disk.c index 581a790865b7..97cd90bf0a75 100644 --- a/module/os/linux/zfs/vdev_disk.c +++ b/module/os/linux/zfs/vdev_disk.c @@ -304,8 +304,6 @@ vdev_disk_open(vdev_t *v, uint64_t *psize, uint64_t *max_psize, rw_exit(&vd->vd_lock); } - struct request_queue *q = bdev_get_queue(vd->vd_bdev); - /* Determine the physical block size */ int physical_block_size = bdev_physical_block_size(vd->vd_bdev); @@ -316,13 +314,13 @@ vdev_disk_open(vdev_t *v, uint64_t *psize, uint64_t *max_psize, v->vdev_nowritecache = B_FALSE; /* Set when device reports it supports TRIM. */ - v->vdev_has_trim = !!blk_queue_discard(q); + v->vdev_has_trim = bdev_discard_supported(vd->vd_bdev); /* Set when device reports it supports secure TRIM. */ - v->vdev_has_securetrim = !!blk_queue_discard_secure(q); + v->vdev_has_securetrim = bdev_secure_discard_supported(vd->vd_bdev); /* Inform the ZIO pipeline that we are non-rotational */ - v->vdev_nonrot = blk_queue_nonrot(q); + v->vdev_nonrot = blk_queue_nonrot(bdev_get_queue(vd->vd_bdev)); /* Physical volume size in bytes for the partition */ *psize = bdev_capacity(vd->vd_bdev); @@ -460,6 +458,13 @@ vdev_submit_bio_impl(struct bio *bio) #define preempt_schedule_notrace(x) preempt_schedule(x) #endif +/* + * As for the Linux 5.18 kernel bio_alloc() expects a block_device struct + * as an argument removing the need to set it with bio_set_dev(). This + * removes the need for all of the following compatibility code. + */ +#if !defined(HAVE_BIO_ALLOC_4ARG) + #ifdef HAVE_BIO_SET_DEV #if defined(CONFIG_BLK_CGROUP) && defined(HAVE_BIO_SET_DEV_GPL_ONLY) /* @@ -467,8 +472,11 @@ vdev_submit_bio_impl(struct bio *bio) * blkg_tryget() to use rcu_read_lock() instead of rcu_read_lock_sched(). * As a side effect the function was converted to GPL-only. Define our * own version when needed which uses rcu_read_lock_sched(). + * + * The Linux 5.17 kernel split linux/blk-cgroup.h into a private and a public + * part, moving blkg_tryget into the private one. Define our own version. */ -#if defined(HAVE_BLKG_TRYGET_GPL_ONLY) +#if defined(HAVE_BLKG_TRYGET_GPL_ONLY) || !defined(HAVE_BLKG_TRYGET) static inline bool vdev_blkg_tryget(struct blkcg_gq *blkg) { @@ -493,7 +501,7 @@ vdev_blkg_tryget(struct blkcg_gq *blkg) return (rc); } -#elif defined(HAVE_BLKG_TRYGET) +#else #define vdev_blkg_tryget(bg) blkg_tryget(bg) #endif #ifdef HAVE_BIO_SET_DEV_MACRO @@ -553,6 +561,7 @@ bio_set_dev(struct bio *bio, struct block_device *bdev) bio->bi_bdev = bdev; } #endif /* HAVE_BIO_SET_DEV */ +#endif /* !HAVE_BIO_ALLOC_4ARG */ static inline void vdev_submit_bio(struct bio *bio) @@ -563,6 +572,36 @@ vdev_submit_bio(struct bio *bio) current->bio_list = bio_list; } +static inline struct bio * +vdev_bio_alloc(struct block_device *bdev, gfp_t gfp_mask, + unsigned short nr_vecs) +{ + struct bio *bio; + +#ifdef HAVE_BIO_ALLOC_4ARG + bio = bio_alloc(bdev, nr_vecs, 0, gfp_mask); +#else + bio = bio_alloc(gfp_mask, nr_vecs); + if (likely(bio != NULL)) + bio_set_dev(bio, bdev); +#endif + + return (bio); +} + +static inline unsigned int +vdev_bio_max_segs(zio_t *zio, int bio_size, uint64_t abd_offset) +{ + unsigned long nr_segs = abd_nr_pages_off(zio->io_abd, + bio_size, abd_offset); + +#ifdef HAVE_BIO_MAX_SEGS + return (bio_max_segs(nr_segs)); +#else + return (MIN(nr_segs, BIO_MAX_PAGES)); +#endif +} + static int __vdev_disk_physio(struct block_device *bdev, zio_t *zio, size_t io_size, uint64_t io_offset, int rw, int flags) @@ -574,6 +613,7 @@ __vdev_disk_physio(struct block_device *bdev, zio_t *zio, int bio_count = 16; int error = 0; struct blk_plug plug; + unsigned short nr_vecs; /* * Accessing outside the block device is never allowed. @@ -623,15 +663,8 @@ __vdev_disk_physio(struct block_device *bdev, zio_t *zio, goto retry; } - /* bio_alloc() with __GFP_WAIT never returns NULL */ -#ifdef HAVE_BIO_MAX_SEGS - dr->dr_bio[i] = bio_alloc(GFP_NOIO, bio_max_segs( - abd_nr_pages_off(zio->io_abd, bio_size, abd_offset))); -#else - dr->dr_bio[i] = bio_alloc(GFP_NOIO, - MIN(abd_nr_pages_off(zio->io_abd, bio_size, abd_offset), - BIO_MAX_PAGES)); -#endif + nr_vecs = vdev_bio_max_segs(zio, bio_size, abd_offset); + dr->dr_bio[i] = vdev_bio_alloc(bdev, GFP_NOIO, nr_vecs); if (unlikely(dr->dr_bio[i] == NULL)) { vdev_disk_dio_free(dr); return (SET_ERROR(ENOMEM)); @@ -640,7 +673,6 @@ __vdev_disk_physio(struct block_device *bdev, zio_t *zio, /* Matching put called by vdev_disk_physio_completion */ vdev_disk_dio_get(dr); - bio_set_dev(dr->dr_bio[i], bdev); BIO_BI_SECTOR(dr->dr_bio[i]) = bio_offset >> 9; dr->dr_bio[i]->bi_end_io = vdev_disk_physio_completion; dr->dr_bio[i]->bi_private = dr; @@ -704,14 +736,12 @@ vdev_disk_io_flush(struct block_device *bdev, zio_t *zio) if (!q) return (SET_ERROR(ENXIO)); - bio = bio_alloc(GFP_NOIO, 0); - /* bio_alloc() with __GFP_WAIT never returns NULL */ + bio = vdev_bio_alloc(bdev, GFP_NOIO, 0); if (unlikely(bio == NULL)) return (SET_ERROR(ENOMEM)); bio->bi_end_io = vdev_disk_io_flush_completion; bio->bi_private = zio; - bio_set_dev(bio, bdev); bio_set_flush(bio); vdev_submit_bio(bio); invalidate_bdev(bdev); @@ -719,12 +749,38 @@ vdev_disk_io_flush(struct block_device *bdev, zio_t *zio) return (0); } +static int +vdev_disk_io_trim(zio_t *zio) +{ + vdev_t *v = zio->io_vd; + vdev_disk_t *vd = v->vdev_tsd; + +#if defined(HAVE_BLKDEV_ISSUE_SECURE_ERASE) + if (zio->io_trim_flags & ZIO_TRIM_SECURE) { + return (-blkdev_issue_secure_erase(vd->vd_bdev, + zio->io_offset >> 9, zio->io_size >> 9, GFP_NOFS)); + } else { + return (-blkdev_issue_discard(vd->vd_bdev, + zio->io_offset >> 9, zio->io_size >> 9, GFP_NOFS)); + } +#elif defined(HAVE_BLKDEV_ISSUE_DISCARD) + unsigned long trim_flags = 0; +#if defined(BLKDEV_DISCARD_SECURE) + if (zio->io_trim_flags & ZIO_TRIM_SECURE) + trim_flags |= BLKDEV_DISCARD_SECURE; +#endif + return (-blkdev_issue_discard(vd->vd_bdev, + zio->io_offset >> 9, zio->io_size >> 9, GFP_NOFS, trim_flags)); +#else +#error "Unsupported kernel" +#endif +} + static void vdev_disk_io_start(zio_t *zio) { vdev_t *v = zio->io_vd; vdev_disk_t *vd = v->vdev_tsd; - unsigned long trim_flags = 0; int rw, error; /* @@ -797,14 +853,7 @@ vdev_disk_io_start(zio_t *zio) break; case ZIO_TYPE_TRIM: -#if defined(BLKDEV_DISCARD_SECURE) - if (zio->io_trim_flags & ZIO_TRIM_SECURE) - trim_flags |= BLKDEV_DISCARD_SECURE; -#endif - zio->io_error = -blkdev_issue_discard(vd->vd_bdev, - zio->io_offset >> 9, zio->io_size >> 9, GFP_NOFS, - trim_flags); - + zio->io_error = vdev_disk_io_trim(zio); rw_exit(&vd->vd_lock); zio_interrupt(zio); return; diff --git a/module/os/linux/zfs/zfs_sysfs.c b/module/os/linux/zfs/zfs_sysfs.c index fb7c68987360..e73b34a2f37a 100644 --- a/module/os/linux/zfs/zfs_sysfs.c +++ b/module/os/linux/zfs/zfs_sysfs.c @@ -65,16 +65,15 @@ /* * A zfs_mod_kobj_t represents a zfs kobject under '/sys/module/zfs' */ -struct zfs_mod_kobj; typedef struct zfs_mod_kobj zfs_mod_kobj_t; - struct zfs_mod_kobj { struct kobject zko_kobj; struct kobj_type zko_kobj_type; struct sysfs_ops zko_sysfs_ops; size_t zko_attr_count; struct attribute *zko_attr_list; /* allocated */ - struct attribute **zko_default_attrs; /* allocated */ + struct attribute_group zko_default_group; /* .attrs allocated */ + const struct attribute_group *zko_default_groups[2]; size_t zko_child_count; zfs_mod_kobj_t *zko_children; /* allocated */ }; @@ -126,10 +125,10 @@ zfs_kobj_release(struct kobject *kobj) zkobj->zko_attr_list = NULL; } - if (zkobj->zko_default_attrs != NULL) { - kmem_free(zkobj->zko_default_attrs, + if (zkobj->zko_default_group.attrs != NULL) { + kmem_free(zkobj->zko_default_group.attrs, DEFAULT_ATTR_SIZE(zkobj->zko_attr_count)); - zkobj->zko_default_attrs = NULL; + zkobj->zko_default_group.attrs = NULL; } if (zkobj->zko_child_count != 0) { @@ -153,11 +152,12 @@ zfs_kobj_add_attr(zfs_mod_kobj_t *zkobj, int attr_num, const char *attr_name) { VERIFY3U(attr_num, <, zkobj->zko_attr_count); ASSERT(zkobj->zko_attr_list); - ASSERT(zkobj->zko_default_attrs); + ASSERT(zkobj->zko_default_group.attrs); zkobj->zko_attr_list[attr_num].name = attr_name; zkobj->zko_attr_list[attr_num].mode = 0444; - zkobj->zko_default_attrs[attr_num] = &zkobj->zko_attr_list[attr_num]; + zkobj->zko_default_group.attrs[attr_num] = + &zkobj->zko_attr_list[attr_num]; sysfs_attr_init(&zkobj->zko_attr_list[attr_num]); } @@ -175,9 +175,9 @@ zfs_kobj_init(zfs_mod_kobj_t *zkobj, int attr_cnt, int child_cnt, return (ENOMEM); } /* this will always have at least one slot for NULL termination */ - zkobj->zko_default_attrs = kmem_zalloc(DEFAULT_ATTR_SIZE(attr_cnt), - KM_SLEEP); - if (zkobj->zko_default_attrs == NULL) { + zkobj->zko_default_group.attrs = + kmem_zalloc(DEFAULT_ATTR_SIZE(attr_cnt), KM_SLEEP); + if (zkobj->zko_default_group.attrs == NULL) { if (zkobj->zko_attr_list != NULL) { kmem_free(zkobj->zko_attr_list, ATTR_TABLE_SIZE(attr_cnt)); @@ -185,14 +185,19 @@ zfs_kobj_init(zfs_mod_kobj_t *zkobj, int attr_cnt, int child_cnt, return (ENOMEM); } zkobj->zko_attr_count = attr_cnt; - zkobj->zko_kobj_type.default_attrs = zkobj->zko_default_attrs; + zkobj->zko_default_groups[0] = &zkobj->zko_default_group; +#ifdef HAVE_SYSFS_DEFAULT_GROUPS + zkobj->zko_kobj_type.default_groups = zkobj->zko_default_groups; +#else + zkobj->zko_kobj_type.default_attrs = zkobj->zko_default_group.attrs; +#endif if (child_cnt > 0) { zkobj->zko_children = kmem_zalloc(CHILD_TABLE_SIZE(child_cnt), KM_SLEEP); if (zkobj->zko_children == NULL) { - if (zkobj->zko_default_attrs != NULL) { - kmem_free(zkobj->zko_default_attrs, + if (zkobj->zko_default_group.attrs != NULL) { + kmem_free(zkobj->zko_default_group.attrs, DEFAULT_ATTR_SIZE(attr_cnt)); } if (zkobj->zko_attr_list != NULL) { @@ -214,9 +219,9 @@ zfs_kobj_init(zfs_mod_kobj_t *zkobj, int attr_cnt, int child_cnt, static int zfs_kobj_add(zfs_mod_kobj_t *zkobj, struct kobject *parent, const char *name) { - /* zko_default_attrs must be NULL terminated */ - ASSERT(zkobj->zko_default_attrs != NULL); - ASSERT(zkobj->zko_default_attrs[zkobj->zko_attr_count] == NULL); + /* zko_default_group.attrs must be NULL terminated */ + ASSERT(zkobj->zko_default_group.attrs != NULL); + ASSERT(zkobj->zko_default_group.attrs[zkobj->zko_attr_count] == NULL); kobject_init(&zkobj->zko_kobj, &zkobj->zko_kobj_type); return (kobject_add(&zkobj->zko_kobj, parent, name)); diff --git a/module/os/linux/zfs/zfs_uio.c b/module/os/linux/zfs/zfs_uio.c index a3d5d5f83b6f..11cd62f5f8eb 100644 --- a/module/os/linux/zfs/zfs_uio.c +++ b/module/os/linux/zfs/zfs_uio.c @@ -248,7 +248,7 @@ zfs_uio_prefaultpages(ssize_t n, zfs_uio_t *uio) /* touch each page in this segment. */ p = iov->iov_base + skip; while (cnt) { - if (get_user(tmp, (uint8_t *)p)) + if (copy_from_user(&tmp, p, 1)) return (EFAULT); ulong_t incr = MIN(cnt, PAGESIZE); p += incr; @@ -256,7 +256,7 @@ zfs_uio_prefaultpages(ssize_t n, zfs_uio_t *uio) } /* touch the last byte in case it straddles a page. */ p--; - if (get_user(tmp, (uint8_t *)p)) + if (copy_from_user(&tmp, p, 1)) return (EFAULT); } } diff --git a/module/os/linux/zfs/zfs_vnops_os.c b/module/os/linux/zfs/zfs_vnops_os.c index 2958439ace82..796a86c25ab7 100644 --- a/module/os/linux/zfs/zfs_vnops_os.c +++ b/module/os/linux/zfs/zfs_vnops_os.c @@ -3594,7 +3594,11 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc) dmu_tx_wait(tx); dmu_tx_abort(tx); +#ifdef HAVE_VFS_FILEMAP_DIRTY_FOLIO + filemap_dirty_folio(page_mapping(pp), page_folio(pp)); +#else __set_page_dirty_nobuffers(pp); +#endif ClearPageError(pp); end_page_writeback(pp); zfs_rangelock_exit(lr); diff --git a/module/os/linux/zfs/zpl_file.c b/module/os/linux/zfs/zpl_file.c index f1241c443797..38d2bd147007 100644 --- a/module/os/linux/zfs/zpl_file.c +++ b/module/os/linux/zfs/zpl_file.c @@ -33,9 +33,13 @@ #include #include #include -#ifdef HAVE_VFS_SET_PAGE_DIRTY_NOBUFFERS +#if defined(HAVE_VFS_SET_PAGE_DIRTY_NOBUFFERS) || \ + defined(HAVE_VFS_FILEMAP_DIRTY_FOLIO) #include #endif +#ifdef HAVE_VFS_FILEMAP_DIRTY_FOLIO +#include +#endif /* * When using fallocate(2) to preallocate space, inflate the requested @@ -413,6 +417,8 @@ zpl_aio_write(struct kiocb *kiocb, const struct iovec *iov, if (ret) return (ret); + kiocb->ki_pos = pos; + zfs_uio_t uio; zfs_uio_iovec_init(&uio, iov, nr_segs, kiocb->ki_pos, UIO_USERSPACE, count, 0); @@ -629,11 +635,19 @@ zpl_readpage_common(struct page *pp) return (error); } +#ifdef HAVE_VFS_READ_FOLIO +static int +zpl_read_folio(struct file *filp, struct folio *folio) +{ + return (zpl_readpage_common(&folio->page)); +} +#else static int zpl_readpage(struct file *filp, struct page *pp) { return (zpl_readpage_common(pp)); } +#endif static int zpl_readpage_filler(void *data, struct page *pp) @@ -647,12 +661,29 @@ zpl_readpage_filler(void *data, struct page *pp) * paging. For simplicity, the code relies on read_cache_pages() to * correctly lock each page for IO and call zpl_readpage(). */ +#ifdef HAVE_VFS_READPAGES static int zpl_readpages(struct file *filp, struct address_space *mapping, struct list_head *pages, unsigned nr_pages) { return (read_cache_pages(mapping, pages, zpl_readpage_filler, NULL)); } +#else +static void +zpl_readahead(struct readahead_control *ractl) +{ + struct page *page; + + while ((page = readahead_page(ractl)) != NULL) { + int ret; + + ret = zpl_readpage_filler(NULL, page); + put_page(page); + if (ret) + break; + } +} +#endif static int zpl_putpage(struct page *pp, struct writeback_control *wbc, void *data) @@ -764,11 +795,13 @@ zpl_fallocate_common(struct inode *ip, int mode, loff_t offset, loff_t len) if (mode & (test_mode)) { flock64_t bf; - if (offset > olen) - goto out_unmark; + if (mode & FALLOC_FL_KEEP_SIZE) { + if (offset > olen) + goto out_unmark; - if (offset + len > olen) - len = olen - offset; + if (offset + len > olen) + len = olen - offset; + } bf.l_type = F_WRLCK; bf.l_whence = SEEK_SET; bf.l_start = offset; @@ -1027,14 +1060,25 @@ zpl_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) const struct address_space_operations zpl_address_space_operations = { +#ifdef HAVE_VFS_READPAGES .readpages = zpl_readpages, +#else + .readahead = zpl_readahead, +#endif +#ifdef HAVE_VFS_READ_FOLIO + .read_folio = zpl_read_folio, +#else .readpage = zpl_readpage, +#endif .writepage = zpl_writepage, .writepages = zpl_writepages, .direct_IO = zpl_direct_IO, #ifdef HAVE_VFS_SET_PAGE_DIRTY_NOBUFFERS .set_page_dirty = __set_page_dirty_nobuffers, #endif +#ifdef HAVE_VFS_FILEMAP_DIRTY_FOLIO + .dirty_folio = filemap_dirty_folio, +#endif }; const struct file_operations zpl_file_operations = { diff --git a/module/os/linux/zfs/zvol_os.c b/module/os/linux/zfs/zvol_os.c index 7a979eb91e7f..bb92c65ca810 100644 --- a/module/os/linux/zfs/zvol_os.c +++ b/module/os/linux/zfs/zvol_os.c @@ -903,22 +903,17 @@ zvol_alloc(dev_t dev, const char *name) zso->zvo_disk->major = zvol_major; zso->zvo_disk->events = DISK_EVENT_MEDIA_CHANGE; + /* + * Setting ZFS_VOLMODE_DEV disables partitioning on ZVOL devices. + * This is accomplished by limiting the number of minors for the + * device to one and explicitly disabling partition scanning. + */ if (volmode == ZFS_VOLMODE_DEV) { - /* - * ZFS_VOLMODE_DEV disable partitioning on ZVOL devices: set - * gendisk->minors = 1 as noted in include/linux/genhd.h. - * Also disable extended partition numbers (GENHD_FL_EXT_DEVT) - * and suppresses partition scanning (GENHD_FL_NO_PART_SCAN) - * setting gendisk->flags accordingly. - */ zso->zvo_disk->minors = 1; -#if defined(GENHD_FL_EXT_DEVT) - zso->zvo_disk->flags &= ~GENHD_FL_EXT_DEVT; -#endif -#if defined(GENHD_FL_NO_PART_SCAN) - zso->zvo_disk->flags |= GENHD_FL_NO_PART_SCAN; -#endif + zso->zvo_disk->flags &= ~ZFS_GENHD_FL_EXT_DEVT; + zso->zvo_disk->flags |= ZFS_GENHD_FL_NO_PART; } + zso->zvo_disk->first_minor = (dev & MINORMASK); zso->zvo_disk->fops = &zvol_ops; zso->zvo_disk->private_data = zv; @@ -1055,7 +1050,9 @@ zvol_os_create_minor(const char *name) (zvol_max_discard_blocks * zv->zv_volblocksize) >> 9); blk_queue_discard_granularity(zv->zv_zso->zvo_queue, zv->zv_volblocksize); +#ifdef QUEUE_FLAG_DISCARD blk_queue_flag_set(QUEUE_FLAG_DISCARD, zv->zv_zso->zvo_queue); +#endif #ifdef QUEUE_FLAG_NONROT blk_queue_flag_set(QUEUE_FLAG_NONROT, zv->zv_zso->zvo_queue); #endif diff --git a/module/zfs/arc.c b/module/zfs/arc.c index 47b58b6c2e0c..9f08f63ea681 100644 --- a/module/zfs/arc.c +++ b/module/zfs/arc.c @@ -3430,7 +3430,6 @@ arc_hdr_realloc_crypt(arc_buf_hdr_t *hdr, boolean_t need_crypt) arc_buf_hdr_t *nhdr; arc_buf_t *buf; kmem_cache_t *ncache, *ocache; - unsigned nsize, osize; /* * This function requires that hdr is in the arc_anon state. @@ -3447,14 +3446,10 @@ arc_hdr_realloc_crypt(arc_buf_hdr_t *hdr, boolean_t need_crypt) if (need_crypt) { ncache = hdr_full_crypt_cache; - nsize = sizeof (hdr->b_crypt_hdr); ocache = hdr_full_cache; - osize = HDR_FULL_SIZE; } else { ncache = hdr_full_cache; - nsize = HDR_FULL_SIZE; ocache = hdr_full_crypt_cache; - osize = sizeof (hdr->b_crypt_hdr); } nhdr = kmem_cache_alloc(ncache, KM_PUSHPAGE); @@ -9312,26 +9307,37 @@ l2arc_apply_transforms(spa_t *spa, arc_buf_hdr_t *hdr, uint64_t asize, } if (compress != ZIO_COMPRESS_OFF && !HDR_COMPRESSION_ENABLED(hdr)) { - cabd = abd_alloc_for_io(asize, ismd); - tmp = abd_borrow_buf(cabd, asize); + /* + * In some cases, we can wind up with size > asize, so + * we need to opt for the larger allocation option here. + * + * (We also need abd_return_buf_copy in all cases because + * it's an ASSERT() to modify the buffer before returning it + * with arc_return_buf(), and all the compressors + * write things before deciding to fail compression in nearly + * every case.) + */ + cabd = abd_alloc_for_io(size, ismd); + tmp = abd_borrow_buf(cabd, size); psize = zio_compress_data(compress, to_write, tmp, size, hdr->b_complevel); - if (psize >= size) { - abd_return_buf(cabd, tmp, asize); + if (psize >= asize) { + psize = HDR_GET_PSIZE(hdr); + abd_return_buf_copy(cabd, tmp, size); HDR_SET_COMPRESS(hdr, ZIO_COMPRESS_OFF); to_write = cabd; - abd_copy(to_write, hdr->b_l1hdr.b_pabd, size); - if (size != asize) - abd_zero_off(to_write, size, asize - size); + abd_copy(to_write, hdr->b_l1hdr.b_pabd, psize); + if (psize != asize) + abd_zero_off(to_write, psize, asize - psize); goto encrypt; } ASSERT3U(psize, <=, HDR_GET_PSIZE(hdr)); if (psize < asize) bzero((char *)tmp + psize, asize - psize); psize = HDR_GET_PSIZE(hdr); - abd_return_buf_copy(cabd, tmp, asize); + abd_return_buf_copy(cabd, tmp, size); to_write = cabd; } diff --git a/module/zfs/dbuf.c b/module/zfs/dbuf.c index d61724be8a07..247eeddb6cd6 100644 --- a/module/zfs/dbuf.c +++ b/module/zfs/dbuf.c @@ -338,18 +338,18 @@ dbuf_find(objset_t *os, uint64_t obj, uint8_t level, uint64_t blkid) hv = dbuf_hash(os, obj, level, blkid); idx = hv & h->hash_table_mask; - mutex_enter(DBUF_HASH_MUTEX(h, idx)); + rw_enter(DBUF_HASH_RWLOCK(h, idx), RW_READER); for (db = h->hash_table[idx]; db != NULL; db = db->db_hash_next) { if (DBUF_EQUAL(db, os, obj, level, blkid)) { mutex_enter(&db->db_mtx); if (db->db_state != DB_EVICTING) { - mutex_exit(DBUF_HASH_MUTEX(h, idx)); + rw_exit(DBUF_HASH_RWLOCK(h, idx)); return (db); } mutex_exit(&db->db_mtx); } } - mutex_exit(DBUF_HASH_MUTEX(h, idx)); + rw_exit(DBUF_HASH_RWLOCK(h, idx)); return (NULL); } @@ -392,13 +392,13 @@ dbuf_hash_insert(dmu_buf_impl_t *db) hv = dbuf_hash(os, obj, level, blkid); idx = hv & h->hash_table_mask; - mutex_enter(DBUF_HASH_MUTEX(h, idx)); + rw_enter(DBUF_HASH_RWLOCK(h, idx), RW_WRITER); for (dbf = h->hash_table[idx], i = 0; dbf != NULL; dbf = dbf->db_hash_next, i++) { if (DBUF_EQUAL(dbf, os, obj, level, blkid)) { mutex_enter(&dbf->db_mtx); if (dbf->db_state != DB_EVICTING) { - mutex_exit(DBUF_HASH_MUTEX(h, idx)); + rw_exit(DBUF_HASH_RWLOCK(h, idx)); return (dbf); } mutex_exit(&dbf->db_mtx); @@ -416,7 +416,7 @@ dbuf_hash_insert(dmu_buf_impl_t *db) mutex_enter(&db->db_mtx); db->db_hash_next = h->hash_table[idx]; h->hash_table[idx] = db; - mutex_exit(DBUF_HASH_MUTEX(h, idx)); + rw_exit(DBUF_HASH_RWLOCK(h, idx)); uint64_t he = atomic_inc_64_nv(&dbuf_stats.hash_elements.value.ui64); DBUF_STAT_MAX(hash_elements_max, he); @@ -473,13 +473,13 @@ dbuf_hash_remove(dmu_buf_impl_t *db) /* * We mustn't hold db_mtx to maintain lock ordering: - * DBUF_HASH_MUTEX > db_mtx. + * DBUF_HASH_RWLOCK > db_mtx. */ ASSERT(zfs_refcount_is_zero(&db->db_holds)); ASSERT(db->db_state == DB_EVICTING); ASSERT(!MUTEX_HELD(&db->db_mtx)); - mutex_enter(DBUF_HASH_MUTEX(h, idx)); + rw_enter(DBUF_HASH_RWLOCK(h, idx), RW_WRITER); dbp = &h->hash_table[idx]; while ((dbf = *dbp) != db) { dbp = &dbf->db_hash_next; @@ -490,7 +490,7 @@ dbuf_hash_remove(dmu_buf_impl_t *db) if (h->hash_table[idx] && h->hash_table[idx]->db_hash_next == NULL) DBUF_STAT_BUMPDOWN(hash_chains); - mutex_exit(DBUF_HASH_MUTEX(h, idx)); + rw_exit(DBUF_HASH_RWLOCK(h, idx)); atomic_dec_64(&dbuf_stats.hash_elements.value.ui64); } @@ -851,8 +851,8 @@ dbuf_init(void) sizeof (dmu_buf_impl_t), 0, dbuf_cons, dbuf_dest, NULL, NULL, NULL, 0); - for (i = 0; i < DBUF_MUTEXES; i++) - mutex_init(&h->hash_mutexes[i], NULL, MUTEX_DEFAULT, NULL); + for (i = 0; i < DBUF_RWLOCKS; i++) + rw_init(&h->hash_rwlocks[i], NULL, RW_DEFAULT, NULL); dbuf_stats_init(h); @@ -918,8 +918,8 @@ dbuf_fini(void) dbuf_stats_destroy(); - for (i = 0; i < DBUF_MUTEXES; i++) - mutex_destroy(&h->hash_mutexes[i]); + for (i = 0; i < DBUF_RWLOCKS; i++) + rw_destroy(&h->hash_rwlocks[i]); #if defined(_KERNEL) /* * Large allocations which do not require contiguous pages @@ -1465,10 +1465,8 @@ dbuf_read_impl(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags, zbookmark_phys_t zb; uint32_t aflags = ARC_FLAG_NOWAIT; int err, zio_flags; - boolean_t bonus_read; err = zio_flags = 0; - bonus_read = B_FALSE; DB_DNODE_ENTER(db); dn = DB_DNODE(db); ASSERT(!zfs_refcount_is_zero(&db->db_holds)); @@ -3886,7 +3884,7 @@ dmu_buf_get_user(dmu_buf_t *db_fake) } void -dmu_buf_user_evict_wait() +dmu_buf_user_evict_wait(void) { taskq_wait(dbu_evict_taskq); } diff --git a/module/zfs/dbuf_stats.c b/module/zfs/dbuf_stats.c index 12bb568a08cc..037190a81bb3 100644 --- a/module/zfs/dbuf_stats.c +++ b/module/zfs/dbuf_stats.c @@ -137,7 +137,7 @@ dbuf_stats_hash_table_data(char *buf, size_t size, void *data) if (size) buf[0] = 0; - mutex_enter(DBUF_HASH_MUTEX(h, dsh->idx)); + rw_enter(DBUF_HASH_RWLOCK(h, dsh->idx), RW_READER); for (db = h->hash_table[dsh->idx]; db != NULL; db = db->db_hash_next) { /* * Returning ENOMEM will cause the data and header functions @@ -158,7 +158,7 @@ dbuf_stats_hash_table_data(char *buf, size_t size, void *data) mutex_exit(&db->db_mtx); } - mutex_exit(DBUF_HASH_MUTEX(h, dsh->idx)); + rw_exit(DBUF_HASH_RWLOCK(h, dsh->idx)); return (error); } diff --git a/module/zfs/dmu.c b/module/zfs/dmu.c index 0c528f68ccf4..4e7127bd1bab 100644 --- a/module/zfs/dmu.c +++ b/module/zfs/dmu.c @@ -73,9 +73,13 @@ int zfs_nopwrite_enabled = 1; unsigned long zfs_per_txg_dirty_frees_percent = 5; /* - * Enable/disable forcing txg sync when dirty in dmu_offset_next. + * Enable/disable forcing txg sync when dirty checking for holes with lseek(). + * By default this is enabled to ensure accurate hole reporting, it can result + * in a significant performance penalty for lseek(SEEK_HOLE) heavy workloads. + * Disabling this option will result in holes never being reported in dirty + * files which is always safe. */ -int zfs_dmu_offset_next_sync = 0; +int zfs_dmu_offset_next_sync = 1; /* * Limit the amount we can prefetch with one call to this amount. This @@ -2110,8 +2114,8 @@ dmu_offset_next(objset_t *os, uint64_t object, boolean_t hole, uint64_t *off) * If the zfs_dmu_offset_next_sync module option is enabled * then strict hole reporting has been requested. Dirty * dnodes must be synced to disk to accurately report all - * holes. When disabled (the default) dirty dnodes are - * reported to not have any holes which is always safe. + * holes. When disabled dirty dnodes are reported to not + * have any holes which is always safe. * * When called by zfs_holey_common() the zp->z_rangelock * is held to prevent zfs_write() and mmap writeback from diff --git a/module/zfs/dsl_scan.c b/module/zfs/dsl_scan.c index fac658180e1f..d7050487ff82 100644 --- a/module/zfs/dsl_scan.c +++ b/module/zfs/dsl_scan.c @@ -1268,9 +1268,12 @@ dsl_scan_should_clear(dsl_scan_t *scn) mutex_enter(&tvd->vdev_scan_io_queue_lock); queue = tvd->vdev_scan_io_queue; if (queue != NULL) { - /* # extents in exts_by_size = # in exts_by_addr */ + /* + * # of extents in exts_by_size = # in exts_by_addr. + * B-tree efficiency is ~75%, but can be as low as 50%. + */ mused += zfs_btree_numnodes(&queue->q_exts_by_size) * - sizeof (range_seg_gap_t) + queue->q_sio_memused; + 3 * sizeof (range_seg_gap_t) + queue->q_sio_memused; } mutex_exit(&tvd->vdev_scan_io_queue_lock); } diff --git a/module/zfs/metaslab.c b/module/zfs/metaslab.c index f367bea98267..9e216c38d954 100644 --- a/module/zfs/metaslab.c +++ b/module/zfs/metaslab.c @@ -2659,7 +2659,8 @@ metaslab_init(metaslab_group_t *mg, uint64_t id, uint64_t object, /* * We only open space map objects that already exist. All others - * will be opened when we finally allocate an object for it. + * will be opened when we finally allocate an object for it. For + * readonly pools there is no need to open the space map object. * * Note: * When called from vdev_expand(), we can't call into the DMU as @@ -2668,7 +2669,8 @@ metaslab_init(metaslab_group_t *mg, uint64_t id, uint64_t object, * that case, the object parameter is zero though, so we won't * call into the DMU. */ - if (object != 0) { + if (object != 0 && !(spa->spa_mode == SPA_MODE_READ && + !spa->spa_read_spacemaps)) { error = space_map_open(&ms->ms_sm, mos, object, ms->ms_start, ms->ms_size, vd->vdev_ashift); diff --git a/module/zfs/refcount.c b/module/zfs/refcount.c index 354e021d9d26..35a379dded69 100644 --- a/module/zfs/refcount.c +++ b/module/zfs/refcount.c @@ -318,6 +318,14 @@ zfs_refcount_not_held(zfs_refcount_t *rc, const void *holder) return (B_TRUE); } +EXPORT_SYMBOL(zfs_refcount_create); +EXPORT_SYMBOL(zfs_refcount_destroy); +EXPORT_SYMBOL(zfs_refcount_is_zero); +EXPORT_SYMBOL(zfs_refcount_count); +EXPORT_SYMBOL(zfs_refcount_add); +EXPORT_SYMBOL(zfs_refcount_remove); +EXPORT_SYMBOL(zfs_refcount_held); + /* BEGIN CSTYLED */ ZFS_MODULE_PARAM(zfs, ,reference_tracking_enable, INT, ZMOD_RW, "Track reference holders to refcount_t objects"); diff --git a/module/zfs/spa.c b/module/zfs/spa.c index 7c49ced9998a..dfa73483accf 100644 --- a/module/zfs/spa.c +++ b/module/zfs/spa.c @@ -180,6 +180,12 @@ boolean_t spa_create_process = B_TRUE; /* no process ==> no sysdc */ */ boolean_t spa_load_verify_dryrun = B_FALSE; +/* + * Allow read spacemaps in case of readonly import (spa_mode == SPA_MODE_READ). + * This is used by zdb for spacemaps verification. + */ +boolean_t spa_mode_readable_spacemaps = B_FALSE; + /* * This (illegal) pool name is used when temporarily importing a spa_t in order * to get the vdev stats associated with the imported devices. @@ -1241,6 +1247,7 @@ spa_activate(spa_t *spa, spa_mode_t mode) spa->spa_state = POOL_STATE_ACTIVE; spa->spa_mode = mode; + spa->spa_read_spacemaps = spa_mode_readable_spacemaps; spa->spa_normal_class = metaslab_class_create(spa, zfs_metaslab_ops); spa->spa_log_class = metaslab_class_create(spa, zfs_metaslab_ops); diff --git a/module/zfs/spa_log_spacemap.c b/module/zfs/spa_log_spacemap.c index f4c2910ad7fe..8e14d9a833cd 100644 --- a/module/zfs/spa_log_spacemap.c +++ b/module/zfs/spa_log_spacemap.c @@ -493,12 +493,6 @@ spa_log_summary_decrement_blkcount(spa_t *spa, uint64_t blocks_gone) for (log_summary_entry_t *e = list_head(&spa->spa_log_summary); e != NULL; e = list_head(&spa->spa_log_summary)) { if (e->lse_blkcount > blocks_gone) { - /* - * Assert that we stopped at an entry that is not - * obsolete. - */ - ASSERT(e->lse_mscount != 0); - e->lse_blkcount -= blocks_gone; blocks_gone = 0; break; diff --git a/module/zfs/vdev.c b/module/zfs/vdev.c index 57dcfe72339d..a323b90a26a2 100644 --- a/module/zfs/vdev.c +++ b/module/zfs/vdev.c @@ -3147,6 +3147,12 @@ vdev_dtl_load(vdev_t *vd) if (vd->vdev_ops->vdev_op_leaf && vd->vdev_dtl_object != 0) { ASSERT(vdev_is_concrete(vd)); + /* + * If the dtl cannot be sync'd there is no need to open it. + */ + if (spa->spa_mode == SPA_MODE_READ && !spa->spa_read_spacemaps) + return (0); + error = space_map_open(&vd->vdev_dtl_sm, mos, vd->vdev_dtl_object, 0, -1ULL, 0); if (error) diff --git a/module/zfs/vdev_indirect.c b/module/zfs/vdev_indirect.c index b541058d94f8..8762855d46aa 100644 --- a/module/zfs/vdev_indirect.c +++ b/module/zfs/vdev_indirect.c @@ -1423,11 +1423,6 @@ vdev_indirect_repair(zio_t *zio) { indirect_vsd_t *iv = zio->io_vsd; - enum zio_flag flags = ZIO_FLAG_IO_REPAIR; - - if (!(zio->io_flags & (ZIO_FLAG_SCRUB | ZIO_FLAG_RESILVER))) - flags |= ZIO_FLAG_SELF_HEAL; - if (!spa_writeable(zio->io_spa)) return; diff --git a/module/zfs/vdev_removal.c b/module/zfs/vdev_removal.c index b51d862f6466..d7385cdf25de 100644 --- a/module/zfs/vdev_removal.c +++ b/module/zfs/vdev_removal.c @@ -1517,10 +1517,6 @@ spa_vdev_remove_thread(void *arg) * specified by zfs_removal_suspend_progress. We do this * solely from the test suite or during debugging. */ - uint64_t bytes_copied = - spa->spa_removing_phys.sr_copied; - for (int i = 0; i < TXG_SIZE; i++) - bytes_copied += svr->svr_bytes_done[i]; while (zfs_removal_suspend_progress && !svr->svr_thread_exit) delay(hz); diff --git a/module/zfs/zfs_fm.c b/module/zfs/zfs_fm.c index 87f793cb4e92..a05ff7330458 100644 --- a/module/zfs/zfs_fm.c +++ b/module/zfs/zfs_fm.c @@ -825,9 +825,6 @@ annotate_ecksum(nvlist_t *ereport, zio_bad_cksum_t *info, const uint64_t *good; const uint64_t *bad; - uint64_t allset = 0; - uint64_t allcleared = 0; - size_t nui64s = size / sizeof (uint64_t); size_t inline_size; @@ -929,9 +926,6 @@ annotate_ecksum(nvlist_t *ereport, zio_bad_cksum_t *info, // bits set in good, but not in bad cleared = (good[idx] & (~bad[idx])); - allset |= set; - allcleared |= cleared; - if (!no_inline) { ASSERT3U(offset, <, inline_size); eip->zei_bits_set[offset] = set; diff --git a/module/zfs/zvol.c b/module/zfs/zvol.c index 721a7b4b878e..59b05b4b08d0 100644 --- a/module/zfs/zvol.c +++ b/module/zfs/zvol.c @@ -1353,13 +1353,12 @@ static void zvol_rename_minors_impl(const char *oldname, const char *newname) { zvol_state_t *zv, *zv_next; - int oldnamelen, newnamelen; + int oldnamelen; if (zvol_inhibit_dev) return; oldnamelen = strlen(oldname); - newnamelen = strlen(newname); rw_enter(&zvol_state_lock, RW_READER); diff --git a/module/zstd/Makefile.in b/module/zstd/Makefile.in index 091f7cea3639..598409ca1627 100644 --- a/module/zstd/Makefile.in +++ b/module/zstd/Makefile.in @@ -37,3 +37,9 @@ $(MODULE)-objs += zstd_sparc.o all: mkdir -p lib + +gensymbols: + @OBJDUMP@ -t lib/zstd.o | awk '$$2 == "g" && !/ zfs_/ {print "#define\t" $$6 " zfs_" $$6}' | sort >> include/zstd_compat_wrapper.h + +checksymbols: + @OBJDUMP@ -t lib/zstd.o | awk '/file format/ {print} $$2 == "g" && !/ zfs_/ {++ret; print} END {exit ret}' diff --git a/module/zstd/include/zstd_compat_wrapper.h b/module/zstd/include/zstd_compat_wrapper.h index 339713590f96..5d20623a73f2 100644 --- a/module/zstd/include/zstd_compat_wrapper.h +++ b/module/zstd/include/zstd_compat_wrapper.h @@ -36,333 +36,273 @@ * This wrapper fixes a problem, in case the ZFS filesystem driver, is compiled * statically into the kernel. * This will cause a symbol collision with the older in-kernel zstd library. - * The following macros will simply rename all local zstd symbols and references * - * Note: if the zstd library for zfs is updated to a newer version, this macro - * list usually needs to be updated. - * this can be done with some hand crafting of the output of the following - * script - * nm zstd.o | awk '{print "#define "$3 " zfs_" $3}' > macrotable + * On update, truncate this file at the scissor line, rebuild the module, + * and make gensymbols. */ #define BIT_initDStream zfs_BIT_initDStream #define BIT_mask zfs_BIT_mask #define BIT_reloadDStream zfs_BIT_reloadDStream + + +/* -- >8 -- */ #define ERR_getErrorString zfs_ERR_getErrorString -#define FSE_NCountWriteBound zfs_FSE_NCountWriteBound -#define FSE_buildCTable zfs_FSE_buildCTable #define FSE_buildCTable_raw zfs_FSE_buildCTable_raw #define FSE_buildCTable_rle zfs_FSE_buildCTable_rle #define FSE_buildCTable_wksp zfs_FSE_buildCTable_wksp -#define FSE_buildDTable zfs_FSE_buildDTable +#define FSE_buildCTable zfs_FSE_buildCTable #define FSE_buildDTable_raw zfs_FSE_buildDTable_raw #define FSE_buildDTable_rle zfs_FSE_buildDTable_rle -#define FSE_compress zfs_FSE_compress +#define FSE_buildDTable zfs_FSE_buildDTable #define FSE_compress2 zfs_FSE_compress2 #define FSE_compressBound zfs_FSE_compressBound #define FSE_compress_usingCTable zfs_FSE_compress_usingCTable -#define FSE_compress_usingCTable_generic zfs_FSE_compress_usingCTable_generic #define FSE_compress_wksp zfs_FSE_compress_wksp +#define FSE_compress zfs_FSE_compress #define FSE_createCTable zfs_FSE_createCTable #define FSE_createDTable zfs_FSE_createDTable -#define FSE_decompress zfs_FSE_decompress #define FSE_decompress_usingDTable zfs_FSE_decompress_usingDTable #define FSE_decompress_wksp zfs_FSE_decompress_wksp +#define FSE_decompress zfs_FSE_decompress #define FSE_freeCTable zfs_FSE_freeCTable #define FSE_freeDTable zfs_FSE_freeDTable #define FSE_getErrorName zfs_FSE_getErrorName +#define FSE_isError zfs_FSE_isError +#define FSE_NCountWriteBound zfs_FSE_NCountWriteBound #define FSE_normalizeCount zfs_FSE_normalizeCount -#define FSE_optimalTableLog zfs_FSE_optimalTableLog #define FSE_optimalTableLog_internal zfs_FSE_optimalTableLog_internal +#define FSE_optimalTableLog zfs_FSE_optimalTableLog #define FSE_readNCount zfs_FSE_readNCount #define FSE_versionNumber zfs_FSE_versionNumber #define FSE_writeNCount zfs_FSE_writeNCount -#define HIST_count zfs_HIST_count -#define HIST_countFast zfs_HIST_countFast +#define g_debuglevel zfs_g_debuglevel #define HIST_countFast_wksp zfs_HIST_countFast_wksp -#define HIST_count_parallel_wksp zfs_HIST_count_parallel_wksp +#define HIST_countFast zfs_HIST_countFast #define HIST_count_simple zfs_HIST_count_simple #define HIST_count_wksp zfs_HIST_count_wksp -#define HUF_buildCTable zfs_HUF_buildCTable +#define HIST_count zfs_HIST_count +#define HIST_isError zfs_HIST_isError #define HUF_buildCTable_wksp zfs_HUF_buildCTable_wksp -#define HUF_compress zfs_HUF_compress -#define HUF_compress1X zfs_HUF_compress1X +#define HUF_buildCTable zfs_HUF_buildCTable #define HUF_compress1X_repeat zfs_HUF_compress1X_repeat #define HUF_compress1X_usingCTable zfs_HUF_compress1X_usingCTable #define HUF_compress1X_wksp zfs_HUF_compress1X_wksp +#define HUF_compress1X zfs_HUF_compress1X #define HUF_compress2 zfs_HUF_compress2 #define HUF_compress4X_repeat zfs_HUF_compress4X_repeat #define HUF_compress4X_usingCTable zfs_HUF_compress4X_usingCTable #define HUF_compress4X_wksp zfs_HUF_compress4X_wksp #define HUF_compressBound zfs_HUF_compressBound -#define HUF_compressWeights zfs_HUF_compressWeights -#define HUF_decompress zfs_HUF_decompress -#define HUF_decompress1X1 zfs_HUF_decompress1X1 -#define HUF_decompress1X1_DCtx zfs_HUF_decompress1X1_DCtx -#define HUF_decompress1X1_DCtx_wksp zfs_HUF_decompress1X1_DCtx_wksp +#define HUF_compress zfs_HUF_compress #define HUF_decompress1X1_DCtx_wksp_bmi2 zfs_HUF_decompress1X1_DCtx_wksp_bmi2 +#define HUF_decompress1X1_DCtx_wksp zfs_HUF_decompress1X1_DCtx_wksp +#define HUF_decompress1X1_DCtx zfs_HUF_decompress1X1_DCtx #define HUF_decompress1X1_usingDTable zfs_HUF_decompress1X1_usingDTable -#define HUF_decompress1X2 zfs_HUF_decompress1X2 -#define HUF_decompress1X2_DCtx zfs_HUF_decompress1X2_DCtx +#define HUF_decompress1X1 zfs_HUF_decompress1X1 #define HUF_decompress1X2_DCtx_wksp zfs_HUF_decompress1X2_DCtx_wksp +#define HUF_decompress1X2_DCtx zfs_HUF_decompress1X2_DCtx #define HUF_decompress1X2_usingDTable zfs_HUF_decompress1X2_usingDTable -#define HUF_decompress1X_DCtx zfs_HUF_decompress1X_DCtx +#define HUF_decompress1X2 zfs_HUF_decompress1X2 #define HUF_decompress1X_DCtx_wksp zfs_HUF_decompress1X_DCtx_wksp -#define HUF_decompress1X_usingDTable zfs_HUF_decompress1X_usingDTable +#define HUF_decompress1X_DCtx zfs_HUF_decompress1X_DCtx #define HUF_decompress1X_usingDTable_bmi2 zfs_HUF_decompress1X_usingDTable_bmi2 -#define HUF_decompress4X1 zfs_HUF_decompress4X1 -#define HUF_decompress4X1_DCtx zfs_HUF_decompress4X1_DCtx +#define HUF_decompress1X_usingDTable zfs_HUF_decompress1X_usingDTable #define HUF_decompress4X1_DCtx_wksp zfs_HUF_decompress4X1_DCtx_wksp +#define HUF_decompress4X1_DCtx zfs_HUF_decompress4X1_DCtx #define HUF_decompress4X1_usingDTable zfs_HUF_decompress4X1_usingDTable -#define HUF_decompress4X2 zfs_HUF_decompress4X2 -#define HUF_decompress4X2_DCtx zfs_HUF_decompress4X2_DCtx +#define HUF_decompress4X1 zfs_HUF_decompress4X1 #define HUF_decompress4X2_DCtx_wksp zfs_HUF_decompress4X2_DCtx_wksp +#define HUF_decompress4X2_DCtx zfs_HUF_decompress4X2_DCtx #define HUF_decompress4X2_usingDTable zfs_HUF_decompress4X2_usingDTable +#define HUF_decompress4X2 zfs_HUF_decompress4X2 #define HUF_decompress4X_DCtx zfs_HUF_decompress4X_DCtx -#define HUF_decompress4X_hufOnly zfs_HUF_decompress4X_hufOnly +#define HUF_decompress4X_hufOnly_wksp_bmi2 zfs_HUF_decompress4X_hufOnly_wksp_bmi2 #define HUF_decompress4X_hufOnly_wksp zfs_HUF_decompress4X_hufOnly_wksp -#define HUF_decompress4X_hufOnly_wksp_bmi2 \ - zfs_HUF_decompress4X_hufOnly_wksp_bmi2 -#define HUF_decompress4X_usingDTable zfs_HUF_decompress4X_usingDTable +#define HUF_decompress4X_hufOnly zfs_HUF_decompress4X_hufOnly #define HUF_decompress4X_usingDTable_bmi2 zfs_HUF_decompress4X_usingDTable_bmi2 +#define HUF_decompress4X_usingDTable zfs_HUF_decompress4X_usingDTable +#define HUF_decompress zfs_HUF_decompress #define HUF_estimateCompressedSize zfs_HUF_estimateCompressedSize -#define HUF_fillDTableX2Level2 zfs_HUF_fillDTableX2Level2 #define HUF_getErrorName zfs_HUF_getErrorName #define HUF_getNbBits zfs_HUF_getNbBits +#define HUF_isError zfs_HUF_isError #define HUF_optimalTableLog zfs_HUF_optimalTableLog #define HUF_readCTable zfs_HUF_readCTable -#define HUF_readDTableX1 zfs_HUF_readDTableX1 #define HUF_readDTableX1_wksp zfs_HUF_readDTableX1_wksp -#define HUF_readDTableX2 zfs_HUF_readDTableX2 +#define HUF_readDTableX1 zfs_HUF_readDTableX1 #define HUF_readDTableX2_wksp zfs_HUF_readDTableX2_wksp +#define HUF_readDTableX2 zfs_HUF_readDTableX2 #define HUF_readStats zfs_HUF_readStats #define HUF_selectDecoder zfs_HUF_selectDecoder -#define HUF_setMaxHeight zfs_HUF_setMaxHeight #define HUF_validateCTable zfs_HUF_validateCTable #define HUF_writeCTable zfs_HUF_writeCTable -#define LL_base zfs_LL_base -#define LL_bits zfs_LL_bits -#define LL_defaultDTable zfs_LL_defaultDTable -#define LL_defaultNorm zfs_LL_defaultNorm -#define ML_base zfs_ML_base -#define ML_bits zfs_ML_bits -#define ML_defaultDTable zfs_ML_defaultDTable -#define ML_defaultNorm zfs_ML_defaultNorm -#define OF_base zfs_OF_base -#define OF_bits zfs_OF_bits -#define OF_defaultDTable zfs_OF_defaultDTable -#define OF_defaultNorm zfs_OF_defaultNorm #define POOL_add zfs_POOL_add -#define POOL_create zfs_POOL_create #define POOL_create_advanced zfs_POOL_create_advanced +#define POOL_create zfs_POOL_create #define POOL_free zfs_POOL_free #define POOL_resize zfs_POOL_resize #define POOL_sizeof zfs_POOL_sizeof #define POOL_tryAdd zfs_POOL_tryAdd +#define ZSTD_adjustCParams zfs_ZSTD_adjustCParams +#define ZSTD_buildCTable zfs_ZSTD_buildCTable +#define ZSTD_buildFSETable zfs_ZSTD_buildFSETable +#define ZSTD_calloc zfs_ZSTD_calloc +#define ZSTD_CCtx_getParameter zfs_ZSTD_CCtx_getParameter +#define ZSTD_CCtx_loadDictionary_advanced zfs_ZSTD_CCtx_loadDictionary_advanced +#define ZSTD_CCtx_loadDictionary_byReference zfs_ZSTD_CCtx_loadDictionary_byReference +#define ZSTD_CCtx_loadDictionary zfs_ZSTD_CCtx_loadDictionary #define ZSTD_CCtxParams_getParameter zfs_ZSTD_CCtxParams_getParameter -#define ZSTD_CCtxParams_init zfs_ZSTD_CCtxParams_init #define ZSTD_CCtxParams_init_advanced zfs_ZSTD_CCtxParams_init_advanced +#define ZSTD_CCtxParams_init zfs_ZSTD_CCtxParams_init #define ZSTD_CCtxParams_reset zfs_ZSTD_CCtxParams_reset #define ZSTD_CCtxParams_setParameter zfs_ZSTD_CCtxParams_setParameter -#define ZSTD_CCtx_getParameter zfs_ZSTD_CCtx_getParameter -#define ZSTD_CCtx_loadDictionary zfs_ZSTD_CCtx_loadDictionary -#define ZSTD_CCtx_loadDictionary_advanced zfs_ZSTD_CCtx_loadDictionary_advanced -#define ZSTD_CCtx_loadDictionary_byReference \ - zfs_ZSTD_CCtx_loadDictionary_byReference #define ZSTD_CCtx_refCDict zfs_ZSTD_CCtx_refCDict -#define ZSTD_CCtx_refPrefix zfs_ZSTD_CCtx_refPrefix #define ZSTD_CCtx_refPrefix_advanced zfs_ZSTD_CCtx_refPrefix_advanced +#define ZSTD_CCtx_refPrefix zfs_ZSTD_CCtx_refPrefix #define ZSTD_CCtx_reset zfs_ZSTD_CCtx_reset +#define ZSTD_CCtx_setParametersUsingCCtxParams zfs_ZSTD_CCtx_setParametersUsingCCtxParams #define ZSTD_CCtx_setParameter zfs_ZSTD_CCtx_setParameter -#define ZSTD_CCtx_setParametersUsingCCtxParams \ - zfs_ZSTD_CCtx_setParametersUsingCCtxParams #define ZSTD_CCtx_setPledgedSrcSize zfs_ZSTD_CCtx_setPledgedSrcSize -#define ZSTD_CStreamInSize zfs_ZSTD_CStreamInSize -#define ZSTD_CStreamOutSize zfs_ZSTD_CStreamOutSize -#define ZSTD_DCtx_loadDictionary zfs_ZSTD_DCtx_loadDictionary -#define ZSTD_DCtx_loadDictionary_advanced zfs_ZSTD_DCtx_loadDictionary_advanced -#define ZSTD_DCtx_loadDictionary_byReference \ - zfs_ZSTD_DCtx_loadDictionary_byReference -#define ZSTD_DCtx_refDDict zfs_ZSTD_DCtx_refDDict -#define ZSTD_DCtx_refPrefix zfs_ZSTD_DCtx_refPrefix -#define ZSTD_DCtx_refPrefix_advanced zfs_ZSTD_DCtx_refPrefix_advanced -#define ZSTD_DCtx_reset zfs_ZSTD_DCtx_reset -#define ZSTD_DCtx_setFormat zfs_ZSTD_DCtx_setFormat -#define ZSTD_DCtx_setMaxWindowSize zfs_ZSTD_DCtx_setMaxWindowSize -#define ZSTD_DCtx_setParameter zfs_ZSTD_DCtx_setParameter -#define ZSTD_DDict_dictContent zfs_ZSTD_DDict_dictContent -#define ZSTD_DDict_dictSize zfs_ZSTD_DDict_dictSize -#define ZSTD_DStreamInSize zfs_ZSTD_DStreamInSize -#define ZSTD_DStreamOutSize zfs_ZSTD_DStreamOutSize -#define ZSTD_DUBT_findBestMatch zfs_ZSTD_DUBT_findBestMatch -#define ZSTD_NCountCost zfs_ZSTD_NCountCost -#define ZSTD_XXH64_digest zfs_ZSTD_XXH64_digest -#define ZSTD_adjustCParams zfs_ZSTD_adjustCParams -#define ZSTD_assignParamsToCCtxParams zfs_ZSTD_assignParamsToCCtxParams -#define ZSTD_buildCTable zfs_ZSTD_buildCTable -#define ZSTD_buildFSETable zfs_ZSTD_buildFSETable -#define ZSTD_buildSeqStore zfs_ZSTD_buildSeqStore -#define ZSTD_buildSeqTable zfs_ZSTD_buildSeqTable -#define ZSTD_cParam_getBounds zfs_ZSTD_cParam_getBounds -#define ZSTD_cParam_withinBounds zfs_ZSTD_cParam_withinBounds -#define ZSTD_calloc zfs_ZSTD_calloc -#define ZSTD_checkCParams zfs_ZSTD_checkCParams #define ZSTD_checkContinuity zfs_ZSTD_checkContinuity -#define ZSTD_compress zfs_ZSTD_compress +#define ZSTD_checkCParams zfs_ZSTD_checkCParams #define ZSTD_compress2 zfs_ZSTD_compress2 -#define ZSTD_compressBegin zfs_ZSTD_compressBegin +#define ZSTD_compress_advanced_internal zfs_ZSTD_compress_advanced_internal +#define ZSTD_compress_advanced zfs_ZSTD_compress_advanced +#define ZSTD_compressBegin_advanced_internal zfs_ZSTD_compressBegin_advanced_internal #define ZSTD_compressBegin_advanced zfs_ZSTD_compressBegin_advanced -#define ZSTD_compressBegin_advanced_internal \ - zfs_ZSTD_compressBegin_advanced_internal +#define ZSTD_compressBegin_usingCDict_advanced zfs_ZSTD_compressBegin_usingCDict_advanced #define ZSTD_compressBegin_usingCDict zfs_ZSTD_compressBegin_usingCDict -#define ZSTD_compressBegin_usingCDict_advanced \ - zfs_ZSTD_compressBegin_usingCDict_advanced #define ZSTD_compressBegin_usingDict zfs_ZSTD_compressBegin_usingDict -#define ZSTD_compressBlock zfs_ZSTD_compressBlock +#define ZSTD_compressBegin zfs_ZSTD_compressBegin +#define ZSTD_compressBlock_btlazy2_dictMatchState zfs_ZSTD_compressBlock_btlazy2_dictMatchState +#define ZSTD_compressBlock_btlazy2_extDict zfs_ZSTD_compressBlock_btlazy2_extDict #define ZSTD_compressBlock_btlazy2 zfs_ZSTD_compressBlock_btlazy2 -#define ZSTD_compressBlock_btlazy2_dictMatchState \ - zfs_ZSTD_compressBlock_btlazy2_dictMatchState -#define ZSTD_compressBlock_btlazy2_extDict \ - zfs_ZSTD_compressBlock_btlazy2_extDict -#define ZSTD_compressBlock_btopt zfs_ZSTD_compressBlock_btopt -#define ZSTD_compressBlock_btopt_dictMatchState \ - zfs_ZSTD_compressBlock_btopt_dictMatchState +#define ZSTD_compressBlock_btopt_dictMatchState zfs_ZSTD_compressBlock_btopt_dictMatchState #define ZSTD_compressBlock_btopt_extDict zfs_ZSTD_compressBlock_btopt_extDict -#define ZSTD_compressBlock_btultra zfs_ZSTD_compressBlock_btultra +#define ZSTD_compressBlock_btopt zfs_ZSTD_compressBlock_btopt #define ZSTD_compressBlock_btultra2 zfs_ZSTD_compressBlock_btultra2 -#define ZSTD_compressBlock_btultra_dictMatchState \ - zfs_ZSTD_compressBlock_btultra_dictMatchState -#define ZSTD_compressBlock_btultra_extDict \ - zfs_ZSTD_compressBlock_btultra_extDict +#define ZSTD_compressBlock_btultra_dictMatchState zfs_ZSTD_compressBlock_btultra_dictMatchState +#define ZSTD_compressBlock_btultra_extDict zfs_ZSTD_compressBlock_btultra_extDict +#define ZSTD_compressBlock_btultra zfs_ZSTD_compressBlock_btultra +#define ZSTD_compressBlock_doubleFast_dictMatchState zfs_ZSTD_compressBlock_doubleFast_dictMatchState +#define ZSTD_compressBlock_doubleFast_extDict zfs_ZSTD_compressBlock_doubleFast_extDict #define ZSTD_compressBlock_doubleFast zfs_ZSTD_compressBlock_doubleFast -#define ZSTD_compressBlock_doubleFast_dictMatchState \ - zfs_ZSTD_compressBlock_doubleFast_dictMatchState -#define ZSTD_compressBlock_doubleFast_extDict \ - zfs_ZSTD_compressBlock_doubleFast_extDict -#define ZSTD_compressBlock_doubleFast_extDict_generic \ - zfs_ZSTD_compressBlock_doubleFast_extDict_generic -#define ZSTD_compressBlock_fast zfs_ZSTD_compressBlock_fast -#define ZSTD_compressBlock_fast_dictMatchState \ - zfs_ZSTD_compressBlock_fast_dictMatchState +#define ZSTD_compressBlock_fast_dictMatchState zfs_ZSTD_compressBlock_fast_dictMatchState #define ZSTD_compressBlock_fast_extDict zfs_ZSTD_compressBlock_fast_extDict -#define ZSTD_compressBlock_fast_extDict_generic \ - zfs_ZSTD_compressBlock_fast_extDict_generic -#define ZSTD_compressBlock_greedy zfs_ZSTD_compressBlock_greedy -#define ZSTD_compressBlock_greedy_dictMatchState \ - zfs_ZSTD_compressBlock_greedy_dictMatchState +#define ZSTD_compressBlock_fast zfs_ZSTD_compressBlock_fast +#define ZSTD_compressBlock_greedy_dictMatchState zfs_ZSTD_compressBlock_greedy_dictMatchState #define ZSTD_compressBlock_greedy_extDict zfs_ZSTD_compressBlock_greedy_extDict -#define ZSTD_compressBlock_internal zfs_ZSTD_compressBlock_internal -#define ZSTD_compressBlock_lazy zfs_ZSTD_compressBlock_lazy -#define ZSTD_compressBlock_lazy2 zfs_ZSTD_compressBlock_lazy2 -#define ZSTD_compressBlock_lazy2_dictMatchState \ - zfs_ZSTD_compressBlock_lazy2_dictMatchState +#define ZSTD_compressBlock_greedy zfs_ZSTD_compressBlock_greedy +#define ZSTD_compressBlock_lazy2_dictMatchState zfs_ZSTD_compressBlock_lazy2_dictMatchState #define ZSTD_compressBlock_lazy2_extDict zfs_ZSTD_compressBlock_lazy2_extDict -#define ZSTD_compressBlock_lazy_dictMatchState \ - zfs_ZSTD_compressBlock_lazy_dictMatchState +#define ZSTD_compressBlock_lazy2 zfs_ZSTD_compressBlock_lazy2 +#define ZSTD_compressBlock_lazy_dictMatchState zfs_ZSTD_compressBlock_lazy_dictMatchState #define ZSTD_compressBlock_lazy_extDict zfs_ZSTD_compressBlock_lazy_extDict +#define ZSTD_compressBlock_lazy zfs_ZSTD_compressBlock_lazy +#define ZSTD_compressBlock zfs_ZSTD_compressBlock #define ZSTD_compressBound zfs_ZSTD_compressBound #define ZSTD_compressCCtx zfs_ZSTD_compressCCtx #define ZSTD_compressContinue zfs_ZSTD_compressContinue -#define ZSTD_compressContinue_internal zfs_ZSTD_compressContinue_internal #define ZSTD_compressEnd zfs_ZSTD_compressEnd #define ZSTD_compressLiterals zfs_ZSTD_compressLiterals #define ZSTD_compressRleLiteralsBlock zfs_ZSTD_compressRleLiteralsBlock -#define ZSTD_compressStream zfs_ZSTD_compressStream -#define ZSTD_compressStream2 zfs_ZSTD_compressStream2 #define ZSTD_compressStream2_simpleArgs zfs_ZSTD_compressStream2_simpleArgs +#define ZSTD_compressStream2 zfs_ZSTD_compressStream2 +#define ZSTD_compressStream zfs_ZSTD_compressStream #define ZSTD_compressSuperBlock zfs_ZSTD_compressSuperBlock -#define ZSTD_compress_advanced zfs_ZSTD_compress_advanced -#define ZSTD_compress_advanced_internal zfs_ZSTD_compress_advanced_internal -#define ZSTD_compress_internal zfs_ZSTD_compress_internal -#define ZSTD_compress_usingCDict zfs_ZSTD_compress_usingCDict #define ZSTD_compress_usingCDict_advanced zfs_ZSTD_compress_usingCDict_advanced +#define ZSTD_compress_usingCDict zfs_ZSTD_compress_usingCDict #define ZSTD_compress_usingDict zfs_ZSTD_compress_usingDict +#define ZSTD_compress zfs_ZSTD_compress #define ZSTD_copyCCtx zfs_ZSTD_copyCCtx #define ZSTD_copyDCtx zfs_ZSTD_copyDCtx #define ZSTD_copyDDictParameters zfs_ZSTD_copyDDictParameters -#define ZSTD_count zfs_ZSTD_count -#define ZSTD_count_2segments zfs_ZSTD_count_2segments -#define ZSTD_createCCtx zfs_ZSTD_createCCtx -#define ZSTD_createCCtxParams zfs_ZSTD_createCCtxParams +#define ZSTD_cParam_getBounds zfs_ZSTD_cParam_getBounds #define ZSTD_createCCtx_advanced zfs_ZSTD_createCCtx_advanced -#define ZSTD_createCDict zfs_ZSTD_createCDict +#define ZSTD_createCCtxParams zfs_ZSTD_createCCtxParams +#define ZSTD_createCCtx zfs_ZSTD_createCCtx #define ZSTD_createCDict_advanced zfs_ZSTD_createCDict_advanced #define ZSTD_createCDict_byReference zfs_ZSTD_createCDict_byReference -#define ZSTD_createCStream zfs_ZSTD_createCStream +#define ZSTD_createCDict zfs_ZSTD_createCDict #define ZSTD_createCStream_advanced zfs_ZSTD_createCStream_advanced -#define ZSTD_createDCtx zfs_ZSTD_createDCtx +#define ZSTD_createCStream zfs_ZSTD_createCStream #define ZSTD_createDCtx_advanced zfs_ZSTD_createDCtx_advanced -#define ZSTD_createDDict zfs_ZSTD_createDDict +#define ZSTD_createDCtx zfs_ZSTD_createDCtx #define ZSTD_createDDict_advanced zfs_ZSTD_createDDict_advanced #define ZSTD_createDDict_byReference zfs_ZSTD_createDDict_byReference -#define ZSTD_createDStream zfs_ZSTD_createDStream +#define ZSTD_createDDict zfs_ZSTD_createDDict #define ZSTD_createDStream_advanced zfs_ZSTD_createDStream_advanced +#define ZSTD_createDStream zfs_ZSTD_createDStream #define ZSTD_crossEntropyCost zfs_ZSTD_crossEntropyCost +#define ZSTD_CStreamInSize zfs_ZSTD_CStreamInSize +#define ZSTD_CStreamOutSize zfs_ZSTD_CStreamOutSize #define ZSTD_cycleLog zfs_ZSTD_cycleLog -#define ZSTD_dParam_getBounds zfs_ZSTD_dParam_getBounds +#define ZSTD_DCtx_loadDictionary_advanced zfs_ZSTD_DCtx_loadDictionary_advanced +#define ZSTD_DCtx_loadDictionary_byReference zfs_ZSTD_DCtx_loadDictionary_byReference +#define ZSTD_DCtx_loadDictionary zfs_ZSTD_DCtx_loadDictionary +#define ZSTD_DCtx_refDDict zfs_ZSTD_DCtx_refDDict +#define ZSTD_DCtx_refPrefix_advanced zfs_ZSTD_DCtx_refPrefix_advanced +#define ZSTD_DCtx_refPrefix zfs_ZSTD_DCtx_refPrefix +#define ZSTD_DCtx_reset zfs_ZSTD_DCtx_reset +#define ZSTD_DCtx_setFormat zfs_ZSTD_DCtx_setFormat +#define ZSTD_DCtx_setMaxWindowSize zfs_ZSTD_DCtx_setMaxWindowSize +#define ZSTD_DCtx_setParameter zfs_ZSTD_DCtx_setParameter +#define ZSTD_DDict_dictContent zfs_ZSTD_DDict_dictContent +#define ZSTD_DDict_dictSize zfs_ZSTD_DDict_dictSize #define ZSTD_decodeLiteralsBlock zfs_ZSTD_decodeLiteralsBlock #define ZSTD_decodeSeqHeaders zfs_ZSTD_decodeSeqHeaders #define ZSTD_decodingBufferSize_min zfs_ZSTD_decodingBufferSize_min -#define ZSTD_decompress zfs_ZSTD_decompress -#define ZSTD_decompressBegin zfs_ZSTD_decompressBegin #define ZSTD_decompressBegin_usingDDict zfs_ZSTD_decompressBegin_usingDDict #define ZSTD_decompressBegin_usingDict zfs_ZSTD_decompressBegin_usingDict -#define ZSTD_decompressBlock zfs_ZSTD_decompressBlock +#define ZSTD_decompressBegin zfs_ZSTD_decompressBegin #define ZSTD_decompressBlock_internal zfs_ZSTD_decompressBlock_internal +#define ZSTD_decompressBlock zfs_ZSTD_decompressBlock #define ZSTD_decompressBound zfs_ZSTD_decompressBound #define ZSTD_decompressContinue zfs_ZSTD_decompressContinue -#define ZSTD_decompressContinueStream zfs_ZSTD_decompressContinueStream #define ZSTD_decompressDCtx zfs_ZSTD_decompressDCtx -#define ZSTD_decompressMultiFrame zfs_ZSTD_decompressMultiFrame -#define ZSTD_decompressStream zfs_ZSTD_decompressStream #define ZSTD_decompressStream_simpleArgs zfs_ZSTD_decompressStream_simpleArgs +#define ZSTD_decompressStream zfs_ZSTD_decompressStream #define ZSTD_decompress_usingDDict zfs_ZSTD_decompress_usingDDict #define ZSTD_decompress_usingDict zfs_ZSTD_decompress_usingDict -#define ZSTD_defaultCParameters zfs_ZSTD_defaultCParameters -#define ZSTD_did_fieldSize zfs_ZSTD_did_fieldSize +#define ZSTD_decompress zfs_ZSTD_decompress +#define ZSTD_dParam_getBounds zfs_ZSTD_dParam_getBounds +#define ZSTD_DStreamInSize zfs_ZSTD_DStreamInSize +#define ZSTD_DStreamOutSize zfs_ZSTD_DStreamOutSize #define ZSTD_encodeSequences zfs_ZSTD_encodeSequences -#define ZSTD_encodeSequences_default zfs_ZSTD_encodeSequences_default #define ZSTD_endStream zfs_ZSTD_endStream +#define ZSTD_estimateCCtxSize_usingCCtxParams zfs_ZSTD_estimateCCtxSize_usingCCtxParams +#define ZSTD_estimateCCtxSize_usingCParams zfs_ZSTD_estimateCCtxSize_usingCParams #define ZSTD_estimateCCtxSize zfs_ZSTD_estimateCCtxSize -#define ZSTD_estimateCCtxSize_usingCCtxParams \ - zfs_ZSTD_estimateCCtxSize_usingCCtxParams -#define ZSTD_estimateCCtxSize_usingCParams \ - zfs_ZSTD_estimateCCtxSize_usingCParams -#define ZSTD_estimateCDictSize zfs_ZSTD_estimateCDictSize #define ZSTD_estimateCDictSize_advanced zfs_ZSTD_estimateCDictSize_advanced +#define ZSTD_estimateCDictSize zfs_ZSTD_estimateCDictSize +#define ZSTD_estimateCStreamSize_usingCCtxParams zfs_ZSTD_estimateCStreamSize_usingCCtxParams +#define ZSTD_estimateCStreamSize_usingCParams zfs_ZSTD_estimateCStreamSize_usingCParams #define ZSTD_estimateCStreamSize zfs_ZSTD_estimateCStreamSize -#define ZSTD_estimateCStreamSize_usingCCtxParams \ - zfs_ZSTD_estimateCStreamSize_usingCCtxParams -#define ZSTD_estimateCStreamSize_usingCParams \ - zfs_ZSTD_estimateCStreamSize_usingCParams #define ZSTD_estimateDCtxSize zfs_ZSTD_estimateDCtxSize #define ZSTD_estimateDDictSize zfs_ZSTD_estimateDDictSize +#define ZSTD_estimateDStreamSize_fromFrame zfs_ZSTD_estimateDStreamSize_fromFrame #define ZSTD_estimateDStreamSize zfs_ZSTD_estimateDStreamSize -#define ZSTD_estimateDStreamSize_fromFrame \ - zfs_ZSTD_estimateDStreamSize_fromFrame -#define ZSTD_fcs_fieldSize zfs_ZSTD_fcs_fieldSize #define ZSTD_fillDoubleHashTable zfs_ZSTD_fillDoubleHashTable #define ZSTD_fillHashTable zfs_ZSTD_fillHashTable #define ZSTD_findDecompressedSize zfs_ZSTD_findDecompressedSize #define ZSTD_findFrameCompressedSize zfs_ZSTD_findFrameCompressedSize -#define ZSTD_findFrameSizeInfo zfs_ZSTD_findFrameSizeInfo #define ZSTD_flushStream zfs_ZSTD_flushStream #define ZSTD_frameHeaderSize zfs_ZSTD_frameHeaderSize -#define ZSTD_free zfs_ZSTD_free -#define ZSTD_freeCCtx zfs_ZSTD_freeCCtx #define ZSTD_freeCCtxParams zfs_ZSTD_freeCCtxParams +#define ZSTD_freeCCtx zfs_ZSTD_freeCCtx #define ZSTD_freeCDict zfs_ZSTD_freeCDict #define ZSTD_freeCStream zfs_ZSTD_freeCStream #define ZSTD_freeDCtx zfs_ZSTD_freeDCtx #define ZSTD_freeDDict zfs_ZSTD_freeDDict #define ZSTD_freeDStream zfs_ZSTD_freeDStream +#define ZSTD_free zfs_ZSTD_free #define ZSTD_fseBitCost zfs_ZSTD_fseBitCost #define ZSTD_getBlockSize zfs_ZSTD_getBlockSize -#define ZSTD_getCParams zfs_ZSTD_getCParams +#define ZSTD_getcBlockSize zfs_ZSTD_getcBlockSize #define ZSTD_getCParamsFromCCtxParams zfs_ZSTD_getCParamsFromCCtxParams #define ZSTD_getCParamsFromCDict zfs_ZSTD_getCParamsFromCDict -#define ZSTD_getCParams_internal zfs_ZSTD_getCParams_internal -#define ZSTD_getDDict zfs_ZSTD_getDDict +#define ZSTD_getCParams zfs_ZSTD_getCParams #define ZSTD_getDecompressedSize zfs_ZSTD_getDecompressedSize #define ZSTD_getDictID_fromDDict zfs_ZSTD_getDictID_fromDDict #define ZSTD_getDictID_fromDict zfs_ZSTD_getDictID_fromDict @@ -371,39 +311,29 @@ #define ZSTD_getErrorName zfs_ZSTD_getErrorName #define ZSTD_getErrorString zfs_ZSTD_getErrorString #define ZSTD_getFrameContentSize zfs_ZSTD_getFrameContentSize -#define ZSTD_getFrameHeader zfs_ZSTD_getFrameHeader #define ZSTD_getFrameHeader_advanced zfs_ZSTD_getFrameHeader_advanced +#define ZSTD_getFrameHeader zfs_ZSTD_getFrameHeader #define ZSTD_getFrameProgression zfs_ZSTD_getFrameProgression #define ZSTD_getParams zfs_ZSTD_getParams #define ZSTD_getSeqStore zfs_ZSTD_getSeqStore #define ZSTD_getSequences zfs_ZSTD_getSequences -#define ZSTD_getcBlockSize zfs_ZSTD_getcBlockSize -#define ZSTD_hashPtr zfs_ZSTD_hashPtr -#define ZSTD_initCDict_internal zfs_ZSTD_initCDict_internal -#define ZSTD_initCStream zfs_ZSTD_initCStream #define ZSTD_initCStream_advanced zfs_ZSTD_initCStream_advanced #define ZSTD_initCStream_internal zfs_ZSTD_initCStream_internal #define ZSTD_initCStream_srcSize zfs_ZSTD_initCStream_srcSize +#define ZSTD_initCStream_usingCDict_advanced zfs_ZSTD_initCStream_usingCDict_advanced #define ZSTD_initCStream_usingCDict zfs_ZSTD_initCStream_usingCDict -#define ZSTD_initCStream_usingCDict_advanced \ - zfs_ZSTD_initCStream_usingCDict_advanced #define ZSTD_initCStream_usingDict zfs_ZSTD_initCStream_usingDict -#define ZSTD_initDDict_internal zfs_ZSTD_initDDict_internal -#define ZSTD_initDStream zfs_ZSTD_initDStream +#define ZSTD_initCStream zfs_ZSTD_initCStream #define ZSTD_initDStream_usingDDict zfs_ZSTD_initDStream_usingDDict #define ZSTD_initDStream_usingDict zfs_ZSTD_initDStream_usingDict -#define ZSTD_initFseState zfs_ZSTD_initFseState +#define ZSTD_initDStream zfs_ZSTD_initDStream #define ZSTD_initStaticCCtx zfs_ZSTD_initStaticCCtx #define ZSTD_initStaticCDict zfs_ZSTD_initStaticCDict #define ZSTD_initStaticCStream zfs_ZSTD_initStaticCStream #define ZSTD_initStaticDCtx zfs_ZSTD_initStaticDCtx #define ZSTD_initStaticDDict zfs_ZSTD_initStaticDDict #define ZSTD_initStaticDStream zfs_ZSTD_initStaticDStream -#define ZSTD_initStats_ultra zfs_ZSTD_initStats_ultra #define ZSTD_insertAndFindFirstIndex zfs_ZSTD_insertAndFindFirstIndex -#define ZSTD_insertAndFindFirstIndexHash3 zfs_ZSTD_insertAndFindFirstIndexHash3 -#define ZSTD_insertAndFindFirstIndex_internal \ - zfs_ZSTD_insertAndFindFirstIndex_internal #define ZSTD_insertBlock zfs_ZSTD_insertBlock #define ZSTD_invalidateRepCodes zfs_ZSTD_invalidateRepCodes #define ZSTD_isError zfs_ZSTD_isError @@ -417,8 +347,6 @@ #define ZSTD_ldm_skipSequences zfs_ZSTD_ldm_skipSequences #define ZSTD_loadCEntropy zfs_ZSTD_loadCEntropy #define ZSTD_loadDEntropy zfs_ZSTD_loadDEntropy -#define ZSTD_loadDictionaryContent zfs_ZSTD_loadDictionaryContent -#define ZSTD_makeCCtxParamsFromCParams zfs_ZSTD_makeCCtxParamsFromCParams #define ZSTD_malloc zfs_ZSTD_malloc #define ZSTD_maxCLevel zfs_ZSTD_maxCLevel #define ZSTD_minCLevel zfs_ZSTD_minCLevel @@ -426,14 +354,10 @@ #define ZSTD_nextSrcSizeToDecompress zfs_ZSTD_nextSrcSizeToDecompress #define ZSTD_noCompressLiterals zfs_ZSTD_noCompressLiterals #define ZSTD_referenceExternalSequences zfs_ZSTD_referenceExternalSequences -#define ZSTD_rescaleFreqs zfs_ZSTD_rescaleFreqs -#define ZSTD_resetCCtx_internal zfs_ZSTD_resetCCtx_internal -#define ZSTD_resetCCtx_usingCDict zfs_ZSTD_resetCCtx_usingCDict +#define ZSTD_reset_compressedBlockState zfs_ZSTD_reset_compressedBlockState #define ZSTD_resetCStream zfs_ZSTD_resetCStream #define ZSTD_resetDStream zfs_ZSTD_resetDStream #define ZSTD_resetSeqStore zfs_ZSTD_resetSeqStore -#define ZSTD_reset_compressedBlockState zfs_ZSTD_reset_compressedBlockState -#define ZSTD_safecopy zfs_ZSTD_safecopy #define ZSTD_selectBlockCompressor zfs_ZSTD_selectBlockCompressor #define ZSTD_selectEncodingType zfs_ZSTD_selectEncodingType #define ZSTD_seqToCodes zfs_ZSTD_seqToCodes @@ -444,18 +368,7 @@ #define ZSTD_sizeof_DDict zfs_ZSTD_sizeof_DDict #define ZSTD_sizeof_DStream zfs_ZSTD_sizeof_DStream #define ZSTD_toFlushNow zfs_ZSTD_toFlushNow -#define ZSTD_updateRep zfs_ZSTD_updateRep -#define ZSTD_updateStats zfs_ZSTD_updateStats #define ZSTD_updateTree zfs_ZSTD_updateTree #define ZSTD_versionNumber zfs_ZSTD_versionNumber #define ZSTD_versionString zfs_ZSTD_versionString -#define ZSTD_writeFrameHeader zfs_ZSTD_writeFrameHeader #define ZSTD_writeLastEmptyBlock zfs_ZSTD_writeLastEmptyBlock -#define algoTime zfs_algoTime -#define attachDictSizeCutoffs zfs_attachDictSizeCutoffs -#define g_ctx zfs_g_ctx -#define g_debuglevel zfs_g_debuglevel -#define kInverseProbabilityLog256 zfs_kInverseProbabilityLog256 -#define repStartValue zfs_repStartValue -#define FSE_isError zfs_FSE_isError -#define HUF_isError zfs_HUF_isError diff --git a/module/zstd/lib/zstd.c b/module/zstd/lib/zstd.c index 2766e5b74f55..9dbba5b82c40 100644 --- a/module/zstd/lib/zstd.c +++ b/module/zstd/lib/zstd.c @@ -7781,7 +7781,7 @@ size_t FSE_writeNCount (void* buffer, size_t bufferSize, FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog) { - size_t size; + size_t size __attribute__ ((unused)); if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX; size = FSE_CTABLE_SIZE_U32 (tableLog, maxSymbolValue) * sizeof(U32); return (FSE_CTable*)malloc(size); @@ -12115,7 +12115,7 @@ static size_t ZSTD_seqDecompressedSize(seqStore_t const* seqStore, const seqDef* const seqDef* const send = sequences + nbSeq; const seqDef* sp = sstart; size_t matchLengthSum = 0; - size_t litLengthSum = 0; + size_t litLengthSum __attribute__ ((unused)) = 0; while (send-sp > 0) { ZSTD_sequenceLength const seqLen = ZSTD_getSequenceLength(seqStore, sp); litLengthSum += seqLen.litLength; diff --git a/rpm/generic/zfs-dkms.spec.in b/rpm/generic/zfs-dkms.spec.in index 02be716aa964..55f0f1cf5249 100644 --- a/rpm/generic/zfs-dkms.spec.in +++ b/rpm/generic/zfs-dkms.spec.in @@ -36,7 +36,7 @@ Obsoletes: spl-dkms Provides: %{module}-kmod = %{version} AutoReqProv: no -%if 0%{?rhel}%{?fedora}%{?suse_version} +%if (0%{?fedora}%{?suse_version}) || (0%{?rhel} && 0%{?rhel} < 9) # We don't directly use it, but if this isn't installed, rpmbuild as root can # crash+corrupt rpmdb # See issue #12071 diff --git a/rpm/generic/zfs-kmod.spec.in b/rpm/generic/zfs-kmod.spec.in index 53b1e1385159..3061fb6ade26 100644 --- a/rpm/generic/zfs-kmod.spec.in +++ b/rpm/generic/zfs-kmod.spec.in @@ -57,7 +57,7 @@ BuildRequires: gcc, make BuildRequires: elfutils-libelf-devel %endif -%if 0%{?rhel}%{?fedora}%{?suse_version} +%if (0%{?fedora}%{?suse_version}) || (0%{?rhel} && 0%{?rhel} < 9) # We don't directly use it, but if this isn't installed, rpmbuild as root can # crash+corrupt rpmdb # See issue #12071 diff --git a/rpm/generic/zfs.spec.in b/rpm/generic/zfs.spec.in index 0e9cdcc31f32..1cd3f6b520ea 100644 --- a/rpm/generic/zfs.spec.in +++ b/rpm/generic/zfs.spec.in @@ -140,12 +140,15 @@ BuildRequires: libblkid-devel BuildRequires: libudev-devel BuildRequires: libattr-devel BuildRequires: openssl-devel +%if 0%{?fedora} || 0%{?rhel} >= 8 || 0%{?centos} >= 8 +BuildRequires: libtirpc-devel +%endif + +%if (0%{?fedora}%{?suse_version}) || (0%{?rhel} && 0%{?rhel} < 9) # We don't directly use it, but if this isn't installed, rpmbuild as root can # crash+corrupt rpmdb # See issue #12071 BuildRequires: ncompress -%if 0%{?fedora} >= 28 || 0%{?rhel} >= 8 || 0%{?centos} >= 8 -BuildRequires: libtirpc-devel %endif %if %{with pam} diff --git a/scripts/dkms.mkconf b/scripts/dkms.mkconf index 408322fa124a..4090efa087f7 100755 --- a/scripts/dkms.mkconf +++ b/scripts/dkms.mkconf @@ -68,7 +68,6 @@ POST_BUILD="scripts/dkms.postbuild -t \${dkms_tree} " AUTOINSTALL="yes" -REMAKE_INITRD="no" MAKE[0]="make" STRIP[0]="\$( [[ -r \${PACKAGE_CONFIG} ]] \\ diff --git a/tests/runfiles/common.run b/tests/runfiles/common.run index aefcd98436d7..19919a00afb3 100644 --- a/tests/runfiles/common.run +++ b/tests/runfiles/common.run @@ -178,7 +178,7 @@ tags = ['functional', 'cli_root', 'zfs_destroy'] [tests/functional/cli_root/zfs_diff] tests = ['zfs_diff_changes', 'zfs_diff_cliargs', 'zfs_diff_timestamp', - 'zfs_diff_types', 'zfs_diff_encrypted'] + 'zfs_diff_types', 'zfs_diff_encrypted', 'zfs_diff_mangle'] tags = ['functional', 'cli_root', 'zfs_diff'] [tests/functional/cli_root/zfs_get] diff --git a/tests/runfiles/linux.run b/tests/runfiles/linux.run index c01e1e3c4d53..94c1cbbc3f9f 100644 --- a/tests/runfiles/linux.run +++ b/tests/runfiles/linux.run @@ -94,7 +94,7 @@ tests = ['events_001_pos', 'events_002_pos', 'zed_rc_filter', 'zed_fd_spill'] tags = ['functional', 'events'] [tests/functional/fallocate:Linux] -tests = ['fallocate_prealloc'] +tests = ['fallocate_prealloc', 'fallocate_zero-range'] tags = ['functional', 'fallocate'] [tests/functional/fault:Linux] diff --git a/tests/zfs-tests/cmd/file_write/file_write.c b/tests/zfs-tests/cmd/file_write/file_write.c index 60893c34fbc9..9d2e71b679eb 100644 --- a/tests/zfs-tests/cmd/file_write/file_write.c +++ b/tests/zfs-tests/cmd/file_write/file_write.c @@ -251,7 +251,7 @@ usage(char *prog) "\t[-s offset] [-c write_count] [-d data]\n\n" "Where [data] equal to zero causes chars " "0->%d to be repeated throughout, or [data]\n" - "equal to 'R' for psudorandom data.\n", + "equal to 'R' for pseudorandom data.\n", prog, DATA_RANGE); exit(1); diff --git a/tests/zfs-tests/include/libtest.shlib b/tests/zfs-tests/include/libtest.shlib index dd43b02a6868..94ab7ffd20f7 100644 --- a/tests/zfs-tests/include/libtest.shlib +++ b/tests/zfs-tests/include/libtest.shlib @@ -4236,6 +4236,22 @@ function punch_hole # offset length file esac } +function zero_range # offset length file +{ + typeset offset=$1 + typeset length=$2 + typeset file=$3 + + case "$UNAME" in + Linux) + fallocate --zero-range --offset $offset --length $length "$file" + ;; + *) + false + ;; + esac +} + # # Wait for the specified arcstat to reach non-zero quiescence. # If echo is 1 echo the value after reaching quiescence, otherwise diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_diff/Makefile.am b/tests/zfs-tests/tests/functional/cli_root/zfs_diff/Makefile.am index db90e058559d..bfb01dcb8f86 100644 --- a/tests/zfs-tests/tests/functional/cli_root/zfs_diff/Makefile.am +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_diff/Makefile.am @@ -8,6 +8,7 @@ dist_pkgdata_SCRIPTS = \ zfs_diff_changes.ksh \ zfs_diff_cliargs.ksh \ zfs_diff_encrypted.ksh \ + zfs_diff_mangle.ksh \ zfs_diff_timestamp.ksh \ zfs_diff_types.ksh diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_diff/zfs_diff_cliargs.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_diff/zfs_diff_cliargs.ksh index 7063bbe9ce6a..67eb18fa4a5d 100755 --- a/tests/zfs-tests/tests/functional/cli_root/zfs_diff/zfs_diff_cliargs.ksh +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_diff/zfs_diff_cliargs.ksh @@ -39,8 +39,8 @@ function cleanup log_assert "'zfs diff' should only work with supported options." log_onexit cleanup -typeset goodopts=("" "-F" "-H" "-t" "-FH" "-Ft" "-Ht" "-FHt") -typeset badopts=("-f" "-h" "-h" "-T" "-Fx" "-Ho" "-tT" "-") +typeset goodopts=("" "-h" "-t" "-th" "-H" "-Hh" "-Ht" "-Hth" "-F" "-Fh" "-Ft" "-Fth" "-FH" "-FHh" "-FHt" "-FHth") +typeset badopts=("-f" "-T" "-Fx" "-Ho" "-tT" "-") DATASET="$TESTPOOL/$TESTFS" TESTSNAP1="$DATASET@snap1" diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_diff/zfs_diff_mangle.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_diff/zfs_diff_mangle.ksh new file mode 100755 index 000000000000..ffce9f06848f --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_diff/zfs_diff_mangle.ksh @@ -0,0 +1,48 @@ +#!/bin/ksh -p +# +# 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 +# http://www.illumos.org/license/CDDL. +# + +. $STF_SUITE/include/libtest.shlib + +# +# DESCRIPTION: +# 'zfs diff' escapes filenames as expected, 'zfs diff -h' doesn't +# +# STRATEGY: +# 1. Prepare a dataset +# 2. Create some files +# 3. verify 'zfs diff' mangles them and 'zfs diff -h' doesn't +# + +verify_runnable "both" + +function cleanup +{ + log_must zfs destroy -r "$DATASET" +} + +log_assert "'zfs diff' mangles filenames, 'zfs diff -h' doesn't" +log_onexit cleanup + +DATASET="$TESTPOOL/$TESTFS/fs" +TESTSNAP1="$DATASET@snap1" + +# 1. Prepare a dataset +log_must zfs create "$DATASET" +MNTPOINT="$(get_prop mountpoint "$DATASET")" +log_must zfs snapshot "$TESTSNAP1" + +printf '%c\t'"$MNTPOINT/"'%s\n' M '' + 'śmieszny żupan' + 'достопримечательности' | sort > "$MNTPOINT/śmieszny żupan" +printf '%c\t'"$MNTPOINT/"'%s\n' M '' + '\0305\0233mieszny\0040\0305\0274upan' + '\0320\0264\0320\0276\0321\0201\0321\0202\0320\0276\0320\0277\0321\0200\0320\0270\0320\0274\0320\0265\0321\0207\0320\0260\0321\0202\0320\0265\0320\0273\0321\0214\0320\0275\0320\0276\0321\0201\0321\0202\0320\0270' | sort > "$MNTPOINT/достопримечательности" +log_must diff -u <(zfs diff -h "$TESTSNAP1" | grep -vF '' | sort) "$MNTPOINT/śmieszny żupan" +log_must diff -u <(zfs diff "$TESTSNAP1" | grep -vF '' | sort) "$MNTPOINT/достопримечательности" + +log_pass "'zfs diff' mangles filenames, 'zfs diff -h' doesn't" diff --git a/tests/zfs-tests/tests/functional/fallocate/Makefile.am b/tests/zfs-tests/tests/functional/fallocate/Makefile.am index 5ff366d2482c..86364d7895dd 100644 --- a/tests/zfs-tests/tests/functional/fallocate/Makefile.am +++ b/tests/zfs-tests/tests/functional/fallocate/Makefile.am @@ -3,4 +3,5 @@ dist_pkgdata_SCRIPTS = \ setup.ksh \ cleanup.ksh \ fallocate_prealloc.ksh \ - fallocate_punch-hole.ksh + fallocate_punch-hole.ksh \ + fallocate_zero-range.ksh diff --git a/tests/zfs-tests/tests/functional/fallocate/fallocate_punch-hole.ksh b/tests/zfs-tests/tests/functional/fallocate/fallocate_punch-hole.ksh index ed83561bd556..92f4552f5bd7 100755 --- a/tests/zfs-tests/tests/functional/fallocate/fallocate_punch-hole.ksh +++ b/tests/zfs-tests/tests/functional/fallocate/fallocate_punch-hole.ksh @@ -60,13 +60,17 @@ function cleanup [[ -e $TESTDIR ]] && log_must rm -f $FILE } -function check_disk_size +function check_reported_size { typeset expected_size=$1 - disk_size=$(du $TESTDIR/file | awk '{print $1}') - if [ $disk_size -ne $expected_size ]; then - log_fail "Incorrect size: $disk_size != $expected_size" + if ! [ -e "${FILE}" ]; then + log_fail "$FILE does not exist" + fi + + reported_size=$(du "${FILE}" | awk '{print $1}') + if [ "$reported_size" != "$expected_size" ]; then + log_fail "Incorrect reported size: $reported_size != $expected_size" fi } @@ -74,9 +78,9 @@ function check_apparent_size { typeset expected_size=$1 - apparent_size=$(stat_size) - if [ $apparent_size -ne $expected_size ]; then - log_fail "Incorrect size: $apparent_size != $expected_size" + apparent_size=$(stat_size "${FILE}") + if [ "$apparent_size" != "$expected_size" ]; then + log_fail "Incorrect apparent size: $apparent_size != $expected_size" fi } @@ -86,25 +90,30 @@ log_onexit cleanup # Create a dense file and check it is the correct size. log_must file_write -o create -f $FILE -b $BLKSZ -c 8 -log_must check_disk_size $((131072 * 8)) +sync_pool $TESTPOOL +log_must check_reported_size 1027 # Punch a hole for the first full block. log_must punch_hole 0 $BLKSZ $FILE -log_must check_disk_size $((131072 * 7)) +sync_pool $TESTPOOL +log_must check_reported_size 899 # Partially punch a hole in the second block. log_must punch_hole $BLKSZ $((BLKSZ / 2)) $FILE -log_must check_disk_size $((131072 * 7)) +sync_pool $TESTPOOL +log_must check_reported_size 899 -# Punch a hole which overlaps the third and forth block. +# Punch a hole which overlaps the third and fourth block. log_must punch_hole $(((BLKSZ * 2) + (BLKSZ / 2))) $((BLKSZ)) $FILE -log_must check_disk_size $((131072 * 7)) +sync_pool $TESTPOOL +log_must check_reported_size 899 # Punch a hole from the fifth block past the end of file. The apparent # file size should not change since --keep-size is implied. apparent_size=$(stat_size $FILE) log_must punch_hole $((BLKSZ * 4)) $((BLKSZ * 10)) $FILE -log_must check_disk_size $((131072 * 4)) +sync_pool $TESTPOOL +log_must check_reported_size 387 log_must check_apparent_size $apparent_size log_pass "Ensure holes can be punched in files making them sparse" diff --git a/tests/zfs-tests/tests/functional/fallocate/fallocate_zero-range.ksh b/tests/zfs-tests/tests/functional/fallocate/fallocate_zero-range.ksh new file mode 100755 index 000000000000..e907b0f5d4c4 --- /dev/null +++ b/tests/zfs-tests/tests/functional/fallocate/fallocate_zero-range.ksh @@ -0,0 +1,119 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (c) 2020 by Lawrence Livermore National Security, LLC. +# Copyright (c) 2021 by The FreeBSD Foundation. +# + +. $STF_SUITE/include/libtest.shlib + +# +# DESCRIPTION: +# Test FALLOC_FL_ZERO_RANGE functionality +# +# STRATEGY: +# 1. Create a dense file +# 2. Zero various ranges in the file and verify the result. +# + +verify_runnable "global" + +if is_freebsd; then + log_unsupported "FreeBSD does not implement an analogue to ZERO_RANGE." +fi + +FILE=$TESTDIR/$TESTFILE0 +BLKSZ=$(get_prop recordsize $TESTPOOL) + +function cleanup +{ + [[ -e $TESTDIR ]] && log_must rm -f $FILE +} + +# Helpfully, this function expects kilobytes, and check_apparent_size expects bytes. +function check_reported_size +{ + typeset expected_size=$1 + + if ! [ -e "${FILE}" ]; then + log_fail "$FILE does not exist" + fi + + reported_size=$(du "${FILE}" | awk '{print $1}') + if [ "$reported_size" != "$expected_size" ]; then + log_fail "Incorrect reported size: $reported_size != $expected_size" + fi +} + +function check_apparent_size +{ + typeset expected_size=$1 + + apparent_size=$(stat_size "${FILE}") + if [ "$apparent_size" != "$expected_size" ]; then + log_fail "Incorrect apparent size: $apparent_size != $expected_size" + fi +} + +log_assert "Ensure ranges can be zeroed in files" + +log_onexit cleanup + +# Create a dense file and check it is the correct size. +log_must file_write -o create -f $FILE -b $BLKSZ -c 8 +sync_pool $TESTPOOL +log_must check_reported_size 1027 + +# Zero a range covering the first full block. +log_must zero_range 0 $BLKSZ $FILE +sync_pool $TESTPOOL +log_must check_reported_size 899 + +# Partially zero a range in the second block. +log_must zero_range $BLKSZ $((BLKSZ / 2)) $FILE +sync_pool $TESTPOOL +log_must check_reported_size 899 + +# Zero range which overlaps the third and fourth block. +log_must zero_range $(((BLKSZ * 2) + (BLKSZ / 2))) $((BLKSZ)) $FILE +sync_pool $TESTPOOL +log_must check_reported_size 899 + +# Zero range from the fifth block past the end of file, with --keep-size. +# The apparent file size must not change, since we did specify --keep-size. +apparent_size=$(stat_size $FILE) +log_must fallocate --keep-size --zero-range --offset $((BLKSZ * 4)) --length $((BLKSZ * 10)) "$FILE" +sync_pool $TESTPOOL +log_must check_reported_size 387 +log_must check_apparent_size $apparent_size + +# Zero range from the fifth block past the end of file. The apparent +# file size should change since --keep-size is not implied, unlike +# with PUNCH_HOLE. +apparent_size=$(stat_size $FILE) +log_must zero_range $((BLKSZ * 4)) $((BLKSZ * 10)) $FILE +sync_pool $TESTPOOL +log_must check_reported_size 387 +log_must check_apparent_size $((BLKSZ * 14)) + +log_pass "Ensure ranges can be zeroed in files" diff --git a/tests/zfs-tests/tests/functional/fallocate/setup.ksh b/tests/zfs-tests/tests/functional/fallocate/setup.ksh index 32334d396865..586ac026aa43 100755 --- a/tests/zfs-tests/tests/functional/fallocate/setup.ksh +++ b/tests/zfs-tests/tests/functional/fallocate/setup.ksh @@ -26,4 +26,7 @@ . $STF_SUITE/include/libtest.shlib DISK=${DISKS%% *} -default_setup $DISK +default_setup_noexit $DISK +log_must zfs set compression=off $TESTPOOL +log_pass +