aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Matuska <mm@FreeBSD.org>2022-03-08 17:52:10 +0000
committerMartin Matuska <mm@FreeBSD.org>2022-03-08 17:53:02 +0000
commitc03c5b1c80914ec656fbee84539355d1fad68bf9 (patch)
tree804d8ffb7943c01f04a7dfa4e98965881bcbfc3c
parent5678114cd8b310bd6f0a5699f036fc5b18addd65 (diff)
parenta86e089415679cf1b98eb424a159bb36aa2c19e3 (diff)
downloadsrc-c03c5b1c80914ec656fbee84539355d1fad68bf9.tar.gz
src-c03c5b1c80914ec656fbee84539355d1fad68bf9.zip
zfs: merge openzfs/zfs@a86e08941 (master) into main
Notable upstream pull request merges: #9078: log xattr=sa create/remove/update to ZIL #11919: Cross-platform xattr user namespace compatibility #13014: Report dnodes with faulty bonuslen #13016: FreeBSD: Fix zvol_cdev_open locking #13019: spl: Don't check FreeBSD rwlocks for double initialization #13027: Fix clearing set-uid and set-gid bits on a file when replying a write #13031: Add enumerated vdev names to 'zpool iostat -v' and 'zpool list -v' #13074: Enable encrypted raw sending to pools with greater ashift #13076: Receive checks should allow unencrypted child datasets #13098: Avoid dirtying the final TXGs when exporting a pool #13172: Fix ENOSPC when unlinking multiple files from full pool Obtained from: OpenZFS OpenZFS commit: a86e089415679cf1b98eb424a159bb36aa2c19e3
-rw-r--r--cddl/contrib/opensolaris/tools/ctf/cvt/ctftools.h4
-rw-r--r--cddl/lib/libicp/Makefile3
-rw-r--r--cddl/lib/libicp_rescue/Makefile3
-rw-r--r--cddl/lib/libzpool/Makefile74
-rw-r--r--stand/libsa/zfs/Makefile.inc61
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/sys/cmn_err.h4
-rw-r--r--sys/contrib/openzfs/.github/workflows/build-dependencies.txt49
-rw-r--r--sys/contrib/openzfs/.github/workflows/checkstyle.yaml32
-rwxr-xr-xsys/contrib/openzfs/.github/workflows/scripts/reclaim_disk_space.sh20
-rw-r--r--sys/contrib/openzfs/.github/workflows/zfs-tests-functional.yml43
-rw-r--r--sys/contrib/openzfs/.github/workflows/zfs-tests-sanity.yml47
-rw-r--r--sys/contrib/openzfs/.github/workflows/zloop.yml17
-rw-r--r--sys/contrib/openzfs/Makefile.am33
-rw-r--r--sys/contrib/openzfs/cmd/Makefile.am1
-rw-r--r--sys/contrib/openzfs/cmd/fsck_zfs/Makefile.am1
-rw-r--r--sys/contrib/openzfs/cmd/mount_zfs/mount_zfs.c49
-rw-r--r--sys/contrib/openzfs/cmd/raidz_test/raidz_test.c11
-rw-r--r--sys/contrib/openzfs/cmd/raidz_test/raidz_test.h16
-rw-r--r--sys/contrib/openzfs/cmd/zdb/zdb.c76
-rw-r--r--sys/contrib/openzfs/cmd/zdb/zdb_il.c25
-rw-r--r--sys/contrib/openzfs/cmd/zed/Makefile.am1
-rw-r--r--sys/contrib/openzfs/cmd/zed/agents/zfs_mod.c179
-rw-r--r--sys/contrib/openzfs/cmd/zed/zed.d/Makefile.am3
-rw-r--r--sys/contrib/openzfs/cmd/zed/zed.d/zed-functions.sh2
-rw-r--r--sys/contrib/openzfs/cmd/zed/zed_disk_event.c10
-rw-r--r--sys/contrib/openzfs/cmd/zfs/zfs_iter.c8
-rw-r--r--sys/contrib/openzfs/cmd/zfs/zfs_main.c43
-rw-r--r--sys/contrib/openzfs/cmd/zgenhostid/zgenhostid.c2
-rw-r--r--sys/contrib/openzfs/cmd/zhack/zhack.c4
-rw-r--r--sys/contrib/openzfs/cmd/zpool/Makefile.am1
-rw-r--r--sys/contrib/openzfs/cmd/zpool/zpool_main.c82
-rw-r--r--sys/contrib/openzfs/cmd/zpool_influxdb/zpool_influxdb.c6
-rw-r--r--sys/contrib/openzfs/cmd/zstream/zstream_dump.c13
-rw-r--r--sys/contrib/openzfs/cmd/ztest/ztest.c24
-rw-r--r--sys/contrib/openzfs/cmd/zvol_id/zvol_id_main.c15
-rw-r--r--sys/contrib/openzfs/cmd/zvol_wait/Makefile.am1
-rw-r--r--sys/contrib/openzfs/config/Abigail.am25
-rw-r--r--sys/contrib/openzfs/config/Rules.am12
-rw-r--r--sys/contrib/openzfs/config/Shellcheck.am10
-rw-r--r--sys/contrib/openzfs/config/Substfiles.am4
-rw-r--r--sys/contrib/openzfs/config/always-compiler-options.m4102
-rw-r--r--sys/contrib/openzfs/config/kernel-add-disk.m426
-rw-r--r--sys/contrib/openzfs/config/kernel-blk-queue.m416
-rw-r--r--sys/contrib/openzfs/config/kernel-block-device-operations.m417
-rw-r--r--sys/contrib/openzfs/config/kernel-fallocate.m417
-rw-r--r--sys/contrib/openzfs/config/kernel-fpu.m449
-rw-r--r--sys/contrib/openzfs/config/kernel-get-disk-ro.m44
-rw-r--r--sys/contrib/openzfs/config/kernel-kmem.m41
-rw-r--r--sys/contrib/openzfs/config/kernel-kthread.m468
-rw-r--r--sys/contrib/openzfs/config/kernel-pde-data.m416
-rw-r--r--sys/contrib/openzfs/config/kernel-vfs-iov_iter.m422
-rw-r--r--sys/contrib/openzfs/config/kernel.m4117
-rw-r--r--sys/contrib/openzfs/config/toolchain-simd.m466
-rw-r--r--sys/contrib/openzfs/config/zfs-build.m48
-rw-r--r--sys/contrib/openzfs/configure.ac6
-rw-r--r--sys/contrib/openzfs/contrib/Makefile.am1
-rw-r--r--sys/contrib/openzfs/contrib/bash_completion.d/Makefile.am1
-rw-r--r--sys/contrib/openzfs/contrib/bpftrace/Makefile.am1
-rw-r--r--sys/contrib/openzfs/contrib/dracut/02zfsexpandknowledge/Makefile.am1
-rwxr-xr-xsys/contrib/openzfs/contrib/dracut/02zfsexpandknowledge/module-setup.sh.in6
-rw-r--r--sys/contrib/openzfs/contrib/dracut/90zfs/Makefile.am1
-rwxr-xr-xsys/contrib/openzfs/contrib/dracut/90zfs/export-zfs.sh.in18
-rwxr-xr-xsys/contrib/openzfs/contrib/dracut/90zfs/module-setup.sh.in161
-rwxr-xr-xsys/contrib/openzfs/contrib/dracut/90zfs/mount-zfs.sh.in2
-rwxr-xr-xsys/contrib/openzfs/contrib/dracut/90zfs/zfs-lib.sh.in16
-rw-r--r--sys/contrib/openzfs/contrib/dracut/90zfs/zfs-rollback-bootfs.service.in2
-rw-r--r--sys/contrib/openzfs/contrib/dracut/90zfs/zfs-snapshot-bootfs.service.in2
-rw-r--r--sys/contrib/openzfs/contrib/dracut/Makefile.am2
-rw-r--r--sys/contrib/openzfs/contrib/dracut/README.dracut.markdown225
-rw-r--r--sys/contrib/openzfs/contrib/dracut/README.md48
-rw-r--r--sys/contrib/openzfs/contrib/initramfs/Makefile.am4
-rw-r--r--sys/contrib/openzfs/contrib/initramfs/README.md (renamed from sys/contrib/openzfs/contrib/initramfs/README.initramfs.markdown)0
-rw-r--r--sys/contrib/openzfs/contrib/initramfs/hooks/Makefile.am1
-rw-r--r--sys/contrib/openzfs/contrib/initramfs/scripts/Makefile.am1
-rw-r--r--sys/contrib/openzfs/contrib/initramfs/scripts/local-top/Makefile.am1
-rw-r--r--sys/contrib/openzfs/contrib/pam_zfs_key/pam_zfs_key.c1
-rw-r--r--sys/contrib/openzfs/contrib/pyzfs/libzfs_core/test/test_libzfs_core.py3
-rw-r--r--sys/contrib/openzfs/etc/Makefile.am1
-rw-r--r--sys/contrib/openzfs/etc/default/Makefile.am3
-rw-r--r--sys/contrib/openzfs/etc/init.d/Makefile.am3
-rw-r--r--sys/contrib/openzfs/etc/systemd/system/zfs-import-cache.service.in1
-rw-r--r--sys/contrib/openzfs/etc/systemd/system/zfs-import-scan.service.in1
-rw-r--r--sys/contrib/openzfs/etc/systemd/system/zfs-mount.service.in1
-rw-r--r--sys/contrib/openzfs/etc/systemd/system/zfs-scrub@.service.in3
-rw-r--r--sys/contrib/openzfs/etc/systemd/system/zfs-share.service.in1
-rw-r--r--sys/contrib/openzfs/etc/systemd/system/zfs-volume-wait.service.in1
-rw-r--r--sys/contrib/openzfs/etc/systemd/system/zfs-zed.service.in1
-rw-r--r--sys/contrib/openzfs/etc/zfs/Makefile.am3
-rw-r--r--sys/contrib/openzfs/include/libuutil.h16
-rw-r--r--sys/contrib/openzfs/include/libzfs.h4
-rw-r--r--sys/contrib/openzfs/include/libzfs_core.h1
-rw-r--r--sys/contrib/openzfs/include/os/freebsd/linux/compiler.h2
-rw-r--r--sys/contrib/openzfs/include/os/freebsd/spl/sys/ccompat.h7
-rw-r--r--sys/contrib/openzfs/include/os/freebsd/spl/sys/ctype.h12
-rw-r--r--sys/contrib/openzfs/include/os/freebsd/spl/sys/debug.h75
-rw-r--r--sys/contrib/openzfs/include/os/freebsd/spl/sys/mod_os.h35
-rw-r--r--sys/contrib/openzfs/include/os/freebsd/spl/sys/rwlock.h11
-rw-r--r--sys/contrib/openzfs/include/os/freebsd/spl/sys/sdt.h2
-rw-r--r--sys/contrib/openzfs/include/os/freebsd/spl/sys/types.h2
-rw-r--r--sys/contrib/openzfs/include/os/freebsd/zfs/sys/freebsd_crypto.h7
-rw-r--r--sys/contrib/openzfs/include/os/freebsd/zfs/sys/sha2.h3
-rw-r--r--sys/contrib/openzfs/include/os/linux/kernel/linux/compiler_compat.h6
-rw-r--r--sys/contrib/openzfs/include/os/linux/kernel/linux/mod_compat.h33
-rw-r--r--sys/contrib/openzfs/include/os/linux/kernel/linux/simd_x86.h124
-rw-r--r--sys/contrib/openzfs/include/os/linux/spl/sys/acl.h10
-rw-r--r--sys/contrib/openzfs/include/os/linux/spl/sys/debug.h81
-rw-r--r--sys/contrib/openzfs/include/os/linux/spl/sys/isa_defs.h23
-rw-r--r--sys/contrib/openzfs/include/os/linux/spl/sys/mutex.h3
-rw-r--r--sys/contrib/openzfs/include/os/linux/spl/sys/rwlock.h12
-rw-r--r--sys/contrib/openzfs/include/os/linux/spl/sys/thread.h8
-rw-r--r--sys/contrib/openzfs/include/os/linux/spl/sys/trace_taskq.h26
-rw-r--r--sys/contrib/openzfs/include/os/linux/spl/sys/uio.h4
-rw-r--r--sys/contrib/openzfs/include/os/linux/zfs/sys/sha2.h3
-rw-r--r--sys/contrib/openzfs/include/os/linux/zfs/sys/trace_acl.h6
-rw-r--r--sys/contrib/openzfs/include/os/linux/zfs/sys/trace_arc.h39
-rw-r--r--sys/contrib/openzfs/include/os/linux/zfs/sys/trace_dbgmsg.h6
-rw-r--r--sys/contrib/openzfs/include/os/linux/zfs/sys/trace_dbuf.h18
-rw-r--r--sys/contrib/openzfs/include/os/linux/zfs/sys/trace_dmu.h14
-rw-r--r--sys/contrib/openzfs/include/os/linux/zfs/sys/trace_dnode.h6
-rw-r--r--sys/contrib/openzfs/include/os/linux/zfs/sys/trace_multilist.h6
-rw-r--r--sys/contrib/openzfs/include/os/linux/zfs/sys/trace_txg.h6
-rw-r--r--sys/contrib/openzfs/include/os/linux/zfs/sys/trace_vdev.h14
-rw-r--r--sys/contrib/openzfs/include/os/linux/zfs/sys/trace_zil.h12
-rw-r--r--sys/contrib/openzfs/include/os/linux/zfs/sys/trace_zrlock.h6
-rw-r--r--sys/contrib/openzfs/include/sys/arc_impl.h13
-rw-r--r--sys/contrib/openzfs/include/sys/crypto/api.h367
-rw-r--r--sys/contrib/openzfs/include/sys/crypto/common.h408
-rw-r--r--sys/contrib/openzfs/include/sys/dsl_dataset.h3
-rw-r--r--sys/contrib/openzfs/include/sys/dsl_pool.h1
-rw-r--r--sys/contrib/openzfs/include/sys/fs/zfs.h73
-rw-r--r--sys/contrib/openzfs/include/sys/lua/lauxlib.h3
-rw-r--r--sys/contrib/openzfs/include/sys/lua/lua.h2
-rw-r--r--sys/contrib/openzfs/include/sys/lua/luaconf.h2
-rw-r--r--sys/contrib/openzfs/include/sys/lua/lualib.h2
-rw-r--r--sys/contrib/openzfs/include/sys/spa.h5
-rw-r--r--sys/contrib/openzfs/include/sys/vdev_impl.h4
-rw-r--r--sys/contrib/openzfs/include/sys/zfs_context.h9
-rw-r--r--sys/contrib/openzfs/include/sys/zfs_sa.h2
-rw-r--r--sys/contrib/openzfs/include/sys/zfs_znode.h4
-rw-r--r--sys/contrib/openzfs/include/sys/zil.h13
-rw-r--r--sys/contrib/openzfs/include/sys/zio.h2
-rw-r--r--sys/contrib/openzfs/include/sys/zvol_impl.h20
-rw-r--r--sys/contrib/openzfs/include/zfeature_common.h1
-rw-r--r--sys/contrib/openzfs/include/zfs_fletcher.h16
-rw-r--r--sys/contrib/openzfs/include/zfs_prop.h14
-rw-r--r--sys/contrib/openzfs/lib/libicp/Makefile.am3
-rw-r--r--sys/contrib/openzfs/lib/libnvpair/Makefile.am4
-rw-r--r--sys/contrib/openzfs/lib/libnvpair/libnvpair.abi7
-rw-r--r--sys/contrib/openzfs/lib/libshare/os/freebsd/nfs.c1
-rw-r--r--sys/contrib/openzfs/lib/libshare/os/freebsd/smb.c5
-rw-r--r--sys/contrib/openzfs/lib/libspl/assert.c8
-rw-r--r--sys/contrib/openzfs/lib/libspl/atomic.c166
-rw-r--r--sys/contrib/openzfs/lib/libspl/include/Makefile.am2
-rw-r--r--sys/contrib/openzfs/lib/libspl/include/assert.h35
-rw-r--r--sys/contrib/openzfs/lib/libspl/include/ia32/Makefile.am1
-rw-r--r--sys/contrib/openzfs/lib/libspl/include/ia32/sys/Makefile.am3
-rw-r--r--sys/contrib/openzfs/lib/libspl/include/ia32/sys/asm_linkage.h302
-rw-r--r--sys/contrib/openzfs/lib/libspl/include/sys/feature_tests.h7
-rw-r--r--sys/contrib/openzfs/lib/libspl/include/sys/isa_defs.h25
-rw-r--r--sys/contrib/openzfs/lib/libspl/include/sys/sha2.h3
-rw-r--r--sys/contrib/openzfs/lib/libspl/include/sys/simd.h1
-rw-r--r--sys/contrib/openzfs/lib/libspl/os/linux/zone.c2
-rw-r--r--sys/contrib/openzfs/lib/libtpool/Makefile.am2
-rw-r--r--sys/contrib/openzfs/lib/libtpool/thread_pool.c3
-rw-r--r--sys/contrib/openzfs/lib/libuutil/libuutil.abi7
-rw-r--r--sys/contrib/openzfs/lib/libuutil/uu_pname.c9
-rw-r--r--sys/contrib/openzfs/lib/libzfs/Makefile.am2
-rw-r--r--sys/contrib/openzfs/lib/libzfs/libzfs.abi95
-rw-r--r--sys/contrib/openzfs/lib/libzfs/libzfs_changelist.c2
-rw-r--r--sys/contrib/openzfs/lib/libzfs/libzfs_crypto.c9
-rw-r--r--sys/contrib/openzfs/lib/libzfs/libzfs_dataset.c26
-rw-r--r--sys/contrib/openzfs/lib/libzfs/libzfs_impl.h12
-rw-r--r--sys/contrib/openzfs/lib/libzfs/libzfs_mount.c36
-rw-r--r--sys/contrib/openzfs/lib/libzfs/libzfs_pool.c11
-rw-r--r--sys/contrib/openzfs/lib/libzfs/libzfs_sendrecv.c708
-rw-r--r--sys/contrib/openzfs/lib/libzfs/libzfs_util.c16
-rw-r--r--sys/contrib/openzfs/lib/libzfs/os/freebsd/libzfs_compat.c20
-rw-r--r--sys/contrib/openzfs/lib/libzfs/os/freebsd/libzfs_zmount.c6
-rw-r--r--sys/contrib/openzfs/lib/libzfs/os/linux/libzfs_sendrecv_os.c52
-rw-r--r--sys/contrib/openzfs/lib/libzfs_core/libzfs_core.abi197
-rw-r--r--sys/contrib/openzfs/lib/libzfs_core/libzfs_core.c208
-rw-r--r--sys/contrib/openzfs/lib/libzfsbootenv/lzbe_device.c2
-rw-r--r--sys/contrib/openzfs/lib/libzpool/Makefile.am3
-rw-r--r--sys/contrib/openzfs/lib/libzpool/kernel.c45
-rw-r--r--sys/contrib/openzfs/lib/libzpool/taskq.c2
-rw-r--r--sys/contrib/openzfs/lib/libzstd/Makefile.am27
-rw-r--r--sys/contrib/openzfs/lib/libzutil/Makefile.am2
-rw-r--r--sys/contrib/openzfs/lib/libzutil/os/linux/zutil_device_path_os.c29
-rw-r--r--sys/contrib/openzfs/lib/libzutil/os/linux/zutil_import_os.c3
-rw-r--r--sys/contrib/openzfs/lib/libzutil/zutil_import.c4
-rw-r--r--sys/contrib/openzfs/man/man1/raidz_test.12
-rw-r--r--sys/contrib/openzfs/man/man4/zfs.453
-rw-r--r--sys/contrib/openzfs/man/man7/zfsconcepts.74
-rw-r--r--sys/contrib/openzfs/man/man7/zfsprops.734
-rw-r--r--sys/contrib/openzfs/man/man7/zpool-features.734
-rw-r--r--sys/contrib/openzfs/man/man7/zpoolprops.76
-rw-r--r--sys/contrib/openzfs/man/man8/zdb.824
-rw-r--r--sys/contrib/openzfs/man/man8/zfs-project.82
-rw-r--r--sys/contrib/openzfs/man/man8/zfs-receive.84
-rw-r--r--sys/contrib/openzfs/man/man8/zinject.88
-rw-r--r--sys/contrib/openzfs/man/man8/zpool-import.87
-rw-r--r--sys/contrib/openzfs/man/man8/zpool-labelclear.83
-rw-r--r--sys/contrib/openzfs/man/man8/zpool-remove.82
-rw-r--r--sys/contrib/openzfs/man/man8/zpool-status.810
-rw-r--r--sys/contrib/openzfs/man/man8/zpool.86
-rw-r--r--sys/contrib/openzfs/module/Makefile.bsd51
-rw-r--r--sys/contrib/openzfs/module/Makefile.in13
-rw-r--r--sys/contrib/openzfs/module/avl/avl.c4
-rw-r--r--sys/contrib/openzfs/module/icp/Makefile.in3
-rw-r--r--sys/contrib/openzfs/module/icp/algs/modes/cbc.c17
-rw-r--r--sys/contrib/openzfs/module/icp/algs/modes/gcm.c35
-rw-r--r--sys/contrib/openzfs/module/icp/api/kcf_cipher.c793
-rw-r--r--sys/contrib/openzfs/module/icp/api/kcf_ctxops.c8
-rw-r--r--sys/contrib/openzfs/module/icp/api/kcf_digest.c491
-rw-r--r--sys/contrib/openzfs/module/icp/api/kcf_mac.c416
-rw-r--r--sys/contrib/openzfs/module/icp/api/kcf_miscapi.c127
-rw-r--r--sys/contrib/openzfs/module/icp/core/kcf_callprov.c1445
-rw-r--r--sys/contrib/openzfs/module/icp/core/kcf_mech_tabs.c538
-rw-r--r--sys/contrib/openzfs/module/icp/core/kcf_prov_lib.c68
-rw-r--r--sys/contrib/openzfs/module/icp/core/kcf_prov_tabs.c379
-rw-r--r--sys/contrib/openzfs/module/icp/core/kcf_sched.c1627
-rw-r--r--sys/contrib/openzfs/module/icp/illumos-crypto.c5
-rw-r--r--sys/contrib/openzfs/module/icp/include/aes/aes_impl.h7
-rw-r--r--sys/contrib/openzfs/module/icp/include/modes/modes.h6
-rw-r--r--sys/contrib/openzfs/module/icp/include/sys/bitmap.h183
-rw-r--r--sys/contrib/openzfs/module/icp/include/sys/crypto/elfsign.h137
-rw-r--r--sys/contrib/openzfs/module/icp/include/sys/crypto/impl.h1057
-rw-r--r--sys/contrib/openzfs/module/icp/include/sys/crypto/ops_impl.h630
-rw-r--r--sys/contrib/openzfs/module/icp/include/sys/crypto/sched_impl.h422
-rw-r--r--sys/contrib/openzfs/module/icp/include/sys/crypto/spi.h572
-rw-r--r--sys/contrib/openzfs/module/icp/include/sys/ia32/asm_linkage.h146
-rw-r--r--sys/contrib/openzfs/module/icp/include/sys/modhash.h147
-rw-r--r--sys/contrib/openzfs/module/icp/include/sys/modhash_impl.h108
-rw-r--r--sys/contrib/openzfs/module/icp/io/aes.c256
-rw-r--r--sys/contrib/openzfs/module/icp/io/sha2_mod.c197
-rw-r--r--sys/contrib/openzfs/module/icp/io/skein_mod.c145
-rw-r--r--sys/contrib/openzfs/module/icp/os/modhash.c927
-rw-r--r--sys/contrib/openzfs/module/icp/spi/kcf_spi.c743
-rw-r--r--sys/contrib/openzfs/module/lua/lapi.c2
-rw-r--r--sys/contrib/openzfs/module/lua/lapi.h2
-rw-r--r--sys/contrib/openzfs/module/lua/lauxlib.c2
-rw-r--r--sys/contrib/openzfs/module/lua/lbaselib.c2
-rw-r--r--sys/contrib/openzfs/module/lua/lcode.c2
-rw-r--r--sys/contrib/openzfs/module/lua/lcode.h2
-rw-r--r--sys/contrib/openzfs/module/lua/lcorolib.c2
-rw-r--r--sys/contrib/openzfs/module/lua/lctype.c2
-rw-r--r--sys/contrib/openzfs/module/lua/lctype.h2
-rw-r--r--sys/contrib/openzfs/module/lua/ldebug.c2
-rw-r--r--sys/contrib/openzfs/module/lua/ldebug.h2
-rw-r--r--sys/contrib/openzfs/module/lua/ldo.c4
-rw-r--r--sys/contrib/openzfs/module/lua/ldo.h2
-rw-r--r--sys/contrib/openzfs/module/lua/lfunc.c2
-rw-r--r--sys/contrib/openzfs/module/lua/lfunc.h2
-rw-r--r--sys/contrib/openzfs/module/lua/lgc.c4
-rw-r--r--sys/contrib/openzfs/module/lua/lgc.h2
-rw-r--r--sys/contrib/openzfs/module/lua/llex.c4
-rw-r--r--sys/contrib/openzfs/module/lua/llex.h2
-rw-r--r--sys/contrib/openzfs/module/lua/llimits.h2
-rw-r--r--sys/contrib/openzfs/module/lua/lmem.c2
-rw-r--r--sys/contrib/openzfs/module/lua/lmem.h2
-rw-r--r--sys/contrib/openzfs/module/lua/lobject.c2
-rw-r--r--sys/contrib/openzfs/module/lua/lobject.h2
-rw-r--r--sys/contrib/openzfs/module/lua/lopcodes.c2
-rw-r--r--sys/contrib/openzfs/module/lua/lopcodes.h2
-rw-r--r--sys/contrib/openzfs/module/lua/lparser.c2
-rw-r--r--sys/contrib/openzfs/module/lua/lparser.h2
-rw-r--r--sys/contrib/openzfs/module/lua/lstate.c2
-rw-r--r--sys/contrib/openzfs/module/lua/lstate.h2
-rw-r--r--sys/contrib/openzfs/module/lua/lstring.c2
-rw-r--r--sys/contrib/openzfs/module/lua/lstring.h2
-rw-r--r--sys/contrib/openzfs/module/lua/lstrlib.c4
-rw-r--r--sys/contrib/openzfs/module/lua/ltable.c4
-rw-r--r--sys/contrib/openzfs/module/lua/ltable.h2
-rw-r--r--sys/contrib/openzfs/module/lua/ltablib.c2
-rw-r--r--sys/contrib/openzfs/module/lua/ltm.c2
-rw-r--r--sys/contrib/openzfs/module/lua/ltm.h2
-rw-r--r--sys/contrib/openzfs/module/lua/lvm.c3
-rw-r--r--sys/contrib/openzfs/module/lua/lvm.h2
-rw-r--r--sys/contrib/openzfs/module/lua/lzio.c2
-rw-r--r--sys/contrib/openzfs/module/lua/lzio.h2
-rw-r--r--sys/contrib/openzfs/module/os/freebsd/spl/callb.c2
-rw-r--r--sys/contrib/openzfs/module/os/freebsd/spl/spl_zlib.c6
-rw-r--r--sys/contrib/openzfs/module/os/freebsd/zfs/arc_os.c4
-rw-r--r--sys/contrib/openzfs/module/os/freebsd/zfs/crypto_os.c12
-rw-r--r--sys/contrib/openzfs/module/os/freebsd/zfs/hkdf.c2
-rw-r--r--sys/contrib/openzfs/module/os/freebsd/zfs/spa_os.c24
-rw-r--r--sys/contrib/openzfs/module/os/freebsd/zfs/sysctl_os.c280
-rw-r--r--sys/contrib/openzfs/module/os/freebsd/zfs/vdev_geom.c11
-rw-r--r--sys/contrib/openzfs/module/os/freebsd/zfs/zfs_acl.c12
-rw-r--r--sys/contrib/openzfs/module/os/freebsd/zfs/zfs_ctldir.c5
-rw-r--r--sys/contrib/openzfs/module/os/freebsd/zfs/zfs_debug.c6
-rw-r--r--sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vfsops.c19
-rw-r--r--sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vnops_os.c318
-rw-r--r--sys/contrib/openzfs/module/os/freebsd/zfs/zfs_znode.c2
-rw-r--r--sys/contrib/openzfs/module/os/freebsd/zfs/zio_crypt.c10
-rw-r--r--sys/contrib/openzfs/module/os/freebsd/zfs/zvol_os.c49
-rw-r--r--sys/contrib/openzfs/module/os/linux/spl/spl-err.c6
-rw-r--r--sys/contrib/openzfs/module/os/linux/spl/spl-generic.c18
-rw-r--r--sys/contrib/openzfs/module/os/linux/spl/spl-kmem-cache.c1
-rw-r--r--sys/contrib/openzfs/module/os/linux/spl/spl-kmem.c2
-rw-r--r--sys/contrib/openzfs/module/os/linux/spl/spl-kstat.c2
-rw-r--r--sys/contrib/openzfs/module/os/linux/spl/spl-proc.c3
-rw-r--r--sys/contrib/openzfs/module/os/linux/spl/spl-procfs-list.c2
-rw-r--r--sys/contrib/openzfs/module/os/linux/spl/spl-thread.c7
-rw-r--r--sys/contrib/openzfs/module/os/linux/zfs/arc_os.c2
-rw-r--r--sys/contrib/openzfs/module/os/linux/zfs/spa_misc_os.c24
-rw-r--r--sys/contrib/openzfs/module/os/linux/zfs/vdev_disk.c2
-rw-r--r--sys/contrib/openzfs/module/os/linux/zfs/zfs_acl.c12
-rw-r--r--sys/contrib/openzfs/module/os/linux/zfs/zfs_vfsops.c5
-rw-r--r--sys/contrib/openzfs/module/os/linux/zfs/zfs_vnops_os.c39
-rw-r--r--sys/contrib/openzfs/module/os/linux/zfs/zfs_znode.c8
-rw-r--r--sys/contrib/openzfs/module/os/linux/zfs/zio_crypt.c49
-rw-r--r--sys/contrib/openzfs/module/os/linux/zfs/zpl_ctldir.c31
-rw-r--r--sys/contrib/openzfs/module/os/linux/zfs/zpl_file.c139
-rw-r--r--sys/contrib/openzfs/module/os/linux/zfs/zpl_xattr.c159
-rw-r--r--sys/contrib/openzfs/module/os/linux/zfs/zvol_os.c48
-rw-r--r--sys/contrib/openzfs/module/zcommon/zfeature_common.c12
-rw-r--r--sys/contrib/openzfs/module/zcommon/zfs_fletcher.c8
-rw-r--r--sys/contrib/openzfs/module/zcommon/zfs_fletcher_aarch64_neon.c2
-rw-r--r--sys/contrib/openzfs/module/zcommon/zfs_fletcher_avx512.c2
-rw-r--r--sys/contrib/openzfs/module/zcommon/zfs_fletcher_intel.c2
-rw-r--r--sys/contrib/openzfs/module/zcommon/zfs_fletcher_sse.c2
-rw-r--r--sys/contrib/openzfs/module/zcommon/zfs_fletcher_superscalar.c4
-rw-r--r--sys/contrib/openzfs/module/zcommon/zfs_fletcher_superscalar4.c4
-rw-r--r--sys/contrib/openzfs/module/zcommon/zfs_prop.c98
-rw-r--r--sys/contrib/openzfs/module/zcommon/zpool_prop.c126
-rw-r--r--sys/contrib/openzfs/module/zcommon/zprop_common.c35
-rw-r--r--sys/contrib/openzfs/module/zfs/abd.c8
-rw-r--r--sys/contrib/openzfs/module/zfs/arc.c17
-rw-r--r--sys/contrib/openzfs/module/zfs/btree.c5
-rw-r--r--sys/contrib/openzfs/module/zfs/dbuf.c24
-rw-r--r--sys/contrib/openzfs/module/zfs/dbuf_stats.c2
-rw-r--r--sys/contrib/openzfs/module/zfs/ddt.c2
-rw-r--r--sys/contrib/openzfs/module/zfs/dmu.c3
-rw-r--r--sys/contrib/openzfs/module/zfs/dmu_recv.c18
-rw-r--r--sys/contrib/openzfs/module/zfs/dmu_redact.c4
-rw-r--r--sys/contrib/openzfs/module/zfs/dmu_send.c12
-rw-r--r--sys/contrib/openzfs/module/zfs/dmu_traverse.c3
-rw-r--r--sys/contrib/openzfs/module/zfs/dmu_tx.c1
-rw-r--r--sys/contrib/openzfs/module/zfs/dmu_zfetch.c2
-rw-r--r--sys/contrib/openzfs/module/zfs/dnode_sync.c2
-rw-r--r--sys/contrib/openzfs/module/zfs/dsl_crypt.c1
-rw-r--r--sys/contrib/openzfs/module/zfs/dsl_dataset.c305
-rw-r--r--sys/contrib/openzfs/module/zfs/dsl_deadlist.c2
-rw-r--r--sys/contrib/openzfs/module/zfs/dsl_dir.c23
-rw-r--r--sys/contrib/openzfs/module/zfs/dsl_pool.c10
-rw-r--r--sys/contrib/openzfs/module/zfs/dsl_prop.c2
-rw-r--r--sys/contrib/openzfs/module/zfs/dsl_scan.c18
-rw-r--r--sys/contrib/openzfs/module/zfs/edonr_zfs.c4
-rw-r--r--sys/contrib/openzfs/module/zfs/hkdf.c14
-rw-r--r--sys/contrib/openzfs/module/zfs/metaslab.c9
-rw-r--r--sys/contrib/openzfs/module/zfs/mmp.c6
-rw-r--r--sys/contrib/openzfs/module/zfs/multilist.c2
-rw-r--r--sys/contrib/openzfs/module/zfs/skein_zfs.c1
-rw-r--r--sys/contrib/openzfs/module/zfs/spa.c116
-rw-r--r--sys/contrib/openzfs/module/zfs/spa_config.c2
-rw-r--r--sys/contrib/openzfs/module/zfs/spa_history.c1
-rw-r--r--sys/contrib/openzfs/module/zfs/spa_log_spacemap.c44
-rw-r--r--sys/contrib/openzfs/module/zfs/spa_stats.c10
-rw-r--r--sys/contrib/openzfs/module/zfs/txg.c10
-rw-r--r--sys/contrib/openzfs/module/zfs/vdev.c10
-rw-r--r--sys/contrib/openzfs/module/zfs/vdev_cache.c6
-rw-r--r--sys/contrib/openzfs/module/zfs/vdev_indirect.c19
-rw-r--r--sys/contrib/openzfs/module/zfs/vdev_initialize.c4
-rw-r--r--sys/contrib/openzfs/module/zfs/vdev_label.c2
-rw-r--r--sys/contrib/openzfs/module/zfs/vdev_mirror.c21
-rw-r--r--sys/contrib/openzfs/module/zfs/vdev_queue.c14
-rw-r--r--sys/contrib/openzfs/module/zfs/vdev_raidz.c2
-rw-r--r--sys/contrib/openzfs/module/zfs/vdev_raidz_math_scalar.c2
-rw-r--r--sys/contrib/openzfs/module/zfs/vdev_rebuild.c6
-rw-r--r--sys/contrib/openzfs/module/zfs/vdev_removal.c6
-rw-r--r--sys/contrib/openzfs/module/zfs/vdev_trim.c18
-rw-r--r--sys/contrib/openzfs/module/zfs/zap.c5
-rw-r--r--sys/contrib/openzfs/module/zfs/zap_leaf.c2
-rw-r--r--sys/contrib/openzfs/module/zfs/zap_micro.c2
-rw-r--r--sys/contrib/openzfs/module/zfs/zcp.c2
-rw-r--r--sys/contrib/openzfs/module/zfs/zcp_get.c30
-rw-r--r--sys/contrib/openzfs/module/zfs/zfs_byteswap.c13
-rw-r--r--sys/contrib/openzfs/module/zfs/zfs_ioctl.c194
-rw-r--r--sys/contrib/openzfs/module/zfs/zfs_log.c36
-rw-r--r--sys/contrib/openzfs/module/zfs/zfs_replay.c93
-rw-r--r--sys/contrib/openzfs/module/zfs/zfs_sa.c29
-rw-r--r--sys/contrib/openzfs/module/zfs/zfs_vnops.c114
-rw-r--r--sys/contrib/openzfs/module/zfs/zil.c76
-rw-r--r--sys/contrib/openzfs/module/zfs/zio.c10
-rw-r--r--sys/contrib/openzfs/module/zfs/zio_inject.c5
-rw-r--r--sys/contrib/openzfs/module/zfs/zthr.c2
-rw-r--r--sys/contrib/openzfs/module/zfs/zvol.c55
-rw-r--r--sys/contrib/openzfs/module/zstd/Makefile.in39
-rw-r--r--sys/contrib/openzfs/module/zstd/README.md36
-rw-r--r--sys/contrib/openzfs/module/zstd/include/string.h1
-rw-r--r--sys/contrib/openzfs/module/zstd/include/zstd_compat_wrapper.h14
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/common/bitstream.h454
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/common/compiler.h175
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/common/cpu.h215
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/common/debug.h114
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/common/entropy_common.c216
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/common/error_private.c55
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/common/error_private.h80
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/common/fse.h688
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/common/fse_decompress.c286
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/common/huf.h340
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/common/mem.h450
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/common/pool.c344
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/common/pool.h84
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/common/xxhash.c864
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/common/xxhash.h285
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/common/zstd_common.c83
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/common/zstd_errors.h (renamed from sys/contrib/openzfs/module/zstd/lib/zstd_errors.h)0
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/common/zstd_internal.h446
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/compress/fse_compress.c698
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/compress/hist.c183
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/compress/hist.h75
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/compress/huf_compress.c798
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress.c4278
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress_internal.h1125
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress_literals.c158
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress_literals.h29
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress_sequences.c419
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress_sequences.h54
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress_superblock.c845
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress_superblock.h32
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/compress/zstd_cwksp.h525
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/compress/zstd_double_fast.c521
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/compress/zstd_double_fast.h38
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/compress/zstd_fast.c496
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/compress/zstd_fast.h37
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/compress/zstd_lazy.c1138
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/compress/zstd_lazy.h67
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/compress/zstd_ldm.c619
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/compress/zstd_ldm.h110
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/compress/zstd_opt.c1200
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/compress/zstd_opt.h56
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/decompress/huf_decompress.c1248
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/decompress/zstd_ddict.c244
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/decompress/zstd_ddict.h44
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/decompress/zstd_decompress.c1885
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/decompress/zstd_decompress_block.c1432
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/decompress/zstd_decompress_block.h59
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/decompress/zstd_decompress_internal.h189
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/zstd.c27824
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/zstd.h37
-rw-r--r--sys/contrib/openzfs/module/zstd/zfs_zstd.c8
-rw-r--r--sys/contrib/openzfs/rpm/generic/zfs-kmod.spec.in5
-rw-r--r--sys/contrib/openzfs/rpm/generic/zfs.spec.in17
-rw-r--r--sys/contrib/openzfs/rpm/redhat/zfs-kmod.spec.in5
-rw-r--r--sys/contrib/openzfs/scripts/Makefile.am4
-rwxr-xr-xsys/contrib/openzfs/scripts/cstyle.pl5
-rwxr-xr-xsys/contrib/openzfs/scripts/dkms.mkconf22
-rwxr-xr-xsys/contrib/openzfs/scripts/zfs-tests-color.sh27
-rwxr-xr-xsys/contrib/openzfs/scripts/zfs-tests.sh56
-rwxr-xr-xsys/contrib/openzfs/scripts/zloop.sh3
-rw-r--r--sys/contrib/openzfs/tests/runfiles/common.run22
-rw-r--r--sys/contrib/openzfs/tests/runfiles/freebsd.run4
-rw-r--r--sys/contrib/openzfs/tests/runfiles/linux.run16
-rw-r--r--sys/contrib/openzfs/tests/runfiles/sanity.run2
-rwxr-xr-xsys/contrib/openzfs/tests/test-runner/bin/test-runner.py.in54
-rwxr-xr-xsys/contrib/openzfs/tests/test-runner/bin/zts-report.py.in10
-rw-r--r--sys/contrib/openzfs/tests/test-runner/man/test-runner.12
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/cmd/Makefile.am2
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/cmd/draid/draid.c2
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/cmd/mkbusy/mkbusy.c6
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/cmd/mkfile/mkfile.c2
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/cmd/read_dos_attributes/.gitignore1
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/cmd/read_dos_attributes/Makefile.am6
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/cmd/read_dos_attributes/read_dos_attributes.c167
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/cmd/write_dos_attributes/.gitignore1
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/cmd/write_dos_attributes/Makefile.am6
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/cmd/write_dos_attributes/write_dos_attributes.c201
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/include/commands.cfg7
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/include/default.cfg.in15
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/include/libtest.shlib144
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/include/tunables.cfg2
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/tests/functional/Makefile.am2
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/tests/functional/acl/off/Makefile.am2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/acl/off/dosmode.ksh97
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/tests/functional/acl/off/dosmode_readonly_write.c11
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/alloc_class/alloc_class_012_pos.ksh3
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/alloc_class/alloc_class_013_pos.ksh4
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zdb/zdb_object_range_pos.ksh4
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zdb/zdb_objset_id.ksh30
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs/zfs_002_pos.ksh1
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/zfs_copies_002_pos.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/setup.ksh4
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_clone_livelist_condense_and_disable.ksh6
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_clone_livelist_condense_races.ksh6
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_clone_livelist_dedup.ksh7
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_clone_livelist.ksh6
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_dev_removal_condense.ksh2
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/Makefile.am3
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/receive-o-x_props_aliases.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/receive-o-x_props_override.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_-wR-encrypted-mix.ksh75
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_010_pos.ksh4
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_to_encrypted.ksh18
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/setup.ksh3
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send-b.ksh10
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_003_pos.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_004_neg.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_005_pos.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_007_pos.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_encrypted.ksh10
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_encrypted_unloaded.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_raw.ksh14
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_skip_missing.ksh5
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_009_pos.ksh7
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool/zpool_002_pos.ksh1
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool/zpool_003_pos.ksh1
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add.kshlib19
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create.shlib17
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_events/zpool_events_clear.ksh3
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_expand/zpool_expand_001_pos.ksh4
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get.cfg1
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/import_devices_missing.ksh4
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/import_rewind_config_changed.ksh58
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_errata4.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_trim/zpool_trim_partial.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_trim/zpool_trim_start_and_cancel_pos.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/deadman/deadman_ratelimit.ksh2
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/tests/functional/dos_attributes/Makefile.am8
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/dos_attributes/cleanup.ksh34
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/dos_attributes/read_dos_attrs_001.ksh60
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/dos_attributes/setup.ksh35
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/dos_attributes/write_dos_attrs_001.ksh61
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/events/cleanup.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/events/events_002_pos.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/events/zed_fd_spill.ksh8
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/fault/decrypt_fault.ksh1
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/features/large_dnode/large_dnode_005_pos.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/history/history_006_neg.ksh4
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/inheritance/inherit_001_pos.ksh4
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/mv_files/mv_files_001_pos.ksh1
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/mv_files/mv_files_002_pos.ksh1
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/tests/functional/mv_files/mv_files_common.kshlib55
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/mv_files/setup.ksh24
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/tests/functional/no_space/Makefile.am3
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/no_space/enospc_002_pos.ksh3
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/no_space/enospc_rm.ksh60
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/online_offline/setup.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/pam/pam_basic.ksh4
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/pam/pam_nounmount.ksh4
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/pam/pam_short_password.ksh4
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/pool_checkpoint/checkpoint_ro_rewind.ksh4
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projecttree_002_pos.ksh3
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/setup.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/pyzfs/pyzfs_unittest.ksh.in4
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/quota/setup.ksh4
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/redacted_send/redacted_incrementals.ksh14
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/redacted_send/redacted_largeblocks.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/redacted_send/redacted_negative.ksh8
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/redacted_send/redacted_resume.ksh2
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/tests/functional/redundancy/redundancy.kshlib4
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/redundancy/redundancy_draid.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/redundancy/redundancy_draid_damaged.ksh6
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/redundancy/redundancy_raidz.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/refquota/setup.ksh4
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/refreserv/refreserv_raidz.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/refreserv/setup.ksh4
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/removal/removal_with_errors.ksh1
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/removal/removal_with_export.ksh1
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/removal/removal_with_send.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/replacement/setup.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/reservation/setup.ksh1
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/Makefile.am2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/recv_dedup.ksh3
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/rsend.kshlib6
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/rsend_009_pos.ksh4
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/rsend_016_neg.ksh11
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/send_invalid.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/send_partial_dataset.ksh4
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/send_raw_ashift.ksh193
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/send_raw_spill_block.ksh161
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/tests/functional/simd/Makefile.am2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/simd/simd_supported.ksh58
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/tests/functional/slog/Makefile.am3
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/slog/slog_016_pos.ksh157
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/slog/slog_replay_fs_001.ksh6
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/slog/slog_replay_fs_002.ksh6
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/snapshot/snapshot_002_pos.ksh39
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/snapshot/snapshot_006_pos.ksh39
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/snapshot/snapshot_014_pos.ksh3
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/Makefile.am1
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/suid_write_to_file.c150
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/suid_write_to_none.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/suid_write_to_sgid.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/suid_write_to_suid.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/suid_write_to_suid_sgid.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/suid_write_zil_replay.ksh99
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/tests/functional/tmpfile/tmpfile_002_pos.c6
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/userquota/setup.ksh4
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/userquota/userspace_send_encrypted.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_004_pos.ksh1
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/write_dirs/setup.ksh4
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/tests/functional/xattr/Makefile.am3
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/xattr/setup.ksh4
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/xattr/xattr_compat.ksh92
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_volmode.ksh49
-rw-r--r--sys/modules/zfs/Makefile100
598 files changed, 31738 insertions, 43822 deletions
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/ctftools.h b/cddl/contrib/opensolaris/tools/ctf/cvt/ctftools.h
index 974d22459991..612c9f25a5a0 100644
--- a/cddl/contrib/opensolaris/tools/ctf/cvt/ctftools.h
+++ b/cddl/contrib/opensolaris/tools/ctf/cvt/ctftools.h
@@ -429,8 +429,8 @@ int streq(const char *, const char *);
int findelfsecidx(Elf *, const char *, const char *);
size_t elf_ptrsz(Elf *);
char *mktmpname(const char *, const char *);
-void terminate(const char *, ...) __NORETURN;
-void aborterr(const char *, ...) __NORETURN;
+void terminate(const char *, ...) __attribute__((noreturn));
+void aborterr(const char *, ...) __attribute__((noreturn));
void set_terminate_cleanup(void (*)(void));
void elfterminate(const char *, const char *, ...);
void warning(const char *, ...);
diff --git a/cddl/lib/libicp/Makefile b/cddl/lib/libicp/Makefile
index 1cdb146d0fa1..6a8e979ea836 100644
--- a/cddl/lib/libicp/Makefile
+++ b/cddl/lib/libicp/Makefile
@@ -28,9 +28,7 @@ ASM_SOURCES_AS =
KERNEL_C = \
spi/kcf_spi.c \
api/kcf_ctxops.c \
- api/kcf_digest.c \
api/kcf_cipher.c \
- api/kcf_miscapi.c \
api/kcf_mac.c \
algs/aes/aes_impl_aesni.c \
algs/aes/aes_impl_generic.c \
@@ -54,7 +52,6 @@ KERNEL_C = \
io/aes.c \
io/sha2_mod.c \
io/skein_mod.c \
- os/modhash.c \
core/kcf_sched.c \
core/kcf_prov_lib.c \
core/kcf_callprov.c \
diff --git a/cddl/lib/libicp_rescue/Makefile b/cddl/lib/libicp_rescue/Makefile
index ea1af847d807..d3e69d276d17 100644
--- a/cddl/lib/libicp_rescue/Makefile
+++ b/cddl/lib/libicp_rescue/Makefile
@@ -27,9 +27,7 @@ ASM_SOURCES_AS =
KERNEL_C = \
spi/kcf_spi.c \
api/kcf_ctxops.c \
- api/kcf_digest.c \
api/kcf_cipher.c \
- api/kcf_miscapi.c \
api/kcf_mac.c \
algs/aes/aes_impl_aesni.c \
algs/aes/aes_impl_generic.c \
@@ -51,7 +49,6 @@ KERNEL_C = \
io/aes.c \
io/sha2_mod.c \
io/skein_mod.c \
- os/modhash.c \
core/kcf_sched.c \
core/kcf_prov_lib.c \
core/kcf_callprov.c \
diff --git a/cddl/lib/libzpool/Makefile b/cddl/lib/libzpool/Makefile
index cbd485a4dd6b..69700ec51407 100644
--- a/cddl/lib/libzpool/Makefile
+++ b/cddl/lib/libzpool/Makefile
@@ -10,7 +10,9 @@ ZFSTOP= ${SRCTOP}/sys/contrib/openzfs
.PATH: ${ZFSTOP}/module/lua
# ZSTD_SRCS
.PATH: ${ZFSTOP}/module/zstd
-.PATH: ${ZFSTOP}/module/zstd/lib
+.PATH: ${ZFSTOP}/module/zstd/lib/common
+.PATH: ${ZFSTOP}/module/zstd/lib/compress
+.PATH: ${ZFSTOP}/module/zstd/lib/decompress
.PATH: ${ZFSTOP}/module/os/linux/zfs
@@ -90,9 +92,16 @@ KERNEL_C = \
dsl_destroy.c \
dsl_userhold.c \
edonr_zfs.c \
- hkdf.c \
+ entropy_common.c \
+ error_private.c \
fm.c \
+ fse_compress.c \
+ fse_decompress.c \
gzip.c \
+ hist.c \
+ hkdf.c \
+ huf_compress.c \
+ huf_decompress.c \
lzjb.c \
lz4.c \
lz4_zfs.c \
@@ -101,6 +110,7 @@ KERNEL_C = \
multilist.c \
objlist.c \
pathname.c \
+ pool.c \
range_tree.c \
refcount.c \
rrwlock.c \
@@ -147,6 +157,7 @@ KERNEL_C = \
vdev_removal.c \
vdev_root.c \
vdev_trim.c \
+ xxhash.c \
zap.c \
zap_leaf.c \
zap_micro.c \
@@ -174,7 +185,19 @@ KERNEL_C = \
zio_inject.c \
zle.c \
zrlock.c \
- zstd.c \
+ zstd_common.c \
+ zstd_compress.c \
+ zstd_compress_literals.c \
+ zstd_compress_sequences.c \
+ zstd_compress_superblock.c \
+ zstd_ddict.c \
+ zstd_decompress.c \
+ zstd_decompress_block.c \
+ zstd_double_fast.c \
+ zstd_fast.c \
+ zstd_lazy.c \
+ zstd_ldm.c \
+ zstd_opt.c \
zthr.c
ARCH_C =
@@ -262,8 +285,47 @@ CSTD= c99
CFLAGS+= -g -DDEBUG=1
-CFLAGS.zfs_zstd.c= -Wno-cast-qual -Wno-pointer-arith
-CFLAGS.zstd.c+= -fno-tree-vectorize
-CFLAGS.zstd.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.entropy_common.c= -fno-tree-vectorize
+CFLAGS.entropy_common.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.error_private.c= -fno-tree-vectorize
+CFLAGS.error_private.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.fse_compress.c= -fno-tree-vectorize
+CFLAGS.fse_compress.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.fse_decompress.c= -fno-tree-vectorize
+CFLAGS.fse_decompress.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.hist.c= -fno-tree-vectorize
+CFLAGS.hist.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.huf_compress.c= -fno-tree-vectorize
+CFLAGS.huf_compress.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.huf_decompress.c= -fno-tree-vectorize
+CFLAGS.huf_decompress.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.pool.c= -fno-tree-vectorize
+CFLAGS.pool.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.xxhash.c= -fno-tree-vectorize
+CFLAGS.xxhash.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_compress.c= -fno-tree-vectorize
+CFLAGS.zstd_compress.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_compress_literals.c= -fno-tree-vectorize
+CFLAGS.zstd_compress_literals.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_compress_sequences.c= -fno-tree-vectorize
+CFLAGS.zstd_compress_sequences.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_compress_superblock.c= -fno-tree-vectorize
+CFLAGS.zstd_compress_superblock.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_double_fast.c= -fno-tree-vectorize
+CFLAGS.zstd_double_fast.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_fast.c= -fno-tree-vectorize
+CFLAGS.zstd_fast.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_lazy.c= -fno-tree-vectorize
+CFLAGS.zstd_lazy.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_ldm.c= -fno-tree-vectorize
+CFLAGS.zstd_ldm.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_opt.c= -fno-tree-vectorize
+CFLAGS.zstd_opt.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_ddict.c= -fno-tree-vectorize
+CFLAGS.zstd_ddict.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_decompress.c= -fno-tree-vectorize
+CFLAGS.zstd_decompress.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_decompress_block.c= -fno-tree-vectorize
+CFLAGS.zstd_decompress_block.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
.include <bsd.lib.mk>
diff --git a/stand/libsa/zfs/Makefile.inc b/stand/libsa/zfs/Makefile.inc
index 00839c05d37d..0b51fff8a698 100644
--- a/stand/libsa/zfs/Makefile.inc
+++ b/stand/libsa/zfs/Makefile.inc
@@ -3,9 +3,20 @@
.PATH: ${ZFSSRC}
.PATH: ${SYSDIR}/crypto/skein
.PATH: ${ZFSOSSRC}/spl
-.PATH: ${OZFS}/module/zstd/lib
+.PATH: ${OZFS}/module/zstd/lib/common
+.PATH: ${OZFS}/module/zstd/lib/compress
+.PATH: ${OZFS}/module/zstd/lib/decompress
ZFSSRC= zfs.c nvlist.c skein.c skein_block.c list.c
-ZFSSRC+= zstd_shim.c zstd.c
+ZFSSRC+= zstd_shim.c
+ZFSSRC+= entropy_common.c error_private.c
+ZFSSRC+= fse_compress.c fse_decompress.c hist.c
+ZFSSRC+= huf_compress.c huf_decompress.c pool.c xxhash.c
+ZFSSRC+= zstd_common.c zstd_compress.c zstd_compress_literals.c
+ZFSSRC+= zstd_compress_sequences.c zstd_compress_superblock.c
+ZFSSRC+= zstd_ddict.c zstd_decompress.c zstd_decompress_block.c
+ZFSSRC+= zstd_double_fast.c zstd_fast.c zstd_lazy.c zstd_ldm.c
+ZFSSRC+= zstd_opt.c
+
CFLAGS+= -DHAS_ZSTD_ZFS
SRCS+= ${ZFSSRC}
@@ -29,8 +40,50 @@ CFLAGS_EARLY.zstd_shim.c+= ${ZFS_EARLY}
CFLAGS.nvlist.c+= -I${ZFSOSINC}/spl
CFLAGS.zfs.c+= -I${ZFSOSINC}/spl \
-I${SRCTOP}/sys/cddl/contrib/opensolaris/common/lz4
-CFLAGS.zstd.c+= -U__BMI__
-CFLAGS.zstd.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.entropy_common.c= -U__BMI__
+CFLAGS.entropy_common.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.error_private.c= -U__BMI__
+CFLAGS.error_private.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.fse_compress.c= -U__BMI__
+CFLAGS.fse_compress.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.fse_decompress.c= -U__BMI__
+CFLAGS.fse_decompress.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.hist.c= -U__BMI__
+CFLAGS.hist.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.huf_compress.c= -U__BMI__
+CFLAGS.huf_compress.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.huf_decompress.c= -U__BMI__
+CFLAGS.huf_decompress.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.pool.c= -U__BMI__
+CFLAGS.pool.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.xxhash.c= -U__BMI__
+CFLAGS.xxhash.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_common.c= -U__BMI__
+CFLAGS.zstd_common.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_compress.c= -U__BMI__
+CFLAGS.zstd_compress.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_compress_literals.c= -U__BMI__
+CFLAGS.zstd_compress_literals.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_compress_sequences.c= -U__BMI__
+CFLAGS.zstd_compress_sequences.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_compress_superblock.c= -U__BMI__
+CFLAGS.zstd_compress_superblock.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_double_fast.c= -U__BMI__
+CFLAGS.zstd_double_fast.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_fast.c= -U__BMI__
+CFLAGS.zstd_fast.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_lazy.c= -U__BMI__
+CFLAGS.zstd_lazy.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_ldm.c= -U__BMI__
+CFLAGS.zstd_ldm.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_opt.c= -U__BMI__
+CFLAGS.zstd_opt.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_ddict.c= -U__BMI__
+CFLAGS.zstd_ddict.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_decompress.c= -U__BMI__
+CFLAGS.zstd_decompress.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_decompress_block.c= -U__BMI__
+CFLAGS.zstd_decompress_block.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
CFLAGS.zstd_shim.c+= -DIN_BASE -I${OZFS}/include
# Do not unroll skein loops, reduce code size
diff --git a/sys/cddl/contrib/opensolaris/uts/common/sys/cmn_err.h b/sys/cddl/contrib/opensolaris/uts/common/sys/cmn_err.h
index e710d8e5c30b..0733c5ee63c3 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/sys/cmn_err.h
+++ b/sys/cddl/contrib/opensolaris/uts/common/sys/cmn_err.h
@@ -111,11 +111,11 @@ extern char *vsprintf(char *, const char *, __va_list)
/*PRINTFLIKE1*/
extern void panic(const char *, ...)
- __KPRINTFLIKE(1) __NORETURN;
+ __KPRINTFLIKE(1) __attribute__((noreturn));
#pragma rarely_called(panic)
extern void vpanic(const char *, __va_list)
- __KVPRINTFLIKE(1) __NORETURN;
+ __KVPRINTFLIKE(1) __attribute__((noreturn));
#pragma rarely_called(vpanic)
#endif /* _KERNEL */
diff --git a/sys/contrib/openzfs/.github/workflows/build-dependencies.txt b/sys/contrib/openzfs/.github/workflows/build-dependencies.txt
new file mode 100644
index 000000000000..e591399001f5
--- /dev/null
+++ b/sys/contrib/openzfs/.github/workflows/build-dependencies.txt
@@ -0,0 +1,49 @@
+acl
+alien
+attr
+autoconf
+bc
+build-essential
+curl
+dbench
+fakeroot
+fio
+gdb
+gdebi
+git
+ksh
+lcov
+libacl1-dev
+libaio-dev
+libattr1-dev
+libblkid-dev
+libcurl4-openssl-dev
+libdevmapper-dev
+libelf-dev
+libffi-dev
+libmount-dev
+libpam0g-dev
+libselinux-dev
+libssl-dev
+libtool
+libudev-dev
+lsscsi
+mdadm
+nfs-kernel-server
+pamtester
+parted
+python3
+python3-cffi
+python3-dev
+python3-packaging
+python3-setuptools
+rng-tools
+rsync
+samba
+sysstat
+uuid-dev
+watchdog
+wget
+xfslibs-dev
+xz-utils
+zlib1g-dev
diff --git a/sys/contrib/openzfs/.github/workflows/checkstyle.yaml b/sys/contrib/openzfs/.github/workflows/checkstyle.yaml
index a102b6e8aa1f..abc0ff11916a 100644
--- a/sys/contrib/openzfs/.github/workflows/checkstyle.yaml
+++ b/sys/contrib/openzfs/.github/workflows/checkstyle.yaml
@@ -6,7 +6,7 @@ on:
jobs:
checkstyle:
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
@@ -14,31 +14,37 @@ jobs:
- name: Install dependencies
run: |
sudo apt-get update
- sudo apt-get install --yes -qq build-essential autoconf libtool gawk alien fakeroot linux-headers-$(uname -r)
- sudo apt-get install --yes -qq zlib1g-dev uuid-dev libattr1-dev libblkid-dev libselinux-dev libudev-dev libssl-dev python3 python3-dev python3-setuptools python3-cffi
- # packages for tests
- sudo apt-get install --yes -qq parted lsscsi ksh attr acl nfs-kernel-server fio
- sudo apt-get install --yes -qq mandoc cppcheck pax-utils devscripts
- sudo -E pip --quiet install flake8
+ sudo xargs --arg-file=${{ github.workspace }}/.github/workflows/build-dependencies.txt apt-get install -qq
+ sudo apt-get install -qq mandoc cppcheck pax-utils devscripts
+ sudo python3 -m pip install --quiet flake8
+ sudo apt-get clean
+
+ # confirm that the tools are installed
+ # the build system doesn't fail when they are not
+ checkbashisms --version
+ cppcheck --version
+ flake8 --version
+ scanelf --version
+ shellcheck --version
- name: Prepare
run: |
- sh ./autogen.sh
+ ./autogen.sh
./configure
- make -j$(nproc)
+ make -j$(nproc) --no-print-directory --silent
- name: Checkstyle
run: |
- make checkstyle
+ make -j$(nproc) --no-print-directory --silent checkstyle
- name: Lint
run: |
- make lint
+ make -j$(nproc) --no-print-directory --silent lint
- name: CheckABI
id: CheckABI
run: |
- sudo docker run -v $(pwd):/source ghcr.io/openzfs/libabigail make checkabi
+ docker run -v $(pwd):/source ghcr.io/openzfs/libabigail make -j$(nproc) --no-print-directory --silent checkabi
- name: StoreABI
if: failure() && steps.CheckABI.outcome == 'failure'
run: |
- sudo docker run -v $(pwd):/source ghcr.io/openzfs/libabigail make storeabi
+ docker run -v $(pwd):/source ghcr.io/openzfs/libabigail make -j$(nproc) --no-print-directory --silent storeabi
- name: Prepare artifacts
if: failure() && steps.CheckABI.outcome == 'failure'
run: |
diff --git a/sys/contrib/openzfs/.github/workflows/scripts/reclaim_disk_space.sh b/sys/contrib/openzfs/.github/workflows/scripts/reclaim_disk_space.sh
new file mode 100755
index 000000000000..cc16a9079317
--- /dev/null
+++ b/sys/contrib/openzfs/.github/workflows/scripts/reclaim_disk_space.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+set -eu
+
+# remove 4GiB of images
+sudo systemd-run docker system prune --force --all --volumes
+
+# remove unused software
+sudo systemd-run rm -rf \
+ "$AGENT_TOOLSDIRECTORY" \
+ /opt/* \
+ /usr/local/* \
+ /usr/share/az* \
+ /usr/share/dotnet \
+ /usr/share/gradle* \
+ /usr/share/miniconda \
+ /usr/share/swift \
+ /var/lib/gems \
+ /var/lib/mysql \
+ /var/lib/snapd
diff --git a/sys/contrib/openzfs/.github/workflows/zfs-tests-functional.yml b/sys/contrib/openzfs/.github/workflows/zfs-tests-functional.yml
index 19d3f57baec9..1a32e2e22932 100644
--- a/sys/contrib/openzfs/.github/workflows/zfs-tests-functional.yml
+++ b/sys/contrib/openzfs/.github/workflows/zfs-tests-functional.yml
@@ -15,27 +15,23 @@ jobs:
- uses: actions/checkout@v2
with:
ref: ${{ github.event.pull_request.head.sha }}
+ - name: Reclaim disk space
+ run: |
+ ${{ github.workspace }}/.github/workflows/scripts/reclaim_disk_space.sh
- name: Install dependencies
run: |
sudo apt-get update
- sudo apt-get install --yes -qq build-essential autoconf libtool gdb lcov \
- git alien fakeroot wget curl bc fio acl \
- sysstat mdadm lsscsi parted gdebi attr dbench watchdog ksh \
- nfs-kernel-server samba rng-tools xz-utils \
- zlib1g-dev uuid-dev libblkid-dev libselinux-dev \
- xfslibs-dev libattr1-dev libacl1-dev libudev-dev libdevmapper-dev \
- libssl-dev libffi-dev libaio-dev libelf-dev libmount-dev \
- libpam0g-dev pamtester libcurl4-openssl-dev \
- python3 python3-dev python3-setuptools python3-cffi python3-packaging
+ xargs --arg-file=${{ github.workspace }}/.github/workflows/build-dependencies.txt sudo apt-get install -qq
+ sudo apt-get clean
- name: Autogen.sh
run: |
- sh autogen.sh
+ ./autogen.sh
- name: Configure
run: |
- ./configure --enable-debug --enable-debuginfo
+ ./configure --enable-debug --enable-debuginfo --enable-asan --enable-ubsan
- name: Make
run: |
- make --no-print-directory -s pkg-utils pkg-kmod
+ make -j$(nproc) --no-print-directory --silent pkg-utils pkg-kmod
- name: Install
run: |
sudo dpkg -i *.deb
@@ -55,21 +51,24 @@ jobs:
sudo udevadm control --reload-rules
fi
fi
- # Workaround to provide additional free space for testing.
- # https://github.com/actions/virtual-environments/issues/2840
- sudo rm -rf /usr/share/dotnet
- sudo rm -rf /opt/ghc
- sudo rm -rf "/usr/local/share/boost"
- sudo rm -rf "$AGENT_TOOLSDIRECTORY"
+ - name: Clear the kernel ring buffer
+ run: |
+ sudo dmesg -c >/var/tmp/dmesg-prerun
+ - name: Report disk space
+ run: |
+ df -h /
- name: Tests
run: |
- /usr/share/zfs/zfs-tests.sh -vR -s 3G
+ set -o pipefail
+ /usr/share/zfs/zfs-tests.sh -vR -s 3G | scripts/zfs-tests-color.sh
+ shell: bash
+ timeout-minutes: 330
- name: Prepare artifacts
if: failure()
run: |
RESULTS_PATH=$(readlink -f /var/tmp/test_results/current)
sudo dmesg > $RESULTS_PATH/dmesg
- sudo cp /var/log/syslog $RESULTS_PATH/
+ sudo cp /var/log/syslog /var/tmp/dmesg-prerun $RESULTS_PATH/
sudo chmod +r $RESULTS_PATH/*
# Replace ':' in dir names, actions/upload-artifact doesn't support it
for f in $(find /var/tmp/test_results -name '*:*'); do mv "$f" "${f//:/__}"; done
@@ -77,5 +76,7 @@ jobs:
if: failure()
with:
name: Test logs Ubuntu-${{ matrix.os }}
- path: /var/tmp/test_results/20*/
+ path: |
+ /var/tmp/test_results/*
+ !/var/tmp/test_results/current
if-no-files-found: ignore
diff --git a/sys/contrib/openzfs/.github/workflows/zfs-tests-sanity.yml b/sys/contrib/openzfs/.github/workflows/zfs-tests-sanity.yml
index 2b97fd61822f..d10350d2961f 100644
--- a/sys/contrib/openzfs/.github/workflows/zfs-tests-sanity.yml
+++ b/sys/contrib/openzfs/.github/workflows/zfs-tests-sanity.yml
@@ -6,32 +6,28 @@ on:
jobs:
tests:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
with:
ref: ${{ github.event.pull_request.head.sha }}
+ - name: Reclaim disk space
+ run: |
+ ${{ github.workspace }}/.github/workflows/scripts/reclaim_disk_space.sh
- name: Install dependencies
run: |
sudo apt-get update
- sudo apt-get install --yes -qq build-essential autoconf libtool gdb lcov \
- git alien fakeroot wget curl bc fio acl \
- sysstat mdadm lsscsi parted gdebi attr dbench watchdog ksh \
- nfs-kernel-server samba rng-tools xz-utils \
- zlib1g-dev uuid-dev libblkid-dev libselinux-dev \
- xfslibs-dev libattr1-dev libacl1-dev libudev-dev libdevmapper-dev \
- libssl-dev libffi-dev libaio-dev libelf-dev libmount-dev \
- libpam0g-dev pamtester libcurl4-openssl-dev \
- python3 python3-dev python3-setuptools python3-cffi python3-packaging
+ xargs --arg-file=${{ github.workspace }}/.github/workflows/build-dependencies.txt sudo apt-get install -qq
+ sudo apt-get clean
- name: Autogen.sh
run: |
- sh autogen.sh
+ ./autogen.sh
- name: Configure
run: |
- ./configure --enable-debug --enable-debuginfo
+ ./configure --enable-debug --enable-debuginfo --enable-asan --enable-ubsan
- name: Make
run: |
- make --no-print-directory -s pkg-utils pkg-kmod
+ make -j$(nproc) --no-print-directory --silent pkg-utils pkg-kmod
- name: Install
run: |
sudo dpkg -i *.deb
@@ -51,27 +47,32 @@ jobs:
sudo udevadm control --reload-rules
fi
fi
- # Workaround to provide additional free space for testing.
- # https://github.com/actions/virtual-environments/issues/2840
- sudo rm -rf /usr/share/dotnet
- sudo rm -rf /opt/ghc
- sudo rm -rf "/usr/local/share/boost"
- sudo rm -rf "$AGENT_TOOLSDIRECTORY"
+ - name: Clear the kernel ring buffer
+ run: |
+ sudo dmesg -c >/var/tmp/dmesg-prerun
+ - name: Report disk space
+ run: |
+ df -h /
- name: Tests
run: |
- /usr/share/zfs/zfs-tests.sh -vR -s 3G -r sanity
+ set -o pipefail
+ /usr/share/zfs/zfs-tests.sh -vR -s 3G -r sanity | scripts/zfs-tests-color.sh
+ shell: bash
+ timeout-minutes: 330
- name: Prepare artifacts
if: failure()
run: |
RESULTS_PATH=$(readlink -f /var/tmp/test_results/current)
sudo dmesg > $RESULTS_PATH/dmesg
- sudo cp /var/log/syslog $RESULTS_PATH/
+ sudo cp /var/log/syslog /var/tmp/dmesg-prerun $RESULTS_PATH/
sudo chmod +r $RESULTS_PATH/*
# Replace ':' in dir names, actions/upload-artifact doesn't support it
for f in $(find /var/tmp/test_results -name '*:*'); do mv "$f" "${f//:/__}"; done
- uses: actions/upload-artifact@v2
if: failure()
with:
- name: Test logs
- path: /var/tmp/test_results/20*/
+ name: Test logs Ubuntu-${{ matrix.os }}
+ path: |
+ /var/tmp/test_results/*
+ !/var/tmp/test_results/current
if-no-files-found: ignore
diff --git a/sys/contrib/openzfs/.github/workflows/zloop.yml b/sys/contrib/openzfs/.github/workflows/zloop.yml
index 5c1b9bd1ce22..8eb2a1d9bb0f 100644
--- a/sys/contrib/openzfs/.github/workflows/zloop.yml
+++ b/sys/contrib/openzfs/.github/workflows/zloop.yml
@@ -6,7 +6,7 @@ on:
jobs:
tests:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-20.04
env:
TEST_DIR: /var/tmp/zloop
steps:
@@ -16,22 +16,17 @@ jobs:
- name: Install dependencies
run: |
sudo apt-get update
- sudo apt-get install --yes -qq build-essential autoconf libtool gdb \
- git alien fakeroot \
- zlib1g-dev uuid-dev libblkid-dev libselinux-dev \
- xfslibs-dev libattr1-dev libacl1-dev libudev-dev libdevmapper-dev \
- libssl-dev libffi-dev libaio-dev libelf-dev libmount-dev \
- libpam0g-dev \
- python3 python3-dev python3-setuptools python3-cffi python3-packaging
+ xargs --arg-file=${{ github.workspace }}/.github/workflows/build-dependencies.txt sudo apt-get install -qq
+ sudo apt-get clean
- name: Autogen.sh
run: |
- sh autogen.sh
+ ./autogen.sh
- name: Configure
run: |
- ./configure --enable-debug --enable-debuginfo
+ ./configure --enable-debug --enable-debuginfo --enable-asan --enable-ubsan
- name: Make
run: |
- make --no-print-directory -s pkg-utils pkg-kmod
+ make -j$(nproc) --no-print-directory --silent pkg-utils pkg-kmod
- name: Install
run: |
sudo dpkg -i *.deb
diff --git a/sys/contrib/openzfs/Makefile.am b/sys/contrib/openzfs/Makefile.am
index 37a9bfdf8697..42330440a689 100644
--- a/sys/contrib/openzfs/Makefile.am
+++ b/sys/contrib/openzfs/Makefile.am
@@ -72,7 +72,7 @@ distclean-local::
-o -name 'core' -o -name 'Makefile' -o -name 'Module.symvers' \
-o -name '*.order' -o -name '*.markers' -o -name '*.gcda' \
-o -name '*.gcno' \) \
- -type f -print | xargs $(RM)
+ -type f -delete
all-local:
-[ -x ${top_builddir}/scripts/zfs-tests.sh ] && \
@@ -126,6 +126,8 @@ cstyle:
! -name 'zfs_config.*' ! -name '*.mod.c' \
! -name 'opt_global.h' ! -name '*_if*.h' \
! -path './module/zstd/lib/*' \
+ ! -path './include/sys/lua/*' \
+ ! -path './module/lua/l*.[ch]' \
! -path './module/zfs/lz4.c' \
$(cstyle_line)
@@ -136,41 +138,24 @@ SHELLCHECKSCRIPTS = autogen.sh
PHONY += checkabi storeabi
-checklibabiversion:
- libabiversion=`abidw -v | $(SED) 's/[^0-9]//g'`; \
- if test $$libabiversion -lt "200"; then \
- /bin/echo -e "\n" \
- "*** Please use libabigail 2.0.0 version or newer;\n" \
- "*** otherwise results are not consistent!\n" \
- "(or see https://github.com/openzfs/libabigail-docker )\n"; \
- exit 1; \
- fi;
-
-checkabi: checklibabiversion lib
+checkabi: lib
$(MAKE) -C lib checkabi
-storeabi: checklibabiversion lib
+storeabi: lib
$(MAKE) -C lib storeabi
PHONY += mancheck
mancheck:
${top_srcdir}/scripts/mancheck.sh ${top_srcdir}/man ${top_srcdir}/tests/test-runner/man
-if BUILD_LINUX
-stat_fmt = -c '%A %n'
-else
-stat_fmt = -f '%Sp %N'
-endif
-
PHONY += testscheck
testscheck:
- @find ${top_srcdir}/tests/zfs-tests -type f \
+ @[ $$(find ${top_srcdir}/tests/zfs-tests -type f \
\( -name '*.ksh' -not ${filter_executable} \) -o \
\( -name '*.kshlib' ${filter_executable} \) -o \
\( -name '*.shlib' ${filter_executable} \) -o \
\( -name '*.cfg' ${filter_executable} \) | \
- xargs -r stat ${stat_fmt} | \
- awk '{c++; print} END {if(c>0) exit 1}'
+ tee /dev/stderr | wc -l) -eq 0 ]
PHONY += vcscheck
vcscheck:
@@ -213,13 +198,13 @@ PHONY += ctags
ctags:
$(RM) tags
find $(top_srcdir) -name '.?*' -prune \
- -o -type f -name '*.[hcS]' -print | xargs ctags -a
+ -o -type f -name '*.[hcS]' -exec ctags -a {} +
PHONY += etags
etags:
$(RM) TAGS
find $(top_srcdir) -name '.?*' -prune \
- -o -type f -name '*.[hcS]' -print | xargs etags -a
+ -o -type f -name '*.[hcS]' -exec etags -a {} +
PHONY += cscopelist
cscopelist:
diff --git a/sys/contrib/openzfs/cmd/Makefile.am b/sys/contrib/openzfs/cmd/Makefile.am
index 3994d1434e99..68f1e892d3f4 100644
--- a/sys/contrib/openzfs/cmd/Makefile.am
+++ b/sys/contrib/openzfs/cmd/Makefile.am
@@ -9,7 +9,6 @@ CPPCHECKDIRS += raidz_test zfs_ids_to_path zpool_influxdb
# TODO: #12084: SHELLCHECKDIRS += vdev_id
SHELLCHECKDIRS = fsck_zfs zed zpool zvol_wait
-SHELLCHECK_OPTS = --enable=all
if USING_PYTHON
SUBDIRS += arcstat arc_summary dbufstat
diff --git a/sys/contrib/openzfs/cmd/fsck_zfs/Makefile.am b/sys/contrib/openzfs/cmd/fsck_zfs/Makefile.am
index d86ea1f786f4..ec955c7c7ff9 100644
--- a/sys/contrib/openzfs/cmd/fsck_zfs/Makefile.am
+++ b/sys/contrib/openzfs/cmd/fsck_zfs/Makefile.am
@@ -5,4 +5,3 @@ dist_sbin_SCRIPTS = fsck.zfs
SUBSTFILES += $(dist_sbin_SCRIPTS)
-SHELLCHECK_OPTS = --enable=all
diff --git a/sys/contrib/openzfs/cmd/mount_zfs/mount_zfs.c b/sys/contrib/openzfs/cmd/mount_zfs/mount_zfs.c
index 434d53cbad04..669ed88f91c4 100644
--- a/sys/contrib/openzfs/cmd/mount_zfs/mount_zfs.c
+++ b/sys/contrib/openzfs/cmd/mount_zfs/mount_zfs.c
@@ -246,13 +246,6 @@ main(int argc, char **argv)
}
}
- if (verbose)
- (void) fprintf(stdout, gettext("mount.zfs:\n"
- " dataset: \"%s\"\n mountpoint: \"%s\"\n"
- " mountflags: 0x%lx\n zfsflags: 0x%lx\n"
- " mountopts: \"%s\"\n mtabopts: \"%s\"\n"),
- dataset, mntpoint, mntflags, zfsflags, mntopts, mtabopt);
-
if (mntflags & MS_REMOUNT) {
nomtab = 1;
remount = 1;
@@ -275,7 +268,10 @@ main(int argc, char **argv)
return (MOUNT_USAGE);
}
- zfs_adjust_mount_options(zhp, mntpoint, mntopts, mtabopt);
+ if (!zfsutil || sloppy ||
+ libzfs_envvar_is_set("ZFS_MOUNT_HELPER")) {
+ zfs_adjust_mount_options(zhp, mntpoint, mntopts, mtabopt);
+ }
/* treat all snapshots as legacy mount points */
if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT)
@@ -293,12 +289,11 @@ main(int argc, char **argv)
if (zfs_version == 0) {
fprintf(stderr, gettext("unable to fetch "
"ZFS version for filesystem '%s'\n"), dataset);
+ zfs_close(zhp);
+ libzfs_fini(g_zfs);
return (MOUNT_SYSERR);
}
- zfs_close(zhp);
- libzfs_fini(g_zfs);
-
/*
* Legacy mount points may only be mounted using 'mount', never using
* 'zfs mount'. However, since 'zfs mount' actually invokes 'mount'
@@ -316,6 +311,8 @@ main(int argc, char **argv)
"Use 'zfs set mountpoint=%s' or 'mount -t zfs %s %s'.\n"
"See zfs(8) for more information.\n"),
dataset, mntpoint, dataset, mntpoint);
+ zfs_close(zhp);
+ libzfs_fini(g_zfs);
return (MOUNT_USAGE);
}
@@ -326,14 +323,38 @@ main(int argc, char **argv)
"Use 'zfs set mountpoint=%s' or 'zfs mount %s'.\n"
"See zfs(8) for more information.\n"),
dataset, "legacy", dataset);
+ zfs_close(zhp);
+ libzfs_fini(g_zfs);
return (MOUNT_USAGE);
}
+ if (verbose)
+ (void) fprintf(stdout, gettext("mount.zfs:\n"
+ " dataset: \"%s\"\n mountpoint: \"%s\"\n"
+ " mountflags: 0x%lx\n zfsflags: 0x%lx\n"
+ " mountopts: \"%s\"\n mtabopts: \"%s\"\n"),
+ dataset, mntpoint, mntflags, zfsflags, mntopts, mtabopt);
+
if (!fake) {
- error = mount(dataset, mntpoint, MNTTYPE_ZFS,
- mntflags, mntopts);
+ if (zfsutil && !sloppy &&
+ !libzfs_envvar_is_set("ZFS_MOUNT_HELPER")) {
+ error = zfs_mount_at(zhp, mntopts, mntflags, mntpoint);
+ if (error) {
+ (void) fprintf(stderr, "zfs_mount_at() failed: "
+ "%s", libzfs_error_description(g_zfs));
+ zfs_close(zhp);
+ libzfs_fini(g_zfs);
+ return (MOUNT_SYSERR);
+ }
+ } else {
+ error = mount(dataset, mntpoint, MNTTYPE_ZFS,
+ mntflags, mntopts);
+ }
}
+ zfs_close(zhp);
+ libzfs_fini(g_zfs);
+
if (error) {
switch (errno) {
case ENOENT:
@@ -369,7 +390,7 @@ main(int argc, char **argv)
return (MOUNT_SYSERR);
}
#endif
- fallthrough;
+ zfs_fallthrough;
default:
(void) fprintf(stderr, gettext("filesystem "
"'%s' can not be mounted: %s\n"), dataset,
diff --git a/sys/contrib/openzfs/cmd/raidz_test/raidz_test.c b/sys/contrib/openzfs/cmd/raidz_test/raidz_test.c
index b177105ee63b..8bb38f2f72c7 100644
--- a/sys/contrib/openzfs/cmd/raidz_test/raidz_test.c
+++ b/sys/contrib/openzfs/cmd/raidz_test/raidz_test.c
@@ -71,12 +71,13 @@ static void print_opts(raidz_test_opts_t *opts, boolean_t force)
{
char *verbose;
switch (opts->rto_v) {
- case 0:
+ case D_ALL:
verbose = "no";
break;
- case 1:
+ case D_INFO:
verbose = "info";
break;
+ case D_DEBUG:
default:
verbose = "debug";
break;
@@ -119,7 +120,7 @@ static void usage(boolean_t requested)
"\t[-B benchmark all raidz implementations]\n"
"\t[-e use expanded raidz map (default: %s)]\n"
"\t[-r expanded raidz map reflow offset (default: %llx)]\n"
- "\t[-v increase verbosity (default: %zu)]\n"
+ "\t[-v increase verbosity (default: %d)]\n"
"\t[-h (print help)]\n"
"\t[-T test the test, see if failure would be detected]\n"
"\t[-D debug (attach gdb on SIGSEGV)]\n"
@@ -131,7 +132,7 @@ static void usage(boolean_t requested)
rto_opts.rto_sweep ? "yes" : "no", /* -S */
rto_opts.rto_expand ? "yes" : "no", /* -e */
(u_longlong_t)o->rto_expand_offset, /* -r */
- o->rto_v); /* -d */
+ o->rto_v); /* -v */
exit(requested ? 0 : 1);
}
@@ -839,7 +840,7 @@ static kcondvar_t sem_cv;
static int max_free_slots;
static int free_slots;
-static void
+static _Noreturn void
sweep_thread(void *arg)
{
int err = 0;
diff --git a/sys/contrib/openzfs/cmd/raidz_test/raidz_test.h b/sys/contrib/openzfs/cmd/raidz_test/raidz_test.h
index 0f7f4cee3eb6..40a8a85e5f6f 100644
--- a/sys/contrib/openzfs/cmd/raidz_test/raidz_test.h
+++ b/sys/contrib/openzfs/cmd/raidz_test/raidz_test.h
@@ -28,7 +28,7 @@
#include <sys/spa.h>
-static const char *raidz_impl_names[] = {
+static const char *const raidz_impl_names[] = {
"original",
"scalar",
"sse2",
@@ -42,12 +42,18 @@ static const char *raidz_impl_names[] = {
NULL
};
+enum raidz_verbosity {
+ D_ALL,
+ D_INFO,
+ D_DEBUG,
+};
+
typedef struct raidz_test_opts {
size_t rto_ashift;
uint64_t rto_offset;
size_t rto_dcols;
size_t rto_dsize;
- size_t rto_v;
+ enum raidz_verbosity rto_v;
size_t rto_sweep;
size_t rto_sweep_timeout;
size_t rto_benchmark;
@@ -68,7 +74,7 @@ static const raidz_test_opts_t rto_opts_defaults = {
.rto_offset = 1ULL << 0,
.rto_dcols = 8,
.rto_dsize = 1<<19,
- .rto_v = 0,
+ .rto_v = D_ALL,
.rto_sweep = 0,
.rto_benchmark = 0,
.rto_expand = 0,
@@ -86,10 +92,6 @@ static inline size_t ilog2(size_t a)
}
-#define D_ALL 0
-#define D_INFO 1
-#define D_DEBUG 2
-
#define LOG(lvl, a...) \
{ \
if (rto_opts.rto_v >= lvl) \
diff --git a/sys/contrib/openzfs/cmd/zdb/zdb.c b/sys/contrib/openzfs/cmd/zdb/zdb.c
index c0b1a62a3182..3fbe7510693a 100644
--- a/sys/contrib/openzfs/cmd/zdb/zdb.c
+++ b/sys/contrib/openzfs/cmd/zdb/zdb.c
@@ -1228,9 +1228,9 @@ dump_bpobj(objset_t *os, uint64_t object, void *data, size_t size)
char bytes[32], comp[32], uncomp[32];
/* make sure the output won't get truncated */
- CTASSERT(sizeof (bytes) >= NN_NUMBUF_SZ);
- CTASSERT(sizeof (comp) >= NN_NUMBUF_SZ);
- CTASSERT(sizeof (uncomp) >= NN_NUMBUF_SZ);
+ _Static_assert(sizeof (bytes) >= NN_NUMBUF_SZ, "bytes truncated");
+ _Static_assert(sizeof (comp) >= NN_NUMBUF_SZ, "comp truncated");
+ _Static_assert(sizeof (uncomp) >= NN_NUMBUF_SZ, "uncomp truncated");
if (bpop == NULL)
return;
@@ -1655,7 +1655,7 @@ dump_metaslab_stats(metaslab_t *msp)
int free_pct = range_tree_space(rt) * 100 / msp->ms_size;
/* max sure nicenum has enough space */
- CTASSERT(sizeof (maxbuf) >= NN_NUMBUF_SZ);
+ _Static_assert(sizeof (maxbuf) >= NN_NUMBUF_SZ, "maxbuf truncated");
zdb_nicenum(metaslab_largest_allocatable(msp), maxbuf, sizeof (maxbuf));
@@ -2490,7 +2490,7 @@ dump_dsl_dir(objset_t *os, uint64_t object, void *data, size_t size)
char nice[32];
/* make sure nicenum has enough space */
- CTASSERT(sizeof (nice) >= NN_NUMBUF_SZ);
+ _Static_assert(sizeof (nice) >= NN_NUMBUF_SZ, "nice truncated");
if (dd == NULL)
return;
@@ -2548,10 +2548,12 @@ dump_dsl_dataset(objset_t *os, uint64_t object, void *data, size_t size)
char blkbuf[BP_SPRINTF_LEN];
/* make sure nicenum has enough space */
- CTASSERT(sizeof (used) >= NN_NUMBUF_SZ);
- CTASSERT(sizeof (compressed) >= NN_NUMBUF_SZ);
- CTASSERT(sizeof (uncompressed) >= NN_NUMBUF_SZ);
- CTASSERT(sizeof (unique) >= NN_NUMBUF_SZ);
+ _Static_assert(sizeof (used) >= NN_NUMBUF_SZ, "used truncated");
+ _Static_assert(sizeof (compressed) >= NN_NUMBUF_SZ,
+ "compressed truncated");
+ _Static_assert(sizeof (uncompressed) >= NN_NUMBUF_SZ,
+ "uncompressed truncated");
+ _Static_assert(sizeof (unique) >= NN_NUMBUF_SZ, "unique truncated");
if (ds == NULL)
return;
@@ -2622,7 +2624,7 @@ dump_bptree(objset_t *os, uint64_t obj, const char *name)
dmu_buf_t *db;
/* make sure nicenum has enough space */
- CTASSERT(sizeof (bytes) >= NN_NUMBUF_SZ);
+ _Static_assert(sizeof (bytes) >= NN_NUMBUF_SZ, "bytes truncated");
if (dump_opt['d'] < 3)
return;
@@ -2663,9 +2665,9 @@ dump_full_bpobj(bpobj_t *bpo, const char *name, int indent)
uint64_t i;
/* make sure nicenum has enough space */
- CTASSERT(sizeof (bytes) >= NN_NUMBUF_SZ);
- CTASSERT(sizeof (comp) >= NN_NUMBUF_SZ);
- CTASSERT(sizeof (uncomp) >= NN_NUMBUF_SZ);
+ _Static_assert(sizeof (bytes) >= NN_NUMBUF_SZ, "bytes truncated");
+ _Static_assert(sizeof (comp) >= NN_NUMBUF_SZ, "comp truncated");
+ _Static_assert(sizeof (uncomp) >= NN_NUMBUF_SZ, "uncomp truncated");
if (dump_opt['d'] < 3)
return;
@@ -2941,10 +2943,10 @@ dump_blkptr_list(dsl_deadlist_t *dl, char *name)
}
/* make sure nicenum has enough space */
- CTASSERT(sizeof (bytes) >= NN_NUMBUF_SZ);
- CTASSERT(sizeof (comp) >= NN_NUMBUF_SZ);
- CTASSERT(sizeof (uncomp) >= NN_NUMBUF_SZ);
- CTASSERT(sizeof (entries) >= NN_NUMBUF_SZ);
+ _Static_assert(sizeof (bytes) >= NN_NUMBUF_SZ, "bytes truncated");
+ _Static_assert(sizeof (comp) >= NN_NUMBUF_SZ, "comp truncated");
+ _Static_assert(sizeof (uncomp) >= NN_NUMBUF_SZ, "uncomp truncated");
+ _Static_assert(sizeof (entries) >= NN_NUMBUF_SZ, "entries truncated");
if (dump_opt['d'] < 3)
return;
@@ -3428,11 +3430,12 @@ dump_object(objset_t *os, uint64_t object, int verbosity,
int error;
/* make sure nicenum has enough space */
- CTASSERT(sizeof (iblk) >= NN_NUMBUF_SZ);
- CTASSERT(sizeof (dblk) >= NN_NUMBUF_SZ);
- CTASSERT(sizeof (lsize) >= NN_NUMBUF_SZ);
- CTASSERT(sizeof (asize) >= NN_NUMBUF_SZ);
- CTASSERT(sizeof (bonus_size) >= NN_NUMBUF_SZ);
+ _Static_assert(sizeof (iblk) >= NN_NUMBUF_SZ, "iblk truncated");
+ _Static_assert(sizeof (dblk) >= NN_NUMBUF_SZ, "dblk truncated");
+ _Static_assert(sizeof (lsize) >= NN_NUMBUF_SZ, "lsize truncated");
+ _Static_assert(sizeof (asize) >= NN_NUMBUF_SZ, "asize truncated");
+ _Static_assert(sizeof (bonus_size) >= NN_NUMBUF_SZ,
+ "bonus_size truncated");
if (*print_header) {
(void) printf("\n%10s %3s %5s %5s %5s %6s %5s %6s %s\n",
@@ -3581,7 +3584,8 @@ dump_object(objset_t *os, uint64_t object, int verbosity,
for (;;) {
char segsize[32];
/* make sure nicenum has enough space */
- CTASSERT(sizeof (segsize) >= NN_NUMBUF_SZ);
+ _Static_assert(sizeof (segsize) >= NN_NUMBUF_SZ,
+ "segsize truncated");
error = dnode_next_offset(dn,
0, &start, minlvl, blkfill, 0);
if (error)
@@ -3770,7 +3774,7 @@ dump_objset(objset_t *os)
uint64_t flags;
/* make sure nicenum has enough space */
- CTASSERT(sizeof (numbuf) >= NN_NUMBUF_SZ);
+ _Static_assert(sizeof (numbuf) >= NN_NUMBUF_SZ, "numbuf truncated");
dsl_pool_config_enter(dmu_objset_pool(os), FTAG);
dmu_objset_fast_stat(os, &dds);
@@ -4651,7 +4655,7 @@ dump_path_impl(objset_t *os, uint64_t obj, char *name, uint64_t *retobj)
case DMU_OT_DIRECTORY_CONTENTS:
if (s != NULL && *(s + 1) != '\0')
return (dump_path_impl(os, child_obj, s + 1, retobj));
- fallthrough;
+ zfs_fallthrough;
case DMU_OT_PLAIN_FILE_CONTENTS:
if (retobj != NULL) {
*retobj = child_obj;
@@ -5542,7 +5546,7 @@ zdb_blkptr_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
(zcb->zcb_totalasize - bytes) / 1024 / kb_per_sec;
/* make sure nicenum has enough space */
- CTASSERT(sizeof (buf) >= NN_NUMBUF_SZ);
+ _Static_assert(sizeof (buf) >= NN_NUMBUF_SZ, "buf truncated");
zfs_nicebytes(bytes, buf, sizeof (buf));
(void) fprintf(stderr,
@@ -6651,12 +6655,18 @@ dump_block_stats(spa_t *spa)
const char *typename;
/* make sure nicenum has enough space */
- CTASSERT(sizeof (csize) >= NN_NUMBUF_SZ);
- CTASSERT(sizeof (lsize) >= NN_NUMBUF_SZ);
- CTASSERT(sizeof (psize) >= NN_NUMBUF_SZ);
- CTASSERT(sizeof (asize) >= NN_NUMBUF_SZ);
- CTASSERT(sizeof (avg) >= NN_NUMBUF_SZ);
- CTASSERT(sizeof (gang) >= NN_NUMBUF_SZ);
+ _Static_assert(sizeof (csize) >= NN_NUMBUF_SZ,
+ "csize truncated");
+ _Static_assert(sizeof (lsize) >= NN_NUMBUF_SZ,
+ "lsize truncated");
+ _Static_assert(sizeof (psize) >= NN_NUMBUF_SZ,
+ "psize truncated");
+ _Static_assert(sizeof (asize) >= NN_NUMBUF_SZ,
+ "asize truncated");
+ _Static_assert(sizeof (avg) >= NN_NUMBUF_SZ,
+ "avg truncated");
+ _Static_assert(sizeof (gang) >= NN_NUMBUF_SZ,
+ "gang truncated");
if (t < DMU_OT_NUMTYPES)
typename = dmu_ot[t].ot_name;
@@ -8644,7 +8654,7 @@ main(int argc, char **argv)
dump_opt[c] += verbose;
}
- libspl_assert_ok = (dump_opt['A'] == 1) || (dump_opt['A'] > 2);
+ libspl_set_assert_ok((dump_opt['A'] == 1) || (dump_opt['A'] > 2));
zfs_recover = (dump_opt['A'] > 1);
argc -= optind;
diff --git a/sys/contrib/openzfs/cmd/zdb/zdb_il.c b/sys/contrib/openzfs/cmd/zdb/zdb_il.c
index d6f588d8316e..76b1d64d76dc 100644
--- a/sys/contrib/openzfs/cmd/zdb/zdb_il.c
+++ b/sys/contrib/openzfs/cmd/zdb/zdb_il.c
@@ -266,6 +266,29 @@ zil_prt_rec_setattr(zilog_t *zilog, int txtype, const void *arg)
}
static void
+zil_prt_rec_setsaxattr(zilog_t *zilog, int txtype, const void *arg)
+{
+ (void) zilog, (void) txtype;
+ const lr_setsaxattr_t *lr = arg;
+
+ char *name = (char *)(lr + 1);
+ (void) printf("%sfoid %llu\n", tab_prefix,
+ (u_longlong_t)lr->lr_foid);
+
+ (void) printf("%sXAT_NAME %s\n", tab_prefix, name);
+ if (lr->lr_size == 0) {
+ (void) printf("%sXAT_VALUE NULL\n", tab_prefix);
+ } else {
+ (void) printf("%sXAT_VALUE ", tab_prefix);
+ char *val = name + (strlen(name) + 1);
+ for (int i = 0; i < lr->lr_size; i++) {
+ (void) printf("%c", *val);
+ val++;
+ }
+ }
+}
+
+static void
zil_prt_rec_acl(zilog_t *zilog, int txtype, const void *arg)
{
(void) zilog, (void) txtype;
@@ -304,6 +327,8 @@ static zil_rec_info_t zil_rec_info[TX_MAX_TYPE] = {
{.zri_print = zil_prt_rec_create, .zri_name = "TX_MKDIR_ATTR "},
{.zri_print = zil_prt_rec_create, .zri_name = "TX_MKDIR_ACL_ATTR "},
{.zri_print = zil_prt_rec_write, .zri_name = "TX_WRITE2 "},
+ {.zri_print = zil_prt_rec_setsaxattr,
+ .zri_name = "TX_SETSAXATTR "},
};
static int
diff --git a/sys/contrib/openzfs/cmd/zed/Makefile.am b/sys/contrib/openzfs/cmd/zed/Makefile.am
index 1492123e1696..7b662994d1c6 100644
--- a/sys/contrib/openzfs/cmd/zed/Makefile.am
+++ b/sys/contrib/openzfs/cmd/zed/Makefile.am
@@ -5,7 +5,6 @@ AM_CFLAGS += $(LIBUDEV_CFLAGS) $(LIBUUID_CFLAGS)
SUBDIRS = zed.d
SHELLCHECKDIRS = $(SUBDIRS)
-SHELLCHECK_OPTS = --enable=all
sbin_PROGRAMS = zed
diff --git a/sys/contrib/openzfs/cmd/zed/agents/zfs_mod.c b/sys/contrib/openzfs/cmd/zed/agents/zfs_mod.c
index c62a976c2e3f..59d8182c0b2e 100644
--- a/sys/contrib/openzfs/cmd/zed/agents/zfs_mod.c
+++ b/sys/contrib/openzfs/cmd/zed/agents/zfs_mod.c
@@ -183,14 +183,14 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
nvlist_t *nvroot, *newvd;
pendingdev_t *device;
uint64_t wholedisk = 0ULL;
- uint64_t offline = 0ULL;
+ uint64_t offline = 0ULL, faulted = 0ULL;
uint64_t guid = 0ULL;
char *physpath = NULL, *new_devid = NULL, *enc_sysfs_path = NULL;
char rawpath[PATH_MAX], fullpath[PATH_MAX];
char devpath[PATH_MAX];
int ret;
- boolean_t is_dm = B_FALSE;
boolean_t is_sd = B_FALSE;
+ boolean_t is_mpath_wholedisk = B_FALSE;
uint_t c;
vdev_stat_t *vs;
@@ -211,15 +211,73 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
&enc_sysfs_path);
(void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK, &wholedisk);
(void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_OFFLINE, &offline);
+ (void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_FAULTED, &faulted);
+
(void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_GUID, &guid);
- if (offline)
- return; /* don't intervene if it was taken offline */
+ /*
+ * Special case:
+ *
+ * We've seen times where a disk won't have a ZPOOL_CONFIG_PHYS_PATH
+ * entry in their config. For example, on this force-faulted disk:
+ *
+ * children[0]:
+ * type: 'disk'
+ * id: 0
+ * guid: 14309659774640089719
+ * path: '/dev/disk/by-vdev/L28'
+ * whole_disk: 0
+ * DTL: 654
+ * create_txg: 4
+ * com.delphix:vdev_zap_leaf: 1161
+ * faulted: 1
+ * aux_state: 'external'
+ * children[1]:
+ * type: 'disk'
+ * id: 1
+ * guid: 16002508084177980912
+ * path: '/dev/disk/by-vdev/L29'
+ * devid: 'dm-uuid-mpath-35000c500a61d68a3'
+ * phys_path: 'L29'
+ * vdev_enc_sysfs_path: '/sys/class/enclosure/0:0:1:0/SLOT 30 32'
+ * whole_disk: 0
+ * DTL: 1028
+ * create_txg: 4
+ * com.delphix:vdev_zap_leaf: 131
+ *
+ * If the disk's path is a /dev/disk/by-vdev/ path, then we can infer
+ * the ZPOOL_CONFIG_PHYS_PATH from the by-vdev disk name.
+ */
+ if (physpath == NULL && path != NULL) {
+ /* If path begins with "/dev/disk/by-vdev/" ... */
+ if (strncmp(path, DEV_BYVDEV_PATH,
+ strlen(DEV_BYVDEV_PATH)) == 0) {
+ /* Set physpath to the char after "/dev/disk/by-vdev" */
+ physpath = &path[strlen(DEV_BYVDEV_PATH)];
+ }
+ }
+
+ /*
+ * We don't want to autoreplace offlined disks. However, we do want to
+ * replace force-faulted disks (`zpool offline -f`). Force-faulted
+ * disks have both offline=1 and faulted=1 in the nvlist.
+ */
+ if (offline && !faulted) {
+ zed_log_msg(LOG_INFO, "%s: %s is offline, skip autoreplace",
+ __func__, path);
+ return;
+ }
- is_dm = zfs_dev_is_dm(path);
+ is_mpath_wholedisk = is_mpath_whole_disk(path);
zed_log_msg(LOG_INFO, "zfs_process_add: pool '%s' vdev '%s', phys '%s'"
- " wholedisk %d, %s dm (guid %llu)", zpool_get_name(zhp), path,
- physpath ? physpath : "NULL", wholedisk, is_dm ? "is" : "not",
+ " %s blank disk, %s mpath blank disk, %s labeled, enc sysfs '%s', "
+ "(guid %llu)",
+ zpool_get_name(zhp), path,
+ physpath ? physpath : "NULL",
+ wholedisk ? "is" : "not",
+ is_mpath_wholedisk? "is" : "not",
+ labeled ? "is" : "not",
+ enc_sysfs_path,
(long long unsigned int)guid);
/*
@@ -253,8 +311,9 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
ZFS_ONLINE_CHECKREMOVE | ZFS_ONLINE_UNSPARE, &newstate) == 0 &&
(newstate == VDEV_STATE_HEALTHY ||
newstate == VDEV_STATE_DEGRADED)) {
- zed_log_msg(LOG_INFO, " zpool_vdev_online: vdev %s is %s",
- fullpath, (newstate == VDEV_STATE_HEALTHY) ?
+ zed_log_msg(LOG_INFO,
+ " zpool_vdev_online: vdev '%s' ('%s') is "
+ "%s", fullpath, physpath, (newstate == VDEV_STATE_HEALTHY) ?
"HEALTHY" : "DEGRADED");
return;
}
@@ -271,11 +330,12 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
* vdev online to trigger a FMA fault by posting an ereport.
*/
if (!zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOREPLACE, NULL) ||
- !(wholedisk || is_dm) || (physpath == NULL)) {
+ !(wholedisk || is_mpath_wholedisk) || (physpath == NULL)) {
(void) zpool_vdev_online(zhp, fullpath, ZFS_ONLINE_FORCEFAULT,
&newstate);
zed_log_msg(LOG_INFO, "Pool's autoreplace is not enabled or "
- "not a whole disk for '%s'", fullpath);
+ "not a blank disk for '%s' ('%s')", fullpath,
+ physpath);
return;
}
@@ -287,7 +347,7 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
(void) snprintf(rawpath, sizeof (rawpath), "%s%s",
is_sd ? DEV_BYVDEV_PATH : DEV_BYPATH_PATH, physpath);
- if (realpath(rawpath, devpath) == NULL && !is_dm) {
+ if (realpath(rawpath, devpath) == NULL && !is_mpath_wholedisk) {
zed_log_msg(LOG_INFO, " realpath: %s failed (%s)",
rawpath, strerror(errno));
@@ -303,12 +363,14 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
if ((vs->vs_state != VDEV_STATE_DEGRADED) &&
(vs->vs_state != VDEV_STATE_FAULTED) &&
(vs->vs_state != VDEV_STATE_CANT_OPEN)) {
+ zed_log_msg(LOG_INFO, " not autoreplacing since disk isn't in "
+ "a bad state (currently %d)", vs->vs_state);
return;
}
nvlist_lookup_string(vdev, "new_devid", &new_devid);
- if (is_dm) {
+ if (is_mpath_wholedisk) {
/* Don't label device mapper or multipath disks. */
} else if (!labeled) {
/*
@@ -522,8 +584,11 @@ zfs_iter_vdev(zpool_handle_t *zhp, nvlist_t *nvl, void *data)
* the dp->dd_compare value.
*/
if (nvlist_lookup_string(nvl, dp->dd_prop, &path) != 0 ||
- strcmp(dp->dd_compare, path) != 0)
+ strcmp(dp->dd_compare, path) != 0) {
+ zed_log_msg(LOG_INFO, " %s: no match (%s != vdev %s)",
+ __func__, dp->dd_compare, path);
return;
+ }
zed_log_msg(LOG_INFO, " zfs_iter_vdev: matched %s on %s",
dp->dd_prop, path);
@@ -571,6 +636,8 @@ zfs_iter_pool(zpool_handle_t *zhp, void *data)
ZPOOL_CONFIG_VDEV_TREE, &nvl);
zfs_iter_vdev(zhp, nvl, data);
}
+ } else {
+ zed_log_msg(LOG_INFO, "%s: no config\n", __func__);
}
/*
@@ -620,6 +687,72 @@ devphys_iter(const char *physical, const char *devid, zfs_process_func_t func,
}
/*
+ * Given a device identifier, find any vdevs with a matching by-vdev
+ * path. Normally we shouldn't need this as the comparison would be
+ * made earlier in the devphys_iter(). For example, if we were replacing
+ * /dev/disk/by-vdev/L28, normally devphys_iter() would match the
+ * ZPOOL_CONFIG_PHYS_PATH of "L28" from the old disk config to "L28"
+ * of the new disk config. However, we've seen cases where
+ * ZPOOL_CONFIG_PHYS_PATH was not in the config for the old disk. Here's
+ * an example of a real 2-disk mirror pool where one disk was force
+ * faulted:
+ *
+ * com.delphix:vdev_zap_top: 129
+ * children[0]:
+ * type: 'disk'
+ * id: 0
+ * guid: 14309659774640089719
+ * path: '/dev/disk/by-vdev/L28'
+ * whole_disk: 0
+ * DTL: 654
+ * create_txg: 4
+ * com.delphix:vdev_zap_leaf: 1161
+ * faulted: 1
+ * aux_state: 'external'
+ * children[1]:
+ * type: 'disk'
+ * id: 1
+ * guid: 16002508084177980912
+ * path: '/dev/disk/by-vdev/L29'
+ * devid: 'dm-uuid-mpath-35000c500a61d68a3'
+ * phys_path: 'L29'
+ * vdev_enc_sysfs_path: '/sys/class/enclosure/0:0:1:0/SLOT 30 32'
+ * whole_disk: 0
+ * DTL: 1028
+ * create_txg: 4
+ * com.delphix:vdev_zap_leaf: 131
+ *
+ * So in the case above, the only thing we could compare is the path.
+ *
+ * We can do this because we assume by-vdev paths are authoritative as physical
+ * paths. We could not assume this for normal paths like /dev/sda since the
+ * physical location /dev/sda points to could change over time.
+ */
+static boolean_t
+by_vdev_path_iter(const char *by_vdev_path, const char *devid,
+ zfs_process_func_t func, boolean_t is_slice)
+{
+ dev_data_t data = { 0 };
+
+ data.dd_compare = by_vdev_path;
+ data.dd_func = func;
+ data.dd_prop = ZPOOL_CONFIG_PATH;
+ data.dd_found = B_FALSE;
+ data.dd_islabeled = is_slice;
+ data.dd_new_devid = devid;
+
+ if (strncmp(by_vdev_path, DEV_BYVDEV_PATH,
+ strlen(DEV_BYVDEV_PATH)) != 0) {
+ /* by_vdev_path doesn't start with "/dev/disk/by-vdev/" */
+ return (B_FALSE);
+ }
+
+ (void) zpool_iter(g_zfshdl, zfs_iter_pool, &data);
+
+ return (data.dd_found);
+}
+
+/*
* Given a device identifier, find any vdevs with a matching devid.
* On Linux we can match devid directly which is always a whole disk.
*/
@@ -683,15 +816,17 @@ guid_iter(uint64_t pool_guid, uint64_t vdev_guid, const char *devid,
static int
zfs_deliver_add(nvlist_t *nvl)
{
- char *devpath = NULL, *devid;
+ char *devpath = NULL, *devid = NULL;
uint64_t pool_guid = 0, vdev_guid = 0;
boolean_t is_slice;
/*
* Expecting a devid string and an optional physical location and guid
*/
- if (nvlist_lookup_string(nvl, DEV_IDENTIFIER, &devid) != 0)
+ if (nvlist_lookup_string(nvl, DEV_IDENTIFIER, &devid) != 0) {
+ zed_log_msg(LOG_INFO, "%s: no dev identifier\n", __func__);
return (-1);
+ }
(void) nvlist_lookup_string(nvl, DEV_PHYS_PATH, &devpath);
(void) nvlist_lookup_uint64(nvl, ZFS_EV_POOL_GUID, &pool_guid);
@@ -707,6 +842,8 @@ zfs_deliver_add(nvlist_t *nvl)
* 1. ZPOOL_CONFIG_DEVID (identifies the unique disk)
* 2. ZPOOL_CONFIG_PHYS_PATH (identifies disk physical location).
* 3. ZPOOL_CONFIG_GUID (identifies unique vdev).
+ * 4. ZPOOL_CONFIG_PATH for /dev/disk/by-vdev devices only (since
+ * by-vdev paths represent physical paths).
*/
if (devid_iter(devid, zfs_process_add, is_slice))
return (0);
@@ -717,6 +854,16 @@ zfs_deliver_add(nvlist_t *nvl)
(void) guid_iter(pool_guid, vdev_guid, devid, zfs_process_add,
is_slice);
+ if (devpath != NULL) {
+ /* Can we match a /dev/disk/by-vdev/ path? */
+ char by_vdev_path[MAXPATHLEN];
+ snprintf(by_vdev_path, sizeof (by_vdev_path),
+ "/dev/disk/by-vdev/%s", devpath);
+ if (by_vdev_path_iter(by_vdev_path, devid, zfs_process_add,
+ is_slice))
+ return (0);
+ }
+
return (0);
}
diff --git a/sys/contrib/openzfs/cmd/zed/zed.d/Makefile.am b/sys/contrib/openzfs/cmd/zed/zed.d/Makefile.am
index 24efaa74f154..3c0f5c3dd1b2 100644
--- a/sys/contrib/openzfs/cmd/zed/zed.d/Makefile.am
+++ b/sys/contrib/openzfs/cmd/zed/zed.d/Makefile.am
@@ -11,8 +11,7 @@ dist_zedconf_DATA = \
zed.rc
SHELLCHECKSCRIPTS = zed-functions.sh zed.rc
-SHELLCHECK_OPTS = --enable=all
-SHELLCHECK_SHELL = dash
+SHELLCHECK_SHELL = sh
zedexecdir = $(zfsexecdir)/zed.d
diff --git a/sys/contrib/openzfs/cmd/zed/zed.d/zed-functions.sh b/sys/contrib/openzfs/cmd/zed/zed.d/zed-functions.sh
index bbff9c008bd1..e6d3ce9ecc49 100644
--- a/sys/contrib/openzfs/cmd/zed/zed.d/zed-functions.sh
+++ b/sys/contrib/openzfs/cmd/zed/zed.d/zed-functions.sh
@@ -417,7 +417,7 @@ zed_notify_slack_webhook()
# Construct the JSON message for posting.
#
- msg_json="$(printf '{"text": "*%s*\n%s"}' "${subject}" "${msg_body}" )"
+ msg_json="$(printf '{"text": "*%s*\\n%s"}' "${subject}" "${msg_body}" )"
# Send the POST request and check for errors.
#
diff --git a/sys/contrib/openzfs/cmd/zed/zed_disk_event.c b/sys/contrib/openzfs/cmd/zed/zed_disk_event.c
index 94e24236063c..52b80d8c4c93 100644
--- a/sys/contrib/openzfs/cmd/zed/zed_disk_event.c
+++ b/sys/contrib/openzfs/cmd/zed/zed_disk_event.c
@@ -215,6 +215,11 @@ zed_udev_monitor(void *arg)
if (type != NULL && type[0] != '\0' &&
strcmp(type, "disk") == 0 &&
part != NULL && part[0] != '\0') {
+ zed_log_msg(LOG_INFO,
+ "%s: skip %s since it has a %s partition already",
+ __func__,
+ udev_device_get_property_value(dev, "DEVNAME"),
+ part);
/* skip and wait for partition event */
udev_device_unref(dev);
continue;
@@ -229,6 +234,11 @@ zed_udev_monitor(void *arg)
sectors = udev_device_get_sysattr_value(dev, "size");
if (sectors != NULL &&
strtoull(sectors, NULL, 10) < MINIMUM_SECTORS) {
+ zed_log_msg(LOG_INFO,
+ "%s: %s sectors %s < %llu (minimum)",
+ __func__,
+ udev_device_get_property_value(dev, "DEVNAME"),
+ sectors, MINIMUM_SECTORS);
udev_device_unref(dev);
continue;
}
diff --git a/sys/contrib/openzfs/cmd/zfs/zfs_iter.c b/sys/contrib/openzfs/cmd/zfs/zfs_iter.c
index 69b802f77a78..8b6a49a79290 100644
--- a/sys/contrib/openzfs/cmd/zfs/zfs_iter.c
+++ b/sys/contrib/openzfs/cmd/zfs/zfs_iter.c
@@ -453,23 +453,21 @@ zfs_for_each(int argc, char **argv, int flags, zfs_type_t types,
cb.cb_flags |= ZFS_ITER_RECURSE;
ret = zfs_iter_root(g_zfs, zfs_callback, &cb);
} else {
- int i;
- zfs_handle_t *zhp;
- zfs_type_t argtype;
+ zfs_handle_t *zhp = NULL;
+ zfs_type_t argtype = types;
/*
* If we're recursive, then we always allow filesystems as
* arguments. If we also are interested in snapshots or
* bookmarks, then we can take volumes as well.
*/
- argtype = types;
if (flags & ZFS_ITER_RECURSE) {
argtype |= ZFS_TYPE_FILESYSTEM;
if (types & (ZFS_TYPE_SNAPSHOT | ZFS_TYPE_BOOKMARK))
argtype |= ZFS_TYPE_VOLUME;
}
- for (i = 0; i < argc; i++) {
+ for (int i = 0; i < argc; i++) {
if (flags & ZFS_ITER_ARGS_CAN_BE_PATHS) {
zhp = zfs_path_to_zhandle(g_zfs, argv[i],
argtype);
diff --git a/sys/contrib/openzfs/cmd/zfs/zfs_main.c b/sys/contrib/openzfs/cmd/zfs/zfs_main.c
index 5aa2508c382f..42e4d6f7e195 100644
--- a/sys/contrib/openzfs/cmd/zfs/zfs_main.c
+++ b/sys/contrib/openzfs/cmd/zfs/zfs_main.c
@@ -575,8 +575,9 @@ usage(boolean_t requested)
(void) fprintf(fp, gettext("\nSizes are specified in bytes "
"with standard units such as K, M, G, etc.\n"));
- (void) fprintf(fp, gettext("\nUser-defined properties can "
- "be specified by using a name containing a colon (:).\n"));
+ (void) fprintf(fp, "%s", gettext("\nUser-defined properties "
+ "can be specified by using a name containing a colon "
+ "(:).\n"));
(void) fprintf(fp, gettext("\nThe {user|group|project}"
"[obj]{used|quota}@ properties must be appended with\n"
"a user|group|project specifier of one of these forms:\n"
@@ -727,32 +728,6 @@ finish_progress(char *done)
pt_header = NULL;
}
-/* This function checks if the passed fd refers to /dev/null or /dev/zero */
-#ifdef __linux__
-static boolean_t
-is_dev_nullzero(int fd)
-{
- struct stat st;
- fstat(fd, &st);
- return (major(st.st_rdev) == 1 && (minor(st.st_rdev) == 3 /* null */ ||
- minor(st.st_rdev) == 5 /* zero */));
-}
-#endif
-
-static void
-note_dev_error(int err, int fd)
-{
-#ifdef __linux__
- if (err == EINVAL && is_dev_nullzero(fd)) {
- (void) fprintf(stderr,
- gettext("Error: Writing directly to /dev/{null,zero} files"
- " on certain kernels is not currently implemented.\n"
- "(As a workaround, "
- "try \"zfs send [...] | cat > /dev/null\")\n"));
- }
-#endif
-}
-
static int
zfs_mount_and_share(libzfs_handle_t *hdl, const char *dataset, zfs_type_t type)
{
@@ -4594,16 +4569,11 @@ zfs_do_send(int argc, char **argv)
err = zfs_send_saved(zhp, &flags, STDOUT_FILENO,
resume_token);
- if (err != 0)
- note_dev_error(errno, STDOUT_FILENO);
zfs_close(zhp);
return (err != 0);
} else if (resume_token != NULL) {
- err = zfs_send_resume(g_zfs, &flags, STDOUT_FILENO,
- resume_token);
- if (err != 0)
- note_dev_error(errno, STDOUT_FILENO);
- return (err);
+ return (zfs_send_resume(g_zfs, &flags, STDOUT_FILENO,
+ resume_token));
}
if (flags.skipmissing && !flags.replicate) {
@@ -4654,8 +4624,6 @@ zfs_do_send(int argc, char **argv)
err = zfs_send_one(zhp, fromname, STDOUT_FILENO, &flags,
redactbook);
zfs_close(zhp);
- if (err != 0)
- note_dev_error(errno, STDOUT_FILENO);
return (err != 0);
}
@@ -4732,7 +4700,6 @@ zfs_do_send(int argc, char **argv)
nvlist_free(dbgnv);
}
zfs_close(zhp);
- note_dev_error(errno, STDOUT_FILENO);
return (err != 0);
}
diff --git a/sys/contrib/openzfs/cmd/zgenhostid/zgenhostid.c b/sys/contrib/openzfs/cmd/zgenhostid/zgenhostid.c
index 853931c6ad6e..6c8f7c6127a1 100644
--- a/sys/contrib/openzfs/cmd/zgenhostid/zgenhostid.c
+++ b/sys/contrib/openzfs/cmd/zgenhostid/zgenhostid.c
@@ -36,7 +36,7 @@
#include <time.h>
#include <unistd.h>
-static __attribute__((noreturn)) void
+static _Noreturn void
usage(void)
{
(void) fprintf(stderr,
diff --git a/sys/contrib/openzfs/cmd/zhack/zhack.c b/sys/contrib/openzfs/cmd/zhack/zhack.c
index 73ce888c0b1d..92d20d753aed 100644
--- a/sys/contrib/openzfs/cmd/zhack/zhack.c
+++ b/sys/contrib/openzfs/cmd/zhack/zhack.c
@@ -57,7 +57,7 @@ static importargs_t g_importargs;
static char *g_pool;
static boolean_t g_readonly;
-static __attribute__((noreturn)) void
+static _Noreturn void
usage(void)
{
(void) fprintf(stderr,
@@ -87,7 +87,7 @@ usage(void)
}
-static __attribute__((noreturn)) __attribute__((format(printf, 3, 4))) void
+static __attribute__((format(printf, 3, 4))) _Noreturn void
fatal(spa_t *spa, void *tag, const char *fmt, ...)
{
va_list ap;
diff --git a/sys/contrib/openzfs/cmd/zpool/Makefile.am b/sys/contrib/openzfs/cmd/zpool/Makefile.am
index b89b5db85800..7ea7c5fc3f3e 100644
--- a/sys/contrib/openzfs/cmd/zpool/Makefile.am
+++ b/sys/contrib/openzfs/cmd/zpool/Makefile.am
@@ -5,7 +5,6 @@ AM_CFLAGS += $(LIBBLKID_CFLAGS) $(LIBUUID_CFLAGS)
DEFAULT_INCLUDES += -I$(srcdir)
-SHELLCHECK_OPTS = --enable=all
sbin_PROGRAMS = zpool
diff --git a/sys/contrib/openzfs/cmd/zpool/zpool_main.c b/sys/contrib/openzfs/cmd/zpool/zpool_main.c
index d7cce73d3dff..717d8b806d79 100644
--- a/sys/contrib/openzfs/cmd/zpool/zpool_main.c
+++ b/sys/contrib/openzfs/cmd/zpool/zpool_main.c
@@ -1760,17 +1760,19 @@ zpool_do_create(int argc, char **argv)
"feature@%s", feat->fi_uname);
if (!nvlist_lookup_string(props, propname, &propval)) {
- if (strcmp(propval, ZFS_FEATURE_DISABLED) == 0)
+ if (strcmp(propval,
+ ZFS_FEATURE_DISABLED) == 0) {
(void) nvlist_remove_all(props,
propname);
- if (strcmp(propval,
+ } else if (strcmp(propval,
ZFS_FEATURE_ENABLED) == 0 &&
- !requested_features[i])
+ !requested_features[i]) {
(void) fprintf(stderr, gettext(
"Warning: feature \"%s\" enabled "
"but is not in specified "
"'compatibility' feature set.\n"),
feat->fi_uname);
+ }
} else if (
enable_pool_features &&
feat->fi_zfs_mod_supported &&
@@ -3039,9 +3041,8 @@ show_import(nvlist_t *config, boolean_t report_error)
ZPOOL_CONFIG_MMP_HOSTID);
(void) printf(gettext(" action: The pool must be "
- "exported from %s (hostid=%lx)\n\tbefore it "
- "can be safely imported.\n"), hostname,
- (unsigned long) hostid);
+ "exported from %s (hostid=%"PRIx64")\n\tbefore it "
+ "can be safely imported.\n"), hostname, hostid);
break;
case ZPOOL_STATUS_HOSTID_REQUIRED:
(void) printf(gettext(" action: Set a unique system "
@@ -3136,7 +3137,7 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts,
{
int ret = 0;
zpool_handle_t *zhp;
- char *name;
+ const char *name;
uint64_t version;
name = fnvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME);
@@ -3157,7 +3158,7 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts,
ZPOOL_CONFIG_MMP_STATE);
if (mmp_state == MMP_STATE_ACTIVE) {
- char *hostname = "<unknown>";
+ const char *hostname = "<unknown>";
uint64_t hostid = 0;
if (nvlist_exists(nvinfo, ZPOOL_CONFIG_MMP_HOSTNAME))
@@ -3170,17 +3171,17 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts,
(void) fprintf(stderr, gettext("cannot import '%s': "
"pool is imported on %s (hostid: "
- "0x%lx)\nExport the pool on the other system, "
- "then run 'zpool import'.\n"),
- name, hostname, (unsigned long) hostid);
+ "0x%"PRIx64")\nExport the pool on the other "
+ "system, then run 'zpool import'.\n"),
+ name, hostname, hostid);
} else if (mmp_state == MMP_STATE_NO_HOSTID) {
(void) fprintf(stderr, gettext("Cannot import '%s': "
"pool has the multihost property on and the\n"
"system's hostid is not set. Set a unique hostid "
"with the zgenhostid(8) command.\n"), name);
} else {
- char *hostname = "<unknown>";
- uint64_t timestamp = 0;
+ const char *hostname = "<unknown>";
+ time_t timestamp = 0;
uint64_t hostid = 0;
if (nvlist_exists(config, ZPOOL_CONFIG_HOSTNAME))
@@ -3197,10 +3198,10 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts,
(void) fprintf(stderr, gettext("cannot import '%s': "
"pool was previously in use from another system.\n"
- "Last accessed by %s (hostid=%lx) at %s"
+ "Last accessed by %s (hostid=%"PRIx64") at %s"
"The pool can be imported, use 'zpool import -f' "
"to import the pool.\n"), name, hostname,
- (unsigned long)hostid, ctime((time_t *)&timestamp));
+ hostid, ctime(&timestamp));
}
return (1);
@@ -3210,7 +3211,7 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts,
return (1);
if (newname != NULL)
- name = (char *)newname;
+ name = newname;
if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL)
return (1);
@@ -3219,11 +3220,9 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts,
* Loading keys is best effort. We don't want to return immediately
* if it fails but we do want to give the error to the caller.
*/
- if (flags & ZFS_IMPORT_LOAD_KEYS) {
- ret = zfs_crypto_attempt_load_keys(g_zfs, name);
- if (ret != 0)
+ if (flags & ZFS_IMPORT_LOAD_KEYS &&
+ zfs_crypto_attempt_load_keys(g_zfs, name) != 0)
ret = 1;
- }
if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
!(flags & ZFS_IMPORT_ONLY) &&
@@ -3273,7 +3272,7 @@ import_pools(nvlist_t *pools, nvlist_t *props, char *mntopts, int flags,
if (first)
first = B_FALSE;
else if (!do_all)
- (void) printf("\n");
+ (void) putchar('\n');
if (do_all) {
err |= do_import(config, NULL, mntopts,
@@ -3724,9 +3723,8 @@ zpool_do_import(int argc, char **argv)
if (argc == 0 && geteuid() != 0) {
(void) fprintf(stderr, gettext("cannot "
"discover pools: permission denied\n"));
- if (searchdirs != NULL)
- free(searchdirs);
+ free(searchdirs);
nvlist_free(props);
nvlist_free(policy);
return (1);
@@ -4690,7 +4688,7 @@ print_iostat_default(vdev_stat_t *vs, iostat_cbdata_t *cb, double scale)
format, column_width, cb->cb_scripted);
}
-static const char *class_name[] = {
+static const char *const class_name[] = {
VDEV_ALLOC_BIAS_DEDUP,
VDEV_ALLOC_BIAS_SPECIAL,
VDEV_ALLOC_CLASS_LOGS
@@ -4850,7 +4848,7 @@ children:
continue;
vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
- cb->cb_vdevs.cb_name_flags);
+ cb->cb_vdevs.cb_name_flags | VDEV_NAME_TYPE_ID);
ret += print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
newchild[c], cb, depth + 2);
free(vname);
@@ -4859,7 +4857,7 @@ children:
/*
* print all other top-level devices
*/
- for (uint_t n = 0; n < 3; n++) {
+ for (uint_t n = 0; n < ARRAY_SIZE(class_name); n++) {
boolean_t printed = B_FALSE;
for (c = 0; c < children; c++) {
@@ -4894,7 +4892,7 @@ children:
}
vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
- cb->cb_vdevs.cb_name_flags);
+ cb->cb_vdevs.cb_name_flags | VDEV_NAME_TYPE_ID);
ret += print_vdev_stats(zhp, vname, oldnv ?
oldchild[c] : NULL, newchild[c], cb, depth + 2);
free(vname);
@@ -5024,7 +5022,7 @@ get_namewidth(zpool_handle_t *zhp, int min_width, int flags, boolean_t verbose)
if ((config = zpool_get_config(zhp, NULL)) != NULL) {
verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
&nvroot) == 0);
- unsigned int poolname_len = strlen(zpool_get_name(zhp));
+ size_t poolname_len = strlen(zpool_get_name(zhp));
if (verbose == B_FALSE) {
width = MAX(poolname_len, min_width);
} else {
@@ -5963,7 +5961,7 @@ print_header(list_cbdata_t *cb)
}
if (!first)
- (void) printf(" ");
+ (void) fputs(" ", stdout);
else
first = B_FALSE;
@@ -5981,14 +5979,14 @@ print_header(list_cbdata_t *cb)
}
if (pl->pl_next == NULL && !right_justify)
- (void) printf("%s", header);
+ (void) fputs(header, stdout);
else if (right_justify)
(void) printf("%*s", (int)width, header);
else
(void) printf("%-*s", (int)width, header);
}
- (void) printf("\n");
+ (void) fputc('\n', stdout);
}
/*
@@ -6018,9 +6016,9 @@ print_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
if (!first) {
if (cb->cb_scripted)
- (void) printf("\t");
+ (void) fputc('\t', stdout);
else
- (void) printf(" ");
+ (void) fputs(" ", stdout);
} else {
first = B_FALSE;
}
@@ -6050,14 +6048,14 @@ print_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
* format specifier.
*/
if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify))
- (void) printf("%s", propstr);
+ (void) fputs(propstr, stdout);
else if (right_justify)
(void) printf("%*s", (int)width, propstr);
else
(void) printf("%-*s", (int)width, propstr);
}
- (void) printf("\n");
+ (void) fputc('\n', stdout);
}
static void
@@ -6130,8 +6128,8 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
char *vname;
boolean_t scripted = cb->cb_scripted;
uint64_t islog = B_FALSE;
- char *dashes = "%-*s - - - - "
- "- - - - -\n";
+ const char *dashes = "%-*s - - - - "
+ "- - - - -\n";
verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
(uint64_t **)&vs, &c) == 0);
@@ -6193,7 +6191,7 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
}
print_one_column(ZPOOL_PROP_HEALTH, 0, state, scripted,
B_TRUE, format);
- (void) printf("\n");
+ (void) fputc('\n', stdout);
}
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
@@ -6216,13 +6214,13 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
continue;
vname = zpool_vdev_name(g_zfs, zhp, child[c],
- cb->cb_name_flags);
+ cb->cb_name_flags | VDEV_NAME_TYPE_ID);
print_list_stats(zhp, vname, child[c], cb, depth + 2, B_FALSE);
free(vname);
}
/* list the classes: 'logs', 'dedup', and 'special' */
- for (uint_t n = 0; n < 3; n++) {
+ for (uint_t n = 0; n < ARRAY_SIZE(class_name); n++) {
boolean_t printed = B_FALSE;
for (c = 0; c < children; c++) {
@@ -6250,7 +6248,7 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
printed = B_TRUE;
}
vname = zpool_vdev_name(g_zfs, zhp, child[c],
- cb->cb_name_flags);
+ cb->cb_name_flags | VDEV_NAME_TYPE_ID);
print_list_stats(zhp, vname, child[c], cb, depth + 2,
B_FALSE);
free(vname);
@@ -9214,7 +9212,7 @@ zpool_do_upgrade(int argc, char **argv)
}
}
- (void) printf(gettext("This system supports ZFS pool feature "
+ (void) printf("%s", gettext("This system supports ZFS pool feature "
"flags.\n\n"));
if (showversions) {
int i;
diff --git a/sys/contrib/openzfs/cmd/zpool_influxdb/zpool_influxdb.c b/sys/contrib/openzfs/cmd/zpool_influxdb/zpool_influxdb.c
index f326b0420ee8..57bb2ee7bf0c 100644
--- a/sys/contrib/openzfs/cmd/zpool_influxdb/zpool_influxdb.c
+++ b/sys/contrib/openzfs/cmd/zpool_influxdb/zpool_influxdb.c
@@ -118,7 +118,7 @@ escape_string(const char *s)
case '=':
case '\\':
*d++ = '\\';
- fallthrough;
+ zfs_fallthrough;
default:
*d = *c;
}
@@ -278,7 +278,7 @@ get_vdev_name(nvlist_t *nvroot, const char *parent_name)
vdev_type);
} else {
(void) snprintf(vdev_name, sizeof (vdev_name),
- "%s/%s-%llu",
+ "%.220s/%s-%llu",
parent_name, vdev_type, (u_longlong_t)vdev_id);
}
return (vdev_name);
@@ -818,7 +818,7 @@ main(int argc, char *argv[])
break;
case 't':
tagslen = strlen(optarg) + 2;
- tags = calloc(tagslen, 1);
+ tags = calloc(1, tagslen);
if (tags == NULL) {
fprintf(stderr,
"error: cannot allocate memory "
diff --git a/sys/contrib/openzfs/cmd/zstream/zstream_dump.c b/sys/contrib/openzfs/cmd/zstream/zstream_dump.c
index 45cf7b97a147..04a4986b45d8 100644
--- a/sys/contrib/openzfs/cmd/zstream/zstream_dump.c
+++ b/sys/contrib/openzfs/cmd/zstream/zstream_dump.c
@@ -297,6 +297,7 @@ zstream_do_dump(int argc, char *argv[])
fletcher_4_init();
while (read_hdr(drr, &zc)) {
+ uint64_t featureflags = 0;
/*
* If this is the first DMU record being processed, check for
@@ -362,6 +363,9 @@ zstream_do_dump(int argc, char *argv[])
BSWAP_64(drrb->drr_fromguid);
}
+ featureflags =
+ DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo);
+
(void) printf("BEGIN record\n");
(void) printf("\thdrtype = %lld\n",
DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo));
@@ -461,6 +465,15 @@ zstream_do_dump(int argc, char *argv[])
BSWAP_64(drro->drr_maxblkid);
}
+ if (featureflags & DMU_BACKUP_FEATURE_RAW &&
+ drro->drr_bonuslen > drro->drr_raw_bonuslen) {
+ (void) fprintf(stderr,
+ "Warning: Object %llu has bonuslen = "
+ "%u > raw_bonuslen = %u\n\n",
+ (u_longlong_t)drro->drr_object,
+ drro->drr_bonuslen, drro->drr_raw_bonuslen);
+ }
+
payload_size = DRR_OBJECT_PAYLOAD_SIZE(drro);
if (verbose) {
diff --git a/sys/contrib/openzfs/cmd/ztest/ztest.c b/sys/contrib/openzfs/cmd/ztest/ztest.c
index bb2f14298279..292493584bf7 100644
--- a/sys/contrib/openzfs/cmd/ztest/ztest.c
+++ b/sys/contrib/openzfs/cmd/ztest/ztest.c
@@ -558,7 +558,7 @@ enum ztest_object {
ZTEST_OBJECTS
};
-static void usage(boolean_t) __NORETURN;
+static _Noreturn void usage(boolean_t);
static int ztest_scrub_impl(spa_t *spa);
/*
@@ -622,7 +622,7 @@ static void sig_handler(int signo)
char *fatal_msg;
-static __attribute__((noreturn)) __attribute__((format(printf, 2, 3))) void
+static __attribute__((format(printf, 2, 3))) _Noreturn void
fatal(int do_perror, char *message, ...)
{
va_list args;
@@ -631,6 +631,8 @@ fatal(int do_perror, char *message, ...)
(void) fflush(stdout);
buf = umem_alloc(FATAL_MSG_SZ, UMEM_NOFAIL);
+ if (buf == NULL)
+ goto out;
va_start(args, message);
(void) sprintf(buf, "ztest: ");
@@ -644,6 +646,7 @@ fatal(int do_perror, char *message, ...)
(void) fprintf(stderr, "%s\n", buf);
fatal_msg = buf; /* to ease debugging */
+out:
if (ztest_dump_core)
abort();
else
@@ -2383,6 +2386,7 @@ zil_replay_func_t *ztest_replay_vector[TX_MAX_TYPE] = {
NULL, /* TX_MKDIR_ATTR */
NULL, /* TX_MKDIR_ACL_ATTR */
NULL, /* TX_WRITE2 */
+ NULL, /* TX_SETSAXATTR */
};
/*
@@ -4269,7 +4273,15 @@ ztest_objset_destroy_cb(const char *name, void *arg)
* Destroy the dataset.
*/
if (strchr(name, '@') != NULL) {
- VERIFY0(dsl_destroy_snapshot(name, B_TRUE));
+ error = dsl_destroy_snapshot(name, B_TRUE);
+ if (error != ECHRNG) {
+ /*
+ * The program was executed, but encountered a runtime
+ * error, such as insufficient slop, or a hold on the
+ * dataset.
+ */
+ ASSERT0(error);
+ }
} else {
error = dsl_destroy_head(name);
if (error == ENOSPC) {
@@ -6981,7 +6993,7 @@ ztest_resume(spa_t *spa)
(void) zio_resume(spa);
}
-static void
+static _Noreturn void
ztest_resume_thread(void *arg)
{
spa_t *spa = arg;
@@ -7007,7 +7019,7 @@ ztest_resume_thread(void *arg)
thread_exit();
}
-static void
+static _Noreturn void
ztest_deadman_thread(void *arg)
{
ztest_shared_t *zs = arg;
@@ -7085,7 +7097,7 @@ ztest_execute(int test, ztest_info_t *zi, uint64_t id)
(double)functime / NANOSEC, zi->zi_funcname);
}
-static void
+static _Noreturn void
ztest_thread(void *arg)
{
int rand;
diff --git a/sys/contrib/openzfs/cmd/zvol_id/zvol_id_main.c b/sys/contrib/openzfs/cmd/zvol_id/zvol_id_main.c
index 22f2e848cba1..929a1a6e794d 100644
--- a/sys/contrib/openzfs/cmd/zvol_id/zvol_id_main.c
+++ b/sys/contrib/openzfs/cmd/zvol_id/zvol_id_main.c
@@ -35,6 +35,21 @@
#include <sys/zfs_znode.h>
#include <sys/fs/zfs.h>
+#if defined(ZFS_ASAN_ENABLED)
+/*
+ * zvol_id is invoked by udev with the help of ptrace()
+ * making sanitized binary with leak detection croak
+ * because of tracing mechanisms collision
+ */
+extern const char *__asan_default_options(void);
+
+const char *__asan_default_options(void) {
+ return ("abort_on_error=true:halt_on_error=true:"
+ "allocator_may_return_null=true:disable_coredump=false:"
+ "detect_stack_use_after_return=true:detect_leaks=false");
+}
+#endif
+
static int
ioctl_get_msg(char *var, int fd)
{
diff --git a/sys/contrib/openzfs/cmd/zvol_wait/Makefile.am b/sys/contrib/openzfs/cmd/zvol_wait/Makefile.am
index ee66d51de96f..e8b546a60659 100644
--- a/sys/contrib/openzfs/cmd/zvol_wait/Makefile.am
+++ b/sys/contrib/openzfs/cmd/zvol_wait/Makefile.am
@@ -2,4 +2,3 @@ include $(top_srcdir)/config/Shellcheck.am
dist_bin_SCRIPTS = zvol_wait
-SHELLCHECK_OPTS = --enable=all
diff --git a/sys/contrib/openzfs/config/Abigail.am b/sys/contrib/openzfs/config/Abigail.am
index 94687b90eef2..d1038f093373 100644
--- a/sys/contrib/openzfs/config/Abigail.am
+++ b/sys/contrib/openzfs/config/Abigail.am
@@ -12,9 +12,24 @@
# a mechanism for suppressing harmless warnings.
#
-PHONY += checkabi storeabi
+PHONY += checkabi storeabi check_libabi_version allow_libabi_only_for_x86_64
-checkabi:
+check_libabi_version:
+ libabiversion=`abidw -v | $(SED) 's/[^0-9]//g'`; \
+ if test $$libabiversion -lt "200"; then \
+ /bin/echo -e "\n" \
+ "*** Please use libabigail 2.0.0 version or newer;\n" \
+ "*** otherwise results are not consistent!\n" \
+ "(or see https://github.com/openzfs/libabigail-docker )\n"; \
+ exit 1; \
+ fi;
+
+allow_libabi_only_for_x86_64:
+ echo '*** ABI definitions provided apply only to x86_64 architecture'
+ echo '*** Skipping `checkabi`/`storeabi` target and assuming success.'
+
+if TARGET_CPU_X86_64
+checkabi: check_libabi_version
for lib in $(lib_LTLIBRARIES) ; do \
abidiff --no-unreferenced-symbols \
--headers-dir1 ../../include \
@@ -22,7 +37,7 @@ checkabi:
$${lib%.la}.abi .libs/$${lib%.la}.so ; \
done
-storeabi:
+storeabi: check_libabi_version
cd .libs ; \
for lib in $(lib_LTLIBRARIES) ; do \
abidw --no-show-locs \
@@ -31,3 +46,7 @@ storeabi:
--type-id-style hash \
$${lib%.la}.so > ../$${lib%.la}.abi ; \
done
+else
+checkabi: allow_libabi_only_for_x86_64
+storeabi: allow_libabi_only_for_x86_64
+endif
diff --git a/sys/contrib/openzfs/config/Rules.am b/sys/contrib/openzfs/config/Rules.am
index 20779ba49259..cbef12e2136d 100644
--- a/sys/contrib/openzfs/config/Rules.am
+++ b/sys/contrib/openzfs/config/Rules.am
@@ -23,12 +23,13 @@ endif
AM_LIBTOOLFLAGS = --silent
-AM_CFLAGS = -std=gnu99 -Wall -Wstrict-prototypes -Wmissing-prototypes
+AM_CFLAGS = -std=gnu99 -Wall -Wextra -Wstrict-prototypes -Wmissing-prototypes -Wno-sign-compare -Wno-missing-field-initializers
AM_CFLAGS += -fno-strict-aliasing
AM_CFLAGS += $(NO_OMIT_FRAME_POINTER)
AM_CFLAGS += $(IMPLICIT_FALLTHROUGH)
AM_CFLAGS += $(DEBUG_CFLAGS)
AM_CFLAGS += $(ASAN_CFLAGS)
+AM_CFLAGS += $(UBSAN_CFLAGS)
AM_CFLAGS += $(CODE_COVERAGE_CFLAGS) $(NO_FORMAT_ZERO_LENGTH)
if BUILD_FREEBSD
AM_CFLAGS += -fPIC -Werror -Wno-unknown-pragmas -Wno-enum-conversion
@@ -58,8 +59,17 @@ AM_CPPFLAGS += -D"__xpg_basename(...)=__xpg_basename(__VA_ARGS__) __attribute__(
AM_CPPFLAGS += -D"basename(...)=basename(__VA_ARGS__) __attribute__((deprecated(\"basename(3) is underspecified. Use zfs_basename() instead!\")))"
AM_CPPFLAGS += -D"dirname(...)=dirname(__VA_ARGS__) __attribute__((deprecated(\"dirname(3) is underspecified. Use zfs_dirnamelen() instead!\")))"
+if ASAN_ENABLED
+AM_CPPFLAGS += -DZFS_ASAN_ENABLED
+endif
+
+if UBSAN_ENABLED
+AM_CPPFLAGS += -DZFS_UBSAN_ENABLED
+endif
+
AM_LDFLAGS = $(DEBUG_LDFLAGS)
AM_LDFLAGS += $(ASAN_LDFLAGS)
+AM_LDFLAGS += $(UBSAN_LDFLAGS)
if BUILD_FREEBSD
AM_LDFLAGS += -fstack-protector-strong -shared
diff --git a/sys/contrib/openzfs/config/Shellcheck.am b/sys/contrib/openzfs/config/Shellcheck.am
index e255e6733dd0..fb0bdedd3be3 100644
--- a/sys/contrib/openzfs/config/Shellcheck.am
+++ b/sys/contrib/openzfs/config/Shellcheck.am
@@ -1,7 +1,15 @@
.PHONY: shellcheck
shellcheck: $(SCRIPTS) $(SHELLCHECKSCRIPTS)
+
+# ShellCheck exclusions
+#
+# ShellCheck can't follow non-constant source. Use a directive to specify location. [SC1090]
+# Not following: a was not specified as input (see shellcheck -x). [SC1091]
+# Prefer putting braces around variable references even when not strictly required. [SC2250]
+# In POSIX sh, 'local' is undefined. [SC2039] # older ShellCheck versions
+# In POSIX sh, 'local' is undefined. [SC3043] # newer ShellCheck versions
if HAVE_SHELLCHECK
- [ -z "$(SCRIPTS)$(SHELLCHECKSCRIPTS)" ] && exit; shellcheck --format=gcc --exclude=SC1090,SC1091,SC2250 $$([ -n "$(SHELLCHECK_SHELL)" ] && echo "--shell=$(SHELLCHECK_SHELL)") $(SHELLCHECK_OPTS) $(SCRIPTS) $(SHELLCHECKSCRIPTS)
+ [ -z "$(SCRIPTS)$(SHELLCHECKSCRIPTS)" ] && exit; shellcheck --format=gcc --enable=all --exclude=SC1090,SC1091,SC2039,SC2250,SC3043 $$([ -n "$(SHELLCHECK_SHELL)" ] && echo "--shell=$(SHELLCHECK_SHELL)") $(SHELLCHECK_OPTS) $(SCRIPTS) $(SHELLCHECKSCRIPTS)
else
@[ -z "$(SCRIPTS)$(SHELLCHECKSCRIPTS)" ] && exit; echo "skipping shellcheck of" $(SCRIPTS) $(SHELLCHECKSCRIPTS) "because shellcheck is not installed"
endif
diff --git a/sys/contrib/openzfs/config/Substfiles.am b/sys/contrib/openzfs/config/Substfiles.am
index 911903e10e69..b051438fb9e3 100644
--- a/sys/contrib/openzfs/config/Substfiles.am
+++ b/sys/contrib/openzfs/config/Substfiles.am
@@ -17,7 +17,9 @@ subst_sed_cmd = \
-e 's|@DEFAULT_INIT_NFS_SERVER[@]|$(DEFAULT_INIT_NFS_SERVER)|g' \
-e 's|@DEFAULT_INIT_SHELL[@]|$(DEFAULT_INIT_SHELL)|g' \
-e 's|@LIBFETCH_DYNAMIC[@]|$(LIBFETCH_DYNAMIC)|g' \
- -e 's|@LIBFETCH_SONAME[@]|$(LIBFETCH_SONAME)|g'
+ -e 's|@LIBFETCH_SONAME[@]|$(LIBFETCH_SONAME)|g' \
+ -e 's|@ASAN_ENABLED[@]|$(ASAN_ENABLED)|g' \
+ -e 's|@UBSAN_ENABLED[@]|$(UBSAN_ENABLED)|g'
SUBSTFILES =
CLEANFILES = $(SUBSTFILES)
diff --git a/sys/contrib/openzfs/config/always-compiler-options.m4 b/sys/contrib/openzfs/config/always-compiler-options.m4
index ce84f7e60684..8cfd27535b57 100644
--- a/sys/contrib/openzfs/config/always-compiler-options.m4
+++ b/sys/contrib/openzfs/config/always-compiler-options.m4
@@ -1,5 +1,5 @@
dnl #
-dnl # Enabled -fsanitize=address if supported by gcc.
+dnl # Enabled -fsanitize=address if supported by $CC.
dnl #
dnl # LDFLAGS needs -fsanitize=address at all times so libraries compiled with
dnl # it will be linked successfully. CFLAGS will vary by binary being built.
@@ -46,7 +46,54 @@ AC_DEFUN([ZFS_AC_CONFIG_ALWAYS_CC_ASAN], [
])
dnl #
-dnl # Check if gcc supports -Wframe-larger-than=<size> option.
+dnl # Enabled -fsanitize=undefined if supported by cc.
+dnl #
+dnl # LDFLAGS needs -fsanitize=undefined at all times so libraries compiled with
+dnl # it will be linked successfully. CFLAGS will vary by binary being built.
+dnl #
+dnl # The UBSAN_OPTIONS environment variable can be used to further control
+dnl # the behavior of binaries and libraries build with -fsanitize=undefined.
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_ALWAYS_CC_UBSAN], [
+ AC_MSG_CHECKING([whether to build with -fsanitize=undefined support])
+ AC_ARG_ENABLE([ubsan],
+ [AS_HELP_STRING([--enable-ubsan],
+ [Enable -fsanitize=undefined support @<:@default=no@:>@])],
+ [],
+ [enable_ubsan=no])
+
+ AM_CONDITIONAL([UBSAN_ENABLED], [test x$enable_ubsan = xyes])
+ AC_SUBST([UBSAN_ENABLED], [$enable_ubsan])
+ AC_MSG_RESULT($enable_ubsan)
+
+ AS_IF([ test "$enable_ubsan" = "yes" ], [
+ AC_MSG_CHECKING([whether $CC supports -fsanitize=undefined])
+ saved_cflags="$CFLAGS"
+ CFLAGS="$CFLAGS -Werror -fsanitize=undefined"
+ AC_LINK_IFELSE([
+ AC_LANG_SOURCE([[ int main() { return 0; } ]])
+ ], [
+ UBSAN_CFLAGS="-fsanitize=undefined"
+ UBSAN_LDFLAGS="-fsanitize=undefined"
+ UBSAN_ZFS="_with_ubsan"
+ AC_MSG_RESULT([yes])
+ ], [
+ AC_MSG_ERROR([$CC does not support -fsanitize=undefined])
+ ])
+ CFLAGS="$saved_cflags"
+ ], [
+ UBSAN_CFLAGS=""
+ UBSAN_LDFLAGS=""
+ UBSAN_ZFS="_without_ubsan"
+ ])
+
+ AC_SUBST([UBSAN_CFLAGS])
+ AC_SUBST([UBSAN_LDFLAGS])
+ AC_SUBST([UBSAN_ZFS])
+])
+
+dnl #
+dnl # Check if cc supports -Wframe-larger-than=<size> option.
dnl #
AC_DEFUN([ZFS_AC_CONFIG_ALWAYS_CC_FRAME_LARGER_THAN], [
AC_MSG_CHECKING([whether $CC supports -Wframe-larger-than=<size>])
@@ -67,7 +114,7 @@ AC_DEFUN([ZFS_AC_CONFIG_ALWAYS_CC_FRAME_LARGER_THAN], [
])
dnl #
-dnl # Check if gcc supports -Wno-format-truncation option.
+dnl # Check if cc supports -Wno-format-truncation option.
dnl #
AC_DEFUN([ZFS_AC_CONFIG_ALWAYS_CC_NO_FORMAT_TRUNCATION], [
AC_MSG_CHECKING([whether $CC supports -Wno-format-truncation])
@@ -88,7 +135,7 @@ AC_DEFUN([ZFS_AC_CONFIG_ALWAYS_CC_NO_FORMAT_TRUNCATION], [
])
dnl #
-dnl # Check if gcc supports -Wno-format-truncation option.
+dnl # Check if cc supports -Wno-format-zero-length option.
dnl #
AC_DEFUN([ZFS_AC_CONFIG_ALWAYS_CC_NO_FORMAT_ZERO_LENGTH], [
AC_MSG_CHECKING([whether $CC supports -Wno-format-zero-length])
@@ -108,61 +155,34 @@ AC_DEFUN([ZFS_AC_CONFIG_ALWAYS_CC_NO_FORMAT_ZERO_LENGTH], [
AC_SUBST([NO_FORMAT_ZERO_LENGTH])
])
-
-dnl #
-dnl # Check if gcc supports -Wno-bool-compare option.
-dnl #
-dnl # We actually invoke gcc with the -Wbool-compare option
-dnl # and infer the 'no-' version does or doesn't exist based upon
-dnl # the results. This is required because when checking any of
-dnl # no- prefixed options gcc always returns success.
-dnl #
-AC_DEFUN([ZFS_AC_CONFIG_ALWAYS_CC_NO_BOOL_COMPARE], [
- AC_MSG_CHECKING([whether $CC supports -Wno-bool-compare])
-
- saved_flags="$CFLAGS"
- CFLAGS="$CFLAGS -Werror -Wbool-compare"
-
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [])], [
- NO_BOOL_COMPARE=-Wno-bool-compare
- AC_MSG_RESULT([yes])
- ], [
- NO_BOOL_COMPARE=
- AC_MSG_RESULT([no])
- ])
-
- CFLAGS="$saved_flags"
- AC_SUBST([NO_BOOL_COMPARE])
-])
-
dnl #
-dnl # Check if gcc supports -Wno-unused-but-set-variable option.
+dnl # Check if cc supports -Wno-clobbered option.
dnl #
-dnl # We actually invoke gcc with the -Wunused-but-set-variable option
+dnl # We actually invoke it with the -Wclobbered option
dnl # and infer the 'no-' version does or doesn't exist based upon
dnl # the results. This is required because when checking any of
dnl # no- prefixed options gcc always returns success.
dnl #
-AC_DEFUN([ZFS_AC_CONFIG_ALWAYS_CC_NO_UNUSED_BUT_SET_VARIABLE], [
- AC_MSG_CHECKING([whether $CC supports -Wno-unused-but-set-variable])
+AC_DEFUN([ZFS_AC_CONFIG_ALWAYS_CC_NO_CLOBBERED], [
+ AC_MSG_CHECKING([whether $CC supports -Wno-clobbered])
saved_flags="$CFLAGS"
- CFLAGS="$CFLAGS -Werror -Wunused-but-set-variable"
+ CFLAGS="$CFLAGS -Werror -Wclobbered"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [])], [
- NO_UNUSED_BUT_SET_VARIABLE=-Wno-unused-but-set-variable
+ NO_CLOBBERED=-Wno-clobbered
AC_MSG_RESULT([yes])
], [
- NO_UNUSED_BUT_SET_VARIABLE=
+ NO_CLOBBERED=
AC_MSG_RESULT([no])
])
CFLAGS="$saved_flags"
- AC_SUBST([NO_UNUSED_BUT_SET_VARIABLE])
+ AC_SUBST([NO_CLOBBERED])
])
dnl #
-dnl # Check if gcc supports -Wimplicit-fallthrough option.
+dnl # Check if cc supports -Wimplicit-fallthrough option.
dnl #
AC_DEFUN([ZFS_AC_CONFIG_ALWAYS_CC_IMPLICIT_FALLTHROUGH], [
AC_MSG_CHECKING([whether $CC supports -Wimplicit-fallthrough])
@@ -185,7 +205,7 @@ AC_DEFUN([ZFS_AC_CONFIG_ALWAYS_CC_IMPLICIT_FALLTHROUGH], [
])
dnl #
-dnl # Check if gcc supports -fno-omit-frame-pointer option.
+dnl # Check if cc supports -fno-omit-frame-pointer option.
dnl #
AC_DEFUN([ZFS_AC_CONFIG_ALWAYS_CC_NO_OMIT_FRAME_POINTER], [
AC_MSG_CHECKING([whether $CC supports -fno-omit-frame-pointer])
diff --git a/sys/contrib/openzfs/config/kernel-add-disk.m4 b/sys/contrib/openzfs/config/kernel-add-disk.m4
new file mode 100644
index 000000000000..5d1779eb4328
--- /dev/null
+++ b/sys/contrib/openzfs/config/kernel-add-disk.m4
@@ -0,0 +1,26 @@
+dnl #
+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 <linux/genhd.h>
+ ], [
+ 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],
+ [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_ADD_DISK_RET, 1,
+ [add_disk() returns int])
+ ], [
+ AC_MSG_RESULT(no)
+ ])
+])
diff --git a/sys/contrib/openzfs/config/kernel-blk-queue.m4 b/sys/contrib/openzfs/config/kernel-blk-queue.m4
index ff5d2d370e98..559ae9800e8f 100644
--- a/sys/contrib/openzfs/config/kernel-blk-queue.m4
+++ b/sys/contrib/openzfs/config/kernel-blk-queue.m4
@@ -215,17 +215,17 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLK_QUEUE_FLUSH], [
ZFS_LINUX_TEST_SRC([blk_queue_flush], [
#include <linux/blkdev.h>
], [
- struct request_queue *q = NULL;
+ struct request_queue *q __attribute__ ((unused)) = NULL;
(void) blk_queue_flush(q, REQ_FLUSH);
- ], [$NO_UNUSED_BUT_SET_VARIABLE], [ZFS_META_LICENSE])
+ ], [], [ZFS_META_LICENSE])
ZFS_LINUX_TEST_SRC([blk_queue_write_cache], [
#include <linux/kernel.h>
#include <linux/blkdev.h>
], [
- struct request_queue *q = NULL;
+ struct request_queue *q __attribute__ ((unused)) = NULL;
blk_queue_write_cache(q, true, true);
- ], [$NO_UNUSED_BUT_SET_VARIABLE], [ZFS_META_LICENSE])
+ ], [], [ZFS_META_LICENSE])
])
AC_DEFUN([ZFS_AC_KERNEL_BLK_QUEUE_FLUSH], [
@@ -278,9 +278,9 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLK_QUEUE_MAX_HW_SECTORS], [
ZFS_LINUX_TEST_SRC([blk_queue_max_hw_sectors], [
#include <linux/blkdev.h>
], [
- struct request_queue *q = NULL;
+ struct request_queue *q __attribute__ ((unused)) = NULL;
(void) blk_queue_max_hw_sectors(q, BLK_SAFE_MAX_SECTORS);
- ], [$NO_UNUSED_BUT_SET_VARIABLE])
+ ], [])
])
AC_DEFUN([ZFS_AC_KERNEL_BLK_QUEUE_MAX_HW_SECTORS], [
@@ -301,9 +301,9 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLK_QUEUE_MAX_SEGMENTS], [
ZFS_LINUX_TEST_SRC([blk_queue_max_segments], [
#include <linux/blkdev.h>
], [
- struct request_queue *q = NULL;
+ struct request_queue *q __attribute__ ((unused)) = NULL;
(void) blk_queue_max_segments(q, BLK_MAX_SEGMENTS);
- ], [$NO_UNUSED_BUT_SET_VARIABLE])
+ ], [])
])
AC_DEFUN([ZFS_AC_KERNEL_BLK_QUEUE_MAX_SEGMENTS], [
diff --git a/sys/contrib/openzfs/config/kernel-block-device-operations.m4 b/sys/contrib/openzfs/config/kernel-block-device-operations.m4
index a48618185bfb..84e39dc8a2f6 100644
--- a/sys/contrib/openzfs/config/kernel-block-device-operations.m4
+++ b/sys/contrib/openzfs/config/kernel-block-device-operations.m4
@@ -6,13 +6,16 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_CHECK_EVENTS], [
#include <linux/blkdev.h>
unsigned int blk_check_events(struct gendisk *disk,
- unsigned int clearing) { return (0); }
+ unsigned int clearing) {
+ (void) disk, (void) clearing;
+ return (0);
+ }
static const struct block_device_operations
bops __attribute__ ((unused)) = {
.check_events = blk_check_events,
};
- ], [], [$NO_UNUSED_BUT_SET_VARIABLE])
+ ], [], [])
])
AC_DEFUN([ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_CHECK_EVENTS], [
@@ -31,7 +34,10 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID], [
ZFS_LINUX_TEST_SRC([block_device_operations_release_void], [
#include <linux/blkdev.h>
- void blk_release(struct gendisk *g, fmode_t mode) { return; }
+ void blk_release(struct gendisk *g, fmode_t mode) {
+ (void) g, (void) mode;
+ return;
+ }
static const struct block_device_operations
bops __attribute__ ((unused)) = {
@@ -40,7 +46,7 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID], [
.ioctl = NULL,
.compat_ioctl = NULL,
};
- ], [], [$NO_UNUSED_BUT_SET_VARIABLE])
+ ], [], [])
])
AC_DEFUN([ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID], [
@@ -61,6 +67,7 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_REVALIDATE_DISK], [
#include <linux/blkdev.h>
int blk_revalidate_disk(struct gendisk *disk) {
+ (void) disk;
return(0);
}
@@ -68,7 +75,7 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_REVALIDATE_DISK], [
bops __attribute__ ((unused)) = {
.revalidate_disk = blk_revalidate_disk,
};
- ], [], [$NO_UNUSED_BUT_SET_VARIABLE])
+ ], [], [])
])
AC_DEFUN([ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_REVALIDATE_DISK], [
diff --git a/sys/contrib/openzfs/config/kernel-fallocate.m4 b/sys/contrib/openzfs/config/kernel-fallocate.m4
index 7a8550f7e760..815602d3e2c6 100644
--- a/sys/contrib/openzfs/config/kernel-fallocate.m4
+++ b/sys/contrib/openzfs/config/kernel-fallocate.m4
@@ -3,6 +3,10 @@ dnl # Linux 2.6.38 - 3.x API
dnl # The fallocate callback was moved from the inode_operations
dnl # structure to the file_operations structure.
dnl #
+dnl #
+dnl # Linux 3.15+
+dnl # fallocate learned a new flag, FALLOC_FL_ZERO_RANGE
+dnl #
AC_DEFUN([ZFS_AC_KERNEL_SRC_FALLOCATE], [
ZFS_LINUX_TEST_SRC([file_fallocate], [
#include <linux/fs.h>
@@ -15,12 +19,25 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_FALLOCATE], [
.fallocate = test_fallocate,
};
], [])
+ ZFS_LINUX_TEST_SRC([falloc_fl_zero_range], [
+ #include <linux/falloc.h>
+ ],[
+ int flags __attribute__ ((unused));
+ flags = FALLOC_FL_ZERO_RANGE;
+ ])
])
AC_DEFUN([ZFS_AC_KERNEL_FALLOCATE], [
AC_MSG_CHECKING([whether fops->fallocate() exists])
ZFS_LINUX_TEST_RESULT([file_fallocate], [
AC_MSG_RESULT(yes)
+ AC_MSG_CHECKING([whether FALLOC_FL_ZERO_RANGE exists])
+ ZFS_LINUX_TEST_RESULT([falloc_fl_zero_range], [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_FALLOC_FL_ZERO_RANGE, 1, [FALLOC_FL_ZERO_RANGE is defined])
+ ],[
+ AC_MSG_RESULT(no)
+ ])
],[
ZFS_LINUX_TEST_ERROR([file_fallocate])
])
diff --git a/sys/contrib/openzfs/config/kernel-fpu.m4 b/sys/contrib/openzfs/config/kernel-fpu.m4
index faa64f1ec46b..7f8b028d043b 100644
--- a/sys/contrib/openzfs/config/kernel-fpu.m4
+++ b/sys/contrib/openzfs/config/kernel-fpu.m4
@@ -1,9 +1,15 @@
-dnl #
+dnl #
dnl # Handle differences in kernel FPU code.
dnl #
dnl # Kernel
dnl # 5.16: XCR code put into asm/fpu/xcr.h
-dnl # HAVE_KERNEL_FPU_XCR_HEADER
+dnl # HAVE_KERNEL_FPU_XCR_HEADER
+dnl #
+dnl # XSTATE_XSAVE and XSTATE_XRESTORE aren't accessible any more
+dnl # HAVE_KERNEL_FPU_XSAVE_INTERNAL
+dnl #
+dnl # 5.11: kernel_fpu_begin() is an inlined function now, so don't check
+dnl # for it inside the kernel symbols.
dnl #
dnl # 5.0: Wrappers have been introduced to save/restore the FPU state.
dnl # This change was made to the 4.19.38 and 4.14.120 LTS kernels.
@@ -107,6 +113,36 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_FPU], [
struct fxregs_state *fxr __attribute__ ((unused)) = &st->fxsave;
struct xregs_state *xr __attribute__ ((unused)) = &st->xsave;
])
+
+ ZFS_LINUX_TEST_SRC([fpu_xsave_internal], [
+ #include <linux/sched.h>
+ #if defined(__x86_64) || defined(__x86_64__) || \
+ defined(__i386) || defined(__i386__)
+ #if !defined(__x86)
+ #define __x86
+ #endif
+ #endif
+
+ #if !defined(__x86)
+ #error Unsupported architecture
+ #endif
+
+ #include <linux/types.h>
+ #ifdef HAVE_KERNEL_FPU_API_HEADER
+ #include <asm/fpu/api.h>
+ #include <asm/fpu/internal.h>
+ #else
+ #include <asm/i387.h>
+ #include <asm/xcr.h>
+ #endif
+
+ ],[
+ struct fpu *fpu = &current->thread.fpu;
+ union fpregs_state *st = &fpu->fpstate->regs;
+ struct fregs_state *fr __attribute__ ((unused)) = &st->fsave;
+ struct fxregs_state *fxr __attribute__ ((unused)) = &st->fxsave;
+ struct xregs_state *xr __attribute__ ((unused)) = &st->xsave;
+ ])
])
AC_DEFUN([ZFS_AC_KERNEL_FPU], [
@@ -114,8 +150,7 @@ AC_DEFUN([ZFS_AC_KERNEL_FPU], [
dnl # Legacy kernel
dnl #
AC_MSG_CHECKING([whether kernel fpu is available])
- ZFS_LINUX_TEST_RESULT_SYMBOL([kernel_fpu_license],
- [kernel_fpu_begin], [arch/x86/kernel/fpu/core.c], [
+ ZFS_LINUX_TEST_RESULT([kernel_fpu_license], [
AC_MSG_RESULT(kernel_fpu_*)
AC_DEFINE(HAVE_KERNEL_FPU, 1,
[kernel has kernel_fpu_* functions])
@@ -139,7 +174,13 @@ AC_DEFUN([ZFS_AC_KERNEL_FPU], [
AC_DEFINE(HAVE_KERNEL_FPU_INTERNAL, 1,
[kernel fpu internal])
],[
+ ZFS_LINUX_TEST_RESULT([fpu_xsave_internal], [
+ AC_MSG_RESULT(internal with internal XSAVE)
+ AC_DEFINE(HAVE_KERNEL_FPU_XSAVE_INTERNAL, 1,
+ [kernel fpu and XSAVE internal])
+ ],[
AC_MSG_RESULT(unavailable)
+ ])
])
])
])
diff --git a/sys/contrib/openzfs/config/kernel-get-disk-ro.m4 b/sys/contrib/openzfs/config/kernel-get-disk-ro.m4
index 8a379c7669fa..acfcb69acc10 100644
--- a/sys/contrib/openzfs/config/kernel-get-disk-ro.m4
+++ b/sys/contrib/openzfs/config/kernel-get-disk-ro.m4
@@ -5,9 +5,9 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_GET_DISK_RO], [
ZFS_LINUX_TEST_SRC([get_disk_ro], [
#include <linux/blkdev.h>
],[
- struct gendisk *disk = NULL;
+ struct gendisk *disk __attribute__ ((unused)) = NULL;
(void) get_disk_ro(disk);
- ], [$NO_UNUSED_BUT_SET_VARIABLE])
+ ], [])
])
AC_DEFUN([ZFS_AC_KERNEL_GET_DISK_RO], [
diff --git a/sys/contrib/openzfs/config/kernel-kmem.m4 b/sys/contrib/openzfs/config/kernel-kmem.m4
index 43f9e72f88d8..03c2a41fbdb2 100644
--- a/sys/contrib/openzfs/config/kernel-kmem.m4
+++ b/sys/contrib/openzfs/config/kernel-kmem.m4
@@ -64,6 +64,7 @@ dnl #
AC_DEFUN([ZFS_AC_KERNEL_SRC_KVMALLOC], [
ZFS_LINUX_TEST_SRC([kvmalloc], [
#include <linux/mm.h>
+ #include <linux/slab.h>
],[
void *p __attribute__ ((unused));
diff --git a/sys/contrib/openzfs/config/kernel-kthread.m4 b/sys/contrib/openzfs/config/kernel-kthread.m4
new file mode 100644
index 000000000000..f5b824d7947a
--- /dev/null
+++ b/sys/contrib/openzfs/config/kernel-kthread.m4
@@ -0,0 +1,68 @@
+AC_DEFUN([ZFS_AC_KERNEL_KTHREAD_COMPLETE_AND_EXIT], [
+ dnl #
+ dnl # 5.17 API,
+ dnl # cead18552660702a4a46f58e65188fe5f36e9dfe ("exit: Rename complete_and_exit to kthread_complete_and_exit")
+ dnl #
+ dnl # Also moves the definition from include/linux/kernel.h to include/linux/kthread.h
+ dnl #
+ AC_MSG_CHECKING([whether kthread_complete_and_exit() is available])
+ ZFS_LINUX_TEST_RESULT([kthread_complete_and_exit], [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(SPL_KTHREAD_COMPLETE_AND_EXIT, kthread_complete_and_exit, [kthread_complete_and_exit() available])
+ ], [
+ AC_MSG_RESULT(no)
+ AC_DEFINE(SPL_KTHREAD_COMPLETE_AND_EXIT, complete_and_exit, [using complete_and_exit() instead])
+ ])
+])
+
+AC_DEFUN([ZFS_AC_KERNEL_KTHREAD_DEQUEUE_SIGNAL_4ARG], [
+ dnl #
+ dnl # 5.17 API: enum pid_type * as new 4th dequeue_signal() argument,
+ dnl # 5768d8906bc23d512b1a736c1e198aa833a6daa4 ("signal: Requeue signals in the appropriate queue")
+ dnl #
+ dnl # int dequeue_signal(struct task_struct *task, sigset_t *mask, kernel_siginfo_t *info);
+ dnl # int dequeue_signal(struct task_struct *task, sigset_t *mask, kernel_siginfo_t *info, enum pid_type *type);
+ dnl #
+ AC_MSG_CHECKING([whether dequeue_signal() takes 4 arguments])
+ ZFS_LINUX_TEST_RESULT([kthread_dequeue_signal], [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_DEQUEUE_SIGNAL_4ARG, 1, [dequeue_signal() takes 4 arguments])
+ ], [
+ AC_MSG_RESULT(no)
+ ])
+])
+
+AC_DEFUN([ZFS_AC_KERNEL_SRC_KTHREAD_COMPLETE_AND_EXIT], [
+ ZFS_LINUX_TEST_SRC([kthread_complete_and_exit], [
+ #include <linux/kthread.h>
+ ], [
+ struct completion *completion = NULL;
+ long code = 0;
+
+ kthread_complete_and_exit(completion, code);
+ ])
+])
+
+AC_DEFUN([ZFS_AC_KERNEL_SRC_KTHREAD_DEQUEUE_SIGNAL_4ARG], [
+ ZFS_LINUX_TEST_SRC([kthread_dequeue_signal], [
+ #include <linux/sched/signal.h>
+ ], [
+ struct task_struct *task = NULL;
+ sigset_t *mask = NULL;
+ kernel_siginfo_t *info = NULL;
+ enum pid_type *type = NULL;
+ int error __attribute__ ((unused));
+
+ error = dequeue_signal(task, mask, info, type);
+ ])
+])
+
+AC_DEFUN([ZFS_AC_KERNEL_KTHREAD], [
+ ZFS_AC_KERNEL_KTHREAD_COMPLETE_AND_EXIT
+ ZFS_AC_KERNEL_KTHREAD_DEQUEUE_SIGNAL_4ARG
+])
+
+AC_DEFUN([ZFS_AC_KERNEL_SRC_KTHREAD], [
+ ZFS_AC_KERNEL_SRC_KTHREAD_COMPLETE_AND_EXIT
+ ZFS_AC_KERNEL_SRC_KTHREAD_DEQUEUE_SIGNAL_4ARG
+])
diff --git a/sys/contrib/openzfs/config/kernel-pde-data.m4 b/sys/contrib/openzfs/config/kernel-pde-data.m4
index f866d77a11df..4fc665dfbe2e 100644
--- a/sys/contrib/openzfs/config/kernel-pde-data.m4
+++ b/sys/contrib/openzfs/config/kernel-pde-data.m4
@@ -1,20 +1,22 @@
dnl #
-dnl # 3.10 API change,
-dnl # PDE is replaced by PDE_DATA
+dnl # 5.17 API: PDE_DATA() renamed to pde_data(),
+dnl # 359745d78351c6f5442435f81549f0207ece28aa ("proc: remove PDE_DATA() completely")
dnl #
AC_DEFUN([ZFS_AC_KERNEL_SRC_PDE_DATA], [
ZFS_LINUX_TEST_SRC([pde_data], [
#include <linux/proc_fs.h>
], [
- PDE_DATA(NULL);
+ pde_data(NULL);
])
])
AC_DEFUN([ZFS_AC_KERNEL_PDE_DATA], [
- AC_MSG_CHECKING([whether PDE_DATA() is available])
- ZFS_LINUX_TEST_RESULT_SYMBOL([pde_data], [PDE_DATA], [], [
+ AC_MSG_CHECKING([whether pde_data() is lowercase])
+ ZFS_LINUX_TEST_RESULT([pde_data], [
AC_MSG_RESULT(yes)
- ],[
- ZFS_LINUX_TEST_ERROR([PDE_DATA])
+ AC_DEFINE(SPL_PDE_DATA, pde_data, [pde_data() is pde_data()])
+ ], [
+ AC_MSG_RESULT(no)
+ AC_DEFINE(SPL_PDE_DATA, PDE_DATA, [pde_data() is PDE_DATA()])
])
])
diff --git a/sys/contrib/openzfs/config/kernel-vfs-iov_iter.m4 b/sys/contrib/openzfs/config/kernel-vfs-iov_iter.m4
index ecdda939f1cf..57f78745a24b 100644
--- a/sys/contrib/openzfs/config/kernel-vfs-iov_iter.m4
+++ b/sys/contrib/openzfs/config/kernel-vfs-iov_iter.m4
@@ -41,6 +41,17 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_VFS_IOV_ITER], [
error = iov_iter_fault_in_readable(&iter, size);
])
+ ZFS_LINUX_TEST_SRC([fault_in_iov_iter_readable], [
+ #include <linux/fs.h>
+ #include <linux/uio.h>
+ ],[
+ struct iov_iter iter = { 0 };
+ size_t size = 512;
+ int error __attribute__ ((unused));
+
+ error = fault_in_iov_iter_readable(&iter, size);
+ ])
+
ZFS_LINUX_TEST_SRC([iov_iter_count], [
#include <linux/fs.h>
#include <linux/uio.h>
@@ -123,8 +134,15 @@ 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)
- enable_vfs_iov_iter="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)
+ AC_DEFINE(HAVE_FAULT_IN_IOV_ITER_READABLE, 1,
+ [fault_in_iov_iter_readable() is available])
+ ],[
+ AC_MSG_RESULT(no)
+ enable_vfs_iov_iter="no"
+ ])
])
AC_MSG_CHECKING([whether iov_iter_count() is available])
diff --git a/sys/contrib/openzfs/config/kernel.m4 b/sys/contrib/openzfs/config/kernel.m4
index bdd3caed2b3d..3122e9dbaa94 100644
--- a/sys/contrib/openzfs/config/kernel.m4
+++ b/sys/contrib/openzfs/config/kernel.m4
@@ -135,6 +135,8 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
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
AC_MSG_CHECKING([for available kernel interfaces])
ZFS_LINUX_TEST_COMPILE_ALL([kabi])
@@ -243,6 +245,8 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
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
])
dnl #
@@ -276,6 +280,35 @@ AC_DEFUN([ZFS_AC_MODULE_SYMVERS], [
dnl #
dnl # Detect the kernel to be built against
dnl #
+dnl # Most modern Linux distributions have separate locations for bare
+dnl # source (source) and prebuilt (build) files. Additionally, there are
+dnl # `source` and `build` symlinks in `/lib/modules/$(KERNEL_VERSION)`
+dnl # pointing to them. The directory search order is now:
+dnl #
+dnl # - `configure` command line values if both `--with-linux` and
+dnl # `--with-linux-obj` were defined
+dnl #
+dnl # - If only `--with-linux` was defined, `--with-linux-obj` is assumed
+dnl # to have the same value as `--with-linux`
+dnl #
+dnl # - If neither `--with-linux` nor `--with-linux-obj` were defined
+dnl # autodetection is used:
+dnl #
+dnl # - `/lib/modules/$(uname -r)/{source,build}` respectively, if exist.
+dnl #
+dnl # - If only `/lib/modules/$(uname -r)/build` exists, it is assumed
+dnl # to be both source and build directory.
+dnl #
+dnl # - The first directory in `/lib/modules` with the highest version
+dnl # number according to `sort -V` which contains both `source` and
+dnl # `build` symlinks/directories. If module directory contains only
+dnl # `build` component, it is assumed to be both source and build
+dnl # directory.
+dnl #
+dnl # - Last resort: the first directory matching `/usr/src/kernels/*`
+dnl # and `/usr/src/linux-*` with the highest version number according
+dnl # to `sort -V` is assumed to be both source and build directory.
+dnl #
AC_DEFUN([ZFS_AC_KERNEL], [
AC_ARG_WITH([linux],
AS_HELP_STRING([--with-linux=PATH],
@@ -287,25 +320,52 @@ AC_DEFUN([ZFS_AC_KERNEL], [
[Path to kernel build objects]),
[kernelbuild="$withval"])
- AC_MSG_CHECKING([kernel source directory])
- AS_IF([test -z "$kernelsrc"], [
- AS_IF([test -e "/lib/modules/$(uname -r)/source"], [
- headersdir="/lib/modules/$(uname -r)/source"
- sourcelink=$(readlink -f "$headersdir")
+ AC_MSG_CHECKING([kernel source and build directories])
+ AS_IF([test -n "$kernelsrc" && test -z "$kernelbuild"], [
+ kernelbuild="$kernelsrc"
+ ], [test -z "$kernelsrc"], [
+ AS_IF([test -e "/lib/modules/$(uname -r)/source" && \
+ test -e "/lib/modules/$(uname -r)/build"], [
+ src="/lib/modules/$(uname -r)/source"
+ build="/lib/modules/$(uname -r)/build"
], [test -e "/lib/modules/$(uname -r)/build"], [
- headersdir="/lib/modules/$(uname -r)/build"
- sourcelink=$(readlink -f "$headersdir")
+ build="/lib/modules/$(uname -r)/build"
+ src="$build"
], [
- sourcelink=$(ls -1d /usr/src/kernels/* \
- /usr/src/linux-* \
- 2>/dev/null | grep -v obj | tail -1)
+ src=
+
+ for d in $(ls -1d /lib/modules/* 2>/dev/null | sort -Vr); do
+ if test -e "$d/source" && test -e "$d/build"; then
+ src="$d/source"
+ build="$d/build"
+ break
+ fi
+
+ if test -e "$d/build"; then
+ src="$d/build"
+ build="$d/build"
+ break
+ fi
+ done
+
+ # the least reliable method
+ if test -z "$src"; then
+ src=$(ls -1d /usr/src/kernels/* /usr/src/linux-* \
+ 2>/dev/null | grep -v obj | sort -Vr | head -1)
+ build="$src"
+ fi
])
- AS_IF([test -n "$sourcelink" && test -e ${sourcelink}], [
- kernelsrc=`readlink -f ${sourcelink}`
+ AS_IF([test -n "$src" && test -e "$src"], [
+ kernelsrc=$(readlink -e "$src")
], [
kernelsrc="[Not found]"
])
+ AS_IF([test -n "$build" && test -e "$build"], [
+ kernelbuild=$(readlink -e "$build")
+ ], [
+ kernelbuild="[Not found]"
+ ])
], [
AS_IF([test "$kernelsrc" = "NONE"], [
kernsrcver=NONE
@@ -313,30 +373,19 @@ AC_DEFUN([ZFS_AC_KERNEL], [
withlinux=yes
])
+ AC_MSG_RESULT([done])
+ AC_MSG_CHECKING([kernel source directory])
AC_MSG_RESULT([$kernelsrc])
- AS_IF([test ! -d "$kernelsrc"], [
+ AC_MSG_CHECKING([kernel build directory])
+ AC_MSG_RESULT([$kernelbuild])
+ AS_IF([test ! -d "$kernelsrc" || test ! -d "$kernelbuild"], [
AC_MSG_ERROR([
*** Please make sure the kernel devel package for your distribution
*** is installed and then try again. If that fails, you can specify the
- *** location of the kernel source with the '--with-linux=PATH' option.])
+ *** location of the kernel source and build with the '--with-linux=PATH' and
+ *** '--with-linux-obj=PATH' options respectively.])
])
- AC_MSG_CHECKING([kernel build directory])
- AS_IF([test -z "$kernelbuild"], [
- AS_IF([test x$withlinux != xyes -a -e "/lib/modules/$(uname -r)/build"], [
- kernelbuild=`readlink -f /lib/modules/$(uname -r)/build`
- ], [test -d ${kernelsrc}-obj/${target_cpu}/${target_cpu}], [
- kernelbuild=${kernelsrc}-obj/${target_cpu}/${target_cpu}
- ], [test -d ${kernelsrc}-obj/${target_cpu}/default], [
- kernelbuild=${kernelsrc}-obj/${target_cpu}/default
- ], [test -d `dirname ${kernelsrc}`/build-${target_cpu}], [
- kernelbuild=`dirname ${kernelsrc}`/build-${target_cpu}
- ], [
- kernelbuild=${kernelsrc}
- ])
- ])
- AC_MSG_RESULT([$kernelbuild])
-
AC_MSG_CHECKING([kernel source version])
utsrelease1=$kernelbuild/include/linux/version.h
utsrelease2=$kernelbuild/include/linux/utsrelease.h
@@ -597,9 +646,15 @@ dnl #
dnl # Used internally by ZFS_LINUX_TEST_{COMPILE,MODPOST}
dnl #
AC_DEFUN([ZFS_LINUX_COMPILE], [
+ AC_ARG_VAR([KERNEL_CC], [C compiler for
+ building kernel modules])
+ AC_ARG_VAR([KERNEL_LD], [Linker for
+ building kernel modules])
+ AC_ARG_VAR([KERNEL_LLVM], [Binary option to
+ build kernel modules with LLVM/CLANG toolchain])
AC_TRY_COMMAND([
KBUILD_MODPOST_NOFINAL="$5" KBUILD_MODPOST_WARN="$6"
- make modules -k -j$TEST_JOBS -C $LINUX_OBJ $ARCH_UM
+ 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])
AS_IF([AC_TRY_COMMAND([$2])], [$3], [$4])
])
diff --git a/sys/contrib/openzfs/config/toolchain-simd.m4 b/sys/contrib/openzfs/config/toolchain-simd.m4
index 1153cd6941a8..061576fd94e3 100644
--- a/sys/contrib/openzfs/config/toolchain-simd.m4
+++ b/sys/contrib/openzfs/config/toolchain-simd.m4
@@ -24,6 +24,9 @@ AC_DEFUN([ZFS_AC_CONFIG_ALWAYS_TOOLCHAIN_SIMD], [
ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AES
ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_PCLMULQDQ
ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_MOVBE
+ ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_XSAVE
+ ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_XSAVEOPT
+ ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_XSAVES
;;
esac
])
@@ -422,3 +425,66 @@ AC_DEFUN([ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_MOVBE], [
AC_MSG_RESULT([no])
])
])
+
+dnl #
+dnl # ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_XSAVE
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_XSAVE], [
+ AC_MSG_CHECKING([whether host toolchain supports XSAVE])
+
+ AC_LINK_IFELSE([AC_LANG_SOURCE([
+ [
+ void main()
+ {
+ char b[4096] __attribute__ ((aligned (64)));
+ __asm__ __volatile__("xsave %[b]\n" : : [b] "m" (*b) : "memory");
+ }
+ ]])], [
+ AC_MSG_RESULT([yes])
+ AC_DEFINE([HAVE_XSAVE], 1, [Define if host toolchain supports XSAVE])
+ ], [
+ AC_MSG_RESULT([no])
+ ])
+])
+
+dnl #
+dnl # ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_XSAVEOPT
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_XSAVEOPT], [
+ AC_MSG_CHECKING([whether host toolchain supports XSAVEOPT])
+
+ AC_LINK_IFELSE([AC_LANG_SOURCE([
+ [
+ void main()
+ {
+ char b[4096] __attribute__ ((aligned (64)));
+ __asm__ __volatile__("xsaveopt %[b]\n" : : [b] "m" (*b) : "memory");
+ }
+ ]])], [
+ AC_MSG_RESULT([yes])
+ AC_DEFINE([HAVE_XSAVEOPT], 1, [Define if host toolchain supports XSAVEOPT])
+ ], [
+ AC_MSG_RESULT([no])
+ ])
+])
+
+dnl #
+dnl # ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_XSAVES
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_XSAVES], [
+ AC_MSG_CHECKING([whether host toolchain supports XSAVES])
+
+ AC_LINK_IFELSE([AC_LANG_SOURCE([
+ [
+ void main()
+ {
+ char b[4096] __attribute__ ((aligned (64)));
+ __asm__ __volatile__("xsaves %[b]\n" : : [b] "m" (*b) : "memory");
+ }
+ ]])], [
+ AC_MSG_RESULT([yes])
+ AC_DEFINE([HAVE_XSAVES], 1, [Define if host toolchain supports XSAVES])
+ ], [
+ AC_MSG_RESULT([no])
+ ])
+])
diff --git a/sys/contrib/openzfs/config/zfs-build.m4 b/sys/contrib/openzfs/config/zfs-build.m4
index b1604eb9d50e..d516f3d2969f 100644
--- a/sys/contrib/openzfs/config/zfs-build.m4
+++ b/sys/contrib/openzfs/config/zfs-build.m4
@@ -209,8 +209,7 @@ AC_DEFUN([ZFS_AC_CONFIG_ALWAYS], [
AX_COUNT_CPUS([])
AC_SUBST(CPU_COUNT)
- ZFS_AC_CONFIG_ALWAYS_CC_NO_UNUSED_BUT_SET_VARIABLE
- ZFS_AC_CONFIG_ALWAYS_CC_NO_BOOL_COMPARE
+ ZFS_AC_CONFIG_ALWAYS_CC_NO_CLOBBERED
ZFS_AC_CONFIG_ALWAYS_CC_IMPLICIT_FALLTHROUGH
ZFS_AC_CONFIG_ALWAYS_CC_FRAME_LARGER_THAN
ZFS_AC_CONFIG_ALWAYS_CC_NO_FORMAT_TRUNCATION
@@ -218,6 +217,7 @@ AC_DEFUN([ZFS_AC_CONFIG_ALWAYS], [
ZFS_AC_CONFIG_ALWAYS_CC_NO_OMIT_FRAME_POINTER
ZFS_AC_CONFIG_ALWAYS_CC_NO_IPA_SRA
ZFS_AC_CONFIG_ALWAYS_CC_ASAN
+ ZFS_AC_CONFIG_ALWAYS_CC_UBSAN
ZFS_AC_CONFIG_ALWAYS_TOOLCHAIN_SIMD
ZFS_AC_CONFIG_ALWAYS_SYSTEM
ZFS_AC_CONFIG_ALWAYS_ARCH
@@ -323,6 +323,7 @@ AC_DEFUN([ZFS_AC_RPM], [
RPM_DEFINE_COMMON=${RPM_DEFINE_COMMON}' --define "$(DEBUG_KMEM_ZFS) 1"'
RPM_DEFINE_COMMON=${RPM_DEFINE_COMMON}' --define "$(DEBUG_KMEM_TRACKING_ZFS) 1"'
RPM_DEFINE_COMMON=${RPM_DEFINE_COMMON}' --define "$(ASAN_ZFS) 1"'
+ RPM_DEFINE_COMMON=${RPM_DEFINE_COMMON}' --define "$(UBSAN_ZFS) 1"'
RPM_DEFINE_UTIL=' --define "_initconfdir $(initconfdir)"'
@@ -369,6 +370,9 @@ AC_DEFUN([ZFS_AC_RPM], [
RPM_DEFINE_KMOD=${RPM_DEFINE_KMOD}' --define "kernels $(LINUX_VERSION)"'
RPM_DEFINE_KMOD=${RPM_DEFINE_KMOD}' --define "ksrc $(LINUX)"'
RPM_DEFINE_KMOD=${RPM_DEFINE_KMOD}' --define "kobj $(LINUX_OBJ)"'
+ RPM_DEFINE_KMOD=${RPM_DEFINE_KMOD}' --define "kernel_cc KERNEL_CC=$(KERNEL_CC)"'
+ RPM_DEFINE_KMOD=${RPM_DEFINE_KMOD}' --define "kernel_ld KERNEL_LD=$(KERNEL_LD)"'
+ RPM_DEFINE_KMOD=${RPM_DEFINE_KMOD}' --define "kernel_llvm KERNEL_LLVM=$(KERNEL_LLVM)"'
])
RPM_DEFINE_DKMS=''
diff --git a/sys/contrib/openzfs/configure.ac b/sys/contrib/openzfs/configure.ac
index 1ba037a36aa4..990958bafa1e 100644
--- a/sys/contrib/openzfs/configure.ac
+++ b/sys/contrib/openzfs/configure.ac
@@ -147,8 +147,6 @@ AC_CONFIG_FILES([
lib/libshare/Makefile
lib/libspl/Makefile
lib/libspl/include/Makefile
- lib/libspl/include/ia32/Makefile
- lib/libspl/include/ia32/sys/Makefile
lib/libspl/include/os/Makefile
lib/libspl/include/os/freebsd/Makefile
lib/libspl/include/os/freebsd/sys/Makefile
@@ -228,12 +226,14 @@ AC_CONFIG_FILES([
tests/zfs-tests/cmd/randfree_file/Makefile
tests/zfs-tests/cmd/randwritecomp/Makefile
tests/zfs-tests/cmd/readmmap/Makefile
+ tests/zfs-tests/cmd/read_dos_attributes/Makefile
tests/zfs-tests/cmd/rename_dir/Makefile
tests/zfs-tests/cmd/rm_lnkcnt_zero_file/Makefile
tests/zfs-tests/cmd/send_doall/Makefile
tests/zfs-tests/cmd/stride_dd/Makefile
tests/zfs-tests/cmd/threadsappend/Makefile
tests/zfs-tests/cmd/user_ns_exec/Makefile
+ tests/zfs-tests/cmd/write_dos_attributes/Makefile
tests/zfs-tests/cmd/xattrtest/Makefile
tests/zfs-tests/include/Makefile
tests/zfs-tests/tests/Makefile
@@ -335,6 +335,7 @@ AC_CONFIG_FILES([
tests/zfs-tests/tests/functional/deadman/Makefile
tests/zfs-tests/tests/functional/delegate/Makefile
tests/zfs-tests/tests/functional/devices/Makefile
+ tests/zfs-tests/tests/functional/dos_attributes/Makefile
tests/zfs-tests/tests/functional/events/Makefile
tests/zfs-tests/tests/functional/exec/Makefile
tests/zfs-tests/tests/functional/fallocate/Makefile
@@ -385,6 +386,7 @@ AC_CONFIG_FILES([
tests/zfs-tests/tests/functional/rootpool/Makefile
tests/zfs-tests/tests/functional/rsend/Makefile
tests/zfs-tests/tests/functional/scrub_mirror/Makefile
+ tests/zfs-tests/tests/functional/simd/Makefile
tests/zfs-tests/tests/functional/slog/Makefile
tests/zfs-tests/tests/functional/snapshot/Makefile
tests/zfs-tests/tests/functional/snapused/Makefile
diff --git a/sys/contrib/openzfs/contrib/Makefile.am b/sys/contrib/openzfs/contrib/Makefile.am
index f13b5f9f629c..5ec13ece5327 100644
--- a/sys/contrib/openzfs/contrib/Makefile.am
+++ b/sys/contrib/openzfs/contrib/Makefile.am
@@ -10,4 +10,3 @@ endif
DIST_SUBDIRS = bash_completion.d bpftrace dracut initramfs pam_zfs_key pyzfs zcp
SHELLCHECKDIRS = bash_completion.d bpftrace dracut initramfs
-SHELLCHECK_OPTS = --enable=all
diff --git a/sys/contrib/openzfs/contrib/bash_completion.d/Makefile.am b/sys/contrib/openzfs/contrib/bash_completion.d/Makefile.am
index f381613ed656..eee617802bbe 100644
--- a/sys/contrib/openzfs/contrib/bash_completion.d/Makefile.am
+++ b/sys/contrib/openzfs/contrib/bash_completion.d/Makefile.am
@@ -10,4 +10,3 @@ SUBSTFILES += $(noinst_DATA)
SHELLCHECKSCRIPTS = $(noinst_DATA)
SHELLCHECK_SHELL = bash
-SHELLCHECK_OPTS = --enable=all
diff --git a/sys/contrib/openzfs/contrib/bpftrace/Makefile.am b/sys/contrib/openzfs/contrib/bpftrace/Makefile.am
index 87732331f8f5..05e4f1c507ce 100644
--- a/sys/contrib/openzfs/contrib/bpftrace/Makefile.am
+++ b/sys/contrib/openzfs/contrib/bpftrace/Makefile.am
@@ -5,4 +5,3 @@ EXTRA_DIST = \
zfs-trace.sh
SHELLCHECKSCRIPTS = zfs-trace.sh
-SHELLCHECK_OPTS = --enable=all
diff --git a/sys/contrib/openzfs/contrib/dracut/02zfsexpandknowledge/Makefile.am b/sys/contrib/openzfs/contrib/dracut/02zfsexpandknowledge/Makefile.am
index cdf06202b7fc..b1bbb6bd3aac 100644
--- a/sys/contrib/openzfs/contrib/dracut/02zfsexpandknowledge/Makefile.am
+++ b/sys/contrib/openzfs/contrib/dracut/02zfsexpandknowledge/Makefile.am
@@ -5,5 +5,4 @@ pkgdracutdir = $(dracutdir)/modules.d/02zfsexpandknowledge
pkgdracut_SCRIPTS = \
module-setup.sh
-SHELLCHECK_OPTS = --enable=all
SUBSTFILES += $(pkgdracut_SCRIPTS)
diff --git a/sys/contrib/openzfs/contrib/dracut/02zfsexpandknowledge/module-setup.sh.in b/sys/contrib/openzfs/contrib/dracut/02zfsexpandknowledge/module-setup.sh.in
index a161fbf6f113..df8df3181fce 100755
--- a/sys/contrib/openzfs/contrib/dracut/02zfsexpandknowledge/module-setup.sh.in
+++ b/sys/contrib/openzfs/contrib/dracut/02zfsexpandknowledge/module-setup.sh.in
@@ -57,6 +57,12 @@ array_contains () {
}
check() {
+ # https://github.com/dracutdevs/dracut/pull/1711 provides a zfs_devs
+ # function to detect the physical devices backing zfs pools. If this
+ # function exists in the version of dracut this module is being called
+ # from, then it does not need to run.
+ type zfs_devs >/dev/null 2>&1 && return 1
+
local mp
local dev
local blockdevs
diff --git a/sys/contrib/openzfs/contrib/dracut/90zfs/Makefile.am b/sys/contrib/openzfs/contrib/dracut/90zfs/Makefile.am
index d25a3d250a55..3f7050300994 100644
--- a/sys/contrib/openzfs/contrib/dracut/90zfs/Makefile.am
+++ b/sys/contrib/openzfs/contrib/dracut/90zfs/Makefile.am
@@ -19,7 +19,6 @@ pkgdracut_DATA = \
zfs-rollback-bootfs.service
SUBSTFILES += $(pkgdracut_SCRIPTS) $(pkgdracut_DATA)
-SHELLCHECK_OPTS = --enable=all
# Provided by /bin/sleep, and, again, every implementation of that supports this
CHECKBASHISMS_IGNORE = -e 'sleep only takes one integer' -e 'sleep 0.'
diff --git a/sys/contrib/openzfs/contrib/dracut/90zfs/export-zfs.sh.in b/sys/contrib/openzfs/contrib/dracut/90zfs/export-zfs.sh.in
index 9ad72bd6f5cc..cfe059479436 100755
--- a/sys/contrib/openzfs/contrib/dracut/90zfs/export-zfs.sh.in
+++ b/sys/contrib/openzfs/contrib/dracut/90zfs/export-zfs.sh.in
@@ -1,30 +1,22 @@
#!/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
+ echo "${errs}" | vwarn
+ if [ "${ret}" -ne 0 ]; then
info "ZFS: There was a problem exporting pools."
fi
- if [ "x${final}" != "x" ]; then
+ if [ -n "$1" ]; then
info "ZFS: pool list"
zpool list 2>&1 | vinfo
fi
- return "${ret}"
+ return "$ret"
}
if command -v zpool >/dev/null; then
_do_zpool_export "${1}"
-else
- :
fi
diff --git a/sys/contrib/openzfs/contrib/dracut/90zfs/module-setup.sh.in b/sys/contrib/openzfs/contrib/dracut/90zfs/module-setup.sh.in
index 1eaff331eab4..c79323a3e613 100755
--- a/sys/contrib/openzfs/contrib/dracut/90zfs/module-setup.sh.in
+++ b/sys/contrib/openzfs/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,88 @@ 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 "${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 "${systemdsystemunitdir}/zfs-import.target"
+ systemctl -q --root "${initdir}" add-wants initrd.target zfs-import.target
- dracut_install systemd-ask-password
- dracut_install systemd-tty-ask-password-agent
+ 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
- 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" \
+ "zfs-load-module.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/sys/contrib/openzfs/contrib/dracut/90zfs/mount-zfs.sh.in b/sys/contrib/openzfs/contrib/dracut/90zfs/mount-zfs.sh.in
index 68e3f0e0d60b..7e11c9afdaee 100755
--- a/sys/contrib/openzfs/contrib/dracut/90zfs/mount-zfs.sh.in
+++ b/sys/contrib/openzfs/contrib/dracut/90zfs/mount-zfs.sh.in
@@ -44,7 +44,7 @@ if [ "${root}" = "zfs:AUTO" ] ; then
zpool import -N -a ${ZPOOL_IMPORT_OPTS}
if ! ZFS_DATASET="$(find_bootfs)" ; then
warn "ZFS: No bootfs attribute found in importable pools."
- export_all -F
+ zpool export -aF
rootok=0
return 1
diff --git a/sys/contrib/openzfs/contrib/dracut/90zfs/zfs-lib.sh.in b/sys/contrib/openzfs/contrib/dracut/90zfs/zfs-lib.sh.in
index d7c3e96c1213..afd872d69d58 100755
--- a/sys/contrib/openzfs/contrib/dracut/90zfs/zfs-lib.sh.in
+++ b/sys/contrib/openzfs/contrib/dracut/90zfs/zfs-lib.sh.in
@@ -122,22 +122,6 @@ 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
#
# Wraps around plymouth ask-for-password and adds fallback to tty password ask
diff --git a/sys/contrib/openzfs/contrib/dracut/90zfs/zfs-rollback-bootfs.service.in b/sys/contrib/openzfs/contrib/dracut/90zfs/zfs-rollback-bootfs.service.in
index bdc246943208..477b64f2b750 100644
--- a/sys/contrib/openzfs/contrib/dracut/90zfs/zfs-rollback-bootfs.service.in
+++ b/sys/contrib/openzfs/contrib/dracut/90zfs/zfs-rollback-bootfs.service.in
@@ -9,6 +9,6 @@ ConditionKernelCommandLine=bootfs.rollback
[Service]
# ${BOOTFS} should have been set by zfs-env-bootfs.service
Type=oneshot
-ExecStartPre=/bin/sh -c 'test -n "${BOOTFS}"'
+ExecStartPre=/bin/test -n ${BOOTFS}
ExecStart=/bin/sh -c '. /lib/dracut-lib.sh; SNAPNAME="$(getarg bootfs.rollback)"; exec @sbindir@/zfs rollback -Rf "${BOOTFS}@${SNAPNAME:-%v}"'
RemainAfterExit=yes
diff --git a/sys/contrib/openzfs/contrib/dracut/90zfs/zfs-snapshot-bootfs.service.in b/sys/contrib/openzfs/contrib/dracut/90zfs/zfs-snapshot-bootfs.service.in
index 6ea13850c3a7..8eae04adfb99 100644
--- a/sys/contrib/openzfs/contrib/dracut/90zfs/zfs-snapshot-bootfs.service.in
+++ b/sys/contrib/openzfs/contrib/dracut/90zfs/zfs-snapshot-bootfs.service.in
@@ -9,6 +9,6 @@ ConditionKernelCommandLine=bootfs.snapshot
[Service]
# ${BOOTFS} should have been set by zfs-env-bootfs.service
Type=oneshot
-ExecStartPre=/bin/sh -c 'test -n "${BOOTFS}"'
+ExecStartPre=/bin/test -n ${BOOTFS}
ExecStart=-/bin/sh -c '. /lib/dracut-lib.sh; SNAPNAME="$(getarg bootfs.snapshot)"; exec @sbindir@/zfs snapshot "${BOOTFS}@${SNAPNAME:-%v}"'
RemainAfterExit=yes
diff --git a/sys/contrib/openzfs/contrib/dracut/Makefile.am b/sys/contrib/openzfs/contrib/dracut/Makefile.am
index 8c9a6be0899a..09805277ffb0 100644
--- a/sys/contrib/openzfs/contrib/dracut/Makefile.am
+++ b/sys/contrib/openzfs/contrib/dracut/Makefile.am
@@ -3,4 +3,4 @@ include $(top_srcdir)/config/Shellcheck.am
SUBDIRS = 02zfsexpandknowledge 90zfs
SHELLCHECKDIRS = $(SUBDIRS)
-EXTRA_DIST = README.dracut.markdown
+EXTRA_DIST = README.md
diff --git a/sys/contrib/openzfs/contrib/dracut/README.dracut.markdown b/sys/contrib/openzfs/contrib/dracut/README.dracut.markdown
deleted file mode 100644
index f31543c3cf6b..000000000000
--- a/sys/contrib/openzfs/contrib/dracut/README.dracut.markdown
+++ /dev/null
@@ -1,225 +0,0 @@
-How to setup a zfs root filesystem using dracut
------------------------------------------------
-
-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.
-
-2) Set the bootfs property for the bootable dataset in the pool. Then set
-the dataset mountpoint property to '/'.
-
- $ zpool set bootfs=pool/dataset pool
- $ zfs set mountpoint=/ pool/dataset
-
-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'.
-
- $ grub.conf/menu.lst: kernel ... root=ZFS=pool/dataset
- $ zfs set mountpoint=legacy pool/dataset
-
-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.
-
-4) Finally, create your new initramfs by running dracut.
-
- $ dracut --force /path/to/initramfs kernel_version
-
-Kernel Command Line
--------------------
-
-The initramfs' behavior is influenced by the following kernel command line
-parameters passed in from the boot loader:
-
-* `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`
-
-* `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=<snapname>`: Is identical to the bootfs.snapshot parameter explained above except that the value substituted for \<snapname\> 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=<snapname>`: Is identical to the bootfs.rollback parameter explained above except that the value substituted for \<snapname\> 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.
diff --git a/sys/contrib/openzfs/contrib/dracut/README.md b/sys/contrib/openzfs/contrib/dracut/README.md
new file mode 100644
index 000000000000..fc3d504ef705
--- /dev/null
+++ b/sys/contrib/openzfs/contrib/dracut/README.md
@@ -0,0 +1,48 @@
+## 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
+
+Encrypted datasets have keys loaded automatically or prompted for.
+
+If the root dataset contains children with `mountpoint=`s of `/etc`, `/bin`, `/lib*`, or `/usr`, they're mounted too.
+
+## cmdline
+1. `root=` | Root dataset is… | Pools imported |
+ -------------------|----------------------------------------------------------|----------------|
+ *(empty)* | the first `bootfs=` after `zpool import -aN` | all |
+ `zfs:AUTO` | *(as above, but overriding other autoselection methods)* | all |
+ `ZFS=pool/dataset` | `pool/dataset` | `pool` |
+ `zfs:pool/dataset` | *(as above)* | `pool` |
+
+ All `+`es are replaced with spaces (i.e. to boot from `root pool/data set`, pass `root=zfs:root+pool/data+set`).
+
+ The dataset can be at any depth, including being the pool's root dataset (i.e. `root=zfs:pool`).
+
+ `rootfstype=zfs` is mostly equivalent to `root=zfs:AUTO`.
+
+2. `spl_hostid`: passed to `zgenhostid -f`, useful to override the `/etc/hostid` file baked into the initrd.
+
+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.
+
+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.
+
+5. If both `bootfs.snapshot` and `bootfs.rollback` are set, `bootfs.rollback` is ordered *after* `bootfs.snapshot`.
+
+6. `zfs_force`, `zfs.force`, `zfsforce`: add `-f` to all `zpool import` invocations.
+ May be useful. Use with caution.
diff --git a/sys/contrib/openzfs/contrib/initramfs/Makefile.am b/sys/contrib/openzfs/contrib/initramfs/Makefile.am
index 76e66216c40b..57e8f5c3a485 100644
--- a/sys/contrib/openzfs/contrib/initramfs/Makefile.am
+++ b/sys/contrib/openzfs/contrib/initramfs/Makefile.am
@@ -7,7 +7,5 @@ dist_initrd_SCRIPTS = \
SUBDIRS = conf.d conf-hooks.d hooks scripts
SHELLCHECKDIRS = hooks scripts
-SHELLCHECK_OPTS = --enable=all
-EXTRA_DIST = \
- README.initramfs.markdown
+EXTRA_DIST = README.md
diff --git a/sys/contrib/openzfs/contrib/initramfs/README.initramfs.markdown b/sys/contrib/openzfs/contrib/initramfs/README.md
index 34e9bab3c756..34e9bab3c756 100644
--- a/sys/contrib/openzfs/contrib/initramfs/README.initramfs.markdown
+++ b/sys/contrib/openzfs/contrib/initramfs/README.md
diff --git a/sys/contrib/openzfs/contrib/initramfs/hooks/Makefile.am b/sys/contrib/openzfs/contrib/initramfs/hooks/Makefile.am
index 7fb7a75285e1..0cd1aafcd359 100644
--- a/sys/contrib/openzfs/contrib/initramfs/hooks/Makefile.am
+++ b/sys/contrib/openzfs/contrib/initramfs/hooks/Makefile.am
@@ -7,5 +7,4 @@ hooks_SCRIPTS = \
zfs \
zfsunlock
-SHELLCHECK_OPTS = --enable=all
SUBSTFILES += $(hooks_SCRIPTS)
diff --git a/sys/contrib/openzfs/contrib/initramfs/scripts/Makefile.am b/sys/contrib/openzfs/contrib/initramfs/scripts/Makefile.am
index 470fd792b13a..444a5f374bfe 100644
--- a/sys/contrib/openzfs/contrib/initramfs/scripts/Makefile.am
+++ b/sys/contrib/openzfs/contrib/initramfs/scripts/Makefile.am
@@ -9,4 +9,3 @@ SUBDIRS = local-top
SHELLCHECKDIRS = $(SUBDIRS)
SHELLCHECK_SHELL = sh
-SHELLCHECK_OPTS = --enable=all
diff --git a/sys/contrib/openzfs/contrib/initramfs/scripts/local-top/Makefile.am b/sys/contrib/openzfs/contrib/initramfs/scripts/local-top/Makefile.am
index a4bb907dd184..f3dc23129f09 100644
--- a/sys/contrib/openzfs/contrib/initramfs/scripts/local-top/Makefile.am
+++ b/sys/contrib/openzfs/contrib/initramfs/scripts/local-top/Makefile.am
@@ -5,4 +5,3 @@ localtopdir = /usr/share/initramfs-tools/scripts/local-top
dist_localtop_SCRIPTS = \
zfs
-SHELLCHECK_OPTS = --enable=all
diff --git a/sys/contrib/openzfs/contrib/pam_zfs_key/pam_zfs_key.c b/sys/contrib/openzfs/contrib/pam_zfs_key/pam_zfs_key.c
index 9702189f6702..f831f65af1d8 100644
--- a/sys/contrib/openzfs/contrib/pam_zfs_key/pam_zfs_key.c
+++ b/sys/contrib/openzfs/contrib/pam_zfs_key/pam_zfs_key.c
@@ -47,6 +47,7 @@
static void
pam_syslog(pam_handle_t *pamh, int loglevel, const char *fmt, ...)
{
+ (void) pamh;
va_list args;
va_start(args, fmt);
vsyslog(loglevel, fmt, args);
diff --git a/sys/contrib/openzfs/contrib/pyzfs/libzfs_core/test/test_libzfs_core.py b/sys/contrib/openzfs/contrib/pyzfs/libzfs_core/test/test_libzfs_core.py
index d949d88d5a1e..2567f7ebf83d 100644
--- a/sys/contrib/openzfs/contrib/pyzfs/libzfs_core/test/test_libzfs_core.py
+++ b/sys/contrib/openzfs/contrib/pyzfs/libzfs_core/test/test_libzfs_core.py
@@ -4132,7 +4132,8 @@ class _TempPool(object):
cachefile = 'none'
self._zpool_create = [
'zpool', 'create', '-o', 'cachefile=' + cachefile,
- '-O', 'mountpoint=legacy', self._pool_name, self._pool_file_path]
+ '-O', 'mountpoint=legacy', '-O', 'compression=off',
+ self._pool_name, self._pool_file_path]
try:
os.ftruncate(fd, size)
os.close(fd)
diff --git a/sys/contrib/openzfs/etc/Makefile.am b/sys/contrib/openzfs/etc/Makefile.am
index 4d2002036102..179c2400978c 100644
--- a/sys/contrib/openzfs/etc/Makefile.am
+++ b/sys/contrib/openzfs/etc/Makefile.am
@@ -2,7 +2,6 @@ include $(top_srcdir)/config/Shellcheck.am
SUBDIRS = zfs sudoers.d
SHELLCHECKDIRS = default $(ZFS_INIT_SYSV) zfs
-SHELLCHECK_OPTS = --enable=all
if BUILD_LINUX
SUBDIRS += default $(ZFS_INIT_SYSTEMD) $(ZFS_INIT_SYSV) $(ZFS_MODULE_LOAD)
diff --git a/sys/contrib/openzfs/etc/default/Makefile.am b/sys/contrib/openzfs/etc/default/Makefile.am
index 74a4edd62873..0f7c96698d45 100644
--- a/sys/contrib/openzfs/etc/default/Makefile.am
+++ b/sys/contrib/openzfs/etc/default/Makefile.am
@@ -5,5 +5,4 @@ initconf_SCRIPTS = zfs
SUBSTFILES += $(initconf_SCRIPTS)
-SHELLCHECK_SHELL = dash
-SHELLCHECK_OPTS = --enable=all
+SHELLCHECK_SHELL = sh
diff --git a/sys/contrib/openzfs/etc/init.d/Makefile.am b/sys/contrib/openzfs/etc/init.d/Makefile.am
index c336d607551d..625d0b91fd11 100644
--- a/sys/contrib/openzfs/etc/init.d/Makefile.am
+++ b/sys/contrib/openzfs/etc/init.d/Makefile.am
@@ -7,5 +7,4 @@ init_SCRIPTS = zfs-import zfs-load-key zfs-mount zfs-share zfs-zed
SUBSTFILES += $(init_SCRIPTS)
-SHELLCHECK_SHELL = dash
-SHELLCHECK_OPTS = --enable=all
+SHELLCHECK_SHELL = sh
diff --git a/sys/contrib/openzfs/etc/systemd/system/zfs-import-cache.service.in b/sys/contrib/openzfs/etc/systemd/system/zfs-import-cache.service.in
index 5e5c6281c9d7..08c11698bcce 100644
--- a/sys/contrib/openzfs/etc/systemd/system/zfs-import-cache.service.in
+++ b/sys/contrib/openzfs/etc/systemd/system/zfs-import-cache.service.in
@@ -14,6 +14,7 @@ ConditionPathIsDirectory=/sys/module/zfs
[Service]
Type=oneshot
RemainAfterExit=yes
+EnvironmentFile=-@initconfdir@/zfs
ExecStart=@sbindir@/zpool import -c @sysconfdir@/zfs/zpool.cache -aN $ZPOOL_IMPORT_OPTS
[Install]
diff --git a/sys/contrib/openzfs/etc/systemd/system/zfs-import-scan.service.in b/sys/contrib/openzfs/etc/systemd/system/zfs-import-scan.service.in
index d3c083f7e9cf..c37f70f13b71 100644
--- a/sys/contrib/openzfs/etc/systemd/system/zfs-import-scan.service.in
+++ b/sys/contrib/openzfs/etc/systemd/system/zfs-import-scan.service.in
@@ -13,6 +13,7 @@ ConditionPathIsDirectory=/sys/module/zfs
[Service]
Type=oneshot
RemainAfterExit=yes
+EnvironmentFile=-@initconfdir@/zfs
ExecStart=@sbindir@/zpool import -aN -o cachefile=none $ZPOOL_IMPORT_OPTS
[Install]
diff --git a/sys/contrib/openzfs/etc/systemd/system/zfs-mount.service.in b/sys/contrib/openzfs/etc/systemd/system/zfs-mount.service.in
index 3ab82fb033c1..66d894923f4a 100644
--- a/sys/contrib/openzfs/etc/systemd/system/zfs-mount.service.in
+++ b/sys/contrib/openzfs/etc/systemd/system/zfs-mount.service.in
@@ -11,6 +11,7 @@ ConditionPathIsDirectory=/sys/module/zfs
[Service]
Type=oneshot
RemainAfterExit=yes
+EnvironmentFile=-@initconfdir@/zfs
ExecStart=@sbindir@/zfs mount -a
[Install]
diff --git a/sys/contrib/openzfs/etc/systemd/system/zfs-scrub@.service.in b/sys/contrib/openzfs/etc/systemd/system/zfs-scrub@.service.in
index bebe91d746ae..8ffffeb0cf6c 100644
--- a/sys/contrib/openzfs/etc/systemd/system/zfs-scrub@.service.in
+++ b/sys/contrib/openzfs/etc/systemd/system/zfs-scrub@.service.in
@@ -7,8 +7,9 @@ ConditionACPower=true
ConditionPathIsDirectory=/sys/module/zfs
[Service]
+EnvironmentFile=-@initconfdir@/zfs
ExecStart=/bin/sh -c '\
-if @sbindir@/zpool status %i | grep "scrub in progress"; then\
+if @sbindir@/zpool status %i | grep -q "scrub in progress"; then\
exec @sbindir@/zpool wait -t scrub %i;\
else exec @sbindir@/zpool scrub -w %i; fi'
ExecStop=-/bin/sh -c '@sbindir@/zpool scrub -p %i 2>/dev/null || true'
diff --git a/sys/contrib/openzfs/etc/systemd/system/zfs-share.service.in b/sys/contrib/openzfs/etc/systemd/system/zfs-share.service.in
index 745077513c30..263055e5281f 100644
--- a/sys/contrib/openzfs/etc/systemd/system/zfs-share.service.in
+++ b/sys/contrib/openzfs/etc/systemd/system/zfs-share.service.in
@@ -13,6 +13,7 @@ ConditionPathIsDirectory=/sys/module/zfs
[Service]
Type=oneshot
RemainAfterExit=yes
+EnvironmentFile=-@initconfdir@/zfs
ExecStart=@sbindir@/zfs share -a
[Install]
diff --git a/sys/contrib/openzfs/etc/systemd/system/zfs-volume-wait.service.in b/sys/contrib/openzfs/etc/systemd/system/zfs-volume-wait.service.in
index 4c77724d8bbb..110c0f5f52ee 100644
--- a/sys/contrib/openzfs/etc/systemd/system/zfs-volume-wait.service.in
+++ b/sys/contrib/openzfs/etc/systemd/system/zfs-volume-wait.service.in
@@ -8,6 +8,7 @@ ConditionPathIsDirectory=/sys/module/zfs
[Service]
Type=oneshot
RemainAfterExit=yes
+EnvironmentFile=-@initconfdir@/zfs
ExecStart=@bindir@/zvol_wait
[Install]
diff --git a/sys/contrib/openzfs/etc/systemd/system/zfs-zed.service.in b/sys/contrib/openzfs/etc/systemd/system/zfs-zed.service.in
index 008075138f02..73a83e59e510 100644
--- a/sys/contrib/openzfs/etc/systemd/system/zfs-zed.service.in
+++ b/sys/contrib/openzfs/etc/systemd/system/zfs-zed.service.in
@@ -4,6 +4,7 @@ Documentation=man:zed(8)
ConditionPathIsDirectory=/sys/module/zfs
[Service]
+EnvironmentFile=-@initconfdir@/zfs
ExecStart=@sbindir@/zed -F
Restart=on-abort
diff --git a/sys/contrib/openzfs/etc/zfs/Makefile.am b/sys/contrib/openzfs/etc/zfs/Makefile.am
index b7dbd33ccf49..8a67d548bf7e 100644
--- a/sys/contrib/openzfs/etc/zfs/Makefile.am
+++ b/sys/contrib/openzfs/etc/zfs/Makefile.am
@@ -15,5 +15,4 @@ pkgsysconf_SCRIPTS = \
SUBSTFILES += $(pkgsysconf_SCRIPTS)
-SHELLCHECK_OPTS = --enable=all
-SHELLCHECK_SHELL = dash
+SHELLCHECK_SHELL = sh
diff --git a/sys/contrib/openzfs/include/libuutil.h b/sys/contrib/openzfs/include/libuutil.h
index cadc20d2d8f3..043152ac26b5 100644
--- a/sys/contrib/openzfs/include/libuutil.h
+++ b/sys/contrib/openzfs/include/libuutil.h
@@ -85,14 +85,14 @@ extern void uu_warn(const char *, ...)
__attribute__((format(printf, 1, 2)));
extern void uu_vwarn(const char *, va_list)
__attribute__((format(printf, 1, 0)));
-extern void uu_die(const char *, ...)
- __attribute__((format(printf, 1, 2))) __NORETURN;
-extern void uu_vdie(const char *, va_list)
- __attribute__((format(printf, 1, 0))) __NORETURN;
-extern void uu_xdie(int, const char *, ...)
- __attribute__((format(printf, 2, 3))) __NORETURN;
-extern void uu_vxdie(int, const char *, va_list)
- __attribute__((format(printf, 2, 0))) __NORETURN;
+extern _Noreturn void uu_die(const char *, ...)
+ __attribute__((format(printf, 1, 2)));
+extern _Noreturn void uu_vdie(const char *, va_list)
+ __attribute__((format(printf, 1, 0)));
+extern _Noreturn void uu_xdie(int, const char *, ...)
+ __attribute__((format(printf, 2, 3)));
+extern _Noreturn void uu_vxdie(int, const char *, va_list)
+ __attribute__((format(printf, 2, 0)));
/*
* Exit status functions (not to be used directly)
diff --git a/sys/contrib/openzfs/include/libzfs.h b/sys/contrib/openzfs/include/libzfs.h
index fe70a5b3a6fd..c0e53b88a636 100644
--- a/sys/contrib/openzfs/include/libzfs.h
+++ b/sys/contrib/openzfs/include/libzfs.h
@@ -553,8 +553,8 @@ _LIBZFS_H int zfs_crypto_create(libzfs_handle_t *, char *, nvlist_t *,
nvlist_t *, boolean_t stdin_available, uint8_t **, uint_t *);
_LIBZFS_H int zfs_crypto_clone_check(libzfs_handle_t *, zfs_handle_t *, char *,
nvlist_t *);
-_LIBZFS_H int zfs_crypto_attempt_load_keys(libzfs_handle_t *, char *);
-_LIBZFS_H int zfs_crypto_load_key(zfs_handle_t *, boolean_t, char *);
+_LIBZFS_H int zfs_crypto_attempt_load_keys(libzfs_handle_t *, const char *);
+_LIBZFS_H int zfs_crypto_load_key(zfs_handle_t *, boolean_t, const char *);
_LIBZFS_H int zfs_crypto_unload_key(zfs_handle_t *);
_LIBZFS_H int zfs_crypto_rewrap(zfs_handle_t *, nvlist_t *, boolean_t);
diff --git a/sys/contrib/openzfs/include/libzfs_core.h b/sys/contrib/openzfs/include/libzfs_core.h
index 7acc03fc71bb..b826e94c4c18 100644
--- a/sys/contrib/openzfs/include/libzfs_core.h
+++ b/sys/contrib/openzfs/include/libzfs_core.h
@@ -86,6 +86,7 @@ enum lzc_send_flags {
LZC_SEND_FLAG_SAVED = 1 << 4,
};
+_LIBZFS_CORE_H int lzc_send_wrapper(int (*)(int, void *), int, void *);
_LIBZFS_CORE_H int lzc_send(const char *, const char *, int,
enum lzc_send_flags);
_LIBZFS_CORE_H int lzc_send_resume(const char *, const char *, int,
diff --git a/sys/contrib/openzfs/include/os/freebsd/linux/compiler.h b/sys/contrib/openzfs/include/os/freebsd/linux/compiler.h
index 20903717b58d..3a66da195891 100644
--- a/sys/contrib/openzfs/include/os/freebsd/linux/compiler.h
+++ b/sys/contrib/openzfs/include/os/freebsd/linux/compiler.h
@@ -67,7 +67,7 @@
#define __always_inline inline
#define noinline __noinline
#define ____cacheline_aligned __aligned(CACHE_LINE_SIZE)
-#define fallthrough __attribute__((__fallthrough__))
+#define zfs_fallthrough __attribute__((__fallthrough__))
#if !defined(_KERNEL) && !defined(_STANDALONE)
#define likely(x) __builtin_expect(!!(x), 1)
diff --git a/sys/contrib/openzfs/include/os/freebsd/spl/sys/ccompat.h b/sys/contrib/openzfs/include/os/freebsd/spl/sys/ccompat.h
index 59abe921dba9..eaee9159eabd 100644
--- a/sys/contrib/openzfs/include/os/freebsd/spl/sys/ccompat.h
+++ b/sys/contrib/openzfs/include/os/freebsd/spl/sys/ccompat.h
@@ -82,18 +82,17 @@ typedef struct {
volatile int counter;
} atomic_t;
- /* BEGIN CSTYLED */
#define hlist_for_each(p, head) \
for (p = (head)->first; p; p = (p)->next)
#define hlist_entry(ptr, type, field) container_of(ptr, type, field)
#define container_of(ptr, type, member) \
+/* CSTYLED */ \
({ \
- const __typeof(((type *)0)->member) *__p = (ptr); \
- (type *)((uintptr_t)__p - offsetof(type, member)); \
+ const __typeof(((type *)0)->member) *__p = (ptr); \
+ (type *)((uintptr_t)__p - offsetof(type, member)); \
})
- /* END CSTYLED */
static inline void
hlist_add_head(struct hlist_node *n, struct hlist_head *h)
diff --git a/sys/contrib/openzfs/include/os/freebsd/spl/sys/ctype.h b/sys/contrib/openzfs/include/os/freebsd/spl/sys/ctype.h
index f225858072ab..53afd8b8bd42 100644
--- a/sys/contrib/openzfs/include/os/freebsd/spl/sys/ctype.h
+++ b/sys/contrib/openzfs/include/os/freebsd/spl/sys/ctype.h
@@ -34,12 +34,10 @@
#define isalnum(ch) (isalpha(ch) || isdigit(ch))
#define iscntrl(C) (uchar(C) <= 0x1f || uchar(C) == 0x7f)
#define isgraph(C) ((C) >= 0x21 && (C) <= 0x7E)
-/* BEGIN CSTYLED */
-#define ispunct(C) \
- (((C) >= 0x21 && (C) <= 0x2F) || \
- ((C) >= 0x3A && (C) <= 0x40) || \
- ((C) >= 0x5B && (C) <= 0x60) || \
- ((C) >= 0x7B && (C) <= 0x7E))
-/* END CSTYLED */
+#define ispunct(C) \
+ (((C) >= 0x21 && (C) <= 0x2F) || \
+ ((C) >= 0x3A && (C) <= 0x40) || \
+ ((C) >= 0x5B && (C) <= 0x60) || \
+ ((C) >= 0x7B && (C) <= 0x7E))
#endif
diff --git a/sys/contrib/openzfs/include/os/freebsd/spl/sys/debug.h b/sys/contrib/openzfs/include/os/freebsd/spl/sys/debug.h
index 6df76db7eadf..86fad18e17d2 100644
--- a/sys/contrib/openzfs/include/os/freebsd/spl/sys/debug.h
+++ b/sys/contrib/openzfs/include/os/freebsd/spl/sys/debug.h
@@ -64,83 +64,87 @@ void spl_dumpstack(void);
#define likely(expr) expect((expr) != 0, 1)
#define unlikely(expr) expect((expr) != 0, 0)
-/* BEGIN CSTYLED */
#define PANIC(fmt, a...) \
spl_panic(__FILE__, __FUNCTION__, __LINE__, fmt, ## a)
-#define VERIFY(cond) \
- (void) (unlikely(!(cond)) && \
+#define VERIFY(cond) \
+ (void) (unlikely(!(cond)) && \
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
"%s", "VERIFY(" #cond ") failed\n"))
-#define VERIFY3B(LEFT, OP, RIGHT) do { \
+#define VERIFY3B(LEFT, OP, RIGHT) do { \
const boolean_t _verify3_left = (boolean_t)(LEFT); \
- const boolean_t _verify3_right = (boolean_t)(RIGHT);\
+ const boolean_t _verify3_right = (boolean_t)(RIGHT); \
if (unlikely(!(_verify3_left OP _verify3_right))) \
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
- "failed (%d " #OP " %d)\n", \
- (boolean_t) (_verify3_left), \
- (boolean_t) (_verify3_right)); \
+ "failed (%d " #OP " %d)\n", \
+ (boolean_t)(_verify3_left), \
+ (boolean_t)(_verify3_right)); \
} while (0)
-#define VERIFY3S(LEFT, OP, RIGHT) do { \
+#define VERIFY3S(LEFT, OP, RIGHT) do { \
const int64_t _verify3_left = (int64_t)(LEFT); \
const int64_t _verify3_right = (int64_t)(RIGHT); \
if (unlikely(!(_verify3_left OP _verify3_right))) \
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
- "failed (%lld " #OP " %lld)\n", \
- (long long) (_verify3_left), \
- (long long) (_verify3_right)); \
+ "failed (%lld " #OP " %lld)\n", \
+ (long long) (_verify3_left), \
+ (long long) (_verify3_right)); \
} while (0)
-#define VERIFY3U(LEFT, OP, RIGHT) do { \
+#define VERIFY3U(LEFT, OP, RIGHT) do { \
const uint64_t _verify3_left = (uint64_t)(LEFT); \
const uint64_t _verify3_right = (uint64_t)(RIGHT); \
if (unlikely(!(_verify3_left OP _verify3_right))) \
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
- "failed (%llu " #OP " %llu)\n", \
- (unsigned long long) (_verify3_left), \
- (unsigned long long) (_verify3_right)); \
+ "failed (%llu " #OP " %llu)\n", \
+ (unsigned long long) (_verify3_left), \
+ (unsigned long long) (_verify3_right)); \
} while (0)
-#define VERIFY3P(LEFT, OP, RIGHT) do { \
+#define VERIFY3P(LEFT, OP, RIGHT) do { \
const uintptr_t _verify3_left = (uintptr_t)(LEFT); \
- const uintptr_t _verify3_right = (uintptr_t)(RIGHT);\
+ const uintptr_t _verify3_right = (uintptr_t)(RIGHT); \
if (unlikely(!(_verify3_left OP _verify3_right))) \
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
- "failed (%px " #OP " %px)\n", \
- (void *) (_verify3_left), \
- (void *) (_verify3_right)); \
+ "failed (%px " #OP " %px)\n", \
+ (void *) (_verify3_left), \
+ (void *) (_verify3_right)); \
} while (0)
-#define VERIFY0(RIGHT) do { \
- const int64_t _verify3_left = (int64_t)(0); \
+#define VERIFY0(RIGHT) do { \
+ const int64_t _verify3_left = (int64_t)(0); \
const int64_t _verify3_right = (int64_t)(RIGHT); \
if (unlikely(!(_verify3_left == _verify3_right))) \
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
- "VERIFY3(0 == " #RIGHT ") " \
- "failed (0 == %lld)\n", \
- (long long) (_verify3_right)); \
+ "VERIFY3(0 == " #RIGHT ") " \
+ "failed (0 == %lld)\n", \
+ (long long) (_verify3_right)); \
} while (0)
-#define CTASSERT_GLOBAL(x) CTASSERT(x)
/*
* Debugging disabled (--disable-debug)
*/
#ifdef NDEBUG
-#define ASSERT(x) ((void) sizeof (!!(x)))
-#define ASSERT3B(x,y,z) ((void) sizeof (!!(x)), (void) sizeof (!!(z)))
-#define ASSERT3S(x,y,z) ((void) sizeof (!!(x)), (void) sizeof (!!(z)))
-#define ASSERT3U(x,y,z) ((void) sizeof (!!(x)), (void) sizeof (!!(z)))
-#define ASSERT3P(x,y,z) ((void) sizeof (!!(x)), (void) sizeof (!!(z)))
-#define ASSERT0(x) ((void) sizeof (!!(x)))
-#define IMPLY(A, B) ((void) sizeof (!!(A)), (void) sizeof (!!(B)))
-#define EQUIV(A, B) ((void) sizeof (!!(A)), (void) sizeof (!!(B)))
+#define ASSERT(x) ((void) sizeof ((uintptr_t)(x)))
+#define ASSERT3B(x, y, z) \
+ ((void) sizeof ((uintptr_t)(x)), (void) sizeof ((uintptr_t)(z)))
+#define ASSERT3S(x, y, z) \
+ ((void) sizeof ((uintptr_t)(x)), (void) sizeof ((uintptr_t)(z)))
+#define ASSERT3U(x, y, z) \
+ ((void) sizeof ((uintptr_t)(x)), (void) sizeof ((uintptr_t)(z)))
+#define ASSERT3P(x, y, z) \
+ ((void) sizeof ((uintptr_t)(x)), (void) sizeof ((uintptr_t)(z)))
+#define ASSERT0(x) ((void) sizeof ((uintptr_t)(x)))
+#define IMPLY(A, B) \
+ ((void) sizeof ((uintptr_t)(A)), (void) sizeof ((uintptr_t)(B)))
+#define EQUIV(A, B) \
+ ((void) sizeof ((uintptr_t)(A)), (void) sizeof ((uintptr_t)(B)))
/*
* Debugging enabled (--enable-debug)
@@ -161,7 +165,6 @@ void spl_dumpstack(void);
((void)(likely(!!(A) == !!(B)) || \
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
"(" #A ") is equivalent to (" #B ")")))
-/* END CSTYLED */
#endif /* NDEBUG */
diff --git a/sys/contrib/openzfs/include/os/freebsd/spl/sys/mod_os.h b/sys/contrib/openzfs/include/os/freebsd/spl/sys/mod_os.h
index 5695abee7b85..293bd7d2b983 100644
--- a/sys/contrib/openzfs/include/os/freebsd/spl/sys/mod_os.h
+++ b/sys/contrib/openzfs/include/os/freebsd/spl/sys/mod_os.h
@@ -43,10 +43,10 @@
#define ZMOD_RW CTLFLAG_RWTUN
#define ZMOD_RD CTLFLAG_RDTUN
-/* BEGIN CSTYLED */
#define ZFS_MODULE_PARAM(scope_prefix, name_prefix, name, type, perm, desc) \
SYSCTL_DECL(_vfs_ ## scope_prefix); \
- SYSCTL_##type(_vfs_ ## scope_prefix, OID_AUTO, name, perm, &name_prefix ## name, 0, desc)
+ SYSCTL_##type(_vfs_ ## scope_prefix, OID_AUTO, name, perm, \
+ &name_prefix ## name, 0, desc)
#define ZFS_MODULE_PARAM_ARGS SYSCTL_HANDLER_ARGS
@@ -54,8 +54,10 @@
SYSCTL_DECL(parent); \
SYSCTL_PROC(parent, OID_AUTO, name, perm | args, desc)
-#define ZFS_MODULE_PARAM_CALL(scope_prefix, name_prefix, name, func, _, perm, desc) \
- ZFS_MODULE_PARAM_CALL_IMPL(_vfs_ ## scope_prefix, name, perm, func ## _args(name_prefix ## name), desc)
+#define ZFS_MODULE_PARAM_CALL( \
+ scope_prefix, name_prefix, name, func, _, perm, desc) \
+ ZFS_MODULE_PARAM_CALL_IMPL(_vfs_ ## scope_prefix, name, perm, \
+ func ## _args(name_prefix ## name), desc)
#define ZFS_MODULE_VIRTUAL_PARAM_CALL ZFS_MODULE_PARAM_CALL
@@ -96,29 +98,28 @@
CTLTYPE_STRING, NULL, 0, fletcher_4_param, "A"
#include <sys/kernel.h>
-#define module_init(fn) \
+#define module_init(fn) \
static void \
wrap_ ## fn(void *dummy __unused) \
-{ \
- fn(); \
-} \
+{ \
+ fn(); \
+} \
SYSINIT(zfs_ ## fn, SI_SUB_LAST, SI_ORDER_FIRST, wrap_ ## fn, NULL)
-#define module_init_early(fn) \
+#define module_init_early(fn) \
static void \
wrap_ ## fn(void *dummy __unused) \
-{ \
- fn(); \
-} \
+{ \
+ fn(); \
+} \
SYSINIT(zfs_ ## fn, SI_SUB_INT_CONFIG_HOOKS, SI_ORDER_FIRST, wrap_ ## fn, NULL)
-#define module_exit(fn) \
+#define module_exit(fn) \
static void \
wrap_ ## fn(void *dummy __unused) \
-{ \
- fn(); \
-} \
+{ \
+ fn(); \
+} \
SYSUNINIT(zfs_ ## fn, SI_SUB_LAST, SI_ORDER_FIRST, wrap_ ## fn, NULL)
-/* END CSTYLED */
#endif /* SPL_MOD_H */
diff --git a/sys/contrib/openzfs/include/os/freebsd/spl/sys/rwlock.h b/sys/contrib/openzfs/include/os/freebsd/spl/sys/rwlock.h
index 10107a9bee84..5146870790cd 100644
--- a/sys/contrib/openzfs/include/os/freebsd/spl/sys/rwlock.h
+++ b/sys/contrib/openzfs/include/os/freebsd/spl/sys/rwlock.h
@@ -48,22 +48,18 @@ typedef enum {
typedef struct sx krwlock_t;
#ifndef OPENSOLARIS_WITNESS
-#define RW_FLAGS (SX_DUPOK | SX_NOWITNESS)
+#define RW_FLAGS (SX_DUPOK | SX_NEW | SX_NOWITNESS)
#else
-#define RW_FLAGS (SX_DUPOK)
+#define RW_FLAGS (SX_DUPOK | SX_NEW)
#endif
#define RW_READ_HELD(x) (rw_read_held((x)))
#define RW_WRITE_HELD(x) (rw_write_held((x)))
#define RW_LOCK_HELD(x) (rw_lock_held((x)))
#define RW_ISWRITER(x) (rw_iswriter(x))
-/* BEGIN CSTYLED */
#define rw_init(lock, desc, type, arg) do { \
const char *_name; \
ASSERT((type) == 0 || (type) == RW_DEFAULT); \
- KASSERT(((lock)->lock_object.lo_flags & LO_ALLMASK) != \
- LO_EXPECTED, ("lock %s already initialized", #lock)); \
- bzero((lock), sizeof(struct sx)); \
for (_name = #lock; *_name != '\0'; _name++) { \
if (*_name >= 'a' && *_name <= 'z') \
break; \
@@ -87,11 +83,10 @@ typedef struct sx krwlock_t;
#define rw_tryupgrade(lock) sx_try_upgrade(lock)
#define rw_read_held(lock) \
((lock)->sx_lock != SX_LOCK_UNLOCKED && \
- ((lock)->sx_lock & SX_LOCK_SHARED))
+ ((lock)->sx_lock & SX_LOCK_SHARED))
#define rw_write_held(lock) sx_xlocked(lock)
#define rw_lock_held(lock) (rw_read_held(lock) || rw_write_held(lock))
#define rw_iswriter(lock) sx_xlocked(lock)
#define rw_owner(lock) sx_xholder(lock)
-/* END CSTYLED */
#endif /* _OPENSOLARIS_SYS_RWLOCK_H_ */
diff --git a/sys/contrib/openzfs/include/os/freebsd/spl/sys/sdt.h b/sys/contrib/openzfs/include/os/freebsd/spl/sys/sdt.h
index 496fc58d7c7b..2daa6de1af08 100644
--- a/sys/contrib/openzfs/include/os/freebsd/spl/sys/sdt.h
+++ b/sys/contrib/openzfs/include/os/freebsd/spl/sys/sdt.h
@@ -30,8 +30,8 @@
#define _OPENSOLARIS_SYS_SDT_H_
#include_next <sys/sdt.h>
-/* BEGIN CSTYLED */
#ifdef KDTRACE_HOOKS
+/* CSTYLED */
SDT_PROBE_DECLARE(sdt, , , set__error);
#define SET_ERROR(err) \
diff --git a/sys/contrib/openzfs/include/os/freebsd/spl/sys/types.h b/sys/contrib/openzfs/include/os/freebsd/spl/sys/types.h
index ecb91fd1bb89..b2897978c2d8 100644
--- a/sys/contrib/openzfs/include/os/freebsd/spl/sys/types.h
+++ b/sys/contrib/openzfs/include/os/freebsd/spl/sys/types.h
@@ -64,8 +64,8 @@ typedef u_int uint_t;
typedef u_char uchar_t;
typedef u_short ushort_t;
typedef u_long ulong_t;
-typedef int minor_t;
/* END CSTYLED */
+typedef int minor_t;
#ifndef _OFF64_T_DECLARED
#define _OFF64_T_DECLARED
typedef off_t off64_t;
diff --git a/sys/contrib/openzfs/include/os/freebsd/zfs/sys/freebsd_crypto.h b/sys/contrib/openzfs/include/os/freebsd/zfs/sys/freebsd_crypto.h
index a3ed4182656c..a61a6cd88c13 100644
--- a/sys/contrib/openzfs/include/os/freebsd/zfs/sys/freebsd_crypto.h
+++ b/sys/contrib/openzfs/include/os/freebsd/zfs/sys/freebsd_crypto.h
@@ -42,8 +42,6 @@
#define SUN_CKM_AES_GCM "CKM_AES_GCM"
#define SUN_CKM_SHA512_HMAC "CKM_SHA512_HMAC"
-#define CRYPTO_KEY_RAW 1
-
#define CRYPTO_BITS2BYTES(n) ((n) == 0 ? 0 : (((n) - 1) >> 3) + 1)
#define CRYPTO_BYTES2BITS(n) ((n) << 3)
@@ -61,12 +59,11 @@ typedef struct freebsd_crypt_session {
typedef void *crypto_mechanism_t;
typedef void *crypto_ctx_template_t;
/*
- * Unlike the ICP crypto_key type, this only
+ * Like the ICP crypto_key type, this only
* supports <data, length> (the equivalent of
- * CRYPTO_KEY_RAW).
+ * the former CRYPTO_KEY_RAW).
*/
typedef struct crypto_key {
- int ck_format; /* Unused, but minimizes code diff */
void *ck_data;
size_t ck_length;
} crypto_key_t;
diff --git a/sys/contrib/openzfs/include/os/freebsd/zfs/sys/sha2.h b/sys/contrib/openzfs/include/os/freebsd/zfs/sys/sha2.h
index e3923e4ca37c..c3bc33d2f6bb 100644
--- a/sys/contrib/openzfs/include/os/freebsd/zfs/sys/sha2.h
+++ b/sys/contrib/openzfs/include/os/freebsd/zfs/sys/sha2.h
@@ -33,9 +33,6 @@
extern "C" {
#endif
-#define SHA2_HMAC_MIN_KEY_LEN 1 /* SHA2-HMAC min key length in bytes */
-#define SHA2_HMAC_MAX_KEY_LEN INT_MAX /* SHA2-HMAC max key length in bytes */
-
#define SHA256_DIGEST_LENGTH 32 /* SHA256 digest length in bytes */
#define SHA384_DIGEST_LENGTH 48 /* SHA384 digest length in bytes */
#define SHA512_DIGEST_LENGTH 64 /* SHA512 digest length in bytes */
diff --git a/sys/contrib/openzfs/include/os/linux/kernel/linux/compiler_compat.h b/sys/contrib/openzfs/include/os/linux/kernel/linux/compiler_compat.h
index 2c0704da2e51..a65689642361 100644
--- a/sys/contrib/openzfs/include/os/linux/kernel/linux/compiler_compat.h
+++ b/sys/contrib/openzfs/include/os/linux/kernel/linux/compiler_compat.h
@@ -28,11 +28,11 @@
#include <linux/compiler.h>
-#if !defined(fallthrough)
+#if !defined(zfs_fallthrough)
#if defined(HAVE_IMPLICIT_FALLTHROUGH)
-#define fallthrough __attribute__((__fallthrough__))
+#define zfs_fallthrough __attribute__((__fallthrough__))
#else
-#define fallthrough ((void)0)
+#define zfs_fallthrough ((void)0)
#endif
#endif
diff --git a/sys/contrib/openzfs/include/os/linux/kernel/linux/mod_compat.h b/sys/contrib/openzfs/include/os/linux/kernel/linux/mod_compat.h
index cc42c3f7c743..a90bdf7cf2d2 100644
--- a/sys/contrib/openzfs/include/os/linux/kernel/linux/mod_compat.h
+++ b/sys/contrib/openzfs/include/os/linux/kernel/linux/mod_compat.h
@@ -40,13 +40,13 @@ typedef struct kernel_param zfs_kernel_param_t;
#define ZMOD_RW 0644
#define ZMOD_RD 0444
-/* BEGIN CSTYLED */
#define INT int
+#define LONG long
+/* BEGIN CSTYLED */
#define UINT uint
#define ULONG ulong
-#define LONG long
-#define STRING charp
/* END CSTYLED */
+#define STRING charp
enum scope_prefix_types {
zfs,
@@ -108,12 +108,12 @@ enum scope_prefix_types {
* on Linux:
* dmu_prefetch_max
*/
-/* BEGIN CSTYLED */
#define ZFS_MODULE_PARAM(scope_prefix, name_prefix, name, type, perm, desc) \
- CTASSERT_GLOBAL((sizeof (scope_prefix) == sizeof (enum scope_prefix_types))); \
+ _Static_assert( \
+ sizeof (scope_prefix) == sizeof (enum scope_prefix_types), \
+ "" #scope_prefix " size mismatch with enum scope_prefix_types"); \
module_param(name_prefix ## name, type, perm); \
MODULE_PARM_DESC(name_prefix ## name, desc)
-/* END CSTYLED */
/*
* Declare a module parameter / sysctl node
@@ -137,23 +137,26 @@ enum scope_prefix_types {
* on Linux:
* spa_slop_shift
*/
-/* BEGIN CSTYLED */
-#define ZFS_MODULE_PARAM_CALL(scope_prefix, name_prefix, name, setfunc, getfunc, perm, desc) \
- CTASSERT_GLOBAL((sizeof (scope_prefix) == sizeof (enum scope_prefix_types))); \
- module_param_call(name_prefix ## name, setfunc, getfunc, &name_prefix ## name, perm); \
+#define ZFS_MODULE_PARAM_CALL( \
+ scope_prefix, name_prefix, name, setfunc, getfunc, perm, desc) \
+ _Static_assert( \
+ sizeof (scope_prefix) == sizeof (enum scope_prefix_types), \
+ "" #scope_prefix " size mismatch with enum scope_prefix_types"); \
+ module_param_call(name_prefix ## name, setfunc, getfunc, \
+ &name_prefix ## name, perm); \
MODULE_PARM_DESC(name_prefix ## name, desc)
-/* END CSTYLED */
/*
* As above, but there is no variable with the name name_prefix ## name,
* so NULL is passed to module_param_call instead.
*/
-/* BEGIN CSTYLED */
-#define ZFS_MODULE_VIRTUAL_PARAM_CALL(scope_prefix, name_prefix, name, setfunc, getfunc, perm, desc) \
- CTASSERT_GLOBAL((sizeof (scope_prefix) == sizeof (enum scope_prefix_types))); \
+#define ZFS_MODULE_VIRTUAL_PARAM_CALL( \
+ scope_prefix, name_prefix, name, setfunc, getfunc, perm, desc) \
+ _Static_assert( \
+ sizeof (scope_prefix) == sizeof (enum scope_prefix_types), \
+ "" #scope_prefix " size mismatch with enum scope_prefix_types"); \
module_param_call(name_prefix ## name, setfunc, getfunc, NULL, perm); \
MODULE_PARM_DESC(name_prefix ## name, desc)
-/* END CSTYLED */
#define ZFS_MODULE_PARAM_ARGS const char *buf, zfs_kernel_param_t *kp
diff --git a/sys/contrib/openzfs/include/os/linux/kernel/linux/simd_x86.h b/sys/contrib/openzfs/include/os/linux/kernel/linux/simd_x86.h
index f2ae0fcbc21a..6d4c7a09fe82 100644
--- a/sys/contrib/openzfs/include/os/linux/kernel/linux/simd_x86.h
+++ b/sys/contrib/openzfs/include/os/linux/kernel/linux/simd_x86.h
@@ -136,9 +136,27 @@
* When the kernel_fpu_* symbols are unavailable then provide our own
* versions which allow the FPU to be safely used.
*/
+#if defined(HAVE_KERNEL_FPU_INTERNAL) || defined(HAVE_KERNEL_FPU_XSAVE_INTERNAL)
+
+#if defined(HAVE_KERNEL_FPU_XSAVE_INTERNAL)
+/*
+ * Some sanity checks.
+ * HAVE_KERNEL_FPU_INTERNAL and HAVE_KERNEL_FPU_XSAVE_INTERNAL are exclusive.
+ */
#if defined(HAVE_KERNEL_FPU_INTERNAL)
+#error "HAVE_KERNEL_FPU_INTERNAL and HAVE_KERNEL_FPU_XSAVE_INTERNAL defined"
+#endif
+/*
+ * For kernels >= 5.16 we have to use inline assembly with the XSAVE{,OPT,S}
+ * instructions, so we need the toolchain to support at least XSAVE.
+ */
+#if !defined(HAVE_XSAVE)
+#error "Toolchain needs to support the XSAVE assembler instruction"
+#endif
+#endif
#include <linux/mm.h>
+#include <linux/slab.h>
extern union fpregs_state **zfs_kfpu_fpregs;
@@ -191,7 +209,9 @@ kfpu_init(void)
}
#define kfpu_allowed() 1
+#if defined(HAVE_KERNEL_FPU_INTERNAL)
#define ex_handler_fprestore ex_handler_default
+#endif
/*
* FPU save and restore instructions.
@@ -206,6 +226,7 @@ kfpu_init(void)
#define kfpu_fxsr_clean(rval) __asm("fnclex; emms; fildl %P[addr]" \
: : [addr] "m" (rval));
+#if defined(HAVE_KERNEL_FPU_INTERNAL)
static inline void
kfpu_save_xsave(struct xregs_state *addr, uint64_t mask)
{
@@ -217,6 +238,21 @@ kfpu_save_xsave(struct xregs_state *addr, uint64_t mask)
XSTATE_XSAVE(addr, low, hi, err);
WARN_ON_ONCE(err);
}
+#endif /* defined(HAVE_KERNEL_FPU_INTERNAL) */
+
+#if defined(HAVE_KERNEL_FPU_XSAVE_INTERNAL)
+#define kfpu_do_xsave(instruction, addr, mask) \
+{ \
+ uint32_t low, hi; \
+ \
+ low = mask; \
+ hi = (uint64_t)(mask) >> 32; \
+ __asm(instruction " %[dst]\n\t" \
+ : \
+ : [dst] "m" (*(addr)), "a" (low), "d" (hi) \
+ : "memory"); \
+}
+#endif /* defined(HAVE_KERNEL_FPU_XSAVE_INTERNAL) */
static inline void
kfpu_save_fxsr(struct fxregs_state *addr)
@@ -233,6 +269,7 @@ kfpu_save_fsave(struct fregs_state *addr)
kfpu_fnsave(addr);
}
+#if defined(HAVE_KERNEL_FPU_INTERNAL)
static inline void
kfpu_begin(void)
{
@@ -250,7 +287,6 @@ kfpu_begin(void)
* FPU state to be correctly preserved and restored.
*/
union fpregs_state *state = zfs_kfpu_fpregs[smp_processor_id()];
-
if (static_cpu_has(X86_FEATURE_XSAVE)) {
kfpu_save_xsave(&state->xsave, ~0);
} else if (static_cpu_has(X86_FEATURE_FXSR)) {
@@ -259,7 +295,49 @@ kfpu_begin(void)
kfpu_save_fsave(&state->fsave);
}
}
+#endif /* defined(HAVE_KERNEL_FPU_INTERNAL) */
+
+#if defined(HAVE_KERNEL_FPU_XSAVE_INTERNAL)
+static inline void
+kfpu_begin(void)
+{
+ /*
+ * Preemption and interrupts must be disabled for the critical
+ * region where the FPU state is being modified.
+ */
+ preempt_disable();
+ local_irq_disable();
+
+ /*
+ * The current FPU registers need to be preserved by kfpu_begin()
+ * and restored by kfpu_end(). They are stored in a dedicated
+ * per-cpu variable, not in the task struct, this allows any user
+ * FPU state to be correctly preserved and restored.
+ */
+ union fpregs_state *state = zfs_kfpu_fpregs[smp_processor_id()];
+#if defined(HAVE_XSAVES)
+ if (static_cpu_has(X86_FEATURE_XSAVES)) {
+ kfpu_do_xsave("xsaves", &state->xsave, ~0);
+ return;
+ }
+#endif
+#if defined(HAVE_XSAVEOPT)
+ if (static_cpu_has(X86_FEATURE_XSAVEOPT)) {
+ kfpu_do_xsave("xsaveopt", &state->xsave, ~0);
+ return;
+ }
+#endif
+ if (static_cpu_has(X86_FEATURE_XSAVE)) {
+ kfpu_do_xsave("xsave", &state->xsave, ~0);
+ } else if (static_cpu_has(X86_FEATURE_FXSR)) {
+ kfpu_save_fxsr(&state->fxsave);
+ } else {
+ kfpu_save_fsave(&state->fsave);
+ }
+}
+#endif /* defined(HAVE_KERNEL_FPU_XSAVE_INTERNAL) */
+#if defined(HAVE_KERNEL_FPU_INTERNAL)
static inline void
kfpu_restore_xsave(struct xregs_state *addr, uint64_t mask)
{
@@ -269,6 +347,21 @@ kfpu_restore_xsave(struct xregs_state *addr, uint64_t mask)
hi = mask >> 32;
XSTATE_XRESTORE(addr, low, hi);
}
+#endif /* defined(HAVE_KERNEL_FPU_INTERNAL) */
+
+#if defined(HAVE_KERNEL_FPU_XSAVE_INTERNAL)
+#define kfpu_do_xrstor(instruction, addr, mask) \
+{ \
+ uint32_t low, hi; \
+ \
+ low = mask; \
+ hi = (uint64_t)(mask) >> 32; \
+ __asm(instruction " %[src]" \
+ : \
+ : [src] "m" (*(addr)), "a" (low), "d" (hi) \
+ : "memory"); \
+}
+#endif /* defined(HAVE_KERNEL_FPU_XSAVE_INTERNAL) */
static inline void
kfpu_restore_fxsr(struct fxregs_state *addr)
@@ -294,6 +387,7 @@ kfpu_restore_fsave(struct fregs_state *addr)
kfpu_frstor(addr);
}
+#if defined(HAVE_KERNEL_FPU_INTERNAL)
static inline void
kfpu_end(void)
{
@@ -310,6 +404,32 @@ kfpu_end(void)
local_irq_enable();
preempt_enable();
}
+#endif /* defined(HAVE_KERNEL_FPU_INTERNAL) */
+
+#if defined(HAVE_KERNEL_FPU_XSAVE_INTERNAL)
+static inline void
+kfpu_end(void)
+{
+ union fpregs_state *state = zfs_kfpu_fpregs[smp_processor_id()];
+#if defined(HAVE_XSAVES)
+ if (static_cpu_has(X86_FEATURE_XSAVES)) {
+ kfpu_do_xrstor("xrstors", &state->xsave, ~0);
+ goto out;
+ }
+#endif
+ if (static_cpu_has(X86_FEATURE_XSAVE)) {
+ kfpu_do_xrstor("xrstor", &state->xsave, ~0);
+ } else if (static_cpu_has(X86_FEATURE_FXSR)) {
+ kfpu_save_fxsr(&state->fxsave);
+ } else {
+ kfpu_save_fsave(&state->fsave);
+ }
+out:
+ local_irq_enable();
+ preempt_enable();
+
+}
+#endif /* defined(HAVE_KERNEL_FPU_XSAVE_INTERNAL) */
#else
@@ -322,7 +442,7 @@ kfpu_end(void)
#define kfpu_init() 0
#define kfpu_fini() ((void) 0)
-#endif /* defined(HAVE_KERNEL_FPU_INTERNAL) */
+#endif /* defined(HAVE_KERNEL_FPU_INTERNAL || HAVE_KERNEL_FPU_XSAVE_INTERNAL) */
#endif /* defined(KERNEL_EXPORTS_X86_FPU) */
/*
diff --git a/sys/contrib/openzfs/include/os/linux/spl/sys/acl.h b/sys/contrib/openzfs/include/os/linux/spl/sys/acl.h
index 5a3d226c7664..5cd7a56b86ec 100644
--- a/sys/contrib/openzfs/include/os/linux/spl/sys/acl.h
+++ b/sys/contrib/openzfs/include/os/linux/spl/sys/acl.h
@@ -102,13 +102,11 @@ typedef struct ace_object {
#define ACE_TYPE_FLAGS (ACE_OWNER|ACE_GROUP|ACE_EVERYONE|ACE_IDENTIFIER_GROUP)
-/* BEGIN CSTYLED */
#define ACE_ALL_PERMS (ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \
- ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_READ_NAMED_ATTRS| \
- ACE_WRITE_NAMED_ATTRS|ACE_EXECUTE|ACE_DELETE_CHILD|ACE_READ_ATTRIBUTES| \
- ACE_WRITE_ATTRIBUTES|ACE_DELETE|ACE_READ_ACL|ACE_WRITE_ACL| \
- ACE_WRITE_OWNER|ACE_SYNCHRONIZE)
-/* END CSTYLED */
+ ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_READ_NAMED_ATTRS|\
+ ACE_WRITE_NAMED_ATTRS|ACE_EXECUTE|ACE_DELETE_CHILD|ACE_READ_ATTRIBUTES|\
+ ACE_WRITE_ATTRIBUTES|ACE_DELETE|ACE_READ_ACL|ACE_WRITE_ACL| \
+ ACE_WRITE_OWNER|ACE_SYNCHRONIZE)
#define VSA_ACE 0x0010
#define VSA_ACECNT 0x0020
diff --git a/sys/contrib/openzfs/include/os/linux/spl/sys/debug.h b/sys/contrib/openzfs/include/os/linux/spl/sys/debug.h
index 102fc640bf56..9c013370c5f0 100644
--- a/sys/contrib/openzfs/include/os/linux/spl/sys/debug.h
+++ b/sys/contrib/openzfs/include/os/linux/spl/sys/debug.h
@@ -58,89 +58,87 @@ int spl_panic(const char *file, const char *func, int line,
const char *fmt, ...);
void spl_dumpstack(void);
-/* BEGIN CSTYLED */
#define PANIC(fmt, a...) \
spl_panic(__FILE__, __FUNCTION__, __LINE__, fmt, ## a)
-#define VERIFY(cond) \
- (void) (unlikely(!(cond)) && \
+#define VERIFY(cond) \
+ (void) (unlikely(!(cond)) && \
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
"%s", "VERIFY(" #cond ") failed\n"))
-#define VERIFY3B(LEFT, OP, RIGHT) do { \
+#define VERIFY3B(LEFT, OP, RIGHT) do { \
const boolean_t _verify3_left = (boolean_t)(LEFT); \
- const boolean_t _verify3_right = (boolean_t)(RIGHT);\
+ const boolean_t _verify3_right = (boolean_t)(RIGHT); \
if (unlikely(!(_verify3_left OP _verify3_right))) \
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
- "failed (%d " #OP " %d)\n", \
- (boolean_t) (_verify3_left), \
- (boolean_t) (_verify3_right)); \
+ "failed (%d " #OP " %d)\n", \
+ (boolean_t)(_verify3_left), \
+ (boolean_t)(_verify3_right)); \
} while (0)
-#define VERIFY3S(LEFT, OP, RIGHT) do { \
+#define VERIFY3S(LEFT, OP, RIGHT) do { \
const int64_t _verify3_left = (int64_t)(LEFT); \
const int64_t _verify3_right = (int64_t)(RIGHT); \
if (unlikely(!(_verify3_left OP _verify3_right))) \
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
- "failed (%lld " #OP " %lld)\n", \
- (long long) (_verify3_left), \
- (long long) (_verify3_right)); \
+ "failed (%lld " #OP " %lld)\n", \
+ (long long)(_verify3_left), \
+ (long long)(_verify3_right)); \
} while (0)
-#define VERIFY3U(LEFT, OP, RIGHT) do { \
+#define VERIFY3U(LEFT, OP, RIGHT) do { \
const uint64_t _verify3_left = (uint64_t)(LEFT); \
const uint64_t _verify3_right = (uint64_t)(RIGHT); \
if (unlikely(!(_verify3_left OP _verify3_right))) \
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
- "failed (%llu " #OP " %llu)\n", \
- (unsigned long long) (_verify3_left), \
- (unsigned long long) (_verify3_right)); \
+ "failed (%llu " #OP " %llu)\n", \
+ (unsigned long long)(_verify3_left), \
+ (unsigned long long)(_verify3_right)); \
} while (0)
-#define VERIFY3P(LEFT, OP, RIGHT) do { \
+#define VERIFY3P(LEFT, OP, RIGHT) do { \
const uintptr_t _verify3_left = (uintptr_t)(LEFT); \
- const uintptr_t _verify3_right = (uintptr_t)(RIGHT);\
+ const uintptr_t _verify3_right = (uintptr_t)(RIGHT); \
if (unlikely(!(_verify3_left OP _verify3_right))) \
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
- "failed (%px " #OP " %px)\n", \
- (void *) (_verify3_left), \
- (void *) (_verify3_right)); \
+ "failed (%px " #OP " %px)\n", \
+ (void *) (_verify3_left), \
+ (void *) (_verify3_right)); \
} while (0)
-#define VERIFY0(RIGHT) do { \
- const int64_t _verify3_left = (int64_t)(0); \
+#define VERIFY0(RIGHT) do { \
+ const int64_t _verify3_left = (int64_t)(0); \
const int64_t _verify3_right = (int64_t)(RIGHT); \
if (unlikely(!(_verify3_left == _verify3_right))) \
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
- "VERIFY3(0 == " #RIGHT ") " \
- "failed (0 == %lld)\n", \
- (long long) (_verify3_right)); \
+ "VERIFY3(0 == " #RIGHT ") " \
+ "failed (0 == %lld)\n", \
+ (long long) (_verify3_right)); \
} while (0)
-#define CTASSERT_GLOBAL(x) _CTASSERT(x, __LINE__)
-#define CTASSERT(x) { _CTASSERT(x, __LINE__); }
-#define _CTASSERT(x, y) __CTASSERT(x, y)
-#define __CTASSERT(x, y) \
- typedef char __attribute__ ((unused)) \
- __compile_time_assertion__ ## y[(x) ? 1 : -1]
-
/*
* Debugging disabled (--disable-debug)
*/
#ifdef NDEBUG
-#define ASSERT(x) ((void) sizeof (!!(x)))
-#define ASSERT3B(x,y,z) ((void) sizeof (!!(x)), (void) sizeof (!!(z)))
-#define ASSERT3S(x,y,z) ((void) sizeof (!!(x)), (void) sizeof (!!(z)))
-#define ASSERT3U(x,y,z) ((void) sizeof (!!(x)), (void) sizeof (!!(z)))
-#define ASSERT3P(x,y,z) ((void) sizeof (!!(x)), (void) sizeof (!!(z)))
-#define ASSERT0(x) ((void) sizeof (!!(x)))
-#define IMPLY(A, B) ((void) sizeof (!!(A)), (void) sizeof (!!(B)))
-#define EQUIV(A, B) ((void) sizeof (!!(A)), (void) sizeof (!!(B)))
+#define ASSERT(x) ((void) sizeof ((uintptr_t)(x)))
+#define ASSERT3B(x, y, z) \
+ ((void) sizeof ((uintptr_t)(x)), (void) sizeof ((uintptr_t)(z)))
+#define ASSERT3S(x, y, z) \
+ ((void) sizeof ((uintptr_t)(x)), (void) sizeof ((uintptr_t)(z)))
+#define ASSERT3U(x, y, z) \
+ ((void) sizeof ((uintptr_t)(x)), (void) sizeof ((uintptr_t)(z)))
+#define ASSERT3P(x, y, z) \
+ ((void) sizeof ((uintptr_t)(x)), (void) sizeof ((uintptr_t)(z)))
+#define ASSERT0(x) ((void) sizeof ((uintptr_t)(x)))
+#define IMPLY(A, B) \
+ ((void) sizeof ((uintptr_t)(A)), (void) sizeof ((uintptr_t)(B)))
+#define EQUIV(A, B) \
+ ((void) sizeof ((uintptr_t)(A)), (void) sizeof ((uintptr_t)(B)))
/*
* Debugging enabled (--enable-debug)
@@ -161,7 +159,6 @@ void spl_dumpstack(void);
((void)(likely(!!(A) == !!(B)) || \
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
"(" #A ") is equivalent to (" #B ")")))
-/* END CSTYLED */
#endif /* NDEBUG */
diff --git a/sys/contrib/openzfs/include/os/linux/spl/sys/isa_defs.h b/sys/contrib/openzfs/include/os/linux/spl/sys/isa_defs.h
index 2207ee20256c..a032aae91658 100644
--- a/sys/contrib/openzfs/include/os/linux/spl/sys/isa_defs.h
+++ b/sys/contrib/openzfs/include/os/linux/spl/sys/isa_defs.h
@@ -95,7 +95,7 @@
#define _ALIGNMENT_REQUIRED 1
/* arm arch specific defines */
-#elif defined(__arm) || defined(__arm__) || defined(__aarch64__)
+#elif defined(__arm) || defined(__arm__)
#if !defined(__arm)
#define __arm
@@ -105,17 +105,11 @@
#define __arm__
#endif
-#if defined(__aarch64__)
-#if !defined(_LP64)
-#define _LP64
-#endif
-#else
#if !defined(_ILP32)
#define _ILP32
#endif
-#endif
-#if defined(__ARMEL__) || defined(__AARCH64EL__)
+#if defined(__ARMEL__)
#define _ZFS_LITTLE_ENDIAN
#else
#define _ZFS_BIG_ENDIAN
@@ -127,6 +121,19 @@
*/
#define _ALIGNMENT_REQUIRED 1
+/* aarch64 arch specific defines */
+#elif defined(__aarch64__)
+
+#if !defined(_LP64)
+#define _LP64
+#endif
+
+#if defined(__AARCH64EL__)
+#define _ZFS_LITTLE_ENDIAN
+#else
+#define _ZFS_BIG_ENDIAN
+#endif
+
/* sparc arch specific defines */
#elif defined(__sparc) || defined(__sparc__)
diff --git a/sys/contrib/openzfs/include/os/linux/spl/sys/mutex.h b/sys/contrib/openzfs/include/os/linux/spl/sys/mutex.h
index 047607f826bc..677076a0f134 100644
--- a/sys/contrib/openzfs/include/os/linux/spl/sys/mutex.h
+++ b/sys/contrib/openzfs/include/os/linux/spl/sys/mutex.h
@@ -113,8 +113,8 @@ spl_mutex_lockdep_on_maybe(kmutex_t *mp) \
VERIFY3P(mutex_owner(mp), ==, NULL); \
}
-/* BEGIN CSTYLED */
#define mutex_tryenter(mp) \
+/* CSTYLED */ \
({ \
int _rc_; \
\
@@ -125,7 +125,6 @@ spl_mutex_lockdep_on_maybe(kmutex_t *mp) \
\
_rc_; \
})
-/* END CSTYLED */
#define NESTED_SINGLE 1
diff --git a/sys/contrib/openzfs/include/os/linux/spl/sys/rwlock.h b/sys/contrib/openzfs/include/os/linux/spl/sys/rwlock.h
index ba7620a1f344..c04b6ca484f6 100644
--- a/sys/contrib/openzfs/include/os/linux/spl/sys/rwlock.h
+++ b/sys/contrib/openzfs/include/os/linux/spl/sys/rwlock.h
@@ -116,8 +116,7 @@ RW_READ_HELD(krwlock_t *rwp)
* will be correctly located in the users code which is important
* for the built in kernel lock analysis tools
*/
-/* BEGIN CSTYLED */
-#define rw_init(rwp, name, type, arg) \
+#define rw_init(rwp, name, type, arg) /* CSTYLED */ \
({ \
static struct lock_class_key __key; \
ASSERT(type == RW_DEFAULT || type == RW_NOLOCKDEP); \
@@ -138,7 +137,7 @@ RW_READ_HELD(krwlock_t *rwp)
*/
#define rw_tryupgrade(rwp) RW_WRITE_HELD(rwp)
-#define rw_tryenter(rwp, rw) \
+#define rw_tryenter(rwp, rw) /* CSTYLED */ \
({ \
int _rc_ = 0; \
\
@@ -158,7 +157,7 @@ RW_READ_HELD(krwlock_t *rwp)
_rc_; \
})
-#define rw_enter(rwp, rw) \
+#define rw_enter(rwp, rw) /* CSTYLED */ \
({ \
spl_rw_lockdep_off_maybe(rwp); \
switch (rw) { \
@@ -175,7 +174,7 @@ RW_READ_HELD(krwlock_t *rwp)
spl_rw_lockdep_on_maybe(rwp); \
})
-#define rw_exit(rwp) \
+#define rw_exit(rwp) /* CSTYLED */ \
({ \
spl_rw_lockdep_off_maybe(rwp); \
if (RW_WRITE_HELD(rwp)) { \
@@ -188,13 +187,12 @@ RW_READ_HELD(krwlock_t *rwp)
spl_rw_lockdep_on_maybe(rwp); \
})
-#define rw_downgrade(rwp) \
+#define rw_downgrade(rwp) /* CSTYLED */ \
({ \
spl_rw_lockdep_off_maybe(rwp); \
spl_rw_clear_owner(rwp); \
downgrade_write(SEM(rwp)); \
spl_rw_lockdep_on_maybe(rwp); \
})
-/* END CSTYLED */
#endif /* _SPL_RWLOCK_H */
diff --git a/sys/contrib/openzfs/include/os/linux/spl/sys/thread.h b/sys/contrib/openzfs/include/os/linux/spl/sys/thread.h
index 220742387b62..7f9f486fcd4b 100644
--- a/sys/contrib/openzfs/include/os/linux/spl/sys/thread.h
+++ b/sys/contrib/openzfs/include/os/linux/spl/sys/thread.h
@@ -49,11 +49,9 @@ typedef void (*thread_func_t)(void *);
__thread_create(stk, stksize, (thread_func_t)func, \
name, arg, len, pp, state, pri)
-/* BEGIN CSTYLED */
#define thread_create(stk, stksize, func, arg, len, pp, state, pri) \
- __thread_create(stk, stksize, (thread_func_t)func, \
- #func, arg, len, pp, state, pri)
-/* END CSTYLED */
+ __thread_create(stk, stksize, (thread_func_t)func, #func, \
+ arg, len, pp, state, pri)
#define thread_exit() __thread_exit()
#define thread_join(t) VERIFY(0)
@@ -64,7 +62,7 @@ typedef void (*thread_func_t)(void *);
extern kthread_t *__thread_create(caddr_t stk, size_t stksize,
thread_func_t func, const char *name, void *args, size_t len, proc_t *pp,
int state, pri_t pri);
-extern void __thread_exit(void);
+extern __attribute__((noreturn)) void __thread_exit(void);
extern struct task_struct *spl_kthread_create(int (*func)(void *),
void *data, const char namefmt[], ...);
diff --git a/sys/contrib/openzfs/include/os/linux/spl/sys/trace_taskq.h b/sys/contrib/openzfs/include/os/linux/spl/sys/trace_taskq.h
index dbbb3c4c7960..002e1af1706d 100644
--- a/sys/contrib/openzfs/include/os/linux/spl/sys/trace_taskq.h
+++ b/sys/contrib/openzfs/include/os/linux/spl/sys/trace_taskq.h
@@ -40,26 +40,20 @@
* DTRACE_PROBE1(...,
* taskq_ent_t *, ...);
*/
-/* BEGIN CSTYLED */
DECLARE_EVENT_CLASS(zfs_taskq_ent_class,
- TP_PROTO(taskq_ent_t *taskq_ent),
- TP_ARGS(taskq_ent),
- TP_STRUCT__entry(
- __field(taskq_ent_t *, taskq_ent)
- ),
- TP_fast_assign(
- __entry->taskq_ent = taskq_ent;
- ),
- TP_printk("taskq_ent %p", __entry->taskq_ent)
+ TP_PROTO(taskq_ent_t *taskq_ent),
+ TP_ARGS(taskq_ent),
+ TP_STRUCT__entry(__field(taskq_ent_t *, taskq_ent)),
+ TP_fast_assign(
+ __entry->taskq_ent = taskq_ent;
+),
+ TP_printk("taskq_ent %p", __entry->taskq_ent)
);
-/* END CSTYLED */
-/* BEGIN CSTYLED */
-#define DEFINE_TASKQ_EVENT(name) \
+#define DEFINE_TASKQ_EVENT(name) \
DEFINE_EVENT(zfs_taskq_ent_class, name, \
- TP_PROTO(taskq_ent_t *taskq_ent), \
- TP_ARGS(taskq_ent))
-/* END CSTYLED */
+ TP_PROTO(taskq_ent_t *taskq_ent), \
+ TP_ARGS(taskq_ent))
DEFINE_TASKQ_EVENT(zfs_taskq_ent__birth);
DEFINE_TASKQ_EVENT(zfs_taskq_ent__start);
DEFINE_TASKQ_EVENT(zfs_taskq_ent__finish);
diff --git a/sys/contrib/openzfs/include/os/linux/spl/sys/uio.h b/sys/contrib/openzfs/include/os/linux/spl/sys/uio.h
index 66af2b0b534c..439eec986236 100644
--- a/sys/contrib/openzfs/include/os/linux/spl/sys/uio.h
+++ b/sys/contrib/openzfs/include/os/linux/spl/sys/uio.h
@@ -34,6 +34,10 @@
#include <asm/uaccess.h>
#include <sys/types.h>
+#if defined(HAVE_VFS_IOV_ITER) && defined(HAVE_FAULT_IN_IOV_ITER_READABLE)
+#define iov_iter_fault_in_readable(a, b) fault_in_iov_iter_readable(a, b)
+#endif
+
typedef struct iovec iovec_t;
typedef enum zfs_uio_rw {
diff --git a/sys/contrib/openzfs/include/os/linux/zfs/sys/sha2.h b/sys/contrib/openzfs/include/os/linux/zfs/sys/sha2.h
index 4dd966b6cab3..48ea0dc5d9d2 100644
--- a/sys/contrib/openzfs/include/os/linux/zfs/sys/sha2.h
+++ b/sys/contrib/openzfs/include/os/linux/zfs/sys/sha2.h
@@ -33,9 +33,6 @@
extern "C" {
#endif
-#define SHA2_HMAC_MIN_KEY_LEN 1 /* SHA2-HMAC min key length in bytes */
-#define SHA2_HMAC_MAX_KEY_LEN INT_MAX /* SHA2-HMAC max key length in bytes */
-
#define SHA256_DIGEST_LENGTH 32 /* SHA256 digest length in bytes */
#define SHA384_DIGEST_LENGTH 48 /* SHA384 digest length in bytes */
#define SHA512_DIGEST_LENGTH 64 /* SHA512 digest length in bytes */
diff --git a/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_acl.h b/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_acl.h
index 4707fc6f4112..f8e0aa8acaf8 100644
--- a/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_acl.h
+++ b/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_acl.h
@@ -135,12 +135,10 @@ DECLARE_EVENT_CLASS(zfs_ace_class,
);
/* END CSTYLED */
-/* BEGIN CSTYLED */
#define DEFINE_ACE_EVENT(name) \
DEFINE_EVENT(zfs_ace_class, name, \
- TP_PROTO(znode_t *zn, zfs_ace_hdr_t *ace, uint32_t mask_matched), \
- TP_ARGS(zn, ace, mask_matched))
-/* END CSTYLED */
+ TP_PROTO(znode_t *zn, zfs_ace_hdr_t *ace, uint32_t mask_matched), \
+ TP_ARGS(zn, ace, mask_matched))
DEFINE_ACE_EVENT(zfs_zfs__ace__denies);
DEFINE_ACE_EVENT(zfs_zfs__ace__allows);
diff --git a/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_arc.h b/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_arc.h
index d3410bc07a32..a318a62b05a4 100644
--- a/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_arc.h
+++ b/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_arc.h
@@ -98,12 +98,10 @@ DECLARE_EVENT_CLASS(zfs_arc_buf_hdr_class,
);
/* END CSTYLED */
-/* BEGIN CSTYLED */
#define DEFINE_ARC_BUF_HDR_EVENT(name) \
DEFINE_EVENT(zfs_arc_buf_hdr_class, name, \
- TP_PROTO(arc_buf_hdr_t *ab), \
- TP_ARGS(ab))
-/* END CSTYLED */
+ TP_PROTO(arc_buf_hdr_t *ab), \
+ TP_ARGS(ab))
DEFINE_ARC_BUF_HDR_EVENT(zfs_arc__hit);
DEFINE_ARC_BUF_HDR_EVENT(zfs_arc__evict);
DEFINE_ARC_BUF_HDR_EVENT(zfs_arc__delete);
@@ -143,12 +141,10 @@ DECLARE_EVENT_CLASS(zfs_l2arc_rw_class,
);
/* END CSTYLED */
-/* BEGIN CSTYLED */
#define DEFINE_L2ARC_RW_EVENT(name) \
DEFINE_EVENT(zfs_l2arc_rw_class, name, \
- TP_PROTO(vdev_t *vd, zio_t *zio), \
- TP_ARGS(vd, zio))
-/* END CSTYLED */
+ TP_PROTO(vdev_t *vd, zio_t *zio), \
+ TP_ARGS(vd, zio))
DEFINE_L2ARC_RW_EVENT(zfs_l2arc__read);
DEFINE_L2ARC_RW_EVENT(zfs_l2arc__write);
@@ -170,12 +166,10 @@ DECLARE_EVENT_CLASS(zfs_l2arc_iodone_class,
);
/* END CSTYLED */
-/* BEGIN CSTYLED */
#define DEFINE_L2ARC_IODONE_EVENT(name) \
DEFINE_EVENT(zfs_l2arc_iodone_class, name, \
- TP_PROTO(zio_t *zio, l2arc_write_callback_t *cb), \
- TP_ARGS(zio, cb))
-/* END CSTYLED */
+ TP_PROTO(zio_t *zio, l2arc_write_callback_t *cb), \
+ TP_ARGS(zio, cb))
DEFINE_L2ARC_IODONE_EVENT(zfs_l2arc__iodone);
@@ -284,13 +278,11 @@ DECLARE_EVENT_CLASS(zfs_arc_miss_class,
);
/* END CSTYLED */
-/* BEGIN CSTYLED */
#define DEFINE_ARC_MISS_EVENT(name) \
DEFINE_EVENT(zfs_arc_miss_class, name, \
- TP_PROTO(arc_buf_hdr_t *hdr, \
- const blkptr_t *bp, uint64_t size, const zbookmark_phys_t *zb), \
- TP_ARGS(hdr, bp, size, zb))
-/* END CSTYLED */
+ TP_PROTO(arc_buf_hdr_t *hdr, \
+ const blkptr_t *bp, uint64_t size, const zbookmark_phys_t *zb), \
+ TP_ARGS(hdr, bp, size, zb))
DEFINE_ARC_MISS_EVENT(zfs_arc__miss);
/*
@@ -345,13 +337,10 @@ DECLARE_EVENT_CLASS(zfs_l2arc_evict_class,
);
/* END CSTYLED */
-/* BEGIN CSTYLED */
#define DEFINE_L2ARC_EVICT_EVENT(name) \
DEFINE_EVENT(zfs_l2arc_evict_class, name, \
- TP_PROTO(l2arc_dev_t *dev, \
- list_t *buflist, uint64_t taddr, boolean_t all), \
- TP_ARGS(dev, buflist, taddr, all))
-/* END CSTYLED */
+ TP_PROTO(l2arc_dev_t *dev, list_t *buflist, uint64_t taddr, boolean_t all),\
+ TP_ARGS(dev, buflist, taddr, all))
DEFINE_L2ARC_EVICT_EVENT(zfs_l2arc__evict);
/*
@@ -381,12 +370,10 @@ DECLARE_EVENT_CLASS(zfs_arc_wait_for_eviction_class,
);
/* END CSTYLED */
-/* BEGIN CSTYLED */
#define DEFINE_ARC_WAIT_FOR_EVICTION_EVENT(name) \
DEFINE_EVENT(zfs_arc_wait_for_eviction_class, name, \
- TP_PROTO(uint64_t amount, uint64_t arc_evict_count, uint64_t aew_count), \
- TP_ARGS(amount, arc_evict_count, aew_count))
-/* END CSTYLED */
+ TP_PROTO(uint64_t amount, uint64_t arc_evict_count, uint64_t aew_count), \
+ TP_ARGS(amount, arc_evict_count, aew_count))
DEFINE_ARC_WAIT_FOR_EVICTION_EVENT(zfs_arc__wait__for__eviction);
#endif /* _TRACE_ARC_H */
diff --git a/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_dbgmsg.h b/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_dbgmsg.h
index 513918d004a4..89722bab4c94 100644
--- a/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_dbgmsg.h
+++ b/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_dbgmsg.h
@@ -65,12 +65,10 @@ DECLARE_EVENT_CLASS(zfs_dprintf_class,
);
/* END CSTYLED */
-/* BEGIN CSTYLED */
#define DEFINE_DPRINTF_EVENT(name) \
DEFINE_EVENT(zfs_dprintf_class, name, \
- TP_PROTO(const char *msg), \
- TP_ARGS(msg))
-/* END CSTYLED */
+ TP_PROTO(const char *msg), \
+ TP_ARGS(msg))
DEFINE_DPRINTF_EVENT(zfs_zfs__dprintf);
#endif /* _TRACE_DBGMSG_H */
diff --git a/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_dbuf.h b/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_dbuf.h
index bd7d791a46e7..ba7c6b1a0144 100644
--- a/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_dbuf.h
+++ b/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_dbuf.h
@@ -117,20 +117,16 @@ DECLARE_EVENT_CLASS(zfs_dbuf_state_class,
);
/* END CSTYLED */
-/* BEGIN CSTYLED */
#define DEFINE_DBUF_EVENT(name) \
DEFINE_EVENT(zfs_dbuf_class, name, \
- TP_PROTO(dmu_buf_impl_t *db, zio_t *zio), \
- TP_ARGS(db, zio))
-/* END CSTYLED */
+ TP_PROTO(dmu_buf_impl_t *db, zio_t *zio), \
+ TP_ARGS(db, zio))
DEFINE_DBUF_EVENT(zfs_blocked__read);
-/* BEGIN CSTYLED */
#define DEFINE_DBUF_STATE_EVENT(name) \
DEFINE_EVENT(zfs_dbuf_state_class, name, \
- TP_PROTO(dmu_buf_impl_t *db, const char *why), \
- TP_ARGS(db, why))
-/* END CSTYLED */
+ TP_PROTO(dmu_buf_impl_t *db, const char *why), \
+ TP_ARGS(db, why))
DEFINE_DBUF_STATE_EVENT(zfs_dbuf__state_change);
/* BEGIN CSTYLED */
@@ -143,12 +139,10 @@ DECLARE_EVENT_CLASS(zfs_dbuf_evict_one_class,
);
/* END CSTYLED */
-/* BEGIN CSTYLED */
#define DEFINE_DBUF_EVICT_ONE_EVENT(name) \
DEFINE_EVENT(zfs_dbuf_evict_one_class, name, \
- TP_PROTO(dmu_buf_impl_t *db, multilist_sublist_t *mls), \
- TP_ARGS(db, mls))
-/* END CSTYLED */
+ TP_PROTO(dmu_buf_impl_t *db, multilist_sublist_t *mls), \
+ TP_ARGS(db, mls))
DEFINE_DBUF_EVICT_ONE_EVENT(zfs_dbuf__evict__one);
#endif /* _TRACE_DBUF_H */
diff --git a/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_dmu.h b/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_dmu.h
index 3c64a370f842..40a4c02eed19 100644
--- a/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_dmu.h
+++ b/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_dmu.h
@@ -81,12 +81,10 @@ DECLARE_EVENT_CLASS(zfs_delay_mintime_class,
);
/* END CSTYLED */
-/* BEGIN CSTYLED */
#define DEFINE_DELAY_MINTIME_EVENT(name) \
DEFINE_EVENT(zfs_delay_mintime_class, name, \
- TP_PROTO(dmu_tx_t *tx, uint64_t dirty, uint64_t min_tx_time), \
- TP_ARGS(tx, dirty, min_tx_time))
-/* END CSTYLED */
+ TP_PROTO(dmu_tx_t *tx, uint64_t dirty, uint64_t min_tx_time), \
+ TP_ARGS(tx, dirty, min_tx_time))
DEFINE_DELAY_MINTIME_EVENT(zfs_delay__mintime);
/* BEGIN CSTYLED */
@@ -110,13 +108,11 @@ DECLARE_EVENT_CLASS(zfs_free_long_range_class,
);
/* END CSTYLED */
-/* BEGIN CSTYLED */
#define DEFINE_FREE_LONG_RANGE_EVENT(name) \
DEFINE_EVENT(zfs_free_long_range_class, name, \
- TP_PROTO(uint64_t long_free_dirty_all_txgs, \
- uint64_t chunk_len, uint64_t txg), \
- TP_ARGS(long_free_dirty_all_txgs, chunk_len, txg))
-/* END CSTYLED */
+ TP_PROTO(uint64_t long_free_dirty_all_txgs, \
+ uint64_t chunk_len, uint64_t txg), \
+ TP_ARGS(long_free_dirty_all_txgs, chunk_len, txg))
DEFINE_FREE_LONG_RANGE_EVENT(zfs_free__long__range);
#endif /* _TRACE_DMU_H */
diff --git a/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_dnode.h b/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_dnode.h
index 27ad6cba16d6..b4b391492bc3 100644
--- a/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_dnode.h
+++ b/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_dnode.h
@@ -105,12 +105,10 @@ DECLARE_EVENT_CLASS(zfs_dnode_move_class,
);
/* END CSTYLED */
-/* BEGIN CSTYLED */
#define DEFINE_DNODE_MOVE_EVENT(name) \
DEFINE_EVENT(zfs_dnode_move_class, name, \
- TP_PROTO(dnode_t *dn, int64_t refcount, uint32_t dbufs), \
- TP_ARGS(dn, refcount, dbufs))
-/* END CSTYLED */
+ TP_PROTO(dnode_t *dn, int64_t refcount, uint32_t dbufs), \
+ TP_ARGS(dn, refcount, dbufs))
DEFINE_DNODE_MOVE_EVENT(zfs_dnode__move);
#endif /* _TRACE_DNODE_H */
diff --git a/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_multilist.h b/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_multilist.h
index fe68d5296f73..638578407a0c 100644
--- a/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_multilist.h
+++ b/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_multilist.h
@@ -63,12 +63,10 @@ DECLARE_EVENT_CLASS(zfs_multilist_insert_remove_class,
);
/* END CSTYLED */
-/* BEGIN CSTYLED */
#define DEFINE_MULTILIST_INSERT_REMOVE_EVENT(name) \
DEFINE_EVENT(zfs_multilist_insert_remove_class, name, \
- TP_PROTO(multilist_t *ml, unsigned int sublist_idx, void *obj), \
- TP_ARGS(ml, sublist_idx, obj))
-/* END CSTYLED */
+ TP_PROTO(multilist_t *ml, unsigned int sublist_idx, void *obj), \
+ TP_ARGS(ml, sublist_idx, obj))
DEFINE_MULTILIST_INSERT_REMOVE_EVENT(zfs_multilist__insert);
DEFINE_MULTILIST_INSERT_REMOVE_EVENT(zfs_multilist__remove);
diff --git a/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_txg.h b/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_txg.h
index 23d5d358bc42..f77e35a78340 100644
--- a/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_txg.h
+++ b/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_txg.h
@@ -55,12 +55,10 @@ DECLARE_EVENT_CLASS(zfs_txg_class,
);
/* END CSTYLED */
-/* BEGIN CSTYLED */
#define DEFINE_TXG_EVENT(name) \
DEFINE_EVENT(zfs_txg_class, name, \
- TP_PROTO(dsl_pool_t *dp, uint64_t txg), \
- TP_ARGS(dp, txg))
-/* END CSTYLED */
+ TP_PROTO(dsl_pool_t *dp, uint64_t txg), \
+ TP_ARGS(dp, txg))
DEFINE_TXG_EVENT(zfs_dsl_pool_sync__done);
DEFINE_TXG_EVENT(zfs_txg__quiescing);
DEFINE_TXG_EVENT(zfs_txg__opened);
diff --git a/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_vdev.h b/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_vdev.h
index 50711446ffa4..079668d35f12 100644
--- a/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_vdev.h
+++ b/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_vdev.h
@@ -68,12 +68,10 @@ DECLARE_EVENT_CLASS(zfs_removing_class_3,
);
/* END CSTYLED */
-/* BEGIN CSTYLED */
-#define DEFINE_REMOVE_FREE_EVENT(name) \
+#define DEFINE_REMOVE_FREE_EVENT(name) \
DEFINE_EVENT(zfs_removing_class_3, name, \
- TP_PROTO(spa_t *spa, uint64_t offset, uint64_t size), \
- TP_ARGS(spa, offset, size))
-/* END CSTYLED */
+ TP_PROTO(spa_t *spa, uint64_t offset, uint64_t size), \
+ TP_ARGS(spa, offset, size))
DEFINE_REMOVE_FREE_EVENT(zfs_remove__free__synced);
DEFINE_REMOVE_FREE_EVENT(zfs_remove__free__unvisited);
@@ -107,12 +105,10 @@ DECLARE_EVENT_CLASS(zfs_removing_class_4,
__entry->vdev_size, __entry->vdev_txg)
);
-/* BEGIN CSTYLED */
#define DEFINE_REMOVE_FREE_EVENT_TXG(name) \
DEFINE_EVENT(zfs_removing_class_4, name, \
- TP_PROTO(spa_t *spa, uint64_t offset, uint64_t size,uint64_t txg), \
- TP_ARGS(spa, offset, size, txg))
-/* END CSTYLED */
+ TP_PROTO(spa_t *spa, uint64_t offset, uint64_t size,uint64_t txg), \
+ TP_ARGS(spa, offset, size, txg))
DEFINE_REMOVE_FREE_EVENT_TXG(zfs_remove__free__inflight);
#endif /* _TRACE_VDEV_H */
diff --git a/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_zil.h b/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_zil.h
index 526846e664b2..8ffda452766c 100644
--- a/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_zil.h
+++ b/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_zil.h
@@ -170,14 +170,12 @@ DECLARE_EVENT_CLASS(zfs_zil_process_itx_class,
);
/* END CSTYLED */
-/* BEGIN CSTYLED */
#define DEFINE_ZIL_PROCESS_ITX_EVENT(name) \
DEFINE_EVENT(zfs_zil_process_itx_class, name, \
- TP_PROTO(zilog_t *zilog, itx_t *itx), \
- TP_ARGS(zilog, itx))
+ TP_PROTO(zilog_t *zilog, itx_t *itx), \
+ TP_ARGS(zilog, itx))
DEFINE_ZIL_PROCESS_ITX_EVENT(zfs_zil__process__commit__itx);
DEFINE_ZIL_PROCESS_ITX_EVENT(zfs_zil__process__normal__itx);
-/* END CSTYLED */
/*
* Generic support for two argument tracepoints of the form:
@@ -203,13 +201,11 @@ DECLARE_EVENT_CLASS(zfs_zil_commit_io_error_class,
ZILOG_TP_PRINTK_ARGS, ZCW_TP_PRINTK_ARGS)
);
-/* BEGIN CSTYLED */
#define DEFINE_ZIL_COMMIT_IO_ERROR_EVENT(name) \
DEFINE_EVENT(zfs_zil_commit_io_error_class, name, \
- TP_PROTO(zilog_t *zilog, zil_commit_waiter_t *zcw), \
- TP_ARGS(zilog, zcw))
+ TP_PROTO(zilog_t *zilog, zil_commit_waiter_t *zcw), \
+ TP_ARGS(zilog, zcw))
DEFINE_ZIL_COMMIT_IO_ERROR_EVENT(zfs_zil__commit__io__error);
-/* END CSTYLED */
#endif /* _TRACE_ZIL_H */
diff --git a/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_zrlock.h b/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_zrlock.h
index 23f9577ba15f..b504e66f9f7b 100644
--- a/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_zrlock.h
+++ b/sys/contrib/openzfs/include/os/linux/zfs/sys/trace_zrlock.h
@@ -70,12 +70,12 @@ DECLARE_EVENT_CLASS(zfs_zrlock_class,
__entry->refcount, __entry->n)
#endif
);
-/* END_CSTYLED */
+/* END CSTYLED */
#define DEFINE_ZRLOCK_EVENT(name) \
DEFINE_EVENT(zfs_zrlock_class, name, \
- TP_PROTO(zrlock_t *zrl, kthread_t *owner, uint32_t n), \
- TP_ARGS(zrl, owner, n))
+ TP_PROTO(zrlock_t *zrl, kthread_t *owner, uint32_t n), \
+ TP_ARGS(zrl, owner, n))
DEFINE_ZRLOCK_EVENT(zfs_zrlock__reentry);
#endif /* _TRACE_ZRLOCK_H */
diff --git a/sys/contrib/openzfs/include/sys/arc_impl.h b/sys/contrib/openzfs/include/sys/arc_impl.h
index 3c5af9d86340..755e87fe6e0e 100644
--- a/sys/contrib/openzfs/include/sys/arc_impl.h
+++ b/sys/contrib/openzfs/include/sys/arc_impl.h
@@ -250,7 +250,8 @@ typedef struct l2arc_dev_hdr_phys {
const uint64_t dh_pad[30]; /* pad to 512 bytes */
zio_eck_t dh_tail;
} l2arc_dev_hdr_phys_t;
-CTASSERT_GLOBAL(sizeof (l2arc_dev_hdr_phys_t) == SPA_MINBLOCKSIZE);
+_Static_assert(sizeof (l2arc_dev_hdr_phys_t) == SPA_MINBLOCKSIZE,
+ "l2arc_dev_hdr_phys_t wrong size");
/*
* A single ARC buffer header entry in a l2arc_log_blk_phys_t.
@@ -307,10 +308,12 @@ typedef struct l2arc_log_blk_phys {
* The size of l2arc_log_blk_phys_t has to be power-of-2 aligned with
* SPA_MINBLOCKSHIFT because of L2BLK_SET_*SIZE macros.
*/
-CTASSERT_GLOBAL(IS_P2ALIGNED(sizeof (l2arc_log_blk_phys_t),
- 1ULL << SPA_MINBLOCKSHIFT));
-CTASSERT_GLOBAL(sizeof (l2arc_log_blk_phys_t) >= SPA_MINBLOCKSIZE);
-CTASSERT_GLOBAL(sizeof (l2arc_log_blk_phys_t) <= SPA_MAXBLOCKSIZE);
+_Static_assert(IS_P2ALIGNED(sizeof (l2arc_log_blk_phys_t),
+ 1ULL << SPA_MINBLOCKSHIFT), "l2arc_log_blk_phys_t misaligned");
+_Static_assert(sizeof (l2arc_log_blk_phys_t) >= SPA_MINBLOCKSIZE,
+ "l2arc_log_blk_phys_t too small");
+_Static_assert(sizeof (l2arc_log_blk_phys_t) <= SPA_MAXBLOCKSIZE,
+ "l2arc_log_blk_phys_t too big");
/*
* These structures hold in-flight abd buffers for log blocks as they're being
diff --git a/sys/contrib/openzfs/include/sys/crypto/api.h b/sys/contrib/openzfs/include/sys/crypto/api.h
index 17c9a645922e..b3d6c9c071b9 100644
--- a/sys/contrib/openzfs/include/sys/crypto/api.h
+++ b/sys/contrib/openzfs/include/sys/crypto/api.h
@@ -33,30 +33,12 @@ extern "C" {
#include <sys/zfs_context.h>
#include <sys/crypto/common.h>
-typedef long crypto_req_id_t;
-typedef void *crypto_bc_t;
typedef void *crypto_context_t;
typedef void *crypto_ctx_template_t;
-typedef uint32_t crypto_call_flag_t;
-
-/* crypto_call_flag's values */
-#define CRYPTO_ALWAYS_QUEUE 0x00000001 /* ALWAYS queue the req. */
-#define CRYPTO_NOTIFY_OPDONE 0x00000002 /* Notify intermediate steps */
-#define CRYPTO_SKIP_REQID 0x00000004 /* Skip request ID generation */
-#define CRYPTO_RESTRICTED 0x00000008 /* cannot use restricted prov */
-
-typedef struct {
- crypto_call_flag_t cr_flag;
- void (*cr_callback_func)(void *, int);
- void *cr_callback_arg;
- crypto_req_id_t cr_reqid;
-} crypto_call_req_t;
-
/*
* Returns the mechanism type corresponding to a mechanism name.
*/
-
#define CRYPTO_MECH_INVALID ((uint64_t)-1)
extern crypto_mech_type_t crypto_mech2id(const char *name);
@@ -64,359 +46,26 @@ extern crypto_mech_type_t crypto_mech2id(const char *name);
* Create and destroy context templates.
*/
extern int crypto_create_ctx_template(crypto_mechanism_t *mech,
- crypto_key_t *key, crypto_ctx_template_t *tmpl, int kmflag);
+ crypto_key_t *key, crypto_ctx_template_t *tmpl);
extern void crypto_destroy_ctx_template(crypto_ctx_template_t tmpl);
/*
- * Single and multi-part digest operations.
- */
-extern int crypto_digest(crypto_mechanism_t *mech, crypto_data_t *data,
- crypto_data_t *digest, crypto_call_req_t *cr);
-extern int crypto_digest_prov(crypto_provider_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_data_t *, crypto_data_t *,
- crypto_call_req_t *);
-extern int crypto_digest_init(crypto_mechanism_t *mech, crypto_context_t *ctxp,
- crypto_call_req_t *cr);
-extern int crypto_digest_init_prov(crypto_provider_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_context_t *, crypto_call_req_t *);
-extern int crypto_digest_update(crypto_context_t ctx, crypto_data_t *data,
- crypto_call_req_t *cr);
-extern int crypto_digest_final(crypto_context_t ctx, crypto_data_t *digest,
- crypto_call_req_t *cr);
-
-/*
* Single and multi-part MAC operations.
*/
extern int crypto_mac(crypto_mechanism_t *mech, crypto_data_t *data,
- crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *mac,
- crypto_call_req_t *cr);
-extern int crypto_mac_prov(crypto_provider_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_data_t *, crypto_key_t *,
- crypto_ctx_template_t, crypto_data_t *, crypto_call_req_t *);
-extern int crypto_mac_verify(crypto_mechanism_t *mech, crypto_data_t *data,
- crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *mac,
- crypto_call_req_t *cr);
-extern int crypto_mac_verify_prov(crypto_provider_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_data_t *, crypto_key_t *,
- crypto_ctx_template_t, crypto_data_t *, crypto_call_req_t *);
+ crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *mac);
extern int crypto_mac_init(crypto_mechanism_t *mech, crypto_key_t *key,
- crypto_ctx_template_t tmpl, crypto_context_t *ctxp, crypto_call_req_t *cr);
-extern int crypto_mac_init_prov(crypto_provider_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_key_t *, crypto_ctx_template_t,
- crypto_context_t *, crypto_call_req_t *);
-extern int crypto_mac_update(crypto_context_t ctx, crypto_data_t *data,
- crypto_call_req_t *cr);
-extern int crypto_mac_final(crypto_context_t ctx, crypto_data_t *data,
- crypto_call_req_t *cr);
+ crypto_ctx_template_t tmpl, crypto_context_t *ctxp);
+extern int crypto_mac_update(crypto_context_t ctx, crypto_data_t *data);
+extern int crypto_mac_final(crypto_context_t ctx, crypto_data_t *data);
/*
- * Single and multi-part sign with private key operations.
- */
-extern int crypto_sign(crypto_mechanism_t *mech, crypto_key_t *key,
- crypto_data_t *data, crypto_ctx_template_t tmpl,
- crypto_data_t *signature, crypto_call_req_t *cr);
-extern int crypto_sign_prov(crypto_provider_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
- crypto_ctx_template_t, crypto_data_t *, crypto_call_req_t *);
-extern int crypto_sign_init(crypto_mechanism_t *mech, crypto_key_t *key,
- crypto_ctx_template_t tmpl, crypto_context_t *ctxp, crypto_call_req_t *cr);
-extern int crypto_sign_init_prov(crypto_provider_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_key_t *, crypto_ctx_template_t,
- crypto_context_t *, crypto_call_req_t *);
-extern int crypto_sign_update(crypto_context_t ctx, crypto_data_t *data,
- crypto_call_req_t *cr);
-extern int crypto_sign_final(crypto_context_t ctx, crypto_data_t *signature,
- crypto_call_req_t *cr);
-extern int crypto_sign_recover_init_prov(crypto_provider_t,
- crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *,
- crypto_ctx_template_t tmpl, crypto_context_t *, crypto_call_req_t *);
-extern int crypto_sign_recover(crypto_mechanism_t *mech, crypto_key_t *key,
- crypto_data_t *data, crypto_ctx_template_t tmpl, crypto_data_t *signature,
- crypto_call_req_t *cr);
-extern int crypto_sign_recover_prov(crypto_provider_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
- crypto_ctx_template_t, crypto_data_t *, crypto_call_req_t *);
-
-/*
- * Single and multi-part verify with public key operations.
- */
-extern int crypto_verify(crypto_mechanism_t *mech, crypto_key_t *key,
- crypto_data_t *data, crypto_ctx_template_t tmpl, crypto_data_t *signature,
- crypto_call_req_t *cr);
-extern int crypto_verify_prov(crypto_provider_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
- crypto_ctx_template_t, crypto_data_t *, crypto_call_req_t *);
-extern int crypto_verify_init(crypto_mechanism_t *mech, crypto_key_t *key,
- crypto_ctx_template_t tmpl, crypto_context_t *ctxp, crypto_call_req_t *cr);
-extern int crypto_verify_init_prov(crypto_provider_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_key_t *, crypto_ctx_template_t,
- crypto_context_t *, crypto_call_req_t *);
-extern int crypto_verify_update(crypto_context_t ctx, crypto_data_t *data,
- crypto_call_req_t *cr);
-extern int crypto_verify_final(crypto_context_t ctx, crypto_data_t *signature,
- crypto_call_req_t *cr);
-extern int crypto_verify_recover_init_prov(crypto_provider_t,
- crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *,
- crypto_ctx_template_t tmpl, crypto_context_t *, crypto_call_req_t *);
-extern int crypto_verify_recover(crypto_mechanism_t *mech, crypto_key_t *key,
- crypto_data_t *signature, crypto_ctx_template_t tmpl, crypto_data_t *data,
- crypto_call_req_t *cr);
-extern int crypto_verify_recover_prov(crypto_provider_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
- crypto_ctx_template_t, crypto_data_t *, crypto_call_req_t *);
-
-/*
- * Single and multi-part encryption operations.
+ * Single-part encryption/decryption operations.
*/
extern int crypto_encrypt(crypto_mechanism_t *mech, crypto_data_t *plaintext,
- crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *ciphertext,
- crypto_call_req_t *cr);
-extern int crypto_encrypt_prov(crypto_provider_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_data_t *, crypto_key_t *,
- crypto_ctx_template_t, crypto_data_t *, crypto_call_req_t *);
-extern int crypto_encrypt_init(crypto_mechanism_t *mech, crypto_key_t *key,
- crypto_ctx_template_t tmpl, crypto_context_t *ctxp, crypto_call_req_t *cr);
-extern int crypto_encrypt_init_prov(crypto_provider_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_key_t *, crypto_ctx_template_t,
- crypto_context_t *, crypto_call_req_t *);
-extern int crypto_encrypt_update(crypto_context_t ctx,
- crypto_data_t *plaintext, crypto_data_t *ciphertext,
- crypto_call_req_t *cr);
-extern int crypto_encrypt_final(crypto_context_t ctx,
- crypto_data_t *ciphertext, crypto_call_req_t *cr);
-
-/*
- * Single and multi-part decryption operations.
- */
+ crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *ciphertext);
extern int crypto_decrypt(crypto_mechanism_t *mech, crypto_data_t *ciphertext,
- crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *plaintext,
- crypto_call_req_t *cr);
-extern int crypto_decrypt_prov(crypto_provider_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_data_t *, crypto_key_t *,
- crypto_ctx_template_t, crypto_data_t *, crypto_call_req_t *);
-extern int crypto_decrypt_init(crypto_mechanism_t *mech, crypto_key_t *key,
- crypto_ctx_template_t tmpl, crypto_context_t *ctxp,
- crypto_call_req_t *cr);
-extern int crypto_decrypt_init_prov(crypto_provider_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_key_t *, crypto_ctx_template_t,
- crypto_context_t *, crypto_call_req_t *);
-extern int crypto_decrypt_update(crypto_context_t ctx,
- crypto_data_t *ciphertext, crypto_data_t *plaintext,
- crypto_call_req_t *cr);
-extern int crypto_decrypt_final(crypto_context_t ctx, crypto_data_t *plaintext,
- crypto_call_req_t *cr);
-
-/*
- * Single and multi-part encrypt/MAC dual operations.
- */
-extern int crypto_encrypt_mac(crypto_mechanism_t *encr_mech,
- crypto_mechanism_t *mac_mech, crypto_data_t *pt,
- crypto_key_t *encr_key, crypto_key_t *mac_key,
- crypto_ctx_template_t encr_tmpl, crypto_ctx_template_t mac_tmpl,
- crypto_dual_data_t *ct, crypto_data_t *mac, crypto_call_req_t *cr);
-extern int crypto_encrypt_mac_prov(crypto_provider_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_mechanism_t *, crypto_data_t *,
- crypto_key_t *, crypto_key_t *, crypto_ctx_template_t,
- crypto_ctx_template_t, crypto_dual_data_t *, crypto_data_t *,
- crypto_call_req_t *);
-extern int crypto_encrypt_mac_init(crypto_mechanism_t *encr_mech,
- crypto_mechanism_t *mac_mech, crypto_key_t *encr_key,
- crypto_key_t *mac_key, crypto_ctx_template_t encr_tmpl,
- crypto_ctx_template_t mac_tmpl, crypto_context_t *ctxp,
- crypto_call_req_t *cr);
-extern int crypto_encrypt_mac_init_prov(crypto_provider_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_mechanism_t *, crypto_key_t *, crypto_key_t *,
- crypto_ctx_template_t, crypto_ctx_template_t, crypto_context_t *,
- crypto_call_req_t *);
-extern int crypto_encrypt_mac_update(crypto_context_t ctx,
- crypto_data_t *pt, crypto_dual_data_t *ct, crypto_call_req_t *cr);
-extern int crypto_encrypt_mac_final(crypto_context_t ctx,
- crypto_dual_data_t *ct, crypto_data_t *mac, crypto_call_req_t *cr);
-
-/*
- * Single and multi-part MAC/decrypt dual operations.
- */
-extern int crypto_mac_decrypt(crypto_mechanism_t *mac_mech,
- crypto_mechanism_t *decr_mech, crypto_dual_data_t *ct,
- crypto_key_t *mac_key, crypto_key_t *decr_key,
- crypto_ctx_template_t mac_tmpl, crypto_ctx_template_t decr_tmpl,
- crypto_data_t *mac, crypto_data_t *pt, crypto_call_req_t *cr);
-extern int crypto_mac_decrypt_prov(crypto_provider_t, crypto_session_id_t,
- crypto_mechanism_t *mac_mech, crypto_mechanism_t *decr_mech,
- crypto_dual_data_t *ct, crypto_key_t *mac_key, crypto_key_t *decr_key,
- crypto_ctx_template_t mac_tmpl, crypto_ctx_template_t decr_tmpl,
- crypto_data_t *mac, crypto_data_t *pt, crypto_call_req_t *cr);
-extern int crypto_mac_verify_decrypt(crypto_mechanism_t *mac_mech,
- crypto_mechanism_t *decr_mech, crypto_dual_data_t *ct,
- crypto_key_t *mac_key, crypto_key_t *decr_key,
- crypto_ctx_template_t mac_tmpl, crypto_ctx_template_t decr_tmpl,
- crypto_data_t *mac, crypto_data_t *pt, crypto_call_req_t *cr);
-extern int crypto_mac_verify_decrypt_prov(crypto_provider_t,
- crypto_session_id_t, crypto_mechanism_t *mac_mech,
- crypto_mechanism_t *decr_mech, crypto_dual_data_t *ct,
- crypto_key_t *mac_key, crypto_key_t *decr_key,
- crypto_ctx_template_t mac_tmpl, crypto_ctx_template_t decr_tmpl,
- crypto_data_t *mac, crypto_data_t *pt, crypto_call_req_t *cr);
-extern int crypto_mac_decrypt_init(crypto_mechanism_t *mac_mech,
- crypto_mechanism_t *decr_mech, crypto_key_t *mac_key,
- crypto_key_t *decr_key, crypto_ctx_template_t mac_tmpl,
- crypto_ctx_template_t decr_tmpl, crypto_context_t *ctxp,
- crypto_call_req_t *cr);
-extern int crypto_mac_decrypt_init_prov(crypto_provider_t,
- crypto_session_id_t, crypto_mechanism_t *mac_mech,
- crypto_mechanism_t *decr_mech, crypto_key_t *mac_key,
- crypto_key_t *decr_key, crypto_ctx_template_t mac_tmpl,
- crypto_ctx_template_t decr_tmpl, crypto_context_t *ctxp,
- crypto_call_req_t *cr);
-extern int crypto_mac_decrypt_update(crypto_context_t ctx,
- crypto_dual_data_t *ct, crypto_data_t *pt, crypto_call_req_t *cr);
-extern int crypto_mac_decrypt_final(crypto_context_t ctx, crypto_data_t *mac,
- crypto_data_t *pt, crypto_call_req_t *cr);
-
-/* Session Management */
-extern int crypto_session_open(crypto_provider_t, crypto_session_id_t *,
- crypto_call_req_t *);
-extern int crypto_session_close(crypto_provider_t, crypto_session_id_t,
- crypto_call_req_t *);
-extern int crypto_session_login(crypto_provider_t, crypto_session_id_t,
- crypto_user_type_t, char *, size_t, crypto_call_req_t *);
-extern int crypto_session_logout(crypto_provider_t, crypto_session_id_t,
- crypto_call_req_t *);
-
-/* Object Management */
-extern int crypto_object_copy(crypto_provider_t, crypto_session_id_t,
- crypto_object_id_t, crypto_object_attribute_t *, uint_t,
- crypto_object_id_t *, crypto_call_req_t *);
-extern int crypto_object_create(crypto_provider_t, crypto_session_id_t,
- crypto_object_attribute_t *, uint_t, crypto_object_id_t *,
- crypto_call_req_t *);
-extern int crypto_object_destroy(crypto_provider_t, crypto_session_id_t,
- crypto_object_id_t, crypto_call_req_t *);
-extern int crypto_object_get_attribute_value(crypto_provider_t,
- crypto_session_id_t, crypto_object_id_t, crypto_object_attribute_t *,
- uint_t, crypto_call_req_t *);
-extern int crypto_object_get_size(crypto_provider_t, crypto_session_id_t,
- crypto_object_id_t, size_t *, crypto_call_req_t *);
-extern int crypto_object_find_final(crypto_provider_t, void *,
- crypto_call_req_t *);
-extern int crypto_object_find_init(crypto_provider_t, crypto_session_id_t,
- crypto_object_attribute_t *, uint_t, void **, crypto_call_req_t *);
-extern int crypto_object_find(crypto_provider_t, void *, crypto_object_id_t *,
- uint_t *, uint_t, crypto_call_req_t *);
-extern int crypto_object_set_attribute_value(crypto_provider_t,
- crypto_session_id_t, crypto_object_id_t, crypto_object_attribute_t *,
- uint_t, crypto_call_req_t *);
-
-/* Key Management */
-extern int crypto_key_derive(crypto_provider_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_key_t *, crypto_object_attribute_t *,
- uint_t, crypto_object_id_t *, crypto_call_req_t *);
-extern int crypto_key_generate(crypto_provider_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_object_attribute_t *, uint_t,
- crypto_object_id_t *, crypto_call_req_t *);
-extern int crypto_key_generate_pair(crypto_provider_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_object_attribute_t *, uint_t,
- crypto_object_attribute_t *, uint_t, crypto_object_id_t *,
- crypto_object_id_t *, crypto_call_req_t *);
-extern int crypto_key_unwrap(crypto_provider_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_key_t *, uchar_t *, size_t *,
- crypto_object_attribute_t *, uint_t, crypto_object_id_t *,
- crypto_call_req_t *);
-extern int crypto_key_wrap(crypto_provider_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_key_t *, crypto_object_id_t *, uchar_t *,
- size_t *, crypto_call_req_t *);
-extern int crypto_key_check_prov(crypto_provider_t, crypto_mechanism_t *mech,
- crypto_key_t *key);
-extern int crypto_key_check(crypto_mechanism_t *mech, crypto_key_t *key);
-
-
-/*
- * Routines to cancel a single asynchronous request or all asynchronous
- * requests associated with a particular context.
- */
-extern void crypto_cancel_req(crypto_req_id_t req);
-extern void crypto_cancel_ctx(crypto_context_t ctx);
-
-/*
- * crypto_get_mech_list(9F) allocates and returns the list of currently
- * supported cryptographic mechanisms.
- */
-extern crypto_mech_name_t *crypto_get_mech_list(uint_t *count, int kmflag);
-extern void crypto_free_mech_list(crypto_mech_name_t *mech_names,
- uint_t count);
-
-extern crypto_provider_t crypto_get_provider(char *, char *, char *);
-extern int crypto_get_provinfo(crypto_provider_t, crypto_provider_ext_info_t *);
-extern void crypto_release_provider(crypto_provider_t);
-
-/*
- * A kernel consumer can request to be notified when some particular event
- * occurs. The valid events, callback function type, and functions to
- * be called to register or unregister for notification are defined below.
- */
-
-#define CRYPTO_EVENT_MECHS_CHANGED 0x00000001
-#define CRYPTO_EVENT_PROVIDER_REGISTERED 0x00000002
-#define CRYPTO_EVENT_PROVIDER_UNREGISTERED 0x00000004
-
-typedef enum {
- CRYPTO_MECH_ADDED = 1,
- CRYPTO_MECH_REMOVED
-} crypto_event_change_t;
-
-/* The event_arg argument structure for CRYPTO_EVENT_PROVIDERS_CHANGE event */
-typedef struct crypto_notify_event_change {
- crypto_mech_name_t ec_mech_name;
- crypto_provider_type_t ec_provider_type;
- crypto_event_change_t ec_change;
-} crypto_notify_event_change_t;
-
-typedef void *crypto_notify_handle_t;
-typedef void (*crypto_notify_callback_t)(uint32_t event_mask, void *event_arg);
-
-extern crypto_notify_handle_t crypto_notify_events(
- crypto_notify_callback_t nf, uint32_t event_mask);
-extern void crypto_unnotify_events(crypto_notify_handle_t);
-
-/*
- * crypto_bufcall(9F) group of routines.
- */
-extern crypto_bc_t crypto_bufcall_alloc(void);
-extern int crypto_bufcall_free(crypto_bc_t bc);
-extern int crypto_bufcall(crypto_bc_t bc, void (*func)(void *arg), void *arg);
-extern int crypto_unbufcall(crypto_bc_t bc);
-
-/*
- * To obtain the list of key size ranges supported by a mechanism.
- */
-
-#define CRYPTO_MECH_USAGE_ENCRYPT 0x00000001
-#define CRYPTO_MECH_USAGE_DECRYPT 0x00000002
-#define CRYPTO_MECH_USAGE_MAC 0x00000004
-
-typedef uint32_t crypto_mech_usage_t;
-
-typedef struct crypto_mechanism_info {
- size_t mi_min_key_size;
- size_t mi_max_key_size;
- crypto_keysize_unit_t mi_keysize_unit; /* for mi_xxx_key_size */
- crypto_mech_usage_t mi_usage;
-} crypto_mechanism_info_t;
-
-#ifdef _SYSCALL32
-
-typedef struct crypto_mechanism_info32 {
- size32_t mi_min_key_size;
- size32_t mi_max_key_size;
- crypto_keysize_unit_t mi_keysize_unit; /* for mi_xxx_key_size */
- crypto_mech_usage_t mi_usage;
-} crypto_mechanism_info32_t;
-
-#endif /* _SYSCALL32 */
-
-extern int crypto_get_all_mech_info(crypto_mech_type_t,
- crypto_mechanism_info_t **, uint_t *, int);
-extern void crypto_free_all_mech_info(crypto_mechanism_info_t *, uint_t);
+ crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *plaintext);
#ifdef __cplusplus
}
diff --git a/sys/contrib/openzfs/include/sys/crypto/common.h b/sys/contrib/openzfs/include/sys/crypto/common.h
index 9a239225cd10..45a95d7eed71 100644
--- a/sys/contrib/openzfs/include/sys/crypto/common.h
+++ b/sys/contrib/openzfs/include/sys/crypto/common.h
@@ -51,16 +51,6 @@ typedef struct crypto_mechanism {
size_t cm_param_len; /* mech. parameter len */
} crypto_mechanism_t;
-#ifdef _SYSCALL32
-
-typedef struct crypto_mechanism32 {
- crypto_mech_type_t cm_type; /* mechanism type */
- caddr32_t cm_param; /* mech. parameter */
- size32_t cm_param_len; /* mech. parameter len */
-} crypto_mechanism32_t;
-
-#endif /* _SYSCALL32 */
-
/* CK_AES_CTR_PARAMS provides parameters to the CKM_AES_CTR mechanism */
typedef struct CK_AES_CTR_PARAMS {
ulong_t ulCounterBits;
@@ -95,88 +85,13 @@ typedef struct CK_AES_GMAC_PARAMS {
} CK_AES_GMAC_PARAMS;
/*
- * CK_ECDH1_DERIVE_PARAMS provides the parameters to the
- * CKM_ECDH1_KEY_DERIVE mechanism
- */
-typedef struct CK_ECDH1_DERIVE_PARAMS {
- ulong_t kdf;
- ulong_t ulSharedDataLen;
- uchar_t *pSharedData;
- ulong_t ulPublicDataLen;
- uchar_t *pPublicData;
-} CK_ECDH1_DERIVE_PARAMS;
-
-#ifdef _SYSCALL32
-
-/* needed for 32-bit applications running on 64-bit kernels */
-typedef struct CK_AES_CTR_PARAMS32 {
- uint32_t ulCounterBits;
- uint8_t cb[16];
-} CK_AES_CTR_PARAMS32;
-
-/* needed for 32-bit applications running on 64-bit kernels */
-typedef struct CK_AES_CCM_PARAMS32 {
- uint32_t ulMACSize;
- uint32_t ulNonceSize;
- uint32_t ulAuthDataSize;
- uint32_t ulDataSize;
- caddr32_t nonce;
- caddr32_t authData;
-} CK_AES_CCM_PARAMS32;
-
-/* needed for 32-bit applications running on 64-bit kernels */
-typedef struct CK_AES_GCM_PARAMS32 {
- caddr32_t pIv;
- uint32_t ulIvLen;
- uint32_t ulIvBits;
- caddr32_t pAAD;
- uint32_t ulAADLen;
- uint32_t ulTagBits;
-} CK_AES_GCM_PARAMS32;
-
-/* needed for 32-bit applications running on 64-bit kernels */
-typedef struct CK_AES_GMAC_PARAMS32 {
- caddr32_t pIv;
- caddr32_t pAAD;
- uint32_t ulAADLen;
-} CK_AES_GMAC_PARAMS32;
-
-typedef struct CK_ECDH1_DERIVE_PARAMS32 {
- uint32_t kdf;
- uint32_t ulSharedDataLen;
- caddr32_t pSharedData;
- uint32_t ulPublicDataLen;
- caddr32_t pPublicData;
-} CK_ECDH1_DERIVE_PARAMS32;
-
-#endif /* _SYSCALL32 */
-
-/*
* The measurement unit bit flag for a mechanism's minimum or maximum key size.
* The unit are mechanism dependent. It can be in bits or in bytes.
*/
typedef uint32_t crypto_keysize_unit_t;
-/*
- * The following bit flags are valid in cm_mech_flags field in
- * the crypto_mech_info_t structure of the SPI.
- *
- * Only the first two bit flags are valid in mi_keysize_unit
- * field in the crypto_mechanism_info_t structure of the API.
- */
-#define CRYPTO_KEYSIZE_UNIT_IN_BITS 0x00000001
-#define CRYPTO_KEYSIZE_UNIT_IN_BYTES 0x00000002
-#define CRYPTO_CAN_SHARE_OPSTATE 0x00000004 /* supports sharing */
-
/* Mechanisms supported out-of-the-box */
-#define SUN_CKM_MD4 "CKM_MD4"
-#define SUN_CKM_MD5 "CKM_MD5"
-#define SUN_CKM_MD5_HMAC "CKM_MD5_HMAC"
-#define SUN_CKM_MD5_HMAC_GENERAL "CKM_MD5_HMAC_GENERAL"
-#define SUN_CKM_SHA1 "CKM_SHA_1"
-#define SUN_CKM_SHA1_HMAC "CKM_SHA_1_HMAC"
-#define SUN_CKM_SHA1_HMAC_GENERAL "CKM_SHA_1_HMAC_GENERAL"
#define SUN_CKM_SHA256 "CKM_SHA256"
#define SUN_CKM_SHA256_HMAC "CKM_SHA256_HMAC"
#define SUN_CKM_SHA256_HMAC_GENERAL "CKM_SHA256_HMAC_GENERAL"
@@ -188,44 +103,12 @@ typedef uint32_t crypto_keysize_unit_t;
#define SUN_CKM_SHA512_HMAC_GENERAL "CKM_SHA512_HMAC_GENERAL"
#define SUN_CKM_SHA512_224 "CKM_SHA512_224"
#define SUN_CKM_SHA512_256 "CKM_SHA512_256"
-#define SUN_CKM_DES_CBC "CKM_DES_CBC"
-#define SUN_CKM_DES3_CBC "CKM_DES3_CBC"
-#define SUN_CKM_DES_ECB "CKM_DES_ECB"
-#define SUN_CKM_DES3_ECB "CKM_DES3_ECB"
-#define SUN_CKM_BLOWFISH_CBC "CKM_BLOWFISH_CBC"
-#define SUN_CKM_BLOWFISH_ECB "CKM_BLOWFISH_ECB"
#define SUN_CKM_AES_CBC "CKM_AES_CBC"
#define SUN_CKM_AES_ECB "CKM_AES_ECB"
#define SUN_CKM_AES_CTR "CKM_AES_CTR"
#define SUN_CKM_AES_CCM "CKM_AES_CCM"
#define SUN_CKM_AES_GCM "CKM_AES_GCM"
#define SUN_CKM_AES_GMAC "CKM_AES_GMAC"
-#define SUN_CKM_AES_CFB128 "CKM_AES_CFB128"
-#define SUN_CKM_RC4 "CKM_RC4"
-#define SUN_CKM_RSA_PKCS "CKM_RSA_PKCS"
-#define SUN_CKM_RSA_X_509 "CKM_RSA_X_509"
-#define SUN_CKM_MD5_RSA_PKCS "CKM_MD5_RSA_PKCS"
-#define SUN_CKM_SHA1_RSA_PKCS "CKM_SHA1_RSA_PKCS"
-#define SUN_CKM_SHA256_RSA_PKCS "CKM_SHA256_RSA_PKCS"
-#define SUN_CKM_SHA384_RSA_PKCS "CKM_SHA384_RSA_PKCS"
-#define SUN_CKM_SHA512_RSA_PKCS "CKM_SHA512_RSA_PKCS"
-#define SUN_CKM_EC_KEY_PAIR_GEN "CKM_EC_KEY_PAIR_GEN"
-#define SUN_CKM_ECDH1_DERIVE "CKM_ECDH1_DERIVE"
-#define SUN_CKM_ECDSA_SHA1 "CKM_ECDSA_SHA1"
-#define SUN_CKM_ECDSA "CKM_ECDSA"
-
-/* Shared operation context format for CKM_RC4 */
-typedef struct {
-#if defined(__amd64)
- uint32_t i, j;
- uint32_t arr[256];
- uint32_t flag;
-#else
- uchar_t arr[256];
- uchar_t i, j;
-#endif /* __amd64 */
- uint64_t pad; /* For 64-bit alignment */
-} arcfour_state_t;
/* Data arguments of cryptographic operations */
@@ -238,140 +121,22 @@ typedef struct crypto_data {
crypto_data_format_t cd_format; /* Format identifier */
off_t cd_offset; /* Offset from the beginning */
size_t cd_length; /* # of bytes in use */
- caddr_t cd_miscdata; /* ancillary data */
union {
/* Raw format */
- iovec_t cdu_raw; /* Pointer and length */
+ iovec_t cd_raw; /* Pointer and length */
/* uio scatter-gather format */
- zfs_uio_t *cdu_uio;
-
- } cdu; /* Crypto Data Union */
+ zfs_uio_t *cd_uio;
+ }; /* Crypto Data Union */
} crypto_data_t;
-#define cd_raw cdu.cdu_raw
-#define cd_uio cdu.cdu_uio
-#define cd_mp cdu.cdu_mp
-
-typedef struct crypto_dual_data {
- crypto_data_t dd_data; /* The data */
- off_t dd_offset2; /* Used by dual operation */
- size_t dd_len2; /* # of bytes to take */
-} crypto_dual_data_t;
-
-#define dd_format dd_data.cd_format
-#define dd_offset1 dd_data.cd_offset
-#define dd_len1 dd_data.cd_length
-#define dd_miscdata dd_data.cd_miscdata
-#define dd_raw dd_data.cd_raw
-#define dd_uio dd_data.cd_uio
-#define dd_mp dd_data.cd_mp
-
/* The keys, and their contents */
-typedef enum {
- CRYPTO_KEY_RAW = 1, /* ck_data is a cleartext key */
- CRYPTO_KEY_REFERENCE, /* ck_obj_id is an opaque reference */
- CRYPTO_KEY_ATTR_LIST /* ck_attrs is a list of object attributes */
-} crypto_key_format_t;
-
-typedef uint64_t crypto_attr_type_t;
-
-/* Attribute types to use for passing a RSA public key or a private key. */
-#define SUN_CKA_MODULUS 0x00000120
-#define SUN_CKA_MODULUS_BITS 0x00000121
-#define SUN_CKA_PUBLIC_EXPONENT 0x00000122
-#define SUN_CKA_PRIVATE_EXPONENT 0x00000123
-#define SUN_CKA_PRIME_1 0x00000124
-#define SUN_CKA_PRIME_2 0x00000125
-#define SUN_CKA_EXPONENT_1 0x00000126
-#define SUN_CKA_EXPONENT_2 0x00000127
-#define SUN_CKA_COEFFICIENT 0x00000128
-#define SUN_CKA_PRIME 0x00000130
-#define SUN_CKA_SUBPRIME 0x00000131
-#define SUN_CKA_BASE 0x00000132
-
-#define CKK_EC 0x00000003
-#define CKK_GENERIC_SECRET 0x00000010
-#define CKK_RC4 0x00000012
-#define CKK_AES 0x0000001F
-#define CKK_DES 0x00000013
-#define CKK_DES2 0x00000014
-#define CKK_DES3 0x00000015
-
-#define CKO_PUBLIC_KEY 0x00000002
-#define CKO_PRIVATE_KEY 0x00000003
-#define CKA_CLASS 0x00000000
-#define CKA_VALUE 0x00000011
-#define CKA_KEY_TYPE 0x00000100
-#define CKA_VALUE_LEN 0x00000161
-#define CKA_EC_PARAMS 0x00000180
-#define CKA_EC_POINT 0x00000181
-
-typedef uint32_t crypto_object_id_t;
-
-typedef struct crypto_object_attribute {
- crypto_attr_type_t oa_type; /* attribute type */
- caddr_t oa_value; /* attribute value */
- ssize_t oa_value_len; /* length of attribute value */
-} crypto_object_attribute_t;
-
-typedef struct crypto_key {
- crypto_key_format_t ck_format; /* format identifier */
- union {
- /* for CRYPTO_KEY_RAW ck_format */
- struct {
- uint_t cku_v_length; /* # of bits in ck_data */
- void *cku_v_data; /* ptr to key value */
- } cku_key_value;
-
- /* for CRYPTO_KEY_REFERENCE ck_format */
- crypto_object_id_t cku_key_id; /* reference to object key */
-
- /* for CRYPTO_KEY_ATTR_LIST ck_format */
- struct {
- uint_t cku_a_count; /* number of attributes */
- crypto_object_attribute_t *cku_a_oattr;
- } cku_key_attrs;
- } cku_data; /* Crypto Key union */
+typedef struct {
+ uint_t ck_length; /* # of bits in ck_data */
+ void *ck_data; /* ptr to key value */
} crypto_key_t;
-#ifdef _SYSCALL32
-
-typedef struct crypto_object_attribute32 {
- uint64_t oa_type; /* attribute type */
- caddr32_t oa_value; /* attribute value */
- ssize32_t oa_value_len; /* length of attribute value */
-} crypto_object_attribute32_t;
-
-typedef struct crypto_key32 {
- crypto_key_format_t ck_format; /* format identifier */
- union {
- /* for CRYPTO_KEY_RAW ck_format */
- struct {
- uint32_t cku_v_length; /* # of bytes in ck_data */
- caddr32_t cku_v_data; /* ptr to key value */
- } cku_key_value;
-
- /* for CRYPTO_KEY_REFERENCE ck_format */
- crypto_object_id_t cku_key_id; /* reference to object key */
-
- /* for CRYPTO_KEY_ATTR_LIST ck_format */
- struct {
- uint32_t cku_a_count; /* number of attributes */
- caddr32_t cku_a_oattr;
- } cku_key_attrs;
- } cku_data; /* Crypto Key union */
-} crypto_key32_t;
-
-#endif /* _SYSCALL32 */
-
-#define ck_data cku_data.cku_key_value.cku_v_data
-#define ck_length cku_data.cku_key_value.cku_v_length
-#define ck_obj_id cku_data.cku_key_id
-#define ck_count cku_data.cku_key_attrs.cku_a_count
-#define ck_attrs cku_data.cku_key_attrs.cku_a_oattr
-
/*
* Raw key lengths are expressed in number of bits.
* The following macro returns the minimum number of
@@ -383,198 +148,37 @@ typedef struct crypto_key32 {
/* Providers */
-typedef enum {
- CRYPTO_HW_PROVIDER = 0,
- CRYPTO_SW_PROVIDER,
- CRYPTO_LOGICAL_PROVIDER
-} crypto_provider_type_t;
-
typedef uint32_t crypto_provider_id_t;
#define KCF_PROVID_INVALID ((uint32_t)-1)
-typedef struct crypto_provider_entry {
- crypto_provider_id_t pe_provider_id;
- uint_t pe_mechanism_count;
-} crypto_provider_entry_t;
-
-typedef struct crypto_dev_list_entry {
- char le_dev_name[MAXNAMELEN];
- uint_t le_dev_instance;
- uint_t le_mechanism_count;
-} crypto_dev_list_entry_t;
-
-/* User type for authentication ioctls and SPI entry points */
-
-typedef enum crypto_user_type {
- CRYPTO_SO = 0,
- CRYPTO_USER
-} crypto_user_type_t;
-
-/* Version for provider management ioctls and SPI entry points */
-
-typedef struct crypto_version {
- uchar_t cv_major;
- uchar_t cv_minor;
-} crypto_version_t;
-
/* session data structure opaque to the consumer */
typedef void *crypto_session_t;
-/* provider data structure opaque to the consumer */
-typedef void *crypto_provider_t;
-
-/* Limits used by both consumers and providers */
-#define CRYPTO_EXT_SIZE_LABEL 32
-#define CRYPTO_EXT_SIZE_MANUF 32
-#define CRYPTO_EXT_SIZE_MODEL 16
-#define CRYPTO_EXT_SIZE_SERIAL 16
-#define CRYPTO_EXT_SIZE_TIME 16
-
-typedef struct crypto_provider_ext_info {
- uchar_t ei_label[CRYPTO_EXT_SIZE_LABEL];
- uchar_t ei_manufacturerID[CRYPTO_EXT_SIZE_MANUF];
- uchar_t ei_model[CRYPTO_EXT_SIZE_MODEL];
- uchar_t ei_serial_number[CRYPTO_EXT_SIZE_SERIAL];
- ulong_t ei_flags;
- ulong_t ei_max_session_count;
- ulong_t ei_max_pin_len;
- ulong_t ei_min_pin_len;
- ulong_t ei_total_public_memory;
- ulong_t ei_free_public_memory;
- ulong_t ei_total_private_memory;
- ulong_t ei_free_private_memory;
- crypto_version_t ei_hardware_version;
- crypto_version_t ei_firmware_version;
- uchar_t ei_time[CRYPTO_EXT_SIZE_TIME];
- int ei_hash_max_input_len;
- int ei_hmac_max_input_len;
-} crypto_provider_ext_info_t;
-
-typedef uint_t crypto_session_id_t;
-
-typedef enum cmd_type {
- COPY_FROM_DATA,
- COPY_TO_DATA,
- COMPARE_TO_DATA,
- MD5_DIGEST_DATA,
- SHA1_DIGEST_DATA,
- SHA2_DIGEST_DATA,
- GHASH_DATA
-} cmd_type_t;
-
-#define CRYPTO_DO_UPDATE 0x01
-#define CRYPTO_DO_FINAL 0x02
-#define CRYPTO_DO_MD5 0x04
-#define CRYPTO_DO_SHA1 0x08
-#define CRYPTO_DO_SIGN 0x10
-#define CRYPTO_DO_VERIFY 0x20
-#define CRYPTO_DO_SHA2 0x40
-
#define PROVIDER_OWNS_KEY_SCHEDULE 0x00000001
/*
* Common cryptographic status and error codes.
*/
#define CRYPTO_SUCCESS 0x00000000
-#define CRYPTO_CANCEL 0x00000001
#define CRYPTO_HOST_MEMORY 0x00000002
-#define CRYPTO_GENERAL_ERROR 0x00000003
#define CRYPTO_FAILED 0x00000004
#define CRYPTO_ARGUMENTS_BAD 0x00000005
-#define CRYPTO_ATTRIBUTE_READ_ONLY 0x00000006
-#define CRYPTO_ATTRIBUTE_SENSITIVE 0x00000007
-#define CRYPTO_ATTRIBUTE_TYPE_INVALID 0x00000008
-#define CRYPTO_ATTRIBUTE_VALUE_INVALID 0x00000009
-#define CRYPTO_CANCELED 0x0000000A
-#define CRYPTO_DATA_INVALID 0x0000000B
#define CRYPTO_DATA_LEN_RANGE 0x0000000C
-#define CRYPTO_DEVICE_ERROR 0x0000000D
-#define CRYPTO_DEVICE_MEMORY 0x0000000E
-#define CRYPTO_DEVICE_REMOVED 0x0000000F
-#define CRYPTO_ENCRYPTED_DATA_INVALID 0x00000010
#define CRYPTO_ENCRYPTED_DATA_LEN_RANGE 0x00000011
-#define CRYPTO_KEY_HANDLE_INVALID 0x00000012
#define CRYPTO_KEY_SIZE_RANGE 0x00000013
#define CRYPTO_KEY_TYPE_INCONSISTENT 0x00000014
-#define CRYPTO_KEY_NOT_NEEDED 0x00000015
-#define CRYPTO_KEY_CHANGED 0x00000016
-#define CRYPTO_KEY_NEEDED 0x00000017
-#define CRYPTO_KEY_INDIGESTIBLE 0x00000018
-#define CRYPTO_KEY_FUNCTION_NOT_PERMITTED 0x00000019
-#define CRYPTO_KEY_NOT_WRAPPABLE 0x0000001A
-#define CRYPTO_KEY_UNEXTRACTABLE 0x0000001B
#define CRYPTO_MECHANISM_INVALID 0x0000001C
#define CRYPTO_MECHANISM_PARAM_INVALID 0x0000001D
-#define CRYPTO_OBJECT_HANDLE_INVALID 0x0000001E
-#define CRYPTO_OPERATION_IS_ACTIVE 0x0000001F
-#define CRYPTO_OPERATION_NOT_INITIALIZED 0x00000020
-#define CRYPTO_PIN_INCORRECT 0x00000021
-#define CRYPTO_PIN_INVALID 0x00000022
-#define CRYPTO_PIN_LEN_RANGE 0x00000023
-#define CRYPTO_PIN_EXPIRED 0x00000024
-#define CRYPTO_PIN_LOCKED 0x00000025
-#define CRYPTO_SESSION_CLOSED 0x00000026
-#define CRYPTO_SESSION_COUNT 0x00000027
-#define CRYPTO_SESSION_HANDLE_INVALID 0x00000028
-#define CRYPTO_SESSION_READ_ONLY 0x00000029
-#define CRYPTO_SESSION_EXISTS 0x0000002A
-#define CRYPTO_SESSION_READ_ONLY_EXISTS 0x0000002B
-#define CRYPTO_SESSION_READ_WRITE_SO_EXISTS 0x0000002C
#define CRYPTO_SIGNATURE_INVALID 0x0000002D
-#define CRYPTO_SIGNATURE_LEN_RANGE 0x0000002E
-#define CRYPTO_TEMPLATE_INCOMPLETE 0x0000002F
-#define CRYPTO_TEMPLATE_INCONSISTENT 0x00000030
-#define CRYPTO_UNWRAPPING_KEY_HANDLE_INVALID 0x00000031
-#define CRYPTO_UNWRAPPING_KEY_SIZE_RANGE 0x00000032
-#define CRYPTO_UNWRAPPING_KEY_TYPE_INCONSISTENT 0x00000033
-#define CRYPTO_USER_ALREADY_LOGGED_IN 0x00000034
-#define CRYPTO_USER_NOT_LOGGED_IN 0x00000035
-#define CRYPTO_USER_PIN_NOT_INITIALIZED 0x00000036
-#define CRYPTO_USER_TYPE_INVALID 0x00000037
-#define CRYPTO_USER_ANOTHER_ALREADY_LOGGED_IN 0x00000038
-#define CRYPTO_USER_TOO_MANY_TYPES 0x00000039
-#define CRYPTO_WRAPPED_KEY_INVALID 0x0000003A
-#define CRYPTO_WRAPPED_KEY_LEN_RANGE 0x0000003B
-#define CRYPTO_WRAPPING_KEY_HANDLE_INVALID 0x0000003C
-#define CRYPTO_WRAPPING_KEY_SIZE_RANGE 0x0000003D
-#define CRYPTO_WRAPPING_KEY_TYPE_INCONSISTENT 0x0000003E
-#define CRYPTO_RANDOM_SEED_NOT_SUPPORTED 0x0000003F
-#define CRYPTO_RANDOM_NO_RNG 0x00000040
-#define CRYPTO_DOMAIN_PARAMS_INVALID 0x00000041
#define CRYPTO_BUFFER_TOO_SMALL 0x00000042
-#define CRYPTO_INFORMATION_SENSITIVE 0x00000043
#define CRYPTO_NOT_SUPPORTED 0x00000044
-#define CRYPTO_QUEUED 0x00000045
-#define CRYPTO_BUFFER_TOO_BIG 0x00000046
#define CRYPTO_INVALID_CONTEXT 0x00000047
#define CRYPTO_INVALID_MAC 0x00000048
#define CRYPTO_MECH_NOT_SUPPORTED 0x00000049
-#define CRYPTO_INCONSISTENT_ATTRIBUTE 0x0000004A
-#define CRYPTO_NO_PERMISSION 0x0000004B
#define CRYPTO_INVALID_PROVIDER_ID 0x0000004C
-#define CRYPTO_VERSION_MISMATCH 0x0000004D
#define CRYPTO_BUSY 0x0000004E
#define CRYPTO_UNKNOWN_PROVIDER 0x0000004F
-#define CRYPTO_MODVERIFICATION_FAILED 0x00000050
-#define CRYPTO_OLD_CTX_TEMPLATE 0x00000051
-#define CRYPTO_WEAK_KEY 0x00000052
-#define CRYPTO_FIPS140_ERROR 0x00000053
-/*
- * Don't forget to update CRYPTO_LAST_ERROR and the error_number_table[]
- * in kernelUtil.c when new error code is added.
- */
-#define CRYPTO_LAST_ERROR 0x00000053
-
-/*
- * Special values that can be used to indicate that information is unavailable
- * or that there is not practical limit. These values can be used
- * by fields of the SPI crypto_provider_ext_info(9S) structure.
- * The value of CRYPTO_UNAVAILABLE_INFO should be the same as
- * CK_UNAVAILABLE_INFO in the PKCS#11 spec.
- */
-#define CRYPTO_UNAVAILABLE_INFO ((ulong_t)(-1))
-#define CRYPTO_EFFECTIVELY_INFINITE 0x0
#ifdef __cplusplus
}
diff --git a/sys/contrib/openzfs/include/sys/dsl_dataset.h b/sys/contrib/openzfs/include/sys/dsl_dataset.h
index 29bbf7e1868a..02147171ae14 100644
--- a/sys/contrib/openzfs/include/sys/dsl_dataset.h
+++ b/sys/contrib/openzfs/include/sys/dsl_dataset.h
@@ -385,8 +385,7 @@ int dsl_dataset_snap_lookup(dsl_dataset_t *ds, const char *name,
void dsl_dataset_dirty(dsl_dataset_t *ds, dmu_tx_t *tx);
int get_clones_stat_impl(dsl_dataset_t *ds, nvlist_t *val);
-char *get_receive_resume_stats_impl(dsl_dataset_t *ds);
-char *get_child_receive_stats(dsl_dataset_t *ds);
+char *get_receive_resume_token(dsl_dataset_t *ds);
uint64_t dsl_get_refratio(dsl_dataset_t *ds);
uint64_t dsl_get_logicalreferenced(dsl_dataset_t *ds);
uint64_t dsl_get_compressratio(dsl_dataset_t *ds);
diff --git a/sys/contrib/openzfs/include/sys/dsl_pool.h b/sys/contrib/openzfs/include/sys/dsl_pool.h
index 0283a8c589c1..32d973f09810 100644
--- a/sys/contrib/openzfs/include/sys/dsl_pool.h
+++ b/sys/contrib/openzfs/include/sys/dsl_pool.h
@@ -162,6 +162,7 @@ int dsl_pool_sync_context(dsl_pool_t *dp);
uint64_t dsl_pool_adjustedsize(dsl_pool_t *dp, zfs_space_check_t slop_policy);
uint64_t dsl_pool_unreserved_space(dsl_pool_t *dp,
zfs_space_check_t slop_policy);
+uint64_t dsl_pool_deferred_space(dsl_pool_t *dp);
void dsl_pool_wrlog_count(dsl_pool_t *dp, int64_t size, uint64_t txg);
boolean_t dsl_pool_wrlog_over_max(dsl_pool_t *dp);
void dsl_pool_dirty_space(dsl_pool_t *dp, int64_t space, dmu_tx_t *tx);
diff --git a/sys/contrib/openzfs/include/sys/fs/zfs.h b/sys/contrib/openzfs/include/sys/fs/zfs.h
index 6bc82198df23..ab29b4e2ef38 100644
--- a/sys/contrib/openzfs/include/sys/fs/zfs.h
+++ b/sys/contrib/openzfs/include/sys/fs/zfs.h
@@ -50,6 +50,7 @@ extern "C" {
* combined into masks that can be passed to various functions.
*/
typedef enum {
+ ZFS_TYPE_INVALID = 0,
ZFS_TYPE_FILESYSTEM = (1 << 0),
ZFS_TYPE_SNAPSHOT = (1 << 1),
ZFS_TYPE_VOLUME = (1 << 2),
@@ -838,6 +839,7 @@ typedef struct zpool_load_policy {
/* Rewind data discovered */
#define ZPOOL_CONFIG_LOAD_TIME "rewind_txg_ts"
+#define ZPOOL_CONFIG_LOAD_META_ERRORS "verify_meta_errors"
#define ZPOOL_CONFIG_LOAD_DATA_ERRORS "verify_data_errors"
#define ZPOOL_CONFIG_REWIND_TIME "seconds_of_rewind"
@@ -1185,11 +1187,9 @@ typedef struct vdev_stat {
uint64_t vs_noalloc; /* allocations halted? */
} vdev_stat_t;
-/* BEGIN CSTYLED */
#define VDEV_STAT_VALID(field, uint64_t_field_count) \
- ((uint64_t_field_count * sizeof (uint64_t)) >= \
- (offsetof(vdev_stat_t, field) + sizeof (((vdev_stat_t *)NULL)->field)))
-/* END CSTYLED */
+((uint64_t_field_count * sizeof (uint64_t)) >= \
+ (offsetof(vdev_stat_t, field) + sizeof (((vdev_stat_t *)NULL)->field)))
/*
* Extended stats
@@ -1459,6 +1459,41 @@ typedef enum zfs_ioc {
*/
#define BLKZNAME _IOR(0x12, 125, char[ZFS_MAX_DATASET_NAME_LEN])
+#ifdef __linux__
+
+/*
+ * IOCTLs to update and retrieve additional file level attributes on
+ * Linux.
+ */
+#define ZFS_IOC_GETDOSFLAGS _IOR(0x83, 1, uint64_t)
+#define ZFS_IOC_SETDOSFLAGS _IOW(0x83, 2, uint64_t)
+
+/*
+ * Additional file level attributes, that are stored
+ * in the upper half of z_pflags
+ */
+#define ZFS_READONLY 0x0000000100000000ull
+#define ZFS_HIDDEN 0x0000000200000000ull
+#define ZFS_SYSTEM 0x0000000400000000ull
+#define ZFS_ARCHIVE 0x0000000800000000ull
+#define ZFS_IMMUTABLE 0x0000001000000000ull
+#define ZFS_NOUNLINK 0x0000002000000000ull
+#define ZFS_APPENDONLY 0x0000004000000000ull
+#define ZFS_NODUMP 0x0000008000000000ull
+#define ZFS_OPAQUE 0x0000010000000000ull
+#define ZFS_AV_QUARANTINED 0x0000020000000000ull
+#define ZFS_AV_MODIFIED 0x0000040000000000ull
+#define ZFS_REPARSE 0x0000080000000000ull
+#define ZFS_OFFLINE 0x0000100000000000ull
+#define ZFS_SPARSE 0x0000200000000000ull
+
+#define ZFS_DOS_FL_USER_VISIBLE (ZFS_IMMUTABLE | ZFS_APPENDONLY | \
+ ZFS_NOUNLINK | ZFS_ARCHIVE | ZFS_NODUMP | ZFS_SYSTEM | \
+ ZFS_HIDDEN | ZFS_READONLY | ZFS_REPARSE | ZFS_OFFLINE | \
+ ZFS_SPARSE)
+
+#endif
+
/*
* ZFS-specific error codes used for returning descriptive errors
* to the userland through zfs ioctls.
@@ -1710,7 +1745,6 @@ typedef enum {
#define ZFS_EV_HIST_DSID "history_dsid"
#define ZFS_EV_RESILVER_TYPE "resilver_type"
-
/*
* We currently support block sizes from 512 bytes to 16MB.
* The benefits of larger blocks, and thus larger IO, need to be weighed
@@ -1732,7 +1766,6 @@ typedef enum {
#define SPA_OLD_MAXBLOCKSIZE (1ULL << SPA_OLD_MAXBLOCKSHIFT)
#define SPA_MAXBLOCKSIZE (1ULL << SPA_MAXBLOCKSHIFT)
-
/* supported encryption algorithms */
enum zio_encrypt {
ZIO_CRYPT_INHERIT = 0,
@@ -1750,6 +1783,34 @@ enum zio_encrypt {
#define ZIO_CRYPT_ON_VALUE ZIO_CRYPT_AES_256_GCM
#define ZIO_CRYPT_DEFAULT ZIO_CRYPT_OFF
+/*
+ * xattr namespace prefixes. These are forbidden in xattr names.
+ *
+ * For cross-platform compatibility, xattrs in the user namespace should not be
+ * prefixed with the namespace name, but for backwards compatibility with older
+ * ZFS on Linux versions we do prefix the namespace.
+ */
+#define ZFS_XA_NS_FREEBSD_PREFIX "freebsd:"
+#define ZFS_XA_NS_FREEBSD_PREFIX_LEN strlen("freebsd:")
+#define ZFS_XA_NS_LINUX_SECURITY_PREFIX "security."
+#define ZFS_XA_NS_LINUX_SECURITY_PREFIX_LEN strlen("security.")
+#define ZFS_XA_NS_LINUX_SYSTEM_PREFIX "system."
+#define ZFS_XA_NS_LINUX_SYSTEM_PREFIX_LEN strlen("system.")
+#define ZFS_XA_NS_LINUX_TRUSTED_PREFIX "trusted."
+#define ZFS_XA_NS_LINUX_TRUSTED_PREFIX_LEN strlen("trusted.")
+#define ZFS_XA_NS_LINUX_USER_PREFIX "user."
+#define ZFS_XA_NS_LINUX_USER_PREFIX_LEN strlen("user.")
+
+#define ZFS_XA_NS_PREFIX_MATCH(ns, name) \
+ (strncmp(name, ZFS_XA_NS_##ns##_PREFIX, \
+ ZFS_XA_NS_##ns##_PREFIX_LEN) == 0)
+
+#define ZFS_XA_NS_PREFIX_FORBIDDEN(name) \
+ (ZFS_XA_NS_PREFIX_MATCH(FREEBSD, name) || \
+ ZFS_XA_NS_PREFIX_MATCH(LINUX_SECURITY, name) || \
+ ZFS_XA_NS_PREFIX_MATCH(LINUX_SYSTEM, name) || \
+ ZFS_XA_NS_PREFIX_MATCH(LINUX_TRUSTED, name) || \
+ ZFS_XA_NS_PREFIX_MATCH(LINUX_USER, name))
#ifdef __cplusplus
}
diff --git a/sys/contrib/openzfs/include/sys/lua/lauxlib.h b/sys/contrib/openzfs/include/sys/lua/lauxlib.h
index 503a99e9426d..1d17837568ac 100644
--- a/sys/contrib/openzfs/include/sys/lua/lauxlib.h
+++ b/sys/contrib/openzfs/include/sys/lua/lauxlib.h
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lauxlib.h,v 1.120.1.1 2013/04/12 18:48:47 roberto Exp $
** Auxiliary functions for building Lua libraries
@@ -171,5 +170,3 @@ LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname,
#endif
-
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/include/sys/lua/lua.h b/sys/contrib/openzfs/include/sys/lua/lua.h
index 0b4eb045cf8f..9220218af035 100644
--- a/sys/contrib/openzfs/include/sys/lua/lua.h
+++ b/sys/contrib/openzfs/include/sys/lua/lua.h
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lua.h,v 1.285.1.4 2015/02/21 14:04:50 roberto Exp $
** Lua - A Scripting Language
@@ -442,4 +441,3 @@ struct lua_Debug {
#endif
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/include/sys/lua/luaconf.h b/sys/contrib/openzfs/include/sys/lua/luaconf.h
index 83202d71c27b..6dfcd03ba9cb 100644
--- a/sys/contrib/openzfs/include/sys/lua/luaconf.h
+++ b/sys/contrib/openzfs/include/sys/lua/luaconf.h
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: luaconf.h,v 1.176.1.2 2013/11/21 17:26:16 roberto Exp $
** Configuration file for Lua
@@ -555,4 +554,3 @@ extern int lcompat_hashnum(int64_t);
#endif
#endif
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/include/sys/lua/lualib.h b/sys/contrib/openzfs/include/sys/lua/lualib.h
index 7b848787c8f0..f23feaa5c44a 100644
--- a/sys/contrib/openzfs/include/sys/lua/lualib.h
+++ b/sys/contrib/openzfs/include/sys/lua/lualib.h
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lualib.h,v 1.43.1.1 2013/04/12 18:48:47 roberto Exp $
** Lua standard libraries
@@ -54,4 +53,3 @@ LUALIB_API void (luaL_openlibs) (lua_State *L);
#endif
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/include/sys/spa.h b/sys/contrib/openzfs/include/sys/spa.h
index 896b0f9563ae..2ce84c21cbdb 100644
--- a/sys/contrib/openzfs/include/sys/spa.h
+++ b/sys/contrib/openzfs/include/sys/spa.h
@@ -1183,6 +1183,11 @@ extern int spa_wait_tag(const char *name, zpool_wait_activity_t activity,
extern void spa_notify_waiters(spa_t *spa);
extern void spa_wake_waiters(spa_t *spa);
+extern void spa_import_os(spa_t *spa);
+extern void spa_export_os(spa_t *spa);
+extern void spa_activate_os(spa_t *spa);
+extern void spa_deactivate_os(spa_t *spa);
+
/* module param call functions */
int param_set_deadman_ziotime(ZFS_MODULE_PARAM_ARGS);
int param_set_deadman_synctime(ZFS_MODULE_PARAM_ARGS);
diff --git a/sys/contrib/openzfs/include/sys/vdev_impl.h b/sys/contrib/openzfs/include/sys/vdev_impl.h
index 1567182a7b7e..db8fbdeb06df 100644
--- a/sys/contrib/openzfs/include/sys/vdev_impl.h
+++ b/sys/contrib/openzfs/include/sys/vdev_impl.h
@@ -521,8 +521,8 @@ typedef struct vdev_boot_envblock {
sizeof (zio_eck_t)];
zio_eck_t vbe_zbt;
} vdev_boot_envblock_t;
-
-CTASSERT_GLOBAL(sizeof (vdev_boot_envblock_t) == VDEV_PAD_SIZE);
+_Static_assert(sizeof (vdev_boot_envblock_t) == VDEV_PAD_SIZE,
+ "vdev_boot_envblock_t wrong size");
typedef struct vdev_label {
char vl_pad1[VDEV_PAD_SIZE]; /* 8K */
diff --git a/sys/contrib/openzfs/include/sys/zfs_context.h b/sys/contrib/openzfs/include/sys/zfs_context.h
index 6d1fd83df522..a1114d746e31 100644
--- a/sys/contrib/openzfs/include/sys/zfs_context.h
+++ b/sys/contrib/openzfs/include/sys/zfs_context.h
@@ -153,8 +153,13 @@ extern void dprintf_setup(int *argc, char **argv);
extern void cmn_err(int, const char *, ...);
extern void vcmn_err(int, const char *, va_list);
-extern void panic(const char *, ...) __NORETURN;
-extern void vpanic(const char *, va_list) __NORETURN;
+#if defined(__cplusplus) && __cplusplus >= 201103L
+extern void panic(const char *, ...) __attribute__((__noreturn__));
+extern void vpanic(const char *, va_list) __attribute__((__noreturn__));
+#else
+extern _Noreturn void panic(const char *, ...);
+extern _Noreturn void vpanic(const char *, va_list);
+#endif
#define fm_panic panic
diff --git a/sys/contrib/openzfs/include/sys/zfs_sa.h b/sys/contrib/openzfs/include/sys/zfs_sa.h
index a0c383807aa4..6b0336997c20 100644
--- a/sys/contrib/openzfs/include/sys/zfs_sa.h
+++ b/sys/contrib/openzfs/include/sys/zfs_sa.h
@@ -138,7 +138,7 @@ void zfs_sa_symlink(struct znode *, char *link, int len, dmu_tx_t *);
void zfs_sa_get_scanstamp(struct znode *, xvattr_t *);
void zfs_sa_set_scanstamp(struct znode *, xvattr_t *, dmu_tx_t *);
int zfs_sa_get_xattr(struct znode *);
-int zfs_sa_set_xattr(struct znode *);
+int zfs_sa_set_xattr(struct znode *, const char *, const void *, size_t);
void zfs_sa_upgrade(struct sa_handle *, dmu_tx_t *);
void zfs_sa_upgrade_txholds(dmu_tx_t *, struct znode *);
void zfs_sa_init(void);
diff --git a/sys/contrib/openzfs/include/sys/zfs_znode.h b/sys/contrib/openzfs/include/sys/zfs_znode.h
index 1bf25a77d3a0..127fd8736ffc 100644
--- a/sys/contrib/openzfs/include/sys/zfs_znode.h
+++ b/sys/contrib/openzfs/include/sys/zfs_znode.h
@@ -37,7 +37,7 @@ extern "C" {
/*
* Additional file level attributes, that are stored
- * in the upper half of zp_flags
+ * in the upper half of z_pflags
*/
#define ZFS_READONLY 0x0000000100000000ull
#define ZFS_HIDDEN 0x0000000200000000ull
@@ -286,6 +286,8 @@ extern void zfs_log_acl(zilog_t *zilog, dmu_tx_t *tx, znode_t *zp,
vsecattr_t *vsecp, zfs_fuid_info_t *fuidp);
extern void zfs_xvattr_set(znode_t *zp, xvattr_t *xvap, dmu_tx_t *tx);
extern void zfs_upgrade(zfsvfs_t *zfsvfs, dmu_tx_t *tx);
+extern void zfs_log_setsaxattr(zilog_t *zilog, dmu_tx_t *tx, int txtype,
+ znode_t *zp, const char *name, const void *value, size_t size);
extern void zfs_znode_update_vfs(struct znode *);
diff --git a/sys/contrib/openzfs/include/sys/zil.h b/sys/contrib/openzfs/include/sys/zil.h
index 8e5a49da2929..05e3647e698a 100644
--- a/sys/contrib/openzfs/include/sys/zil.h
+++ b/sys/contrib/openzfs/include/sys/zil.h
@@ -162,7 +162,8 @@ typedef enum zil_create {
#define TX_MKDIR_ATTR 18 /* mkdir with attr */
#define TX_MKDIR_ACL_ATTR 19 /* mkdir with ACL + attrs */
#define TX_WRITE2 20 /* dmu_sync EALREADY write */
-#define TX_MAX_TYPE 21 /* Max transaction type */
+#define TX_SETSAXATTR 21 /* Set sa xattrs on file */
+#define TX_MAX_TYPE 22 /* Max transaction type */
/*
* The transactions for mkdir, symlink, remove, rmdir, link, and rename
@@ -182,7 +183,8 @@ typedef enum zil_create {
(txtype) == TX_SETATTR || \
(txtype) == TX_ACL_V0 || \
(txtype) == TX_ACL || \
- (txtype) == TX_WRITE2)
+ (txtype) == TX_WRITE2 || \
+ (txtype) == TX_SETSAXATTR)
/*
* The number of dnode slots consumed by the object is stored in the 8
@@ -337,6 +339,13 @@ typedef struct {
typedef struct {
lr_t lr_common; /* common portion of log record */
+ uint64_t lr_foid; /* file object to change attributes */
+ uint64_t lr_size;
+ /* xattr name and value follows */
+} lr_setsaxattr_t;
+
+typedef struct {
+ lr_t lr_common; /* common portion of log record */
uint64_t lr_foid; /* obj id of file */
uint64_t lr_aclcnt; /* number of acl entries */
/* lr_aclcnt number of ace_t entries follow this */
diff --git a/sys/contrib/openzfs/include/sys/zio.h b/sys/contrib/openzfs/include/sys/zio.h
index 07135d1e2a07..2cf10f30974b 100644
--- a/sys/contrib/openzfs/include/sys/zio.h
+++ b/sys/contrib/openzfs/include/sys/zio.h
@@ -125,7 +125,7 @@ enum zio_checksum {
#define ZIO_COMPRESS_LEGACY_ON_VALUE ZIO_COMPRESS_LZJB
#define ZIO_COMPRESS_LZ4_ON_VALUE ZIO_COMPRESS_LZ4
-#define ZIO_COMPRESS_DEFAULT ZIO_COMPRESS_OFF
+#define ZIO_COMPRESS_DEFAULT ZIO_COMPRESS_ON
#define BOOTFS_COMPRESS_VALID(compress) \
((compress) == ZIO_COMPRESS_LZJB || \
diff --git a/sys/contrib/openzfs/include/sys/zvol_impl.h b/sys/contrib/openzfs/include/sys/zvol_impl.h
index 223393de79fd..94203347066b 100644
--- a/sys/contrib/openzfs/include/sys/zvol_impl.h
+++ b/sys/contrib/openzfs/include/sys/zvol_impl.h
@@ -93,17 +93,13 @@ void zvol_wait_close(zvol_state_t *zv);
/*
* platform dependent functions exported to platform independent code
*/
-typedef struct zvol_platform_ops {
- void (*zv_free)(zvol_state_t *);
- void (*zv_rename_minor)(zvol_state_t *, const char *);
- int (*zv_create_minor)(const char *);
- int (*zv_update_volsize)(zvol_state_t *, uint64_t);
- boolean_t (*zv_is_zvol)(const char *);
- void (*zv_clear_private)(zvol_state_t *);
- void (*zv_set_disk_ro)(zvol_state_t *, int flags);
- void (*zv_set_capacity)(zvol_state_t *, uint64_t capacity);
-} zvol_platform_ops_t;
-
-void zvol_register_ops(const zvol_platform_ops_t *ops);
+void zvol_os_free(zvol_state_t *zv);
+void zvol_os_rename_minor(zvol_state_t *zv, const char *newname);
+int zvol_os_create_minor(const char *name);
+int zvol_os_update_volsize(zvol_state_t *zv, uint64_t volsize);
+boolean_t zvol_os_is_zvol(const char *path);
+void zvol_os_clear_private(zvol_state_t *zv);
+void zvol_os_set_disk_ro(zvol_state_t *zv, int flags);
+void zvol_os_set_capacity(zvol_state_t *zv, uint64_t capacity);
#endif
diff --git a/sys/contrib/openzfs/include/zfeature_common.h b/sys/contrib/openzfs/include/zfeature_common.h
index 874cbd9ff714..580f5ff3e0ee 100644
--- a/sys/contrib/openzfs/include/zfeature_common.h
+++ b/sys/contrib/openzfs/include/zfeature_common.h
@@ -75,6 +75,7 @@ typedef enum spa_feature {
SPA_FEATURE_DEVICE_REBUILD,
SPA_FEATURE_ZSTD_COMPRESS,
SPA_FEATURE_DRAID,
+ SPA_FEATURE_ZILSAXATTR,
SPA_FEATURES
} spa_feature_t;
diff --git a/sys/contrib/openzfs/include/zfs_fletcher.h b/sys/contrib/openzfs/include/zfs_fletcher.h
index bb356c59acb1..28cb8ba234e5 100644
--- a/sys/contrib/openzfs/include/zfs_fletcher.h
+++ b/sys/contrib/openzfs/include/zfs_fletcher.h
@@ -160,4 +160,20 @@ _ZFS_FLETCHER_H const fletcher_4_ops_t fletcher_4_aarch64_neon_ops;
}
#endif
+#if defined(ZFS_UBSAN_ENABLED)
+#if defined(__has_attribute)
+#if __has_attribute(no_sanitize_undefined)
+#define ZFS_NO_SANITIZE_UNDEFINED __attribute__((no_sanitize_undefined))
+#elif __has_attribute(no_sanitize)
+#define ZFS_NO_SANITIZE_UNDEFINED __attribute__((no_sanitize("undefined")))
+#else
+#error "Compiler has to support attribute "
+ "`no_sanitize_undefined` or `no_sanitize(\"undefined\")`"
+ "when compiling with UBSan enabled"
+#endif /* __has_attribute(no_sanitize_undefined) */
+#endif /* defined(__has_attribute) */
+#else
+#define ZFS_NO_SANITIZE_UNDEFINED
+#endif /* defined(ZFS_UBSAN_ENABLED) */
+
#endif /* _ZFS_FLETCHER_H */
diff --git a/sys/contrib/openzfs/include/zfs_prop.h b/sys/contrib/openzfs/include/zfs_prop.h
index c7363f701530..dca537c3761a 100644
--- a/sys/contrib/openzfs/include/zfs_prop.h
+++ b/sys/contrib/openzfs/include/zfs_prop.h
@@ -76,10 +76,11 @@ typedef struct {
/* fs | vol | snap; or pool */
const char *pd_values; /* string telling acceptable values */
const char *pd_colname; /* column header for "zfs list" */
- boolean_t pd_rightalign; /* column alignment for "zfs list" */
- boolean_t pd_visible; /* do we list this property with the */
+ boolean_t pd_rightalign: 1; /* column alignment for "zfs list" */
+ boolean_t pd_visible: 1; /* do we list this property with the */
/* "zfs get" help message */
- boolean_t pd_zfs_mod_supported; /* supported by running zfs module */
+ boolean_t pd_zfs_mod_supported: 1; /* supported by running zfs module */
+ boolean_t pd_always_flex: 1; /* never fixed-width */
const zprop_index_t *pd_table; /* for index properties, a table */
/* defining the possible values */
size_t pd_table_size; /* number of entries in pd_table[] */
@@ -112,19 +113,20 @@ _ZFS_PROP_H zprop_desc_t *vdev_prop_get_table(void);
*/
_ZFS_PROP_H void zprop_register_impl(int, const char *, zprop_type_t, uint64_t,
const char *, zprop_attr_t, int, const char *, const char *,
- boolean_t, boolean_t, const zprop_index_t *,
+ boolean_t, boolean_t, boolean_t, const zprop_index_t *,
const struct zfs_mod_supported_features *);
_ZFS_PROP_H void zprop_register_string(int, const char *, const char *,
zprop_attr_t attr, int, const char *, const char *,
const struct zfs_mod_supported_features *);
_ZFS_PROP_H void zprop_register_number(int, const char *, uint64_t,
- zprop_attr_t, int, const char *, const char *,
+ zprop_attr_t, int, const char *, const char *, boolean_t,
const struct zfs_mod_supported_features *);
_ZFS_PROP_H void zprop_register_index(int, const char *, uint64_t, zprop_attr_t,
int, const char *, const char *, const zprop_index_t *,
const struct zfs_mod_supported_features *);
_ZFS_PROP_H void zprop_register_hidden(int, const char *, zprop_type_t,
- zprop_attr_t, int, const char *, const struct zfs_mod_supported_features *);
+ zprop_attr_t, int, const char *, boolean_t,
+ const struct zfs_mod_supported_features *);
/*
* Common routines for zfs and zpool property management
diff --git a/sys/contrib/openzfs/lib/libicp/Makefile.am b/sys/contrib/openzfs/lib/libicp/Makefile.am
index 831d2fedff4d..382253f6fa48 100644
--- a/sys/contrib/openzfs/lib/libicp/Makefile.am
+++ b/sys/contrib/openzfs/lib/libicp/Makefile.am
@@ -27,9 +27,7 @@ endif
KERNEL_C = \
spi/kcf_spi.c \
api/kcf_ctxops.c \
- api/kcf_digest.c \
api/kcf_cipher.c \
- api/kcf_miscapi.c \
api/kcf_mac.c \
algs/aes/aes_impl_aesni.c \
algs/aes/aes_impl_generic.c \
@@ -53,7 +51,6 @@ KERNEL_C = \
io/aes.c \
io/sha2_mod.c \
io/skein_mod.c \
- os/modhash.c \
core/kcf_sched.c \
core/kcf_prov_lib.c \
core/kcf_callprov.c \
diff --git a/sys/contrib/openzfs/lib/libnvpair/Makefile.am b/sys/contrib/openzfs/lib/libnvpair/Makefile.am
index 7b9ebebe7906..9a71a2ea6198 100644
--- a/sys/contrib/openzfs/lib/libnvpair/Makefile.am
+++ b/sys/contrib/openzfs/lib/libnvpair/Makefile.am
@@ -9,6 +9,10 @@ VPATH = \
AM_CFLAGS += $(FRAME_LARGER_THAN) $(LIBTIRPC_CFLAGS)
AM_CFLAGS += -fvisibility=hidden
+# wchar_t is undefined-signedness, but we compare to >=0; this warns with unsigned wchar_t
+libnvpair_json.$(OBJEXT): CFLAGS += -Wno-type-limits
+libnvpair_json.l$(OBJEXT): CFLAGS += -Wno-type-limits
+
lib_LTLIBRARIES = libnvpair.la
include $(top_srcdir)/config/Abigail.am
diff --git a/sys/contrib/openzfs/lib/libnvpair/libnvpair.abi b/sys/contrib/openzfs/lib/libnvpair/libnvpair.abi
index 01be5785a4ae..f9874da81f82 100644
--- a/sys/contrib/openzfs/lib/libnvpair/libnvpair.abi
+++ b/sys/contrib/openzfs/lib/libnvpair/libnvpair.abi
@@ -78,6 +78,7 @@
<elf-symbol name='fnvpair_value_uint64' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='fnvpair_value_uint8' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='libspl_assertf' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ <elf-symbol name='libspl_set_assert_ok' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='nv_alloc_fini' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='nv_alloc_init' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='nv_alloc_reset' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@@ -230,7 +231,6 @@
<elf-symbol name='nvpair_value_uint8_array' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
</elf-function-symbols>
<elf-variable-symbols>
- <elf-symbol name='libspl_assert_ok' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='nv_alloc_nosleep' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='nv_fixed_ops' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
</elf-variable-symbols>
@@ -2793,7 +2793,10 @@
</function-type>
</abi-instr>
<abi-instr address-size='64' path='assert.c' language='LANG_C99'>
- <var-decl name='libspl_assert_ok' type-id='95e97e5e' mangled-name='libspl_assert_ok' visibility='default' elf-symbol-id='libspl_assert_ok'/>
+ <function-decl name='libspl_set_assert_ok' mangled-name='libspl_set_assert_ok' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='libspl_set_assert_ok'>
+ <parameter type-id='f58c8277' name='val'/>
+ <return type-id='48b5725f'/>
+ </function-decl>
<function-decl name='libspl_assertf' mangled-name='libspl_assertf' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='libspl_assertf'>
<parameter type-id='80f4b756' name='file'/>
<parameter type-id='80f4b756' name='func'/>
diff --git a/sys/contrib/openzfs/lib/libshare/os/freebsd/nfs.c b/sys/contrib/openzfs/lib/libshare/os/freebsd/nfs.c
index 494442cb520f..ea02dc1bae3c 100644
--- a/sys/contrib/openzfs/lib/libshare/os/freebsd/nfs.c
+++ b/sys/contrib/openzfs/lib/libshare/os/freebsd/nfs.c
@@ -155,6 +155,7 @@ nfs_is_shared(sa_share_impl_t impl_share)
static int
nfs_validate_shareopts(const char *shareopts)
{
+ (void) shareopts;
return (SA_OK);
}
diff --git a/sys/contrib/openzfs/lib/libshare/os/freebsd/smb.c b/sys/contrib/openzfs/lib/libshare/os/freebsd/smb.c
index 5b606ab96955..a25990d3bfb2 100644
--- a/sys/contrib/openzfs/lib/libshare/os/freebsd/smb.c
+++ b/sys/contrib/openzfs/lib/libshare/os/freebsd/smb.c
@@ -47,6 +47,7 @@ static sa_fstype_t *smb_fstype;
static int
smb_enable_share(sa_share_impl_t impl_share)
{
+ (void) impl_share;
fprintf(stderr, "No SMB support in FreeBSD yet.\n");
return (SA_NOT_SUPPORTED);
}
@@ -56,6 +57,7 @@ smb_enable_share(sa_share_impl_t impl_share)
static int
smb_disable_share(sa_share_impl_t impl_share)
{
+ (void) impl_share;
fprintf(stderr, "No SMB support in FreeBSD yet.\n");
return (SA_NOT_SUPPORTED);
}
@@ -66,6 +68,7 @@ smb_disable_share(sa_share_impl_t impl_share)
static int
smb_validate_shareopts(const char *shareopts)
{
+ (void) shareopts;
fprintf(stderr, "No SMB support in FreeBSD yet.\n");
return (SA_NOT_SUPPORTED);
}
@@ -76,6 +79,7 @@ smb_validate_shareopts(const char *shareopts)
static boolean_t
smb_is_share_active(sa_share_impl_t impl_share)
{
+ (void) impl_share;
return (B_FALSE);
}
@@ -88,6 +92,7 @@ smb_is_share_active(sa_share_impl_t impl_share)
static int
smb_update_shareopts(sa_share_impl_t impl_share, const char *shareopts)
{
+ (void) impl_share, (void) shareopts;
return (SA_OK);
}
diff --git a/sys/contrib/openzfs/lib/libspl/assert.c b/sys/contrib/openzfs/lib/libspl/assert.c
index 8e4333976f95..ad8fdcd8cf0a 100644
--- a/sys/contrib/openzfs/lib/libspl/assert.c
+++ b/sys/contrib/openzfs/lib/libspl/assert.c
@@ -25,7 +25,13 @@
#include <assert.h>
-int libspl_assert_ok = 0;
+static boolean_t libspl_assert_ok = B_FALSE;
+
+void
+libspl_set_assert_ok(boolean_t val)
+{
+ libspl_assert_ok = val;
+}
/* printf version of libspl_assert */
void
diff --git a/sys/contrib/openzfs/lib/libspl/atomic.c b/sys/contrib/openzfs/lib/libspl/atomic.c
index 4717d818ce5c..9307cea194e6 100644
--- a/sys/contrib/openzfs/lib/libspl/atomic.c
+++ b/sys/contrib/openzfs/lib/libspl/atomic.c
@@ -29,21 +29,22 @@
/*
* These are the void returning variants
*/
-/* BEGIN CSTYLED */
#define ATOMIC_INC(name, type) \
void atomic_inc_##name(volatile type *target) \
{ \
(void) __atomic_add_fetch(target, 1, __ATOMIC_SEQ_CST); \
}
+/* BEGIN CSTYLED */
ATOMIC_INC(8, uint8_t)
-ATOMIC_INC(uchar, uchar_t)
ATOMIC_INC(16, uint16_t)
-ATOMIC_INC(ushort, ushort_t)
ATOMIC_INC(32, uint32_t)
+ATOMIC_INC(64, uint64_t)
+ATOMIC_INC(uchar, uchar_t)
+ATOMIC_INC(ushort, ushort_t)
ATOMIC_INC(uint, uint_t)
ATOMIC_INC(ulong, ulong_t)
-ATOMIC_INC(64, uint64_t)
+/* END CSTYLED */
#define ATOMIC_DEC(name, type) \
@@ -52,14 +53,16 @@ ATOMIC_INC(64, uint64_t)
(void) __atomic_sub_fetch(target, 1, __ATOMIC_SEQ_CST); \
}
+/* BEGIN CSTYLED */
ATOMIC_DEC(8, uint8_t)
-ATOMIC_DEC(uchar, uchar_t)
ATOMIC_DEC(16, uint16_t)
-ATOMIC_DEC(ushort, ushort_t)
ATOMIC_DEC(32, uint32_t)
+ATOMIC_DEC(64, uint64_t)
+ATOMIC_DEC(uchar, uchar_t)
+ATOMIC_DEC(ushort, ushort_t)
ATOMIC_DEC(uint, uint_t)
ATOMIC_DEC(ulong, ulong_t)
-ATOMIC_DEC(64, uint64_t)
+/* END CSTYLED */
#define ATOMIC_ADD(name, type1, type2) \
@@ -68,21 +71,23 @@ ATOMIC_DEC(64, uint64_t)
(void) __atomic_add_fetch(target, bits, __ATOMIC_SEQ_CST); \
}
-ATOMIC_ADD(8, uint8_t, int8_t)
-ATOMIC_ADD(char, uchar_t, signed char)
-ATOMIC_ADD(16, uint16_t, int16_t)
-ATOMIC_ADD(short, ushort_t, short)
-ATOMIC_ADD(32, uint32_t, int32_t)
-ATOMIC_ADD(int, uint_t, int)
-ATOMIC_ADD(long, ulong_t, long)
-ATOMIC_ADD(64, uint64_t, int64_t)
-
void
atomic_add_ptr(volatile void *target, ssize_t bits)
{
(void) __atomic_add_fetch((void **)target, bits, __ATOMIC_SEQ_CST);
}
+/* BEGIN CSTYLED */
+ATOMIC_ADD(8, uint8_t, int8_t)
+ATOMIC_ADD(16, uint16_t, int16_t)
+ATOMIC_ADD(32, uint32_t, int32_t)
+ATOMIC_ADD(64, uint64_t, int64_t)
+ATOMIC_ADD(char, uchar_t, signed char)
+ATOMIC_ADD(short, ushort_t, short)
+ATOMIC_ADD(int, uint_t, int)
+ATOMIC_ADD(long, ulong_t, long)
+/* END CSTYLED */
+
#define ATOMIC_SUB(name, type1, type2) \
void atomic_sub_##name(volatile type1 *target, type2 bits) \
@@ -90,21 +95,23 @@ atomic_add_ptr(volatile void *target, ssize_t bits)
(void) __atomic_sub_fetch(target, bits, __ATOMIC_SEQ_CST); \
}
-ATOMIC_SUB(8, uint8_t, int8_t)
-ATOMIC_SUB(char, uchar_t, signed char)
-ATOMIC_SUB(16, uint16_t, int16_t)
-ATOMIC_SUB(short, ushort_t, short)
-ATOMIC_SUB(32, uint32_t, int32_t)
-ATOMIC_SUB(int, uint_t, int)
-ATOMIC_SUB(long, ulong_t, long)
-ATOMIC_SUB(64, uint64_t, int64_t)
-
void
atomic_sub_ptr(volatile void *target, ssize_t bits)
{
(void) __atomic_sub_fetch((void **)target, bits, __ATOMIC_SEQ_CST);
}
+/* BEGIN CSTYLED */
+ATOMIC_SUB(8, uint8_t, int8_t)
+ATOMIC_SUB(16, uint16_t, int16_t)
+ATOMIC_SUB(32, uint32_t, int32_t)
+ATOMIC_SUB(64, uint64_t, int64_t)
+ATOMIC_SUB(char, uchar_t, signed char)
+ATOMIC_SUB(short, ushort_t, short)
+ATOMIC_SUB(int, uint_t, int)
+ATOMIC_SUB(long, ulong_t, long)
+/* END CSTYLED */
+
#define ATOMIC_OR(name, type) \
void atomic_or_##name(volatile type *target, type bits) \
@@ -112,14 +119,16 @@ atomic_sub_ptr(volatile void *target, ssize_t bits)
(void) __atomic_or_fetch(target, bits, __ATOMIC_SEQ_CST); \
}
+/* BEGIN CSTYLED */
ATOMIC_OR(8, uint8_t)
-ATOMIC_OR(uchar, uchar_t)
ATOMIC_OR(16, uint16_t)
-ATOMIC_OR(ushort, ushort_t)
ATOMIC_OR(32, uint32_t)
+ATOMIC_OR(64, uint64_t)
+ATOMIC_OR(uchar, uchar_t)
+ATOMIC_OR(ushort, ushort_t)
ATOMIC_OR(uint, uint_t)
ATOMIC_OR(ulong, ulong_t)
-ATOMIC_OR(64, uint64_t)
+/* END CSTYLED */
#define ATOMIC_AND(name, type) \
@@ -128,14 +137,16 @@ ATOMIC_OR(64, uint64_t)
(void) __atomic_and_fetch(target, bits, __ATOMIC_SEQ_CST); \
}
+/* BEGIN CSTYLED */
ATOMIC_AND(8, uint8_t)
-ATOMIC_AND(uchar, uchar_t)
ATOMIC_AND(16, uint16_t)
-ATOMIC_AND(ushort, ushort_t)
ATOMIC_AND(32, uint32_t)
+ATOMIC_AND(64, uint64_t)
+ATOMIC_AND(uchar, uchar_t)
+ATOMIC_AND(ushort, ushort_t)
ATOMIC_AND(uint, uint_t)
ATOMIC_AND(ulong, ulong_t)
-ATOMIC_AND(64, uint64_t)
+/* END CSTYLED */
/*
@@ -148,14 +159,16 @@ ATOMIC_AND(64, uint64_t)
return (__atomic_add_fetch(target, 1, __ATOMIC_SEQ_CST)); \
}
+/* BEGIN CSTYLED */
ATOMIC_INC_NV(8, uint8_t)
-ATOMIC_INC_NV(uchar, uchar_t)
ATOMIC_INC_NV(16, uint16_t)
-ATOMIC_INC_NV(ushort, ushort_t)
ATOMIC_INC_NV(32, uint32_t)
+ATOMIC_INC_NV(64, uint64_t)
+ATOMIC_INC_NV(uchar, uchar_t)
+ATOMIC_INC_NV(ushort, ushort_t)
ATOMIC_INC_NV(uint, uint_t)
ATOMIC_INC_NV(ulong, ulong_t)
-ATOMIC_INC_NV(64, uint64_t)
+/* END CSTYLED */
#define ATOMIC_DEC_NV(name, type) \
@@ -164,14 +177,16 @@ ATOMIC_INC_NV(64, uint64_t)
return (__atomic_sub_fetch(target, 1, __ATOMIC_SEQ_CST)); \
}
+/* BEGIN CSTYLED */
ATOMIC_DEC_NV(8, uint8_t)
-ATOMIC_DEC_NV(uchar, uchar_t)
ATOMIC_DEC_NV(16, uint16_t)
-ATOMIC_DEC_NV(ushort, ushort_t)
ATOMIC_DEC_NV(32, uint32_t)
+ATOMIC_DEC_NV(64, uint64_t)
+ATOMIC_DEC_NV(uchar, uchar_t)
+ATOMIC_DEC_NV(ushort, ushort_t)
ATOMIC_DEC_NV(uint, uint_t)
ATOMIC_DEC_NV(ulong, ulong_t)
-ATOMIC_DEC_NV(64, uint64_t)
+/* END CSTYLED */
#define ATOMIC_ADD_NV(name, type1, type2) \
@@ -180,21 +195,23 @@ ATOMIC_DEC_NV(64, uint64_t)
return (__atomic_add_fetch(target, bits, __ATOMIC_SEQ_CST)); \
}
-ATOMIC_ADD_NV(8, uint8_t, int8_t)
-ATOMIC_ADD_NV(char, uchar_t, signed char)
-ATOMIC_ADD_NV(16, uint16_t, int16_t)
-ATOMIC_ADD_NV(short, ushort_t, short)
-ATOMIC_ADD_NV(32, uint32_t, int32_t)
-ATOMIC_ADD_NV(int, uint_t, int)
-ATOMIC_ADD_NV(long, ulong_t, long)
-ATOMIC_ADD_NV(64, uint64_t, int64_t)
-
void *
atomic_add_ptr_nv(volatile void *target, ssize_t bits)
{
return (__atomic_add_fetch((void **)target, bits, __ATOMIC_SEQ_CST));
}
+/* BEGIN CSTYLED */
+ATOMIC_ADD_NV(8, uint8_t, int8_t)
+ATOMIC_ADD_NV(16, uint16_t, int16_t)
+ATOMIC_ADD_NV(32, uint32_t, int32_t)
+ATOMIC_ADD_NV(64, uint64_t, int64_t)
+ATOMIC_ADD_NV(char, uchar_t, signed char)
+ATOMIC_ADD_NV(short, ushort_t, short)
+ATOMIC_ADD_NV(int, uint_t, int)
+ATOMIC_ADD_NV(long, ulong_t, long)
+/* END CSTYLED */
+
#define ATOMIC_SUB_NV(name, type1, type2) \
type1 atomic_sub_##name##_nv(volatile type1 *target, type2 bits) \
@@ -202,6 +219,13 @@ atomic_add_ptr_nv(volatile void *target, ssize_t bits)
return (__atomic_sub_fetch(target, bits, __ATOMIC_SEQ_CST)); \
}
+void *
+atomic_sub_ptr_nv(volatile void *target, ssize_t bits)
+{
+ return (__atomic_sub_fetch((void **)target, bits, __ATOMIC_SEQ_CST));
+}
+
+/* BEGIN CSTYLED */
ATOMIC_SUB_NV(8, uint8_t, int8_t)
ATOMIC_SUB_NV(char, uchar_t, signed char)
ATOMIC_SUB_NV(16, uint16_t, int16_t)
@@ -210,12 +234,7 @@ ATOMIC_SUB_NV(32, uint32_t, int32_t)
ATOMIC_SUB_NV(int, uint_t, int)
ATOMIC_SUB_NV(long, ulong_t, long)
ATOMIC_SUB_NV(64, uint64_t, int64_t)
-
-void *
-atomic_sub_ptr_nv(volatile void *target, ssize_t bits)
-{
- return (__atomic_sub_fetch((void **)target, bits, __ATOMIC_SEQ_CST));
-}
+/* END CSTYLED */
#define ATOMIC_OR_NV(name, type) \
@@ -224,14 +243,16 @@ atomic_sub_ptr_nv(volatile void *target, ssize_t bits)
return (__atomic_or_fetch(target, bits, __ATOMIC_SEQ_CST)); \
}
+/* BEGIN CSTYLED */
ATOMIC_OR_NV(8, uint8_t)
-ATOMIC_OR_NV(uchar, uchar_t)
ATOMIC_OR_NV(16, uint16_t)
-ATOMIC_OR_NV(ushort, ushort_t)
ATOMIC_OR_NV(32, uint32_t)
+ATOMIC_OR_NV(64, uint64_t)
+ATOMIC_OR_NV(uchar, uchar_t)
+ATOMIC_OR_NV(ushort, ushort_t)
ATOMIC_OR_NV(uint, uint_t)
ATOMIC_OR_NV(ulong, ulong_t)
-ATOMIC_OR_NV(64, uint64_t)
+/* END CSTYLED */
#define ATOMIC_AND_NV(name, type) \
@@ -240,14 +261,16 @@ ATOMIC_OR_NV(64, uint64_t)
return (__atomic_and_fetch(target, bits, __ATOMIC_SEQ_CST)); \
}
+/* BEGIN CSTYLED */
ATOMIC_AND_NV(8, uint8_t)
-ATOMIC_AND_NV(uchar, uchar_t)
ATOMIC_AND_NV(16, uint16_t)
-ATOMIC_AND_NV(ushort, ushort_t)
ATOMIC_AND_NV(32, uint32_t)
+ATOMIC_AND_NV(64, uint64_t)
+ATOMIC_AND_NV(uchar, uchar_t)
+ATOMIC_AND_NV(ushort, ushort_t)
ATOMIC_AND_NV(uint, uint_t)
ATOMIC_AND_NV(ulong, ulong_t)
-ATOMIC_AND_NV(64, uint64_t)
+/* END CSTYLED */
/*
@@ -268,15 +291,6 @@ ATOMIC_AND_NV(64, uint64_t)
return (exp); \
}
-ATOMIC_CAS(8, uint8_t)
-ATOMIC_CAS(uchar, uchar_t)
-ATOMIC_CAS(16, uint16_t)
-ATOMIC_CAS(ushort, ushort_t)
-ATOMIC_CAS(32, uint32_t)
-ATOMIC_CAS(uint, uint_t)
-ATOMIC_CAS(ulong, ulong_t)
-ATOMIC_CAS(64, uint64_t)
-
void *
atomic_cas_ptr(volatile void *target, void *exp, void *des)
{
@@ -286,6 +300,17 @@ atomic_cas_ptr(volatile void *target, void *exp, void *des)
return (exp);
}
+/* BEGIN CSTYLED */
+ATOMIC_CAS(8, uint8_t)
+ATOMIC_CAS(16, uint16_t)
+ATOMIC_CAS(32, uint32_t)
+ATOMIC_CAS(64, uint64_t)
+ATOMIC_CAS(uchar, uchar_t)
+ATOMIC_CAS(ushort, ushort_t)
+ATOMIC_CAS(uint, uint_t)
+ATOMIC_CAS(ulong, ulong_t)
+/* END CSTYLED */
+
/*
* Swap target and return old value
@@ -297,14 +322,15 @@ atomic_cas_ptr(volatile void *target, void *exp, void *des)
return (__atomic_exchange_n(target, bits, __ATOMIC_SEQ_CST)); \
}
+/* BEGIN CSTYLED */
ATOMIC_SWAP(8, uint8_t)
-ATOMIC_SWAP(uchar, uchar_t)
ATOMIC_SWAP(16, uint16_t)
-ATOMIC_SWAP(ushort, ushort_t)
ATOMIC_SWAP(32, uint32_t)
+ATOMIC_SWAP(64, uint64_t)
+ATOMIC_SWAP(uchar, uchar_t)
+ATOMIC_SWAP(ushort, ushort_t)
ATOMIC_SWAP(uint, uint_t)
ATOMIC_SWAP(ulong, ulong_t)
-ATOMIC_SWAP(64, uint64_t)
/* END CSTYLED */
void *
diff --git a/sys/contrib/openzfs/lib/libspl/include/Makefile.am b/sys/contrib/openzfs/lib/libspl/include/Makefile.am
index 9ca08b2bc0f7..20996366030c 100644
--- a/sys/contrib/openzfs/lib/libspl/include/Makefile.am
+++ b/sys/contrib/openzfs/lib/libspl/include/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = ia32 rpc sys util os
+SUBDIRS = rpc sys util os
libspldir = $(includedir)/libspl
libspl_HEADERS = \
diff --git a/sys/contrib/openzfs/lib/libspl/include/assert.h b/sys/contrib/openzfs/lib/libspl/include/assert.h
index fadff14cce01..e968a2310774 100644
--- a/sys/contrib/openzfs/lib/libspl/include/assert.h
+++ b/sys/contrib/openzfs/lib/libspl/include/assert.h
@@ -32,9 +32,10 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
+#include <sys/types.h>
/* Set to non-zero to avoid abort()ing on an assertion failure */
-extern int libspl_assert_ok;
+extern void libspl_set_assert_ok(boolean_t val);
/* printf version of libspl_assert */
extern void libspl_assertf(const char *file, const char *func, int line,
@@ -111,24 +112,22 @@ do { \
#undef assert
#endif
-/* Compile time assert */
-#define CTASSERT_GLOBAL(x) _CTASSERT(x, __LINE__)
-#define CTASSERT(x) { _CTASSERT(x, __LINE__); }
-#define _CTASSERT(x, y) __CTASSERT(x, y)
-#define __CTASSERT(x, y) \
- typedef char __attribute__((unused)) \
- __compile_time_assertion__ ## y[(x) ? 1 : -1]
-
#ifdef NDEBUG
-#define ASSERT3B(x, y, z) ((void) sizeof (!!(x)), (void) sizeof (!!(z)))
-#define ASSERT3S(x, y, z) ((void) sizeof (!!(x)), (void) sizeof (!!(z)))
-#define ASSERT3U(x, y, z) ((void) sizeof (!!(x)), (void) sizeof (!!(z)))
-#define ASSERT3P(x, y, z) ((void) sizeof (!!(x)), (void) sizeof (!!(z)))
-#define ASSERT0(x) ((void) sizeof (!!(x)))
-#define ASSERT(x) ((void) sizeof (!!(x)))
-#define assert(x) ((void) sizeof (!!(x)))
-#define IMPLY(A, B) ((void) sizeof (!!(A)), (void) sizeof (!!(B)))
-#define EQUIV(A, B) ((void) sizeof (!!(A)), (void) sizeof (!!(B)))
+#define ASSERT3B(x, y, z) \
+ ((void) sizeof ((uintptr_t)(x)), (void) sizeof ((uintptr_t)(z)))
+#define ASSERT3S(x, y, z) \
+ ((void) sizeof ((uintptr_t)(x)), (void) sizeof ((uintptr_t)(z)))
+#define ASSERT3U(x, y, z) \
+ ((void) sizeof ((uintptr_t)(x)), (void) sizeof ((uintptr_t)(z)))
+#define ASSERT3P(x, y, z) \
+ ((void) sizeof ((uintptr_t)(x)), (void) sizeof ((uintptr_t)(z)))
+#define ASSERT0(x) ((void) sizeof ((uintptr_t)(x)))
+#define ASSERT(x) ((void) sizeof ((uintptr_t)(x)))
+#define assert(x) ((void) sizeof ((uintptr_t)(x)))
+#define IMPLY(A, B) \
+ ((void) sizeof ((uintptr_t)(A)), (void) sizeof ((uintptr_t)(B)))
+#define EQUIV(A, B) \
+ ((void) sizeof ((uintptr_t)(A)), (void) sizeof ((uintptr_t)(B)))
#else
#define ASSERT3B VERIFY3B
#define ASSERT3S VERIFY3S
diff --git a/sys/contrib/openzfs/lib/libspl/include/ia32/Makefile.am b/sys/contrib/openzfs/lib/libspl/include/ia32/Makefile.am
deleted file mode 100644
index 081839c48c8f..000000000000
--- a/sys/contrib/openzfs/lib/libspl/include/ia32/Makefile.am
+++ /dev/null
@@ -1 +0,0 @@
-SUBDIRS = sys
diff --git a/sys/contrib/openzfs/lib/libspl/include/ia32/sys/Makefile.am b/sys/contrib/openzfs/lib/libspl/include/ia32/sys/Makefile.am
deleted file mode 100644
index 683288460cdf..000000000000
--- a/sys/contrib/openzfs/lib/libspl/include/ia32/sys/Makefile.am
+++ /dev/null
@@ -1,3 +0,0 @@
-libspldir = $(includedir)/libspl/ia32/sys
-libspl_HEADERS = \
- asm_linkage.h
diff --git a/sys/contrib/openzfs/lib/libspl/include/ia32/sys/asm_linkage.h b/sys/contrib/openzfs/lib/libspl/include/ia32/sys/asm_linkage.h
deleted file mode 100644
index 61c4d1a26977..000000000000
--- a/sys/contrib/openzfs/lib/libspl/include/ia32/sys/asm_linkage.h
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (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 2004 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#ifndef _IA32_SYS_ASM_LINKAGE_H
-#define _IA32_SYS_ASM_LINKAGE_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef _ASM /* The remainder of this file is only for assembly files */
-
-/*
- * make annoying differences in assembler syntax go away
- */
-
-/*
- * D16 and A16 are used to insert instructions prefixes; the
- * macros help the assembler code be slightly more portable.
- */
-#if !defined(__GNUC_AS__)
-/*
- * /usr/ccs/bin/as prefixes are parsed as separate instructions
- */
-#define D16 data16;
-#define A16 addr16;
-
-/*
- * (There are some weird constructs in constant expressions)
- */
-#define _CONST(const) [const]
-#define _BITNOT(const) -1!_CONST(const)
-#define _MUL(a, b) _CONST(a \* b)
-
-#else
-/*
- * Why not use the 'data16' and 'addr16' prefixes .. well, the
- * assembler doesn't quite believe in real mode, and thus argues with
- * us about what we're trying to do.
- */
-#define D16 .byte 0x66;
-#define A16 .byte 0x67;
-
-#define _CONST(const) (const)
-#define _BITNOT(const) ~_CONST(const)
-#define _MUL(a, b) _CONST(a * b)
-
-#endif
-
-/*
- * C pointers are different sizes between i386 and amd64.
- * These constants can be used to compute offsets into pointer arrays.
- */
-#if defined(__amd64)
-#define CLONGSHIFT 3
-#define CLONGSIZE 8
-#define CLONGMASK 7
-#elif defined(__i386)
-#define CLONGSHIFT 2
-#define CLONGSIZE 4
-#define CLONGMASK 3
-#endif
-
-/*
- * Since we know we're either ILP32 or LP64 ..
- */
-#define CPTRSHIFT CLONGSHIFT
-#define CPTRSIZE CLONGSIZE
-#define CPTRMASK CLONGMASK
-
-#if CPTRSIZE != (1 << CPTRSHIFT) || CLONGSIZE != (1 << CLONGSHIFT)
-#error "inconsistent shift constants"
-#endif
-
-#if CPTRMASK != (CPTRSIZE - 1) || CLONGMASK != (CLONGSIZE - 1)
-#error "inconsistent mask constants"
-#endif
-
-#define ASM_ENTRY_ALIGN 16
-
-/*
- * SSE register alignment and save areas
- */
-
-#define XMM_SIZE 16
-#define XMM_ALIGN 16
-
-#if defined(__amd64)
-
-#define SAVE_XMM_PROLOG(sreg, nreg) \
- subq $_CONST(_MUL(XMM_SIZE, nreg)), %rsp; \
- movq %rsp, sreg
-
-#define RSTOR_XMM_EPILOG(sreg, nreg) \
- addq $_CONST(_MUL(XMM_SIZE, nreg)), %rsp
-
-#elif defined(__i386)
-
-#define SAVE_XMM_PROLOG(sreg, nreg) \
- subl $_CONST(_MUL(XMM_SIZE, nreg) + XMM_ALIGN), %esp; \
- movl %esp, sreg; \
- addl $XMM_ALIGN, sreg; \
- andl $_BITNOT(XMM_ALIGN-1), sreg
-
-#define RSTOR_XMM_EPILOG(sreg, nreg) \
- addl $_CONST(_MUL(XMM_SIZE, nreg) + XMM_ALIGN), %esp;
-
-#endif /* __i386 */
-
-/*
- * profiling causes definitions of the MCOUNT and RTMCOUNT
- * particular to the type
- */
-#ifdef GPROF
-
-#define MCOUNT(x) \
- pushl %ebp; \
- movl %esp, %ebp; \
- call _mcount; \
- popl %ebp
-
-#endif /* GPROF */
-
-#ifdef PROF
-
-#define MCOUNT(x) \
-/* CSTYLED */ \
- .lcomm .L_/**/x/**/1, 4, 4; \
- pushl %ebp; \
- movl %esp, %ebp; \
-/* CSTYLED */ \
- movl $.L_/**/x/**/1, %edx; \
- call _mcount; \
- popl %ebp
-
-#endif /* PROF */
-
-/*
- * if we are not profiling, MCOUNT should be defined to nothing
- */
-#if !defined(PROF) && !defined(GPROF)
-#define MCOUNT(x)
-#endif /* !defined(PROF) && !defined(GPROF) */
-
-#define RTMCOUNT(x) MCOUNT(x)
-
-/*
- * Macro to define weak symbol aliases. These are similar to the ANSI-C
- * #pragma weak name = _name
- * except a compiler can determine type. The assembler must be told. Hence,
- * the second parameter must be the type of the symbol (i.e.: function,...)
- */
-#define ANSI_PRAGMA_WEAK(sym, stype) \
- .weak sym; \
- .type sym, @stype; \
-/* CSTYLED */ \
-sym = _/**/sym
-
-/*
- * Like ANSI_PRAGMA_WEAK(), but for unrelated names, as in:
- * #pragma weak sym1 = sym2
- */
-#define ANSI_PRAGMA_WEAK2(sym1, sym2, stype) \
- .weak sym1; \
- .type sym1, @stype; \
-sym1 = sym2
-
-/*
- * ENTRY provides the standard procedure entry code and an easy way to
- * insert the calls to mcount for profiling. ENTRY_NP is identical, but
- * never calls mcount.
- */
-#define ENTRY(x) \
- .text; \
- .align ASM_ENTRY_ALIGN; \
- .globl x; \
- .type x, @function; \
-x: MCOUNT(x)
-
-#define ENTRY_NP(x) \
- .text; \
- .align ASM_ENTRY_ALIGN; \
- .globl x; \
- .type x, @function; \
-x:
-
-#define RTENTRY(x) \
- .text; \
- .align ASM_ENTRY_ALIGN; \
- .globl x; \
- .type x, @function; \
-x: RTMCOUNT(x)
-
-/*
- * ENTRY2 is identical to ENTRY but provides two labels for the entry point.
- */
-#define ENTRY2(x, y) \
- .text; \
- .align ASM_ENTRY_ALIGN; \
- .globl x, y; \
- .type x, @function; \
- .type y, @function; \
-/* CSTYLED */ \
-x: ; \
-y: MCOUNT(x)
-
-#define ENTRY_NP2(x, y) \
- .text; \
- .align ASM_ENTRY_ALIGN; \
- .globl x, y; \
- .type x, @function; \
- .type y, @function; \
-/* CSTYLED */ \
-x: ; \
-y:
-
-
-/*
- * ALTENTRY provides for additional entry points.
- */
-#define ALTENTRY(x) \
- .globl x; \
- .type x, @function; \
-x:
-
-/*
- * DGDEF and DGDEF2 provide global data declarations.
- *
- * DGDEF provides a word aligned word of storage.
- *
- * DGDEF2 allocates "sz" bytes of storage with **NO** alignment. This
- * implies this macro is best used for byte arrays.
- *
- * DGDEF3 allocates "sz" bytes of storage with "algn" alignment.
- */
-#define DGDEF2(name, sz) \
- .data; \
- .globl name; \
- .type name, @object; \
- .size name, sz; \
-name:
-
-#define DGDEF3(name, sz, algn) \
- .data; \
- .align algn; \
- .globl name; \
- .type name, @object; \
- .size name, sz; \
-name:
-
-#define DGDEF(name) DGDEF3(name, 4, 4)
-
-/*
- * SET_SIZE trails a function and set the size for the ELF symbol table.
- */
-#define SET_SIZE(x) \
- .size x, [.-x]
-
-/*
- * NWORD provides native word value.
- */
-#if defined(__amd64)
-
-/*CSTYLED*/
-#define NWORD quad
-
-#elif defined(__i386)
-
-#define NWORD long
-
-#endif /* __i386 */
-
-#endif /* _ASM */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _IA32_SYS_ASM_LINKAGE_H */
diff --git a/sys/contrib/openzfs/lib/libspl/include/sys/feature_tests.h b/sys/contrib/openzfs/lib/libspl/include/sys/feature_tests.h
index c9564b2c3269..877e0a15a89e 100644
--- a/sys/contrib/openzfs/lib/libspl/include/sys/feature_tests.h
+++ b/sys/contrib/openzfs/lib/libspl/include/sys/feature_tests.h
@@ -28,13 +28,12 @@
#define _SYS_FEATURE_TESTS_H
#define ____cacheline_aligned
-#define __NORETURN __attribute__((__noreturn__))
-#if !defined(fallthrough) && !defined(_LIBCPP_VERSION)
+#if !defined(zfs_fallthrough) && !defined(_LIBCPP_VERSION)
#if defined(HAVE_IMPLICIT_FALLTHROUGH)
-#define fallthrough __attribute__((__fallthrough__))
+#define zfs_fallthrough __attribute__((__fallthrough__))
#else
-#define fallthrough ((void)0)
+#define zfs_fallthrough ((void)0)
#endif
#endif
diff --git a/sys/contrib/openzfs/lib/libspl/include/sys/isa_defs.h b/sys/contrib/openzfs/lib/libspl/include/sys/isa_defs.h
index 8c0932f57654..3922445db31c 100644
--- a/sys/contrib/openzfs/lib/libspl/include/sys/isa_defs.h
+++ b/sys/contrib/openzfs/lib/libspl/include/sys/isa_defs.h
@@ -126,7 +126,7 @@ extern "C" {
#endif
/* arm arch specific defines */
-#elif defined(__arm) || defined(__arm__) || defined(__aarch64__)
+#elif defined(__arm) || defined(__arm__)
#if !defined(__arm)
#define __arm
@@ -136,17 +136,11 @@ extern "C" {
#define __arm__
#endif
-#if defined(__aarch64__)
-#if !defined(_LP64)
-#define _LP64
-#endif
-#else
#if !defined(_ILP32)
#define _ILP32
#endif
-#endif
-#if defined(__ARMEL__) || defined(__AARCH64EL__)
+#if defined(__ARMEL__)
#define _ZFS_LITTLE_ENDIAN
#else
#define _ZFS_BIG_ENDIAN
@@ -158,6 +152,21 @@ extern "C" {
#define HAVE_EFFICIENT_UNALIGNED_ACCESS
#endif
+/* aarch64 arch specific defines */
+#elif defined(__aarch64__)
+
+#if !defined(_LP64)
+#define _LP64
+#endif
+
+#if defined(__AARCH64EL__)
+#define _ZFS_LITTLE_ENDIAN
+#else
+#define _ZFS_BIG_ENDIAN
+#endif
+
+#define _SUNOS_VTOC_16
+
/* sparc arch specific defines */
#elif defined(__sparc) || defined(__sparc__)
diff --git a/sys/contrib/openzfs/lib/libspl/include/sys/sha2.h b/sys/contrib/openzfs/lib/libspl/include/sys/sha2.h
index e2f66d225e25..8bdc23a5f61e 100644
--- a/sys/contrib/openzfs/lib/libspl/include/sys/sha2.h
+++ b/sys/contrib/openzfs/lib/libspl/include/sys/sha2.h
@@ -33,9 +33,6 @@
extern "C" {
#endif
-#define SHA2_HMAC_MIN_KEY_LEN 1 /* SHA2-HMAC min key length in bytes */
-#define SHA2_HMAC_MAX_KEY_LEN INT_MAX /* SHA2-HMAC max key length in bytes */
-
#define SHA256_DIGEST_LENGTH 32 /* SHA256 digest length in bytes */
#define SHA384_DIGEST_LENGTH 48 /* SHA384 digest length in bytes */
#define SHA512_DIGEST_LENGTH 64 /* SHA512 digest length in bytes */
diff --git a/sys/contrib/openzfs/lib/libspl/include/sys/simd.h b/sys/contrib/openzfs/lib/libspl/include/sys/simd.h
index dceedb698fe0..6ef836c16e5c 100644
--- a/sys/contrib/openzfs/lib/libspl/include/sys/simd.h
+++ b/sys/contrib/openzfs/lib/libspl/include/sys/simd.h
@@ -468,6 +468,7 @@ zfs_avx512vbmi_available(void)
static jmp_buf env;
static void sigillhandler(int x)
{
+ (void) x;
longjmp(env, 1);
}
#endif
diff --git a/sys/contrib/openzfs/lib/libspl/os/linux/zone.c b/sys/contrib/openzfs/lib/libspl/os/linux/zone.c
index a71c4e0b275b..393a16ad5cdd 100644
--- a/sys/contrib/openzfs/lib/libspl/os/linux/zone.c
+++ b/sys/contrib/openzfs/lib/libspl/os/linux/zone.c
@@ -26,7 +26,7 @@
#include <zone.h>
zoneid_t
-getzoneid()
+getzoneid(void)
{
return (GLOBAL_ZONEID);
}
diff --git a/sys/contrib/openzfs/lib/libtpool/Makefile.am b/sys/contrib/openzfs/lib/libtpool/Makefile.am
index 40fd137b4335..638d427bdf1c 100644
--- a/sys/contrib/openzfs/lib/libtpool/Makefile.am
+++ b/sys/contrib/openzfs/lib/libtpool/Makefile.am
@@ -1,6 +1,8 @@
include $(top_srcdir)/config/Rules.am
AM_CFLAGS += -fvisibility=hidden
+# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61118
+AM_CFLAGS += $(NO_CLOBBERED)
noinst_LTLIBRARIES = libtpool.la
diff --git a/sys/contrib/openzfs/lib/libtpool/thread_pool.c b/sys/contrib/openzfs/lib/libtpool/thread_pool.c
index 892beeffa5ae..58b706ddebf5 100644
--- a/sys/contrib/openzfs/lib/libtpool/thread_pool.c
+++ b/sys/contrib/openzfs/lib/libtpool/thread_pool.c
@@ -108,8 +108,7 @@ job_cleanup(void *arg)
tpool_active_t **activepp;
pthread_mutex_lock(&tpool->tp_mutex);
- /* CSTYLED */
- for (activepp = &tpool->tp_active;; activepp = &activep->tpa_next) {
+ for (activepp = &tpool->tp_active; ; activepp = &activep->tpa_next) {
activep = *activepp;
if (activep->tpa_tid == my_tid) {
*activepp = activep->tpa_next;
diff --git a/sys/contrib/openzfs/lib/libuutil/libuutil.abi b/sys/contrib/openzfs/lib/libuutil/libuutil.abi
index 48575ebc6a9f..bf13d62e2f04 100644
--- a/sys/contrib/openzfs/lib/libuutil/libuutil.abi
+++ b/sys/contrib/openzfs/lib/libuutil/libuutil.abi
@@ -152,6 +152,7 @@
<elf-symbol name='getmntany' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='getzoneid' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='libspl_assertf' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ <elf-symbol name='libspl_set_assert_ok' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='list_create' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='list_destroy' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='list_head' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@@ -255,7 +256,6 @@
<elf-symbol name='uu_zalloc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
</elf-function-symbols>
<elf-variable-symbols>
- <elf-symbol name='libspl_assert_ok' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='uu_exit_fatal_value' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='uu_exit_ok_value' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='uu_exit_usage_value' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@@ -365,7 +365,10 @@
</function-type>
</abi-instr>
<abi-instr address-size='64' path='assert.c' language='LANG_C99'>
- <var-decl name='libspl_assert_ok' type-id='95e97e5e' mangled-name='libspl_assert_ok' visibility='default' elf-symbol-id='libspl_assert_ok'/>
+ <function-decl name='libspl_set_assert_ok' mangled-name='libspl_set_assert_ok' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='libspl_set_assert_ok'>
+ <parameter type-id='f58c8277' name='val'/>
+ <return type-id='48b5725f'/>
+ </function-decl>
<function-decl name='libspl_assertf' mangled-name='libspl_assertf' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='libspl_assertf'>
<parameter type-id='80f4b756' name='file'/>
<parameter type-id='80f4b756' name='func'/>
diff --git a/sys/contrib/openzfs/lib/libuutil/uu_pname.c b/sys/contrib/openzfs/lib/libuutil/uu_pname.c
index 28c4a8a9cf7b..b6c9f2cc03ef 100644
--- a/sys/contrib/openzfs/lib/libuutil/uu_pname.c
+++ b/sys/contrib/openzfs/lib/libuutil/uu_pname.c
@@ -40,8 +40,8 @@
static const char *pname;
-static void
-uu_die_internal(int status, const char *format, va_list alist) __NORETURN;
+static _Noreturn void
+uu_die_internal(int status, const char *format, va_list alist);
int uu_exit_ok_value = EXIT_SUCCESS;
int uu_exit_fatal_value = EXIT_FAILURE;
@@ -88,7 +88,8 @@ uu_warn_internal(int err, const char *format, va_list alist)
if (pname != NULL)
(void) fprintf(stderr, "%s: ", pname);
- (void) vfprintf(stderr, format, alist);
+ if (format != NULL)
+ (void) vfprintf(stderr, format, alist);
if (strrchr(format, '\n') == NULL)
(void) fprintf(stderr, ": %s\n", strerror(err));
@@ -109,7 +110,7 @@ uu_warn(const char *format, ...)
va_end(alist);
}
-static __attribute__((format(printf, 2, 0))) __NORETURN void
+static __attribute__((format(printf, 2, 0))) _Noreturn void
uu_die_internal(int status, const char *format, va_list alist)
{
uu_warn_internal(errno, format, alist);
diff --git a/sys/contrib/openzfs/lib/libzfs/Makefile.am b/sys/contrib/openzfs/lib/libzfs/Makefile.am
index e23f7c162afb..332094469ccf 100644
--- a/sys/contrib/openzfs/lib/libzfs/Makefile.am
+++ b/sys/contrib/openzfs/lib/libzfs/Makefile.am
@@ -6,7 +6,6 @@ VPATH = \
$(top_srcdir)/lib/libzfs
# Suppress unused but set variable warnings often due to ASSERTs
-AM_CFLAGS += $(NO_UNUSED_BUT_SET_VARIABLE)
AM_CFLAGS += $(LIBCRYPTO_CFLAGS) $(ZLIB_CFLAGS)
AM_CFLAGS += -fvisibility=hidden
@@ -42,7 +41,6 @@ if BUILD_LINUX
USER_C += \
os/linux/libzfs_mount_os.c \
os/linux/libzfs_pool_os.c \
- os/linux/libzfs_sendrecv_os.c \
os/linux/libzfs_util_os.c
endif
diff --git a/sys/contrib/openzfs/lib/libzfs/libzfs.abi b/sys/contrib/openzfs/lib/libzfs/libzfs.abi
index 122321103f7a..69931fda9770 100644
--- a/sys/contrib/openzfs/lib/libzfs/libzfs.abi
+++ b/sys/contrib/openzfs/lib/libzfs/libzfs.abi
@@ -10,6 +10,7 @@
<dependency name='libm.so.6'/>
<dependency name='libcrypto.so.1.1'/>
<dependency name='libz.so.1'/>
+ <dependency name='libdl.so.2'/>
<dependency name='libpthread.so.0'/>
<dependency name='libc.so.6'/>
<dependency name='ld-linux-x86-64.so.2'/>
@@ -191,6 +192,7 @@
<elf-symbol name='is_mounted' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='is_mpath_whole_disk' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='libspl_assertf' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ <elf-symbol name='libspl_set_assert_ok' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='libzfs_add_handle' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='libzfs_envvar_is_set' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='libzfs_errno' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@@ -593,9 +595,8 @@
<elf-symbol name='fletcher_4_ssse3_ops' size='64' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='fletcher_4_superscalar4_ops' size='64' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='fletcher_4_superscalar_ops' size='64' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
- <elf-symbol name='libspl_assert_ok' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='libzfs_config_ops' size='16' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
- <elf-symbol name='spa_feature_table' size='1904' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ <elf-symbol name='spa_feature_table' size='1960' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zfeature_checks_disable' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zfs_deleg_perm_tab' size='512' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zfs_history_event_names' size='328' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@@ -906,7 +907,10 @@
<var-decl name='smb_shares' type-id='a3e5c654' visibility='default'/>
</abi-instr>
<abi-instr address-size='64' path='assert.c' language='LANG_C99'>
- <var-decl name='libspl_assert_ok' type-id='95e97e5e' mangled-name='libspl_assert_ok' visibility='default' elf-symbol-id='libspl_assert_ok'/>
+ <function-decl name='libspl_set_assert_ok' mangled-name='libspl_set_assert_ok' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='libspl_set_assert_ok'>
+ <parameter type-id='c19b74c3' name='val'/>
+ <return type-id='48b5725f'/>
+ </function-decl>
<function-decl name='libspl_assertf' mangled-name='libspl_assertf' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='libspl_assertf'>
<parameter type-id='80f4b756' name='file'/>
<parameter type-id='80f4b756' name='func'/>
@@ -967,6 +971,11 @@
<parameter type-id='64698d33' name='target'/>
<return type-id='48b5725f'/>
</function-decl>
+ <function-decl name='atomic_add_ptr' mangled-name='atomic_add_ptr' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_add_ptr'>
+ <parameter type-id='fe09dd29' name='target'/>
+ <parameter type-id='79a0948f' name='bits'/>
+ <return type-id='48b5725f'/>
+ </function-decl>
<function-decl name='atomic_add_8' mangled-name='atomic_add_8' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_add_8'>
<parameter type-id='aa323ea4' name='target'/>
<parameter type-id='ee31ee44' name='bits'/>
@@ -987,7 +996,7 @@
<parameter type-id='bd54fe1a' name='bits'/>
<return type-id='48b5725f'/>
</function-decl>
- <function-decl name='atomic_add_ptr' mangled-name='atomic_add_ptr' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_add_ptr'>
+ <function-decl name='atomic_sub_ptr' mangled-name='atomic_sub_ptr' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_sub_ptr'>
<parameter type-id='fe09dd29' name='target'/>
<parameter type-id='79a0948f' name='bits'/>
<return type-id='48b5725f'/>
@@ -1012,11 +1021,6 @@
<parameter type-id='bd54fe1a' name='bits'/>
<return type-id='48b5725f'/>
</function-decl>
- <function-decl name='atomic_sub_ptr' mangled-name='atomic_sub_ptr' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_sub_ptr'>
- <parameter type-id='fe09dd29' name='target'/>
- <parameter type-id='79a0948f' name='bits'/>
- <return type-id='48b5725f'/>
- </function-decl>
<function-decl name='atomic_or_8' mangled-name='atomic_or_8' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_or_8'>
<parameter type-id='aa323ea4' name='target'/>
<parameter type-id='b96825af' name='bits'/>
@@ -1089,6 +1093,11 @@
<parameter type-id='64698d33' name='target'/>
<return type-id='ee1f298e'/>
</function-decl>
+ <function-decl name='atomic_add_ptr_nv' mangled-name='atomic_add_ptr_nv' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_add_ptr_nv'>
+ <parameter type-id='fe09dd29' name='target'/>
+ <parameter type-id='79a0948f' name='bits'/>
+ <return type-id='eaa32e2f'/>
+ </function-decl>
<function-decl name='atomic_add_8_nv' mangled-name='atomic_add_8_nv' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_add_8_nv'>
<parameter type-id='aa323ea4' name='target'/>
<parameter type-id='ee31ee44' name='bits'/>
@@ -1109,7 +1118,7 @@
<parameter type-id='bd54fe1a' name='bits'/>
<return type-id='ee1f298e'/>
</function-decl>
- <function-decl name='atomic_add_ptr_nv' mangled-name='atomic_add_ptr_nv' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_add_ptr_nv'>
+ <function-decl name='atomic_sub_ptr_nv' mangled-name='atomic_sub_ptr_nv' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_sub_ptr_nv'>
<parameter type-id='fe09dd29' name='target'/>
<parameter type-id='79a0948f' name='bits'/>
<return type-id='eaa32e2f'/>
@@ -1134,11 +1143,6 @@
<parameter type-id='bd54fe1a' name='bits'/>
<return type-id='ee1f298e'/>
</function-decl>
- <function-decl name='atomic_sub_ptr_nv' mangled-name='atomic_sub_ptr_nv' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_sub_ptr_nv'>
- <parameter type-id='fe09dd29' name='target'/>
- <parameter type-id='79a0948f' name='bits'/>
- <return type-id='eaa32e2f'/>
- </function-decl>
<function-decl name='atomic_or_8_nv' mangled-name='atomic_or_8_nv' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_or_8_nv'>
<parameter type-id='aa323ea4' name='target'/>
<parameter type-id='b96825af' name='bits'/>
@@ -1179,6 +1183,12 @@
<parameter type-id='ee1f298e' name='bits'/>
<return type-id='ee1f298e'/>
</function-decl>
+ <function-decl name='atomic_cas_ptr' mangled-name='atomic_cas_ptr' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_cas_ptr'>
+ <parameter type-id='fe09dd29' name='target'/>
+ <parameter type-id='eaa32e2f' name='exp'/>
+ <parameter type-id='eaa32e2f' name='des'/>
+ <return type-id='eaa32e2f'/>
+ </function-decl>
<function-decl name='atomic_cas_8' mangled-name='atomic_cas_8' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_cas_8'>
<parameter type-id='aa323ea4' name='target'/>
<parameter type-id='b96825af' name='exp'/>
@@ -1203,12 +1213,6 @@
<parameter type-id='ee1f298e' name='des'/>
<return type-id='ee1f298e'/>
</function-decl>
- <function-decl name='atomic_cas_ptr' mangled-name='atomic_cas_ptr' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_cas_ptr'>
- <parameter type-id='fe09dd29' name='target'/>
- <parameter type-id='eaa32e2f' name='exp'/>
- <parameter type-id='eaa32e2f' name='des'/>
- <return type-id='eaa32e2f'/>
- </function-decl>
<function-decl name='atomic_swap_8' mangled-name='atomic_swap_8' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_swap_8'>
<parameter type-id='aa323ea4' name='target'/>
<parameter type-id='b96825af' name='bits'/>
@@ -1851,8 +1855,8 @@
</function-decl>
</abi-instr>
<abi-instr address-size='64' path='../../module/zcommon/zfeature_common.c' language='LANG_C99'>
- <array-type-def dimensions='1' type-id='83f29ca2' size-in-bits='15232' id='d96379d0'>
- <subrange length='34' type-id='7359adad' id='6a6a7e00'/>
+ <array-type-def dimensions='1' type-id='83f29ca2' size-in-bits='15680' id='9d60dcc5'>
+ <subrange length='35' type-id='7359adad' id='6e6845b5'/>
</array-type-def>
<enum-decl name='spa_feature' id='33ecb627'>
<underlying-type type-id='9cac1fee'/>
@@ -1891,7 +1895,8 @@
<enumerator name='SPA_FEATURE_DEVICE_REBUILD' value='31'/>
<enumerator name='SPA_FEATURE_ZSTD_COMPRESS' value='32'/>
<enumerator name='SPA_FEATURE_DRAID' value='33'/>
- <enumerator name='SPA_FEATURES' value='34'/>
+ <enumerator name='SPA_FEATURE_ZILSAXATTR' value='34'/>
+ <enumerator name='SPA_FEATURES' value='35'/>
</enum-decl>
<typedef-decl name='spa_feature_t' type-id='33ecb627' id='d6618c78'/>
<enum-decl name='zfeature_flags' id='6db816a4'>
@@ -1949,7 +1954,7 @@
<qualified-type-def type-id='3eee3342' const='yes' id='0c1d5bbb'/>
<pointer-type-def type-id='0c1d5bbb' size-in-bits='64' id='a3372543'/>
<pointer-type-def type-id='d6618c78' size-in-bits='64' id='a8425263'/>
- <var-decl name='spa_feature_table' type-id='d96379d0' mangled-name='spa_feature_table' visibility='default' elf-symbol-id='spa_feature_table'/>
+ <var-decl name='spa_feature_table' type-id='9d60dcc5' mangled-name='spa_feature_table' visibility='default' elf-symbol-id='spa_feature_table'/>
<var-decl name='zfeature_checks_disable' type-id='c19b74c3' mangled-name='zfeature_checks_disable' visibility='default' elf-symbol-id='zfeature_checks_disable'/>
<function-decl name='zfeature_is_valid_guid' mangled-name='zfeature_is_valid_guid' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfeature_is_valid_guid'>
<parameter type-id='80f4b756' name='name'/>
@@ -2484,7 +2489,7 @@
</data-member>
</class-decl>
<typedef-decl name='zprop_index_t' type-id='87957af9' id='64636ce3'/>
- <class-decl name='zprop_desc_t' size-in-bits='704' is-struct='yes' naming-typedef-id='ffa52b96' visibility='default' id='bbff5e4b'>
+ <class-decl name='zprop_desc_t' size-in-bits='640' is-struct='yes' naming-typedef-id='ffa52b96' visibility='default' id='bbff5e4b'>
<data-member access='public' layout-offset-in-bits='0'>
<var-decl name='pd_name' type-id='80f4b756' visibility='default'/>
</data-member>
@@ -2515,16 +2520,19 @@
<data-member access='public' layout-offset-in-bits='448'>
<var-decl name='pd_rightalign' type-id='c19b74c3' visibility='default'/>
</data-member>
- <data-member access='public' layout-offset-in-bits='480'>
+ <data-member access='public' layout-offset-in-bits='449'>
<var-decl name='pd_visible' type-id='c19b74c3' visibility='default'/>
</data-member>
- <data-member access='public' layout-offset-in-bits='512'>
+ <data-member access='public' layout-offset-in-bits='450'>
<var-decl name='pd_zfs_mod_supported' type-id='c19b74c3' visibility='default'/>
</data-member>
- <data-member access='public' layout-offset-in-bits='576'>
+ <data-member access='public' layout-offset-in-bits='451'>
+ <var-decl name='pd_always_flex' type-id='c19b74c3' visibility='default'/>
+ </data-member>
+ <data-member access='public' layout-offset-in-bits='512'>
<var-decl name='pd_table' type-id='c8bc397b' visibility='default'/>
</data-member>
- <data-member access='public' layout-offset-in-bits='640'>
+ <data-member access='public' layout-offset-in-bits='576'>
<var-decl name='pd_table_size' type-id='b59d7dce' visibility='default'/>
</data-member>
</class-decl>
@@ -2794,6 +2802,7 @@
<parameter type-id='80f4b756' name='colname'/>
<parameter type-id='c19b74c3' name='rightalign'/>
<parameter type-id='c19b74c3' name='visible'/>
+ <parameter type-id='c19b74c3' name='flex'/>
<parameter type-id='c8bc397b' name='idx_tbl'/>
<parameter type-id='a3372543' name='sfeatures'/>
<return type-id='48b5725f'/>
@@ -2817,6 +2826,7 @@
<parameter type-id='95e97e5e' name='objset_types'/>
<parameter type-id='80f4b756' name='values'/>
<parameter type-id='80f4b756' name='colname'/>
+ <parameter type-id='c19b74c3' name='flex'/>
<parameter type-id='a3372543' name='sfeatures'/>
<return type-id='48b5725f'/>
</function-decl>
@@ -2839,6 +2849,7 @@
<parameter type-id='999701cc' name='attr'/>
<parameter type-id='95e97e5e' name='objset_types'/>
<parameter type-id='80f4b756' name='colname'/>
+ <parameter type-id='c19b74c3' name='flex'/>
<parameter type-id='a3372543' name='sfeatures'/>
<return type-id='48b5725f'/>
</function-decl>
@@ -2987,6 +2998,7 @@
<typedef-decl name='dmu_objset_stats_t' type-id='098f0221' id='b2c14f17'/>
<enum-decl name='zfs_type_t' naming-typedef-id='2e45de5d' id='5d8f7321'>
<underlying-type type-id='9cac1fee'/>
+ <enumerator name='ZFS_TYPE_INVALID' value='0'/>
<enumerator name='ZFS_TYPE_FILESYSTEM' value='1'/>
<enumerator name='ZFS_TYPE_SNAPSHOT' value='2'/>
<enumerator name='ZFS_TYPE_VOLUME' value='4'/>
@@ -3356,13 +3368,13 @@
</function-decl>
<function-decl name='zfs_crypto_attempt_load_keys' mangled-name='zfs_crypto_attempt_load_keys' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfs_crypto_attempt_load_keys'>
<parameter type-id='b0382bb3' name='hdl'/>
- <parameter type-id='26a90f95' name='fsname'/>
+ <parameter type-id='80f4b756' name='fsname'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='zfs_crypto_load_key' mangled-name='zfs_crypto_load_key' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfs_crypto_load_key'>
<parameter type-id='9200a744' name='zhp'/>
<parameter type-id='c19b74c3' name='noop'/>
- <parameter type-id='26a90f95' name='alt_keylocation'/>
+ <parameter type-id='80f4b756' name='alt_keylocation'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='zfs_crypto_unload_key' mangled-name='zfs_crypto_unload_key' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfs_crypto_unload_key'>
@@ -4077,9 +4089,6 @@
</function-decl>
</abi-instr>
<abi-instr address-size='64' path='libzfs_mount.c' language='LANG_C99'>
- <array-type-def dimensions='1' type-id='f1bd64e2' size-in-bits='384' id='b2c36c9f'>
- <subrange length='2' type-id='7359adad' id='52efc4ef'/>
- </array-type-def>
<class-decl name='get_all_cb' size-in-bits='192' is-struct='yes' visibility='default' id='803dac95'>
<data-member access='public' layout-offset-in-bits='0'>
<var-decl name='cb_handles' type-id='4507922a' visibility='default'/>
@@ -4092,24 +4101,8 @@
</data-member>
</class-decl>
<typedef-decl name='get_all_cb_t' type-id='803dac95' id='9b293607'/>
- <class-decl name='proto_table_t' size-in-bits='192' is-struct='yes' naming-typedef-id='f1bd64e2' visibility='default' id='f4c8e1ed'>
- <data-member access='public' layout-offset-in-bits='0'>
- <var-decl name='p_prop' type-id='58603c44' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='64'>
- <var-decl name='p_name' type-id='26a90f95' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='128'>
- <var-decl name='p_share_err' type-id='95e97e5e' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='160'>
- <var-decl name='p_unshare_err' type-id='95e97e5e' visibility='default'/>
- </data-member>
- </class-decl>
- <typedef-decl name='proto_table_t' type-id='f4c8e1ed' id='f1bd64e2'/>
<pointer-type-def type-id='9b293607' size-in-bits='64' id='77bf1784'/>
<pointer-type-def type-id='9200a744' size-in-bits='64' id='4507922a'/>
- <var-decl name='proto_table' type-id='b2c36c9f' visibility='default'/>
<function-decl name='is_mounted' mangled-name='is_mounted' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='is_mounted'>
<parameter type-id='b0382bb3' name='zfs_hdl'/>
<parameter type-id='80f4b756' name='special'/>
diff --git a/sys/contrib/openzfs/lib/libzfs/libzfs_changelist.c b/sys/contrib/openzfs/lib/libzfs/libzfs_changelist.c
index 9c8241a874fa..f2282ee01177 100644
--- a/sys/contrib/openzfs/lib/libzfs/libzfs_changelist.c
+++ b/sys/contrib/openzfs/lib/libzfs/libzfs_changelist.c
@@ -345,7 +345,7 @@ changelist_rename(prop_changelist_t *clp, const char *src, const char *dst)
* unshare all the datasets in the list.
*/
int
-changelist_unshare(prop_changelist_t *clp, zfs_share_proto_t *proto)
+changelist_unshare(prop_changelist_t *clp, const zfs_share_proto_t *proto)
{
prop_changenode_t *cn;
uu_avl_walk_t *walk;
diff --git a/sys/contrib/openzfs/lib/libzfs/libzfs_crypto.c b/sys/contrib/openzfs/lib/libzfs/libzfs_crypto.c
index e3486cf9a386..e7d3b09c67aa 100644
--- a/sys/contrib/openzfs/lib/libzfs/libzfs_crypto.c
+++ b/sys/contrib/openzfs/lib/libzfs/libzfs_crypto.c
@@ -685,7 +685,7 @@ end:
*/
static int
get_key_material(libzfs_handle_t *hdl, boolean_t do_verify, boolean_t newkey,
- zfs_keyformat_t keyformat, char *keylocation, const char *fsname,
+ zfs_keyformat_t keyformat, const char *keylocation, const char *fsname,
uint8_t **km_out, size_t *kmlen_out, boolean_t *can_retry_out)
{
int ret;
@@ -1240,7 +1240,7 @@ out:
* filesystem and all of its children.
*/
int
-zfs_crypto_attempt_load_keys(libzfs_handle_t *hdl, char *fsname)
+zfs_crypto_attempt_load_keys(libzfs_handle_t *hdl, const char *fsname)
{
int ret;
zfs_handle_t *zhp = NULL;
@@ -1275,7 +1275,8 @@ error:
}
int
-zfs_crypto_load_key(zfs_handle_t *zhp, boolean_t noop, char *alt_keylocation)
+zfs_crypto_load_key(zfs_handle_t *zhp, boolean_t noop,
+ const char *alt_keylocation)
{
int ret, attempts = 0;
char errbuf[1024];
@@ -1283,7 +1284,7 @@ zfs_crypto_load_key(zfs_handle_t *zhp, boolean_t noop, char *alt_keylocation)
uint64_t keyformat = ZFS_KEYFORMAT_NONE;
char prop_keylocation[MAXNAMELEN];
char prop_encroot[MAXNAMELEN];
- char *keylocation = NULL;
+ const char *keylocation = NULL;
uint8_t *key_material = NULL, *key_data = NULL;
size_t key_material_len;
boolean_t is_encroot, can_retry = B_FALSE, correctible = B_FALSE;
diff --git a/sys/contrib/openzfs/lib/libzfs/libzfs_dataset.c b/sys/contrib/openzfs/lib/libzfs/libzfs_dataset.c
index bbc12877dc05..0115a17e6fec 100644
--- a/sys/contrib/openzfs/lib/libzfs/libzfs_dataset.c
+++ b/sys/contrib/openzfs/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;
@@ -1363,7 +1368,7 @@ badlabel:
(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
goto error;
}
- fallthrough;
+ zfs_fallthrough;
}
case ZFS_PROP_SHARESMB:
@@ -2898,6 +2903,8 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
break;
case ZFS_PROP_GUID:
+ case ZFS_PROP_KEY_GUID:
+ case ZFS_PROP_IVSET_GUID:
case ZFS_PROP_CREATETXG:
case ZFS_PROP_OBJSETID:
case ZFS_PROP_PBKDF2_ITERS:
@@ -3783,7 +3790,7 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
if (type == ZFS_TYPE_VOLUME)
return (zfs_error(hdl, EZFS_VOLTOOBIG,
errbuf));
- fallthrough;
+ zfs_fallthrough;
#endif
default:
return (zfs_standard_error(hdl, errno, errbuf));
@@ -3967,13 +3974,10 @@ zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props)
/* do the clone */
if (props) {
- zfs_type_t type;
+ zfs_type_t type = ZFS_TYPE_FILESYSTEM;
- if (ZFS_IS_VOLUME(zhp)) {
+ if (ZFS_IS_VOLUME(zhp))
type = ZFS_TYPE_VOLUME;
- } else {
- type = ZFS_TYPE_FILESYSTEM;
- }
if ((props = zfs_valid_proplist(hdl, type, props, zoned,
zhp, zhp->zpool_hdl, B_TRUE, errbuf)) == NULL)
return (-1);
diff --git a/sys/contrib/openzfs/lib/libzfs/libzfs_impl.h b/sys/contrib/openzfs/lib/libzfs/libzfs_impl.h
index 33b3feed43e6..6a18f6c328f4 100644
--- a/sys/contrib/openzfs/lib/libzfs/libzfs_impl.h
+++ b/sys/contrib/openzfs/lib/libzfs/libzfs_impl.h
@@ -189,7 +189,7 @@ extern void changelist_remove(prop_changelist_t *, const char *);
extern void changelist_free(prop_changelist_t *);
extern prop_changelist_t *changelist_gather(zfs_handle_t *, zfs_prop_t, int,
int);
-extern int changelist_unshare(prop_changelist_t *, zfs_share_proto_t *);
+extern int changelist_unshare(prop_changelist_t *, const zfs_share_proto_t *);
extern int changelist_haszonedchild(prop_changelist_t *);
extern void remove_mountpoint(zfs_handle_t *);
@@ -240,14 +240,13 @@ typedef struct differ_info {
int datafd;
} differ_info_t;
-extern proto_table_t proto_table[PROTO_END];
-
extern int do_mount(zfs_handle_t *zhp, const char *mntpt, char *opts,
int flags);
extern int do_unmount(zfs_handle_t *zhp, const char *mntpt, int flags);
extern int zfs_mount_delegation_check(void);
-extern int zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto);
-extern int zfs_unshare_proto(zfs_handle_t *, const char *, zfs_share_proto_t *);
+extern int zfs_share_proto(zfs_handle_t *zhp, const zfs_share_proto_t *proto);
+extern int zfs_unshare_proto(zfs_handle_t *, const char *,
+ const zfs_share_proto_t *);
extern int unshare_one(libzfs_handle_t *hdl, const char *name,
const char *mountpoint, zfs_share_proto_t proto);
extern boolean_t zfs_is_mountable(zfs_handle_t *zhp, char *buf, size_t buflen,
@@ -258,8 +257,7 @@ extern int libzfs_load_module(void);
extern int zpool_relabel_disk(libzfs_handle_t *hdl, const char *path,
const char *msg);
extern int find_shares_object(differ_info_t *di);
-extern void libzfs_set_pipe_max(int infd);
-extern void zfs_commit_proto(zfs_share_proto_t *);
+extern void zfs_commit_proto(const zfs_share_proto_t *);
#ifdef __cplusplus
}
diff --git a/sys/contrib/openzfs/lib/libzfs/libzfs_mount.c b/sys/contrib/openzfs/lib/libzfs/libzfs_mount.c
index 7959933ede5a..62c46be9532b 100644
--- a/sys/contrib/openzfs/lib/libzfs/libzfs_mount.c
+++ b/sys/contrib/openzfs/lib/libzfs/libzfs_mount.c
@@ -102,21 +102,21 @@ static zfs_share_type_t zfs_is_shared_proto(zfs_handle_t *, char **,
* The share protocols table must be in the same order as the zfs_share_proto_t
* enum in libzfs_impl.h
*/
-proto_table_t proto_table[PROTO_END] = {
+static const proto_table_t proto_table[PROTO_END] = {
{ZFS_PROP_SHARENFS, "nfs", EZFS_SHARENFSFAILED, EZFS_UNSHARENFSFAILED},
{ZFS_PROP_SHARESMB, "smb", EZFS_SHARESMBFAILED, EZFS_UNSHARESMBFAILED},
};
-static zfs_share_proto_t nfs_only[] = {
+static const zfs_share_proto_t nfs_only[] = {
PROTO_NFS,
PROTO_END
};
-static zfs_share_proto_t smb_only[] = {
+static const zfs_share_proto_t smb_only[] = {
PROTO_SMB,
PROTO_END
};
-static zfs_share_proto_t share_all_proto[] = {
+static const zfs_share_proto_t share_all_proto[] = {
PROTO_NFS,
PROTO_SMB,
PROTO_END
@@ -706,7 +706,7 @@ boolean_t
zfs_is_shared(zfs_handle_t *zhp)
{
zfs_share_type_t rc = 0;
- zfs_share_proto_t *curr_proto;
+ const zfs_share_proto_t *curr_proto;
if (ZFS_IS_VOLUME(zhp))
return (B_FALSE);
@@ -762,12 +762,12 @@ is_shared(const char *mountpoint, zfs_share_proto_t proto)
* on "libshare" to do the dirty work for us.
*/
int
-zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
+zfs_share_proto(zfs_handle_t *zhp, const zfs_share_proto_t *proto)
{
char mountpoint[ZFS_MAXPROPLEN];
char shareopts[ZFS_MAXPROPLEN];
char sourcestr[ZFS_MAXPROPLEN];
- zfs_share_proto_t *curr_proto;
+ const zfs_share_proto_t *curr_proto;
zprop_source_t sourcetype;
int err = 0;
@@ -872,12 +872,11 @@ zfs_parse_options(char *options, zfs_share_proto_t proto)
}
void
-zfs_commit_proto(zfs_share_proto_t *proto)
+zfs_commit_proto(const zfs_share_proto_t *proto)
{
- zfs_share_proto_t *curr_proto;
- for (curr_proto = proto; *curr_proto != PROTO_END; curr_proto++) {
+ const zfs_share_proto_t *curr_proto;
+ for (curr_proto = proto; *curr_proto != PROTO_END; curr_proto++)
sa_commit_shares(proto_table[*curr_proto].p_name);
- }
}
void
@@ -932,7 +931,7 @@ zfs_shareall(zfs_handle_t *zhp)
*/
int
zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint,
- zfs_share_proto_t *proto)
+ const zfs_share_proto_t *proto)
{
libzfs_handle_t *hdl = zhp->zfs_hdl;
struct mnttab entry;
@@ -944,7 +943,7 @@ zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint,
if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) &&
libzfs_mnttab_find(hdl, zfs_get_name(zhp), &entry) == 0)) {
- zfs_share_proto_t *curr_proto;
+ const zfs_share_proto_t *curr_proto;
if (mountpoint == NULL)
mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp);
@@ -984,7 +983,7 @@ zfs_unshare_smb(zfs_handle_t *zhp, const char *mountpoint)
* Same as zfs_unmountall(), but for NFS and SMB unshares.
*/
static int
-zfs_unshareall_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
+zfs_unshareall_proto(zfs_handle_t *zhp, const zfs_share_proto_t *proto)
{
prop_changelist_t *clp;
int ret;
@@ -1353,7 +1352,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
@@ -1374,6 +1373,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);
}
@@ -1610,13 +1611,14 @@ zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force)
* At this point, we have the entire list of filesystems, so sort it by
* mountpoint.
*/
- qsort(sets, used, sizeof (struct sets_s), mountpoint_compare);
+ if (used != 0)
+ qsort(sets, used, sizeof (struct sets_s), mountpoint_compare);
/*
* Walk through and first unshare everything.
*/
for (i = 0; i < used; i++) {
- zfs_share_proto_t *curr_proto;
+ const zfs_share_proto_t *curr_proto;
for (curr_proto = share_all_proto; *curr_proto != PROTO_END;
curr_proto++) {
if (is_shared(sets[i].mountpoint, *curr_proto) &&
diff --git a/sys/contrib/openzfs/lib/libzfs/libzfs_pool.c b/sys/contrib/openzfs/lib/libzfs/libzfs_pool.c
index 2179c03d76ed..fe58221a0268 100644
--- a/sys/contrib/openzfs/lib/libzfs/libzfs_pool.c
+++ b/sys/contrib/openzfs/lib/libzfs/libzfs_pool.c
@@ -316,7 +316,7 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf,
len);
break;
}
- fallthrough;
+ zfs_fallthrough;
default:
(void) strlcpy(buf, "-", len);
break;
@@ -347,6 +347,8 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf,
case ZPOOL_PROP_FREEING:
case ZPOOL_PROP_LEAKED:
case ZPOOL_PROP_ASHIFT:
+ case ZPOOL_PROP_MAXBLOCKSIZE:
+ case ZPOOL_PROP_MAXDNODESIZE:
if (literal)
(void) snprintf(buf, len, "%llu",
(u_longlong_t)intval);
@@ -407,7 +409,7 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf,
(void) snprintf(buf, len, "-");
break;
}
- fallthrough;
+ zfs_fallthrough;
default:
(void) snprintf(buf, len, "%llu", (u_longlong_t)intval);
}
@@ -2030,7 +2032,7 @@ zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
nvlist_t *nv = NULL;
nvlist_t *nvinfo = NULL;
nvlist_t *missing = NULL;
- char *thename;
+ const char *thename;
char *origname;
int ret;
int error = 0;
@@ -2047,7 +2049,7 @@ zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
return (zfs_error_fmt(hdl, EZFS_INVALIDNAME,
dgettext(TEXT_DOMAIN, "cannot import '%s'"),
newname));
- thename = (char *)newname;
+ thename = newname;
} else {
thename = origname;
}
@@ -5160,6 +5162,7 @@ zpool_get_vdev_prop_value(nvlist_t *nvprop, vdev_prop_t prop, char *prop_name,
case VDEV_PROP_ASIZE:
case VDEV_PROP_PSIZE:
case VDEV_PROP_SIZE:
+ case VDEV_PROP_BOOTSIZE:
case VDEV_PROP_ALLOCATED:
case VDEV_PROP_FREE:
case VDEV_PROP_READ_ERRORS:
diff --git a/sys/contrib/openzfs/lib/libzfs/libzfs_sendrecv.c b/sys/contrib/openzfs/lib/libzfs/libzfs_sendrecv.c
index d07e355e3921..ba6eddd12ea7 100644
--- a/sys/contrib/openzfs/lib/libzfs/libzfs_sendrecv.c
+++ b/sys/contrib/openzfs/lib/libzfs/libzfs_sendrecv.c
@@ -86,7 +86,7 @@ typedef struct progress_arg {
} progress_arg_t;
static int
-dump_record(dmu_replay_record_t *drr, void *payload, int payload_len,
+dump_record(dmu_replay_record_t *drr, void *payload, size_t payload_len,
zio_cksum_t *zc, int outfd)
{
ASSERT3U(offsetof(dmu_replay_record_t, drr_u.drr_checksum.drr_checksum),
@@ -191,23 +191,22 @@ fsavl_create(nvlist_t *fss)
while ((snapelem =
nvlist_next_nvpair(snaps, snapelem)) != NULL) {
fsavl_node_t *fn;
- uint64_t guid;
- guid = fnvpair_value_uint64(snapelem);
if ((fn = malloc(sizeof (fsavl_node_t))) == NULL) {
fsavl_destroy(fsavl);
return (NULL);
}
fn->fn_nvfs = nvfs;
fn->fn_snapname = nvpair_name(snapelem);
- fn->fn_guid = guid;
+ fn->fn_guid = fnvpair_value_uint64(snapelem);
/*
* Note: if there are multiple snaps with the
* same GUID, we ignore all but one.
*/
- if (avl_find(fsavl, fn, NULL) == NULL)
- avl_add(fsavl, fn);
+ avl_index_t where = 0;
+ if (avl_find(fsavl, fn, &where) == NULL)
+ avl_insert(fsavl, fn, where);
else
free(fn);
}
@@ -284,51 +283,56 @@ typedef struct send_data {
static void
send_iterate_prop(zfs_handle_t *zhp, boolean_t received_only, nvlist_t *nv);
+/*
+ * Collect guid, valid props, optionally holds, etc. of a snapshot.
+ * This interface is intended for use as a zfs_iter_snapshots_sorted visitor.
+ */
static int
send_iterate_snap(zfs_handle_t *zhp, void *arg)
{
send_data_t *sd = arg;
uint64_t guid = zhp->zfs_dmustats.dds_guid;
uint64_t txg = zhp->zfs_dmustats.dds_creation_txg;
- char *snapname;
- nvlist_t *nv;
boolean_t isfromsnap, istosnap, istosnapwithnofrom;
+ char *snapname;
+ const char *from = sd->fromsnap;
+ const char *to = sd->tosnap;
+
+ snapname = strrchr(zhp->zfs_name, '@');
+ assert(snapname != NULL);
+ ++snapname;
- snapname = strrchr(zhp->zfs_name, '@')+1;
- isfromsnap = (sd->fromsnap != NULL &&
- strcmp(sd->fromsnap, snapname) == 0);
- istosnap = (sd->tosnap != NULL && (strcmp(sd->tosnap, snapname) == 0));
- istosnapwithnofrom = (istosnap && sd->fromsnap == NULL);
+ isfromsnap = (from != NULL && strcmp(from, snapname) == 0);
+ istosnap = (to != NULL && strcmp(to, snapname) == 0);
+ istosnapwithnofrom = (istosnap && from == NULL);
if (sd->tosnap_txg != 0 && txg > sd->tosnap_txg) {
if (sd->verbose) {
(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
"skipping snapshot %s because it was created "
"after the destination snapshot (%s)\n"),
- zhp->zfs_name, sd->tosnap);
+ zhp->zfs_name, to);
}
zfs_close(zhp);
return (0);
}
fnvlist_add_uint64(sd->parent_snaps, snapname, guid);
+
/*
* NB: if there is no fromsnap here (it's a newly created fs in
* an incremental replication), we will substitute the tosnap.
*/
- if (isfromsnap || (sd->parent_fromsnap_guid == 0 && istosnap)) {
+ if (isfromsnap || (sd->parent_fromsnap_guid == 0 && istosnap))
sd->parent_fromsnap_guid = guid;
- }
if (!sd->recursive) {
-
/*
* To allow a doall stream to work properly
* with a NULL fromsnap
*/
- if (sd->doall && sd->fromsnap == NULL && !sd->seenfrom) {
+ if (sd->doall && from == NULL && !sd->seenfrom)
sd->seenfrom = B_TRUE;
- }
if (!sd->seenfrom && isfromsnap) {
sd->seenfrom = B_TRUE;
@@ -345,38 +349,40 @@ send_iterate_snap(zfs_handle_t *zhp, void *arg)
sd->seento = B_TRUE;
}
- nv = fnvlist_alloc();
+ nvlist_t *nv = fnvlist_alloc();
send_iterate_prop(zhp, sd->backup, nv);
fnvlist_add_nvlist(sd->snapprops, snapname, nv);
fnvlist_free(nv);
+
if (sd->holds) {
- nvlist_t *holds = fnvlist_alloc();
- int err = lzc_get_holds(zhp->zfs_name, &holds);
- if (err == 0) {
+ nvlist_t *holds;
+ if (lzc_get_holds(zhp->zfs_name, &holds) == 0) {
fnvlist_add_nvlist(sd->snapholds, snapname, holds);
+ fnvlist_free(holds);
}
- fnvlist_free(holds);
}
zfs_close(zhp);
return (0);
}
+/*
+ * Collect all valid props from the handle snap into an nvlist.
+ */
static void
send_iterate_prop(zfs_handle_t *zhp, boolean_t received_only, nvlist_t *nv)
{
- nvlist_t *props = NULL;
- nvpair_t *elem = NULL;
+ nvlist_t *props;
if (received_only)
props = zfs_get_recvd_props(zhp);
else
props = zhp->zfs_props;
+ nvpair_t *elem = NULL;
while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
char *propname = nvpair_name(elem);
zfs_prop_t prop = zfs_name_to_prop(propname);
- nvlist_t *propnv;
if (!zfs_prop_user(propname)) {
/*
@@ -394,34 +400,26 @@ send_iterate_prop(zfs_handle_t *zhp, boolean_t received_only, nvlist_t *nv)
continue;
}
- verify(nvpair_value_nvlist(elem, &propnv) == 0);
- if (prop == ZFS_PROP_QUOTA || prop == ZFS_PROP_RESERVATION ||
+ nvlist_t *propnv = fnvpair_value_nvlist(elem);
+
+ boolean_t isspacelimit = (prop == ZFS_PROP_QUOTA ||
+ prop == ZFS_PROP_RESERVATION ||
prop == ZFS_PROP_REFQUOTA ||
- prop == ZFS_PROP_REFRESERVATION) {
- char *source;
- uint64_t value;
- verify(nvlist_lookup_uint64(propnv,
- ZPROP_VALUE, &value) == 0);
- if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT)
+ prop == ZFS_PROP_REFRESERVATION);
+ if (isspacelimit && zhp->zfs_type == ZFS_TYPE_SNAPSHOT)
+ continue;
+
+ char *source;
+ if (nvlist_lookup_string(propnv, ZPROP_SOURCE, &source) == 0) {
+ if (strcmp(source, zhp->zfs_name) != 0 &&
+ strcmp(source, ZPROP_SOURCE_VAL_RECVD) != 0)
continue;
+ } else {
/*
* May have no source before SPA_VERSION_RECVD_PROPS,
* but is still modifiable.
*/
- if (nvlist_lookup_string(propnv,
- ZPROP_SOURCE, &source) == 0) {
- if ((strcmp(source, zhp->zfs_name) != 0) &&
- (strcmp(source,
- ZPROP_SOURCE_VAL_RECVD) != 0))
- continue;
- }
- } else {
- char *source;
- if (nvlist_lookup_string(propnv,
- ZPROP_SOURCE, &source) != 0)
- continue;
- if ((strcmp(source, zhp->zfs_name) != 0) &&
- (strcmp(source, ZPROP_SOURCE_VAL_RECVD) != 0))
+ if (!isspacelimit)
continue;
}
@@ -464,7 +462,7 @@ get_snap_txg(libzfs_handle_t *hdl, const char *fs, const char *snap)
}
/*
- * recursively generate nvlists describing datasets. See comment
+ * Recursively generate nvlists describing datasets. See comment
* for the data structure send_data_t above for description of contents
* of the nvlist.
*/
@@ -475,14 +473,16 @@ send_iterate_fs(zfs_handle_t *zhp, void *arg)
nvlist_t *nvfs = NULL, *nv = NULL;
int rv = 0;
uint64_t min_txg = 0, max_txg = 0;
- uint64_t parent_fromsnap_guid_save = sd->parent_fromsnap_guid;
- uint64_t fromsnap_txg_save = sd->fromsnap_txg;
- uint64_t tosnap_txg_save = sd->tosnap_txg;
uint64_t txg = zhp->zfs_dmustats.dds_creation_txg;
uint64_t guid = zhp->zfs_dmustats.dds_guid;
uint64_t fromsnap_txg, tosnap_txg;
char guidstring[64];
+ /* These fields are restored on return from a recursive call. */
+ uint64_t parent_fromsnap_guid_save = sd->parent_fromsnap_guid;
+ uint64_t fromsnap_txg_save = sd->fromsnap_txg;
+ uint64_t tosnap_txg_save = sd->tosnap_txg;
+
fromsnap_txg = get_snap_txg(zhp->zfs_hdl, zhp->zfs_name, sd->fromsnap);
if (fromsnap_txg != 0)
sd->fromsnap_txg = fromsnap_txg;
@@ -492,14 +492,14 @@ send_iterate_fs(zfs_handle_t *zhp, void *arg)
sd->tosnap_txg = tosnap_txg;
/*
- * on the send side, if the current dataset does not have tosnap,
+ * On the send side, if the current dataset does not have tosnap,
* perform two additional checks:
*
- * - skip sending the current dataset if it was created later than
- * the parent tosnap
- * - return error if the current dataset was created earlier than
+ * - Skip sending the current dataset if it was created later than
+ * the parent tosnap.
+ * - Return error if the current dataset was created earlier than
* the parent tosnap, unless --skip-missing specified. Then
- * just print a warning
+ * just print a warning.
*/
if (sd->tosnap != NULL && tosnap_txg == 0) {
if (sd->tosnap_txg != 0 && txg > sd->tosnap_txg) {
@@ -526,10 +526,9 @@ send_iterate_fs(zfs_handle_t *zhp, void *arg)
nvfs = fnvlist_alloc();
fnvlist_add_string(nvfs, "name", zhp->zfs_name);
- fnvlist_add_uint64(nvfs, "parentfromsnap",
- sd->parent_fromsnap_guid);
+ fnvlist_add_uint64(nvfs, "parentfromsnap", sd->parent_fromsnap_guid);
- if (zhp->zfs_dmustats.dds_origin[0]) {
+ if (zhp->zfs_dmustats.dds_origin[0] != '\0') {
zfs_handle_t *origin = zfs_open(zhp->zfs_hdl,
zhp->zfs_dmustats.dds_origin, ZFS_TYPE_SNAPSHOT);
if (origin == NULL) {
@@ -538,19 +537,19 @@ send_iterate_fs(zfs_handle_t *zhp, void *arg)
}
fnvlist_add_uint64(nvfs, "origin",
origin->zfs_dmustats.dds_guid);
-
zfs_close(origin);
}
- /* iterate over props */
+ /* Iterate over props. */
if (sd->props || sd->backup || sd->recursive) {
nv = fnvlist_alloc();
send_iterate_prop(zhp, sd->backup, nv);
+ fnvlist_add_nvlist(nvfs, "props", nv);
}
if (zfs_prop_get_int(zhp, ZFS_PROP_ENCRYPTION) != ZIO_CRYPT_OFF) {
boolean_t encroot;
- /* determine if this dataset is an encryption root */
+ /* Determine if this dataset is an encryption root. */
if (zfs_crypto_get_encryption_root(zhp, &encroot, NULL) != 0) {
rv = -1;
goto out;
@@ -576,22 +575,19 @@ send_iterate_fs(zfs_handle_t *zhp, void *arg)
}
- if (nv != NULL)
- fnvlist_add_nvlist(nvfs, "props", nv);
-
- /* iterate over snaps, and set sd->parent_fromsnap_guid */
- sd->parent_fromsnap_guid = 0;
- sd->parent_snaps = fnvlist_alloc();
- sd->snapprops = fnvlist_alloc();
- if (sd->holds)
- sd->snapholds = fnvlist_alloc();
-
/*
+ * Iterate over snaps, and set sd->parent_fromsnap_guid.
+ *
* If this is a "doall" send, a replicate send or we're just trying
* to gather a list of previous snapshots, iterate through all the
* snaps in the txg range. Otherwise just look at the one we're
* interested in.
*/
+ sd->parent_fromsnap_guid = 0;
+ sd->parent_snaps = fnvlist_alloc();
+ sd->snapprops = fnvlist_alloc();
+ if (sd->holds)
+ sd->snapholds = fnvlist_alloc();
if (sd->doall || sd->replicate || sd->tosnap == NULL) {
if (!sd->replicate && fromsnap_txg != 0)
min_txg = fromsnap_txg;
@@ -600,26 +596,26 @@ send_iterate_fs(zfs_handle_t *zhp, void *arg)
(void) zfs_iter_snapshots_sorted(zhp, send_iterate_snap, sd,
min_txg, max_txg);
} else {
- char snapname[MAXPATHLEN] = { 0 };
+ char snapname[MAXPATHLEN];
zfs_handle_t *snap;
(void) snprintf(snapname, sizeof (snapname), "%s@%s",
zhp->zfs_name, sd->tosnap);
if (sd->fromsnap != NULL)
sd->seenfrom = B_TRUE;
- snap = zfs_open(zhp->zfs_hdl, snapname,
- ZFS_TYPE_SNAPSHOT);
+ snap = zfs_open(zhp->zfs_hdl, snapname, ZFS_TYPE_SNAPSHOT);
if (snap != NULL)
(void) send_iterate_snap(snap, sd);
}
fnvlist_add_nvlist(nvfs, "snaps", sd->parent_snaps);
- fnvlist_add_nvlist(nvfs, "snapprops", sd->snapprops);
- if (sd->holds)
- fnvlist_add_nvlist(nvfs, "snapholds", sd->snapholds);
fnvlist_free(sd->parent_snaps);
+ fnvlist_add_nvlist(nvfs, "snapprops", sd->snapprops);
fnvlist_free(sd->snapprops);
- fnvlist_free(sd->snapholds);
+ if (sd->holds) {
+ fnvlist_add_nvlist(nvfs, "snapholds", sd->snapholds);
+ fnvlist_free(sd->snapholds);
+ }
/* Do not allow the size of the properties list to exceed the limit */
if ((fnvlist_size(nvfs) + fnvlist_size(sd->fss)) >
@@ -633,19 +629,21 @@ send_iterate_fs(zfs_handle_t *zhp, void *arg)
rv = EZFS_NOSPC;
goto out;
}
- /* add this fs to nvlist */
+ /* Add this fs to nvlist. */
(void) snprintf(guidstring, sizeof (guidstring),
"0x%llx", (longlong_t)guid);
fnvlist_add_nvlist(sd->fss, guidstring, nvfs);
- /* iterate over children */
+ /* Iterate over children. */
if (sd->recursive)
rv = zfs_iter_filesystems(zhp, send_iterate_fs, sd);
out:
+ /* Restore saved fields. */
sd->parent_fromsnap_guid = parent_fromsnap_guid_save;
sd->fromsnap_txg = fromsnap_txg_save;
sd->tosnap_txg = tosnap_txg_save;
+
fnvlist_free(nv);
fnvlist_free(nvfs);
@@ -730,53 +728,50 @@ static int
zfs_send_space(zfs_handle_t *zhp, const char *snapname, const char *from,
enum lzc_send_flags flags, uint64_t *spacep)
{
- libzfs_handle_t *hdl = zhp->zfs_hdl;
- int error;
-
assert(snapname != NULL);
- error = lzc_send_space(snapname, from, flags, spacep);
-
- if (error != 0) {
- char errbuf[1024];
- (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
- "warning: cannot estimate space for '%s'"), snapname);
- switch (error) {
- case EXDEV:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "not an earlier snapshot from the same fs"));
- return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));
+ int error = lzc_send_space(snapname, from, flags, spacep);
+ if (error == 0)
+ return (0);
- case ENOENT:
- if (zfs_dataset_exists(hdl, snapname,
- ZFS_TYPE_SNAPSHOT)) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "incremental source (%s) does not exist"),
- snapname);
- }
- return (zfs_error(hdl, EZFS_NOENT, errbuf));
+ char errbuf[1024];
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "warning: cannot estimate space for '%s'"), snapname);
- case EDQUOT:
- case EFBIG:
- case EIO:
- case ENOLINK:
- case ENOSPC:
- case ENOSTR:
- case ENXIO:
- case EPIPE:
- case ERANGE:
- case EFAULT:
- case EROFS:
- case EINVAL:
- zfs_error_aux(hdl, "%s", strerror(error));
- return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+ switch (error) {
+ case EXDEV:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "not an earlier snapshot from the same fs"));
+ return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));
- default:
- return (zfs_standard_error(hdl, error, errbuf));
+ case ENOENT:
+ if (zfs_dataset_exists(hdl, snapname,
+ ZFS_TYPE_SNAPSHOT)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "incremental source (%s) does not exist"),
+ snapname);
}
- }
+ return (zfs_error(hdl, EZFS_NOENT, errbuf));
- return (0);
+ case EDQUOT:
+ case EFBIG:
+ case EIO:
+ case ENOLINK:
+ case ENOSPC:
+ case ENOSTR:
+ case ENXIO:
+ case EPIPE:
+ case ERANGE:
+ case EFAULT:
+ case EROFS:
+ case EINVAL:
+ zfs_error_aux(hdl, "%s", strerror(error));
+ return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));
+
+ default:
+ return (zfs_standard_error(hdl, error, errbuf));
+ }
}
/*
@@ -802,23 +797,27 @@ dump_ioctl(zfs_handle_t *zhp, const char *fromsnap, uint64_t fromsnap_obj,
zc.zc_fromobj = fromsnap_obj;
zc.zc_flags = flags;
- thisdbg = fnvlist_alloc();
- if (fromsnap && fromsnap[0] != '\0') {
- fnvlist_add_string(thisdbg, "fromsnap", fromsnap);
+ if (debugnv != NULL) {
+ thisdbg = fnvlist_alloc();
+ if (fromsnap != NULL && fromsnap[0] != '\0')
+ fnvlist_add_string(thisdbg, "fromsnap", fromsnap);
}
if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SEND, &zc) != 0) {
char errbuf[1024];
- (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
- "warning: cannot send '%s'"), zhp->zfs_name);
+ int error = errno;
+
+ (void) snprintf(errbuf, sizeof (errbuf), "%s '%s'",
+ dgettext(TEXT_DOMAIN, "warning: cannot send"),
+ zhp->zfs_name);
- fnvlist_add_uint64(thisdbg, "error", errno);
- if (debugnv) {
+ if (debugnv != NULL) {
+ fnvlist_add_uint64(thisdbg, "error", error);
fnvlist_add_nvlist(debugnv, zhp->zfs_name, thisdbg);
+ fnvlist_free(thisdbg);
}
- fnvlist_free(thisdbg);
- switch (errno) {
+ switch (error) {
case EXDEV:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"not an earlier snapshot from the same fs"));
@@ -858,9 +857,10 @@ dump_ioctl(zfs_handle_t *zhp, const char *fromsnap, uint64_t fromsnap_obj,
}
}
- if (debugnv)
+ if (debugnv != NULL) {
fnvlist_add_nvlist(debugnv, zhp->zfs_name, thisdbg);
- fnvlist_free(thisdbg);
+ fnvlist_free(thisdbg);
+ }
return (0);
}
@@ -886,6 +886,10 @@ zfs_send_progress(zfs_handle_t *zhp, int fd, uint64_t *bytes_written,
{
zfs_cmd_t zc = {"\0"};
+ if (bytes_written != NULL)
+ *bytes_written = 0;
+ if (blocks_visited != NULL)
+ *blocks_visited = 0;
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
zc.zc_cookie = fd;
if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SEND_PROGRESS, &zc) != 0)
@@ -907,13 +911,20 @@ send_progress_thread(void *arg)
char buf[16];
time_t t;
struct tm *tm;
- boolean_t firstloop = B_TRUE;
+ int err;
+
+ if (!pa->pa_parsable) {
+ (void) fprintf(stderr,
+ "TIME %s %sSNAPSHOT %s\n",
+ pa->pa_estimate ? "BYTES" : " SENT",
+ pa->pa_verbosity >= 2 ? " BLOCKS " : "",
+ zhp->zfs_name);
+ }
/*
* Print the progress from ZFS_IOC_SEND_PROGRESS every second.
*/
for (;;) {
- int err;
(void) sleep(1);
if ((err = zfs_send_progress(zhp, pa->pa_fd, &bytes,
&blocks)) != 0) {
@@ -922,15 +933,6 @@ send_progress_thread(void *arg)
return ((void *)(uintptr_t)err);
}
- if (firstloop && !pa->pa_parsable) {
- (void) fprintf(stderr,
- "TIME %s %sSNAPSHOT %s\n",
- pa->pa_estimate ? "BYTES" : " SENT",
- pa->pa_verbosity >= 2 ? " BLOCKS " : "",
- zhp->zfs_name);
- firstloop = B_FALSE;
- }
-
(void) time(&t);
tm = localtime(&t);
@@ -965,43 +967,41 @@ send_print_verbose(FILE *fout, const char *tosnap, const char *fromsnap,
{
if (parsable) {
if (fromsnap != NULL) {
- (void) fprintf(fout, "incremental\t%s\t%s",
- fromsnap, tosnap);
+ (void) fprintf(fout, dgettext(TEXT_DOMAIN,
+ "incremental\t%s\t%s"), fromsnap, tosnap);
} else {
- (void) fprintf(fout, "full\t%s",
- tosnap);
+ (void) fprintf(fout, dgettext(TEXT_DOMAIN,
+ "full\t%s"), tosnap);
}
+ (void) fprintf(fout, "\t%llu", (longlong_t)size);
} else {
if (fromsnap != NULL) {
if (strchr(fromsnap, '@') == NULL &&
strchr(fromsnap, '#') == NULL) {
(void) fprintf(fout, dgettext(TEXT_DOMAIN,
- "send from @%s to %s"),
- fromsnap, tosnap);
+ "send from @%s to %s"), fromsnap, tosnap);
} else {
(void) fprintf(fout, dgettext(TEXT_DOMAIN,
- "send from %s to %s"),
- fromsnap, tosnap);
+ "send from %s to %s"), fromsnap, tosnap);
}
} else {
(void) fprintf(fout, dgettext(TEXT_DOMAIN,
- "full send of %s"),
- tosnap);
+ "full send of %s"), tosnap);
+ }
+ if (size != 0) {
+ char buf[16];
+ zfs_nicebytes(size, buf, sizeof (buf));
+ (void) fprintf(fout, dgettext(TEXT_DOMAIN,
+ " estimated size is %s"), buf);
}
- }
-
- if (parsable) {
- (void) fprintf(fout, "\t%llu",
- (longlong_t)size);
- } else if (size != 0) {
- char buf[16];
- zfs_nicebytes(size, buf, sizeof (buf));
- (void) fprintf(fout, dgettext(TEXT_DOMAIN,
- " estimated size is %s"), buf);
}
(void) fprintf(fout, "\n");
}
+/*
+ * Send a single filesystem snapshot, updating the send dump data.
+ * This interface is intended for use as a zfs_iter_snapshots_sorted visitor.
+ */
static int
dump_snapshot(zfs_handle_t *zhp, void *arg)
{
@@ -1023,8 +1023,7 @@ dump_snapshot(zfs_handle_t *zhp, void *arg)
if (!sdd->seenfrom && isfromsnap) {
gather_holds(zhp, sdd);
sdd->seenfrom = B_TRUE;
- (void) strlcpy(sdd->prevsnap, thissnap,
- sizeof (sdd->prevsnap));
+ (void) strlcpy(sdd->prevsnap, thissnap, sizeof (sdd->prevsnap));
sdd->prevsnap_obj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID);
zfs_close(zhp);
return (0);
@@ -1104,14 +1103,12 @@ dump_snapshot(zfs_handle_t *zhp, void *arg)
(void) strlcat(fromds, sdd->prevsnap, sizeof (fromds));
}
if (zfs_send_space(zhp, zhp->zfs_name,
- sdd->prevsnap[0] ? fromds : NULL, flags, &size) != 0) {
- size = 0; /* cannot estimate send space */
- } else {
+ sdd->prevsnap[0] ? fromds : NULL, flags, &size) == 0) {
send_print_verbose(fout, zhp->zfs_name,
sdd->prevsnap[0] ? sdd->prevsnap : NULL,
size, sdd->parsable);
+ sdd->size += size;
}
- sdd->size += size;
}
if (!sdd->dryrun) {
@@ -1142,12 +1139,9 @@ dump_snapshot(zfs_handle_t *zhp, void *arg)
(void) pthread_join(tid, &status);
int error = (int)(uintptr_t)status;
if (error != 0 && status != PTHREAD_CANCELED) {
- char errbuf[1024];
- (void) snprintf(errbuf, sizeof (errbuf),
- dgettext(TEXT_DOMAIN,
- "progress thread exited nonzero"));
return (zfs_standard_error(zhp->zfs_hdl, error,
- errbuf));
+ dgettext(TEXT_DOMAIN,
+ "progress thread exited nonzero")));
}
}
}
@@ -1158,15 +1152,20 @@ dump_snapshot(zfs_handle_t *zhp, void *arg)
return (err);
}
+/*
+ * Send all snapshots for a filesystem, updating the send dump data.
+ */
static int
-dump_filesystem(zfs_handle_t *zhp, void *arg)
+dump_filesystem(zfs_handle_t *zhp, send_dump_data_t *sdd)
{
int rv = 0;
- send_dump_data_t *sdd = arg;
boolean_t missingfrom = B_FALSE;
zfs_cmd_t zc = {"\0"};
uint64_t min_txg = 0, max_txg = 0;
+ /*
+ * Make sure the tosnap exists.
+ */
(void) snprintf(zc.zc_name, sizeof (zc.zc_name), "%s@%s",
zhp->zfs_name, sdd->tosnap);
if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_OBJSET_STATS, &zc) != 0) {
@@ -1177,47 +1176,52 @@ dump_filesystem(zfs_handle_t *zhp, void *arg)
return (0);
}
+ /*
+ * If this fs does not have fromsnap, and we're doing
+ * recursive, we need to send a full stream from the
+ * beginning (or an incremental from the origin if this
+ * is a clone). If we're doing non-recursive, then let
+ * them get the error.
+ */
if (sdd->replicate && sdd->fromsnap) {
/*
- * If this fs does not have fromsnap, and we're doing
- * recursive, we need to send a full stream from the
- * beginning (or an incremental from the origin if this
- * is a clone). If we're doing non-recursive, then let
- * them get the error.
+ * Make sure the fromsnap exists.
*/
(void) snprintf(zc.zc_name, sizeof (zc.zc_name), "%s@%s",
zhp->zfs_name, sdd->fromsnap);
- if (zfs_ioctl(zhp->zfs_hdl,
- ZFS_IOC_OBJSET_STATS, &zc) != 0) {
+ if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_OBJSET_STATS, &zc) != 0)
missingfrom = B_TRUE;
- }
}
- sdd->seenfrom = sdd->seento = sdd->prevsnap[0] = 0;
+ sdd->seenfrom = sdd->seento = B_FALSE;
+ sdd->prevsnap[0] = '\0';
sdd->prevsnap_obj = 0;
if (sdd->fromsnap == NULL || missingfrom)
sdd->seenfrom = B_TRUE;
-
-
/*
* Iterate through all snapshots and process the ones we will be
* sending. If we only have a "from" and "to" snapshot to deal
* with, we can avoid iterating through all the other snapshots.
*/
if (sdd->doall || sdd->replicate || sdd->tosnap == NULL) {
- if (!sdd->replicate && sdd->fromsnap != NULL)
- min_txg = get_snap_txg(zhp->zfs_hdl, zhp->zfs_name,
- sdd->fromsnap);
- if (!sdd->replicate && sdd->tosnap != NULL)
- max_txg = get_snap_txg(zhp->zfs_hdl, zhp->zfs_name,
- sdd->tosnap);
- rv = zfs_iter_snapshots_sorted(zhp, dump_snapshot, arg,
+ if (!sdd->replicate) {
+ if (sdd->fromsnap != NULL) {
+ min_txg = get_snap_txg(zhp->zfs_hdl,
+ zhp->zfs_name, sdd->fromsnap);
+ }
+ if (sdd->tosnap != NULL) {
+ max_txg = get_snap_txg(zhp->zfs_hdl,
+ zhp->zfs_name, sdd->tosnap);
+ }
+ }
+ rv = zfs_iter_snapshots_sorted(zhp, dump_snapshot, sdd,
min_txg, max_txg);
} else {
char snapname[MAXPATHLEN] = { 0 };
zfs_handle_t *snap;
+ /* Dump fromsnap. */
if (!sdd->seenfrom) {
(void) snprintf(snapname, sizeof (snapname),
"%s@%s", zhp->zfs_name, sdd->fromsnap);
@@ -1229,6 +1233,7 @@ dump_filesystem(zfs_handle_t *zhp, void *arg)
rv = -1;
}
+ /* Dump tosnap. */
if (rv == 0) {
(void) snprintf(snapname, sizeof (snapname),
"%s@%s", zhp->zfs_name, sdd->tosnap);
@@ -1268,10 +1273,12 @@ dump_filesystem(zfs_handle_t *zhp, void *arg)
return (rv);
}
+/*
+ * Send all snapshots for all filesystems in sdd.
+ */
static int
-dump_filesystems(zfs_handle_t *rzhp, void *arg)
+dump_filesystems(zfs_handle_t *rzhp, send_dump_data_t *sdd)
{
- send_dump_data_t *sdd = arg;
nvpair_t *fspair;
boolean_t needagain, progress;
@@ -1324,7 +1331,7 @@ again:
if (parent_guid != 0) {
parent_nv = fsavl_find(sdd->fsavl, parent_guid, NULL);
if (!nvlist_exists(parent_nv, "sent")) {
- /* parent has not been sent; skip this one */
+ /* Parent has not been sent; skip this one. */
needagain = B_TRUE;
continue;
}
@@ -1336,7 +1343,7 @@ again:
if (origin_nv != NULL &&
!nvlist_exists(origin_nv, "sent")) {
/*
- * origin has not been sent yet;
+ * Origin has not been sent yet;
* skip this clone.
*/
needagain = B_TRUE;
@@ -1359,7 +1366,7 @@ again:
goto again;
}
- /* clean out the sent flags in case we reuse this fss */
+ /* Clean out the sent flags in case we reuse this fss. */
for (fspair = nvlist_next_nvpair(sdd->fss, NULL); fspair;
fspair = nvlist_next_nvpair(sdd->fss, fspair)) {
nvlist_t *fslist;
@@ -1398,7 +1405,7 @@ zfs_send_resume_token_to_nvlist(libzfs_handle_t *hdl, const char *token)
return (NULL);
}
- /* convert hexadecimal representation to binary */
+ /* Convert hexadecimal representation to binary. */
token = strrchr(token, '-') + 1;
int len = strlen(token) / 2;
unsigned char *compressed = zfs_alloc(hdl, len);
@@ -1413,7 +1420,7 @@ zfs_send_resume_token_to_nvlist(libzfs_handle_t *hdl, const char *token)
}
}
- /* verify checksum */
+ /* Verify checksum. */
zio_cksum_t cksum;
fletcher_4_native_varsize(compressed, len, &cksum);
if (cksum.zc_word[0] != checksum) {
@@ -1423,7 +1430,7 @@ zfs_send_resume_token_to_nvlist(libzfs_handle_t *hdl, const char *token)
return (NULL);
}
- /* uncompress */
+ /* Uncompress. */
void *packed = zfs_alloc(hdl, packed_len);
uLongf packed_len_long = packed_len;
if (uncompress(packed, &packed_len_long, compressed, len) != Z_OK ||
@@ -1435,7 +1442,7 @@ zfs_send_resume_token_to_nvlist(libzfs_handle_t *hdl, const char *token)
return (NULL);
}
- /* unpack nvlist */
+ /* Unpack nvlist. */
nvlist_t *nv;
int error = nvlist_unpack(packed, packed_len, &nv, KM_SLEEP);
free(packed);
@@ -1447,10 +1454,12 @@ zfs_send_resume_token_to_nvlist(libzfs_handle_t *hdl, const char *token)
}
return (nv);
}
+
static enum lzc_send_flags
lzc_flags_from_sendflags(const sendflags_t *flags)
{
enum lzc_send_flags lzc_flags = 0;
+
if (flags->largeblock)
lzc_flags |= LZC_SEND_FLAG_LARGE_BLOCK;
if (flags->embed_data)
@@ -1461,6 +1470,7 @@ lzc_flags_from_sendflags(const sendflags_t *flags)
lzc_flags |= LZC_SEND_FLAG_RAW;
if (flags->saved)
lzc_flags |= LZC_SEND_FLAG_SAVED;
+
return (lzc_flags);
}
@@ -1552,6 +1562,53 @@ redact_snaps_equal(const uint64_t *snaps1, uint64_t num_snaps1,
return (B_TRUE);
}
+static int
+get_bookmarks(const char *path, nvlist_t **bmarksp)
+{
+ nvlist_t *props = fnvlist_alloc();
+ int error;
+
+ fnvlist_add_boolean(props, "redact_complete");
+ fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_REDACT_SNAPS));
+ error = lzc_get_bookmarks(path, props, bmarksp);
+ fnvlist_free(props);
+ return (error);
+}
+
+static nvpair_t *
+find_redact_pair(nvlist_t *bmarks, const uint64_t *redact_snap_guids,
+ int num_redact_snaps)
+{
+ nvpair_t *pair;
+
+ for (pair = nvlist_next_nvpair(bmarks, NULL); pair;
+ pair = nvlist_next_nvpair(bmarks, pair)) {
+
+ nvlist_t *bmark = fnvpair_value_nvlist(pair);
+ nvlist_t *vallist = fnvlist_lookup_nvlist(bmark,
+ zfs_prop_to_name(ZFS_PROP_REDACT_SNAPS));
+ uint_t len = 0;
+ uint64_t *bmarksnaps = fnvlist_lookup_uint64_array(vallist,
+ ZPROP_VALUE, &len);
+ if (redact_snaps_equal(redact_snap_guids,
+ num_redact_snaps, bmarksnaps, len)) {
+ break;
+ }
+ }
+ return (pair);
+}
+
+static boolean_t
+get_redact_complete(nvpair_t *pair)
+{
+ nvlist_t *bmark = fnvpair_value_nvlist(pair);
+ nvlist_t *vallist = fnvlist_lookup_nvlist(bmark, "redact_complete");
+ boolean_t complete = fnvlist_lookup_boolean_value(vallist,
+ ZPROP_VALUE);
+
+ return (complete);
+}
+
/*
* Check that the list of redaction snapshots in the bookmark matches the send
* we're resuming, and return whether or not it's complete.
@@ -1565,17 +1622,12 @@ find_redact_book(libzfs_handle_t *hdl, const char *path,
char **bookname)
{
char errbuf[1024];
- int error = 0;
- nvlist_t *props = fnvlist_alloc();
nvlist_t *bmarks;
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
"cannot resume send"));
- fnvlist_add_boolean(props, "redact_complete");
- fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_REDACT_SNAPS));
- error = lzc_get_bookmarks(path, props, &bmarks);
- fnvlist_free(props);
+ int error = get_bookmarks(path, &bmarks);
if (error != 0) {
if (error == ESRCH) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
@@ -1589,47 +1641,49 @@ find_redact_book(libzfs_handle_t *hdl, const char *path,
}
return (zfs_error(hdl, EZFS_BADPROP, errbuf));
}
- nvpair_t *pair;
- for (pair = nvlist_next_nvpair(bmarks, NULL); pair;
- pair = nvlist_next_nvpair(bmarks, pair)) {
-
- nvlist_t *bmark = fnvpair_value_nvlist(pair);
- nvlist_t *vallist = fnvlist_lookup_nvlist(bmark,
- zfs_prop_to_name(ZFS_PROP_REDACT_SNAPS));
- uint_t len = 0;
- uint64_t *bmarksnaps = fnvlist_lookup_uint64_array(vallist,
- ZPROP_VALUE, &len);
- if (redact_snaps_equal(redact_snap_guids,
- num_redact_snaps, bmarksnaps, len)) {
- break;
- }
- }
+ nvpair_t *pair = find_redact_pair(bmarks, redact_snap_guids,
+ num_redact_snaps);
if (pair == NULL) {
fnvlist_free(bmarks);
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"no appropriate redaction bookmark exists"));
return (zfs_error(hdl, EZFS_BADPROP, errbuf));
}
- char *name = nvpair_name(pair);
- nvlist_t *bmark = fnvpair_value_nvlist(pair);
- nvlist_t *vallist = fnvlist_lookup_nvlist(bmark, "redact_complete");
- boolean_t complete = fnvlist_lookup_boolean_value(vallist,
- ZPROP_VALUE);
+ boolean_t complete = get_redact_complete(pair);
if (!complete) {
fnvlist_free(bmarks);
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"incomplete redaction bookmark provided"));
return (zfs_error(hdl, EZFS_BADPROP, errbuf));
}
- *bookname = strndup(name, ZFS_MAX_DATASET_NAME_LEN);
+ *bookname = strndup(nvpair_name(pair), ZFS_MAX_DATASET_NAME_LEN);
ASSERT3P(*bookname, !=, NULL);
fnvlist_free(bmarks);
return (0);
}
+static enum lzc_send_flags
+lzc_flags_from_resume_nvl(nvlist_t *resume_nvl)
+{
+ enum lzc_send_flags lzc_flags = 0;
+
+ if (nvlist_exists(resume_nvl, "largeblockok"))
+ lzc_flags |= LZC_SEND_FLAG_LARGE_BLOCK;
+ if (nvlist_exists(resume_nvl, "embedok"))
+ lzc_flags |= LZC_SEND_FLAG_EMBED_DATA;
+ if (nvlist_exists(resume_nvl, "compressok"))
+ lzc_flags |= LZC_SEND_FLAG_COMPRESS;
+ if (nvlist_exists(resume_nvl, "rawok"))
+ lzc_flags |= LZC_SEND_FLAG_RAW;
+ if (nvlist_exists(resume_nvl, "savedok"))
+ lzc_flags |= LZC_SEND_FLAG_SAVED;
+
+ return (lzc_flags);
+}
+
static int
-zfs_send_resume_impl(libzfs_handle_t *hdl, sendflags_t *flags, int outfd,
- nvlist_t *resume_nvl)
+zfs_send_resume_impl_cb_impl(libzfs_handle_t *hdl, sendflags_t *flags,
+ int outfd, nvlist_t *resume_nvl)
{
char errbuf[1024];
char *toname;
@@ -1638,7 +1692,6 @@ zfs_send_resume_impl(libzfs_handle_t *hdl, sendflags_t *flags, int outfd,
zfs_handle_t *zhp;
int error = 0;
char name[ZFS_MAX_DATASET_NAME_LEN];
- enum lzc_send_flags lzc_flags = 0;
FILE *fout = (flags->verbosity > 0 && flags->dryrun) ? stdout : stderr;
uint64_t *redact_snap_guids = NULL;
int num_redact_snaps = 0;
@@ -1665,17 +1718,6 @@ zfs_send_resume_impl(libzfs_handle_t *hdl, sendflags_t *flags, int outfd,
fromguid = 0;
(void) nvlist_lookup_uint64(resume_nvl, "fromguid", &fromguid);
- if (flags->largeblock || nvlist_exists(resume_nvl, "largeblockok"))
- lzc_flags |= LZC_SEND_FLAG_LARGE_BLOCK;
- if (flags->embed_data || nvlist_exists(resume_nvl, "embedok"))
- lzc_flags |= LZC_SEND_FLAG_EMBED_DATA;
- if (flags->compress || nvlist_exists(resume_nvl, "compressok"))
- lzc_flags |= LZC_SEND_FLAG_COMPRESS;
- if (flags->raw || nvlist_exists(resume_nvl, "rawok"))
- lzc_flags |= LZC_SEND_FLAG_RAW;
- if (flags->saved || nvlist_exists(resume_nvl, "savedok"))
- lzc_flags |= LZC_SEND_FLAG_SAVED;
-
if (flags->saved) {
(void) strcpy(name, toname);
} else {
@@ -1736,6 +1778,9 @@ zfs_send_resume_impl(libzfs_handle_t *hdl, sendflags_t *flags, int outfd,
}
}
+ enum lzc_send_flags lzc_flags = lzc_flags_from_sendflags(flags) |
+ lzc_flags_from_resume_nvl(resume_nvl);
+
if (flags->verbosity != 0) {
/*
* Some of these may have come from the resume token, set them
@@ -1848,6 +1893,32 @@ zfs_send_resume_impl(libzfs_handle_t *hdl, sendflags_t *flags, int outfd,
return (error);
}
+struct zfs_send_resume_impl {
+ libzfs_handle_t *hdl;
+ sendflags_t *flags;
+ nvlist_t *resume_nvl;
+};
+
+static int
+zfs_send_resume_impl_cb(int outfd, void *arg)
+{
+ struct zfs_send_resume_impl *zsri = arg;
+ return (zfs_send_resume_impl_cb_impl(zsri->hdl, zsri->flags, outfd,
+ zsri->resume_nvl));
+}
+
+static int
+zfs_send_resume_impl(libzfs_handle_t *hdl, sendflags_t *flags, int outfd,
+ nvlist_t *resume_nvl)
+{
+ struct zfs_send_resume_impl zsri = {
+ .hdl = hdl,
+ .flags = flags,
+ .resume_nvl = resume_nvl,
+ };
+ return (lzc_send_wrapper(zfs_send_resume_impl_cb, outfd, &zsri));
+}
+
int
zfs_send_resume(libzfs_handle_t *hdl, sendflags_t *flags, int outfd,
const char *resume_token)
@@ -2125,9 +2196,11 @@ send_prelim_records(zfs_handle_t *zhp, const char *from, int fd,
* if "replicate" is set. If "doall" is set, dump all the intermediate
* snapshots. The DMU_COMPOUNDSTREAM header is used in the "doall"
* case too. If "props" is set, send properties.
+ *
+ * Pre-wrapped (cf. lzc_send_wrapper()).
*/
-int
-zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
+static int
+zfs_send_cb_impl(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
sendflags_t *flags, int outfd, snapfilter_cb_t filter_func,
void *cb_arg, nvlist_t **debugnvp)
{
@@ -2329,6 +2402,42 @@ err_out:
return (err);
}
+struct zfs_send {
+ zfs_handle_t *zhp;
+ const char *fromsnap;
+ const char *tosnap;
+ sendflags_t *flags;
+ snapfilter_cb_t *filter_func;
+ void *cb_arg;
+ nvlist_t **debugnvp;
+};
+
+static int
+zfs_send_cb(int outfd, void *arg)
+{
+ struct zfs_send *zs = arg;
+ return (zfs_send_cb_impl(zs->zhp, zs->fromsnap, zs->tosnap, zs->flags,
+ outfd, zs->filter_func, zs->cb_arg, zs->debugnvp));
+}
+
+int
+zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
+ sendflags_t *flags, int outfd, snapfilter_cb_t filter_func,
+ void *cb_arg, nvlist_t **debugnvp)
+{
+ struct zfs_send arg = {
+ .zhp = zhp,
+ .fromsnap = fromsnap,
+ .tosnap = tosnap,
+ .flags = flags,
+ .filter_func = filter_func,
+ .cb_arg = cb_arg,
+ .debugnvp = debugnvp,
+ };
+ return (lzc_send_wrapper(zfs_send_cb, outfd, &arg));
+}
+
+
static zfs_handle_t *
name_to_dir_handle(libzfs_handle_t *hdl, const char *snapname)
{
@@ -2405,10 +2514,12 @@ snapshot_is_before(zfs_handle_t *earlier, zfs_handle_t *later)
* The "zhp" argument is the handle of the dataset to send (typically a
* snapshot). The "from" argument is the full name of the snapshot or
* bookmark that is the incremental source.
+ *
+ * Pre-wrapped (cf. lzc_send_wrapper()).
*/
-int
-zfs_send_one(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags,
- const char *redactbook)
+static int
+zfs_send_one_cb_impl(zfs_handle_t *zhp, const char *from, int fd,
+ sendflags_t *flags, const char *redactbook)
{
int err;
libzfs_handle_t *hdl = zhp->zfs_hdl;
@@ -2597,6 +2708,34 @@ zfs_send_one(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags,
return (err != 0);
}
+struct zfs_send_one {
+ zfs_handle_t *zhp;
+ const char *from;
+ sendflags_t *flags;
+ const char *redactbook;
+};
+
+static int
+zfs_send_one_cb(int fd, void *arg)
+{
+ struct zfs_send_one *zso = arg;
+ return (zfs_send_one_cb_impl(zso->zhp, zso->from, fd, zso->flags,
+ zso->redactbook));
+}
+
+int
+zfs_send_one(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags,
+ const char *redactbook)
+{
+ struct zfs_send_one zso = {
+ .zhp = zhp,
+ .from = from,
+ .flags = flags,
+ .redactbook = redactbook,
+ };
+ return (lzc_send_wrapper(zfs_send_one_cb, fd, &zso));
+}
+
/*
* Routines specific to "zfs recv"
*/
@@ -2857,22 +2996,24 @@ recv_destroy(libzfs_handle_t *hdl, const char *name, int baselen,
zhp = zfs_open(hdl, name, ZFS_TYPE_DATASET);
if (zhp == NULL)
return (-1);
- clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,
- flags->force ? MS_FORCE : 0);
- if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT &&
+ zfs_type_t type = zfs_get_type(zhp);
+ if (type == ZFS_TYPE_SNAPSHOT &&
zfs_spa_version(zhp, &spa_version) == 0 &&
spa_version >= SPA_VERSION_USERREFS)
defer = B_TRUE;
+ clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,
+ flags->force ? MS_FORCE : 0);
zfs_close(zhp);
if (clp == NULL)
return (-1);
+
err = changelist_prefix(clp);
if (err)
return (err);
if (flags->verbose)
(void) printf("attempting destroy %s\n", name);
- if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
+ if (type == ZFS_TYPE_SNAPSHOT) {
nvlist_t *nv = fnvlist_alloc();
fnvlist_add_boolean(nv, name);
err = lzc_destroy_snaps(nv, defer, NULL);
@@ -3101,7 +3242,7 @@ created_before(libzfs_handle_t *hdl, avl_tree_t *avl,
*/
static int
recv_fix_encryption_hierarchy(libzfs_handle_t *hdl, const char *top_zfs,
- nvlist_t *stream_nv, avl_tree_t *stream_avl)
+ nvlist_t *stream_nv)
{
int err;
nvpair_t *fselem = NULL;
@@ -3728,7 +3869,7 @@ zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname,
if (raw && softerr == 0 && *top_zfs != NULL) {
softerr = recv_fix_encryption_hierarchy(hdl, *top_zfs,
- stream_nv, stream_avl);
+ stream_nv);
}
out:
@@ -4033,8 +4174,8 @@ zfs_setup_cmdline_props(libzfs_handle_t *hdl, zfs_type_t type,
* properties: if we're asked to exclude this kind of
* values we remove them from "recvprops" input nvlist.
*/
- if (!zfs_prop_inheritable(prop) &&
- !zfs_prop_user(name) && /* can be inherited too */
+ if (!zfs_prop_user(name) && /* can be inherited too */
+ !zfs_prop_inheritable(prop) &&
nvlist_exists(recvprops, newname))
fnvlist_remove(recvprops, newname);
else
@@ -4124,7 +4265,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
avl_tree_t *stream_avl, char **top_zfs,
const char *finalsnap, nvlist_t *cmdprops)
{
- time_t begin_time;
+ struct timespec begin_time;
int ioctl_err, ioctl_errno, err;
char *cp;
struct drr_begin *drrb = &drr->drr_u.drr_begin;
@@ -4150,7 +4291,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
nvlist_t *rcvprops = NULL; /* props received from the send stream */
nvlist_t *oxprops = NULL; /* override (-o) and exclude (-x) props */
nvlist_t *origprops = NULL; /* original props (if destination exists) */
- zfs_type_t type;
+ zfs_type_t type = ZFS_TYPE_INVALID;
boolean_t toplevel = B_FALSE;
boolean_t zoned = B_FALSE;
boolean_t hastoken = B_FALSE;
@@ -4158,7 +4299,10 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
uint8_t *wkeydata = NULL;
uint_t wkeylen = 0;
- begin_time = time(NULL);
+#ifndef CLOCK_MONOTONIC_RAW
+#define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
+#endif
+ clock_gettime(CLOCK_MONOTONIC_RAW, &begin_time);
bzero(origin, MAXNAMELEN);
bzero(tmp_keylocation, MAXNAMELEN);
@@ -4903,7 +5047,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
(void) zfs_error(hdl, EZFS_BUSY, errbuf);
break;
}
- fallthrough;
+ zfs_fallthrough;
default:
(void) zfs_standard_error(hdl, ioctl_errno, errbuf);
}
@@ -4943,14 +5087,23 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
char buf1[64];
char buf2[64];
uint64_t bytes = read_bytes;
- time_t delta = time(NULL) - begin_time;
- if (delta == 0)
- delta = 1;
+ struct timespec delta;
+ clock_gettime(CLOCK_MONOTONIC_RAW, &delta);
+ if (begin_time.tv_nsec > delta.tv_nsec) {
+ delta.tv_nsec =
+ 1000000000 + delta.tv_nsec - begin_time.tv_nsec;
+ delta.tv_sec -= 1;
+ } else
+ delta.tv_nsec -= begin_time.tv_nsec;
+ delta.tv_sec -= begin_time.tv_sec;
+ if (delta.tv_sec == 0 && delta.tv_nsec == 0)
+ delta.tv_nsec = 1;
+ double delta_f = delta.tv_sec + (delta.tv_nsec / 1e9);
zfs_nicebytes(bytes, buf1, sizeof (buf1));
- zfs_nicebytes(bytes/delta, buf2, sizeof (buf1));
+ zfs_nicebytes(bytes / delta_f, buf2, sizeof (buf2));
- (void) printf("received %s stream in %lld seconds (%s/sec)\n",
- buf1, (longlong_t)delta, buf2);
+ (void) printf("received %s stream in %.2f seconds (%s/sec)\n",
+ buf1, delta_f, buf2);
}
err = 0;
@@ -4979,11 +5132,10 @@ static boolean_t
zfs_receive_checkprops(libzfs_handle_t *hdl, nvlist_t *props,
const char *errbuf)
{
- nvpair_t *nvp;
+ nvpair_t *nvp = NULL;
zfs_prop_t prop;
const char *name;
- nvp = NULL;
while ((nvp = nvlist_next_nvpair(props, nvp)) != NULL) {
name = nvpair_name(nvp);
prop = zfs_name_to_prop(name);
@@ -4991,7 +5143,7 @@ zfs_receive_checkprops(libzfs_handle_t *hdl, nvlist_t *props,
if (prop == ZPROP_INVAL) {
if (!zfs_prop_user(name)) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "invalid property '%s'"), name);
+ "%s: invalid property '%s'"), errbuf, name);
return (B_FALSE);
}
continue;
@@ -5015,7 +5167,7 @@ zfs_receive_checkprops(libzfs_handle_t *hdl, nvlist_t *props,
if (zfs_prop_readonly(prop) || prop == ZFS_PROP_VERSION ||
prop == ZFS_PROP_VOLSIZE) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "invalid property '%s'"), name);
+ "%s: invalid property '%s'"), errbuf, name);
return (B_FALSE);
}
}
@@ -5041,9 +5193,8 @@ zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap,
"cannot receive"));
/* check cmdline props, raise an error if they cannot be received */
- if (!zfs_receive_checkprops(hdl, cmdprops, errbuf)) {
+ if (!zfs_receive_checkprops(hdl, cmdprops, errbuf))
return (zfs_error(hdl, EZFS_BADPROP, errbuf));
- }
if (flags->isprefix &&
!zfs_dataset_exists(hdl, tosnap, ZFS_TYPE_DATASET)) {
@@ -5186,13 +5337,6 @@ zfs_receive(libzfs_handle_t *hdl, const char *tosnap, nvlist_t *props,
return (-2);
}
- /*
- * It is not uncommon for gigabytes to be processed in zfs receive.
- * Speculatively increase the buffer size if supported by the platform.
- */
- if (S_ISFIFO(sb.st_mode))
- libzfs_set_pipe_max(infd);
-
if (props) {
err = nvlist_lookup_string(props, "origin", &originsnap);
if (err && err != ENOENT)
diff --git a/sys/contrib/openzfs/lib/libzfs/libzfs_util.c b/sys/contrib/openzfs/lib/libzfs/libzfs_util.c
index b3f39afe2182..f38eeb5125e6 100644
--- a/sys/contrib/openzfs/lib/libzfs/libzfs_util.c
+++ b/sys/contrib/openzfs/lib/libzfs/libzfs_util.c
@@ -600,8 +600,8 @@ zfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err,
(void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf);
break;
}
+ zfs_fallthrough;
#endif
- fallthrough;
default:
(void) zfs_standard_error(hdl, err, errbuf);
}
@@ -1778,16 +1778,10 @@ addlist(libzfs_handle_t *hdl, char *propname, zprop_list_t **listp,
dgettext(TEXT_DOMAIN, "bad property list")));
}
- if ((entry = zfs_alloc(hdl, sizeof (zprop_list_t))) == NULL)
- return (-1);
-
+ entry = zfs_alloc(hdl, sizeof (zprop_list_t));
entry->pl_prop = prop;
if (prop == ZPROP_INVAL) {
- if ((entry->pl_user_prop = zfs_strdup(hdl, propname)) ==
- NULL) {
- free(entry);
- return (-1);
- }
+ entry->pl_user_prop = zfs_strdup(hdl, propname);
entry->pl_width = strlen(propname);
} else {
entry->pl_width = zprop_width(prop, &entry->pl_fixed,
@@ -1951,9 +1945,7 @@ zprop_expand_list(libzfs_handle_t *hdl, zprop_list_t **plp, zfs_type_t type)
* Add 'name' to the beginning of the list, which is handled
* specially.
*/
- if ((entry = zfs_alloc(hdl, sizeof (zprop_list_t))) == NULL)
- return (-1);
-
+ entry = zfs_alloc(hdl, sizeof (zprop_list_t));
entry->pl_prop = ((type == ZFS_TYPE_POOL) ? ZPOOL_PROP_NAME :
((type == ZFS_TYPE_VDEV) ? VDEV_PROP_NAME : ZFS_PROP_NAME));
entry->pl_width = zprop_width(entry->pl_prop,
diff --git a/sys/contrib/openzfs/lib/libzfs/os/freebsd/libzfs_compat.c b/sys/contrib/openzfs/lib/libzfs/os/freebsd/libzfs_compat.c
index e3f17662a11e..f5be2b90bba9 100644
--- a/sys/contrib/openzfs/lib/libzfs/os/freebsd/libzfs_compat.c
+++ b/sys/contrib/openzfs/lib/libzfs/os/freebsd/libzfs_compat.c
@@ -38,11 +38,6 @@
#define ZFS_KMOD "openzfs"
#endif
-void
-libzfs_set_pipe_max(int infd)
-{
- /* FreeBSD automatically resizes */
-}
static int
execvPe(const char *name, const char *path, char * const *argv,
@@ -198,7 +193,7 @@ execvpe(const char *name, char * const argv[], char * const envp[])
return (execvPe(name, path, argv, envp));
}
-#define ERRBUFLEN 256
+#define ERRBUFLEN 1024
static __thread char errbuf[ERRBUFLEN];
@@ -206,10 +201,10 @@ const char *
libzfs_error_init(int error)
{
char *msg = errbuf;
- size_t len, msglen = ERRBUFLEN;
+ size_t msglen = sizeof (errbuf);
if (modfind("zfs") < 0) {
- len = snprintf(msg, msglen, dgettext(TEXT_DOMAIN,
+ size_t len = snprintf(msg, msglen, dgettext(TEXT_DOMAIN,
"Failed to load %s module: "), ZFS_KMOD);
msg += len;
msglen -= len;
@@ -251,24 +246,28 @@ libzfs_load_module(void)
int
zpool_relabel_disk(libzfs_handle_t *hdl, const char *path, const char *msg)
{
+ (void) hdl, (void) path, (void) msg;
return (0);
}
int
zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, const char *name)
{
+ (void) hdl, (void) zhp, (void) name;
return (0);
}
int
find_shares_object(differ_info_t *di)
{
+ (void) di;
return (0);
}
int
zfs_destroy_snaps_nvl_os(libzfs_handle_t *hdl, nvlist_t *snaps)
{
+ (void) hdl, (void) snaps;
return (0);
}
@@ -280,7 +279,6 @@ zfs_jail(zfs_handle_t *zhp, int jailid, int attach)
{
libzfs_handle_t *hdl = zhp->zfs_hdl;
zfs_cmd_t zc = {"\0"};
- char errbuf[1024];
unsigned long cmd;
int ret;
@@ -309,6 +307,10 @@ zfs_jail(zfs_handle_t *zhp, int jailid, int attach)
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"vdevs can not be jailed"));
return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
+ case ZFS_TYPE_INVALID:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "invalid zfs_type_t: ZFS_TYPE_INVALID"));
+ return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
case ZFS_TYPE_POOL:
case ZFS_TYPE_FILESYSTEM:
/* OK */
diff --git a/sys/contrib/openzfs/lib/libzfs/os/freebsd/libzfs_zmount.c b/sys/contrib/openzfs/lib/libzfs/os/freebsd/libzfs_zmount.c
index 79a8fe111f29..3a6ab43e953d 100644
--- a/sys/contrib/openzfs/lib/libzfs/os/freebsd/libzfs_zmount.c
+++ b/sys/contrib/openzfs/lib/libzfs/os/freebsd/libzfs_zmount.c
@@ -85,10 +85,10 @@ do_mount_(const char *spec, const char *dir, int mflag, char *fstype,
assert(dir != NULL);
assert(fstype != NULL);
assert(strcmp(fstype, MNTTYPE_ZFS) == 0);
- assert(dataptr == NULL);
- assert(datalen == 0);
+ assert(dataptr == NULL), (void) dataptr;
+ assert(datalen == 0), (void) datalen;
assert(optptr != NULL);
- assert(optlen > 0);
+ assert(optlen > 0), (void) optlen;
tofree = optstr = strdup(optptr);
assert(optstr != NULL);
diff --git a/sys/contrib/openzfs/lib/libzfs/os/linux/libzfs_sendrecv_os.c b/sys/contrib/openzfs/lib/libzfs/os/linux/libzfs_sendrecv_os.c
deleted file mode 100644
index 593c38ec62df..000000000000
--- a/sys/contrib/openzfs/lib/libzfs/os/linux/libzfs_sendrecv_os.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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
- */
-
-
-#include <libzfs.h>
-
-#include "../../libzfs_impl.h"
-
-#ifndef F_SETPIPE_SZ
-#define F_SETPIPE_SZ (F_SETLEASE + 7)
-#endif /* F_SETPIPE_SZ */
-
-#ifndef F_GETPIPE_SZ
-#define F_GETPIPE_SZ (F_GETLEASE + 7)
-#endif /* F_GETPIPE_SZ */
-
-void
-libzfs_set_pipe_max(int infd)
-{
- FILE *procf = fopen("/proc/sys/fs/pipe-max-size", "re");
-
- if (procf != NULL) {
- unsigned long max_psize;
- long cur_psize;
- if (fscanf(procf, "%lu", &max_psize) > 0) {
- cur_psize = fcntl(infd, F_GETPIPE_SZ);
- if (cur_psize > 0 &&
- max_psize > (unsigned long) cur_psize)
- fcntl(infd, F_SETPIPE_SZ,
- max_psize);
- }
- fclose(procf);
- }
-}
diff --git a/sys/contrib/openzfs/lib/libzfs_core/libzfs_core.abi b/sys/contrib/openzfs/lib/libzfs_core/libzfs_core.abi
index 5a3cbaf0b80d..266007e4dcad 100644
--- a/sys/contrib/openzfs/lib/libzfs_core/libzfs_core.abi
+++ b/sys/contrib/openzfs/lib/libzfs_core/libzfs_core.abi
@@ -6,8 +6,6 @@
<dependency name='ld-linux-x86-64.so.2'/>
</elf-needed>
<elf-function-symbols>
- <elf-symbol name='_fini' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
- <elf-symbol name='_init' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='_sol_getmntent' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='atomic_add_16' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='atomic_add_16_nv' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@@ -135,6 +133,7 @@
<elf-symbol name='getmntany' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='getzoneid' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='libspl_assertf' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ <elf-symbol name='libspl_set_assert_ok' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='libzfs_core_fini' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='libzfs_core_init' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='list_create' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@@ -194,6 +193,7 @@
<elf-symbol name='lzc_send_resume_redacted' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='lzc_send_space' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='lzc_send_space_resume_redacted' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ <elf-symbol name='lzc_send_wrapper' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='lzc_set_bootenv' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='lzc_set_vdev_prop' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='lzc_snaprange_space' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@@ -214,12 +214,12 @@
<elf-symbol name='strlcat' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='strlcpy' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
</elf-function-symbols>
- <elf-variable-symbols>
- <elf-symbol name='libspl_assert_ok' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
- </elf-variable-symbols>
<abi-instr address-size='64' path='assert.c' language='LANG_C99'>
<type-decl name='variadic parameter type' id='2c1145c5'/>
- <var-decl name='libspl_assert_ok' type-id='95e97e5e' mangled-name='libspl_assert_ok' visibility='default' elf-symbol-id='libspl_assert_ok'/>
+ <function-decl name='libspl_set_assert_ok' mangled-name='libspl_set_assert_ok' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='libspl_set_assert_ok'>
+ <parameter type-id='c19b74c3' name='val'/>
+ <return type-id='48b5725f'/>
+ </function-decl>
<function-decl name='libspl_assertf' mangled-name='libspl_assertf' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='libspl_assertf'>
<parameter type-id='80f4b756' name='file'/>
<parameter type-id='80f4b756' name='func'/>
@@ -243,7 +243,6 @@
<typedef-decl name='__uint16_t' type-id='8efea9e5' id='253c2d2a'/>
<typedef-decl name='__ssize_t' type-id='bd54fe1a' id='41060289'/>
<typedef-decl name='ssize_t' type-id='41060289' id='79a0948f'/>
- <pointer-type-def type-id='48b5725f' size-in-bits='64' id='eaa32e2f'/>
<qualified-type-def type-id='149c6638' volatile='yes' id='5120c5f7'/>
<pointer-type-def type-id='5120c5f7' size-in-bits='64' id='93977ae7'/>
<qualified-type-def type-id='8f92235e' volatile='yes' id='430e0681'/>
@@ -286,6 +285,11 @@
<parameter type-id='64698d33' name='target'/>
<return type-id='48b5725f'/>
</function-decl>
+ <function-decl name='atomic_add_ptr' mangled-name='atomic_add_ptr' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_add_ptr'>
+ <parameter type-id='fe09dd29' name='target'/>
+ <parameter type-id='79a0948f' name='bits'/>
+ <return type-id='48b5725f'/>
+ </function-decl>
<function-decl name='atomic_add_8' mangled-name='atomic_add_8' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_add_8'>
<parameter type-id='aa323ea4' name='target'/>
<parameter type-id='ee31ee44' name='bits'/>
@@ -306,7 +310,7 @@
<parameter type-id='bd54fe1a' name='bits'/>
<return type-id='48b5725f'/>
</function-decl>
- <function-decl name='atomic_add_ptr' mangled-name='atomic_add_ptr' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_add_ptr'>
+ <function-decl name='atomic_sub_ptr' mangled-name='atomic_sub_ptr' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_sub_ptr'>
<parameter type-id='fe09dd29' name='target'/>
<parameter type-id='79a0948f' name='bits'/>
<return type-id='48b5725f'/>
@@ -331,11 +335,6 @@
<parameter type-id='bd54fe1a' name='bits'/>
<return type-id='48b5725f'/>
</function-decl>
- <function-decl name='atomic_sub_ptr' mangled-name='atomic_sub_ptr' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_sub_ptr'>
- <parameter type-id='fe09dd29' name='target'/>
- <parameter type-id='79a0948f' name='bits'/>
- <return type-id='48b5725f'/>
- </function-decl>
<function-decl name='atomic_or_8' mangled-name='atomic_or_8' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_or_8'>
<parameter type-id='aa323ea4' name='target'/>
<parameter type-id='b96825af' name='bits'/>
@@ -408,6 +407,11 @@
<parameter type-id='64698d33' name='target'/>
<return type-id='ee1f298e'/>
</function-decl>
+ <function-decl name='atomic_add_ptr_nv' mangled-name='atomic_add_ptr_nv' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_add_ptr_nv'>
+ <parameter type-id='fe09dd29' name='target'/>
+ <parameter type-id='79a0948f' name='bits'/>
+ <return type-id='eaa32e2f'/>
+ </function-decl>
<function-decl name='atomic_add_8_nv' mangled-name='atomic_add_8_nv' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_add_8_nv'>
<parameter type-id='aa323ea4' name='target'/>
<parameter type-id='ee31ee44' name='bits'/>
@@ -428,7 +432,7 @@
<parameter type-id='bd54fe1a' name='bits'/>
<return type-id='ee1f298e'/>
</function-decl>
- <function-decl name='atomic_add_ptr_nv' mangled-name='atomic_add_ptr_nv' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_add_ptr_nv'>
+ <function-decl name='atomic_sub_ptr_nv' mangled-name='atomic_sub_ptr_nv' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_sub_ptr_nv'>
<parameter type-id='fe09dd29' name='target'/>
<parameter type-id='79a0948f' name='bits'/>
<return type-id='eaa32e2f'/>
@@ -453,11 +457,6 @@
<parameter type-id='bd54fe1a' name='bits'/>
<return type-id='ee1f298e'/>
</function-decl>
- <function-decl name='atomic_sub_ptr_nv' mangled-name='atomic_sub_ptr_nv' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_sub_ptr_nv'>
- <parameter type-id='fe09dd29' name='target'/>
- <parameter type-id='79a0948f' name='bits'/>
- <return type-id='eaa32e2f'/>
- </function-decl>
<function-decl name='atomic_or_8_nv' mangled-name='atomic_or_8_nv' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_or_8_nv'>
<parameter type-id='aa323ea4' name='target'/>
<parameter type-id='b96825af' name='bits'/>
@@ -498,6 +497,12 @@
<parameter type-id='ee1f298e' name='bits'/>
<return type-id='ee1f298e'/>
</function-decl>
+ <function-decl name='atomic_cas_ptr' mangled-name='atomic_cas_ptr' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_cas_ptr'>
+ <parameter type-id='fe09dd29' name='target'/>
+ <parameter type-id='eaa32e2f' name='exp'/>
+ <parameter type-id='eaa32e2f' name='des'/>
+ <return type-id='eaa32e2f'/>
+ </function-decl>
<function-decl name='atomic_cas_8' mangled-name='atomic_cas_8' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_cas_8'>
<parameter type-id='aa323ea4' name='target'/>
<parameter type-id='b96825af' name='exp'/>
@@ -522,12 +527,6 @@
<parameter type-id='ee1f298e' name='des'/>
<return type-id='ee1f298e'/>
</function-decl>
- <function-decl name='atomic_cas_ptr' mangled-name='atomic_cas_ptr' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_cas_ptr'>
- <parameter type-id='fe09dd29' name='target'/>
- <parameter type-id='eaa32e2f' name='exp'/>
- <parameter type-id='eaa32e2f' name='des'/>
- <return type-id='eaa32e2f'/>
- </function-decl>
<function-decl name='atomic_swap_8' mangled-name='atomic_swap_8' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='atomic_swap_8'>
<parameter type-id='aa323ea4' name='target'/>
<parameter type-id='b96825af' name='bits'/>
@@ -715,6 +714,9 @@
<array-type-def dimensions='1' type-id='a84c031d' size-in-bits='160' id='664ac0b7'>
<subrange length='20' type-id='7359adad' id='fdca39cf'/>
</array-type-def>
+ <class-decl name='_IO_codecvt' is-struct='yes' visibility='default' is-declaration-only='yes' id='a4036571'/>
+ <class-decl name='_IO_marker' is-struct='yes' visibility='default' is-declaration-only='yes' id='010ae0b9'/>
+ <class-decl name='_IO_wide_data' is-struct='yes' visibility='default' is-declaration-only='yes' id='79bd3751'/>
<class-decl name='mnttab' size-in-bits='256' is-struct='yes' visibility='default' id='1b055409'>
<data-member access='public' layout-offset-in-bits='0'>
<var-decl name='mnt_special' type-id='26a90f95' visibility='default'/>
@@ -749,18 +751,66 @@
<var-decl name='mnt_minor' type-id='3502e3ff' visibility='default'/>
</data-member>
</class-decl>
- <typedef-decl name='_IO_lock_t' type-id='48b5725f' id='bb4788fa'/>
- <class-decl name='_IO_marker' size-in-bits='192' is-struct='yes' visibility='default' id='010ae0b9'>
+ <class-decl name='stat64' size-in-bits='1152' is-struct='yes' visibility='default' id='0bbec9cd'>
<data-member access='public' layout-offset-in-bits='0'>
- <var-decl name='_next' type-id='e4c6fa61' visibility='default'/>
+ <var-decl name='st_dev' type-id='35ed8932' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='64'>
- <var-decl name='_sbuf' type-id='dca988a5' visibility='default'/>
+ <var-decl name='st_ino' type-id='71288a47' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='128'>
- <var-decl name='_pos' type-id='95e97e5e' visibility='default'/>
+ <var-decl name='st_nlink' type-id='80f0b9df' visibility='default'/>
+ </data-member>
+ <data-member access='public' layout-offset-in-bits='192'>
+ <var-decl name='st_mode' type-id='e1c52942' visibility='default'/>
+ </data-member>
+ <data-member access='public' layout-offset-in-bits='224'>
+ <var-decl name='st_uid' type-id='cc5fcceb' visibility='default'/>
+ </data-member>
+ <data-member access='public' layout-offset-in-bits='256'>
+ <var-decl name='st_gid' type-id='d94ec6d9' visibility='default'/>
+ </data-member>
+ <data-member access='public' layout-offset-in-bits='288'>
+ <var-decl name='__pad0' type-id='95e97e5e' visibility='default'/>
+ </data-member>
+ <data-member access='public' layout-offset-in-bits='320'>
+ <var-decl name='st_rdev' type-id='35ed8932' visibility='default'/>
+ </data-member>
+ <data-member access='public' layout-offset-in-bits='384'>
+ <var-decl name='st_size' type-id='79989e9c' visibility='default'/>
+ </data-member>
+ <data-member access='public' layout-offset-in-bits='448'>
+ <var-decl name='st_blksize' type-id='d3f10a7f' visibility='default'/>
+ </data-member>
+ <data-member access='public' layout-offset-in-bits='512'>
+ <var-decl name='st_blocks' type-id='4e711bf1' visibility='default'/>
+ </data-member>
+ <data-member access='public' layout-offset-in-bits='576'>
+ <var-decl name='st_atim' type-id='a9c79a1f' visibility='default'/>
+ </data-member>
+ <data-member access='public' layout-offset-in-bits='704'>
+ <var-decl name='st_mtim' type-id='a9c79a1f' visibility='default'/>
+ </data-member>
+ <data-member access='public' layout-offset-in-bits='832'>
+ <var-decl name='st_ctim' type-id='a9c79a1f' visibility='default'/>
+ </data-member>
+ <data-member access='public' layout-offset-in-bits='960'>
+ <var-decl name='__glibc_reserved' type-id='083f8d58' visibility='default'/>
</data-member>
</class-decl>
+ <typedef-decl name='__dev_t' type-id='7359adad' id='35ed8932'/>
+ <typedef-decl name='__uid_t' type-id='f0981eeb' id='cc5fcceb'/>
+ <typedef-decl name='__gid_t' type-id='f0981eeb' id='d94ec6d9'/>
+ <typedef-decl name='__ino64_t' type-id='7359adad' id='71288a47'/>
+ <typedef-decl name='__nlink_t' type-id='7359adad' id='80f0b9df'/>
+ <typedef-decl name='__off_t' type-id='bd54fe1a' id='79989e9c'/>
+ <typedef-decl name='__off64_t' type-id='bd54fe1a' id='724e4de6'/>
+ <typedef-decl name='__time_t' type-id='bd54fe1a' id='65eda9c0'/>
+ <typedef-decl name='__blksize_t' type-id='bd54fe1a' id='d3f10a7f'/>
+ <typedef-decl name='__blkcnt64_t' type-id='bd54fe1a' id='4e711bf1'/>
+ <typedef-decl name='__syscall_slong_t' type-id='bd54fe1a' id='03085adc'/>
+ <typedef-decl name='FILE' type-id='ec1ed955' id='aa12d1ba'/>
+ <typedef-decl name='_IO_lock_t' type-id='48b5725f' id='bb4788fa'/>
<class-decl name='_IO_FILE' size-in-bits='1728' is-struct='yes' visibility='default' id='ec1ed955'>
<data-member access='public' layout-offset-in-bits='0'>
<var-decl name='_flags' type-id='95e97e5e' visibility='default'/>
@@ -829,16 +879,16 @@
<var-decl name='_offset' type-id='724e4de6' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='1216'>
- <var-decl name='__pad1' type-id='eaa32e2f' visibility='default'/>
+ <var-decl name='_codecvt' type-id='570f8c59' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='1280'>
- <var-decl name='__pad2' type-id='eaa32e2f' visibility='default'/>
+ <var-decl name='_wide_data' type-id='c65a1f29' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='1344'>
- <var-decl name='__pad3' type-id='eaa32e2f' visibility='default'/>
+ <var-decl name='_freeres_list' type-id='dca988a5' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='1408'>
- <var-decl name='__pad4' type-id='eaa32e2f' visibility='default'/>
+ <var-decl name='_freeres_buf' type-id='eaa32e2f' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='1472'>
<var-decl name='__pad5' type-id='b59d7dce' visibility='default'/>
@@ -850,65 +900,6 @@
<var-decl name='_unused2' type-id='664ac0b7' visibility='default'/>
</data-member>
</class-decl>
- <class-decl name='stat64' size-in-bits='1152' is-struct='yes' visibility='default' id='0bbec9cd'>
- <data-member access='public' layout-offset-in-bits='0'>
- <var-decl name='st_dev' type-id='35ed8932' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='64'>
- <var-decl name='st_ino' type-id='71288a47' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='128'>
- <var-decl name='st_nlink' type-id='80f0b9df' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='192'>
- <var-decl name='st_mode' type-id='e1c52942' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='224'>
- <var-decl name='st_uid' type-id='cc5fcceb' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='256'>
- <var-decl name='st_gid' type-id='d94ec6d9' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='288'>
- <var-decl name='__pad0' type-id='95e97e5e' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='320'>
- <var-decl name='st_rdev' type-id='35ed8932' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='384'>
- <var-decl name='st_size' type-id='79989e9c' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='448'>
- <var-decl name='st_blksize' type-id='d3f10a7f' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='512'>
- <var-decl name='st_blocks' type-id='4e711bf1' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='576'>
- <var-decl name='st_atim' type-id='a9c79a1f' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='704'>
- <var-decl name='st_mtim' type-id='a9c79a1f' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='832'>
- <var-decl name='st_ctim' type-id='a9c79a1f' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='960'>
- <var-decl name='__glibc_reserved' type-id='083f8d58' visibility='default'/>
- </data-member>
- </class-decl>
- <typedef-decl name='__dev_t' type-id='7359adad' id='35ed8932'/>
- <typedef-decl name='__uid_t' type-id='f0981eeb' id='cc5fcceb'/>
- <typedef-decl name='__gid_t' type-id='f0981eeb' id='d94ec6d9'/>
- <typedef-decl name='__ino64_t' type-id='7359adad' id='71288a47'/>
- <typedef-decl name='__nlink_t' type-id='7359adad' id='80f0b9df'/>
- <typedef-decl name='__off_t' type-id='bd54fe1a' id='79989e9c'/>
- <typedef-decl name='__off64_t' type-id='bd54fe1a' id='724e4de6'/>
- <typedef-decl name='__time_t' type-id='bd54fe1a' id='65eda9c0'/>
- <typedef-decl name='__blksize_t' type-id='bd54fe1a' id='d3f10a7f'/>
- <typedef-decl name='__blkcnt64_t' type-id='bd54fe1a' id='4e711bf1'/>
- <typedef-decl name='__syscall_slong_t' type-id='bd54fe1a' id='03085adc'/>
- <typedef-decl name='FILE' type-id='ec1ed955' id='aa12d1ba'/>
<class-decl name='timespec' size-in-bits='128' is-struct='yes' visibility='default' id='a9c79a1f'>
<data-member access='public' layout-offset-in-bits='0'>
<var-decl name='tv_sec' type-id='65eda9c0' visibility='default'/>
@@ -919,11 +910,16 @@
</class-decl>
<pointer-type-def type-id='aa12d1ba' size-in-bits='64' id='822cd80b'/>
<pointer-type-def type-id='ec1ed955' size-in-bits='64' id='dca988a5'/>
+ <pointer-type-def type-id='a4036571' size-in-bits='64' id='570f8c59'/>
<pointer-type-def type-id='bb4788fa' size-in-bits='64' id='cecf4ea7'/>
<pointer-type-def type-id='010ae0b9' size-in-bits='64' id='e4c6fa61'/>
+ <pointer-type-def type-id='79bd3751' size-in-bits='64' id='c65a1f29'/>
<pointer-type-def type-id='0c544dc0' size-in-bits='64' id='394fc496'/>
<pointer-type-def type-id='1b055409' size-in-bits='64' id='9d424d31'/>
<pointer-type-def type-id='0bbec9cd' size-in-bits='64' id='62f7a03d'/>
+ <class-decl name='_IO_codecvt' is-struct='yes' visibility='default' is-declaration-only='yes' id='a4036571'/>
+ <class-decl name='_IO_marker' is-struct='yes' visibility='default' is-declaration-only='yes' id='010ae0b9'/>
+ <class-decl name='_IO_wide_data' is-struct='yes' visibility='default' is-declaration-only='yes' id='79bd3751'/>
<function-decl name='getmntany' mangled-name='getmntany' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='getmntany'>
<parameter type-id='822cd80b' name='fp'/>
<parameter type-id='9d424d31' name='mgetp'/>
@@ -1009,6 +1005,7 @@
<type-decl name='unsigned char' size-in-bits='8' id='002ac4a6'/>
<type-decl name='unsigned int' size-in-bits='32' id='f0981eeb'/>
<type-decl name='unsigned long int' size-in-bits='64' id='7359adad'/>
+ <type-decl name='void' id='48b5725f'/>
<enum-decl name='lzc_dataset_type' id='bc9887f1'>
<underlying-type type-id='9cac1fee'/>
<enumerator name='LZC_DATSET_TYPE_ZFS' value='2'/>
@@ -1571,10 +1568,12 @@
<pointer-type-def type-id='9623bc03' size-in-bits='64' id='8341348b'/>
<qualified-type-def type-id='8e8d4be3' const='yes' id='693c3853'/>
<pointer-type-def type-id='693c3853' size-in-bits='64' id='22cce67b'/>
+ <pointer-type-def type-id='c70fa2e8' size-in-bits='64' id='2e711a2a'/>
<pointer-type-def type-id='8e8d4be3' size-in-bits='64' id='5ce45b60'/>
<pointer-type-def type-id='5ce45b60' size-in-bits='64' id='857bb57e'/>
<pointer-type-def type-id='9c313c2d' size-in-bits='64' id='5d6479ae'/>
<pointer-type-def type-id='b96825af' size-in-bits='64' id='ae3e8ca6'/>
+ <pointer-type-def type-id='48b5725f' size-in-bits='64' id='eaa32e2f'/>
<function-decl name='libzfs_core_init' mangled-name='libzfs_core_init' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='libzfs_core_init'>
<return type-id='95e97e5e'/>
</function-decl>
@@ -1654,6 +1653,12 @@
<parameter type-id='857bb57e' name='holdsp'/>
<return type-id='95e97e5e'/>
</function-decl>
+ <function-decl name='lzc_send_wrapper' mangled-name='lzc_send_wrapper' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='lzc_send_wrapper'>
+ <parameter type-id='2e711a2a' name='func'/>
+ <parameter type-id='95e97e5e' name='orig_fd'/>
+ <parameter type-id='eaa32e2f' name='data'/>
+ <return type-id='95e97e5e'/>
+ </function-decl>
<function-decl name='lzc_send' mangled-name='lzc_send' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='lzc_send'>
<parameter type-id='80f4b756' name='snapname'/>
<parameter type-id='80f4b756' name='from'/>
@@ -1916,7 +1921,11 @@
<parameter type-id='857bb57e' name='outnvl'/>
<return type-id='95e97e5e'/>
</function-decl>
- <type-decl name='void' id='48b5725f'/>
+ <function-type size-in-bits='64' id='c70fa2e8'>
+ <parameter type-id='95e97e5e'/>
+ <parameter type-id='eaa32e2f'/>
+ <return type-id='95e97e5e'/>
+ </function-type>
</abi-instr>
<abi-instr address-size='64' path='os/linux/libzfs_core_ioctl.c' language='LANG_C99'>
<array-type-def dimensions='1' type-id='a84c031d' size-in-bits='32768' id='d16c6df4'>
diff --git a/sys/contrib/openzfs/lib/libzfs_core/libzfs_core.c b/sys/contrib/openzfs/lib/libzfs_core/libzfs_core.c
index 99652bc4a03a..0d74aa2133f4 100644
--- a/sys/contrib/openzfs/lib/libzfs_core/libzfs_core.c
+++ b/sys/contrib/openzfs/lib/libzfs_core/libzfs_core.c
@@ -91,6 +91,9 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/zfs_ioctl.h>
+#if __FreeBSD__
+#define BIG_PIPE_SIZE (64 * 1024) /* From sys/pipe.h */
+#endif
static int g_fd = -1;
static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
@@ -586,6 +589,116 @@ lzc_get_holds(const char *snapname, nvlist_t **holdsp)
return (lzc_ioctl(ZFS_IOC_GET_HOLDS, snapname, NULL, holdsp));
}
+static unsigned int
+max_pipe_buffer(int infd)
+{
+#if __linux__
+ static unsigned int max;
+ if (max == 0) {
+ max = 1048576; /* fs/pipe.c default */
+
+ FILE *procf = fopen("/proc/sys/fs/pipe-max-size", "re");
+ if (procf != NULL) {
+ if (fscanf(procf, "%u", &max) <= 0) {
+ /* ignore error: max untouched if parse fails */
+ }
+ fclose(procf);
+ }
+ }
+
+ unsigned int cur = fcntl(infd, F_GETPIPE_SZ);
+ if (cur < max && fcntl(infd, F_SETPIPE_SZ, max) != -1)
+ cur = max;
+ return (cur);
+#else
+ /* FreeBSD automatically resizes */
+ (void) infd;
+ return (BIG_PIPE_SIZE);
+#endif
+}
+
+#if __linux__
+struct send_worker_ctx {
+ int from; /* read end of pipe, with send data; closed on exit */
+ int to; /* original arbitrary output fd; mustn't be a pipe */
+};
+
+static void *
+send_worker(void *arg)
+{
+ struct send_worker_ctx *ctx = arg;
+ unsigned int bufsiz = max_pipe_buffer(ctx->from);
+ ssize_t rd;
+
+ while ((rd = splice(ctx->from, NULL, ctx->to, NULL, bufsiz,
+ SPLICE_F_MOVE | SPLICE_F_MORE)) > 0)
+ ;
+
+ int err = (rd == -1) ? errno : 0;
+ close(ctx->from);
+ return ((void *)(uintptr_t)err);
+}
+#endif
+
+/*
+ * Since Linux 5.10, 4d03e3cc59828c82ee89ea6e27a2f3cdf95aaadf
+ * ("fs: don't allow kernel reads and writes without iter ops"),
+ * ZFS_IOC_SEND* will EINVAL when writing to /dev/null, /dev/zero, &c.
+ *
+ * This wrapper transparently executes func() with a pipe
+ * by spawning a thread to copy from that pipe to the original output
+ * in the background.
+ *
+ * Returns the error from func(), if nonzero,
+ * otherwise the error from the thread.
+ *
+ * No-op if orig_fd is -1, already a pipe (but the buffer size is bumped),
+ * and on not-Linux; as such, it is safe to wrap/call wrapped functions
+ * in a wrapped context.
+ */
+int
+lzc_send_wrapper(int (*func)(int, void *), int orig_fd, void *data)
+{
+#if __linux__
+ struct stat sb;
+ if (orig_fd != -1 && fstat(orig_fd, &sb) == -1)
+ return (errno);
+ if (orig_fd == -1 || S_ISFIFO(sb.st_mode)) {
+ if (orig_fd != -1)
+ (void) max_pipe_buffer(orig_fd);
+ return (func(orig_fd, data));
+ }
+ if ((fcntl(orig_fd, F_GETFL) & O_ACCMODE) == O_RDONLY)
+ return (errno = EBADF);
+
+ int rw[2];
+ if (pipe2(rw, O_CLOEXEC) == -1)
+ return (errno);
+
+ int err;
+ pthread_t send_thread;
+ struct send_worker_ctx ctx = {.from = rw[0], .to = orig_fd};
+ if ((err = pthread_create(&send_thread, NULL, send_worker, &ctx))
+ != 0) {
+ close(rw[0]);
+ close(rw[1]);
+ return (errno = err);
+ }
+
+ err = func(rw[1], data);
+
+ void *send_err;
+ close(rw[1]);
+ pthread_join(send_thread, &send_err);
+ if (err == 0 && send_err != 0)
+ errno = err = (uintptr_t)send_err;
+
+ return (err);
+#else
+ return (func(orig_fd, data));
+#endif
+}
+
/*
* Generate a zfs send stream for the specified snapshot and write it to
* the specified file descriptor.
@@ -656,9 +769,11 @@ lzc_send_resume(const char *snapname, const char *from, int fd,
* redactnv: nvlist of string -> boolean(ignored) containing the names of all
* the snapshots that we should redact with respect to.
* redactbook: Name of the redaction bookmark to create.
+ *
+ * Pre-wrapped.
*/
-int
-lzc_send_resume_redacted(const char *snapname, const char *from, int fd,
+static int
+lzc_send_resume_redacted_cb_impl(const char *snapname, const char *from, int fd,
enum lzc_send_flags flags, uint64_t resumeobj, uint64_t resumeoff,
const char *redactbook)
{
@@ -691,6 +806,40 @@ lzc_send_resume_redacted(const char *snapname, const char *from, int fd,
return (err);
}
+struct lzc_send_resume_redacted {
+ const char *snapname;
+ const char *from;
+ enum lzc_send_flags flags;
+ uint64_t resumeobj;
+ uint64_t resumeoff;
+ const char *redactbook;
+};
+
+static int
+lzc_send_resume_redacted_cb(int fd, void *arg)
+{
+ struct lzc_send_resume_redacted *zsrr = arg;
+ return (lzc_send_resume_redacted_cb_impl(zsrr->snapname, zsrr->from,
+ fd, zsrr->flags, zsrr->resumeobj, zsrr->resumeoff,
+ zsrr->redactbook));
+}
+
+int
+lzc_send_resume_redacted(const char *snapname, const char *from, int fd,
+ enum lzc_send_flags flags, uint64_t resumeobj, uint64_t resumeoff,
+ const char *redactbook)
+{
+ struct lzc_send_resume_redacted zsrr = {
+ .snapname = snapname,
+ .from = from,
+ .flags = flags,
+ .resumeobj = resumeobj,
+ .resumeoff = resumeoff,
+ .redactbook = redactbook,
+ };
+ return (lzc_send_wrapper(lzc_send_resume_redacted_cb, fd, &zsrr));
+}
+
/*
* "from" can be NULL, a snapshot, or a bookmark.
*
@@ -706,9 +855,11 @@ lzc_send_resume_redacted(const char *snapname, const char *from, int fd,
* significantly more I/O and be less efficient than a send space estimation on
* an equivalent snapshot. This process is also used if redact_snaps is
* non-null.
+ *
+ * Pre-wrapped.
*/
-int
-lzc_send_space_resume_redacted(const char *snapname, const char *from,
+static int
+lzc_send_space_resume_redacted_cb_impl(const char *snapname, const char *from,
enum lzc_send_flags flags, uint64_t resumeobj, uint64_t resumeoff,
uint64_t resume_bytes, const char *redactbook, int fd, uint64_t *spacep)
{
@@ -745,6 +896,45 @@ lzc_send_space_resume_redacted(const char *snapname, const char *from,
return (err);
}
+struct lzc_send_space_resume_redacted {
+ const char *snapname;
+ const char *from;
+ enum lzc_send_flags flags;
+ uint64_t resumeobj;
+ uint64_t resumeoff;
+ uint64_t resume_bytes;
+ const char *redactbook;
+ uint64_t *spacep;
+};
+
+static int
+lzc_send_space_resume_redacted_cb(int fd, void *arg)
+{
+ struct lzc_send_space_resume_redacted *zssrr = arg;
+ return (lzc_send_space_resume_redacted_cb_impl(zssrr->snapname,
+ zssrr->from, zssrr->flags, zssrr->resumeobj, zssrr->resumeoff,
+ zssrr->resume_bytes, zssrr->redactbook, fd, zssrr->spacep));
+}
+
+int
+lzc_send_space_resume_redacted(const char *snapname, const char *from,
+ enum lzc_send_flags flags, uint64_t resumeobj, uint64_t resumeoff,
+ uint64_t resume_bytes, const char *redactbook, int fd, uint64_t *spacep)
+{
+ struct lzc_send_space_resume_redacted zssrr = {
+ .snapname = snapname,
+ .from = from,
+ .flags = flags,
+ .resumeobj = resumeobj,
+ .resumeoff = resumeoff,
+ .resume_bytes = resume_bytes,
+ .redactbook = redactbook,
+ .spacep = spacep,
+ };
+ return (lzc_send_wrapper(lzc_send_space_resume_redacted_cb,
+ fd, &zssrr));
+}
+
int
lzc_send_space(const char *snapname, const char *from,
enum lzc_send_flags flags, uint64_t *spacep)
@@ -812,6 +1002,16 @@ recv_impl(const char *snapname, nvlist_t *recvdprops, nvlist_t *localprops,
}
/*
+ * It is not uncommon for gigabytes to be processed by zfs receive.
+ * Speculatively increase the buffer size if supported by the platform.
+ */
+ struct stat sb;
+ if (fstat(input_fd, &sb) == -1)
+ return (errno);
+ if (S_ISFIFO(sb.st_mode))
+ (void) max_pipe_buffer(input_fd);
+
+ /*
* The begin_record is normally a non-byteswapped BEGIN record.
* For resumable streams it may be set to any non-byteswapped
* dmu_replay_record_t.
diff --git a/sys/contrib/openzfs/lib/libzfsbootenv/lzbe_device.c b/sys/contrib/openzfs/lib/libzfsbootenv/lzbe_device.c
index 2d9c7b749ef2..39e33324b315 100644
--- a/sys/contrib/openzfs/lib/libzfsbootenv/lzbe_device.c
+++ b/sys/contrib/openzfs/lib/libzfsbootenv/lzbe_device.c
@@ -63,7 +63,7 @@ lzbe_set_boot_device(const char *pool, lzbe_flags_t flag, const char *device)
/* Drop this nvlist */
fnvlist_free(nv);
}
- fallthrough;
+ zfs_fallthrough;
case lzbe_replace:
nv = fnvlist_alloc();
break;
diff --git a/sys/contrib/openzfs/lib/libzpool/Makefile.am b/sys/contrib/openzfs/lib/libzpool/Makefile.am
index e49577ec4a63..e60a906a5cb6 100644
--- a/sys/contrib/openzfs/lib/libzpool/Makefile.am
+++ b/sys/contrib/openzfs/lib/libzpool/Makefile.am
@@ -17,9 +17,6 @@ endif
# Unconditionally enable debugging for libzpool
AM_CPPFLAGS += -DDEBUG -UNDEBUG -DZFS_DEBUG
-# Suppress unused but set variable warnings often due to ASSERTs
-AM_CFLAGS += $(NO_UNUSED_BUT_SET_VARIABLE)
-
# Includes kernel code generate warnings for large stack frames
AM_CFLAGS += $(FRAME_LARGER_THAN)
diff --git a/sys/contrib/openzfs/lib/libzpool/kernel.c b/sys/contrib/openzfs/lib/libzpool/kernel.c
index 41e0e7815c43..6b29d6d39e6a 100644
--- a/sys/contrib/openzfs/lib/libzpool/kernel.c
+++ b/sys/contrib/openzfs/lib/libzpool/kernel.c
@@ -75,12 +75,28 @@ struct proc p0;
#define TS_STACK_MIN MAX(PTHREAD_STACK_MIN, 32768)
#define TS_STACK_MAX (256 * 1024)
+struct zk_thread_wrapper {
+ void (*func)(void *);
+ void *arg;
+};
+
+static void *
+zk_thread_wrapper(void *arg)
+{
+ struct zk_thread_wrapper ztw;
+ memcpy(&ztw, arg, sizeof (ztw));
+ free(arg);
+ ztw.func(ztw.arg);
+ return (NULL);
+}
+
kthread_t *
zk_thread_create(void (*func)(void *), void *arg, size_t stksize, int state)
{
pthread_attr_t attr;
pthread_t tid;
char *stkstr;
+ struct zk_thread_wrapper *ztw;
int detachstate = PTHREAD_CREATE_DETACHED;
VERIFY0(pthread_attr_init(&attr));
@@ -117,7 +133,10 @@ zk_thread_create(void (*func)(void *), void *arg, size_t stksize, int state)
VERIFY0(pthread_attr_setstacksize(&attr, stksize));
VERIFY0(pthread_attr_setguardsize(&attr, PAGESIZE));
- VERIFY0(pthread_create(&tid, &attr, (void *(*)(void *))func, arg));
+ VERIFY(ztw = malloc(sizeof (*ztw)));
+ ztw->func = func;
+ ztw->arg = arg;
+ VERIFY0(pthread_create(&tid, &attr, zk_thread_wrapper, ztw));
VERIFY0(pthread_attr_destroy(&attr));
return ((void *)(uintptr_t)tid);
@@ -1405,3 +1424,27 @@ zfsvfs_update_fromname(const char *oldname, const char *newname)
{
(void) oldname, (void) newname;
}
+
+void
+spa_import_os(spa_t *spa)
+{
+ (void) spa;
+}
+
+void
+spa_export_os(spa_t *spa)
+{
+ (void) spa;
+}
+
+void
+spa_activate_os(spa_t *spa)
+{
+ (void) spa;
+}
+
+void
+spa_deactivate_os(spa_t *spa)
+{
+ (void) spa;
+}
diff --git a/sys/contrib/openzfs/lib/libzpool/taskq.c b/sys/contrib/openzfs/lib/libzpool/taskq.c
index 8a61130911c1..146044bb8b0a 100644
--- a/sys/contrib/openzfs/lib/libzpool/taskq.c
+++ b/sys/contrib/openzfs/lib/libzpool/taskq.c
@@ -211,7 +211,7 @@ taskq_wait_outstanding(taskq_t *tq, taskqid_t id)
taskq_wait(tq);
}
-static void
+static _Noreturn void
taskq_thread(void *arg)
{
taskq_t *tq = arg;
diff --git a/sys/contrib/openzfs/lib/libzstd/Makefile.am b/sys/contrib/openzfs/lib/libzstd/Makefile.am
index c9ed7e2aafbc..91b7a366c3b2 100644
--- a/sys/contrib/openzfs/lib/libzstd/Makefile.am
+++ b/sys/contrib/openzfs/lib/libzstd/Makefile.am
@@ -8,14 +8,33 @@ AM_CFLAGS += -fno-tree-vectorize
noinst_LTLIBRARIES = libzstd.la
-KERNEL_C = \
- lib/zstd.c \
+KERNEL_C = lib/common/entropy_common.c \
+ lib/common/error_private.c \
+ lib/common/fse_decompress.c \
+ lib/common/pool.c \
+ lib/common/zstd_common.c \
+ lib/compress/fse_compress.c \
+ lib/compress/hist.c \
+ lib/compress/huf_compress.c \
+ lib/compress/zstd_compress_literals.c \
+ lib/compress/zstd_compress_sequences.c \
+ lib/compress/zstd_compress_superblock.c \
+ lib/compress/zstd_compress.c \
+ lib/compress/zstd_double_fast.c \
+ lib/compress/zstd_fast.c \
+ lib/compress/zstd_lazy.c \
+ lib/compress/zstd_ldm.c \
+ lib/compress/zstd_opt.c \
+ lib/decompress/huf_decompress.c \
+ lib/decompress/zstd_ddict.c \
+ lib/decompress/zstd_decompress.c \
+ lib/decompress/zstd_decompress_block.c \
zfs_zstd.c
nodist_libzstd_la_SOURCES = $(KERNEL_C)
-lib/zstd.$(OBJEXT): CFLAGS += -fno-tree-vectorize -include $(top_srcdir)/module/zstd/include/zstd_compat_wrapper.h -Wp,-w
-lib/zstd.l$(OBJEXT): CFLAGS += -fno-tree-vectorize -include $(top_srcdir)/module/zstd/include/zstd_compat_wrapper.h -Wp,-w
+%.$(OBJEXT): CFLAGS += -fno-tree-vectorize -include $(top_srcdir)/module/zstd/include/zstd_compat_wrapper.h -Wp,-w
+%.l$(OBJEXT): CFLAGS += -fno-tree-vectorize -include $(top_srcdir)/module/zstd/include/zstd_compat_wrapper.h -Wp,-w
zfs_zstd.$(OBJEXT): CFLAGS += -include $(top_srcdir)/module/zstd/include/zstd_compat_wrapper.h
zfs_zstd.l$(OBJEXT): CFLAGS += -include $(top_srcdir)/module/zstd/include/zstd_compat_wrapper.h
diff --git a/sys/contrib/openzfs/lib/libzutil/Makefile.am b/sys/contrib/openzfs/lib/libzutil/Makefile.am
index b163250619ba..4f2dbc62bc0f 100644
--- a/sys/contrib/openzfs/lib/libzutil/Makefile.am
+++ b/sys/contrib/openzfs/lib/libzutil/Makefile.am
@@ -1,7 +1,5 @@
include $(top_srcdir)/config/Rules.am
-# Suppress unused but set variable warnings often due to ASSERTs
-AM_CFLAGS += $(NO_UNUSED_BUT_SET_VARIABLE)
AM_CFLAGS += $(LIBBLKID_CFLAGS) $(LIBUDEV_CFLAGS)
AM_CFLAGS += -fvisibility=hidden
diff --git a/sys/contrib/openzfs/lib/libzutil/os/linux/zutil_device_path_os.c b/sys/contrib/openzfs/lib/libzutil/os/linux/zutil_device_path_os.c
index 17247233bcf2..c4a36549dfff 100644
--- a/sys/contrib/openzfs/lib/libzutil/os/linux/zutil_device_path_os.c
+++ b/sys/contrib/openzfs/lib/libzutil/os/linux/zutil_device_path_os.c
@@ -527,7 +527,7 @@ zfs_dev_is_dm(const char *dev_name)
boolean_t
zfs_dev_is_whole_disk(const char *dev_name)
{
- struct dk_gpt *label;
+ struct dk_gpt *label = NULL;
int fd;
if ((fd = open(dev_name, O_RDONLY | O_DIRECT | O_CLOEXEC)) < 0)
@@ -613,22 +613,27 @@ zfs_get_underlying_path(const char *dev_name)
/*
* A disk is considered a multipath whole disk when:
* DEVNAME key value has "dm-"
- * DM_NAME key value has "mpath" prefix
+ * MPATH_DEVICE_READY is present
* DM_UUID key exists
* ID_PART_TABLE_TYPE key does not exist or is not gpt
+ * ID_FS_LABEL key does not exist (disk isn't labeled)
*/
static boolean_t
-udev_mpath_whole_disk(struct udev_device *dev)
+is_mpath_udev_sane(struct udev_device *dev)
{
- const char *devname, *type, *uuid;
+ const char *devname, *type, *uuid, *label, *mpath_ready;
devname = udev_device_get_property_value(dev, "DEVNAME");
type = udev_device_get_property_value(dev, "ID_PART_TABLE_TYPE");
uuid = udev_device_get_property_value(dev, "DM_UUID");
+ label = udev_device_get_property_value(dev, "ID_FS_LABEL");
+ mpath_ready = udev_device_get_property_value(dev, "MPATH_DEVICE_READY");
if ((devname != NULL && strncmp(devname, "/dev/dm-", 8) == 0) &&
((type == NULL) || (strcmp(type, "gpt") != 0)) &&
- (uuid != NULL)) {
+ (uuid != NULL) &&
+ (label == NULL) &&
+ (mpath_ready != NULL && strncmp(mpath_ready, "1", 1) == 0)) {
return (B_TRUE);
}
@@ -636,7 +641,11 @@ udev_mpath_whole_disk(struct udev_device *dev)
}
/*
- * Check if a disk is effectively a multipath whole disk
+ * Check if a disk is a multipath "blank" disk:
+ *
+ * 1. The disk has udev values that suggest it's a multipath disk
+ * 2. The disk is not currently labeled with a filesystem of any type
+ * 3. There are no partitions on the disk
*/
boolean_t
is_mpath_whole_disk(const char *path)
@@ -645,7 +654,6 @@ is_mpath_whole_disk(const char *path)
struct udev_device *dev = NULL;
char nodepath[MAXPATHLEN];
char *sysname;
- boolean_t wholedisk = B_FALSE;
if (realpath(path, nodepath) == NULL)
return (B_FALSE);
@@ -660,10 +668,11 @@ is_mpath_whole_disk(const char *path)
return (B_FALSE);
}
- wholedisk = udev_mpath_whole_disk(dev);
-
+ /* Sanity check some udev values */
+ boolean_t is_sane = is_mpath_udev_sane(dev);
udev_device_unref(dev);
- return (wholedisk);
+
+ return (is_sane);
}
#else /* HAVE_LIBUDEV */
diff --git a/sys/contrib/openzfs/lib/libzutil/os/linux/zutil_import_os.c b/sys/contrib/openzfs/lib/libzutil/os/linux/zutil_import_os.c
index 60d3369c9c45..0493e897bbe8 100644
--- a/sys/contrib/openzfs/lib/libzutil/os/linux/zutil_import_os.c
+++ b/sys/contrib/openzfs/lib/libzutil/os/linux/zutil_import_os.c
@@ -754,6 +754,9 @@ no_dev:
return (ret);
#else
+ (void) path;
+ (void) ds;
+ (void) wholedisk;
return (ENOENT);
#endif
}
diff --git a/sys/contrib/openzfs/lib/libzutil/zutil_import.c b/sys/contrib/openzfs/lib/libzutil/zutil_import.c
index 8876e7a7aa10..d7547c4249ea 100644
--- a/sys/contrib/openzfs/lib/libzutil/zutil_import.c
+++ b/sys/contrib/openzfs/lib/libzutil/zutil_import.c
@@ -1032,11 +1032,11 @@ zpool_read_label(int fd, nvlist_t **config, int *num_labels)
// This shouldn't be possible to
// encounter, die if we do.
ASSERT(B_FALSE);
- fallthrough;
+ zfs_fallthrough;
case EOPNOTSUPP:
case ENOSYS:
do_slow = B_TRUE;
- fallthrough;
+ zfs_fallthrough;
case 0:
default:
(void) aio_return(&aiocbs[l]);
diff --git a/sys/contrib/openzfs/man/man1/raidz_test.1 b/sys/contrib/openzfs/man/man1/raidz_test.1
index 4283a4b527f3..5281d2b86db9 100644
--- a/sys/contrib/openzfs/man/man1/raidz_test.1
+++ b/sys/contrib/openzfs/man/man1/raidz_test.1
@@ -40,7 +40,7 @@
The purpose of this tool is to run all supported raidz implementation and verify
the results of all methods.
It also contains a parameter sweep option where all
-parameters affecting a RAIDZ block are verified (like ashift size, data offset,
+parameters affecting a RAID-Z block are verified (like ashift size, data offset,
data size, etc.).
The tool also supports a benchmarking mode using the
.Fl B
diff --git a/sys/contrib/openzfs/man/man4/zfs.4 b/sys/contrib/openzfs/man/man4/zfs.4
index b2e850f840a1..01e9c5de445d 100644
--- a/sys/contrib/openzfs/man/man4/zfs.4
+++ b/sys/contrib/openzfs/man/man4/zfs.4
@@ -880,7 +880,7 @@ is set, then the deadman behavior is invoked as described by
.Sy zfs_deadman_failmode .
By default, the deadman is enabled and set to
.Sy wait
-which results in "hung" I/Os only being logged.
+which results in "hung" I/O operations only being logged.
The deadman is automatically disabled when a pool gets suspended.
.
.It Sy zfs_deadman_failmode Ns = Ns Sy wait Pq charp
@@ -964,7 +964,7 @@ will result in objects waiting when there is not actually contention on the
same object.
.
.It Sy zfs_slow_io_events_per_second Ns = Ns Sy 20 Ns /s Pq int
-Rate limit delay and deadman zevents (which report slow I/Os) to this many per
+Rate limit delay and deadman zevents (which report slow I/O operations) to this many per
second.
.
.It Sy zfs_unflushed_max_mem_amt Ns = Ns Sy 1073741824 Ns B Po 1GB Pc Pq ulong
@@ -990,7 +990,7 @@ This tunable is important because it involves a trade-off between import
time after an unclean export and the frequency of flushing metaslabs.
The higher this number is, the more log blocks we allow when the pool is
active which means that we flush metaslabs less often and thus decrease
-the number of I/Os for spacemap updates per TXG.
+the number of I/O operations for spacemap updates per TXG.
At the same time though, that means that in the event of an unclean export,
there will be more log spacemap blocks for us to read, inducing overhead
in the import time of the pool.
@@ -1087,7 +1087,8 @@ This should be less than
.It Sy zfs_wrlog_data_max Ns = Pq int
The upper limit of write-transaction zil log data size in bytes.
Once it is reached, write operation is blocked, until log data is cleared out
-after transaction group sync. Because of some overhead, it should be set
+after transaction group sync.
+Because of some overhead, it should be set
at least 2 times the size of
.Sy zfs_dirty_data_max
.No to prevent harming normal write throughput.
@@ -1622,8 +1623,8 @@ After this threshold is crossed, additional frees will wait until the next TXG.
.
.It Sy zfs_prefetch_disable Ns = Ns Sy 0 Ns | Ns 1 Pq int
Disable predictive prefetch.
-Note that it leaves "prescient" prefetch (for. e.g.\&
-.Nm zfs Cm send )
+Note that it leaves "prescient" prefetch
+.Pq for, e.g., Nm zfs Cm send
intact.
Unlike predictive prefetch, prescient prefetch never issues I/O
that ends up not being needed, so it can't hurt performance.
@@ -1683,8 +1684,8 @@ This should only be used as a last resort,
as it typically results in leaked space, or worse.
.
.It Sy zfs_removal_ignore_errors Ns = Ns Sy 0 Ns | Ns 1 Pq int
-Ignore hard IO errors during device removal.
-When set, if a device encounters a hard IO error during the removal process
+Ignore hard I/O errors during device removal.
+When set, if a device encounters a hard I/O error during the removal process
the removal will not be cancelled.
This can result in a normally recoverable block becoming permanently damaged
and is hence not recommended.
@@ -1948,7 +1949,7 @@ Historical statistics for this many latest TXGs will be available in
Flush dirty data to disk at least every this many seconds (maximum TXG duration).
.
.It Sy zfs_vdev_aggregate_trim Ns = Ns Sy 0 Ns | Ns 1 Pq int
-Allow TRIM I/Os to be aggregated.
+Allow TRIM I/O operations to be aggregated.
This is normally not helpful because the extents to be trimmed
will have been already been aggregated by the metaslab.
This option is provided for debugging and performance analysis.
@@ -2098,6 +2099,16 @@ Limit SLOG write size per commit executed with synchronous priority.
Any writes above that will be executed with lower (asynchronous) priority
to limit potential SLOG device abuse by single active ZIL writer.
.
+.It Sy zfs_zil_saxattr Ns = Ns Sy 1 Ns | Ns 0 Pq int
+Setting this tunable to zero disables ZIL logging of new
+.Sy xattr Ns = Ns Sy sa
+records if the
+.Sy org.openzfs:zilsaxattr
+feature is enabled on the pool.
+This would only be necessary to work around bugs in the ZIL logging or replay
+code for this record type.
+The tunable has no effect if the feature is disabled.
+.
.It Sy zfs_embedded_slog_min_ms Ns = Ns Sy 64 Pq int
Usually, one metaslab from each normal-class vdev is dedicated for use by
the ZIL to log synchronous writes.
@@ -2129,6 +2140,30 @@ When enabled, the maximum number of pending allocations per top-level vdev
is limited by
.Sy zfs_vdev_queue_depth_pct .
.
+.It Sy zfs_xattr_compat Ns = Ns 0 Ns | Ns 1 Pq int
+Control the naming scheme used when setting new xattrs in the user namespace.
+If
+.Sy 0
+.Pq the default on Linux ,
+user namespace xattr names are prefixed with the namespace, to be backwards
+compatible with previous versions of ZFS on Linux.
+If
+.Sy 1
+.Pq the default on Fx ,
+user namespace xattr names are not prefixed, to be backwards compatible with
+previous versions of ZFS on illumos and
+.Fx .
+.Pp
+Either naming scheme can be read on this and future versions of ZFS, regardless
+of this tunable, but legacy ZFS on illumos or
+.Fx
+are unable to read user namespace xattrs written in the Linux format, and
+legacy versions of ZFS on Linux are unable to read user namespace xattrs written
+in the legacy ZFS format.
+.Pp
+An existing xattr with the alternate naming scheme is removed when overwriting
+the xattr so as to not accumulate duplicates.
+.
.It Sy zio_requeue_io_start_cut_in_line Ns = Ns Sy 0 Ns | Ns 1 Pq int
Prioritize requeued I/O.
.
diff --git a/sys/contrib/openzfs/man/man7/zfsconcepts.7 b/sys/contrib/openzfs/man/man7/zfsconcepts.7
index f958035f72df..0e5b21d54c78 100644
--- a/sys/contrib/openzfs/man/man7/zfsconcepts.7
+++ b/sys/contrib/openzfs/man/man7/zfsconcepts.7
@@ -193,10 +193,10 @@ Calculating the exact requirement depends heavily
on the type of data stored in the pool.
.Pp
Enabling deduplication on an improperly-designed system can result in
-performance issues (slow IO and administrative operations).
+performance issues (slow I/O and administrative operations).
It can potentially lead to problems importing a pool due to memory exhaustion.
Deduplication can consume significant processing power (CPU) and memory as well
-as generate additional disk IO.
+as generate additional disk I/O.
.Pp
Before creating a pool with deduplication enabled, ensure that you have planned
your hardware requirements appropriately and implemented appropriate recovery
diff --git a/sys/contrib/openzfs/man/man7/zfsprops.7 b/sys/contrib/openzfs/man/man7/zfsprops.7
index c6aa8daa964f..0976e80d7309 100644
--- a/sys/contrib/openzfs/man/man7/zfsprops.7
+++ b/sys/contrib/openzfs/man/man7/zfsprops.7
@@ -784,9 +784,9 @@ Changing this property affects only newly-written data.
.Xc
Controls the compression algorithm used for this dataset.
.Pp
-Setting compression to
+When set to
.Sy on
-indicates that the current default compression algorithm should be used.
+(the default), indicates that the current default compression algorithm should be used.
The default balances compression and decompression speed, with compression ratio
and is expected to work well on a wide variety of workloads.
Unlike all other settings for this property,
@@ -1610,8 +1610,11 @@ the file systems are unshared.
.Pp
The share is created with the ACL (Access Control List) "Everyone:F" ("F"
stands for "full permissions", i.e. read and write permissions) and no guest
-access (which means Samba must be able to authenticate a real user, system
-passwd/shadow, LDAP or smbpasswd based) by default.
+access (which means Samba must be able to authenticate a real user \(em
+.Xr passwd 5 Ns / Ns Xr shadow 5 Ns - ,
+LDAP- or
+.Xr smbpasswd 5 Ns -based )
+by default.
This means that any additional access control
(disallow specific user specific access etc) must be done on the underlying file system.
.It Sy sharenfs Ns = Ns Sy on Ns | Ns Sy off Ns | Ns Ar opts
@@ -1816,31 +1819,34 @@ The default value is
This property is not used by OpenZFS.
.It Sy xattr Ns = Ns Sy on Ns | Ns Sy off Ns | Ns Sy sa
Controls whether extended attributes are enabled for this file system.
-Two styles of extended attributes are supported: either directory based
-or system attribute based.
+Two styles of extended attributes are supported: either directory-based
+or system-attribute-based.
.Pp
The default value of
.Sy on
-enables directory based extended attributes.
+enables directory-based extended attributes.
This style of extended attribute imposes no practical limit
on either the size or number of attributes which can be set on a file.
Although under Linux the
.Xr getxattr 2
and
.Xr setxattr 2
-system calls limit the maximum size to 64K.
+system calls limit the maximum size to
+.Sy 64K .
This is the most compatible
style of extended attribute and is supported by all ZFS implementations.
.Pp
-System attribute based xattrs can be enabled by setting the value to
+System-attribute-based xattrs can be enabled by setting the value to
.Sy sa .
The key advantage of this type of xattr is improved performance.
Storing extended attributes as system attributes
-significantly decreases the amount of disk IO required.
-Up to 64K of data may be stored per-file in the space reserved for system attributes.
+significantly decreases the amount of disk I/O required.
+Up to
+.Sy 64K
+of data may be stored per-file in the space reserved for system attributes.
If there is not enough space available for an extended attribute
-then it will be automatically written as a directory based xattr.
-System attribute based extended attributes are not accessible
+then it will be automatically written as a directory-based xattr.
+System-attribute-based extended attributes are not accessible
on platforms which do not support the
.Sy xattr Ns = Ns Sy sa
feature.
@@ -1850,7 +1856,7 @@ on both
.Fx
and Linux.
.Pp
-The use of system attribute based xattrs is strongly encouraged for users of
+The use of system-attribute-based xattrs is strongly encouraged for users of
SELinux or POSIX ACLs.
Both of these features heavily rely on extended
attributes and benefit significantly from the reduced access time.
diff --git a/sys/contrib/openzfs/man/man7/zpool-features.7 b/sys/contrib/openzfs/man/man7/zpool-features.7
index d10ca7f441f6..9a202ca8a596 100644
--- a/sys/contrib/openzfs/man/man7/zpool-features.7
+++ b/sys/contrib/openzfs/man/man7/zpool-features.7
@@ -403,8 +403,8 @@ on a top-level vdev, and will never return to being
This feature enables use of the
.Sy draid
vdev type.
-dRAID is a variant of raidz which provides integrated distributed
-hot spares that allow faster resilvering while retaining the benefits of raidz.
+dRAID is a variant of RAID-Z which provides integrated distributed
+hot spares that allow faster resilvering while retaining the benefits of RAID-Z.
Data, parity, and spare space are organized in redundancy groups
and distributed evenly over all of the devices.
.Pp
@@ -474,8 +474,7 @@ This has no user-visible impact, but other features may depend on this feature.
.Pp
This feature becomes
.Sy active
- as soon as it is enabled and will
-never return to being
+as soon as it is enabled and will never return to being
.Sy enabled .
.
.feature com.datto encryption no bookmark_v2 extensible_dataset
@@ -504,8 +503,9 @@ can be created at the point in the tree on which the limits are set.
.Pp
This feature is
.Sy active
-once either of the limit properties has been set on a dataset.
-Once activated the feature is never deactivated.
+once either of the limit properties has been set on a dataset
+and will never return to being
+.Sy enabled .
.
.feature com.delphix hole_birth no enabled_txg
This feature has/had bugs, the result of which is that, if you do a
@@ -700,8 +700,8 @@ For more information about redacted sends, see
.
.feature com.delphix redacted_datasets no extensible_dataset
This feature enables the receiving of redacted
-.Nm zfs Cm send Ns
-streams. which create redacted datasets when received.
+.Nm zfs Cm send
+streams, which create redacted datasets when received.
These datasets are missing some of their blocks,
and so cannot be safely mounted, and their contents cannot be safely read.
For more information about redacted receives, see
@@ -778,6 +778,24 @@ by user and group.
\*[instant-never]
\*[remount-upgrade]
.
+.feature org.openzfs zilsaxattr yes extensible_dataset
+This feature enables
+.Sy xattr Ns = Ns Sy sa
+extended attribute logging in the ZIL.
+If enabled, extended attribute changes
+.Pq both Sy xattrdir Ns = Ns Sy dir No and Sy xattr Ns = Ns Sy sa
+are guaranteed to be durable if either the dataset had
+.Sy sync Ns = Ns Sy always
+set at the time the changes were made, or
+.Xr sync 2
+is called on the dataset after the changes were made.
+.Pp
+This feature becomes
+.Sy active
+when a ZIL is created for at least one dataset and will be returned to the
+.Sy enabled
+state when it is destroyed for all datasets that use this feature.
+.
.feature com.delphix zpool_checkpoint yes
This feature enables the
.Nm zpool Cm checkpoint
diff --git a/sys/contrib/openzfs/man/man7/zpoolprops.7 b/sys/contrib/openzfs/man/man7/zpoolprops.7
index 543920a1d58e..944fbf2b8d29 100644
--- a/sys/contrib/openzfs/man/man7/zpoolprops.7
+++ b/sys/contrib/openzfs/man/man7/zpoolprops.7
@@ -101,6 +101,10 @@ Over time
will decrease while
.Sy free
increases.
+.It Sy leaked
+Space not released while
+.Sy freeing
+due to corruption, now permanently leaked into the pool.
.It Sy health
The current health of the pool.
Health can be one of
@@ -184,7 +188,7 @@ layer and a ZFS internal exception list.
I/O operations will be aligned to the specified size boundaries.
Additionally, the minimum (disk)
write size will be set to the specified size, so this represents a
-space vs. performance trade-off.
+space/performance trade-off.
For optimal performance, the pool sector size should be greater than
or equal to the sector size of the underlying disks.
The typical case for setting this property is when
diff --git a/sys/contrib/openzfs/man/man8/zdb.8 b/sys/contrib/openzfs/man/man8/zdb.8
index 55c575f0db1b..902f818cc485 100644
--- a/sys/contrib/openzfs/man/man8/zdb.8
+++ b/sys/contrib/openzfs/man/man8/zdb.8
@@ -25,18 +25,18 @@
.Nm
.Op Fl AbcdDFGhikLMNPsvXYy
.Op Fl e Oo Fl V Oc Oo Fl p Ar path Oc Ns …
-.Op Fl I Ar inflight I/Os
+.Op Fl I Ar inflight-I/O-ops
.Oo Fl o Ar var Ns = Ns Ar value Oc Ns …
.Op Fl t Ar txg
.Op Fl U Ar cache
.Op Fl x Ar dumpdir
-.Op Ar poolname Ns Op / Ns Ar dataset | objset ID
+.Op Ar poolname Ns Op / Ns Ar dataset Ns | Ns Ar objset-ID
.Op Ar object Ns | Ns Ar range Ns …
.Nm
.Op Fl AdiPv
.Op Fl e Oo Fl V Oc Oo Fl p Ar path Oc Ns …
.Op Fl U Ar cache
-.Ar poolname Ns Op Ar / Ns Ar dataset | objset ID
+.Ar poolname Ns Op Ar / Ns Ar dataset Ns | Ns Ar objset-ID
.Op Ar object Ns | Ns Ar range Ns …
.Nm
.Fl C
@@ -84,7 +84,7 @@ some amount of consistency checking.
It is a not a general purpose tool and options
.Pq and facilities
may change.
-This is not a
+It is not a
.Xr fsck 8
utility.
.Pp
@@ -140,9 +140,9 @@ size, and object count.
See
.Fl N
for determining if
-.Op Ar poolname Ns Op / Ns Ar dataset | objset ID
+.Ar poolname Ns Op / Ns Ar dataset Ns | Ns Ar objset-ID
is to use the specified
-.Op Ar dataset | objset ID
+.Ar dataset Ns | Ns Ar objset-ID
as a string (dataset name) or a number (objset ID) when
datasets have numeric names.
.Pp
@@ -198,7 +198,7 @@ compression ratio
inflation due to the zfs copies property
.Pq Sy copies ,
and an overall effective ratio
-.Pq Sy dedup No * Sy compress No / Sy copies .
+.Pq Sy dedup No \(mu Sy compress No / Sy copies .
.It Fl DD
Display a histogram of deduplication statistics, showing the allocated
.Pq physically present on disk
@@ -287,9 +287,9 @@ Display every spacemap record.
Same as
.Fl d
but force zdb to interpret the
-.Op Ar dataset | objset ID
+.Op Ar dataset Ns | Ns Ar objset-ID
in
-.Op Ar poolname Ns Op / Ns Ar dataset | objset ID
+.Op Ar poolname Ns Op / Ns Ar dataset Ns | Ns Ar objset-ID
as a numeric objset ID.
.It Fl O Ar dataset path
Look up the specified
@@ -404,13 +404,13 @@ transactions.
Dump the contents of the zfs_dbgmsg buffer before exiting
.Nm .
zfs_dbgmsg is a buffer used by ZFS to dump advanced debug information.
-.It Fl I , -inflight Ns = Ns Ar inflight I/Os
-Limit the number of outstanding checksum I/Os to the specified value.
+.It Fl I , -inflight Ns = Ns Ar inflight-I/O-ops
+Limit the number of outstanding checksum I/O operations to the specified value.
The default value is 200.
This option affects the performance of the
.Fl c
option.
-.It Fl o , -option Ns = Ns Ar var Ns = Ns Ar value …
+.It Fl o , -option Ns = Ns Ar var Ns = Ns Ar value Ns …
Set the given global libzpool variable to the provided value.
The value must be an unsigned 32-bit integer.
Currently only little-endian systems are supported to avoid accidentally setting
diff --git a/sys/contrib/openzfs/man/man8/zfs-project.8 b/sys/contrib/openzfs/man/man8/zfs-project.8
index f264a110fc00..0edaad0820d7 100644
--- a/sys/contrib/openzfs/man/man8/zfs-project.8
+++ b/sys/contrib/openzfs/man/man8/zfs-project.8
@@ -104,7 +104,7 @@ target directory's project ID or the one specified with
.Fl p .
.Bl -tag -width "-p id"
.It Fl 0
-Delimit filenames with a NUL byte instead of newline.
+Delimit filenames with a NUL byte instead of newline, don't output diagnoses.
.It Fl d
Check the directory project ID and inherit flag, not its children.
.It Fl p Ar id
diff --git a/sys/contrib/openzfs/man/man8/zfs-receive.8 b/sys/contrib/openzfs/man/man8/zfs-receive.8
index 84ec657e5cd6..fc1e943bd61b 100644
--- a/sys/contrib/openzfs/man/man8/zfs-receive.8
+++ b/sys/contrib/openzfs/man/man8/zfs-receive.8
@@ -319,7 +319,7 @@ received as an encryption root, specify encryption properties in the same
manner as is required for
.Nm zfs Cm create .
For instance:
-.Dl # Nm zfs Cm send Pa tank/test@snap1 | Nm zfs Cm recv Fl o Sy encryption Ns = Ns Sy on Fl o keyformat=passphrase Fl o Sy keylocation Ns = Ns Pa file:///path/to/keyfile
+.Dl # Nm zfs Cm send Pa tank/test@snap1 | Nm zfs Cm recv Fl o Sy encryption Ns = Ns Sy on Fl o Sy keyformat Ns = Ns Sy passphrase Fl o Sy keylocation Ns = Ns Pa file:///path/to/keyfile
.Pp
Note that
.Fl o Sy keylocation Ns = Ns Sy prompt
@@ -329,7 +329,7 @@ Once the receive has completed, you can use
.Nm zfs Cm set
to change this setting after the fact.
Similarly, you can receive a dataset as an encrypted child by specifying
-.Op Fl x Ar encryption
+.Fl x Sy encryption
to force the property to be inherited.
Overriding encryption properties (except for
.Sy keylocation )
diff --git a/sys/contrib/openzfs/man/man8/zinject.8 b/sys/contrib/openzfs/man/man8/zinject.8
index a29346929988..1cd8aa85e3cd 100644
--- a/sys/contrib/openzfs/man/man8/zinject.8
+++ b/sys/contrib/openzfs/man/man8/zinject.8
@@ -71,18 +71,18 @@ Force a vdev into the DEGRADED or FAULTED state.
.Fl D Ar latency : Ns Ar lanes
.Ar pool
.Xc
-Add an artificial delay to IO requests on a particular
+Add an artificial delay to I/O requests on a particular
device, such that the requests take a minimum of
.Ar latency
milliseconds to complete.
Each delay has an associated number of
.Ar lanes
which defines the number of concurrent
-IO requests that can be processed.
+I/O requests that can be processed.
.Pp
For example, with a single lane delay of 10 ms
.No (\& Ns Fl D Ar 10 : Ns Ar 1 ) ,
-the device will only be able to service a single IO request
+the device will only be able to service a single I/O request
at a time with each request taking 10 ms to complete.
So, if only a single request is submitted every 10 ms, the
average latency will be 10 ms; but if more than one request
@@ -188,7 +188,7 @@ Each number is in hexadecimal, and only one block can be specified.
.It Fl C Ar dvas
Inject the given error only into specific DVAs.
The mask should be specified as a list of 0-indexed DVAs separated by commas
-.No (ex. Ar 0,2 Ns No ).
+.No (e.g. Ar 0,2 Ns No ).
This option is not applicable to logical data errors such as
.Sy decompress
and
diff --git a/sys/contrib/openzfs/man/man8/zpool-import.8 b/sys/contrib/openzfs/man/man8/zpool-import.8
index 518e3cf1d76a..39b0e17ef586 100644
--- a/sys/contrib/openzfs/man/man8/zpool-import.8
+++ b/sys/contrib/openzfs/man/man8/zpool-import.8
@@ -386,13 +386,14 @@ For more details
about pool recovery mode, see the
.Fl X
option, above.
-WARNING: This option can be extremely hazardous to the
+.Em WARNING :
+This option can be extremely hazardous to the
health of your pool and should only be used as a last resort.
.It Fl t
Used with
-.Sy newpool .
+.Ar newpool .
Specifies that
-.Sy newpool
+.Ar newpool
is temporary.
Temporary pool names last until export.
Ensures that the original pool name will be used
diff --git a/sys/contrib/openzfs/man/man8/zpool-labelclear.8 b/sys/contrib/openzfs/man/man8/zpool-labelclear.8
index c7edc911604d..912adb0700a7 100644
--- a/sys/contrib/openzfs/man/man8/zpool-labelclear.8
+++ b/sys/contrib/openzfs/man/man8/zpool-labelclear.8
@@ -45,7 +45,8 @@ Removes ZFS label information from the specified
If the
.Ar device
is a cache device, it also removes the L2ARC header
-(persistent L2ARC). The
+(persistent L2ARC).
+The
.Ar device
must not be part of an active pool configuration.
.Bl -tag -width Ds
diff --git a/sys/contrib/openzfs/man/man8/zpool-remove.8 b/sys/contrib/openzfs/man/man8/zpool-remove.8
index a14218ee17fd..2e1bfec3fa65 100644
--- a/sys/contrib/openzfs/man/man8/zpool-remove.8
+++ b/sys/contrib/openzfs/man/man8/zpool-remove.8
@@ -66,7 +66,7 @@ command initiates the removal and returns, while the evacuation continues in
the background.
The removal progress can be monitored with
.Nm zpool Cm status .
-If an IO error is encountered during the removal process it will be cancelled.
+If an I/O error is encountered during the removal process it will be cancelled.
The
.Sy device_removal
feature flag must be enabled to remove a top-level vdev, see
diff --git a/sys/contrib/openzfs/man/man8/zpool-status.8 b/sys/contrib/openzfs/man/man8/zpool-status.8
index 7c825f69d8e2..1b7c3515bd0a 100644
--- a/sys/contrib/openzfs/man/man8/zpool-status.8
+++ b/sys/contrib/openzfs/man/man8/zpool-status.8
@@ -93,12 +93,12 @@ and referenced
.Pq logically referenced in the pool
block counts and sizes by reference count.
.It Fl s
-Display the number of leaf VDEV slow IOs.
-This is the number of IOs that
-didn't complete in
+Display the number of leaf vdev slow I/O operations.
+This is the number of I/O operations that didn't complete in
.Sy zio_slow_io_ms
-milliseconds (default 30 seconds).
-This does not necessarily mean the IOs failed to complete, just took an
+milliseconds
+.Pq Sy 30000 No by default .
+This does not necessarily mean the I/O operations failed to complete, just took an
unreasonably long amount of time.
This may indicate a problem with the underlying storage.
.It Fl t
diff --git a/sys/contrib/openzfs/man/man8/zpool.8 b/sys/contrib/openzfs/man/man8/zpool.8
index e2de528a301f..3e71e65ab7d7 100644
--- a/sys/contrib/openzfs/man/man8/zpool.8
+++ b/sys/contrib/openzfs/man/man8/zpool.8
@@ -148,8 +148,8 @@ for the specified storage pool(s).
.It Xr zpool-status 8
Displays the detailed health status for the given pools.
.It Xr zpool-iostat 8
-Displays logical I/O statistics for the given pools/vdevs. Physical I/Os may
-be observed via
+Displays logical I/O statistics for the given pools/vdevs.
+Physical I/O operations may be observed via
.Xr iostat 1 .
.It Xr zpool-events 8
Lists all recent events generated by the ZFS kernel modules.
@@ -474,7 +474,7 @@ This behavior is identical to the
command line option.
.It Sy ZFS_VDEV_DEVID_OPT_OUT
Older OpenZFS implementations had issues when attempting to display pool
-config VDEV names if a
+config vdev names if a
.Sy devid
NVP value is present in the pool's config.
.Pp
diff --git a/sys/contrib/openzfs/module/Makefile.bsd b/sys/contrib/openzfs/module/Makefile.bsd
index 5172394e6ac8..695b6630ae24 100644
--- a/sys/contrib/openzfs/module/Makefile.bsd
+++ b/sys/contrib/openzfs/module/Makefile.bsd
@@ -19,7 +19,9 @@ KMOD= openzfs
${SRCDIR}/zcommon \
${SRCDIR}/zfs \
${SRCDIR}/zstd \
- ${SRCDIR}/zstd/lib
+ ${SRCDIR}/zstd/lib/common \
+ ${SRCDIR}/zstd/lib/compress \
+ ${SRCDIR}/zstd/lib/decompress
@@ -313,7 +315,29 @@ SRCS+= abd.c \
#zstd
SRCS+= zfs_zstd.c \
- zstd.c
+ entropy_common.c \
+ error_private.c \
+ fse_decompress.c \
+ pool.c \
+ zstd_common.c \
+ fse_compress.c \
+ hist.c \
+ huf_compress.c \
+ zstd_compress.c \
+ zstd_compress_literals.c \
+ zstd_compress_sequences.c \
+ zstd_compress_superblock.c \
+ zstd_double_fast.c \
+ zstd_fast.c \
+ zstd_lazy.c \
+ zstd_ldm.c \
+ zstd_opt.c \
+ huf_decompress.c \
+ zstd_ddict.c \
+ zstd_decompress.c \
+ zstd_decompress_block.c
+
+
beforeinstall:
.if ${MK_DEBUG_FILES} != "no"
@@ -373,4 +397,25 @@ CFLAGS.zil.c= -Wno-cast-qual
CFLAGS.zio.c= -Wno-cast-qual
CFLAGS.zrlock.c= -Wno-cast-qual
CFLAGS.zfs_zstd.c= -Wno-cast-qual -Wno-pointer-arith
-CFLAGS.zstd.c= -fno-tree-vectorize -U__BMI__
+CFLAGS.entropy_common.c= -fno-tree-vectorize -U__BMI__
+CFLAGS.error_private.c= -fno-tree-vectorize -U__BMI__
+CFLAGS.fse_decompress.c= -fno-tree-vectorize -U__BMI__
+CFLAGS.pool.c= -fno-tree-vectorize -U__BMI__
+CFLAGS.xxhash.c= -fno-tree-vectorize -U__BMI__
+CFLAGS.zstd_common.c= -fno-tree-vectorize -U__BMI__
+CFLAGS.fse_compress.c= -fno-tree-vectorize -U__BMI__
+CFLAGS.hist.c= -fno-tree-vectorize -U__BMI__
+CFLAGS.huf_compress.c= -fno-tree-vectorize -U__BMI__
+CFLAGS.zstd_compress.c= -fno-tree-vectorize -U__BMI__
+CFLAGS.zstd_compress_literals.c= -fno-tree-vectorize -U__BMI__
+CFLAGS.zstd_compress_sequences.c= -fno-tree-vectorize -U__BMI__
+CFLAGS.zstd_compress_superblock.c= -fno-tree-vectorize -U__BMI__
+CFLAGS.zstd_double_fast.c= -fno-tree-vectorize -U__BMI__
+CFLAGS.zstd_fast.c= -fno-tree-vectorize -U__BMI__
+CFLAGS.zstd_lazy.c= -fno-tree-vectorize -U__BMI__
+CFLAGS.zstd_ldm.c= -fno-tree-vectorize -U__BMI__
+CFLAGS.zstd_opt.c= -fno-tree-vectorize -U__BMI__
+CFLAGS.huf_decompress.c= -fno-tree-vectorize -U__BMI__
+CFLAGS.zstd_ddict.c= -fno-tree-vectorize -U__BMI__
+CFLAGS.zstd_decompress.c= -fno-tree-vectorize -U__BMI__
+CFLAGS.zstd_decompress_block.c= -fno-tree-vectorize -U__BMI__
diff --git a/sys/contrib/openzfs/module/Makefile.in b/sys/contrib/openzfs/module/Makefile.in
index 0dd9df501782..762f9394dd20 100644
--- a/sys/contrib/openzfs/module/Makefile.in
+++ b/sys/contrib/openzfs/module/Makefile.in
@@ -52,7 +52,9 @@ FMAKE = env -u MAKEFLAGS make $(FMAKEFLAGS)
modules-Linux:
list='$(SUBDIR_TARGETS)'; for td in $$list; do $(MAKE) -C $$td; done
- $(MAKE) -C @LINUX_OBJ@ M="$$PWD" @KERNEL_MAKE@ CONFIG_ZFS=m modules
+ $(MAKE) -C @LINUX_OBJ@ $(if @KERNEL_CC@,CC=@KERNEL_CC@) \
+ $(if @KERNEL_LD@,LD=@KERNEL_LD@) $(if @KERNEL_LLVM@,LLVM=@KERNEL_LLVM@) \
+ M="$$PWD" @KERNEL_MAKE@ CONFIG_ZFS=m modules
modules-FreeBSD:
+$(FMAKE)
@@ -67,10 +69,8 @@ clean-Linux:
@# is defined. This indicates that kernel modules should be built.
@CONFIG_KERNEL_TRUE@ $(MAKE) -C @LINUX_OBJ@ M="$$PWD" @KERNEL_MAKE@ clean
- if [ -f @LINUX_SYMBOLS@ ]; then $(RM) @LINUX_SYMBOLS@; fi
- if [ -f Module.markers ]; then $(RM) Module.markers; fi
-
- find . -name '*.ur-safe' -type f -print | xargs $(RM)
+ $(RM) @LINUX_SYMBOLS@ Module.markers
+ find . -name '*.ur-safe' -type f -delete
clean-FreeBSD:
+$(FMAKE) clean
@@ -86,7 +86,7 @@ modules_install-Linux:
@# Remove extraneous build products when packaging
kmoddir=$(INSTALL_MOD_PATH)/lib/modules/@LINUX_VERSION@; \
if [ -n "$(DESTDIR)" ]; then \
- find $$kmoddir -name 'modules.*' | xargs $(RM); \
+ find $$kmoddir -name 'modules.*' -delete; \
fi
@# Debian ships tiny fake System.map files that are
@# syntactically valid but just say
@@ -128,6 +128,7 @@ cppcheck-Linux:
--include=@LINUX_OBJ@/include/generated/autoconf.h \
--include=@top_srcdir@/zfs_config.h \
--config-exclude=@LINUX_OBJ@/include \
+ -i zstd/lib \
-I @LINUX_OBJ@/include \
-I @top_srcdir@/include/os/linux/kernel \
-I @top_srcdir@/include/os/linux/spl \
diff --git a/sys/contrib/openzfs/module/avl/avl.c b/sys/contrib/openzfs/module/avl/avl.c
index c86dc9835a54..3891a2d62880 100644
--- a/sys/contrib/openzfs/module/avl/avl.c
+++ b/sys/contrib/openzfs/module/avl/avl.c
@@ -319,7 +319,6 @@ avl_rotation(avl_tree_t *tree, avl_node_t *node, int balance)
int which_child = AVL_XCHILD(node);
int child_bal = AVL_XBALANCE(child);
- /* BEGIN CSTYLED */
/*
* case 1 : node is overly left heavy, the left child is balanced or
* also left heavy. This requires the following rotation.
@@ -345,7 +344,6 @@ avl_rotation(avl_tree_t *tree, avl_node_t *node, int balance)
* we detect this situation by noting that child's balance is not
* right_heavy.
*/
- /* END CSTYLED */
if (child_bal != right_heavy) {
/*
@@ -388,7 +386,6 @@ avl_rotation(avl_tree_t *tree, avl_node_t *node, int balance)
return (child_bal == 0);
}
- /* BEGIN CSTYLED */
/*
* case 2 : When node is left heavy, but child is right heavy we use
* a different rotation.
@@ -420,7 +417,6 @@ avl_rotation(avl_tree_t *tree, avl_node_t *node, int balance)
* if gchild was right_heavy, then child is now left heavy
* else it is balanced
*/
- /* END CSTYLED */
gchild = child->avl_child[right];
gleft = gchild->avl_child[left];
gright = gchild->avl_child[right];
diff --git a/sys/contrib/openzfs/module/icp/Makefile.in b/sys/contrib/openzfs/module/icp/Makefile.in
index f51fcac6d9e1..72c9ab12adb7 100644
--- a/sys/contrib/openzfs/module/icp/Makefile.in
+++ b/sys/contrib/openzfs/module/icp/Makefile.in
@@ -15,9 +15,7 @@ ccflags-y := -I$(icp_include)
$(MODULE)-objs += illumos-crypto.o
$(MODULE)-objs += api/kcf_cipher.o
-$(MODULE)-objs += api/kcf_digest.o
$(MODULE)-objs += api/kcf_mac.o
-$(MODULE)-objs += api/kcf_miscapi.o
$(MODULE)-objs += api/kcf_ctxops.o
$(MODULE)-objs += core/kcf_callprov.o
$(MODULE)-objs += core/kcf_prov_tabs.o
@@ -28,7 +26,6 @@ $(MODULE)-objs += spi/kcf_spi.o
$(MODULE)-objs += io/aes.o
$(MODULE)-objs += io/sha2_mod.o
$(MODULE)-objs += io/skein_mod.o
-$(MODULE)-objs += os/modhash.o
$(MODULE)-objs += algs/modes/cbc.o
$(MODULE)-objs += algs/modes/ccm.o
$(MODULE)-objs += algs/modes/ctr.o
diff --git a/sys/contrib/openzfs/module/icp/algs/modes/cbc.c b/sys/contrib/openzfs/module/icp/algs/modes/cbc.c
index bddb5b64ddd3..73605f04d858 100644
--- a/sys/contrib/openzfs/module/icp/algs/modes/cbc.c
+++ b/sys/contrib/openzfs/module/icp/algs/modes/cbc.c
@@ -242,19 +242,12 @@ int
cbc_init_ctx(cbc_ctx_t *cbc_ctx, char *param, size_t param_len,
size_t block_size, void (*copy_block)(uint8_t *, uint64_t *))
{
- /*
- * Copy IV into context.
- *
- * If cm_param == NULL then the IV comes from the
- * cd_miscdata field in the crypto_data structure.
- */
- if (param != NULL) {
- ASSERT(param_len == block_size);
- copy_block((uchar_t *)param, cbc_ctx->cbc_iv);
- }
+ /* Copy IV into context. */
+ ASSERT3P(param, !=, NULL);
+ ASSERT3U(param_len, ==, block_size);
+
+ copy_block((uchar_t *)param, cbc_ctx->cbc_iv);
- cbc_ctx->cbc_lastp = (uint8_t *)&cbc_ctx->cbc_iv[0];
- cbc_ctx->cbc_flags |= CBC_MODE;
return (CRYPTO_SUCCESS);
}
diff --git a/sys/contrib/openzfs/module/icp/algs/modes/gcm.c b/sys/contrib/openzfs/module/icp/algs/modes/gcm.c
index d9796cd0ed49..7d34c2b040f6 100644
--- a/sys/contrib/openzfs/module/icp/algs/modes/gcm.c
+++ b/sys/contrib/openzfs/module/icp/algs/modes/gcm.c
@@ -342,14 +342,20 @@ gcm_mode_decrypt_contiguous_blocks(gcm_ctx_t *ctx, char *data, size_t length,
*/
if (length > 0) {
new_len = ctx->gcm_pt_buf_len + length;
- new = vmem_alloc(new_len, ctx->gcm_kmflag);
+ new = vmem_alloc(new_len, KM_SLEEP);
if (new == NULL) {
vmem_free(ctx->gcm_pt_buf, ctx->gcm_pt_buf_len);
ctx->gcm_pt_buf = NULL;
return (CRYPTO_HOST_MEMORY);
}
- bcopy(ctx->gcm_pt_buf, new, ctx->gcm_pt_buf_len);
- vmem_free(ctx->gcm_pt_buf, ctx->gcm_pt_buf_len);
+
+ if (ctx->gcm_pt_buf != NULL) {
+ bcopy(ctx->gcm_pt_buf, new, ctx->gcm_pt_buf_len);
+ vmem_free(ctx->gcm_pt_buf, ctx->gcm_pt_buf_len);
+ } else {
+ ASSERT0(ctx->gcm_pt_buf_len);
+ }
+
ctx->gcm_pt_buf = new;
ctx->gcm_pt_buf_len = new_len;
bcopy(data, &ctx->gcm_pt_buf[ctx->gcm_processed_data_len],
@@ -554,8 +560,15 @@ gcm_init(gcm_ctx_t *ctx, unsigned char *iv, size_t iv_len,
* There's not a block full of data, pad rest of
* buffer with zero
*/
- bzero(authp, block_size);
- bcopy(&(auth_data[processed]), authp, remainder);
+
+ if (auth_data != NULL) {
+ bzero(authp, block_size);
+ bcopy(&(auth_data[processed]),
+ authp, remainder);
+ } else {
+ ASSERT0(remainder);
+ }
+
datap = (uint8_t *)authp;
remainder = 0;
} else {
@@ -641,7 +654,7 @@ gcm_init_ctx(gcm_ctx_t *gcm_ctx, char *param, size_t block_size,
}
gcm_ctx->gcm_htab_len = htab_len;
gcm_ctx->gcm_Htable =
- (uint64_t *)kmem_alloc(htab_len, gcm_ctx->gcm_kmflag);
+ (uint64_t *)kmem_alloc(htab_len, KM_SLEEP);
if (gcm_ctx->gcm_Htable == NULL) {
return (CRYPTO_HOST_MEMORY);
@@ -716,7 +729,7 @@ gmac_init_ctx(gcm_ctx_t *gcm_ctx, char *param, size_t block_size,
}
gcm_ctx->gcm_htab_len = htab_len;
gcm_ctx->gcm_Htable =
- (uint64_t *)kmem_alloc(htab_len, gcm_ctx->gcm_kmflag);
+ (uint64_t *)kmem_alloc(htab_len, KM_SLEEP);
if (gcm_ctx->gcm_Htable == NULL) {
return (CRYPTO_HOST_MEMORY);
@@ -767,12 +780,6 @@ gmac_alloc_ctx(int kmflag)
return (gcm_ctx);
}
-void
-gcm_set_kmflag(gcm_ctx_t *ctx, int kmflag)
-{
- ctx->gcm_kmflag = kmflag;
-}
-
/* GCM implementation that contains the fastest methods */
static gcm_impl_ops_t gcm_fastest_impl = {
.name = "fastest"
@@ -1199,7 +1206,7 @@ gcm_mode_encrypt_contiguous_blocks_avx(gcm_ctx_t *ctx, char *data,
/* Allocate a buffer to encrypt to if there is enough input. */
if (bleft >= GCM_AVX_MIN_ENCRYPT_BYTES) {
- ct_buf = vmem_alloc(chunk_size, ctx->gcm_kmflag);
+ ct_buf = vmem_alloc(chunk_size, KM_SLEEP);
if (ct_buf == NULL) {
return (CRYPTO_HOST_MEMORY);
}
diff --git a/sys/contrib/openzfs/module/icp/api/kcf_cipher.c b/sys/contrib/openzfs/module/icp/api/kcf_cipher.c
index d6aa48147edb..81c3b96b1509 100644
--- a/sys/contrib/openzfs/module/icp/api/kcf_cipher.c
+++ b/sys/contrib/openzfs/module/icp/api/kcf_cipher.c
@@ -34,253 +34,11 @@
* Encryption and decryption routines.
*/
-/*
- * The following are the possible returned values common to all the routines
- * below. The applicability of some of these return values depends on the
- * presence of the arguments.
- *
- * CRYPTO_SUCCESS: The operation completed successfully.
- * CRYPTO_QUEUED: A request was submitted successfully. The callback
- * routine will be called when the operation is done.
- * CRYPTO_INVALID_MECH_NUMBER, CRYPTO_INVALID_MECH_PARAM, or
- * CRYPTO_INVALID_MECH for problems with the 'mech'.
- * CRYPTO_INVALID_DATA for bogus 'data'
- * CRYPTO_HOST_MEMORY for failure to allocate memory to handle this work.
- * CRYPTO_INVALID_CONTEXT: Not a valid context.
- * CRYPTO_BUSY: Cannot process the request now. Schedule a
- * crypto_bufcall(), or try later.
- * CRYPTO_NOT_SUPPORTED and CRYPTO_MECH_NOT_SUPPORTED: No provider is
- * capable of a function or a mechanism.
- * CRYPTO_INVALID_KEY: bogus 'key' argument.
- * CRYPTO_INVALID_PLAINTEXT: bogus 'plaintext' argument.
- * CRYPTO_INVALID_CIPHERTEXT: bogus 'ciphertext' argument.
- */
/*
- * crypto_cipher_init_prov()
+ * crypto_encrypt()
*
* Arguments:
- *
- * pd: provider descriptor
- * sid: session id
- * mech: crypto_mechanism_t pointer.
- * mech_type is a valid value previously returned by
- * crypto_mech2id();
- * When the mech's parameter is not NULL, its definition depends
- * on the standard definition of the mechanism.
- * key: pointer to a crypto_key_t structure.
- * tmpl: a crypto_ctx_template_t, opaque template of a context of an
- * encryption or decryption with the 'mech' using 'key'.
- * 'tmpl' is created by a previous call to
- * crypto_create_ctx_template().
- * ctxp: Pointer to a crypto_context_t.
- * func: CRYPTO_FG_ENCRYPT or CRYPTO_FG_DECRYPT.
- * cr: crypto_call_req_t calling conditions and call back info.
- *
- * Description:
- * This is a common function invoked internally by both
- * crypto_encrypt_init() and crypto_decrypt_init().
- * Asynchronously submits a request for, or synchronously performs the
- * initialization of an encryption or a decryption operation.
- * When possible and applicable, will internally use the pre-expanded key
- * schedule from the context template, tmpl.
- * When complete and successful, 'ctxp' will contain a crypto_context_t
- * valid for later calls to encrypt_update() and encrypt_final(), or
- * decrypt_update() and decrypt_final().
- * The caller should hold a reference on the specified provider
- * descriptor before calling this function.
- *
- * Context:
- * Process or interrupt, according to the semantics dictated by the 'cr'.
- *
- * Returns:
- * See comment in the beginning of the file.
- */
-static int
-crypto_cipher_init_prov(crypto_provider_t provider, crypto_session_id_t sid,
- crypto_mechanism_t *mech, crypto_key_t *key,
- crypto_spi_ctx_template_t tmpl, crypto_context_t *ctxp,
- crypto_call_req_t *crq, crypto_func_group_t func)
-{
- int error;
- crypto_ctx_t *ctx;
- kcf_req_params_t params;
- kcf_provider_desc_t *pd = provider;
- kcf_provider_desc_t *real_provider = pd;
-
- ASSERT(KCF_PROV_REFHELD(pd));
-
- if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
- if (func == CRYPTO_FG_ENCRYPT) {
- error = kcf_get_hardware_provider(mech->cm_type,
- CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd,
- &real_provider, CRYPTO_FG_ENCRYPT);
- } else {
- error = kcf_get_hardware_provider(mech->cm_type,
- CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd,
- &real_provider, CRYPTO_FG_DECRYPT);
- }
-
- if (error != CRYPTO_SUCCESS)
- return (error);
- }
-
- /* Allocate and initialize the canonical context */
- if ((ctx = kcf_new_ctx(crq, real_provider, sid)) == NULL) {
- if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
- KCF_PROV_REFRELE(real_provider);
- return (CRYPTO_HOST_MEMORY);
- }
-
- /* The fast path for SW providers. */
- if (CHECK_FASTPATH(crq, pd)) {
- crypto_mechanism_t lmech;
-
- lmech = *mech;
- KCF_SET_PROVIDER_MECHNUM(mech->cm_type, real_provider, &lmech);
-
- if (func == CRYPTO_FG_ENCRYPT)
- error = KCF_PROV_ENCRYPT_INIT(real_provider, ctx,
- &lmech, key, tmpl, KCF_SWFP_RHNDL(crq));
- else {
- ASSERT(func == CRYPTO_FG_DECRYPT);
-
- error = KCF_PROV_DECRYPT_INIT(real_provider, ctx,
- &lmech, key, tmpl, KCF_SWFP_RHNDL(crq));
- }
- KCF_PROV_INCRSTATS(pd, error);
-
- goto done;
- }
-
- /* Check if context sharing is possible */
- if (pd->pd_prov_type == CRYPTO_HW_PROVIDER &&
- key->ck_format == CRYPTO_KEY_RAW &&
- KCF_CAN_SHARE_OPSTATE(pd, mech->cm_type)) {
- kcf_context_t *tctxp = (kcf_context_t *)ctx;
- kcf_provider_desc_t *tpd = NULL;
- crypto_mech_info_t *sinfo;
-
- if ((kcf_get_sw_prov(mech->cm_type, &tpd, &tctxp->kc_mech,
- B_FALSE) == CRYPTO_SUCCESS)) {
- int tlen;
-
- sinfo = &(KCF_TO_PROV_MECHINFO(tpd, mech->cm_type));
- /*
- * key->ck_length from the consumer is always in bits.
- * We convert it to be in the same unit registered by
- * the provider in order to do a comparison.
- */
- if (sinfo->cm_mech_flags & CRYPTO_KEYSIZE_UNIT_IN_BYTES)
- tlen = key->ck_length >> 3;
- else
- tlen = key->ck_length;
- /*
- * Check if the software provider can support context
- * sharing and support this key length.
- */
- if ((sinfo->cm_mech_flags & CRYPTO_CAN_SHARE_OPSTATE) &&
- (tlen >= sinfo->cm_min_key_length) &&
- (tlen <= sinfo->cm_max_key_length)) {
- ctx->cc_flags = CRYPTO_INIT_OPSTATE;
- tctxp->kc_sw_prov_desc = tpd;
- } else
- KCF_PROV_REFRELE(tpd);
- }
- }
-
- if (func == CRYPTO_FG_ENCRYPT) {
- KCF_WRAP_ENCRYPT_OPS_PARAMS(&params, KCF_OP_INIT, sid,
- mech, key, NULL, NULL, tmpl);
- } else {
- ASSERT(func == CRYPTO_FG_DECRYPT);
- KCF_WRAP_DECRYPT_OPS_PARAMS(&params, KCF_OP_INIT, sid,
- mech, key, NULL, NULL, tmpl);
- }
-
- error = kcf_submit_request(real_provider, ctx, crq, &params,
- B_FALSE);
-
- if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
- KCF_PROV_REFRELE(real_provider);
-
-done:
- if ((error == CRYPTO_SUCCESS) || (error == CRYPTO_QUEUED))
- *ctxp = (crypto_context_t)ctx;
- else {
- /* Release the hold done in kcf_new_ctx(). */
- KCF_CONTEXT_REFRELE((kcf_context_t *)ctx->cc_framework_private);
- }
-
- return (error);
-}
-
-/*
- * Same as crypto_cipher_init_prov(), but relies on the scheduler to pick
- * an appropriate provider. See crypto_cipher_init_prov() comments for more
- * details.
- */
-static int
-crypto_cipher_init(crypto_mechanism_t *mech, crypto_key_t *key,
- crypto_ctx_template_t tmpl, crypto_context_t *ctxp,
- crypto_call_req_t *crq, crypto_func_group_t func)
-{
- int error;
- kcf_mech_entry_t *me;
- kcf_provider_desc_t *pd;
- kcf_ctx_template_t *ctx_tmpl;
- crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;
- kcf_prov_tried_t *list = NULL;
-
-retry:
- /* pd is returned held */
- if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error,
- list, func, CHECK_RESTRICT(crq), 0)) == NULL) {
- if (list != NULL)
- kcf_free_triedlist(list);
- return (error);
- }
-
- /*
- * For SW providers, check the validity of the context template
- * It is very rare that the generation number mis-matches, so
- * is acceptable to fail here, and let the consumer recover by
- * freeing this tmpl and create a new one for the key and new SW
- * provider
- */
- if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) &&
- ((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) {
- if (ctx_tmpl->ct_generation != me->me_gen_swprov) {
- if (list != NULL)
- kcf_free_triedlist(list);
- KCF_PROV_REFRELE(pd);
- return (CRYPTO_OLD_CTX_TEMPLATE);
- } else {
- spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
- }
- }
-
- error = crypto_cipher_init_prov(pd, pd->pd_sid, mech, key,
- spi_ctx_tmpl, ctxp, crq, func);
- if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
- IS_RECOVERABLE(error)) {
- /* Add pd to the linked list of providers tried. */
- if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
- goto retry;
- }
-
- if (list != NULL)
- kcf_free_triedlist(list);
-
- KCF_PROV_REFRELE(pd);
- return (error);
-}
-
-/*
- * crypto_encrypt_prov()
- *
- * Arguments:
- * pd: provider descriptor
* sid: session id
* mech: crypto_mechanism_t pointer.
* mech_type is a valid value previously returned by
@@ -294,7 +52,6 @@ retry:
* tmpl: a crypto_ctx_template_t, opaque template of a context of an
* encryption with the 'mech' using 'key'. 'tmpl' is created by
* a previous call to crypto_create_ctx_template().
- * cr: crypto_call_req_t calling conditions and call back info.
*
* Description:
* Asynchronously submits a request for, or synchronously performs a
@@ -302,57 +59,17 @@ retry:
* the key 'key'.
* When complete and successful, 'ciphertext' will contain the encrypted
* message.
- *
- * Context:
- * Process or interrupt, according to the semantics dictated by the 'cr'.
+ * Relies on the KCF scheduler to pick a provider.
*
* Returns:
* See comment in the beginning of the file.
*/
int
-crypto_encrypt_prov(crypto_provider_t provider, crypto_session_id_t sid,
- crypto_mechanism_t *mech, crypto_data_t *plaintext, crypto_key_t *key,
- crypto_ctx_template_t tmpl, crypto_data_t *ciphertext,
- crypto_call_req_t *crq)
-{
- kcf_req_params_t params;
- kcf_provider_desc_t *pd = provider;
- kcf_provider_desc_t *real_provider = pd;
- int error;
-
- ASSERT(KCF_PROV_REFHELD(pd));
-
- if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
- error = kcf_get_hardware_provider(mech->cm_type,
- CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd,
- &real_provider, CRYPTO_FG_ENCRYPT_ATOMIC);
-
- if (error != CRYPTO_SUCCESS)
- return (error);
- }
-
- KCF_WRAP_ENCRYPT_OPS_PARAMS(&params, KCF_OP_ATOMIC, sid, mech, key,
- plaintext, ciphertext, tmpl);
-
- error = kcf_submit_request(real_provider, NULL, crq, &params, B_FALSE);
- if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
- KCF_PROV_REFRELE(real_provider);
-
- return (error);
-}
-
-/*
- * Same as crypto_encrypt_prov(), but relies on the scheduler to pick
- * a provider. See crypto_encrypt_prov() for more details.
- */
-int
crypto_encrypt(crypto_mechanism_t *mech, crypto_data_t *plaintext,
- crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *ciphertext,
- crypto_call_req_t *crq)
+ crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *ciphertext)
{
int error;
kcf_mech_entry_t *me;
- kcf_req_params_t params;
kcf_provider_desc_t *pd;
kcf_ctx_template_t *ctx_tmpl;
crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;
@@ -361,52 +78,23 @@ crypto_encrypt(crypto_mechanism_t *mech, crypto_data_t *plaintext,
retry:
/* pd is returned held */
if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error,
- list, CRYPTO_FG_ENCRYPT_ATOMIC, CHECK_RESTRICT(crq),
- plaintext->cd_length)) == NULL) {
+ list, CRYPTO_FG_ENCRYPT_ATOMIC)) == NULL) {
if (list != NULL)
kcf_free_triedlist(list);
return (error);
}
- /*
- * For SW providers, check the validity of the context template
- * It is very rare that the generation number mis-matches, so
- * is acceptable to fail here, and let the consumer recover by
- * freeing this tmpl and create a new one for the key and new SW
- * provider
- */
- if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) &&
- ((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) {
- if (ctx_tmpl->ct_generation != me->me_gen_swprov) {
- if (list != NULL)
- kcf_free_triedlist(list);
- KCF_PROV_REFRELE(pd);
- return (CRYPTO_OLD_CTX_TEMPLATE);
- } else {
- spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
- }
- }
-
- /* The fast path for SW providers. */
- if (CHECK_FASTPATH(crq, pd)) {
- crypto_mechanism_t lmech;
+ if (((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL))
+ spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
- lmech = *mech;
- KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
+ crypto_mechanism_t lmech = *mech;
+ KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
+ error = KCF_PROV_ENCRYPT_ATOMIC(pd, &lmech, key,
+ plaintext, ciphertext, spi_ctx_tmpl);
- error = KCF_PROV_ENCRYPT_ATOMIC(pd, pd->pd_sid, &lmech, key,
- plaintext, ciphertext, spi_ctx_tmpl, KCF_SWFP_RHNDL(crq));
- KCF_PROV_INCRSTATS(pd, error);
- } else {
- KCF_WRAP_ENCRYPT_OPS_PARAMS(&params, KCF_OP_ATOMIC, pd->pd_sid,
- mech, key, plaintext, ciphertext, spi_ctx_tmpl);
- error = kcf_submit_request(pd, NULL, crq, &params, B_FALSE);
- }
-
- if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
- IS_RECOVERABLE(error)) {
+ if (error != CRYPTO_SUCCESS && IS_RECOVERABLE(error)) {
/* Add pd to the linked list of providers tried. */
- if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
+ if (kcf_insert_triedlist(&list, pd, KM_SLEEP) != NULL)
goto retry;
}
@@ -418,147 +106,6 @@ retry:
}
/*
- * crypto_encrypt_init_prov()
- *
- * Calls crypto_cipher_init_prov() to initialize an encryption operation.
- */
-int
-crypto_encrypt_init_prov(crypto_provider_t pd, crypto_session_id_t sid,
- crypto_mechanism_t *mech, crypto_key_t *key,
- crypto_ctx_template_t tmpl, crypto_context_t *ctxp,
- crypto_call_req_t *crq)
-{
- return (crypto_cipher_init_prov(pd, sid, mech, key, tmpl, ctxp, crq,
- CRYPTO_FG_ENCRYPT));
-}
-
-/*
- * crypto_encrypt_init()
- *
- * Calls crypto_cipher_init() to initialize an encryption operation
- */
-int
-crypto_encrypt_init(crypto_mechanism_t *mech, crypto_key_t *key,
- crypto_ctx_template_t tmpl, crypto_context_t *ctxp,
- crypto_call_req_t *crq)
-{
- return (crypto_cipher_init(mech, key, tmpl, ctxp, crq,
- CRYPTO_FG_ENCRYPT));
-}
-
-/*
- * crypto_encrypt_update()
- *
- * Arguments:
- * context: A crypto_context_t initialized by encrypt_init().
- * plaintext: The message part to be encrypted
- * ciphertext: Storage for the encrypted message part.
- * cr: crypto_call_req_t calling conditions and call back info.
- *
- * Description:
- * Asynchronously submits a request for, or synchronously performs a
- * part of an encryption operation.
- *
- * Context:
- * Process or interrupt, according to the semantics dictated by the 'cr'.
- *
- * Returns:
- * See comment in the beginning of the file.
- */
-int
-crypto_encrypt_update(crypto_context_t context, crypto_data_t *plaintext,
- crypto_data_t *ciphertext, crypto_call_req_t *cr)
-{
- crypto_ctx_t *ctx = (crypto_ctx_t *)context;
- kcf_context_t *kcf_ctx;
- kcf_provider_desc_t *pd;
- int error;
- kcf_req_params_t params;
-
- if ((ctx == NULL) ||
- ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
- ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
- return (CRYPTO_INVALID_CONTEXT);
- }
-
- ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
-
- /* The fast path for SW providers. */
- if (CHECK_FASTPATH(cr, pd)) {
- error = KCF_PROV_ENCRYPT_UPDATE(pd, ctx, plaintext,
- ciphertext, NULL);
- KCF_PROV_INCRSTATS(pd, error);
- return (error);
- }
-
- /* Check if we should use a software provider for small jobs */
- if ((ctx->cc_flags & CRYPTO_USE_OPSTATE) && cr == NULL) {
- if (plaintext->cd_length < kcf_ctx->kc_mech->me_threshold &&
- kcf_ctx->kc_sw_prov_desc != NULL &&
- KCF_IS_PROV_USABLE(kcf_ctx->kc_sw_prov_desc)) {
- pd = kcf_ctx->kc_sw_prov_desc;
- }
- }
-
- KCF_WRAP_ENCRYPT_OPS_PARAMS(&params, KCF_OP_UPDATE,
- ctx->cc_session, NULL, NULL, plaintext, ciphertext, NULL);
- error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
-
- return (error);
-}
-
-/*
- * crypto_encrypt_final()
- *
- * Arguments:
- * context: A crypto_context_t initialized by encrypt_init().
- * ciphertext: Storage for the last part of encrypted message
- * cr: crypto_call_req_t calling conditions and call back info.
- *
- * Description:
- * Asynchronously submits a request for, or synchronously performs the
- * final part of an encryption operation.
- *
- * Context:
- * Process or interrupt, according to the semantics dictated by the 'cr'.
- *
- * Returns:
- * See comment in the beginning of the file.
- */
-int
-crypto_encrypt_final(crypto_context_t context, crypto_data_t *ciphertext,
- crypto_call_req_t *cr)
-{
- crypto_ctx_t *ctx = (crypto_ctx_t *)context;
- kcf_context_t *kcf_ctx;
- kcf_provider_desc_t *pd;
- int error;
- kcf_req_params_t params;
-
- if ((ctx == NULL) ||
- ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
- ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
- return (CRYPTO_INVALID_CONTEXT);
- }
-
- ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
-
- /* The fast path for SW providers. */
- if (CHECK_FASTPATH(cr, pd)) {
- error = KCF_PROV_ENCRYPT_FINAL(pd, ctx, ciphertext, NULL);
- KCF_PROV_INCRSTATS(pd, error);
- } else {
- KCF_WRAP_ENCRYPT_OPS_PARAMS(&params, KCF_OP_FINAL,
- ctx->cc_session, NULL, NULL, NULL, ciphertext, NULL);
- error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
- }
-
- /* Release the hold done in kcf_new_ctx() during init step. */
- KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
- return (error);
-}
-
-/*
* crypto_decrypt_prov()
*
* Arguments:
@@ -576,7 +123,6 @@ crypto_encrypt_final(crypto_context_t context, crypto_data_t *ciphertext,
* tmpl: a crypto_ctx_template_t, opaque template of a context of an
* encryption with the 'mech' using 'key'. 'tmpl' is created by
* a previous call to crypto_create_ctx_template().
- * cr: crypto_call_req_t calling conditions and call back info.
*
* Description:
* Asynchronously submits a request for, or synchronously performs a
@@ -584,58 +130,17 @@ crypto_encrypt_final(crypto_context_t context, crypto_data_t *ciphertext,
* the key 'key'.
* When complete and successful, 'plaintext' will contain the decrypted
* message.
- *
- * Context:
- * Process or interrupt, according to the semantics dictated by the 'cr'.
+ * Relies on the KCF scheduler to choose a provider.
*
* Returns:
* See comment in the beginning of the file.
*/
int
-crypto_decrypt_prov(crypto_provider_t provider, crypto_session_id_t sid,
- crypto_mechanism_t *mech, crypto_data_t *ciphertext, crypto_key_t *key,
- crypto_ctx_template_t tmpl, crypto_data_t *plaintext,
- crypto_call_req_t *crq)
-{
- kcf_req_params_t params;
- kcf_provider_desc_t *pd = provider;
- kcf_provider_desc_t *real_provider = pd;
- int rv;
-
- ASSERT(KCF_PROV_REFHELD(pd));
-
- if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
- rv = kcf_get_hardware_provider(mech->cm_type,
- CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd,
- &real_provider, CRYPTO_FG_DECRYPT_ATOMIC);
-
- if (rv != CRYPTO_SUCCESS)
- return (rv);
- }
-
- KCF_WRAP_DECRYPT_OPS_PARAMS(&params, KCF_OP_ATOMIC, sid, mech, key,
- ciphertext, plaintext, tmpl);
-
- rv = kcf_submit_request(real_provider, NULL, crq, &params, B_FALSE);
- if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
- KCF_PROV_REFRELE(real_provider);
-
- return (rv);
-}
-
-/*
- * Same as crypto_decrypt_prov(), but relies on the KCF scheduler to
- * choose a provider. See crypto_decrypt_prov() comments for more
- * information.
- */
-int
crypto_decrypt(crypto_mechanism_t *mech, crypto_data_t *ciphertext,
- crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *plaintext,
- crypto_call_req_t *crq)
+ crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *plaintext)
{
int error;
kcf_mech_entry_t *me;
- kcf_req_params_t params;
kcf_provider_desc_t *pd;
kcf_ctx_template_t *ctx_tmpl;
crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;
@@ -644,52 +149,24 @@ crypto_decrypt(crypto_mechanism_t *mech, crypto_data_t *ciphertext,
retry:
/* pd is returned held */
if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error,
- list, CRYPTO_FG_DECRYPT_ATOMIC, CHECK_RESTRICT(crq),
- ciphertext->cd_length)) == NULL) {
+ list, CRYPTO_FG_DECRYPT_ATOMIC)) == NULL) {
if (list != NULL)
kcf_free_triedlist(list);
return (error);
}
- /*
- * For SW providers, check the validity of the context template
- * It is very rare that the generation number mis-matches, so
- * is acceptable to fail here, and let the consumer recover by
- * freeing this tmpl and create a new one for the key and new SW
- * provider
- */
- if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) &&
- ((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) {
- if (ctx_tmpl->ct_generation != me->me_gen_swprov) {
- if (list != NULL)
- kcf_free_triedlist(list);
- KCF_PROV_REFRELE(pd);
- return (CRYPTO_OLD_CTX_TEMPLATE);
- } else {
- spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
- }
- }
-
- /* The fast path for SW providers. */
- if (CHECK_FASTPATH(crq, pd)) {
- crypto_mechanism_t lmech;
+ if (((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL))
+ spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
- lmech = *mech;
- KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
+ crypto_mechanism_t lmech = *mech;
+ KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
- error = KCF_PROV_DECRYPT_ATOMIC(pd, pd->pd_sid, &lmech, key,
- ciphertext, plaintext, spi_ctx_tmpl, KCF_SWFP_RHNDL(crq));
- KCF_PROV_INCRSTATS(pd, error);
- } else {
- KCF_WRAP_DECRYPT_OPS_PARAMS(&params, KCF_OP_ATOMIC, pd->pd_sid,
- mech, key, ciphertext, plaintext, spi_ctx_tmpl);
- error = kcf_submit_request(pd, NULL, crq, &params, B_FALSE);
- }
+ error = KCF_PROV_DECRYPT_ATOMIC(pd, &lmech, key,
+ ciphertext, plaintext, spi_ctx_tmpl);
- if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
- IS_RECOVERABLE(error)) {
+ if (error != CRYPTO_SUCCESS && IS_RECOVERABLE(error)) {
/* Add pd to the linked list of providers tried. */
- if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
+ if (kcf_insert_triedlist(&list, pd, KM_SLEEP) != NULL)
goto retry;
}
@@ -700,231 +177,7 @@ retry:
return (error);
}
-/*
- * crypto_decrypt_init_prov()
- *
- * Calls crypto_cipher_init_prov() to initialize a decryption operation
- */
-int
-crypto_decrypt_init_prov(crypto_provider_t pd, crypto_session_id_t sid,
- crypto_mechanism_t *mech, crypto_key_t *key,
- crypto_ctx_template_t tmpl, crypto_context_t *ctxp,
- crypto_call_req_t *crq)
-{
- return (crypto_cipher_init_prov(pd, sid, mech, key, tmpl, ctxp, crq,
- CRYPTO_FG_DECRYPT));
-}
-
-/*
- * crypto_decrypt_init()
- *
- * Calls crypto_cipher_init() to initialize a decryption operation
- */
-int
-crypto_decrypt_init(crypto_mechanism_t *mech, crypto_key_t *key,
- crypto_ctx_template_t tmpl, crypto_context_t *ctxp,
- crypto_call_req_t *crq)
-{
- return (crypto_cipher_init(mech, key, tmpl, ctxp, crq,
- CRYPTO_FG_DECRYPT));
-}
-
-/*
- * crypto_decrypt_update()
- *
- * Arguments:
- * context: A crypto_context_t initialized by decrypt_init().
- * ciphertext: The message part to be decrypted
- * plaintext: Storage for the decrypted message part.
- * cr: crypto_call_req_t calling conditions and call back info.
- *
- * Description:
- * Asynchronously submits a request for, or synchronously performs a
- * part of an decryption operation.
- *
- * Context:
- * Process or interrupt, according to the semantics dictated by the 'cr'.
- *
- * Returns:
- * See comment in the beginning of the file.
- */
-int
-crypto_decrypt_update(crypto_context_t context, crypto_data_t *ciphertext,
- crypto_data_t *plaintext, crypto_call_req_t *cr)
-{
- crypto_ctx_t *ctx = (crypto_ctx_t *)context;
- kcf_context_t *kcf_ctx;
- kcf_provider_desc_t *pd;
- int error;
- kcf_req_params_t params;
-
- if ((ctx == NULL) ||
- ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
- ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
- return (CRYPTO_INVALID_CONTEXT);
- }
-
- ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
-
- /* The fast path for SW providers. */
- if (CHECK_FASTPATH(cr, pd)) {
- error = KCF_PROV_DECRYPT_UPDATE(pd, ctx, ciphertext,
- plaintext, NULL);
- KCF_PROV_INCRSTATS(pd, error);
- return (error);
- }
-
- /* Check if we should use a software provider for small jobs */
- if ((ctx->cc_flags & CRYPTO_USE_OPSTATE) && cr == NULL) {
- if (ciphertext->cd_length < kcf_ctx->kc_mech->me_threshold &&
- kcf_ctx->kc_sw_prov_desc != NULL &&
- KCF_IS_PROV_USABLE(kcf_ctx->kc_sw_prov_desc)) {
- pd = kcf_ctx->kc_sw_prov_desc;
- }
- }
-
- KCF_WRAP_DECRYPT_OPS_PARAMS(&params, KCF_OP_UPDATE,
- ctx->cc_session, NULL, NULL, ciphertext, plaintext, NULL);
- error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
-
- return (error);
-}
-
-/*
- * crypto_decrypt_final()
- *
- * Arguments:
- * context: A crypto_context_t initialized by decrypt_init().
- * plaintext: Storage for the last part of the decrypted message
- * cr: crypto_call_req_t calling conditions and call back info.
- *
- * Description:
- * Asynchronously submits a request for, or synchronously performs the
- * final part of a decryption operation.
- *
- * Context:
- * Process or interrupt, according to the semantics dictated by the 'cr'.
- *
- * Returns:
- * See comment in the beginning of the file.
- */
-int
-crypto_decrypt_final(crypto_context_t context, crypto_data_t *plaintext,
- crypto_call_req_t *cr)
-{
- crypto_ctx_t *ctx = (crypto_ctx_t *)context;
- kcf_context_t *kcf_ctx;
- kcf_provider_desc_t *pd;
- int error;
- kcf_req_params_t params;
-
- if ((ctx == NULL) ||
- ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
- ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
- return (CRYPTO_INVALID_CONTEXT);
- }
-
- ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
-
- /* The fast path for SW providers. */
- if (CHECK_FASTPATH(cr, pd)) {
- error = KCF_PROV_DECRYPT_FINAL(pd, ctx, plaintext,
- NULL);
- KCF_PROV_INCRSTATS(pd, error);
- } else {
- KCF_WRAP_DECRYPT_OPS_PARAMS(&params, KCF_OP_FINAL,
- ctx->cc_session, NULL, NULL, NULL, plaintext, NULL);
- error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
- }
-
- /* Release the hold done in kcf_new_ctx() during init step. */
- KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
- return (error);
-}
-
-/*
- * See comments for crypto_encrypt_update().
- */
-int
-crypto_encrypt_single(crypto_context_t context, crypto_data_t *plaintext,
- crypto_data_t *ciphertext, crypto_call_req_t *cr)
-{
- crypto_ctx_t *ctx = (crypto_ctx_t *)context;
- kcf_context_t *kcf_ctx;
- kcf_provider_desc_t *pd;
- int error;
- kcf_req_params_t params;
-
- if ((ctx == NULL) ||
- ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
- ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
- return (CRYPTO_INVALID_CONTEXT);
- }
-
- /* The fast path for SW providers. */
- if (CHECK_FASTPATH(cr, pd)) {
- error = KCF_PROV_ENCRYPT(pd, ctx, plaintext,
- ciphertext, NULL);
- KCF_PROV_INCRSTATS(pd, error);
- } else {
- KCF_WRAP_ENCRYPT_OPS_PARAMS(&params, KCF_OP_SINGLE, pd->pd_sid,
- NULL, NULL, plaintext, ciphertext, NULL);
- error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
- }
-
- /* Release the hold done in kcf_new_ctx() during init step. */
- KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
- return (error);
-}
-
-/*
- * See comments for crypto_decrypt_update().
- */
-int
-crypto_decrypt_single(crypto_context_t context, crypto_data_t *ciphertext,
- crypto_data_t *plaintext, crypto_call_req_t *cr)
-{
- crypto_ctx_t *ctx = (crypto_ctx_t *)context;
- kcf_context_t *kcf_ctx;
- kcf_provider_desc_t *pd;
- int error;
- kcf_req_params_t params;
-
- if ((ctx == NULL) ||
- ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
- ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
- return (CRYPTO_INVALID_CONTEXT);
- }
-
- /* The fast path for SW providers. */
- if (CHECK_FASTPATH(cr, pd)) {
- error = KCF_PROV_DECRYPT(pd, ctx, ciphertext,
- plaintext, NULL);
- KCF_PROV_INCRSTATS(pd, error);
- } else {
- KCF_WRAP_DECRYPT_OPS_PARAMS(&params, KCF_OP_SINGLE, pd->pd_sid,
- NULL, NULL, ciphertext, plaintext, NULL);
- error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
- }
-
- /* Release the hold done in kcf_new_ctx() during init step. */
- KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
- return (error);
-}
-
#if defined(_KERNEL)
-EXPORT_SYMBOL(crypto_encrypt_prov);
EXPORT_SYMBOL(crypto_encrypt);
-EXPORT_SYMBOL(crypto_encrypt_init_prov);
-EXPORT_SYMBOL(crypto_encrypt_init);
-EXPORT_SYMBOL(crypto_encrypt_update);
-EXPORT_SYMBOL(crypto_encrypt_final);
-EXPORT_SYMBOL(crypto_decrypt_prov);
EXPORT_SYMBOL(crypto_decrypt);
-EXPORT_SYMBOL(crypto_decrypt_init_prov);
-EXPORT_SYMBOL(crypto_decrypt_init);
-EXPORT_SYMBOL(crypto_decrypt_update);
-EXPORT_SYMBOL(crypto_decrypt_final);
-EXPORT_SYMBOL(crypto_encrypt_single);
-EXPORT_SYMBOL(crypto_decrypt_single);
#endif
diff --git a/sys/contrib/openzfs/module/icp/api/kcf_ctxops.c b/sys/contrib/openzfs/module/icp/api/kcf_ctxops.c
index 21b0977d3634..67bf76a8f1fc 100644
--- a/sys/contrib/openzfs/module/icp/api/kcf_ctxops.c
+++ b/sys/contrib/openzfs/module/icp/api/kcf_ctxops.c
@@ -48,7 +48,6 @@
* ptmpl: a storage for the opaque crypto_ctx_template_t, allocated and
* initialized by the software provider this routine is
* dispatched to.
- * kmflag: KM_SLEEP/KM_NOSLEEP mem. alloc. flag.
*
* Description:
* Redirects the call to the software provider of the specified
@@ -69,7 +68,7 @@
*/
int
crypto_create_ctx_template(crypto_mechanism_t *mech, crypto_key_t *key,
- crypto_ctx_template_t *ptmpl, int kmflag)
+ crypto_ctx_template_t *ptmpl)
{
int error;
kcf_mech_entry_t *me;
@@ -90,7 +89,7 @@ crypto_create_ctx_template(crypto_mechanism_t *mech, crypto_key_t *key,
return (error);
if ((ctx_tmpl = (kcf_ctx_template_t *)kmem_alloc(
- sizeof (kcf_ctx_template_t), kmflag)) == NULL) {
+ sizeof (kcf_ctx_template_t), KM_SLEEP)) == NULL) {
KCF_PROV_REFRELE(pd);
return (CRYPTO_HOST_MEMORY);
}
@@ -101,10 +100,9 @@ crypto_create_ctx_template(crypto_mechanism_t *mech, crypto_key_t *key,
prov_mech.cm_param_len = mech->cm_param_len;
error = KCF_PROV_CREATE_CTX_TEMPLATE(pd, &prov_mech, key,
- &(ctx_tmpl->ct_prov_tmpl), &(ctx_tmpl->ct_size), KCF_RHNDL(kmflag));
+ &(ctx_tmpl->ct_prov_tmpl), &(ctx_tmpl->ct_size));
if (error == CRYPTO_SUCCESS) {
- ctx_tmpl->ct_generation = me->me_gen_swprov;
*ptmpl = ctx_tmpl;
} else {
kmem_free(ctx_tmpl, sizeof (kcf_ctx_template_t));
diff --git a/sys/contrib/openzfs/module/icp/api/kcf_digest.c b/sys/contrib/openzfs/module/icp/api/kcf_digest.c
deleted file mode 100644
index aa68d69bc162..000000000000
--- a/sys/contrib/openzfs/module/icp/api/kcf_digest.c
+++ /dev/null
@@ -1,491 +0,0 @@
-/*
- * 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 2007 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#include <sys/zfs_context.h>
-#include <sys/crypto/common.h>
-#include <sys/crypto/impl.h>
-#include <sys/crypto/api.h>
-#include <sys/crypto/spi.h>
-#include <sys/crypto/sched_impl.h>
-
-/*
- * Message digest routines
- */
-
-/*
- * The following are the possible returned values common to all the routines
- * below. The applicability of some of these return values depends on the
- * presence of the arguments.
- *
- * CRYPTO_SUCCESS: The operation completed successfully.
- * CRYPTO_QUEUED: A request was submitted successfully. The callback
- * routine will be called when the operation is done.
- * CRYPTO_MECHANISM_INVALID or CRYPTO_INVALID_MECH_PARAM
- * for problems with the 'mech'.
- * CRYPTO_INVALID_DATA for bogus 'data'
- * CRYPTO_HOST_MEMORY for failure to allocate memory to handle this work.
- * CRYPTO_INVALID_CONTEXT: Not a valid context.
- * CRYPTO_BUSY: Cannot process the request now. Schedule a
- * crypto_bufcall(), or try later.
- * CRYPTO_NOT_SUPPORTED and CRYPTO_MECH_NOT_SUPPORTED:
- * No provider is capable of a function or a mechanism.
- */
-
-
-/*
- * crypto_digest_prov()
- *
- * Arguments:
- * pd: pointer to the descriptor of the provider to use for this
- * operation.
- * sid: provider session id.
- * mech: crypto_mechanism_t pointer.
- * mech_type is a valid value previously returned by
- * crypto_mech2id();
- * When the mech's parameter is not NULL, its definition depends
- * on the standard definition of the mechanism.
- * data: The message to be digested.
- * digest: Storage for the digest. The length needed depends on the
- * mechanism.
- * cr: crypto_call_req_t calling conditions and call back info.
- *
- * Description:
- * Asynchronously submits a request for, or synchronously performs the
- * digesting operation of 'data' on the specified
- * provider with the specified session.
- * When complete and successful, 'digest' will contain the digest value.
- * The caller should hold a reference on the specified provider
- * descriptor before calling this function.
- *
- * Context:
- * Process or interrupt, according to the semantics dictated by the 'cr'.
- *
- * Returns:
- * See comment in the beginning of the file.
- */
-int
-crypto_digest_prov(crypto_provider_t provider, crypto_session_id_t sid,
- crypto_mechanism_t *mech, crypto_data_t *data, crypto_data_t *digest,
- crypto_call_req_t *crq)
-{
- kcf_req_params_t params;
- kcf_provider_desc_t *pd = provider;
- kcf_provider_desc_t *real_provider = pd;
- int rv;
-
- ASSERT(KCF_PROV_REFHELD(pd));
-
- if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
- rv = kcf_get_hardware_provider(mech->cm_type,
- CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq),
- pd, &real_provider, CRYPTO_FG_DIGEST_ATOMIC);
-
- if (rv != CRYPTO_SUCCESS)
- return (rv);
- }
- KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_ATOMIC, sid, mech, NULL,
- data, digest);
-
- /* no crypto context to carry between multiple parts. */
- rv = kcf_submit_request(real_provider, NULL, crq, &params, B_FALSE);
- if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
- KCF_PROV_REFRELE(real_provider);
-
- return (rv);
-}
-
-
-/*
- * Same as crypto_digest_prov(), but relies on the KCF scheduler to
- * choose a provider. See crypto_digest_prov() comments for more information.
- */
-int
-crypto_digest(crypto_mechanism_t *mech, crypto_data_t *data,
- crypto_data_t *digest, crypto_call_req_t *crq)
-{
- int error;
- kcf_provider_desc_t *pd;
- kcf_req_params_t params;
- kcf_prov_tried_t *list = NULL;
-
-retry:
- /* The pd is returned held */
- if ((pd = kcf_get_mech_provider(mech->cm_type, NULL, &error, list,
- CRYPTO_FG_DIGEST_ATOMIC, CHECK_RESTRICT(crq),
- data->cd_length)) == NULL) {
- if (list != NULL)
- kcf_free_triedlist(list);
- return (error);
- }
-
- /* The fast path for SW providers. */
- if (CHECK_FASTPATH(crq, pd)) {
- crypto_mechanism_t lmech;
-
- lmech = *mech;
- KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
- error = KCF_PROV_DIGEST_ATOMIC(pd, pd->pd_sid, &lmech, data,
- digest, KCF_SWFP_RHNDL(crq));
- KCF_PROV_INCRSTATS(pd, error);
- } else {
- if (pd->pd_prov_type == CRYPTO_HW_PROVIDER &&
- (pd->pd_flags & CRYPTO_HASH_NO_UPDATE) &&
- (data->cd_length > pd->pd_hash_limit)) {
- error = CRYPTO_BUFFER_TOO_BIG;
- } else {
- KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_ATOMIC,
- pd->pd_sid, mech, NULL, data, digest);
-
- /* no crypto context to carry between multiple parts. */
- error = kcf_submit_request(pd, NULL, crq, &params,
- B_FALSE);
- }
- }
-
- if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
- IS_RECOVERABLE(error)) {
- /* Add pd to the linked list of providers tried. */
- if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
- goto retry;
- }
-
- if (list != NULL)
- kcf_free_triedlist(list);
-
- KCF_PROV_REFRELE(pd);
- return (error);
-}
-
-/*
- * crypto_digest_init_prov()
- *
- * pd: pointer to the descriptor of the provider to use for this
- * operation.
- * sid: provider session id.
- * mech: crypto_mechanism_t pointer.
- * mech_type is a valid value previously returned by
- * crypto_mech2id();
- * When the mech's parameter is not NULL, its definition depends
- * on the standard definition of the mechanism.
- * ctxp: Pointer to a crypto_context_t.
- * cr: crypto_call_req_t calling conditions and call back info.
- *
- * Description:
- * Asynchronously submits a request for, or synchronously performs the
- * initialization of a message digest operation on the specified
- * provider with the specified session.
- * When complete and successful, 'ctxp' will contain a crypto_context_t
- * valid for later calls to digest_update() and digest_final().
- * The caller should hold a reference on the specified provider
- * descriptor before calling this function.
- */
-int
-crypto_digest_init_prov(crypto_provider_t provider, crypto_session_id_t sid,
- crypto_mechanism_t *mech, crypto_context_t *ctxp, crypto_call_req_t *crq)
-{
- int error;
- crypto_ctx_t *ctx;
- kcf_req_params_t params;
- kcf_provider_desc_t *pd = provider;
- kcf_provider_desc_t *real_provider = pd;
-
- ASSERT(KCF_PROV_REFHELD(pd));
-
- if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
- error = kcf_get_hardware_provider(mech->cm_type,
- CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd,
- &real_provider, CRYPTO_FG_DIGEST);
-
- if (error != CRYPTO_SUCCESS)
- return (error);
- }
-
- /* Allocate and initialize the canonical context */
- if ((ctx = kcf_new_ctx(crq, real_provider, sid)) == NULL) {
- if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
- KCF_PROV_REFRELE(real_provider);
- return (CRYPTO_HOST_MEMORY);
- }
-
- /* The fast path for SW providers. */
- if (CHECK_FASTPATH(crq, pd)) {
- crypto_mechanism_t lmech;
-
- lmech = *mech;
- KCF_SET_PROVIDER_MECHNUM(mech->cm_type, real_provider, &lmech);
- error = KCF_PROV_DIGEST_INIT(real_provider, ctx, &lmech,
- KCF_SWFP_RHNDL(crq));
- KCF_PROV_INCRSTATS(pd, error);
- } else {
- KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_INIT, sid,
- mech, NULL, NULL, NULL);
- error = kcf_submit_request(real_provider, ctx, crq, &params,
- B_FALSE);
- }
-
- if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
- KCF_PROV_REFRELE(real_provider);
-
- if ((error == CRYPTO_SUCCESS) || (error == CRYPTO_QUEUED))
- *ctxp = (crypto_context_t)ctx;
- else {
- /* Release the hold done in kcf_new_ctx(). */
- KCF_CONTEXT_REFRELE((kcf_context_t *)ctx->cc_framework_private);
- }
-
- return (error);
-}
-
-/*
- * Same as crypto_digest_init_prov(), but relies on the KCF scheduler
- * to choose a provider. See crypto_digest_init_prov() comments for
- * more information.
- */
-int
-crypto_digest_init(crypto_mechanism_t *mech, crypto_context_t *ctxp,
- crypto_call_req_t *crq)
-{
- int error;
- kcf_provider_desc_t *pd;
- kcf_prov_tried_t *list = NULL;
-
-retry:
- /* The pd is returned held */
- if ((pd = kcf_get_mech_provider(mech->cm_type, NULL, &error,
- list, CRYPTO_FG_DIGEST, CHECK_RESTRICT(crq), 0)) == NULL) {
- if (list != NULL)
- kcf_free_triedlist(list);
- return (error);
- }
-
- if (pd->pd_prov_type == CRYPTO_HW_PROVIDER &&
- (pd->pd_flags & CRYPTO_HASH_NO_UPDATE)) {
- /*
- * The hardware provider has limited digest support.
- * So, we fallback early here to using a software provider.
- *
- * XXX - need to enhance to do the fallback later in
- * crypto_digest_update() if the size of accumulated input data
- * exceeds the maximum size digestable by hardware provider.
- */
- error = CRYPTO_BUFFER_TOO_BIG;
- } else {
- error = crypto_digest_init_prov(pd, pd->pd_sid,
- mech, ctxp, crq);
- }
-
- if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
- IS_RECOVERABLE(error)) {
- /* Add pd to the linked list of providers tried. */
- if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
- goto retry;
- }
-
- if (list != NULL)
- kcf_free_triedlist(list);
- KCF_PROV_REFRELE(pd);
- return (error);
-}
-
-/*
- * crypto_digest_update()
- *
- * Arguments:
- * context: A crypto_context_t initialized by digest_init().
- * data: The part of message to be digested.
- * cr: crypto_call_req_t calling conditions and call back info.
- *
- * Description:
- * Asynchronously submits a request for, or synchronously performs a
- * part of a message digest operation.
- *
- * Context:
- * Process or interrupt, according to the semantics dictated by the 'cr'.
- *
- * Returns:
- * See comment in the beginning of the file.
- */
-int
-crypto_digest_update(crypto_context_t context, crypto_data_t *data,
- crypto_call_req_t *cr)
-{
- crypto_ctx_t *ctx = (crypto_ctx_t *)context;
- kcf_context_t *kcf_ctx;
- kcf_provider_desc_t *pd;
- int error;
- kcf_req_params_t params;
-
- if ((ctx == NULL) ||
- ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
- ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
- return (CRYPTO_INVALID_CONTEXT);
- }
-
- ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
-
- /* The fast path for SW providers. */
- if (CHECK_FASTPATH(cr, pd)) {
- error = KCF_PROV_DIGEST_UPDATE(pd, ctx, data, NULL);
- KCF_PROV_INCRSTATS(pd, error);
- } else {
- KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_UPDATE,
- ctx->cc_session, NULL, NULL, data, NULL);
- error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
- }
-
- return (error);
-}
-
-/*
- * crypto_digest_final()
- *
- * Arguments:
- * context: A crypto_context_t initialized by digest_init().
- * digest: The storage for the digest.
- * cr: crypto_call_req_t calling conditions and call back info.
- *
- * Description:
- * Asynchronously submits a request for, or synchronously performs the
- * final part of a message digest operation.
- *
- * Context:
- * Process or interrupt, according to the semantics dictated by the 'cr'.
- *
- * Returns:
- * See comment in the beginning of the file.
- */
-int
-crypto_digest_final(crypto_context_t context, crypto_data_t *digest,
- crypto_call_req_t *cr)
-{
- crypto_ctx_t *ctx = (crypto_ctx_t *)context;
- kcf_context_t *kcf_ctx;
- kcf_provider_desc_t *pd;
- int error;
- kcf_req_params_t params;
-
- if ((ctx == NULL) ||
- ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
- ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
- return (CRYPTO_INVALID_CONTEXT);
- }
-
- ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
-
- /* The fast path for SW providers. */
- if (CHECK_FASTPATH(cr, pd)) {
- error = KCF_PROV_DIGEST_FINAL(pd, ctx, digest, NULL);
- KCF_PROV_INCRSTATS(pd, error);
- } else {
- KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_FINAL,
- ctx->cc_session, NULL, NULL, NULL, digest);
- error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
- }
-
- /* Release the hold done in kcf_new_ctx() during init step. */
- KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
- return (error);
-}
-
-/*
- * Performs a digest update on the specified key. Note that there is
- * no k-API crypto_digest_key() equivalent of this function.
- */
-int
-crypto_digest_key_prov(crypto_context_t context, crypto_key_t *key,
- crypto_call_req_t *cr)
-{
- crypto_ctx_t *ctx = (crypto_ctx_t *)context;
- kcf_context_t *kcf_ctx;
- kcf_provider_desc_t *pd;
- int error;
- kcf_req_params_t params;
-
- if ((ctx == NULL) ||
- ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
- ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
- return (CRYPTO_INVALID_CONTEXT);
- }
-
- ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
-
- /* The fast path for SW providers. */
- if (CHECK_FASTPATH(cr, pd)) {
- error = KCF_PROV_DIGEST_KEY(pd, ctx, key, NULL);
- KCF_PROV_INCRSTATS(pd, error);
- } else {
- KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_DIGEST_KEY,
- ctx->cc_session, NULL, key, NULL, NULL);
- error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
- }
-
- return (error);
-}
-
-/*
- * See comments for crypto_digest_update() and crypto_digest_final().
- */
-int
-crypto_digest_single(crypto_context_t context, crypto_data_t *data,
- crypto_data_t *digest, crypto_call_req_t *cr)
-{
- crypto_ctx_t *ctx = (crypto_ctx_t *)context;
- kcf_context_t *kcf_ctx;
- kcf_provider_desc_t *pd;
- int error;
- kcf_req_params_t params;
-
- if ((ctx == NULL) ||
- ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
- ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
- return (CRYPTO_INVALID_CONTEXT);
- }
-
-
- /* The fast path for SW providers. */
- if (CHECK_FASTPATH(cr, pd)) {
- error = KCF_PROV_DIGEST(pd, ctx, data, digest, NULL);
- KCF_PROV_INCRSTATS(pd, error);
- } else {
- KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_SINGLE, pd->pd_sid,
- NULL, NULL, data, digest);
- error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
- }
-
- /* Release the hold done in kcf_new_ctx() during init step. */
- KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
- return (error);
-}
-
-#if defined(_KERNEL)
-EXPORT_SYMBOL(crypto_digest_prov);
-EXPORT_SYMBOL(crypto_digest);
-EXPORT_SYMBOL(crypto_digest_init_prov);
-EXPORT_SYMBOL(crypto_digest_init);
-EXPORT_SYMBOL(crypto_digest_update);
-EXPORT_SYMBOL(crypto_digest_final);
-EXPORT_SYMBOL(crypto_digest_key_prov);
-EXPORT_SYMBOL(crypto_digest_single);
-#endif
diff --git a/sys/contrib/openzfs/module/icp/api/kcf_mac.c b/sys/contrib/openzfs/module/icp/api/kcf_mac.c
index a7722d8f914c..6a72811ea480 100644
--- a/sys/contrib/openzfs/module/icp/api/kcf_mac.c
+++ b/sys/contrib/openzfs/module/icp/api/kcf_mac.c
@@ -40,15 +40,12 @@
* presence of the arguments.
*
* CRYPTO_SUCCESS: The operation completed successfully.
- * CRYPTO_QUEUED: A request was submitted successfully. The callback
- * routine will be called when the operation is done.
* CRYPTO_INVALID_MECH_NUMBER, CRYPTO_INVALID_MECH_PARAM, or
* CRYPTO_INVALID_MECH for problems with the 'mech'.
* CRYPTO_INVALID_DATA for bogus 'data'
* CRYPTO_HOST_MEMORY for failure to allocate memory to handle this work.
* CRYPTO_INVALID_CONTEXT: Not a valid context.
- * CRYPTO_BUSY: Cannot process the request now. Schedule a
- * crypto_bufcall(), or try later.
+ * CRYPTO_BUSY: Cannot process the request now. Try later.
* CRYPTO_NOT_SUPPORTED and CRYPTO_MECH_NOT_SUPPORTED: No provider is
* capable of a function or a mechanism.
* CRYPTO_INVALID_KEY: bogus 'key' argument.
@@ -70,7 +67,6 @@
* tmpl: a crypto_ctx_template_t, opaque template of a context of a
* MAC with the 'mech' using 'key'. 'tmpl' is created by
* a previous call to crypto_create_ctx_template().
- * cr: crypto_call_req_t calling conditions and call back info.
*
* Description:
* Asynchronously submits a request for, or synchronously performs a
@@ -79,55 +75,17 @@
* the specified session id.
* When complete and successful, 'mac' will contain the message
* authentication code.
- *
- * Context:
- * Process or interrupt, according to the semantics dictated by the 'crq'.
+ * Relies on the KCF scheduler to choose a provider.
*
* Returns:
* See comment in the beginning of the file.
*/
int
-crypto_mac_prov(crypto_provider_t provider, crypto_session_id_t sid,
- crypto_mechanism_t *mech, crypto_data_t *data, crypto_key_t *key,
- crypto_ctx_template_t tmpl, crypto_data_t *mac, crypto_call_req_t *crq)
-{
- kcf_req_params_t params;
- kcf_provider_desc_t *pd = provider;
- kcf_provider_desc_t *real_provider = pd;
- int rv;
-
- ASSERT(KCF_PROV_REFHELD(pd));
-
- if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
- rv = kcf_get_hardware_provider(mech->cm_type,
- CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd,
- &real_provider, CRYPTO_FG_MAC_ATOMIC);
-
- if (rv != CRYPTO_SUCCESS)
- return (rv);
- }
-
- KCF_WRAP_MAC_OPS_PARAMS(&params, KCF_OP_ATOMIC, sid, mech, key,
- data, mac, tmpl);
- rv = kcf_submit_request(real_provider, NULL, crq, &params, B_FALSE);
- if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
- KCF_PROV_REFRELE(real_provider);
-
- return (rv);
-}
-
-/*
- * Same as crypto_mac_prov(), but relies on the KCF scheduler to choose
- * a provider. See crypto_mac() comments for more information.
- */
-int
crypto_mac(crypto_mechanism_t *mech, crypto_data_t *data,
- crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *mac,
- crypto_call_req_t *crq)
+ crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *mac)
{
int error;
kcf_mech_entry_t *me;
- kcf_req_params_t params;
kcf_provider_desc_t *pd;
kcf_ctx_template_t *ctx_tmpl;
crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;
@@ -136,187 +94,23 @@ crypto_mac(crypto_mechanism_t *mech, crypto_data_t *data,
retry:
/* The pd is returned held */
if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error,
- list, CRYPTO_FG_MAC_ATOMIC, CHECK_RESTRICT(crq),
- data->cd_length)) == NULL) {
+ list, CRYPTO_FG_MAC_ATOMIC)) == NULL) {
if (list != NULL)
kcf_free_triedlist(list);
return (error);
}
- /*
- * For SW providers, check the validity of the context template
- * It is very rare that the generation number mis-matches, so
- * is acceptable to fail here, and let the consumer recover by
- * freeing this tmpl and create a new one for the key and new SW
- * provider
- */
- if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) &&
- ((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) {
- if (ctx_tmpl->ct_generation != me->me_gen_swprov) {
- if (list != NULL)
- kcf_free_triedlist(list);
- KCF_PROV_REFRELE(pd);
- return (CRYPTO_OLD_CTX_TEMPLATE);
- } else {
- spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
- }
- }
-
- /* The fast path for SW providers. */
- if (CHECK_FASTPATH(crq, pd)) {
- crypto_mechanism_t lmech;
-
- lmech = *mech;
- KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
-
- error = KCF_PROV_MAC_ATOMIC(pd, pd->pd_sid, &lmech, key, data,
- mac, spi_ctx_tmpl, KCF_SWFP_RHNDL(crq));
- KCF_PROV_INCRSTATS(pd, error);
- } else {
- if (pd->pd_prov_type == CRYPTO_HW_PROVIDER &&
- (pd->pd_flags & CRYPTO_HASH_NO_UPDATE) &&
- (data->cd_length > pd->pd_hash_limit)) {
- /*
- * XXX - We need a check to see if this is indeed
- * a HMAC. So far, all kernel clients use
- * this interface only for HMAC. So, this is fine
- * for now.
- */
- error = CRYPTO_BUFFER_TOO_BIG;
- } else {
- KCF_WRAP_MAC_OPS_PARAMS(&params, KCF_OP_ATOMIC,
- pd->pd_sid, mech, key, data, mac, spi_ctx_tmpl);
+ if (((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL))
+ spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
- error = kcf_submit_request(pd, NULL, crq, &params,
- KCF_ISDUALREQ(crq));
- }
- }
+ crypto_mechanism_t lmech = *mech;
+ KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
+ error = KCF_PROV_MAC_ATOMIC(pd, &lmech, key, data,
+ mac, spi_ctx_tmpl);
- if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
- IS_RECOVERABLE(error)) {
+ if (error != CRYPTO_SUCCESS && IS_RECOVERABLE(error)) {
/* Add pd to the linked list of providers tried. */
- if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
- goto retry;
- }
-
- if (list != NULL)
- kcf_free_triedlist(list);
-
- KCF_PROV_REFRELE(pd);
- return (error);
-}
-
-/*
- * Single part operation to compute the MAC corresponding to the specified
- * 'data' and to verify that it matches the MAC specified by 'mac'.
- * The other arguments are the same as the function crypto_mac_prov().
- */
-int
-crypto_mac_verify_prov(crypto_provider_t provider, crypto_session_id_t sid,
- crypto_mechanism_t *mech, crypto_data_t *data, crypto_key_t *key,
- crypto_ctx_template_t tmpl, crypto_data_t *mac, crypto_call_req_t *crq)
-{
- kcf_req_params_t params;
- kcf_provider_desc_t *pd = provider;
- kcf_provider_desc_t *real_provider = pd;
- int rv;
-
- ASSERT(KCF_PROV_REFHELD(pd));
-
- if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
- rv = kcf_get_hardware_provider(mech->cm_type,
- CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd,
- &real_provider, CRYPTO_FG_MAC_ATOMIC);
-
- if (rv != CRYPTO_SUCCESS)
- return (rv);
- }
-
- KCF_WRAP_MAC_OPS_PARAMS(&params, KCF_OP_MAC_VERIFY_ATOMIC, sid, mech,
- key, data, mac, tmpl);
- rv = kcf_submit_request(real_provider, NULL, crq, &params, B_FALSE);
- if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
- KCF_PROV_REFRELE(real_provider);
-
- return (rv);
-}
-
-/*
- * Same as crypto_mac_verify_prov(), but relies on the KCF scheduler to choose
- * a provider. See crypto_mac_verify_prov() comments for more information.
- */
-int
-crypto_mac_verify(crypto_mechanism_t *mech, crypto_data_t *data,
- crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *mac,
- crypto_call_req_t *crq)
-{
- int error;
- kcf_mech_entry_t *me;
- kcf_req_params_t params;
- kcf_provider_desc_t *pd;
- kcf_ctx_template_t *ctx_tmpl;
- crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;
- kcf_prov_tried_t *list = NULL;
-
-retry:
- /* The pd is returned held */
- if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error,
- list, CRYPTO_FG_MAC_ATOMIC, CHECK_RESTRICT(crq),
- data->cd_length)) == NULL) {
- if (list != NULL)
- kcf_free_triedlist(list);
- return (error);
- }
-
- /*
- * For SW providers, check the validity of the context template
- * It is very rare that the generation number mis-matches, so
- * is acceptable to fail here, and let the consumer recover by
- * freeing this tmpl and create a new one for the key and new SW
- * provider
- */
- if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) &&
- ((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) {
- if (ctx_tmpl->ct_generation != me->me_gen_swprov) {
- if (list != NULL)
- kcf_free_triedlist(list);
- KCF_PROV_REFRELE(pd);
- return (CRYPTO_OLD_CTX_TEMPLATE);
- } else {
- spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
- }
- }
-
- /* The fast path for SW providers. */
- if (CHECK_FASTPATH(crq, pd)) {
- crypto_mechanism_t lmech;
-
- lmech = *mech;
- KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
-
- error = KCF_PROV_MAC_VERIFY_ATOMIC(pd, pd->pd_sid, &lmech, key,
- data, mac, spi_ctx_tmpl, KCF_SWFP_RHNDL(crq));
- KCF_PROV_INCRSTATS(pd, error);
- } else {
- if (pd->pd_prov_type == CRYPTO_HW_PROVIDER &&
- (pd->pd_flags & CRYPTO_HASH_NO_UPDATE) &&
- (data->cd_length > pd->pd_hash_limit)) {
- /* see comments in crypto_mac() */
- error = CRYPTO_BUFFER_TOO_BIG;
- } else {
- KCF_WRAP_MAC_OPS_PARAMS(&params,
- KCF_OP_MAC_VERIFY_ATOMIC, pd->pd_sid, mech,
- key, data, mac, spi_ctx_tmpl);
-
- error = kcf_submit_request(pd, NULL, crq, &params,
- KCF_ISDUALREQ(crq));
- }
- }
-
- if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
- IS_RECOVERABLE(error)) {
- /* Add pd to the linked list of providers tried. */
- if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
+ if (kcf_insert_triedlist(&list, pd, KM_SLEEP) != NULL)
goto retry;
}
@@ -333,7 +127,6 @@ retry:
* Arguments:
* pd: pointer to the descriptor of the provider to use for this
* operation.
- * sid: provider session id.
* mech: crypto_mechanism_t pointer.
* mech_type is a valid value previously returned by
* crypto_mech2id();
@@ -344,7 +137,6 @@ retry:
* MAC with the 'mech' using 'key'. 'tmpl' is created by
* a previous call to crypto_create_ctx_template().
* ctxp: Pointer to a crypto_context_t.
- * cr: crypto_call_req_t calling conditions and call back info.
*
* Description:
* Asynchronously submits a request for, or synchronously performs the
@@ -357,61 +149,29 @@ retry:
* The caller should hold a reference on the specified provider
* descriptor before calling this function.
*
- * Context:
- * Process or interrupt, according to the semantics dictated by the 'cr'.
- *
* Returns:
* See comment in the beginning of the file.
*/
-int
-crypto_mac_init_prov(crypto_provider_t provider, crypto_session_id_t sid,
+static int
+crypto_mac_init_prov(kcf_provider_desc_t *pd,
crypto_mechanism_t *mech, crypto_key_t *key, crypto_spi_ctx_template_t tmpl,
- crypto_context_t *ctxp, crypto_call_req_t *crq)
+ crypto_context_t *ctxp)
{
int rv;
crypto_ctx_t *ctx;
- kcf_req_params_t params;
- kcf_provider_desc_t *pd = provider;
kcf_provider_desc_t *real_provider = pd;
ASSERT(KCF_PROV_REFHELD(pd));
- if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
- rv = kcf_get_hardware_provider(mech->cm_type,
- CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd,
- &real_provider, CRYPTO_FG_MAC);
-
- if (rv != CRYPTO_SUCCESS)
- return (rv);
- }
-
/* Allocate and initialize the canonical context */
- if ((ctx = kcf_new_ctx(crq, real_provider, sid)) == NULL) {
- if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
- KCF_PROV_REFRELE(real_provider);
+ if ((ctx = kcf_new_ctx(real_provider)) == NULL)
return (CRYPTO_HOST_MEMORY);
- }
- /* The fast path for SW providers. */
- if (CHECK_FASTPATH(crq, pd)) {
- crypto_mechanism_t lmech;
+ crypto_mechanism_t lmech = *mech;
+ KCF_SET_PROVIDER_MECHNUM(mech->cm_type, real_provider, &lmech);
+ rv = KCF_PROV_MAC_INIT(real_provider, ctx, &lmech, key, tmpl);
- lmech = *mech;
- KCF_SET_PROVIDER_MECHNUM(mech->cm_type, real_provider, &lmech);
- rv = KCF_PROV_MAC_INIT(real_provider, ctx, &lmech, key, tmpl,
- KCF_SWFP_RHNDL(crq));
- KCF_PROV_INCRSTATS(pd, rv);
- } else {
- KCF_WRAP_MAC_OPS_PARAMS(&params, KCF_OP_INIT, sid, mech, key,
- NULL, NULL, tmpl);
- rv = kcf_submit_request(real_provider, ctx, crq, &params,
- B_FALSE);
- }
-
- if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
- KCF_PROV_REFRELE(real_provider);
-
- if ((rv == CRYPTO_SUCCESS) || (rv == CRYPTO_QUEUED))
+ if (rv == CRYPTO_SUCCESS)
*ctxp = (crypto_context_t)ctx;
else {
/* Release the hold done in kcf_new_ctx(). */
@@ -428,8 +188,7 @@ crypto_mac_init_prov(crypto_provider_t provider, crypto_session_id_t sid,
*/
int
crypto_mac_init(crypto_mechanism_t *mech, crypto_key_t *key,
- crypto_ctx_template_t tmpl, crypto_context_t *ctxp,
- crypto_call_req_t *crq)
+ crypto_ctx_template_t tmpl, crypto_context_t *ctxp)
{
int error;
kcf_mech_entry_t *me;
@@ -441,51 +200,27 @@ crypto_mac_init(crypto_mechanism_t *mech, crypto_key_t *key,
retry:
/* The pd is returned held */
if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error,
- list, CRYPTO_FG_MAC, CHECK_RESTRICT(crq), 0)) == NULL) {
+ list, CRYPTO_FG_MAC)) == NULL) {
if (list != NULL)
kcf_free_triedlist(list);
return (error);
}
/*
- * For SW providers, check the validity of the context template
+ * Check the validity of the context template
* It is very rare that the generation number mis-matches, so
* is acceptable to fail here, and let the consumer recover by
- * freeing this tmpl and create a new one for the key and new SW
- * provider
+ * freeing this tmpl and create a new one for the key and new provider
*/
- if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) &&
- ((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) {
- if (ctx_tmpl->ct_generation != me->me_gen_swprov) {
- if (list != NULL)
- kcf_free_triedlist(list);
- KCF_PROV_REFRELE(pd);
- return (CRYPTO_OLD_CTX_TEMPLATE);
- } else {
- spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
- }
- }
+ if (((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL))
+ spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
- if (pd->pd_prov_type == CRYPTO_HW_PROVIDER &&
- (pd->pd_flags & CRYPTO_HASH_NO_UPDATE)) {
- /*
- * The hardware provider has limited HMAC support.
- * So, we fallback early here to using a software provider.
- *
- * XXX - need to enhance to do the fallback later in
- * crypto_mac_update() if the size of accumulated input data
- * exceeds the maximum size digestable by hardware provider.
- */
- error = CRYPTO_BUFFER_TOO_BIG;
- } else {
- error = crypto_mac_init_prov(pd, pd->pd_sid, mech, key,
- spi_ctx_tmpl, ctxp, crq);
- }
- if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
- IS_RECOVERABLE(error)) {
+ error = crypto_mac_init_prov(pd, mech, key,
+ spi_ctx_tmpl, ctxp);
+ if (error != CRYPTO_SUCCESS && IS_RECOVERABLE(error)) {
/* Add pd to the linked list of providers tried. */
- if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
+ if (kcf_insert_triedlist(&list, pd, KM_SLEEP) != NULL)
goto retry;
}
@@ -502,27 +237,19 @@ retry:
* Arguments:
* context: A crypto_context_t initialized by mac_init().
* data: The message part to be MAC'ed
- * cr: crypto_call_req_t calling conditions and call back info.
*
* Description:
- * Asynchronously submits a request for, or synchronously performs a
- * part of a MAC operation.
- *
- * Context:
- * Process or interrupt, according to the semantics dictated by the 'cr'.
+ * Synchronously performs a part of a MAC operation.
*
* Returns:
* See comment in the beginning of the file.
*/
int
-crypto_mac_update(crypto_context_t context, crypto_data_t *data,
- crypto_call_req_t *cr)
+crypto_mac_update(crypto_context_t context, crypto_data_t *data)
{
crypto_ctx_t *ctx = (crypto_ctx_t *)context;
kcf_context_t *kcf_ctx;
kcf_provider_desc_t *pd;
- kcf_req_params_t params;
- int rv;
if ((ctx == NULL) ||
((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
@@ -530,19 +257,7 @@ crypto_mac_update(crypto_context_t context, crypto_data_t *data,
return (CRYPTO_INVALID_CONTEXT);
}
- ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
-
- /* The fast path for SW providers. */
- if (CHECK_FASTPATH(cr, pd)) {
- rv = KCF_PROV_MAC_UPDATE(pd, ctx, data, NULL);
- KCF_PROV_INCRSTATS(pd, rv);
- } else {
- KCF_WRAP_MAC_OPS_PARAMS(&params, KCF_OP_UPDATE,
- ctx->cc_session, NULL, NULL, data, NULL, NULL);
- rv = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
- }
-
- return (rv);
+ return (KCF_PROV_MAC_UPDATE(pd, ctx, data));
}
/*
@@ -551,27 +266,19 @@ crypto_mac_update(crypto_context_t context, crypto_data_t *data,
* Arguments:
* context: A crypto_context_t initialized by mac_init().
* mac: Storage for the message authentication code.
- * cr: crypto_call_req_t calling conditions and call back info.
*
* Description:
- * Asynchronously submits a request for, or synchronously performs a
- * part of a message authentication operation.
- *
- * Context:
- * Process or interrupt, according to the semantics dictated by the 'cr'.
+ * Synchronously performs a part of a message authentication operation.
*
* Returns:
* See comment in the beginning of the file.
*/
int
-crypto_mac_final(crypto_context_t context, crypto_data_t *mac,
- crypto_call_req_t *cr)
+crypto_mac_final(crypto_context_t context, crypto_data_t *mac)
{
crypto_ctx_t *ctx = (crypto_ctx_t *)context;
kcf_context_t *kcf_ctx;
kcf_provider_desc_t *pd;
- kcf_req_params_t params;
- int rv;
if ((ctx == NULL) ||
((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
@@ -579,67 +286,16 @@ crypto_mac_final(crypto_context_t context, crypto_data_t *mac,
return (CRYPTO_INVALID_CONTEXT);
}
- ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
-
- /* The fast path for SW providers. */
- if (CHECK_FASTPATH(cr, pd)) {
- rv = KCF_PROV_MAC_FINAL(pd, ctx, mac, NULL);
- KCF_PROV_INCRSTATS(pd, rv);
- } else {
- KCF_WRAP_MAC_OPS_PARAMS(&params, KCF_OP_FINAL,
- ctx->cc_session, NULL, NULL, NULL, mac, NULL);
- rv = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
- }
+ int rv = KCF_PROV_MAC_FINAL(pd, ctx, mac);
/* Release the hold done in kcf_new_ctx() during init step. */
KCF_CONTEXT_COND_RELEASE(rv, kcf_ctx);
return (rv);
}
-/*
- * See comments for crypto_mac_update() and crypto_mac_final().
- */
-int
-crypto_mac_single(crypto_context_t context, crypto_data_t *data,
- crypto_data_t *mac, crypto_call_req_t *cr)
-{
- crypto_ctx_t *ctx = (crypto_ctx_t *)context;
- kcf_context_t *kcf_ctx;
- kcf_provider_desc_t *pd;
- int error;
- kcf_req_params_t params;
-
-
- if ((ctx == NULL) ||
- ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
- ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
- return (CRYPTO_INVALID_CONTEXT);
- }
-
-
- /* The fast path for SW providers. */
- if (CHECK_FASTPATH(cr, pd)) {
- error = KCF_PROV_MAC(pd, ctx, data, mac, NULL);
- KCF_PROV_INCRSTATS(pd, error);
- } else {
- KCF_WRAP_MAC_OPS_PARAMS(&params, KCF_OP_SINGLE, pd->pd_sid,
- NULL, NULL, data, mac, NULL);
- error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
- }
-
- /* Release the hold done in kcf_new_ctx() during init step. */
- KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
- return (error);
-}
-
#if defined(_KERNEL)
-EXPORT_SYMBOL(crypto_mac_prov);
EXPORT_SYMBOL(crypto_mac);
-EXPORT_SYMBOL(crypto_mac_verify_prov);
-EXPORT_SYMBOL(crypto_mac_verify);
-EXPORT_SYMBOL(crypto_mac_init_prov);
EXPORT_SYMBOL(crypto_mac_init);
EXPORT_SYMBOL(crypto_mac_update);
EXPORT_SYMBOL(crypto_mac_final);
-EXPORT_SYMBOL(crypto_mac_single);
#endif
diff --git a/sys/contrib/openzfs/module/icp/api/kcf_miscapi.c b/sys/contrib/openzfs/module/icp/api/kcf_miscapi.c
deleted file mode 100644
index 5c0d60391f44..000000000000
--- a/sys/contrib/openzfs/module/icp/api/kcf_miscapi.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * 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 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#include <sys/zfs_context.h>
-#include <sys/crypto/common.h>
-#include <sys/crypto/api.h>
-#include <sys/crypto/impl.h>
-#include <sys/crypto/sched_impl.h>
-
-/*
- * All event subscribers are put on a list. kcf_notify_list_lock
- * protects changes to this list.
- *
- * The following locking order is maintained in the code - The
- * global kcf_notify_list_lock followed by the individual lock
- * in a kcf_ntfy_elem structure (kn_lock).
- */
-kmutex_t ntfy_list_lock;
-kcondvar_t ntfy_list_cv; /* cv the service thread waits on */
-static kcf_ntfy_elem_t *ntfy_list_head;
-
-/*
- * crypto_mech2id()
- *
- * Arguments:
- * . mechname: A null-terminated string identifying the mechanism name.
- *
- * Description:
- * Walks the mechanisms tables, looking for an entry that matches the
- * mechname. Once it find it, it builds the 64-bit mech_type and returns
- * it. If there are no hardware or software providers for the mechanism,
- * but there is an unloaded software provider, this routine will attempt
- * to load it.
- *
- * Context:
- * Process and interruption.
- *
- * Returns:
- * The unique mechanism identified by 'mechname', if found.
- * CRYPTO_MECH_INVALID otherwise.
- */
-crypto_mech_type_t
-crypto_mech2id(const char *mechname)
-{
- return (crypto_mech2id_common(mechname, B_TRUE));
-}
-
-/*
- * We walk the notification list and do the callbacks.
- */
-void
-kcf_walk_ntfylist(uint32_t event, void *event_arg)
-{
- kcf_ntfy_elem_t *nep;
- int nelem = 0;
-
- mutex_enter(&ntfy_list_lock);
-
- /*
- * Count how many clients are on the notification list. We need
- * this count to ensure that clients which joined the list after we
- * have started this walk, are not wrongly notified.
- */
- for (nep = ntfy_list_head; nep != NULL; nep = nep->kn_next)
- nelem++;
-
- for (nep = ntfy_list_head; (nep != NULL && nelem); nep = nep->kn_next) {
- nelem--;
-
- /*
- * Check if this client is interested in the
- * event.
- */
- if (!(nep->kn_event_mask & event))
- continue;
-
- mutex_enter(&nep->kn_lock);
- nep->kn_state = NTFY_RUNNING;
- mutex_exit(&nep->kn_lock);
- mutex_exit(&ntfy_list_lock);
-
- /*
- * We invoke the callback routine with no locks held. Another
- * client could have joined the list meanwhile. This is fine
- * as we maintain nelem as stated above. The NULL check in the
- * for loop guards against shrinkage. Also, any callers of
- * crypto_unnotify_events() at this point cv_wait till kn_state
- * changes to NTFY_WAITING. Hence, nep is assured to be valid.
- */
- (*nep->kn_func)(event, event_arg);
-
- mutex_enter(&nep->kn_lock);
- nep->kn_state = NTFY_WAITING;
- cv_broadcast(&nep->kn_cv);
- mutex_exit(&nep->kn_lock);
-
- mutex_enter(&ntfy_list_lock);
- }
-
- mutex_exit(&ntfy_list_lock);
-}
-
-#if defined(_KERNEL)
-EXPORT_SYMBOL(crypto_mech2id);
-#endif
diff --git a/sys/contrib/openzfs/module/icp/core/kcf_callprov.c b/sys/contrib/openzfs/module/icp/core/kcf_callprov.c
index 345014d0a1e4..b5ef5f111d50 100644
--- a/sys/contrib/openzfs/module/icp/core/kcf_callprov.c
+++ b/sys/contrib/openzfs/module/icp/core/kcf_callprov.c
@@ -27,9 +27,6 @@
#include <sys/crypto/impl.h>
#include <sys/crypto/sched_impl.h>
-static int kcf_emulate_dual(kcf_provider_desc_t *, crypto_ctx_t *,
- kcf_req_params_t *);
-
void
kcf_free_triedlist(kcf_prov_tried_t *list)
{
@@ -72,168 +69,6 @@ is_in_triedlist(kcf_provider_desc_t *pd, kcf_prov_tried_t *triedl)
}
/*
- * Search a mech entry's hardware provider list for the specified
- * provider. Return true if found.
- */
-static boolean_t
-is_valid_provider_for_mech(kcf_provider_desc_t *pd, kcf_mech_entry_t *me,
- crypto_func_group_t fg)
-{
- kcf_prov_mech_desc_t *prov_chain;
-
- prov_chain = me->me_hw_prov_chain;
- if (prov_chain != NULL) {
- ASSERT(me->me_num_hwprov > 0);
- for (; prov_chain != NULL; prov_chain = prov_chain->pm_next) {
- if (prov_chain->pm_prov_desc == pd &&
- IS_FG_SUPPORTED(prov_chain, fg)) {
- return (B_TRUE);
- }
- }
- }
- return (B_FALSE);
-}
-
-/*
- * This routine, given a logical provider, returns the least loaded
- * provider belonging to the logical provider. The provider must be
- * able to do the specified mechanism, i.e. check that the mechanism
- * hasn't been disabled. In addition, just in case providers are not
- * entirely equivalent, the provider's entry point is checked for
- * non-nullness. This is accomplished by having the caller pass, as
- * arguments, the offset of the function group (offset_1), and the
- * offset of the function within the function group (offset_2).
- * Returns NULL if no provider can be found.
- */
-int
-kcf_get_hardware_provider(crypto_mech_type_t mech_type_1,
- crypto_mech_type_t mech_type_2, boolean_t call_restrict,
- kcf_provider_desc_t *old, kcf_provider_desc_t **new, crypto_func_group_t fg)
-{
- kcf_provider_desc_t *provider, *real_pd = old;
- kcf_provider_desc_t *gpd = NULL; /* good provider */
- kcf_provider_desc_t *bpd = NULL; /* busy provider */
- kcf_provider_list_t *p;
- kcf_ops_class_t class;
- kcf_mech_entry_t *me;
- const kcf_mech_entry_tab_t *me_tab;
- int index, len, gqlen = INT_MAX, rv = CRYPTO_SUCCESS;
-
- /* get the mech entry for the specified mechanism */
- class = KCF_MECH2CLASS(mech_type_1);
- if ((class < KCF_FIRST_OPSCLASS) || (class > KCF_LAST_OPSCLASS)) {
- return (CRYPTO_MECHANISM_INVALID);
- }
-
- me_tab = &kcf_mech_tabs_tab[class];
- index = KCF_MECH2INDEX(mech_type_1);
- if ((index < 0) || (index >= me_tab->met_size)) {
- return (CRYPTO_MECHANISM_INVALID);
- }
-
- me = &((me_tab->met_tab)[index]);
- mutex_enter(&me->me_mutex);
-
- /*
- * We assume the provider descriptor will not go away because
- * it is being held somewhere, i.e. its reference count has been
- * incremented. In the case of the crypto module, the provider
- * descriptor is held by the session structure.
- */
- if (old->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
- if (old->pd_provider_list == NULL) {
- real_pd = NULL;
- rv = CRYPTO_DEVICE_ERROR;
- goto out;
- }
- /*
- * Find the least loaded real provider. KCF_PROV_LOAD gives
- * the load (number of pending requests) of the provider.
- */
- mutex_enter(&old->pd_lock);
- p = old->pd_provider_list;
- while (p != NULL) {
- provider = p->pl_provider;
-
- ASSERT(provider->pd_prov_type !=
- CRYPTO_LOGICAL_PROVIDER);
-
- if (call_restrict &&
- (provider->pd_flags & KCF_PROV_RESTRICTED)) {
- p = p->pl_next;
- continue;
- }
-
- if (!is_valid_provider_for_mech(provider, me, fg)) {
- p = p->pl_next;
- continue;
- }
-
- /* provider does second mech */
- if (mech_type_2 != CRYPTO_MECH_INVALID) {
- int i;
-
- i = KCF_TO_PROV_MECH_INDX(provider,
- mech_type_2);
- if (i == KCF_INVALID_INDX) {
- p = p->pl_next;
- continue;
- }
- }
-
- if (provider->pd_state != KCF_PROV_READY) {
- /* choose BUSY if no READY providers */
- if (provider->pd_state == KCF_PROV_BUSY)
- bpd = provider;
- p = p->pl_next;
- continue;
- }
-
- len = KCF_PROV_LOAD(provider);
- if (len < gqlen) {
- gqlen = len;
- gpd = provider;
- }
-
- p = p->pl_next;
- }
-
- if (gpd != NULL) {
- real_pd = gpd;
- KCF_PROV_REFHOLD(real_pd);
- } else if (bpd != NULL) {
- real_pd = bpd;
- KCF_PROV_REFHOLD(real_pd);
- } else {
- /* can't find provider */
- real_pd = NULL;
- rv = CRYPTO_MECHANISM_INVALID;
- }
- mutex_exit(&old->pd_lock);
-
- } else {
- if (!KCF_IS_PROV_USABLE(old) ||
- (call_restrict && (old->pd_flags & KCF_PROV_RESTRICTED))) {
- real_pd = NULL;
- rv = CRYPTO_DEVICE_ERROR;
- goto out;
- }
-
- if (!is_valid_provider_for_mech(old, me, fg)) {
- real_pd = NULL;
- rv = CRYPTO_MECHANISM_INVALID;
- goto out;
- }
-
- KCF_PROV_REFHOLD(real_pd);
- }
-out:
- mutex_exit(&me->me_mutex);
- *new = real_pd;
- return (rv);
-}
-
-/*
* Return the best provider for the specified mechanism. The provider
* is held and it is the caller's responsibility to release it when done.
* The fg input argument is used as a search criterion to pick a provider.
@@ -243,18 +78,13 @@ out:
* search to find one. This is fine as we assume there are only a few
* number of providers in this list. If this assumption ever changes,
* we should revisit this.
- *
- * call_restrict represents if the caller should not be allowed to
- * use restricted providers.
*/
kcf_provider_desc_t *
kcf_get_mech_provider(crypto_mech_type_t mech_type, kcf_mech_entry_t **mepp,
- int *error, kcf_prov_tried_t *triedl, crypto_func_group_t fg,
- boolean_t call_restrict, size_t data_size)
+ int *error, kcf_prov_tried_t *triedl, crypto_func_group_t fg)
{
- kcf_provider_desc_t *pd = NULL, *gpd = NULL;
- kcf_prov_mech_desc_t *prov_chain, *mdesc;
- int len, gqlen = INT_MAX;
+ kcf_provider_desc_t *pd = NULL;
+ kcf_prov_mech_desc_t *mdesc;
kcf_ops_class_t class;
int index;
kcf_mech_entry_t *me;
@@ -277,58 +107,12 @@ kcf_get_mech_provider(crypto_mech_type_t mech_type, kcf_mech_entry_t **mepp,
if (mepp != NULL)
*mepp = me;
- mutex_enter(&me->me_mutex);
-
- prov_chain = me->me_hw_prov_chain;
-
- /*
- * We check for the threshold for using a hardware provider for
- * this amount of data. If there is no software provider available
- * for the mechanism, then the threshold is ignored.
- */
- if ((prov_chain != NULL) &&
- ((data_size == 0) || (me->me_threshold == 0) ||
- (data_size >= me->me_threshold) ||
- ((mdesc = me->me_sw_prov) == NULL) ||
- (!IS_FG_SUPPORTED(mdesc, fg)) ||
- (!KCF_IS_PROV_USABLE(mdesc->pm_prov_desc)))) {
- ASSERT(me->me_num_hwprov > 0);
- /* there is at least one provider */
-
- /*
- * Find the least loaded real provider. KCF_PROV_LOAD gives
- * the load (number of pending requests) of the provider.
- */
- while (prov_chain != NULL) {
- pd = prov_chain->pm_prov_desc;
-
- if (!IS_FG_SUPPORTED(prov_chain, fg) ||
- !KCF_IS_PROV_USABLE(pd) ||
- IS_PROVIDER_TRIED(pd, triedl) ||
- (call_restrict &&
- (pd->pd_flags & KCF_PROV_RESTRICTED))) {
- prov_chain = prov_chain->pm_next;
- continue;
- }
-
- if ((len = KCF_PROV_LOAD(pd)) < gqlen) {
- gqlen = len;
- gpd = pd;
- }
-
- prov_chain = prov_chain->pm_next;
- }
-
- pd = gpd;
- }
-
- /* No HW provider for this mech, is there a SW provider? */
+ /* Is there a provider? */
if (pd == NULL && (mdesc = me->me_sw_prov) != NULL) {
pd = mdesc->pm_prov_desc;
if (!IS_FG_SUPPORTED(mdesc, fg) ||
!KCF_IS_PROV_USABLE(pd) ||
- IS_PROVIDER_TRIED(pd, triedl) ||
- (call_restrict && (pd->pd_flags & KCF_PROV_RESTRICTED)))
+ IS_PROVIDER_TRIED(pd, triedl))
pd = NULL;
}
@@ -344,1224 +128,5 @@ kcf_get_mech_provider(crypto_mech_type_t mech_type, kcf_mech_entry_t **mepp,
} else
KCF_PROV_REFHOLD(pd);
- mutex_exit(&me->me_mutex);
return (pd);
}
-
-/*
- * Very similar to kcf_get_mech_provider(). Finds the best provider capable of
- * a dual operation with both me1 and me2.
- * When no dual-ops capable providers are available, return the best provider
- * for me1 only, and sets *prov_mt2 to CRYPTO_INVALID_MECHID;
- * We assume/expect that a slower HW capable of the dual is still
- * faster than the 2 fastest providers capable of the individual ops
- * separately.
- */
-kcf_provider_desc_t *
-kcf_get_dual_provider(crypto_mechanism_t *mech1, crypto_mechanism_t *mech2,
- kcf_mech_entry_t **mepp, crypto_mech_type_t *prov_mt1,
- crypto_mech_type_t *prov_mt2, int *error, kcf_prov_tried_t *triedl,
- crypto_func_group_t fg1, crypto_func_group_t fg2, boolean_t call_restrict,
- size_t data_size)
-{
- kcf_provider_desc_t *pd = NULL, *pdm1 = NULL, *pdm1m2 = NULL;
- kcf_prov_mech_desc_t *prov_chain, *mdesc;
- int len, gqlen = INT_MAX, dgqlen = INT_MAX;
- crypto_mech_info_list_t *mil;
- crypto_mech_type_t m2id = mech2->cm_type;
- kcf_mech_entry_t *me;
-
- /* when mech is a valid mechanism, me will be its mech_entry */
- if (kcf_get_mech_entry(mech1->cm_type, &me) != KCF_SUCCESS) {
- *error = CRYPTO_MECHANISM_INVALID;
- return (NULL);
- }
-
- *prov_mt2 = CRYPTO_MECH_INVALID;
-
- if (mepp != NULL)
- *mepp = me;
- mutex_enter(&me->me_mutex);
-
- prov_chain = me->me_hw_prov_chain;
- /*
- * We check the threshold for using a hardware provider for
- * this amount of data. If there is no software provider available
- * for the first mechanism, then the threshold is ignored.
- */
- if ((prov_chain != NULL) &&
- ((data_size == 0) || (me->me_threshold == 0) ||
- (data_size >= me->me_threshold) ||
- ((mdesc = me->me_sw_prov) == NULL) ||
- (!IS_FG_SUPPORTED(mdesc, fg1)) ||
- (!KCF_IS_PROV_USABLE(mdesc->pm_prov_desc)))) {
- /* there is at least one provider */
- ASSERT(me->me_num_hwprov > 0);
-
- /*
- * Find the least loaded provider capable of the combo
- * me1 + me2, and save a pointer to the least loaded
- * provider capable of me1 only.
- */
- while (prov_chain != NULL) {
- pd = prov_chain->pm_prov_desc;
- len = KCF_PROV_LOAD(pd);
-
- if (!IS_FG_SUPPORTED(prov_chain, fg1) ||
- !KCF_IS_PROV_USABLE(pd) ||
- IS_PROVIDER_TRIED(pd, triedl) ||
- (call_restrict &&
- (pd->pd_flags & KCF_PROV_RESTRICTED))) {
- prov_chain = prov_chain->pm_next;
- continue;
- }
-
- /* Save the best provider capable of m1 */
- if (len < gqlen) {
- *prov_mt1 =
- prov_chain->pm_mech_info.cm_mech_number;
- gqlen = len;
- pdm1 = pd;
- }
-
- /* See if pd can do me2 too */
- for (mil = prov_chain->pm_mi_list;
- mil != NULL; mil = mil->ml_next) {
- if ((mil->ml_mech_info.cm_func_group_mask &
- fg2) == 0)
- continue;
-
- if ((mil->ml_kcf_mechid == m2id) &&
- (len < dgqlen)) {
- /* Bingo! */
- dgqlen = len;
- pdm1m2 = pd;
- *prov_mt2 =
- mil->ml_mech_info.cm_mech_number;
- *prov_mt1 = prov_chain->
- pm_mech_info.cm_mech_number;
- break;
- }
- }
-
- prov_chain = prov_chain->pm_next;
- }
-
- pd = (pdm1m2 != NULL) ? pdm1m2 : pdm1;
- }
-
- /* no HW provider for this mech, is there a SW provider? */
- if (pd == NULL && (mdesc = me->me_sw_prov) != NULL) {
- pd = mdesc->pm_prov_desc;
- if (!IS_FG_SUPPORTED(mdesc, fg1) ||
- !KCF_IS_PROV_USABLE(pd) ||
- IS_PROVIDER_TRIED(pd, triedl) ||
- (call_restrict && (pd->pd_flags & KCF_PROV_RESTRICTED)))
- pd = NULL;
- else {
- /* See if pd can do me2 too */
- for (mil = me->me_sw_prov->pm_mi_list;
- mil != NULL; mil = mil->ml_next) {
- if ((mil->ml_mech_info.cm_func_group_mask &
- fg2) == 0)
- continue;
-
- if (mil->ml_kcf_mechid == m2id) {
- /* Bingo! */
- *prov_mt2 =
- mil->ml_mech_info.cm_mech_number;
- break;
- }
- }
- *prov_mt1 = me->me_sw_prov->pm_mech_info.cm_mech_number;
- }
- }
-
- if (pd == NULL)
- *error = CRYPTO_MECH_NOT_SUPPORTED;
- else
- KCF_PROV_REFHOLD(pd);
-
- mutex_exit(&me->me_mutex);
- return (pd);
-}
-
-/*
- * Do the actual work of calling the provider routines.
- *
- * pd - Provider structure
- * ctx - Context for this operation
- * params - Parameters for this operation
- * rhndl - Request handle to use for notification
- *
- * The return values are the same as that of the respective SPI.
- */
-int
-common_submit_request(kcf_provider_desc_t *pd, crypto_ctx_t *ctx,
- kcf_req_params_t *params, crypto_req_handle_t rhndl)
-{
- int err = CRYPTO_ARGUMENTS_BAD;
- kcf_op_type_t optype;
-
- optype = params->rp_optype;
-
- switch (params->rp_opgrp) {
- case KCF_OG_DIGEST: {
- kcf_digest_ops_params_t *dops = &params->rp_u.digest_params;
-
- switch (optype) {
- case KCF_OP_INIT:
- /*
- * We should do this only here and not in KCF_WRAP_*
- * macros. This is because we may want to try other
- * providers, in case we recover from a failure.
- */
- KCF_SET_PROVIDER_MECHNUM(dops->do_framework_mechtype,
- pd, &dops->do_mech);
-
- err = KCF_PROV_DIGEST_INIT(pd, ctx, &dops->do_mech,
- rhndl);
- break;
-
- case KCF_OP_SINGLE:
- err = KCF_PROV_DIGEST(pd, ctx, dops->do_data,
- dops->do_digest, rhndl);
- break;
-
- case KCF_OP_UPDATE:
- err = KCF_PROV_DIGEST_UPDATE(pd, ctx,
- dops->do_data, rhndl);
- break;
-
- case KCF_OP_FINAL:
- err = KCF_PROV_DIGEST_FINAL(pd, ctx,
- dops->do_digest, rhndl);
- break;
-
- case KCF_OP_ATOMIC:
- ASSERT(ctx == NULL);
- KCF_SET_PROVIDER_MECHNUM(dops->do_framework_mechtype,
- pd, &dops->do_mech);
- err = KCF_PROV_DIGEST_ATOMIC(pd, dops->do_sid,
- &dops->do_mech, dops->do_data, dops->do_digest,
- rhndl);
- break;
-
- case KCF_OP_DIGEST_KEY:
- err = KCF_PROV_DIGEST_KEY(pd, ctx, dops->do_digest_key,
- rhndl);
- break;
-
- default:
- break;
- }
- break;
- }
-
- case KCF_OG_MAC: {
- kcf_mac_ops_params_t *mops = &params->rp_u.mac_params;
-
- switch (optype) {
- case KCF_OP_INIT:
- KCF_SET_PROVIDER_MECHNUM(mops->mo_framework_mechtype,
- pd, &mops->mo_mech);
-
- err = KCF_PROV_MAC_INIT(pd, ctx, &mops->mo_mech,
- mops->mo_key, mops->mo_templ, rhndl);
- break;
-
- case KCF_OP_SINGLE:
- err = KCF_PROV_MAC(pd, ctx, mops->mo_data,
- mops->mo_mac, rhndl);
- break;
-
- case KCF_OP_UPDATE:
- err = KCF_PROV_MAC_UPDATE(pd, ctx, mops->mo_data,
- rhndl);
- break;
-
- case KCF_OP_FINAL:
- err = KCF_PROV_MAC_FINAL(pd, ctx, mops->mo_mac, rhndl);
- break;
-
- case KCF_OP_ATOMIC:
- ASSERT(ctx == NULL);
- KCF_SET_PROVIDER_MECHNUM(mops->mo_framework_mechtype,
- pd, &mops->mo_mech);
-
- err = KCF_PROV_MAC_ATOMIC(pd, mops->mo_sid,
- &mops->mo_mech, mops->mo_key, mops->mo_data,
- mops->mo_mac, mops->mo_templ, rhndl);
- break;
-
- case KCF_OP_MAC_VERIFY_ATOMIC:
- ASSERT(ctx == NULL);
- KCF_SET_PROVIDER_MECHNUM(mops->mo_framework_mechtype,
- pd, &mops->mo_mech);
-
- err = KCF_PROV_MAC_VERIFY_ATOMIC(pd, mops->mo_sid,
- &mops->mo_mech, mops->mo_key, mops->mo_data,
- mops->mo_mac, mops->mo_templ, rhndl);
- break;
-
- default:
- break;
- }
- break;
- }
-
- case KCF_OG_ENCRYPT: {
- kcf_encrypt_ops_params_t *eops = &params->rp_u.encrypt_params;
-
- switch (optype) {
- case KCF_OP_INIT:
- KCF_SET_PROVIDER_MECHNUM(eops->eo_framework_mechtype,
- pd, &eops->eo_mech);
-
- err = KCF_PROV_ENCRYPT_INIT(pd, ctx, &eops->eo_mech,
- eops->eo_key, eops->eo_templ, rhndl);
- break;
-
- case KCF_OP_SINGLE:
- err = KCF_PROV_ENCRYPT(pd, ctx, eops->eo_plaintext,
- eops->eo_ciphertext, rhndl);
- break;
-
- case KCF_OP_UPDATE:
- err = KCF_PROV_ENCRYPT_UPDATE(pd, ctx,
- eops->eo_plaintext, eops->eo_ciphertext, rhndl);
- break;
-
- case KCF_OP_FINAL:
- err = KCF_PROV_ENCRYPT_FINAL(pd, ctx,
- eops->eo_ciphertext, rhndl);
- break;
-
- case KCF_OP_ATOMIC:
- ASSERT(ctx == NULL);
- KCF_SET_PROVIDER_MECHNUM(eops->eo_framework_mechtype,
- pd, &eops->eo_mech);
-
- err = KCF_PROV_ENCRYPT_ATOMIC(pd, eops->eo_sid,
- &eops->eo_mech, eops->eo_key, eops->eo_plaintext,
- eops->eo_ciphertext, eops->eo_templ, rhndl);
- break;
-
- default:
- break;
- }
- break;
- }
-
- case KCF_OG_DECRYPT: {
- kcf_decrypt_ops_params_t *dcrops = &params->rp_u.decrypt_params;
-
- switch (optype) {
- case KCF_OP_INIT:
- KCF_SET_PROVIDER_MECHNUM(dcrops->dop_framework_mechtype,
- pd, &dcrops->dop_mech);
-
- err = KCF_PROV_DECRYPT_INIT(pd, ctx, &dcrops->dop_mech,
- dcrops->dop_key, dcrops->dop_templ, rhndl);
- break;
-
- case KCF_OP_SINGLE:
- err = KCF_PROV_DECRYPT(pd, ctx, dcrops->dop_ciphertext,
- dcrops->dop_plaintext, rhndl);
- break;
-
- case KCF_OP_UPDATE:
- err = KCF_PROV_DECRYPT_UPDATE(pd, ctx,
- dcrops->dop_ciphertext, dcrops->dop_plaintext,
- rhndl);
- break;
-
- case KCF_OP_FINAL:
- err = KCF_PROV_DECRYPT_FINAL(pd, ctx,
- dcrops->dop_plaintext, rhndl);
- break;
-
- case KCF_OP_ATOMIC:
- ASSERT(ctx == NULL);
- KCF_SET_PROVIDER_MECHNUM(dcrops->dop_framework_mechtype,
- pd, &dcrops->dop_mech);
-
- err = KCF_PROV_DECRYPT_ATOMIC(pd, dcrops->dop_sid,
- &dcrops->dop_mech, dcrops->dop_key,
- dcrops->dop_ciphertext, dcrops->dop_plaintext,
- dcrops->dop_templ, rhndl);
- break;
-
- default:
- break;
- }
- break;
- }
-
- case KCF_OG_SIGN: {
- kcf_sign_ops_params_t *sops = &params->rp_u.sign_params;
-
- switch (optype) {
- case KCF_OP_INIT:
- KCF_SET_PROVIDER_MECHNUM(sops->so_framework_mechtype,
- pd, &sops->so_mech);
-
- err = KCF_PROV_SIGN_INIT(pd, ctx, &sops->so_mech,
- sops->so_key, sops->so_templ, rhndl);
- break;
-
- case KCF_OP_SIGN_RECOVER_INIT:
- KCF_SET_PROVIDER_MECHNUM(sops->so_framework_mechtype,
- pd, &sops->so_mech);
-
- err = KCF_PROV_SIGN_RECOVER_INIT(pd, ctx,
- &sops->so_mech, sops->so_key, sops->so_templ,
- rhndl);
- break;
-
- case KCF_OP_SINGLE:
- err = KCF_PROV_SIGN(pd, ctx, sops->so_data,
- sops->so_signature, rhndl);
- break;
-
- case KCF_OP_SIGN_RECOVER:
- err = KCF_PROV_SIGN_RECOVER(pd, ctx,
- sops->so_data, sops->so_signature, rhndl);
- break;
-
- case KCF_OP_UPDATE:
- err = KCF_PROV_SIGN_UPDATE(pd, ctx, sops->so_data,
- rhndl);
- break;
-
- case KCF_OP_FINAL:
- err = KCF_PROV_SIGN_FINAL(pd, ctx, sops->so_signature,
- rhndl);
- break;
-
- case KCF_OP_ATOMIC:
- ASSERT(ctx == NULL);
- KCF_SET_PROVIDER_MECHNUM(sops->so_framework_mechtype,
- pd, &sops->so_mech);
-
- err = KCF_PROV_SIGN_ATOMIC(pd, sops->so_sid,
- &sops->so_mech, sops->so_key, sops->so_data,
- sops->so_templ, sops->so_signature, rhndl);
- break;
-
- case KCF_OP_SIGN_RECOVER_ATOMIC:
- ASSERT(ctx == NULL);
- KCF_SET_PROVIDER_MECHNUM(sops->so_framework_mechtype,
- pd, &sops->so_mech);
-
- err = KCF_PROV_SIGN_RECOVER_ATOMIC(pd, sops->so_sid,
- &sops->so_mech, sops->so_key, sops->so_data,
- sops->so_templ, sops->so_signature, rhndl);
- break;
-
- default:
- break;
- }
- break;
- }
-
- case KCF_OG_VERIFY: {
- kcf_verify_ops_params_t *vops = &params->rp_u.verify_params;
-
- switch (optype) {
- case KCF_OP_INIT:
- KCF_SET_PROVIDER_MECHNUM(vops->vo_framework_mechtype,
- pd, &vops->vo_mech);
-
- err = KCF_PROV_VERIFY_INIT(pd, ctx, &vops->vo_mech,
- vops->vo_key, vops->vo_templ, rhndl);
- break;
-
- case KCF_OP_VERIFY_RECOVER_INIT:
- KCF_SET_PROVIDER_MECHNUM(vops->vo_framework_mechtype,
- pd, &vops->vo_mech);
-
- err = KCF_PROV_VERIFY_RECOVER_INIT(pd, ctx,
- &vops->vo_mech, vops->vo_key, vops->vo_templ,
- rhndl);
- break;
-
- case KCF_OP_SINGLE:
- err = KCF_PROV_VERIFY(pd, ctx, vops->vo_data,
- vops->vo_signature, rhndl);
- break;
-
- case KCF_OP_VERIFY_RECOVER:
- err = KCF_PROV_VERIFY_RECOVER(pd, ctx,
- vops->vo_signature, vops->vo_data, rhndl);
- break;
-
- case KCF_OP_UPDATE:
- err = KCF_PROV_VERIFY_UPDATE(pd, ctx, vops->vo_data,
- rhndl);
- break;
-
- case KCF_OP_FINAL:
- err = KCF_PROV_VERIFY_FINAL(pd, ctx, vops->vo_signature,
- rhndl);
- break;
-
- case KCF_OP_ATOMIC:
- ASSERT(ctx == NULL);
- KCF_SET_PROVIDER_MECHNUM(vops->vo_framework_mechtype,
- pd, &vops->vo_mech);
-
- err = KCF_PROV_VERIFY_ATOMIC(pd, vops->vo_sid,
- &vops->vo_mech, vops->vo_key, vops->vo_data,
- vops->vo_templ, vops->vo_signature, rhndl);
- break;
-
- case KCF_OP_VERIFY_RECOVER_ATOMIC:
- ASSERT(ctx == NULL);
- KCF_SET_PROVIDER_MECHNUM(vops->vo_framework_mechtype,
- pd, &vops->vo_mech);
-
- err = KCF_PROV_VERIFY_RECOVER_ATOMIC(pd, vops->vo_sid,
- &vops->vo_mech, vops->vo_key, vops->vo_signature,
- vops->vo_templ, vops->vo_data, rhndl);
- break;
-
- default:
- break;
- }
- break;
- }
-
- case KCF_OG_ENCRYPT_MAC: {
- kcf_encrypt_mac_ops_params_t *eops =
- &params->rp_u.encrypt_mac_params;
- kcf_context_t *kcf_secondctx;
-
- switch (optype) {
- case KCF_OP_INIT:
- kcf_secondctx = ((kcf_context_t *)
- (ctx->cc_framework_private))->kc_secondctx;
-
- if (kcf_secondctx != NULL) {
- err = kcf_emulate_dual(pd, ctx, params);
- break;
- }
- KCF_SET_PROVIDER_MECHNUM(
- eops->em_framework_encr_mechtype,
- pd, &eops->em_encr_mech);
-
- KCF_SET_PROVIDER_MECHNUM(
- eops->em_framework_mac_mechtype,
- pd, &eops->em_mac_mech);
-
- err = KCF_PROV_ENCRYPT_MAC_INIT(pd, ctx,
- &eops->em_encr_mech, eops->em_encr_key,
- &eops->em_mac_mech, eops->em_mac_key,
- eops->em_encr_templ, eops->em_mac_templ,
- rhndl);
-
- break;
-
- case KCF_OP_SINGLE:
- err = KCF_PROV_ENCRYPT_MAC(pd, ctx,
- eops->em_plaintext, eops->em_ciphertext,
- eops->em_mac, rhndl);
- break;
-
- case KCF_OP_UPDATE:
- kcf_secondctx = ((kcf_context_t *)
- (ctx->cc_framework_private))->kc_secondctx;
- if (kcf_secondctx != NULL) {
- err = kcf_emulate_dual(pd, ctx, params);
- break;
- }
- err = KCF_PROV_ENCRYPT_MAC_UPDATE(pd, ctx,
- eops->em_plaintext, eops->em_ciphertext, rhndl);
- break;
-
- case KCF_OP_FINAL:
- kcf_secondctx = ((kcf_context_t *)
- (ctx->cc_framework_private))->kc_secondctx;
- if (kcf_secondctx != NULL) {
- err = kcf_emulate_dual(pd, ctx, params);
- break;
- }
- err = KCF_PROV_ENCRYPT_MAC_FINAL(pd, ctx,
- eops->em_ciphertext, eops->em_mac, rhndl);
- break;
-
- case KCF_OP_ATOMIC:
- ASSERT(ctx == NULL);
-
- KCF_SET_PROVIDER_MECHNUM(
- eops->em_framework_encr_mechtype,
- pd, &eops->em_encr_mech);
-
- KCF_SET_PROVIDER_MECHNUM(
- eops->em_framework_mac_mechtype,
- pd, &eops->em_mac_mech);
-
- err = KCF_PROV_ENCRYPT_MAC_ATOMIC(pd, eops->em_sid,
- &eops->em_encr_mech, eops->em_encr_key,
- &eops->em_mac_mech, eops->em_mac_key,
- eops->em_plaintext, eops->em_ciphertext,
- eops->em_mac,
- eops->em_encr_templ, eops->em_mac_templ,
- rhndl);
-
- break;
-
- default:
- break;
- }
- break;
- }
-
- case KCF_OG_MAC_DECRYPT: {
- kcf_mac_decrypt_ops_params_t *dops =
- &params->rp_u.mac_decrypt_params;
- kcf_context_t *kcf_secondctx;
-
- switch (optype) {
- case KCF_OP_INIT:
- kcf_secondctx = ((kcf_context_t *)
- (ctx->cc_framework_private))->kc_secondctx;
-
- if (kcf_secondctx != NULL) {
- err = kcf_emulate_dual(pd, ctx, params);
- break;
- }
- KCF_SET_PROVIDER_MECHNUM(
- dops->md_framework_mac_mechtype,
- pd, &dops->md_mac_mech);
-
- KCF_SET_PROVIDER_MECHNUM(
- dops->md_framework_decr_mechtype,
- pd, &dops->md_decr_mech);
-
- err = KCF_PROV_MAC_DECRYPT_INIT(pd, ctx,
- &dops->md_mac_mech, dops->md_mac_key,
- &dops->md_decr_mech, dops->md_decr_key,
- dops->md_mac_templ, dops->md_decr_templ,
- rhndl);
-
- break;
-
- case KCF_OP_SINGLE:
- err = KCF_PROV_MAC_DECRYPT(pd, ctx,
- dops->md_ciphertext, dops->md_mac,
- dops->md_plaintext, rhndl);
- break;
-
- case KCF_OP_UPDATE:
- kcf_secondctx = ((kcf_context_t *)
- (ctx->cc_framework_private))->kc_secondctx;
- if (kcf_secondctx != NULL) {
- err = kcf_emulate_dual(pd, ctx, params);
- break;
- }
- err = KCF_PROV_MAC_DECRYPT_UPDATE(pd, ctx,
- dops->md_ciphertext, dops->md_plaintext, rhndl);
- break;
-
- case KCF_OP_FINAL:
- kcf_secondctx = ((kcf_context_t *)
- (ctx->cc_framework_private))->kc_secondctx;
- if (kcf_secondctx != NULL) {
- err = kcf_emulate_dual(pd, ctx, params);
- break;
- }
- err = KCF_PROV_MAC_DECRYPT_FINAL(pd, ctx,
- dops->md_mac, dops->md_plaintext, rhndl);
- break;
-
- case KCF_OP_ATOMIC:
- ASSERT(ctx == NULL);
-
- KCF_SET_PROVIDER_MECHNUM(
- dops->md_framework_mac_mechtype,
- pd, &dops->md_mac_mech);
-
- KCF_SET_PROVIDER_MECHNUM(
- dops->md_framework_decr_mechtype,
- pd, &dops->md_decr_mech);
-
- err = KCF_PROV_MAC_DECRYPT_ATOMIC(pd, dops->md_sid,
- &dops->md_mac_mech, dops->md_mac_key,
- &dops->md_decr_mech, dops->md_decr_key,
- dops->md_ciphertext, dops->md_mac,
- dops->md_plaintext,
- dops->md_mac_templ, dops->md_decr_templ,
- rhndl);
-
- break;
-
- case KCF_OP_MAC_VERIFY_DECRYPT_ATOMIC:
- ASSERT(ctx == NULL);
-
- KCF_SET_PROVIDER_MECHNUM(
- dops->md_framework_mac_mechtype,
- pd, &dops->md_mac_mech);
-
- KCF_SET_PROVIDER_MECHNUM(
- dops->md_framework_decr_mechtype,
- pd, &dops->md_decr_mech);
-
- err = KCF_PROV_MAC_VERIFY_DECRYPT_ATOMIC(pd,
- dops->md_sid, &dops->md_mac_mech, dops->md_mac_key,
- &dops->md_decr_mech, dops->md_decr_key,
- dops->md_ciphertext, dops->md_mac,
- dops->md_plaintext,
- dops->md_mac_templ, dops->md_decr_templ,
- rhndl);
-
- break;
-
- default:
- break;
- }
- break;
- }
-
- case KCF_OG_KEY: {
- kcf_key_ops_params_t *kops = &params->rp_u.key_params;
-
- ASSERT(ctx == NULL);
- KCF_SET_PROVIDER_MECHNUM(kops->ko_framework_mechtype, pd,
- &kops->ko_mech);
-
- switch (optype) {
- case KCF_OP_KEY_GENERATE:
- err = KCF_PROV_KEY_GENERATE(pd, kops->ko_sid,
- &kops->ko_mech,
- kops->ko_key_template, kops->ko_key_attribute_count,
- kops->ko_key_object_id_ptr, rhndl);
- break;
-
- case KCF_OP_KEY_GENERATE_PAIR:
- err = KCF_PROV_KEY_GENERATE_PAIR(pd, kops->ko_sid,
- &kops->ko_mech,
- kops->ko_key_template, kops->ko_key_attribute_count,
- kops->ko_private_key_template,
- kops->ko_private_key_attribute_count,
- kops->ko_key_object_id_ptr,
- kops->ko_private_key_object_id_ptr, rhndl);
- break;
-
- case KCF_OP_KEY_WRAP:
- err = KCF_PROV_KEY_WRAP(pd, kops->ko_sid,
- &kops->ko_mech,
- kops->ko_key, kops->ko_key_object_id_ptr,
- kops->ko_wrapped_key, kops->ko_wrapped_key_len_ptr,
- rhndl);
- break;
-
- case KCF_OP_KEY_UNWRAP:
- err = KCF_PROV_KEY_UNWRAP(pd, kops->ko_sid,
- &kops->ko_mech,
- kops->ko_key, kops->ko_wrapped_key,
- kops->ko_wrapped_key_len_ptr,
- kops->ko_key_template, kops->ko_key_attribute_count,
- kops->ko_key_object_id_ptr, rhndl);
- break;
-
- case KCF_OP_KEY_DERIVE:
- err = KCF_PROV_KEY_DERIVE(pd, kops->ko_sid,
- &kops->ko_mech,
- kops->ko_key, kops->ko_key_template,
- kops->ko_key_attribute_count,
- kops->ko_key_object_id_ptr, rhndl);
- break;
-
- default:
- break;
- }
- break;
- }
-
- case KCF_OG_RANDOM: {
- kcf_random_number_ops_params_t *rops =
- &params->rp_u.random_number_params;
-
- ASSERT(ctx == NULL);
-
- switch (optype) {
- case KCF_OP_RANDOM_SEED:
- err = KCF_PROV_SEED_RANDOM(pd, rops->rn_sid,
- rops->rn_buf, rops->rn_buflen, rops->rn_entropy_est,
- rops->rn_flags, rhndl);
- break;
-
- case KCF_OP_RANDOM_GENERATE:
- err = KCF_PROV_GENERATE_RANDOM(pd, rops->rn_sid,
- rops->rn_buf, rops->rn_buflen, rhndl);
- break;
-
- default:
- break;
- }
- break;
- }
-
- case KCF_OG_SESSION: {
- kcf_session_ops_params_t *sops = &params->rp_u.session_params;
-
- ASSERT(ctx == NULL);
- switch (optype) {
- case KCF_OP_SESSION_OPEN:
- /*
- * so_pd may be a logical provider, in which case
- * we need to check whether it has been removed.
- */
- if (KCF_IS_PROV_REMOVED(sops->so_pd)) {
- err = CRYPTO_DEVICE_ERROR;
- break;
- }
- err = KCF_PROV_SESSION_OPEN(pd, sops->so_sid_ptr,
- rhndl, sops->so_pd);
- break;
-
- case KCF_OP_SESSION_CLOSE:
- /*
- * so_pd may be a logical provider, in which case
- * we need to check whether it has been removed.
- */
- if (KCF_IS_PROV_REMOVED(sops->so_pd)) {
- err = CRYPTO_DEVICE_ERROR;
- break;
- }
- err = KCF_PROV_SESSION_CLOSE(pd, sops->so_sid,
- rhndl, sops->so_pd);
- break;
-
- case KCF_OP_SESSION_LOGIN:
- err = KCF_PROV_SESSION_LOGIN(pd, sops->so_sid,
- sops->so_user_type, sops->so_pin,
- sops->so_pin_len, rhndl);
- break;
-
- case KCF_OP_SESSION_LOGOUT:
- err = KCF_PROV_SESSION_LOGOUT(pd, sops->so_sid, rhndl);
- break;
-
- default:
- break;
- }
- break;
- }
-
- case KCF_OG_OBJECT: {
- kcf_object_ops_params_t *jops = &params->rp_u.object_params;
-
- ASSERT(ctx == NULL);
- switch (optype) {
- case KCF_OP_OBJECT_CREATE:
- err = KCF_PROV_OBJECT_CREATE(pd, jops->oo_sid,
- jops->oo_template, jops->oo_attribute_count,
- jops->oo_object_id_ptr, rhndl);
- break;
-
- case KCF_OP_OBJECT_COPY:
- err = KCF_PROV_OBJECT_COPY(pd, jops->oo_sid,
- jops->oo_object_id,
- jops->oo_template, jops->oo_attribute_count,
- jops->oo_object_id_ptr, rhndl);
- break;
-
- case KCF_OP_OBJECT_DESTROY:
- err = KCF_PROV_OBJECT_DESTROY(pd, jops->oo_sid,
- jops->oo_object_id, rhndl);
- break;
-
- case KCF_OP_OBJECT_GET_SIZE:
- err = KCF_PROV_OBJECT_GET_SIZE(pd, jops->oo_sid,
- jops->oo_object_id, jops->oo_object_size, rhndl);
- break;
-
- case KCF_OP_OBJECT_GET_ATTRIBUTE_VALUE:
- err = KCF_PROV_OBJECT_GET_ATTRIBUTE_VALUE(pd,
- jops->oo_sid, jops->oo_object_id,
- jops->oo_template, jops->oo_attribute_count, rhndl);
- break;
-
- case KCF_OP_OBJECT_SET_ATTRIBUTE_VALUE:
- err = KCF_PROV_OBJECT_SET_ATTRIBUTE_VALUE(pd,
- jops->oo_sid, jops->oo_object_id,
- jops->oo_template, jops->oo_attribute_count, rhndl);
- break;
-
- case KCF_OP_OBJECT_FIND_INIT:
- err = KCF_PROV_OBJECT_FIND_INIT(pd, jops->oo_sid,
- jops->oo_template, jops->oo_attribute_count,
- jops->oo_find_init_pp_ptr, rhndl);
- break;
-
- case KCF_OP_OBJECT_FIND:
- err = KCF_PROV_OBJECT_FIND(pd, jops->oo_find_pp,
- jops->oo_object_id_ptr, jops->oo_max_object_count,
- jops->oo_object_count_ptr, rhndl);
- break;
-
- case KCF_OP_OBJECT_FIND_FINAL:
- err = KCF_PROV_OBJECT_FIND_FINAL(pd, jops->oo_find_pp,
- rhndl);
- break;
-
- default:
- break;
- }
- break;
- }
-
- case KCF_OG_PROVMGMT: {
- kcf_provmgmt_ops_params_t *pops = &params->rp_u.provmgmt_params;
-
- ASSERT(ctx == NULL);
- switch (optype) {
- case KCF_OP_MGMT_EXTINFO:
- /*
- * po_pd may be a logical provider, in which case
- * we need to check whether it has been removed.
- */
- if (KCF_IS_PROV_REMOVED(pops->po_pd)) {
- err = CRYPTO_DEVICE_ERROR;
- break;
- }
- err = KCF_PROV_EXT_INFO(pd, pops->po_ext_info, rhndl,
- pops->po_pd);
- break;
-
- case KCF_OP_MGMT_INITTOKEN:
- err = KCF_PROV_INIT_TOKEN(pd, pops->po_pin,
- pops->po_pin_len, pops->po_label, rhndl);
- break;
-
- case KCF_OP_MGMT_INITPIN:
- err = KCF_PROV_INIT_PIN(pd, pops->po_sid, pops->po_pin,
- pops->po_pin_len, rhndl);
- break;
-
- case KCF_OP_MGMT_SETPIN:
- err = KCF_PROV_SET_PIN(pd, pops->po_sid,
- pops->po_old_pin, pops->po_old_pin_len,
- pops->po_pin, pops->po_pin_len, rhndl);
- break;
-
- default:
- break;
- }
- break;
- }
-
- case KCF_OG_NOSTORE_KEY: {
- kcf_key_ops_params_t *kops = &params->rp_u.key_params;
-
- ASSERT(ctx == NULL);
- KCF_SET_PROVIDER_MECHNUM(kops->ko_framework_mechtype, pd,
- &kops->ko_mech);
-
- switch (optype) {
- case KCF_OP_KEY_GENERATE:
- err = KCF_PROV_NOSTORE_KEY_GENERATE(pd, kops->ko_sid,
- &kops->ko_mech, kops->ko_key_template,
- kops->ko_key_attribute_count,
- kops->ko_out_template1,
- kops->ko_out_attribute_count1, rhndl);
- break;
-
- case KCF_OP_KEY_GENERATE_PAIR:
- err = KCF_PROV_NOSTORE_KEY_GENERATE_PAIR(pd,
- kops->ko_sid, &kops->ko_mech,
- kops->ko_key_template, kops->ko_key_attribute_count,
- kops->ko_private_key_template,
- kops->ko_private_key_attribute_count,
- kops->ko_out_template1,
- kops->ko_out_attribute_count1,
- kops->ko_out_template2,
- kops->ko_out_attribute_count2,
- rhndl);
- break;
-
- case KCF_OP_KEY_DERIVE:
- err = KCF_PROV_NOSTORE_KEY_DERIVE(pd, kops->ko_sid,
- &kops->ko_mech, kops->ko_key,
- kops->ko_key_template,
- kops->ko_key_attribute_count,
- kops->ko_out_template1,
- kops->ko_out_attribute_count1, rhndl);
- break;
-
- default:
- break;
- }
- break;
- }
- default:
- break;
- } /* end of switch(params->rp_opgrp) */
-
- KCF_PROV_INCRSTATS(pd, err);
- return (err);
-}
-
-
-/*
- * Emulate the call for a multipart dual ops with 2 single steps.
- * This routine is always called in the context of a working thread
- * running kcf_svc_do_run().
- * The single steps are submitted in a pure synchronous way (blocking).
- * When this routine returns, kcf_svc_do_run() will call kcf_aop_done()
- * so the originating consumer's callback gets invoked. kcf_aop_done()
- * takes care of freeing the operation context. So, this routine does
- * not free the operation context.
- *
- * The provider descriptor is assumed held by the callers.
- */
-static int
-kcf_emulate_dual(kcf_provider_desc_t *pd, crypto_ctx_t *ctx,
- kcf_req_params_t *params)
-{
- int err = CRYPTO_ARGUMENTS_BAD;
- kcf_op_type_t optype;
- size_t save_len;
- off_t save_offset;
-
- optype = params->rp_optype;
-
- switch (params->rp_opgrp) {
- case KCF_OG_ENCRYPT_MAC: {
- kcf_encrypt_mac_ops_params_t *cmops =
- &params->rp_u.encrypt_mac_params;
- kcf_context_t *encr_kcf_ctx;
- crypto_ctx_t *mac_ctx;
- kcf_req_params_t encr_params;
-
- encr_kcf_ctx = (kcf_context_t *)(ctx->cc_framework_private);
-
- switch (optype) {
- case KCF_OP_INIT: {
- encr_kcf_ctx->kc_secondctx = NULL;
-
- KCF_WRAP_ENCRYPT_OPS_PARAMS(&encr_params, KCF_OP_INIT,
- pd->pd_sid, &cmops->em_encr_mech,
- cmops->em_encr_key, NULL, NULL,
- cmops->em_encr_templ);
-
- err = kcf_submit_request(pd, ctx, NULL, &encr_params,
- B_FALSE);
-
- /* It can't be CRYPTO_QUEUED */
- if (err != CRYPTO_SUCCESS) {
- break;
- }
-
- err = crypto_mac_init(&cmops->em_mac_mech,
- cmops->em_mac_key, cmops->em_mac_templ,
- (crypto_context_t *)&mac_ctx, NULL);
-
- if (err == CRYPTO_SUCCESS) {
- encr_kcf_ctx->kc_secondctx = (kcf_context_t *)
- mac_ctx->cc_framework_private;
- KCF_CONTEXT_REFHOLD((kcf_context_t *)
- mac_ctx->cc_framework_private);
- }
-
- break;
-
- }
- case KCF_OP_UPDATE: {
- crypto_dual_data_t *ct = cmops->em_ciphertext;
- crypto_data_t *pt = cmops->em_plaintext;
- kcf_context_t *mac_kcf_ctx = encr_kcf_ctx->kc_secondctx;
- crypto_ctx_t *mac_ctx = &mac_kcf_ctx->kc_glbl_ctx;
-
- KCF_WRAP_ENCRYPT_OPS_PARAMS(&encr_params, KCF_OP_UPDATE,
- pd->pd_sid, NULL, NULL, pt, (crypto_data_t *)ct,
- NULL);
-
- err = kcf_submit_request(pd, ctx, NULL, &encr_params,
- B_FALSE);
-
- /* It can't be CRYPTO_QUEUED */
- if (err != CRYPTO_SUCCESS) {
- break;
- }
-
- save_offset = ct->dd_offset1;
- save_len = ct->dd_len1;
- if (ct->dd_len2 == 0) {
- /*
- * The previous encrypt step was an
- * accumulation only and didn't produce any
- * partial output
- */
- if (ct->dd_len1 == 0)
- break;
-
- } else {
- ct->dd_offset1 = ct->dd_offset2;
- ct->dd_len1 = ct->dd_len2;
- }
- err = crypto_mac_update((crypto_context_t)mac_ctx,
- (crypto_data_t *)ct, NULL);
-
- ct->dd_offset1 = save_offset;
- ct->dd_len1 = save_len;
-
- break;
- }
- case KCF_OP_FINAL: {
- crypto_dual_data_t *ct = cmops->em_ciphertext;
- crypto_data_t *mac = cmops->em_mac;
- kcf_context_t *mac_kcf_ctx = encr_kcf_ctx->kc_secondctx;
- crypto_ctx_t *mac_ctx = &mac_kcf_ctx->kc_glbl_ctx;
- crypto_context_t mac_context = mac_ctx;
-
- KCF_WRAP_ENCRYPT_OPS_PARAMS(&encr_params, KCF_OP_FINAL,
- pd->pd_sid, NULL, NULL, NULL, (crypto_data_t *)ct,
- NULL);
-
- err = kcf_submit_request(pd, ctx, NULL, &encr_params,
- B_FALSE);
-
- /* It can't be CRYPTO_QUEUED */
- if (err != CRYPTO_SUCCESS) {
- crypto_cancel_ctx(mac_context);
- break;
- }
-
- if (ct->dd_len2 > 0) {
- save_offset = ct->dd_offset1;
- save_len = ct->dd_len1;
- ct->dd_offset1 = ct->dd_offset2;
- ct->dd_len1 = ct->dd_len2;
-
- err = crypto_mac_update(mac_context,
- (crypto_data_t *)ct, NULL);
-
- ct->dd_offset1 = save_offset;
- ct->dd_len1 = save_len;
-
- if (err != CRYPTO_SUCCESS) {
- crypto_cancel_ctx(mac_context);
- return (err);
- }
- }
-
- /* and finally, collect the MAC */
- err = crypto_mac_final(mac_context, mac, NULL);
- break;
- }
-
- default:
- break;
- }
- KCF_PROV_INCRSTATS(pd, err);
- break;
- }
- case KCF_OG_MAC_DECRYPT: {
- kcf_mac_decrypt_ops_params_t *mdops =
- &params->rp_u.mac_decrypt_params;
- kcf_context_t *decr_kcf_ctx;
- crypto_ctx_t *mac_ctx;
- kcf_req_params_t decr_params;
-
- decr_kcf_ctx = (kcf_context_t *)(ctx->cc_framework_private);
-
- switch (optype) {
- case KCF_OP_INIT: {
- decr_kcf_ctx->kc_secondctx = NULL;
-
- err = crypto_mac_init(&mdops->md_mac_mech,
- mdops->md_mac_key, mdops->md_mac_templ,
- (crypto_context_t *)&mac_ctx, NULL);
-
- /* It can't be CRYPTO_QUEUED */
- if (err != CRYPTO_SUCCESS) {
- break;
- }
-
- KCF_WRAP_DECRYPT_OPS_PARAMS(&decr_params, KCF_OP_INIT,
- pd->pd_sid, &mdops->md_decr_mech,
- mdops->md_decr_key, NULL, NULL,
- mdops->md_decr_templ);
-
- err = kcf_submit_request(pd, ctx, NULL, &decr_params,
- B_FALSE);
-
- /* It can't be CRYPTO_QUEUED */
- if (err != CRYPTO_SUCCESS) {
- crypto_cancel_ctx((crypto_context_t)mac_ctx);
- break;
- }
-
- decr_kcf_ctx->kc_secondctx = (kcf_context_t *)
- mac_ctx->cc_framework_private;
- KCF_CONTEXT_REFHOLD((kcf_context_t *)
- mac_ctx->cc_framework_private);
-
- break;
- default:
- break;
-
- }
- case KCF_OP_UPDATE: {
- crypto_dual_data_t *ct = mdops->md_ciphertext;
- crypto_data_t *pt = mdops->md_plaintext;
- kcf_context_t *mac_kcf_ctx = decr_kcf_ctx->kc_secondctx;
- crypto_ctx_t *mac_ctx = &mac_kcf_ctx->kc_glbl_ctx;
-
- err = crypto_mac_update((crypto_context_t)mac_ctx,
- (crypto_data_t *)ct, NULL);
-
- if (err != CRYPTO_SUCCESS)
- break;
-
- save_offset = ct->dd_offset1;
- save_len = ct->dd_len1;
-
- /* zero ct->dd_len2 means decrypt everything */
- if (ct->dd_len2 > 0) {
- ct->dd_offset1 = ct->dd_offset2;
- ct->dd_len1 = ct->dd_len2;
- }
-
- err = crypto_decrypt_update((crypto_context_t)ctx,
- (crypto_data_t *)ct, pt, NULL);
-
- ct->dd_offset1 = save_offset;
- ct->dd_len1 = save_len;
-
- break;
- }
- case KCF_OP_FINAL: {
- crypto_data_t *pt = mdops->md_plaintext;
- crypto_data_t *mac = mdops->md_mac;
- kcf_context_t *mac_kcf_ctx = decr_kcf_ctx->kc_secondctx;
- crypto_ctx_t *mac_ctx = &mac_kcf_ctx->kc_glbl_ctx;
-
- err = crypto_mac_final((crypto_context_t)mac_ctx,
- mac, NULL);
-
- if (err != CRYPTO_SUCCESS) {
- crypto_cancel_ctx(ctx);
- break;
- }
-
- /* Get the last chunk of plaintext */
- KCF_CONTEXT_REFHOLD(decr_kcf_ctx);
- err = crypto_decrypt_final((crypto_context_t)ctx, pt,
- NULL);
-
- break;
- }
- }
- break;
- }
- default:
-
- break;
- } /* end of switch(params->rp_opgrp) */
-
- return (err);
-}
diff --git a/sys/contrib/openzfs/module/icp/core/kcf_mech_tabs.c b/sys/contrib/openzfs/module/icp/core/kcf_mech_tabs.c
index 60055e78af68..347190aa7f8b 100644
--- a/sys/contrib/openzfs/module/icp/core/kcf_mech_tabs.c
+++ b/sys/contrib/openzfs/module/icp/core/kcf_mech_tabs.c
@@ -27,7 +27,6 @@
#include <sys/crypto/common.h>
#include <sys/crypto/api.h>
#include <sys/crypto/impl.h>
-#include <sys/modhash.h>
/* Cryptographic mechanisms tables and their access functions */
@@ -55,9 +54,6 @@
/*
* Locking conventions:
* --------------------
- * A global mutex, kcf_mech_tabs_lock, serializes writes to the
- * mechanism table via kcf_create_mech_entry().
- *
* A mutex is associated with every entry of the tables.
* The mutex is acquired whenever the entry is accessed for
* 1) retrieving the mech_id (comparing the mech name)
@@ -72,9 +68,6 @@
* long enough to justify the cost of using rwlocks, so the per-mechanism
* entry mutex won't be very *hot*.
*
- * When both kcf_mech_tabs_lock and a mech_entry mutex need to be held,
- * kcf_mech_tabs_lock must always be acquired first.
- *
*/
/* Mechanisms tables */
@@ -85,76 +78,30 @@
static kcf_mech_entry_t kcf_digest_mechs_tab[KCF_MAXDIGEST];
static kcf_mech_entry_t kcf_cipher_mechs_tab[KCF_MAXCIPHER];
static kcf_mech_entry_t kcf_mac_mechs_tab[KCF_MAXMAC];
-static kcf_mech_entry_t kcf_sign_mechs_tab[KCF_MAXSIGN];
-static kcf_mech_entry_t kcf_keyops_mechs_tab[KCF_MAXKEYOPS];
-static kcf_mech_entry_t kcf_misc_mechs_tab[KCF_MAXMISC];
const kcf_mech_entry_tab_t kcf_mech_tabs_tab[KCF_LAST_OPSCLASS + 1] = {
{0, NULL}, /* No class zero */
{KCF_MAXDIGEST, kcf_digest_mechs_tab},
{KCF_MAXCIPHER, kcf_cipher_mechs_tab},
{KCF_MAXMAC, kcf_mac_mechs_tab},
- {KCF_MAXSIGN, kcf_sign_mechs_tab},
- {KCF_MAXKEYOPS, kcf_keyops_mechs_tab},
- {KCF_MAXMISC, kcf_misc_mechs_tab}
};
-/*
- * Per-algorithm internal thresholds for the minimum input size of before
- * offloading to hardware provider.
- * Dispatching a crypto operation to a hardware provider entails paying the
- * cost of an additional context switch. Measurements with Sun Accelerator 4000
- * shows that 512-byte jobs or smaller are better handled in software.
- * There is room for refinement here.
- *
- */
-static const int kcf_md5_threshold = 512;
-static const int kcf_sha1_threshold = 512;
-static const int kcf_des_threshold = 512;
-static const int kcf_des3_threshold = 512;
-static const int kcf_aes_threshold = 512;
-static const int kcf_bf_threshold = 512;
-static const int kcf_rc4_threshold = 512;
-
-static kmutex_t kcf_mech_tabs_lock;
-static uint32_t kcf_gen_swprov = 0;
-
-static const int kcf_mech_hash_size = 256;
-static mod_hash_t *kcf_mech_hash; /* mech name to id hash */
-
-static crypto_mech_type_t
-kcf_mech_hash_find(const char *mechname)
-{
- mod_hash_val_t hv;
- crypto_mech_type_t mt;
-
- mt = CRYPTO_MECH_INVALID;
- if (mod_hash_find(kcf_mech_hash, (mod_hash_key_t)mechname, &hv) == 0) {
- mt = *(crypto_mech_type_t *)hv;
- ASSERT(mt != CRYPTO_MECH_INVALID);
- }
+static avl_tree_t kcf_mech_hash;
- return (mt);
+static int
+kcf_mech_hash_compar(const void *lhs, const void *rhs)
+{
+ const kcf_mech_entry_t *l = lhs, *r = rhs;
+ int cmp = strncmp(l->me_name, r->me_name, CRYPTO_MAX_MECH_NAME);
+ return ((0 < cmp) - (cmp < 0));
}
void
kcf_destroy_mech_tabs(void)
{
- int i, max;
- kcf_ops_class_t class;
- kcf_mech_entry_t *me_tab;
-
- if (kcf_mech_hash)
- mod_hash_destroy_hash(kcf_mech_hash);
-
- mutex_destroy(&kcf_mech_tabs_lock);
-
- for (class = KCF_FIRST_OPSCLASS; class <= KCF_LAST_OPSCLASS; class++) {
- max = kcf_mech_tabs_tab[class].met_size;
- me_tab = kcf_mech_tabs_tab[class].met_tab;
- for (i = 0; i < max; i++)
- mutex_destroy(&(me_tab[i].me_mutex));
- }
+ for (void *cookie = NULL; avl_destroy_nodes(&kcf_mech_hash, &cookie); )
+ ;
+ avl_destroy(&kcf_mech_hash);
}
/*
@@ -166,101 +113,8 @@ kcf_destroy_mech_tabs(void)
void
kcf_init_mech_tabs(void)
{
- kcf_ops_class_t class;
- kcf_mech_entry_t *me_tab;
-
- /* Initializes the mutex locks. */
-
- mutex_init(&kcf_mech_tabs_lock, NULL, MUTEX_DEFAULT, NULL);
-
- /* Then the pre-defined mechanism entries */
-
- /* Two digests */
- (void) strncpy(kcf_digest_mechs_tab[0].me_name, SUN_CKM_MD5,
- CRYPTO_MAX_MECH_NAME);
- kcf_digest_mechs_tab[0].me_threshold = kcf_md5_threshold;
-
- (void) strncpy(kcf_digest_mechs_tab[1].me_name, SUN_CKM_SHA1,
- CRYPTO_MAX_MECH_NAME);
- kcf_digest_mechs_tab[1].me_threshold = kcf_sha1_threshold;
-
- /* The symmetric ciphers in various modes */
- (void) strncpy(kcf_cipher_mechs_tab[0].me_name, SUN_CKM_DES_CBC,
- CRYPTO_MAX_MECH_NAME);
- kcf_cipher_mechs_tab[0].me_threshold = kcf_des_threshold;
-
- (void) strncpy(kcf_cipher_mechs_tab[1].me_name, SUN_CKM_DES3_CBC,
- CRYPTO_MAX_MECH_NAME);
- kcf_cipher_mechs_tab[1].me_threshold = kcf_des3_threshold;
-
- (void) strncpy(kcf_cipher_mechs_tab[2].me_name, SUN_CKM_DES_ECB,
- CRYPTO_MAX_MECH_NAME);
- kcf_cipher_mechs_tab[2].me_threshold = kcf_des_threshold;
-
- (void) strncpy(kcf_cipher_mechs_tab[3].me_name, SUN_CKM_DES3_ECB,
- CRYPTO_MAX_MECH_NAME);
- kcf_cipher_mechs_tab[3].me_threshold = kcf_des3_threshold;
-
- (void) strncpy(kcf_cipher_mechs_tab[4].me_name, SUN_CKM_BLOWFISH_CBC,
- CRYPTO_MAX_MECH_NAME);
- kcf_cipher_mechs_tab[4].me_threshold = kcf_bf_threshold;
-
- (void) strncpy(kcf_cipher_mechs_tab[5].me_name, SUN_CKM_BLOWFISH_ECB,
- CRYPTO_MAX_MECH_NAME);
- kcf_cipher_mechs_tab[5].me_threshold = kcf_bf_threshold;
-
- (void) strncpy(kcf_cipher_mechs_tab[6].me_name, SUN_CKM_AES_CBC,
- CRYPTO_MAX_MECH_NAME);
- kcf_cipher_mechs_tab[6].me_threshold = kcf_aes_threshold;
-
- (void) strncpy(kcf_cipher_mechs_tab[7].me_name, SUN_CKM_AES_ECB,
- CRYPTO_MAX_MECH_NAME);
- kcf_cipher_mechs_tab[7].me_threshold = kcf_aes_threshold;
-
- (void) strncpy(kcf_cipher_mechs_tab[8].me_name, SUN_CKM_RC4,
- CRYPTO_MAX_MECH_NAME);
- kcf_cipher_mechs_tab[8].me_threshold = kcf_rc4_threshold;
-
-
- /* 4 HMACs */
- (void) strncpy(kcf_mac_mechs_tab[0].me_name, SUN_CKM_MD5_HMAC,
- CRYPTO_MAX_MECH_NAME);
- kcf_mac_mechs_tab[0].me_threshold = kcf_md5_threshold;
-
- (void) strncpy(kcf_mac_mechs_tab[1].me_name, SUN_CKM_MD5_HMAC_GENERAL,
- CRYPTO_MAX_MECH_NAME);
- kcf_mac_mechs_tab[1].me_threshold = kcf_md5_threshold;
-
- (void) strncpy(kcf_mac_mechs_tab[2].me_name, SUN_CKM_SHA1_HMAC,
- CRYPTO_MAX_MECH_NAME);
- kcf_mac_mechs_tab[2].me_threshold = kcf_sha1_threshold;
-
- (void) strncpy(kcf_mac_mechs_tab[3].me_name, SUN_CKM_SHA1_HMAC_GENERAL,
- CRYPTO_MAX_MECH_NAME);
- kcf_mac_mechs_tab[3].me_threshold = kcf_sha1_threshold;
-
-
- /* 1 random number generation pseudo mechanism */
- (void) strncpy(kcf_misc_mechs_tab[0].me_name, SUN_RANDOM,
- CRYPTO_MAX_MECH_NAME);
-
- kcf_mech_hash = mod_hash_create_strhash_nodtr("kcf mech2id hash",
- kcf_mech_hash_size, mod_hash_null_valdtor);
-
- for (class = KCF_FIRST_OPSCLASS; class <= KCF_LAST_OPSCLASS; class++) {
- int max = kcf_mech_tabs_tab[class].met_size;
- me_tab = kcf_mech_tabs_tab[class].met_tab;
- for (int i = 0; i < max; i++) {
- mutex_init(&(me_tab[i].me_mutex), NULL,
- MUTEX_DEFAULT, NULL);
- if (me_tab[i].me_name[0] != 0) {
- me_tab[i].me_mechid = KCF_MECHID(class, i);
- (void) mod_hash_insert(kcf_mech_hash,
- (mod_hash_key_t)me_tab[i].me_name,
- (mod_hash_val_t)&(me_tab[i].me_mechid));
- }
- }
- }
+ avl_create(&kcf_mech_hash, kcf_mech_hash_compar,
+ sizeof (kcf_mech_entry_t), offsetof(kcf_mech_entry_t, me_node));
}
/*
@@ -290,12 +144,8 @@ kcf_init_mech_tabs(void)
* KCF_SUCCESS otherwise.
*/
static int
-kcf_create_mech_entry(kcf_ops_class_t class, char *mechname)
+kcf_create_mech_entry(kcf_ops_class_t class, const char *mechname)
{
- crypto_mech_type_t mt;
- kcf_mech_entry_t *me_tab;
- int i = 0, size;
-
if ((class < KCF_FIRST_OPSCLASS) || (class > KCF_LAST_OPSCLASS))
return (KCF_INVALID_MECH_CLASS);
@@ -305,49 +155,28 @@ kcf_create_mech_entry(kcf_ops_class_t class, char *mechname)
* First check if the mechanism is already in one of the tables.
* The mech_entry could be in another class.
*/
- mutex_enter(&kcf_mech_tabs_lock);
- mt = kcf_mech_hash_find(mechname);
- if (mt != CRYPTO_MECH_INVALID) {
- /* Nothing to do, regardless the suggested class. */
- mutex_exit(&kcf_mech_tabs_lock);
+ avl_index_t where = 0;
+ kcf_mech_entry_t tmptab;
+ strlcpy(tmptab.me_name, mechname, CRYPTO_MAX_MECH_NAME);
+ if (avl_find(&kcf_mech_hash, &tmptab, &where) != NULL)
return (KCF_SUCCESS);
- }
/* Now take the next unused mech entry in the class's tab */
- me_tab = kcf_mech_tabs_tab[class].met_tab;
- size = kcf_mech_tabs_tab[class].met_size;
+ kcf_mech_entry_t *me_tab = kcf_mech_tabs_tab[class].met_tab;
+ int size = kcf_mech_tabs_tab[class].met_size;
- while (i < size) {
- mutex_enter(&(me_tab[i].me_mutex));
+ for (int i = 0; i < size; ++i)
if (me_tab[i].me_name[0] == 0) {
/* Found an empty spot */
- (void) strlcpy(me_tab[i].me_name, mechname,
+ strlcpy(me_tab[i].me_name, mechname,
CRYPTO_MAX_MECH_NAME);
- me_tab[i].me_name[CRYPTO_MAX_MECH_NAME-1] = '\0';
me_tab[i].me_mechid = KCF_MECHID(class, i);
- /*
- * No a-priori information about the new mechanism, so
- * the threshold is set to zero.
- */
- me_tab[i].me_threshold = 0;
- mutex_exit(&(me_tab[i].me_mutex));
/* Add the new mechanism to the hash table */
- (void) mod_hash_insert(kcf_mech_hash,
- (mod_hash_key_t)me_tab[i].me_name,
- (mod_hash_val_t)&(me_tab[i].me_mechid));
- break;
+ avl_insert(&kcf_mech_hash, &me_tab[i], where);
+ return (KCF_SUCCESS);
}
- mutex_exit(&(me_tab[i].me_mutex));
- i++;
- }
- mutex_exit(&kcf_mech_tabs_lock);
-
- if (i == size) {
- return (KCF_MECH_TAB_FULL);
- }
-
- return (KCF_SUCCESS);
+ return (KCF_MECH_TAB_FULL);
}
/*
@@ -375,16 +204,9 @@ kcf_add_mech_provider(short mech_indx,
{
int error;
kcf_mech_entry_t *mech_entry = NULL;
- crypto_mech_info_t *mech_info;
- crypto_mech_type_t kcf_mech_type, mt;
- kcf_prov_mech_desc_t *prov_mech, *prov_mech2;
- crypto_func_group_t simple_fg_mask, dual_fg_mask;
- crypto_mech_info_t *dmi;
- crypto_mech_info_list_t *mil, *mil2;
- kcf_mech_entry_t *me;
- int i;
-
- ASSERT(prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
+ const crypto_mech_info_t *mech_info;
+ crypto_mech_type_t kcf_mech_type;
+ kcf_prov_mech_desc_t *prov_mech;
mech_info = &prov_desc->pd_mechanisms[mech_indx];
@@ -393,7 +215,7 @@ kcf_add_mech_provider(short mech_indx,
* Find the class corresponding to the function group flag of
* the mechanism.
*/
- kcf_mech_type = kcf_mech_hash_find(mech_info->cm_mech_name);
+ kcf_mech_type = crypto_mech2id(mech_info->cm_mech_name);
if (kcf_mech_type == CRYPTO_MECH_INVALID) {
crypto_func_group_t fg = mech_info->cm_func_group_mask;
kcf_ops_class_t class;
@@ -406,19 +228,8 @@ kcf_add_mech_provider(short mech_indx,
class = KCF_CIPHER_CLASS;
else if (fg & CRYPTO_FG_MAC || fg & CRYPTO_FG_MAC_ATOMIC)
class = KCF_MAC_CLASS;
- else if (fg & CRYPTO_FG_SIGN || fg & CRYPTO_FG_VERIFY ||
- fg & CRYPTO_FG_SIGN_ATOMIC ||
- fg & CRYPTO_FG_VERIFY_ATOMIC ||
- fg & CRYPTO_FG_SIGN_RECOVER ||
- fg & CRYPTO_FG_VERIFY_RECOVER)
- class = KCF_SIGN_CLASS;
- else if (fg & CRYPTO_FG_GENERATE ||
- fg & CRYPTO_FG_GENERATE_KEY_PAIR ||
- fg & CRYPTO_FG_WRAP || fg & CRYPTO_FG_UNWRAP ||
- fg & CRYPTO_FG_DERIVE)
- class = KCF_KEYOPS_CLASS;
else
- class = KCF_MISC_CLASS;
+ __builtin_unreachable();
/*
* Attempt to create a new mech_entry for the specified
@@ -430,7 +241,7 @@ kcf_add_mech_provider(short mech_indx,
return (error);
}
/* get the KCF mech type that was assigned to the mechanism */
- kcf_mech_type = kcf_mech_hash_find(mech_info->cm_mech_name);
+ kcf_mech_type = crypto_mech2id(mech_info->cm_mech_name);
ASSERT(kcf_mech_type != CRYPTO_MECH_INVALID);
}
@@ -447,142 +258,32 @@ kcf_add_mech_provider(short mech_indx,
KCF_PROV_REFHOLD(prov_desc);
KCF_PROV_IREFHOLD(prov_desc);
- dual_fg_mask = mech_info->cm_func_group_mask & CRYPTO_FG_DUAL_MASK;
-
- if (dual_fg_mask == ((crypto_func_group_t)0))
- goto add_entry;
-
- simple_fg_mask = (mech_info->cm_func_group_mask &
- CRYPTO_FG_SIMPLEOP_MASK) | CRYPTO_FG_RANDOM;
-
- for (i = 0; i < prov_desc->pd_mech_list_count; i++) {
- dmi = &prov_desc->pd_mechanisms[i];
-
- /* skip self */
- if (dmi->cm_mech_number == mech_info->cm_mech_number)
- continue;
-
- /* skip if not a dual operation mechanism */
- if (!(dmi->cm_func_group_mask & dual_fg_mask) ||
- (dmi->cm_func_group_mask & simple_fg_mask))
- continue;
-
- mt = kcf_mech_hash_find(dmi->cm_mech_name);
- if (mt == CRYPTO_MECH_INVALID)
- continue;
-
- if (kcf_get_mech_entry(mt, &me) != KCF_SUCCESS)
- continue;
-
- mil = kmem_zalloc(sizeof (*mil), KM_SLEEP);
- mil2 = kmem_zalloc(sizeof (*mil2), KM_SLEEP);
-
- /*
- * Ignore hard-coded entries in the mech table
- * if the provider hasn't registered.
- */
- mutex_enter(&me->me_mutex);
- if (me->me_hw_prov_chain == NULL && me->me_sw_prov == NULL) {
- mutex_exit(&me->me_mutex);
- kmem_free(mil, sizeof (*mil));
- kmem_free(mil2, sizeof (*mil2));
- continue;
- }
-
- /*
- * Add other dual mechanisms that have registered
- * with the framework to this mechanism's
- * cross-reference list.
- */
- mil->ml_mech_info = *dmi; /* struct assignment */
- mil->ml_kcf_mechid = mt;
-
- /* add to head of list */
- mil->ml_next = prov_mech->pm_mi_list;
- prov_mech->pm_mi_list = mil;
-
- if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
- prov_mech2 = me->me_hw_prov_chain;
- else
- prov_mech2 = me->me_sw_prov;
-
- if (prov_mech2 == NULL) {
- kmem_free(mil2, sizeof (*mil2));
- mutex_exit(&me->me_mutex);
- continue;
- }
-
- /*
- * Update all other cross-reference lists by
- * adding this new mechanism.
- */
- while (prov_mech2 != NULL) {
- if (prov_mech2->pm_prov_desc == prov_desc) {
- /* struct assignment */
- mil2->ml_mech_info = *mech_info;
- mil2->ml_kcf_mechid = kcf_mech_type;
-
- /* add to head of list */
- mil2->ml_next = prov_mech2->pm_mi_list;
- prov_mech2->pm_mi_list = mil2;
- break;
- }
- prov_mech2 = prov_mech2->pm_next;
- }
- if (prov_mech2 == NULL)
- kmem_free(mil2, sizeof (*mil2));
-
- mutex_exit(&me->me_mutex);
- }
-
-add_entry:
/*
* Add new kcf_prov_mech_desc at the front of HW providers
* chain.
*/
- switch (prov_desc->pd_prov_type) {
-
- case CRYPTO_HW_PROVIDER:
- mutex_enter(&mech_entry->me_mutex);
- prov_mech->pm_me = mech_entry;
- prov_mech->pm_next = mech_entry->me_hw_prov_chain;
- mech_entry->me_hw_prov_chain = prov_mech;
- mech_entry->me_num_hwprov++;
- mutex_exit(&mech_entry->me_mutex);
- break;
-
- case CRYPTO_SW_PROVIDER:
- mutex_enter(&mech_entry->me_mutex);
- if (mech_entry->me_sw_prov != NULL) {
- /*
- * There is already a SW provider for this mechanism.
- * Since we allow only one SW provider per mechanism,
- * report this condition.
- */
- cmn_err(CE_WARN, "The cryptographic software provider "
- "\"%s\" will not be used for %s. The provider "
- "\"%s\" will be used for this mechanism "
- "instead.", prov_desc->pd_description,
- mech_info->cm_mech_name,
- mech_entry->me_sw_prov->pm_prov_desc->
- pd_description);
- KCF_PROV_REFRELE(prov_desc);
- kmem_free(prov_mech, sizeof (kcf_prov_mech_desc_t));
- prov_mech = NULL;
- } else {
- /*
- * Set the provider as the software provider for
- * this mechanism.
- */
- mech_entry->me_sw_prov = prov_mech;
-
- /* We'll wrap around after 4 billion registrations! */
- mech_entry->me_gen_swprov = kcf_gen_swprov++;
- }
- mutex_exit(&mech_entry->me_mutex);
- break;
- default:
- break;
+ if (mech_entry->me_sw_prov != NULL) {
+ /*
+ * There is already a provider for this mechanism.
+ * Since we allow only one provider per mechanism,
+ * report this condition.
+ */
+ cmn_err(CE_WARN, "The cryptographic provider "
+ "\"%s\" will not be used for %s. The provider "
+ "\"%s\" will be used for this mechanism "
+ "instead.", prov_desc->pd_description,
+ mech_info->cm_mech_name,
+ mech_entry->me_sw_prov->pm_prov_desc->
+ pd_description);
+ KCF_PROV_REFRELE(prov_desc);
+ kmem_free(prov_mech, sizeof (kcf_prov_mech_desc_t));
+ prov_mech = NULL;
+ } else {
+ /*
+ * Set the provider as the provider for
+ * this mechanism.
+ */
+ mech_entry->me_sw_prov = prov_mech;
}
*pmdpp = prov_mech;
@@ -606,18 +307,14 @@ add_entry:
* User context only.
*/
void
-kcf_remove_mech_provider(char *mech_name, kcf_provider_desc_t *prov_desc)
+kcf_remove_mech_provider(const char *mech_name, kcf_provider_desc_t *prov_desc)
{
crypto_mech_type_t mech_type;
- kcf_prov_mech_desc_t *prov_mech = NULL, *prov_chain;
- kcf_prov_mech_desc_t **prev_entry_next;
+ kcf_prov_mech_desc_t *prov_mech = NULL;
kcf_mech_entry_t *mech_entry;
- crypto_mech_info_list_t *mil, *mil2, *next, **prev_next;
-
- ASSERT(prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
/* get the KCF mech type that was assigned to the mechanism */
- if ((mech_type = kcf_mech_hash_find(mech_name)) ==
+ if ((mech_type = crypto_mech2id(mech_name)) ==
CRYPTO_MECH_INVALID) {
/*
* Provider was not allowed for this mech due to policy or
@@ -635,88 +332,13 @@ kcf_remove_mech_provider(char *mech_name, kcf_provider_desc_t *prov_desc)
return;
}
- mutex_enter(&mech_entry->me_mutex);
-
- switch (prov_desc->pd_prov_type) {
-
- case CRYPTO_HW_PROVIDER:
- /* find the provider in the mech_entry chain */
- prev_entry_next = &mech_entry->me_hw_prov_chain;
- prov_mech = mech_entry->me_hw_prov_chain;
- while (prov_mech != NULL &&
- prov_mech->pm_prov_desc != prov_desc) {
- prev_entry_next = &prov_mech->pm_next;
- prov_mech = prov_mech->pm_next;
- }
-
- if (prov_mech == NULL) {
- /* entry not found, simply return */
- mutex_exit(&mech_entry->me_mutex);
- return;
- }
-
- /* remove provider entry from mech_entry chain */
- *prev_entry_next = prov_mech->pm_next;
- ASSERT(mech_entry->me_num_hwprov > 0);
- mech_entry->me_num_hwprov--;
- break;
-
- case CRYPTO_SW_PROVIDER:
- if (mech_entry->me_sw_prov == NULL ||
- mech_entry->me_sw_prov->pm_prov_desc != prov_desc) {
- /* not the software provider for this mechanism */
- mutex_exit(&mech_entry->me_mutex);
- return;
- }
- prov_mech = mech_entry->me_sw_prov;
- mech_entry->me_sw_prov = NULL;
- break;
- default:
- /* unexpected crypto_provider_type_t */
- mutex_exit(&mech_entry->me_mutex);
+ if (mech_entry->me_sw_prov == NULL ||
+ mech_entry->me_sw_prov->pm_prov_desc != prov_desc) {
+ /* not the provider for this mechanism */
return;
}
-
- mutex_exit(&mech_entry->me_mutex);
-
- /* Free the dual ops cross-reference lists */
- mil = prov_mech->pm_mi_list;
- while (mil != NULL) {
- next = mil->ml_next;
- if (kcf_get_mech_entry(mil->ml_kcf_mechid,
- &mech_entry) != KCF_SUCCESS) {
- mil = next;
- continue;
- }
-
- mutex_enter(&mech_entry->me_mutex);
- if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
- prov_chain = mech_entry->me_hw_prov_chain;
- else
- prov_chain = mech_entry->me_sw_prov;
-
- while (prov_chain != NULL) {
- if (prov_chain->pm_prov_desc == prov_desc) {
- prev_next = &prov_chain->pm_mi_list;
- mil2 = prov_chain->pm_mi_list;
- while (mil2 != NULL &&
- mil2->ml_kcf_mechid != mech_type) {
- prev_next = &mil2->ml_next;
- mil2 = mil2->ml_next;
- }
- if (mil2 != NULL) {
- *prev_next = mil2->ml_next;
- kmem_free(mil2, sizeof (*mil2));
- }
- break;
- }
- prov_chain = prov_chain->pm_next;
- }
-
- mutex_exit(&mech_entry->me_mutex);
- kmem_free(mil, sizeof (crypto_mech_info_list_t));
- mil = next;
- }
+ prov_mech = mech_entry->me_sw_prov;
+ mech_entry->me_sw_prov = NULL;
/* free entry */
KCF_PROV_REFRELE(prov_mech->pm_prov_desc);
@@ -769,16 +391,44 @@ kcf_get_mech_entry(crypto_mech_type_t mech_type, kcf_mech_entry_t **mep)
return (KCF_SUCCESS);
}
-/* CURRENTLY UNSUPPORTED: attempting to load the module if it isn't found */
+/*
+ * crypto_mech2id()
+ *
+ * Arguments:
+ * . mechname: A null-terminated string identifying the mechanism name.
+ *
+ * Description:
+ * Walks the mechanisms tables, looking for an entry that matches the
+ * mechname. Once it find it, it builds the 64-bit mech_type and returns
+ * it.
+ *
+ * Context:
+ * Process and interruption.
+ *
+ * Returns:
+ * The unique mechanism identified by 'mechname', if found.
+ * CRYPTO_MECH_INVALID otherwise.
+ */
/*
* Lookup the hash table for an entry that matches the mechname.
- * If there are no hardware or software providers for the mechanism,
- * but there is an unloaded software provider, this routine will attempt
+ * If there are no providers for the mechanism,
+ * but there is an unloaded provider, this routine will attempt
* to load it.
*/
crypto_mech_type_t
-crypto_mech2id_common(const char *mechname, boolean_t load_module)
+crypto_mech2id(const char *mechname)
{
- (void) load_module;
- return (kcf_mech_hash_find(mechname));
+ kcf_mech_entry_t tmptab, *found;
+ strlcpy(tmptab.me_name, mechname, CRYPTO_MAX_MECH_NAME);
+
+ if ((found = avl_find(&kcf_mech_hash, &tmptab, NULL))) {
+ ASSERT(found->me_mechid != CRYPTO_MECH_INVALID);
+ return (found->me_mechid);
+ }
+
+ return (CRYPTO_MECH_INVALID);
}
+
+#if defined(_KERNEL)
+EXPORT_SYMBOL(crypto_mech2id);
+#endif
diff --git a/sys/contrib/openzfs/module/icp/core/kcf_prov_lib.c b/sys/contrib/openzfs/module/icp/core/kcf_prov_lib.c
index 6e8853c56dc6..505dbec313de 100644
--- a/sys/contrib/openzfs/module/icp/core/kcf_prov_lib.c
+++ b/sys/contrib/openzfs/module/icp/core/kcf_prov_lib.c
@@ -33,14 +33,12 @@
*/
/*
- * Utility routine to apply the command, 'cmd', to the
+ * Utility routine to apply the command COPY_TO_DATA to the
* data in the uio structure.
*/
-int
-crypto_uio_data(crypto_data_t *data, uchar_t *buf, int len, cmd_type_t cmd,
- void *digest_ctx, void (*update)(void))
+static int
+crypto_uio_copy_to_data(crypto_data_t *data, uchar_t *buf, int len)
{
- (void) digest_ctx, (void) update;
zfs_uio_t *uiop = data->cd_uio;
off_t offset = data->cd_offset;
size_t length = len;
@@ -72,26 +70,8 @@ crypto_uio_data(crypto_data_t *data, uchar_t *buf, int len, cmd_type_t cmd,
offset, length);
datap = (uchar_t *)(zfs_uio_iovbase(uiop, vec_idx) + offset);
- switch (cmd) {
- case COPY_FROM_DATA:
- bcopy(datap, buf, cur_len);
- buf += cur_len;
- break;
- case COPY_TO_DATA:
- bcopy(buf, datap, cur_len);
- buf += cur_len;
- break;
- case COMPARE_TO_DATA:
- if (bcmp(datap, buf, cur_len))
- return (CRYPTO_SIGNATURE_INVALID);
- buf += cur_len;
- break;
- case MD5_DIGEST_DATA:
- case SHA1_DIGEST_DATA:
- case SHA2_DIGEST_DATA:
- case GHASH_DATA:
- return (CRYPTO_ARGUMENTS_BAD);
- }
+ bcopy(buf, datap, cur_len);
+ buf += cur_len;
length -= cur_len;
vec_idx++;
@@ -100,16 +80,11 @@ crypto_uio_data(crypto_data_t *data, uchar_t *buf, int len, cmd_type_t cmd,
if (vec_idx == zfs_uio_iovcnt(uiop) && length > 0) {
/*
- * The end of the specified iovec's was reached but
+ * The end of the specified iovecs was reached but
* the length requested could not be processed.
*/
- switch (cmd) {
- case COPY_TO_DATA:
- data->cd_length = len;
- return (CRYPTO_BUFFER_TOO_SMALL);
- default:
- return (CRYPTO_DATA_LEN_RANGE);
- }
+ data->cd_length = len;
+ return (CRYPTO_BUFFER_TOO_SMALL);
}
return (CRYPTO_SUCCESS);
@@ -129,8 +104,7 @@ crypto_put_output_data(uchar_t *buf, crypto_data_t *output, int len)
break;
case CRYPTO_DATA_UIO:
- return (crypto_uio_data(output, buf, len,
- COPY_TO_DATA, NULL, NULL));
+ return (crypto_uio_copy_to_data(output, buf, len));
default:
return (CRYPTO_ARGUMENTS_BAD);
}
@@ -140,33 +114,21 @@ crypto_put_output_data(uchar_t *buf, crypto_data_t *output, int len)
int
crypto_update_iov(void *ctx, crypto_data_t *input, crypto_data_t *output,
- int (*cipher)(void *, caddr_t, size_t, crypto_data_t *),
- void (*copy_block)(uint8_t *, uint64_t *))
+ int (*cipher)(void *, caddr_t, size_t, crypto_data_t *))
{
- common_ctx_t *common_ctx = ctx;
- int rv;
-
ASSERT(input != output);
- if (input->cd_miscdata != NULL) {
- copy_block((uint8_t *)input->cd_miscdata,
- &common_ctx->cc_iv[0]);
- }
if (input->cd_raw.iov_len < input->cd_length)
return (CRYPTO_ARGUMENTS_BAD);
- rv = (cipher)(ctx, input->cd_raw.iov_base + input->cd_offset,
- input->cd_length, output);
-
- return (rv);
+ return ((cipher)(ctx, input->cd_raw.iov_base + input->cd_offset,
+ input->cd_length, output));
}
int
crypto_update_uio(void *ctx, crypto_data_t *input, crypto_data_t *output,
- int (*cipher)(void *, caddr_t, size_t, crypto_data_t *),
- void (*copy_block)(uint8_t *, uint64_t *))
+ int (*cipher)(void *, caddr_t, size_t, crypto_data_t *))
{
- common_ctx_t *common_ctx = ctx;
zfs_uio_t *uiop = input->cd_uio;
off_t offset = input->cd_offset;
size_t length = input->cd_length;
@@ -174,10 +136,6 @@ crypto_update_uio(void *ctx, crypto_data_t *input, crypto_data_t *output,
size_t cur_len;
ASSERT(input != output);
- if (input->cd_miscdata != NULL) {
- copy_block((uint8_t *)input->cd_miscdata,
- &common_ctx->cc_iv[0]);
- }
if (zfs_uio_segflg(input->cd_uio) != UIO_SYSSPACE) {
return (CRYPTO_ARGUMENTS_BAD);
diff --git a/sys/contrib/openzfs/module/icp/core/kcf_prov_tabs.c b/sys/contrib/openzfs/module/icp/core/kcf_prov_tabs.c
index 664e96da9c28..029d0526ec97 100644
--- a/sys/contrib/openzfs/module/icp/core/kcf_prov_tabs.c
+++ b/sys/contrib/openzfs/module/icp/core/kcf_prov_tabs.c
@@ -45,7 +45,7 @@
#include <sys/crypto/sched_impl.h>
#include <sys/crypto/spi.h>
-#define KCF_MAX_PROVIDERS 512 /* max number of providers */
+#define KCF_MAX_PROVIDERS 8 /* max number of providers */
/*
* Prov_tab is an array of providers which is updated when
@@ -59,33 +59,25 @@
*
* prov_tab entries are not updated from kcf.conf or by cryptoadm(1M).
*/
-static kcf_provider_desc_t **prov_tab = NULL;
+static kcf_provider_desc_t *prov_tab[KCF_MAX_PROVIDERS];
static kmutex_t prov_tab_mutex; /* ensure exclusive access to the table */
static uint_t prov_tab_num = 0; /* number of providers in table */
-static uint_t prov_tab_max = KCF_MAX_PROVIDERS;
void
kcf_prov_tab_destroy(void)
{
mutex_destroy(&prov_tab_mutex);
-
- if (prov_tab)
- kmem_free(prov_tab, prov_tab_max *
- sizeof (kcf_provider_desc_t *));
}
/*
* Initialize a mutex and the KCF providers table, prov_tab.
- * The providers table is dynamically allocated with prov_tab_max entries.
+ * The providers table is dynamically allocated with KCF_MAX_PROVIDERS entries.
* Called from kcf module _init().
*/
void
kcf_prov_tab_init(void)
{
mutex_init(&prov_tab_mutex, NULL, MUTEX_DEFAULT, NULL);
-
- prov_tab = kmem_zalloc(prov_tab_max * sizeof (kcf_provider_desc_t *),
- KM_SLEEP);
}
/*
@@ -101,8 +93,6 @@ kcf_prov_tab_add_provider(kcf_provider_desc_t *prov_desc)
{
uint_t i;
- ASSERT(prov_tab != NULL);
-
mutex_enter(&prov_tab_mutex);
/* find free slot in providers table */
@@ -146,9 +136,6 @@ kcf_prov_tab_rem_provider(crypto_provider_id_t prov_id)
{
kcf_provider_desc_t *prov_desc;
- ASSERT(prov_tab != NULL);
- ASSERT(prov_tab_num >= 0);
-
/*
* Validate provider id, since it can be specified by a 3rd-party
* provider.
@@ -204,92 +191,6 @@ kcf_prov_tab_lookup(crypto_provider_id_t prov_id)
return (prov_desc);
}
-static void
-allocate_ops_v1(const crypto_ops_t *src, crypto_ops_t *dst,
- uint_t *mech_list_count)
-{
- if (src->co_control_ops != NULL)
- dst->co_control_ops = kmem_alloc(sizeof (crypto_control_ops_t),
- KM_SLEEP);
-
- if (src->co_digest_ops != NULL)
- dst->co_digest_ops = kmem_alloc(sizeof (crypto_digest_ops_t),
- KM_SLEEP);
-
- if (src->co_cipher_ops != NULL)
- dst->co_cipher_ops = kmem_alloc(sizeof (crypto_cipher_ops_t),
- KM_SLEEP);
-
- if (src->co_mac_ops != NULL)
- dst->co_mac_ops = kmem_alloc(sizeof (crypto_mac_ops_t),
- KM_SLEEP);
-
- if (src->co_sign_ops != NULL)
- dst->co_sign_ops = kmem_alloc(sizeof (crypto_sign_ops_t),
- KM_SLEEP);
-
- if (src->co_verify_ops != NULL)
- dst->co_verify_ops = kmem_alloc(sizeof (crypto_verify_ops_t),
- KM_SLEEP);
-
- if (src->co_dual_ops != NULL)
- dst->co_dual_ops = kmem_alloc(sizeof (crypto_dual_ops_t),
- KM_SLEEP);
-
- if (src->co_dual_cipher_mac_ops != NULL)
- dst->co_dual_cipher_mac_ops = kmem_alloc(
- sizeof (crypto_dual_cipher_mac_ops_t), KM_SLEEP);
-
- if (src->co_random_ops != NULL) {
- dst->co_random_ops = kmem_alloc(
- sizeof (crypto_random_number_ops_t), KM_SLEEP);
-
- /*
- * Allocate storage to store the array of supported mechanisms
- * specified by provider. We allocate extra mechanism storage
- * if the provider has random_ops since we keep an internal
- * mechanism, SUN_RANDOM, in this case.
- */
- (*mech_list_count)++;
- }
-
- if (src->co_session_ops != NULL)
- dst->co_session_ops = kmem_alloc(sizeof (crypto_session_ops_t),
- KM_SLEEP);
-
- if (src->co_object_ops != NULL)
- dst->co_object_ops = kmem_alloc(sizeof (crypto_object_ops_t),
- KM_SLEEP);
-
- if (src->co_key_ops != NULL)
- dst->co_key_ops = kmem_alloc(sizeof (crypto_key_ops_t),
- KM_SLEEP);
-
- if (src->co_provider_ops != NULL)
- dst->co_provider_ops = kmem_alloc(
- sizeof (crypto_provider_management_ops_t), KM_SLEEP);
-
- if (src->co_ctx_ops != NULL)
- dst->co_ctx_ops = kmem_alloc(sizeof (crypto_ctx_ops_t),
- KM_SLEEP);
-}
-
-static void
-allocate_ops_v2(const crypto_ops_t *src, crypto_ops_t *dst)
-{
- if (src->co_mech_ops != NULL)
- dst->co_mech_ops = kmem_alloc(sizeof (crypto_mech_ops_t),
- KM_SLEEP);
-}
-
-static void
-allocate_ops_v3(const crypto_ops_t *src, crypto_ops_t *dst)
-{
- if (src->co_nostore_key_ops != NULL)
- dst->co_nostore_key_ops =
- kmem_alloc(sizeof (crypto_nostore_key_ops_t), KM_SLEEP);
-}
-
/*
* Allocate a provider descriptor. mech_list_count specifies the
* number of mechanisms supported by the providers, and is used
@@ -298,52 +199,11 @@ allocate_ops_v3(const crypto_ops_t *src, crypto_ops_t *dst)
* since it is invoked from user context during provider registration.
*/
kcf_provider_desc_t *
-kcf_alloc_provider_desc(const crypto_provider_info_t *info)
+kcf_alloc_provider_desc(void)
{
- kcf_provider_desc_t *desc;
- uint_t mech_list_count = info->pi_mech_list_count;
- const crypto_ops_t *src_ops = info->pi_ops_vector;
-
- desc = kmem_zalloc(sizeof (kcf_provider_desc_t), KM_SLEEP);
-
- /*
- * pd_description serves two purposes
- * - Appears as a blank padded PKCS#11 style string, that will be
- * returned to applications in CK_SLOT_INFO.slotDescription.
- * This means that we should not have a null character in the
- * first CRYPTO_PROVIDER_DESCR_MAX_LEN bytes.
- * - Appears as a null-terminated string that can be used by
- * other kcf routines.
- *
- * So, we allocate enough room for one extra null terminator
- * which keeps every one happy.
- */
- desc->pd_description = kmem_alloc(CRYPTO_PROVIDER_DESCR_MAX_LEN + 1,
- KM_SLEEP);
- (void) memset(desc->pd_description, ' ',
- CRYPTO_PROVIDER_DESCR_MAX_LEN);
- desc->pd_description[CRYPTO_PROVIDER_DESCR_MAX_LEN] = '\0';
-
- /*
- * Since the framework does not require the ops vector specified
- * by the providers during registration to be persistent,
- * KCF needs to allocate storage where copies of the ops
- * vectors are copied.
- */
- crypto_ops_t *opvec = kmem_zalloc(sizeof (crypto_ops_t), KM_SLEEP);
-
- if (info->pi_provider_type != CRYPTO_LOGICAL_PROVIDER) {
- allocate_ops_v1(src_ops, opvec, &mech_list_count);
- if (info->pi_interface_version >= CRYPTO_SPI_VERSION_2)
- allocate_ops_v2(src_ops, opvec);
- if (info->pi_interface_version == CRYPTO_SPI_VERSION_3)
- allocate_ops_v3(src_ops, opvec);
- }
- desc->pd_ops_vector = opvec;
+ kcf_provider_desc_t *desc =
+ kmem_zalloc(sizeof (kcf_provider_desc_t), KM_SLEEP);
- desc->pd_mech_list_count = mech_list_count;
- desc->pd_mechanisms = kmem_zalloc(sizeof (crypto_mech_info_t) *
- mech_list_count, KM_SLEEP);
for (int i = 0; i < KCF_OPS_CLASSSIZE; i++)
for (int j = 0; j < KCF_MAXMECHTAB; j++)
desc->pd_mech_indx[i][j] = KCF_INVALID_INDX;
@@ -352,7 +212,6 @@ kcf_alloc_provider_desc(const crypto_provider_info_t *info)
desc->pd_state = KCF_PROV_ALLOCATED;
mutex_init(&desc->pd_lock, NULL, MUTEX_DEFAULT, NULL);
- cv_init(&desc->pd_resume_cv, NULL, CV_DEFAULT, NULL);
cv_init(&desc->pd_remove_cv, NULL, CV_DEFAULT, NULL);
return (desc);
@@ -361,7 +220,7 @@ kcf_alloc_provider_desc(const crypto_provider_info_t *info)
/*
* Called by KCF_PROV_REFRELE when a provider's reference count drops
* to zero. We free the descriptor when the last reference is released.
- * However, for software providers, we do not free it when there is an
+ * However, for providers, we do not free it when there is an
* unregister thread waiting. We signal that thread in this case and
* that thread is responsible for freeing the descriptor.
*/
@@ -369,22 +228,16 @@ void
kcf_provider_zero_refcnt(kcf_provider_desc_t *desc)
{
mutex_enter(&desc->pd_lock);
- switch (desc->pd_prov_type) {
- case CRYPTO_SW_PROVIDER:
- if (desc->pd_state == KCF_PROV_REMOVED ||
- desc->pd_state == KCF_PROV_DISABLED) {
- desc->pd_state = KCF_PROV_FREED;
- cv_broadcast(&desc->pd_remove_cv);
- mutex_exit(&desc->pd_lock);
- break;
- }
- fallthrough;
-
- case CRYPTO_HW_PROVIDER:
- case CRYPTO_LOGICAL_PROVIDER:
+ if (desc->pd_state == KCF_PROV_REMOVED ||
+ desc->pd_state == KCF_PROV_DISABLED) {
+ desc->pd_state = KCF_PROV_FREED;
+ cv_broadcast(&desc->pd_remove_cv);
mutex_exit(&desc->pd_lock);
- kcf_free_provider_desc(desc);
+ return;
}
+
+ mutex_exit(&desc->pd_lock);
+ kcf_free_provider_desc(desc);
}
/*
@@ -407,202 +260,15 @@ kcf_free_provider_desc(kcf_provider_desc_t *desc)
/* free the kernel memory associated with the provider descriptor */
- if (desc->pd_description != NULL)
- kmem_free(desc->pd_description,
- CRYPTO_PROVIDER_DESCR_MAX_LEN + 1);
-
- if (desc->pd_ops_vector != NULL) {
-
- if (desc->pd_ops_vector->co_control_ops != NULL)
- kmem_free(desc->pd_ops_vector->co_control_ops,
- sizeof (crypto_control_ops_t));
-
- if (desc->pd_ops_vector->co_digest_ops != NULL)
- kmem_free(desc->pd_ops_vector->co_digest_ops,
- sizeof (crypto_digest_ops_t));
-
- if (desc->pd_ops_vector->co_cipher_ops != NULL)
- kmem_free(desc->pd_ops_vector->co_cipher_ops,
- sizeof (crypto_cipher_ops_t));
-
- if (desc->pd_ops_vector->co_mac_ops != NULL)
- kmem_free(desc->pd_ops_vector->co_mac_ops,
- sizeof (crypto_mac_ops_t));
-
- if (desc->pd_ops_vector->co_sign_ops != NULL)
- kmem_free(desc->pd_ops_vector->co_sign_ops,
- sizeof (crypto_sign_ops_t));
-
- if (desc->pd_ops_vector->co_verify_ops != NULL)
- kmem_free(desc->pd_ops_vector->co_verify_ops,
- sizeof (crypto_verify_ops_t));
-
- if (desc->pd_ops_vector->co_dual_ops != NULL)
- kmem_free(desc->pd_ops_vector->co_dual_ops,
- sizeof (crypto_dual_ops_t));
-
- if (desc->pd_ops_vector->co_dual_cipher_mac_ops != NULL)
- kmem_free(desc->pd_ops_vector->co_dual_cipher_mac_ops,
- sizeof (crypto_dual_cipher_mac_ops_t));
-
- if (desc->pd_ops_vector->co_random_ops != NULL)
- kmem_free(desc->pd_ops_vector->co_random_ops,
- sizeof (crypto_random_number_ops_t));
-
- if (desc->pd_ops_vector->co_session_ops != NULL)
- kmem_free(desc->pd_ops_vector->co_session_ops,
- sizeof (crypto_session_ops_t));
-
- if (desc->pd_ops_vector->co_object_ops != NULL)
- kmem_free(desc->pd_ops_vector->co_object_ops,
- sizeof (crypto_object_ops_t));
-
- if (desc->pd_ops_vector->co_key_ops != NULL)
- kmem_free(desc->pd_ops_vector->co_key_ops,
- sizeof (crypto_key_ops_t));
-
- if (desc->pd_ops_vector->co_provider_ops != NULL)
- kmem_free(desc->pd_ops_vector->co_provider_ops,
- sizeof (crypto_provider_management_ops_t));
-
- if (desc->pd_ops_vector->co_ctx_ops != NULL)
- kmem_free(desc->pd_ops_vector->co_ctx_ops,
- sizeof (crypto_ctx_ops_t));
-
- if (desc->pd_ops_vector->co_mech_ops != NULL)
- kmem_free(desc->pd_ops_vector->co_mech_ops,
- sizeof (crypto_mech_ops_t));
-
- if (desc->pd_ops_vector->co_nostore_key_ops != NULL)
- kmem_free(desc->pd_ops_vector->co_nostore_key_ops,
- sizeof (crypto_nostore_key_ops_t));
-
- kmem_free(desc->pd_ops_vector, sizeof (crypto_ops_t));
- }
-
- if (desc->pd_mechanisms != NULL)
- /* free the memory associated with the mechanism info's */
- kmem_free(desc->pd_mechanisms, sizeof (crypto_mech_info_t) *
- desc->pd_mech_list_count);
-
- if (desc->pd_sched_info.ks_taskq != NULL)
- taskq_destroy(desc->pd_sched_info.ks_taskq);
-
mutex_destroy(&desc->pd_lock);
- cv_destroy(&desc->pd_resume_cv);
cv_destroy(&desc->pd_remove_cv);
kmem_free(desc, sizeof (kcf_provider_desc_t));
}
/*
- * Returns an array of hardware and logical provider descriptors,
- * a.k.a the PKCS#11 slot list. A REFHOLD is done on each descriptor
- * before the array is returned. The entire table can be freed by
- * calling kcf_free_provider_tab().
- */
-int
-kcf_get_slot_list(uint_t *count, kcf_provider_desc_t ***array,
- boolean_t unverified)
-{
- kcf_provider_desc_t *prov_desc;
- kcf_provider_desc_t **p = NULL;
- char *last;
- uint_t cnt = 0;
- uint_t i, j;
- int rval = CRYPTO_SUCCESS;
- size_t n, final_size;
-
- /* count the providers */
- mutex_enter(&prov_tab_mutex);
- for (i = 0; i < KCF_MAX_PROVIDERS; i++) {
- if ((prov_desc = prov_tab[i]) != NULL &&
- ((prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER &&
- (prov_desc->pd_flags & CRYPTO_HIDE_PROVIDER) == 0) ||
- prov_desc->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)) {
- if (KCF_IS_PROV_USABLE(prov_desc) ||
- (unverified && KCF_IS_PROV_UNVERIFIED(prov_desc))) {
- cnt++;
- }
- }
- }
- mutex_exit(&prov_tab_mutex);
-
- if (cnt == 0)
- goto out;
-
- n = cnt * sizeof (kcf_provider_desc_t *);
-again:
- p = kmem_zalloc(n, KM_SLEEP);
-
- /* pointer to last entry in the array */
- last = (char *)&p[cnt-1];
-
- mutex_enter(&prov_tab_mutex);
- /* fill the slot list */
- for (i = 0, j = 0; i < KCF_MAX_PROVIDERS; i++) {
- if ((prov_desc = prov_tab[i]) != NULL &&
- ((prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER &&
- (prov_desc->pd_flags & CRYPTO_HIDE_PROVIDER) == 0) ||
- prov_desc->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)) {
- if (KCF_IS_PROV_USABLE(prov_desc) ||
- (unverified && KCF_IS_PROV_UNVERIFIED(prov_desc))) {
- if ((char *)&p[j] > last) {
- mutex_exit(&prov_tab_mutex);
- kcf_free_provider_tab(cnt, p);
- n = n << 1;
- cnt = cnt << 1;
- goto again;
- }
- p[j++] = prov_desc;
- KCF_PROV_REFHOLD(prov_desc);
- }
- }
- }
- mutex_exit(&prov_tab_mutex);
-
- final_size = j * sizeof (kcf_provider_desc_t *);
- cnt = j;
- ASSERT(final_size <= n);
-
- /* check if buffer we allocated is too large */
- if (final_size < n) {
- char *final_buffer = NULL;
-
- if (final_size > 0) {
- final_buffer = kmem_alloc(final_size, KM_SLEEP);
- bcopy(p, final_buffer, final_size);
- }
- kmem_free(p, n);
- p = (kcf_provider_desc_t **)final_buffer;
- }
-out:
- *count = cnt;
- *array = p;
- return (rval);
-}
-
-/*
- * Free an array of hardware provider descriptors. A REFRELE
- * is done on each descriptor before the table is freed.
- */
-void
-kcf_free_provider_tab(uint_t count, kcf_provider_desc_t **array)
-{
- kcf_provider_desc_t *prov_desc;
- int i;
-
- for (i = 0; i < count; i++) {
- if ((prov_desc = array[i]) != NULL) {
- KCF_PROV_REFRELE(prov_desc);
- }
- }
- kmem_free(array, count * sizeof (kcf_provider_desc_t *));
-}
-
-/*
* Returns in the location pointed to by pd a pointer to the descriptor
- * for the software provider for the specified mechanism.
+ * for the provider for the specified mechanism.
* The provider descriptor is returned held and it is the caller's
* responsibility to release it when done. The mechanism entry
* is returned if the optional argument mep is non NULL.
@@ -620,24 +286,17 @@ kcf_get_sw_prov(crypto_mech_type_t mech_type, kcf_provider_desc_t **pd,
if (kcf_get_mech_entry(mech_type, &me) != KCF_SUCCESS)
return (CRYPTO_MECHANISM_INVALID);
- /*
- * Get the software provider for this mechanism.
- * Lock the mech_entry until we grab the 'pd'.
- */
- mutex_enter(&me->me_mutex);
-
+ /* Get the provider for this mechanism. */
if (me->me_sw_prov == NULL ||
(*pd = me->me_sw_prov->pm_prov_desc) == NULL) {
- /* no SW provider for this mechanism */
+ /* no provider for this mechanism */
if (log_warn)
- cmn_err(CE_WARN, "no SW provider for \"%s\"\n",
+ cmn_err(CE_WARN, "no provider for \"%s\"\n",
me->me_name);
- mutex_exit(&me->me_mutex);
return (CRYPTO_MECH_NOT_SUPPORTED);
}
KCF_PROV_REFHOLD(*pd);
- mutex_exit(&me->me_mutex);
if (mep != NULL)
*mep = me;
diff --git a/sys/contrib/openzfs/module/icp/core/kcf_sched.c b/sys/contrib/openzfs/module/icp/core/kcf_sched.c
index 062e96059f20..7d2b46a5f1f8 100644
--- a/sys/contrib/openzfs/module/icp/core/kcf_sched.c
+++ b/sys/contrib/openzfs/module/icp/core/kcf_sched.c
@@ -35,771 +35,36 @@
#include <sys/crypto/sched_impl.h>
#include <sys/crypto/api.h>
-static kcf_global_swq_t *gswq; /* Global software queue */
-
-/* Thread pool related variables */
-static kcf_pool_t *kcfpool; /* Thread pool of kcfd LWPs */
-static const int kcf_maxthreads = 2;
-static const int kcf_minthreads = 1;
-
/* kmem caches used by the scheduler */
-static kmem_cache_t *kcf_sreq_cache;
-static kmem_cache_t *kcf_areq_cache;
static kmem_cache_t *kcf_context_cache;
-/* Global request ID table */
-static kcf_reqid_table_t *kcf_reqid_table[REQID_TABLES];
-
-/* KCF stats. Not protected. */
-static kcf_stats_t kcf_ksdata = {
- { "total threads in pool", KSTAT_DATA_UINT32},
- { "idle threads in pool", KSTAT_DATA_UINT32},
- { "min threads in pool", KSTAT_DATA_UINT32},
- { "max threads in pool", KSTAT_DATA_UINT32},
- { "requests in gswq", KSTAT_DATA_UINT32},
- { "max requests in gswq", KSTAT_DATA_UINT32},
- { "threads for HW taskq", KSTAT_DATA_UINT32},
- { "minalloc for HW taskq", KSTAT_DATA_UINT32},
- { "maxalloc for HW taskq", KSTAT_DATA_UINT32}
-};
-
-static kstat_t *kcf_misc_kstat = NULL;
-ulong_t kcf_swprov_hndl = 0;
-
-static kcf_areq_node_t *kcf_areqnode_alloc(kcf_provider_desc_t *,
- kcf_context_t *, crypto_call_req_t *, kcf_req_params_t *, boolean_t);
-static int kcf_disp_sw_request(kcf_areq_node_t *);
-static void process_req_hwp(void *);
-static int kcf_enqueue(kcf_areq_node_t *);
-static void kcfpool_alloc(void);
-static void kcf_reqid_delete(kcf_areq_node_t *areq);
-static crypto_req_id_t kcf_reqid_insert(kcf_areq_node_t *areq);
-static int kcf_misc_kstat_update(kstat_t *ksp, int rw);
-
/*
* Create a new context.
*/
crypto_ctx_t *
-kcf_new_ctx(crypto_call_req_t *crq, kcf_provider_desc_t *pd,
- crypto_session_id_t sid)
+kcf_new_ctx(kcf_provider_desc_t *pd)
{
crypto_ctx_t *ctx;
kcf_context_t *kcf_ctx;
- kcf_ctx = kmem_cache_alloc(kcf_context_cache,
- (crq == NULL) ? KM_SLEEP : KM_NOSLEEP);
+ kcf_ctx = kmem_cache_alloc(kcf_context_cache, KM_SLEEP);
if (kcf_ctx == NULL)
return (NULL);
/* initialize the context for the consumer */
kcf_ctx->kc_refcnt = 1;
- kcf_ctx->kc_req_chain_first = NULL;
- kcf_ctx->kc_req_chain_last = NULL;
- kcf_ctx->kc_secondctx = NULL;
KCF_PROV_REFHOLD(pd);
kcf_ctx->kc_prov_desc = pd;
kcf_ctx->kc_sw_prov_desc = NULL;
- kcf_ctx->kc_mech = NULL;
ctx = &kcf_ctx->kc_glbl_ctx;
- ctx->cc_provider = pd->pd_prov_handle;
- ctx->cc_session = sid;
ctx->cc_provider_private = NULL;
ctx->cc_framework_private = (void *)kcf_ctx;
- ctx->cc_flags = 0;
- ctx->cc_opstate = NULL;
return (ctx);
}
/*
- * Allocate a new async request node.
- *
- * ictx - Framework private context pointer
- * crq - Has callback function and argument. Should be non NULL.
- * req - The parameters to pass to the SPI
- */
-static kcf_areq_node_t *
-kcf_areqnode_alloc(kcf_provider_desc_t *pd, kcf_context_t *ictx,
- crypto_call_req_t *crq, kcf_req_params_t *req, boolean_t isdual)
-{
- kcf_areq_node_t *arptr, *areq;
-
- ASSERT(crq != NULL);
- arptr = kmem_cache_alloc(kcf_areq_cache, KM_NOSLEEP);
- if (arptr == NULL)
- return (NULL);
-
- arptr->an_state = REQ_ALLOCATED;
- arptr->an_reqarg = *crq;
- arptr->an_params = *req;
- arptr->an_context = ictx;
- arptr->an_isdual = isdual;
-
- arptr->an_next = arptr->an_prev = NULL;
- KCF_PROV_REFHOLD(pd);
- arptr->an_provider = pd;
- arptr->an_tried_plist = NULL;
- arptr->an_refcnt = 1;
- arptr->an_idnext = arptr->an_idprev = NULL;
-
- /*
- * Requests for context-less operations do not use the
- * fields - an_is_my_turn, and an_ctxchain_next.
- */
- if (ictx == NULL)
- return (arptr);
-
- KCF_CONTEXT_REFHOLD(ictx);
- /*
- * Chain this request to the context.
- */
- mutex_enter(&ictx->kc_in_use_lock);
- arptr->an_ctxchain_next = NULL;
- if ((areq = ictx->kc_req_chain_last) == NULL) {
- arptr->an_is_my_turn = B_TRUE;
- ictx->kc_req_chain_last =
- ictx->kc_req_chain_first = arptr;
- } else {
- ASSERT(ictx->kc_req_chain_first != NULL);
- arptr->an_is_my_turn = B_FALSE;
- /* Insert the new request to the end of the chain. */
- areq->an_ctxchain_next = arptr;
- ictx->kc_req_chain_last = arptr;
- }
- mutex_exit(&ictx->kc_in_use_lock);
-
- return (arptr);
-}
-
-/*
- * Queue the request node and do one of the following:
- * - If there is an idle thread signal it to run.
- * - If there is no idle thread and max running threads is not
- * reached, signal the creator thread for more threads.
- *
- * If the two conditions above are not met, we don't need to do
- * anything. The request will be picked up by one of the
- * worker threads when it becomes available.
- */
-static int
-kcf_disp_sw_request(kcf_areq_node_t *areq)
-{
- int err;
- int cnt = 0;
-
- if ((err = kcf_enqueue(areq)) != 0)
- return (err);
-
- if (kcfpool->kp_idlethreads > 0) {
- /* Signal an idle thread to run */
- mutex_enter(&gswq->gs_lock);
- cv_signal(&gswq->gs_cv);
- mutex_exit(&gswq->gs_lock);
-
- return (CRYPTO_QUEUED);
- }
-
- /*
- * We keep the number of running threads to be at
- * kcf_minthreads to reduce gs_lock contention.
- */
- cnt = kcf_minthreads -
- (kcfpool->kp_threads - kcfpool->kp_blockedthreads);
- if (cnt > 0) {
- /*
- * The following ensures the number of threads in pool
- * does not exceed kcf_maxthreads.
- */
- cnt = MIN(cnt, kcf_maxthreads - (int)kcfpool->kp_threads);
- if (cnt > 0) {
- /* Signal the creator thread for more threads */
- mutex_enter(&kcfpool->kp_user_lock);
- if (!kcfpool->kp_signal_create_thread) {
- kcfpool->kp_signal_create_thread = B_TRUE;
- kcfpool->kp_nthrs = cnt;
- cv_signal(&kcfpool->kp_user_cv);
- }
- mutex_exit(&kcfpool->kp_user_lock);
- }
- }
-
- return (CRYPTO_QUEUED);
-}
-
-/*
- * This routine is called by the taskq associated with
- * each hardware provider. We notify the kernel consumer
- * via the callback routine in case of CRYPTO_SUCCESS or
- * a failure.
- *
- * A request can be of type kcf_areq_node_t or of type
- * kcf_sreq_node_t.
- */
-static void
-process_req_hwp(void *ireq)
-{
- int error = 0;
- crypto_ctx_t *ctx;
- kcf_call_type_t ctype;
- kcf_provider_desc_t *pd;
- kcf_areq_node_t *areq = (kcf_areq_node_t *)ireq;
- kcf_sreq_node_t *sreq = (kcf_sreq_node_t *)ireq;
-
- pd = ((ctype = GET_REQ_TYPE(ireq)) == CRYPTO_SYNCH) ?
- sreq->sn_provider : areq->an_provider;
-
- /*
- * Wait if flow control is in effect for the provider. A
- * CRYPTO_PROVIDER_READY or CRYPTO_PROVIDER_FAILED
- * notification will signal us. We also get signaled if
- * the provider is unregistering.
- */
- if (pd->pd_state == KCF_PROV_BUSY) {
- mutex_enter(&pd->pd_lock);
- while (pd->pd_state == KCF_PROV_BUSY)
- cv_wait(&pd->pd_resume_cv, &pd->pd_lock);
- mutex_exit(&pd->pd_lock);
- }
-
- /*
- * Bump the internal reference count while the request is being
- * processed. This is how we know when it's safe to unregister
- * a provider. This step must precede the pd_state check below.
- */
- KCF_PROV_IREFHOLD(pd);
-
- /*
- * Fail the request if the provider has failed. We return a
- * recoverable error and the notified clients attempt any
- * recovery. For async clients this is done in kcf_aop_done()
- * and for sync clients it is done in the k-api routines.
- */
- if (pd->pd_state >= KCF_PROV_FAILED) {
- error = CRYPTO_DEVICE_ERROR;
- goto bail;
- }
-
- if (ctype == CRYPTO_SYNCH) {
- mutex_enter(&sreq->sn_lock);
- sreq->sn_state = REQ_INPROGRESS;
- mutex_exit(&sreq->sn_lock);
-
- ctx = sreq->sn_context ? &sreq->sn_context->kc_glbl_ctx : NULL;
- error = common_submit_request(sreq->sn_provider, ctx,
- sreq->sn_params, sreq);
- } else {
- kcf_context_t *ictx;
- ASSERT(ctype == CRYPTO_ASYNCH);
-
- /*
- * We are in the per-hardware provider thread context and
- * hence can sleep. Note that the caller would have done
- * a taskq_dispatch(..., TQ_NOSLEEP) and would have returned.
- */
- ctx = (ictx = areq->an_context) ? &ictx->kc_glbl_ctx : NULL;
-
- mutex_enter(&areq->an_lock);
- /*
- * We need to maintain ordering for multi-part requests.
- * an_is_my_turn is set to B_TRUE initially for a request
- * when it is enqueued and there are no other requests
- * for that context. It is set later from kcf_aop_done() when
- * the request before us in the chain of requests for the
- * context completes. We get signaled at that point.
- */
- if (ictx != NULL) {
- ASSERT(ictx->kc_prov_desc == areq->an_provider);
-
- while (areq->an_is_my_turn == B_FALSE) {
- cv_wait(&areq->an_turn_cv, &areq->an_lock);
- }
- }
- areq->an_state = REQ_INPROGRESS;
- mutex_exit(&areq->an_lock);
-
- error = common_submit_request(areq->an_provider, ctx,
- &areq->an_params, areq);
- }
-
-bail:
- if (error == CRYPTO_QUEUED) {
- /*
- * The request is queued by the provider and we should
- * get a crypto_op_notification() from the provider later.
- * We notify the consumer at that time.
- */
- return;
- } else { /* CRYPTO_SUCCESS or other failure */
- KCF_PROV_IREFRELE(pd);
- if (ctype == CRYPTO_SYNCH)
- kcf_sop_done(sreq, error);
- else
- kcf_aop_done(areq, error);
- }
-}
-
-/*
- * This routine checks if a request can be retried on another
- * provider. If true, mech1 is initialized to point to the mechanism
- * structure. mech2 is also initialized in case of a dual operation. fg
- * is initialized to the correct crypto_func_group_t bit flag. They are
- * initialized by this routine, so that the caller can pass them to a
- * kcf_get_mech_provider() or kcf_get_dual_provider() with no further change.
- *
- * We check that the request is for a init or atomic routine and that
- * it is for one of the operation groups used from k-api .
- */
-static boolean_t
-can_resubmit(kcf_areq_node_t *areq, crypto_mechanism_t **mech1,
- crypto_mechanism_t **mech2, crypto_func_group_t *fg)
-{
- kcf_req_params_t *params;
- kcf_op_type_t optype;
-
- params = &areq->an_params;
- optype = params->rp_optype;
-
- if (!(IS_INIT_OP(optype) || IS_ATOMIC_OP(optype)))
- return (B_FALSE);
-
- switch (params->rp_opgrp) {
- case KCF_OG_DIGEST: {
- kcf_digest_ops_params_t *dops = &params->rp_u.digest_params;
-
- dops->do_mech.cm_type = dops->do_framework_mechtype;
- *mech1 = &dops->do_mech;
- *fg = (optype == KCF_OP_INIT) ? CRYPTO_FG_DIGEST :
- CRYPTO_FG_DIGEST_ATOMIC;
- break;
- }
-
- case KCF_OG_MAC: {
- kcf_mac_ops_params_t *mops = &params->rp_u.mac_params;
-
- mops->mo_mech.cm_type = mops->mo_framework_mechtype;
- *mech1 = &mops->mo_mech;
- *fg = (optype == KCF_OP_INIT) ? CRYPTO_FG_MAC :
- CRYPTO_FG_MAC_ATOMIC;
- break;
- }
-
- case KCF_OG_SIGN: {
- kcf_sign_ops_params_t *sops = &params->rp_u.sign_params;
-
- sops->so_mech.cm_type = sops->so_framework_mechtype;
- *mech1 = &sops->so_mech;
- switch (optype) {
- case KCF_OP_INIT:
- *fg = CRYPTO_FG_SIGN;
- break;
- case KCF_OP_ATOMIC:
- *fg = CRYPTO_FG_SIGN_ATOMIC;
- break;
- default:
- ASSERT(optype == KCF_OP_SIGN_RECOVER_ATOMIC);
- *fg = CRYPTO_FG_SIGN_RECOVER_ATOMIC;
- }
- break;
- }
-
- case KCF_OG_VERIFY: {
- kcf_verify_ops_params_t *vops = &params->rp_u.verify_params;
-
- vops->vo_mech.cm_type = vops->vo_framework_mechtype;
- *mech1 = &vops->vo_mech;
- switch (optype) {
- case KCF_OP_INIT:
- *fg = CRYPTO_FG_VERIFY;
- break;
- case KCF_OP_ATOMIC:
- *fg = CRYPTO_FG_VERIFY_ATOMIC;
- break;
- default:
- ASSERT(optype == KCF_OP_VERIFY_RECOVER_ATOMIC);
- *fg = CRYPTO_FG_VERIFY_RECOVER_ATOMIC;
- }
- break;
- }
-
- case KCF_OG_ENCRYPT: {
- kcf_encrypt_ops_params_t *eops = &params->rp_u.encrypt_params;
-
- eops->eo_mech.cm_type = eops->eo_framework_mechtype;
- *mech1 = &eops->eo_mech;
- *fg = (optype == KCF_OP_INIT) ? CRYPTO_FG_ENCRYPT :
- CRYPTO_FG_ENCRYPT_ATOMIC;
- break;
- }
-
- case KCF_OG_DECRYPT: {
- kcf_decrypt_ops_params_t *dcrops = &params->rp_u.decrypt_params;
-
- dcrops->dop_mech.cm_type = dcrops->dop_framework_mechtype;
- *mech1 = &dcrops->dop_mech;
- *fg = (optype == KCF_OP_INIT) ? CRYPTO_FG_DECRYPT :
- CRYPTO_FG_DECRYPT_ATOMIC;
- break;
- }
-
- case KCF_OG_ENCRYPT_MAC: {
- kcf_encrypt_mac_ops_params_t *eops =
- &params->rp_u.encrypt_mac_params;
-
- eops->em_encr_mech.cm_type = eops->em_framework_encr_mechtype;
- *mech1 = &eops->em_encr_mech;
- eops->em_mac_mech.cm_type = eops->em_framework_mac_mechtype;
- *mech2 = &eops->em_mac_mech;
- *fg = (optype == KCF_OP_INIT) ? CRYPTO_FG_ENCRYPT_MAC :
- CRYPTO_FG_ENCRYPT_MAC_ATOMIC;
- break;
- }
-
- case KCF_OG_MAC_DECRYPT: {
- kcf_mac_decrypt_ops_params_t *dops =
- &params->rp_u.mac_decrypt_params;
-
- dops->md_mac_mech.cm_type = dops->md_framework_mac_mechtype;
- *mech1 = &dops->md_mac_mech;
- dops->md_decr_mech.cm_type = dops->md_framework_decr_mechtype;
- *mech2 = &dops->md_decr_mech;
- *fg = (optype == KCF_OP_INIT) ? CRYPTO_FG_MAC_DECRYPT :
- CRYPTO_FG_MAC_DECRYPT_ATOMIC;
- break;
- }
-
- default:
- return (B_FALSE);
- }
-
- return (B_TRUE);
-}
-
-/*
- * This routine is called when a request to a provider has failed
- * with a recoverable error. This routine tries to find another provider
- * and dispatches the request to the new provider, if one is available.
- * We reuse the request structure.
- *
- * A return value of NULL from kcf_get_mech_provider() indicates
- * we have tried the last provider.
- */
-static int
-kcf_resubmit_request(kcf_areq_node_t *areq)
-{
- int error = CRYPTO_FAILED;
- kcf_context_t *ictx;
- kcf_provider_desc_t *old_pd;
- kcf_provider_desc_t *new_pd;
- crypto_mechanism_t *mech1 = NULL, *mech2 = NULL;
- crypto_mech_type_t prov_mt1, prov_mt2;
- crypto_func_group_t fg = 0;
-
- if (!can_resubmit(areq, &mech1, &mech2, &fg))
- return (error);
-
- old_pd = areq->an_provider;
- /*
- * Add old_pd to the list of providers already tried. We release
- * the hold on old_pd (from the earlier kcf_get_mech_provider()) in
- * kcf_free_triedlist().
- */
- if (kcf_insert_triedlist(&areq->an_tried_plist, old_pd,
- KM_NOSLEEP) == NULL)
- return (error);
-
- if (mech1 && !mech2) {
- new_pd = kcf_get_mech_provider(mech1->cm_type, NULL, &error,
- areq->an_tried_plist, fg,
- (areq->an_reqarg.cr_flag & CRYPTO_RESTRICTED), 0);
- } else {
- ASSERT(mech1 != NULL && mech2 != NULL);
-
- new_pd = kcf_get_dual_provider(mech1, mech2, NULL, &prov_mt1,
- &prov_mt2, &error, areq->an_tried_plist, fg, fg,
- (areq->an_reqarg.cr_flag & CRYPTO_RESTRICTED), 0);
- }
-
- if (new_pd == NULL)
- return (error);
-
- /*
- * We reuse the old context by resetting provider specific
- * fields in it.
- */
- if ((ictx = areq->an_context) != NULL) {
- crypto_ctx_t *ctx;
-
- ASSERT(old_pd == ictx->kc_prov_desc);
- KCF_PROV_REFRELE(ictx->kc_prov_desc);
- KCF_PROV_REFHOLD(new_pd);
- ictx->kc_prov_desc = new_pd;
-
- ctx = &ictx->kc_glbl_ctx;
- ctx->cc_provider = new_pd->pd_prov_handle;
- ctx->cc_session = new_pd->pd_sid;
- ctx->cc_provider_private = NULL;
- }
-
- /* We reuse areq. by resetting the provider and context fields. */
- KCF_PROV_REFRELE(old_pd);
- KCF_PROV_REFHOLD(new_pd);
- areq->an_provider = new_pd;
- mutex_enter(&areq->an_lock);
- areq->an_state = REQ_WAITING;
- mutex_exit(&areq->an_lock);
-
- switch (new_pd->pd_prov_type) {
- case CRYPTO_SW_PROVIDER:
- error = kcf_disp_sw_request(areq);
- break;
-
- case CRYPTO_HW_PROVIDER: {
- taskq_t *taskq = new_pd->pd_sched_info.ks_taskq;
-
- if (taskq_dispatch(taskq, process_req_hwp, areq, TQ_NOSLEEP) ==
- TASKQID_INVALID) {
- error = CRYPTO_HOST_MEMORY;
- } else {
- error = CRYPTO_QUEUED;
- }
-
- break;
- default:
- break;
- }
- }
-
- return (error);
-}
-
-static inline int EMPTY_TASKQ(taskq_t *tq)
-{
-#ifdef _KERNEL
- return (tq->tq_lowest_id == tq->tq_next_id);
-#else
- return (tq->tq_task.tqent_next == &tq->tq_task || tq->tq_active == 0);
-#endif
-}
-
-/*
- * Routine called by both ioctl and k-api. The consumer should
- * bundle the parameters into a kcf_req_params_t structure. A bunch
- * of macros are available in ops_impl.h for this bundling. They are:
- *
- * KCF_WRAP_DIGEST_OPS_PARAMS()
- * KCF_WRAP_MAC_OPS_PARAMS()
- * KCF_WRAP_ENCRYPT_OPS_PARAMS()
- * KCF_WRAP_DECRYPT_OPS_PARAMS() ... etc.
- *
- * It is the caller's responsibility to free the ctx argument when
- * appropriate. See the KCF_CONTEXT_COND_RELEASE macro for details.
- */
-int
-kcf_submit_request(kcf_provider_desc_t *pd, crypto_ctx_t *ctx,
- crypto_call_req_t *crq, kcf_req_params_t *params, boolean_t cont)
-{
- int error = CRYPTO_SUCCESS;
- kcf_areq_node_t *areq;
- kcf_sreq_node_t *sreq;
- kcf_context_t *kcf_ctx;
- taskq_t *taskq = pd->pd_sched_info.ks_taskq;
-
- kcf_ctx = ctx ? (kcf_context_t *)ctx->cc_framework_private : NULL;
-
- /* Synchronous cases */
- if (crq == NULL) {
- switch (pd->pd_prov_type) {
- case CRYPTO_SW_PROVIDER:
- error = common_submit_request(pd, ctx, params,
- KCF_RHNDL(KM_SLEEP));
- break;
-
- case CRYPTO_HW_PROVIDER:
- /*
- * Special case for CRYPTO_SYNCHRONOUS providers that
- * never return a CRYPTO_QUEUED error. We skip any
- * request allocation and call the SPI directly.
- */
- if ((pd->pd_flags & CRYPTO_SYNCHRONOUS) &&
- EMPTY_TASKQ(taskq)) {
- KCF_PROV_IREFHOLD(pd);
- if (pd->pd_state == KCF_PROV_READY) {
- error = common_submit_request(pd, ctx,
- params, KCF_RHNDL(KM_SLEEP));
- KCF_PROV_IREFRELE(pd);
- ASSERT(error != CRYPTO_QUEUED);
- break;
- }
- KCF_PROV_IREFRELE(pd);
- }
-
- sreq = kmem_cache_alloc(kcf_sreq_cache, KM_SLEEP);
- sreq->sn_state = REQ_ALLOCATED;
- sreq->sn_rv = CRYPTO_FAILED;
- sreq->sn_params = params;
-
- /*
- * Note that we do not need to hold the context
- * for synchronous case as the context will never
- * become invalid underneath us. We do not need to hold
- * the provider here either as the caller has a hold.
- */
- sreq->sn_context = kcf_ctx;
- ASSERT(KCF_PROV_REFHELD(pd));
- sreq->sn_provider = pd;
-
- ASSERT(taskq != NULL);
- /*
- * Call the SPI directly if the taskq is empty and the
- * provider is not busy, else dispatch to the taskq.
- * Calling directly is fine as this is the synchronous
- * case. This is unlike the asynchronous case where we
- * must always dispatch to the taskq.
- */
- if (EMPTY_TASKQ(taskq) &&
- pd->pd_state == KCF_PROV_READY) {
- process_req_hwp(sreq);
- } else {
- /*
- * We can not tell from taskq_dispatch() return
- * value if we exceeded maxalloc. Hence the
- * check here. Since we are allowed to wait in
- * the synchronous case, we wait for the taskq
- * to become empty.
- */
- if (taskq->tq_nalloc >= crypto_taskq_maxalloc) {
- taskq_wait(taskq);
- }
-
- (void) taskq_dispatch(taskq, process_req_hwp,
- sreq, TQ_SLEEP);
- }
-
- /*
- * Wait for the notification to arrive,
- * if the operation is not done yet.
- * Bug# 4722589 will make the wait a cv_wait_sig().
- */
- mutex_enter(&sreq->sn_lock);
- while (sreq->sn_state < REQ_DONE)
- cv_wait(&sreq->sn_cv, &sreq->sn_lock);
- mutex_exit(&sreq->sn_lock);
-
- error = sreq->sn_rv;
- kmem_cache_free(kcf_sreq_cache, sreq);
-
- break;
-
- default:
- error = CRYPTO_FAILED;
- break;
- }
-
- } else { /* Asynchronous cases */
- switch (pd->pd_prov_type) {
- case CRYPTO_SW_PROVIDER:
- if (!(crq->cr_flag & CRYPTO_ALWAYS_QUEUE)) {
- /*
- * This case has less overhead since there is
- * no switching of context.
- */
- error = common_submit_request(pd, ctx, params,
- KCF_RHNDL(KM_NOSLEEP));
- } else {
- /*
- * CRYPTO_ALWAYS_QUEUE is set. We need to
- * queue the request and return.
- */
- areq = kcf_areqnode_alloc(pd, kcf_ctx, crq,
- params, cont);
- if (areq == NULL)
- error = CRYPTO_HOST_MEMORY;
- else {
- if (!(crq->cr_flag
- & CRYPTO_SKIP_REQID)) {
- /*
- * Set the request handle. This handle
- * is used for any crypto_cancel_req(9f)
- * calls from the consumer. We have to
- * do this before dispatching the
- * request.
- */
- crq->cr_reqid = kcf_reqid_insert(areq);
- }
-
- error = kcf_disp_sw_request(areq);
- /*
- * There is an error processing this
- * request. Remove the handle and
- * release the request structure.
- */
- if (error != CRYPTO_QUEUED) {
- if (!(crq->cr_flag
- & CRYPTO_SKIP_REQID))
- kcf_reqid_delete(areq);
- KCF_AREQ_REFRELE(areq);
- }
- }
- }
- break;
-
- case CRYPTO_HW_PROVIDER:
- /*
- * We need to queue the request and return.
- */
- areq = kcf_areqnode_alloc(pd, kcf_ctx, crq, params,
- cont);
- if (areq == NULL) {
- error = CRYPTO_HOST_MEMORY;
- goto done;
- }
-
- ASSERT(taskq != NULL);
- /*
- * We can not tell from taskq_dispatch() return
- * value if we exceeded maxalloc. Hence the check
- * here.
- */
- if (taskq->tq_nalloc >= crypto_taskq_maxalloc) {
- error = CRYPTO_BUSY;
- KCF_AREQ_REFRELE(areq);
- goto done;
- }
-
- if (!(crq->cr_flag & CRYPTO_SKIP_REQID)) {
- /*
- * Set the request handle. This handle is used
- * for any crypto_cancel_req(9f) calls from the
- * consumer. We have to do this before dispatching
- * the request.
- */
- crq->cr_reqid = kcf_reqid_insert(areq);
- }
-
- if (taskq_dispatch(taskq,
- process_req_hwp, areq, TQ_NOSLEEP) ==
- TASKQID_INVALID) {
- error = CRYPTO_HOST_MEMORY;
- if (!(crq->cr_flag & CRYPTO_SKIP_REQID))
- kcf_reqid_delete(areq);
- KCF_AREQ_REFRELE(areq);
- } else {
- error = CRYPTO_QUEUED;
- }
- break;
-
- default:
- error = CRYPTO_FAILED;
- break;
- }
- }
-
-done:
- return (error);
-}
-
-/*
* We're done with this framework context, so free it. Note that freeing
* framework context (kcf_context) frees the global context (crypto_ctx).
*
@@ -814,12 +79,6 @@ kcf_free_context(kcf_context_t *kcf_ctx)
{
kcf_provider_desc_t *pd = kcf_ctx->kc_prov_desc;
crypto_ctx_t *gctx = &kcf_ctx->kc_glbl_ctx;
- kcf_context_t *kcf_secondctx = kcf_ctx->kc_secondctx;
-
- /* Release the second context, if any */
-
- if (kcf_secondctx != NULL)
- KCF_CONTEXT_REFRELE(kcf_secondctx);
if (gctx->cc_provider_private != NULL) {
mutex_enter(&pd->pd_lock);
@@ -841,186 +100,10 @@ kcf_free_context(kcf_context_t *kcf_ctx)
/* kcf_ctx->kc_prov_desc has a hold on pd */
KCF_PROV_REFRELE(kcf_ctx->kc_prov_desc);
- /* check if this context is shared with a software provider */
- if ((gctx->cc_flags & CRYPTO_INIT_OPSTATE) &&
- kcf_ctx->kc_sw_prov_desc != NULL) {
- KCF_PROV_REFRELE(kcf_ctx->kc_sw_prov_desc);
- }
-
kmem_cache_free(kcf_context_cache, kcf_ctx);
}
/*
- * Free the request after releasing all the holds.
- */
-void
-kcf_free_req(kcf_areq_node_t *areq)
-{
- KCF_PROV_REFRELE(areq->an_provider);
- if (areq->an_context != NULL)
- KCF_CONTEXT_REFRELE(areq->an_context);
-
- if (areq->an_tried_plist != NULL)
- kcf_free_triedlist(areq->an_tried_plist);
- kmem_cache_free(kcf_areq_cache, areq);
-}
-
-/*
- * Utility routine to remove a request from the chain of requests
- * hanging off a context.
- */
-static void
-kcf_removereq_in_ctxchain(kcf_context_t *ictx, kcf_areq_node_t *areq)
-{
- kcf_areq_node_t *cur, *prev;
-
- /*
- * Get context lock, search for areq in the chain and remove it.
- */
- ASSERT(ictx != NULL);
- mutex_enter(&ictx->kc_in_use_lock);
- prev = cur = ictx->kc_req_chain_first;
-
- while (cur != NULL) {
- if (cur == areq) {
- if (prev == cur) {
- if ((ictx->kc_req_chain_first =
- cur->an_ctxchain_next) == NULL)
- ictx->kc_req_chain_last = NULL;
- } else {
- if (cur == ictx->kc_req_chain_last)
- ictx->kc_req_chain_last = prev;
- prev->an_ctxchain_next = cur->an_ctxchain_next;
- }
-
- break;
- }
- prev = cur;
- cur = cur->an_ctxchain_next;
- }
- mutex_exit(&ictx->kc_in_use_lock);
-}
-
-/*
- * Remove the specified node from the global software queue.
- *
- * The caller must hold the queue lock and request lock (an_lock).
- */
-static void
-kcf_remove_node(kcf_areq_node_t *node)
-{
- kcf_areq_node_t *nextp = node->an_next;
- kcf_areq_node_t *prevp = node->an_prev;
-
- if (nextp != NULL)
- nextp->an_prev = prevp;
- else
- gswq->gs_last = prevp;
-
- if (prevp != NULL)
- prevp->an_next = nextp;
- else
- gswq->gs_first = nextp;
-
- node->an_state = REQ_CANCELED;
-}
-
-/*
- * Add the request node to the end of the global software queue.
- *
- * The caller should not hold the queue lock. Returns 0 if the
- * request is successfully queued. Returns CRYPTO_BUSY if the limit
- * on the number of jobs is exceeded.
- */
-static int
-kcf_enqueue(kcf_areq_node_t *node)
-{
- kcf_areq_node_t *tnode;
-
- mutex_enter(&gswq->gs_lock);
-
- if (gswq->gs_njobs >= gswq->gs_maxjobs) {
- mutex_exit(&gswq->gs_lock);
- return (CRYPTO_BUSY);
- }
-
- if (gswq->gs_last == NULL) {
- gswq->gs_first = gswq->gs_last = node;
- } else {
- ASSERT(gswq->gs_last->an_next == NULL);
- tnode = gswq->gs_last;
- tnode->an_next = node;
- gswq->gs_last = node;
- node->an_prev = tnode;
- }
-
- gswq->gs_njobs++;
-
- /* an_lock not needed here as we hold gs_lock */
- node->an_state = REQ_WAITING;
-
- mutex_exit(&gswq->gs_lock);
-
- return (0);
-}
-
-/*
- * kmem_cache_alloc constructor for sync request structure.
- */
-static int
-kcf_sreq_cache_constructor(void *buf, void *cdrarg, int kmflags)
-{
- (void) cdrarg, (void) kmflags;
- kcf_sreq_node_t *sreq = (kcf_sreq_node_t *)buf;
-
- sreq->sn_type = CRYPTO_SYNCH;
- cv_init(&sreq->sn_cv, NULL, CV_DEFAULT, NULL);
- mutex_init(&sreq->sn_lock, NULL, MUTEX_DEFAULT, NULL);
-
- return (0);
-}
-
-static void
-kcf_sreq_cache_destructor(void *buf, void *cdrarg)
-{
- (void) cdrarg;
- kcf_sreq_node_t *sreq = (kcf_sreq_node_t *)buf;
-
- mutex_destroy(&sreq->sn_lock);
- cv_destroy(&sreq->sn_cv);
-}
-
-/*
- * kmem_cache_alloc constructor for async request structure.
- */
-static int
-kcf_areq_cache_constructor(void *buf, void *cdrarg, int kmflags)
-{
- (void) cdrarg, (void) kmflags;
- kcf_areq_node_t *areq = (kcf_areq_node_t *)buf;
-
- areq->an_type = CRYPTO_ASYNCH;
- areq->an_refcnt = 0;
- mutex_init(&areq->an_lock, NULL, MUTEX_DEFAULT, NULL);
- cv_init(&areq->an_done, NULL, CV_DEFAULT, NULL);
- cv_init(&areq->an_turn_cv, NULL, CV_DEFAULT, NULL);
-
- return (0);
-}
-
-static void
-kcf_areq_cache_destructor(void *buf, void *cdrarg)
-{
- (void) cdrarg;
- kcf_areq_node_t *areq = (kcf_areq_node_t *)buf;
-
- ASSERT(areq->an_refcnt == 0);
- mutex_destroy(&areq->an_lock);
- cv_destroy(&areq->an_done);
- cv_destroy(&areq->an_turn_cv);
-}
-
-/*
* kmem_cache_alloc constructor for kcf_context structure.
*/
static int
@@ -1030,7 +113,6 @@ kcf_context_cache_constructor(void *buf, void *cdrarg, int kmflags)
kcf_context_t *kctx = (kcf_context_t *)buf;
kctx->kc_refcnt = 0;
- mutex_init(&kctx->kc_in_use_lock, NULL, MUTEX_DEFAULT, NULL);
return (0);
}
@@ -1042,49 +124,13 @@ kcf_context_cache_destructor(void *buf, void *cdrarg)
kcf_context_t *kctx = (kcf_context_t *)buf;
ASSERT(kctx->kc_refcnt == 0);
- mutex_destroy(&kctx->kc_in_use_lock);
}
void
kcf_sched_destroy(void)
{
- int i;
-
- if (kcf_misc_kstat)
- kstat_delete(kcf_misc_kstat);
-
- if (kcfpool) {
- mutex_destroy(&kcfpool->kp_thread_lock);
- cv_destroy(&kcfpool->kp_nothr_cv);
- mutex_destroy(&kcfpool->kp_user_lock);
- cv_destroy(&kcfpool->kp_user_cv);
-
- kmem_free(kcfpool, sizeof (kcf_pool_t));
- }
-
- for (i = 0; i < REQID_TABLES; i++) {
- if (kcf_reqid_table[i]) {
- mutex_destroy(&(kcf_reqid_table[i]->rt_lock));
- kmem_free(kcf_reqid_table[i],
- sizeof (kcf_reqid_table_t));
- }
- }
-
- if (gswq) {
- mutex_destroy(&gswq->gs_lock);
- cv_destroy(&gswq->gs_cv);
- kmem_free(gswq, sizeof (kcf_global_swq_t));
- }
-
if (kcf_context_cache)
kmem_cache_destroy(kcf_context_cache);
- if (kcf_areq_cache)
- kmem_cache_destroy(kcf_areq_cache);
- if (kcf_sreq_cache)
- kmem_cache_destroy(kcf_sreq_cache);
-
- mutex_destroy(&ntfy_list_lock);
- cv_destroy(&ntfy_list_cv);
}
/*
@@ -1093,9 +139,6 @@ kcf_sched_destroy(void)
void
kcf_sched_init(void)
{
- int i;
- kcf_reqid_table_t *rt;
-
/*
* Create all the kmem caches needed by the framework. We set the
* align argument to 64, to get a slab aligned to 64-byte as well as
@@ -1103,673 +146,7 @@ kcf_sched_init(void)
* This helps to avoid false sharing as this is the size of the
* CPU cache line.
*/
- kcf_sreq_cache = kmem_cache_create("kcf_sreq_cache",
- sizeof (struct kcf_sreq_node), 64, kcf_sreq_cache_constructor,
- kcf_sreq_cache_destructor, NULL, NULL, NULL, 0);
-
- kcf_areq_cache = kmem_cache_create("kcf_areq_cache",
- sizeof (struct kcf_areq_node), 64, kcf_areq_cache_constructor,
- kcf_areq_cache_destructor, NULL, NULL, NULL, 0);
-
kcf_context_cache = kmem_cache_create("kcf_context_cache",
sizeof (struct kcf_context), 64, kcf_context_cache_constructor,
kcf_context_cache_destructor, NULL, NULL, NULL, 0);
-
- gswq = kmem_alloc(sizeof (kcf_global_swq_t), KM_SLEEP);
-
- mutex_init(&gswq->gs_lock, NULL, MUTEX_DEFAULT, NULL);
- cv_init(&gswq->gs_cv, NULL, CV_DEFAULT, NULL);
- gswq->gs_njobs = 0;
- gswq->gs_maxjobs = kcf_maxthreads * crypto_taskq_maxalloc;
- gswq->gs_first = gswq->gs_last = NULL;
-
- /* Initialize the global reqid table */
- for (i = 0; i < REQID_TABLES; i++) {
- rt = kmem_zalloc(sizeof (kcf_reqid_table_t), KM_SLEEP);
- kcf_reqid_table[i] = rt;
- mutex_init(&rt->rt_lock, NULL, MUTEX_DEFAULT, NULL);
- rt->rt_curid = i;
- }
-
- /* Allocate and initialize the thread pool */
- kcfpool_alloc();
-
- /* Initialize the event notification list variables */
- mutex_init(&ntfy_list_lock, NULL, MUTEX_DEFAULT, NULL);
- cv_init(&ntfy_list_cv, NULL, CV_DEFAULT, NULL);
-
- /* Create the kcf kstat */
- kcf_misc_kstat = kstat_create("kcf", 0, "framework_stats", "crypto",
- KSTAT_TYPE_NAMED, sizeof (kcf_stats_t) / sizeof (kstat_named_t),
- KSTAT_FLAG_VIRTUAL);
-
- if (kcf_misc_kstat != NULL) {
- kcf_misc_kstat->ks_data = &kcf_ksdata;
- kcf_misc_kstat->ks_update = kcf_misc_kstat_update;
- kstat_install(kcf_misc_kstat);
- }
-}
-
-/*
- * Signal the waiting sync client.
- */
-void
-kcf_sop_done(kcf_sreq_node_t *sreq, int error)
-{
- mutex_enter(&sreq->sn_lock);
- sreq->sn_state = REQ_DONE;
- sreq->sn_rv = error;
- cv_signal(&sreq->sn_cv);
- mutex_exit(&sreq->sn_lock);
-}
-
-/*
- * Callback the async client with the operation status.
- * We free the async request node and possibly the context.
- * We also handle any chain of requests hanging off of
- * the context.
- */
-void
-kcf_aop_done(kcf_areq_node_t *areq, int error)
-{
- kcf_op_type_t optype;
- boolean_t skip_notify = B_FALSE;
- kcf_context_t *ictx;
- kcf_areq_node_t *nextreq;
-
- /*
- * Handle recoverable errors. This has to be done first
- * before doing anything else in this routine so that
- * we do not change the state of the request.
- */
- if (error != CRYPTO_SUCCESS && IS_RECOVERABLE(error)) {
- /*
- * We try another provider, if one is available. Else
- * we continue with the failure notification to the
- * client.
- */
- if (kcf_resubmit_request(areq) == CRYPTO_QUEUED)
- return;
- }
-
- mutex_enter(&areq->an_lock);
- areq->an_state = REQ_DONE;
- mutex_exit(&areq->an_lock);
-
- optype = (&areq->an_params)->rp_optype;
- if ((ictx = areq->an_context) != NULL) {
- /*
- * A request after it is removed from the request
- * queue, still stays on a chain of requests hanging
- * of its context structure. It needs to be removed
- * from this chain at this point.
- */
- mutex_enter(&ictx->kc_in_use_lock);
- nextreq = areq->an_ctxchain_next;
- if (nextreq != NULL) {
- mutex_enter(&nextreq->an_lock);
- nextreq->an_is_my_turn = B_TRUE;
- cv_signal(&nextreq->an_turn_cv);
- mutex_exit(&nextreq->an_lock);
- }
-
- ictx->kc_req_chain_first = nextreq;
- if (nextreq == NULL)
- ictx->kc_req_chain_last = NULL;
- mutex_exit(&ictx->kc_in_use_lock);
-
- if (IS_SINGLE_OP(optype) || IS_FINAL_OP(optype)) {
- ASSERT(nextreq == NULL);
- KCF_CONTEXT_REFRELE(ictx);
- } else if (error != CRYPTO_SUCCESS && IS_INIT_OP(optype)) {
- /*
- * NOTE - We do not release the context in case of update
- * operations. We require the consumer to free it explicitly,
- * in case it wants to abandon an update operation. This is done
- * as there may be mechanisms in ECB mode that can continue
- * even if an operation on a block fails.
- */
- KCF_CONTEXT_REFRELE(ictx);
- }
- }
-
- /* Deal with the internal continuation to this request first */
-
- if (areq->an_isdual) {
- kcf_dual_req_t *next_arg;
- next_arg = (kcf_dual_req_t *)areq->an_reqarg.cr_callback_arg;
- next_arg->kr_areq = areq;
- KCF_AREQ_REFHOLD(areq);
- areq->an_isdual = B_FALSE;
-
- NOTIFY_CLIENT(areq, error);
- return;
- }
-
- /*
- * If CRYPTO_NOTIFY_OPDONE flag is set, we should notify
- * always. If this flag is clear, we skip the notification
- * provided there are no errors. We check this flag for only
- * init or update operations. It is ignored for single, final or
- * atomic operations.
- */
- skip_notify = (IS_UPDATE_OP(optype) || IS_INIT_OP(optype)) &&
- (!(areq->an_reqarg.cr_flag & CRYPTO_NOTIFY_OPDONE)) &&
- (error == CRYPTO_SUCCESS);
-
- if (!skip_notify) {
- NOTIFY_CLIENT(areq, error);
- }
-
- if (!(areq->an_reqarg.cr_flag & CRYPTO_SKIP_REQID))
- kcf_reqid_delete(areq);
-
- KCF_AREQ_REFRELE(areq);
-}
-
-/*
- * Allocate the thread pool and initialize all the fields.
- */
-static void
-kcfpool_alloc()
-{
- kcfpool = kmem_alloc(sizeof (kcf_pool_t), KM_SLEEP);
-
- kcfpool->kp_threads = kcfpool->kp_idlethreads = 0;
- kcfpool->kp_blockedthreads = 0;
- kcfpool->kp_signal_create_thread = B_FALSE;
- kcfpool->kp_nthrs = 0;
- kcfpool->kp_user_waiting = B_FALSE;
-
- mutex_init(&kcfpool->kp_thread_lock, NULL, MUTEX_DEFAULT, NULL);
- cv_init(&kcfpool->kp_nothr_cv, NULL, CV_DEFAULT, NULL);
-
- mutex_init(&kcfpool->kp_user_lock, NULL, MUTEX_DEFAULT, NULL);
- cv_init(&kcfpool->kp_user_cv, NULL, CV_DEFAULT, NULL);
-}
-
-/*
- * Insert the async request in the hash table after assigning it
- * an ID. Returns the ID.
- *
- * The ID is used by the caller to pass as an argument to a
- * cancel_req() routine later.
- */
-static crypto_req_id_t
-kcf_reqid_insert(kcf_areq_node_t *areq)
-{
- int indx;
- crypto_req_id_t id;
- kcf_areq_node_t *headp;
- kcf_reqid_table_t *rt;
-
- rt = kcf_reqid_table[CPU_SEQID_UNSTABLE & REQID_TABLE_MASK];
-
- mutex_enter(&rt->rt_lock);
-
- rt->rt_curid = id =
- (rt->rt_curid - REQID_COUNTER_LOW) | REQID_COUNTER_HIGH;
- SET_REQID(areq, id);
- indx = REQID_HASH(id);
- headp = areq->an_idnext = rt->rt_idhash[indx];
- areq->an_idprev = NULL;
- if (headp != NULL)
- headp->an_idprev = areq;
-
- rt->rt_idhash[indx] = areq;
- mutex_exit(&rt->rt_lock);
-
- return (id);
-}
-
-/*
- * Delete the async request from the hash table.
- */
-static void
-kcf_reqid_delete(kcf_areq_node_t *areq)
-{
- int indx;
- kcf_areq_node_t *nextp, *prevp;
- crypto_req_id_t id = GET_REQID(areq);
- kcf_reqid_table_t *rt;
-
- rt = kcf_reqid_table[id & REQID_TABLE_MASK];
- indx = REQID_HASH(id);
-
- mutex_enter(&rt->rt_lock);
-
- nextp = areq->an_idnext;
- prevp = areq->an_idprev;
- if (nextp != NULL)
- nextp->an_idprev = prevp;
- if (prevp != NULL)
- prevp->an_idnext = nextp;
- else
- rt->rt_idhash[indx] = nextp;
-
- SET_REQID(areq, 0);
- cv_broadcast(&areq->an_done);
-
- mutex_exit(&rt->rt_lock);
-}
-
-/*
- * Cancel a single asynchronous request.
- *
- * We guarantee that no problems will result from calling
- * crypto_cancel_req() for a request which is either running, or
- * has already completed. We remove the request from any queues
- * if it is possible. We wait for request completion if the
- * request is dispatched to a provider.
- *
- * Calling context:
- * Can be called from user context only.
- *
- * NOTE: We acquire the following locks in this routine (in order):
- * - rt_lock (kcf_reqid_table_t)
- * - gswq->gs_lock
- * - areq->an_lock
- * - ictx->kc_in_use_lock (from kcf_removereq_in_ctxchain())
- *
- * This locking order MUST be maintained in code every where else.
- */
-void
-crypto_cancel_req(crypto_req_id_t id)
-{
- int indx;
- kcf_areq_node_t *areq;
- kcf_provider_desc_t *pd;
- kcf_context_t *ictx;
- kcf_reqid_table_t *rt;
-
- rt = kcf_reqid_table[id & REQID_TABLE_MASK];
- indx = REQID_HASH(id);
-
- mutex_enter(&rt->rt_lock);
- for (areq = rt->rt_idhash[indx]; areq; areq = areq->an_idnext) {
- if (GET_REQID(areq) == id) {
- /*
- * We found the request. It is either still waiting
- * in the framework queues or running at the provider.
- */
- pd = areq->an_provider;
- ASSERT(pd != NULL);
-
- switch (pd->pd_prov_type) {
- case CRYPTO_SW_PROVIDER:
- mutex_enter(&gswq->gs_lock);
- mutex_enter(&areq->an_lock);
-
- /* This request can be safely canceled. */
- if (areq->an_state <= REQ_WAITING) {
- /* Remove from gswq, global software queue. */
- kcf_remove_node(areq);
- if ((ictx = areq->an_context) != NULL)
- kcf_removereq_in_ctxchain(ictx, areq);
-
- mutex_exit(&areq->an_lock);
- mutex_exit(&gswq->gs_lock);
- mutex_exit(&rt->rt_lock);
-
- /* Remove areq from hash table and free it. */
- kcf_reqid_delete(areq);
- KCF_AREQ_REFRELE(areq);
- return;
- }
-
- mutex_exit(&areq->an_lock);
- mutex_exit(&gswq->gs_lock);
- break;
-
- case CRYPTO_HW_PROVIDER:
- /*
- * There is no interface to remove an entry
- * once it is on the taskq. So, we do not do
- * anything for a hardware provider.
- */
- break;
- default:
- break;
- }
-
- /*
- * The request is running. Wait for the request completion
- * to notify us.
- */
- KCF_AREQ_REFHOLD(areq);
- while (GET_REQID(areq) == id)
- cv_wait(&areq->an_done, &rt->rt_lock);
- KCF_AREQ_REFRELE(areq);
- break;
- }
- }
-
- mutex_exit(&rt->rt_lock);
-}
-
-/*
- * Cancel all asynchronous requests associated with the
- * passed in crypto context and free it.
- *
- * A client SHOULD NOT call this routine after calling a crypto_*_final
- * routine. This routine is called only during intermediate operations.
- * The client should not use the crypto context after this function returns
- * since we destroy it.
- *
- * Calling context:
- * Can be called from user context only.
- */
-void
-crypto_cancel_ctx(crypto_context_t ctx)
-{
- kcf_context_t *ictx;
- kcf_areq_node_t *areq;
-
- if (ctx == NULL)
- return;
-
- ictx = (kcf_context_t *)((crypto_ctx_t *)ctx)->cc_framework_private;
-
- mutex_enter(&ictx->kc_in_use_lock);
-
- /* Walk the chain and cancel each request */
- while ((areq = ictx->kc_req_chain_first) != NULL) {
- /*
- * We have to drop the lock here as we may have
- * to wait for request completion. We hold the
- * request before dropping the lock though, so that it
- * won't be freed underneath us.
- */
- KCF_AREQ_REFHOLD(areq);
- mutex_exit(&ictx->kc_in_use_lock);
-
- crypto_cancel_req(GET_REQID(areq));
- KCF_AREQ_REFRELE(areq);
-
- mutex_enter(&ictx->kc_in_use_lock);
- }
-
- mutex_exit(&ictx->kc_in_use_lock);
- KCF_CONTEXT_REFRELE(ictx);
-}
-
-/*
- * Update kstats.
- */
-static int
-kcf_misc_kstat_update(kstat_t *ksp, int rw)
-{
- uint_t tcnt;
- kcf_stats_t *ks_data;
-
- if (rw == KSTAT_WRITE)
- return (EACCES);
-
- ks_data = ksp->ks_data;
-
- ks_data->ks_thrs_in_pool.value.ui32 = kcfpool->kp_threads;
- /*
- * The failover thread is counted in kp_idlethreads in
- * some corner cases. This is done to avoid doing more checks
- * when submitting a request. We account for those cases below.
- */
- if ((tcnt = kcfpool->kp_idlethreads) == (kcfpool->kp_threads + 1))
- tcnt--;
- ks_data->ks_idle_thrs.value.ui32 = tcnt;
- ks_data->ks_minthrs.value.ui32 = kcf_minthreads;
- ks_data->ks_maxthrs.value.ui32 = kcf_maxthreads;
- ks_data->ks_swq_njobs.value.ui32 = gswq->gs_njobs;
- ks_data->ks_swq_maxjobs.value.ui32 = gswq->gs_maxjobs;
- ks_data->ks_taskq_threads.value.ui32 = crypto_taskq_threads;
- ks_data->ks_taskq_minalloc.value.ui32 = crypto_taskq_minalloc;
- ks_data->ks_taskq_maxalloc.value.ui32 = crypto_taskq_maxalloc;
-
- return (0);
-}
-
-/*
- * Allocate and initialize a kcf_dual_req, used for saving the arguments of
- * a dual operation or an atomic operation that has to be internally
- * simulated with multiple single steps.
- * crq determines the memory allocation flags.
- */
-
-kcf_dual_req_t *
-kcf_alloc_req(crypto_call_req_t *crq)
-{
- kcf_dual_req_t *kcr;
-
- kcr = kmem_alloc(sizeof (kcf_dual_req_t), KCF_KMFLAG(crq));
-
- if (kcr == NULL)
- return (NULL);
-
- /* Copy the whole crypto_call_req struct, as it isn't persistent */
- if (crq != NULL)
- kcr->kr_callreq = *crq;
- else
- bzero(&(kcr->kr_callreq), sizeof (crypto_call_req_t));
- kcr->kr_areq = NULL;
- kcr->kr_saveoffset = 0;
- kcr->kr_savelen = 0;
-
- return (kcr);
-}
-
-/*
- * Callback routine for the next part of a simulated dual part.
- * Schedules the next step.
- *
- * This routine can be called from interrupt context.
- */
-void
-kcf_next_req(void *next_req_arg, int status)
-{
- kcf_dual_req_t *next_req = (kcf_dual_req_t *)next_req_arg;
- kcf_req_params_t *params = &(next_req->kr_params);
- kcf_areq_node_t *areq = next_req->kr_areq;
- int error = status;
- kcf_provider_desc_t *pd = NULL;
- crypto_dual_data_t *ct = NULL;
-
- /* Stop the processing if an error occurred at this step */
- if (error != CRYPTO_SUCCESS) {
-out:
- areq->an_reqarg = next_req->kr_callreq;
- KCF_AREQ_REFRELE(areq);
- kmem_free(next_req, sizeof (kcf_dual_req_t));
- areq->an_isdual = B_FALSE;
- kcf_aop_done(areq, error);
- return;
- }
-
- switch (params->rp_opgrp) {
- case KCF_OG_MAC: {
-
- /*
- * The next req is submitted with the same reqid as the
- * first part. The consumer only got back that reqid, and
- * should still be able to cancel the operation during its
- * second step.
- */
- kcf_mac_ops_params_t *mops = &(params->rp_u.mac_params);
- crypto_ctx_template_t mac_tmpl;
- kcf_mech_entry_t *me;
-
- ct = (crypto_dual_data_t *)mops->mo_data;
- mac_tmpl = (crypto_ctx_template_t)mops->mo_templ;
-
- /* No expected recoverable failures, so no retry list */
- pd = kcf_get_mech_provider(mops->mo_framework_mechtype,
- &me, &error, NULL, CRYPTO_FG_MAC_ATOMIC,
- (areq->an_reqarg.cr_flag & CRYPTO_RESTRICTED), ct->dd_len2);
-
- if (pd == NULL) {
- error = CRYPTO_MECH_NOT_SUPPORTED;
- goto out;
- }
- /* Validate the MAC context template here */
- if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) &&
- (mac_tmpl != NULL)) {
- kcf_ctx_template_t *ctx_mac_tmpl;
-
- ctx_mac_tmpl = (kcf_ctx_template_t *)mac_tmpl;
-
- if (ctx_mac_tmpl->ct_generation != me->me_gen_swprov) {
- KCF_PROV_REFRELE(pd);
- error = CRYPTO_OLD_CTX_TEMPLATE;
- goto out;
- }
- mops->mo_templ = ctx_mac_tmpl->ct_prov_tmpl;
- }
-
- break;
- }
- case KCF_OG_DECRYPT: {
- kcf_decrypt_ops_params_t *dcrops =
- &(params->rp_u.decrypt_params);
-
- ct = (crypto_dual_data_t *)dcrops->dop_ciphertext;
- /* No expected recoverable failures, so no retry list */
- pd = kcf_get_mech_provider(dcrops->dop_framework_mechtype,
- NULL, &error, NULL, CRYPTO_FG_DECRYPT_ATOMIC,
- (areq->an_reqarg.cr_flag & CRYPTO_RESTRICTED), ct->dd_len1);
-
- if (pd == NULL) {
- error = CRYPTO_MECH_NOT_SUPPORTED;
- goto out;
- }
- break;
- }
- default:
- break;
- }
-
- /* The second step uses len2 and offset2 of the dual_data */
- next_req->kr_saveoffset = ct->dd_offset1;
- next_req->kr_savelen = ct->dd_len1;
- ct->dd_offset1 = ct->dd_offset2;
- ct->dd_len1 = ct->dd_len2;
-
- /* preserve if the caller is restricted */
- if (areq->an_reqarg.cr_flag & CRYPTO_RESTRICTED) {
- areq->an_reqarg.cr_flag = CRYPTO_RESTRICTED;
- } else {
- areq->an_reqarg.cr_flag = 0;
- }
-
- areq->an_reqarg.cr_callback_func = kcf_last_req;
- areq->an_reqarg.cr_callback_arg = next_req;
- areq->an_isdual = B_TRUE;
-
- /*
- * We would like to call kcf_submit_request() here. But,
- * that is not possible as that routine allocates a new
- * kcf_areq_node_t request structure, while we need to
- * reuse the existing request structure.
- */
- switch (pd->pd_prov_type) {
- case CRYPTO_SW_PROVIDER:
- error = common_submit_request(pd, NULL, params,
- KCF_RHNDL(KM_NOSLEEP));
- break;
-
- case CRYPTO_HW_PROVIDER: {
- kcf_provider_desc_t *old_pd;
- taskq_t *taskq = pd->pd_sched_info.ks_taskq;
-
- /*
- * Set the params for the second step in the
- * dual-ops.
- */
- areq->an_params = *params;
- old_pd = areq->an_provider;
- KCF_PROV_REFRELE(old_pd);
- KCF_PROV_REFHOLD(pd);
- areq->an_provider = pd;
-
- /*
- * Note that we have to do a taskq_dispatch()
- * here as we may be in interrupt context.
- */
- if (taskq_dispatch(taskq, process_req_hwp, areq,
- TQ_NOSLEEP) == (taskqid_t)0) {
- error = CRYPTO_HOST_MEMORY;
- } else {
- error = CRYPTO_QUEUED;
- }
- break;
- }
- default:
- break;
- }
-
- /*
- * We have to release the holds on the request and the provider
- * in all cases.
- */
- KCF_AREQ_REFRELE(areq);
- KCF_PROV_REFRELE(pd);
-
- if (error != CRYPTO_QUEUED) {
- /* restore, clean up, and invoke the client's callback */
-
- ct->dd_offset1 = next_req->kr_saveoffset;
- ct->dd_len1 = next_req->kr_savelen;
- areq->an_reqarg = next_req->kr_callreq;
- kmem_free(next_req, sizeof (kcf_dual_req_t));
- areq->an_isdual = B_FALSE;
- kcf_aop_done(areq, error);
- }
-}
-
-/*
- * Last part of an emulated dual operation.
- * Clean up and restore ...
- */
-void
-kcf_last_req(void *last_req_arg, int status)
-{
- kcf_dual_req_t *last_req = (kcf_dual_req_t *)last_req_arg;
-
- kcf_req_params_t *params = &(last_req->kr_params);
- kcf_areq_node_t *areq = last_req->kr_areq;
- crypto_dual_data_t *ct = NULL;
-
- switch (params->rp_opgrp) {
- case KCF_OG_MAC: {
- kcf_mac_ops_params_t *mops = &(params->rp_u.mac_params);
-
- ct = (crypto_dual_data_t *)mops->mo_data;
- break;
- }
- case KCF_OG_DECRYPT: {
- kcf_decrypt_ops_params_t *dcrops =
- &(params->rp_u.decrypt_params);
-
- ct = (crypto_dual_data_t *)dcrops->dop_ciphertext;
- break;
- }
- default: {
- panic("invalid kcf_op_group_t %d", (int)params->rp_opgrp);
- return;
- }
- }
- ct->dd_offset1 = last_req->kr_saveoffset;
- ct->dd_len1 = last_req->kr_savelen;
-
- /* The submitter used kcf_last_req as its callback */
-
- if (areq == NULL) {
- crypto_call_req_t *cr = &last_req->kr_callreq;
-
- (*(cr->cr_callback_func))(cr->cr_callback_arg, status);
- kmem_free(last_req, sizeof (kcf_dual_req_t));
- return;
- }
- areq->an_reqarg = last_req->kr_callreq;
- KCF_AREQ_REFRELE(areq);
- kmem_free(last_req, sizeof (kcf_dual_req_t));
- areq->an_isdual = B_FALSE;
- kcf_aop_done(areq, status);
}
diff --git a/sys/contrib/openzfs/module/icp/illumos-crypto.c b/sys/contrib/openzfs/module/icp/illumos-crypto.c
index 5b2820220f2c..f68f6bc765a2 100644
--- a/sys/contrib/openzfs/module/icp/illumos-crypto.c
+++ b/sys/contrib/openzfs/module/icp/illumos-crypto.c
@@ -36,7 +36,6 @@
#include <sys/crypto/api.h>
#include <sys/crypto/impl.h>
#include <sys/crypto/sched_impl.h>
-#include <sys/modhash_impl.h>
#include <sys/crypto/icp.h>
/*
@@ -114,16 +113,12 @@ icp_fini(void)
kcf_sched_destroy();
kcf_prov_tab_destroy();
kcf_destroy_mech_tabs();
- mod_hash_fini();
}
/* roughly equivalent to kcf.c: _init() */
int __init
icp_init(void)
{
- /* initialize the mod hash module */
- mod_hash_init();
-
/* initialize the mechanisms tables supported out-of-the-box */
kcf_init_mech_tabs();
diff --git a/sys/contrib/openzfs/module/icp/include/aes/aes_impl.h b/sys/contrib/openzfs/module/icp/include/aes/aes_impl.h
index 41dccaa3848a..b2348022e1db 100644
--- a/sys/contrib/openzfs/module/icp/include/aes/aes_impl.h
+++ b/sys/contrib/openzfs/module/icp/include/aes/aes_impl.h
@@ -83,14 +83,7 @@ extern "C" {
/* AES key size definitions */
#define AES_MINBITS 128
-#define AES_MINBYTES ((AES_MINBITS) >> 3)
#define AES_MAXBITS 256
-#define AES_MAXBYTES ((AES_MAXBITS) >> 3)
-
-#define AES_MIN_KEY_BYTES ((AES_MINBITS) >> 3)
-#define AES_MAX_KEY_BYTES ((AES_MAXBITS) >> 3)
-#define AES_192_KEY_BYTES 24
-#define AES_IV_LEN 16
/* AES key schedule may be implemented with 32- or 64-bit elements: */
#define AES_32BIT_KS 32
diff --git a/sys/contrib/openzfs/module/icp/include/modes/modes.h b/sys/contrib/openzfs/module/icp/include/modes/modes.h
index ab71197542eb..aa88ea97e045 100644
--- a/sys/contrib/openzfs/module/icp/include/modes/modes.h
+++ b/sys/contrib/openzfs/module/icp/include/modes/modes.h
@@ -207,10 +207,6 @@ typedef struct ccm_ctx {
*
* gcm_len_a_len_c: 64-bit representations of the bit lengths of
* AAD and ciphertext.
- *
- * gcm_kmflag: Current value of kmflag. Used for allocating
- * the plaintext buffer during decryption and a
- * gcm_avx_chunk_size'd buffer for avx enabled encryption.
*/
typedef struct gcm_ctx {
struct common_ctx gcm_common;
@@ -231,7 +227,6 @@ typedef struct gcm_ctx {
uint64_t gcm_J0[2];
uint64_t gcm_len_a_len_c[2];
uint8_t *gcm_pt_buf;
- int gcm_kmflag;
#ifdef CAN_USE_GCM_ASM
boolean_t gcm_use_avx;
#endif
@@ -402,7 +397,6 @@ extern void *ccm_alloc_ctx(int);
extern void *gcm_alloc_ctx(int);
extern void *gmac_alloc_ctx(int);
extern void crypto_free_mode_ctx(void *);
-extern void gcm_set_kmflag(gcm_ctx_t *, int);
#ifdef __cplusplus
}
diff --git a/sys/contrib/openzfs/module/icp/include/sys/bitmap.h b/sys/contrib/openzfs/module/icp/include/sys/bitmap.h
deleted file mode 100644
index 4e86ee70ed9e..000000000000
--- a/sys/contrib/openzfs/module/icp/include/sys/bitmap.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * 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 2006 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
-/* All Rights Reserved */
-
-
-#ifndef _SYS_BITMAP_H
-#define _SYS_BITMAP_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if defined(__GNUC__) && defined(_ASM_INLINES) && \
- (defined(__i386) || defined(__amd64))
-#include <asm/bitmap.h>
-#endif
-
-/*
- * Operations on bitmaps of arbitrary size
- * A bitmap is a vector of 1 or more ulong_t's.
- * The user of the package is responsible for range checks and keeping
- * track of sizes.
- */
-
-#ifdef _LP64
-#define BT_ULSHIFT 6 /* log base 2 of BT_NBIPUL, to extract word index */
-#define BT_ULSHIFT32 5 /* log base 2 of BT_NBIPUL, to extract word index */
-#else
-#define BT_ULSHIFT 5 /* log base 2 of BT_NBIPUL, to extract word index */
-#endif
-
-#define BT_NBIPUL (1 << BT_ULSHIFT) /* n bits per ulong_t */
-#define BT_ULMASK (BT_NBIPUL - 1) /* to extract bit index */
-
-#ifdef _LP64
-#define BT_NBIPUL32 (1 << BT_ULSHIFT32) /* n bits per ulong_t */
-#define BT_ULMASK32 (BT_NBIPUL32 - 1) /* to extract bit index */
-#define BT_ULMAXMASK 0xffffffffffffffff /* used by bt_getlowbit */
-#else
-#define BT_ULMAXMASK 0xffffffff
-#endif
-
-/*
- * bitmap is a ulong_t *, bitindex an index_t
- *
- * The macros BT_WIM and BT_BIW internal; there is no need
- * for users of this package to use them.
- */
-
-/*
- * word in map
- */
-#define BT_WIM(bitmap, bitindex) \
- ((bitmap)[(bitindex) >> BT_ULSHIFT])
-/*
- * bit in word
- */
-#define BT_BIW(bitindex) \
- (1UL << ((bitindex) & BT_ULMASK))
-
-#ifdef _LP64
-#define BT_WIM32(bitmap, bitindex) \
- ((bitmap)[(bitindex) >> BT_ULSHIFT32])
-
-#define BT_BIW32(bitindex) \
- (1UL << ((bitindex) & BT_ULMASK32))
-#endif
-
-/*
- * These are public macros
- *
- * BT_BITOUL == n bits to n ulong_t's
- */
-#define BT_BITOUL(nbits) \
- (((nbits) + BT_NBIPUL - 1l) / BT_NBIPUL)
-#define BT_SIZEOFMAP(nbits) \
- (BT_BITOUL(nbits) * sizeof (ulong_t))
-#define BT_TEST(bitmap, bitindex) \
- ((BT_WIM((bitmap), (bitindex)) & BT_BIW(bitindex)) ? 1 : 0)
-#define BT_SET(bitmap, bitindex) \
- { BT_WIM((bitmap), (bitindex)) |= BT_BIW(bitindex); }
-#define BT_CLEAR(bitmap, bitindex) \
- { BT_WIM((bitmap), (bitindex)) &= ~BT_BIW(bitindex); }
-
-#ifdef _LP64
-#define BT_BITOUL32(nbits) \
- (((nbits) + BT_NBIPUL32 - 1l) / BT_NBIPUL32)
-#define BT_SIZEOFMAP32(nbits) \
- (BT_BITOUL32(nbits) * sizeof (uint_t))
-#define BT_TEST32(bitmap, bitindex) \
- ((BT_WIM32((bitmap), (bitindex)) & BT_BIW32(bitindex)) ? 1 : 0)
-#define BT_SET32(bitmap, bitindex) \
- { BT_WIM32((bitmap), (bitindex)) |= BT_BIW32(bitindex); }
-#define BT_CLEAR32(bitmap, bitindex) \
- { BT_WIM32((bitmap), (bitindex)) &= ~BT_BIW32(bitindex); }
-#endif /* _LP64 */
-
-
-/*
- * BIT_ONLYONESET is a private macro not designed for bitmaps of
- * arbitrary size. u must be an unsigned integer/long. It returns
- * true if one and only one bit is set in u.
- */
-#define BIT_ONLYONESET(u) \
- ((((u) == 0) ? 0 : ((u) & ((u) - 1)) == 0))
-
-#ifndef _ASM
-
-/*
- * return next available bit index from map with specified number of bits
- */
-extern index_t bt_availbit(ulong_t *bitmap, size_t nbits);
-/*
- * find the highest order bit that is on, and is within or below
- * the word specified by wx
- */
-extern int bt_gethighbit(ulong_t *mapp, int wx);
-extern int bt_range(ulong_t *bitmap, size_t *pos1, size_t *pos2,
- size_t end_pos);
-extern int bt_getlowbit(ulong_t *bitmap, size_t start, size_t stop);
-extern void bt_copy(ulong_t *, ulong_t *, ulong_t);
-
-/*
- * find the parity
- */
-extern int odd_parity(ulong_t);
-
-/*
- * Atomically set/clear bits
- * Atomic exclusive operations will set "result" to "-1"
- * if the bit is already set/cleared. "result" will be set
- * to 0 otherwise.
- */
-#define BT_ATOMIC_SET(bitmap, bitindex) \
- { atomic_or_ulong(&(BT_WIM(bitmap, bitindex)), BT_BIW(bitindex)); }
-#define BT_ATOMIC_CLEAR(bitmap, bitindex) \
- { atomic_and_ulong(&(BT_WIM(bitmap, bitindex)), ~BT_BIW(bitindex)); }
-
-#define BT_ATOMIC_SET_EXCL(bitmap, bitindex, result) \
- { result = atomic_set_long_excl(&(BT_WIM(bitmap, bitindex)), \
- (bitindex) % BT_NBIPUL); }
-#define BT_ATOMIC_CLEAR_EXCL(bitmap, bitindex, result) \
- { result = atomic_clear_long_excl(&(BT_WIM(bitmap, bitindex)), \
- (bitindex) % BT_NBIPUL); }
-
-/*
- * Extracts bits between index h (high, inclusive) and l (low, exclusive) from
- * u, which must be an unsigned integer.
- */
-#define BITX(u, h, l) (((u) >> (l)) & ((1LU << ((h) - (l) + 1LU)) - 1LU))
-
-#endif /* _ASM */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _SYS_BITMAP_H */
diff --git a/sys/contrib/openzfs/module/icp/include/sys/crypto/elfsign.h b/sys/contrib/openzfs/module/icp/include/sys/crypto/elfsign.h
deleted file mode 100644
index 5432f0c8d607..000000000000
--- a/sys/contrib/openzfs/module/icp/include/sys/crypto/elfsign.h
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * 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 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#ifndef _SYS_CRYPTO_ELFSIGN_H
-#define _SYS_CRYPTO_ELFSIGN_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Consolidation Private Interface for elfsign/libpkcs11/kcfd
- */
-
-#include <sys/zfs_context.h>
-
-/*
- * Project Private structures and types used for communication between kcfd
- * and KCF over the door.
- */
-
-typedef enum ELFsign_status_e {
- ELFSIGN_UNKNOWN,
- ELFSIGN_SUCCESS,
- ELFSIGN_FAILED,
- ELFSIGN_NOTSIGNED,
- ELFSIGN_INVALID_CERTPATH,
- ELFSIGN_INVALID_ELFOBJ,
- ELFSIGN_RESTRICTED
-} ELFsign_status_t;
-
-#define KCF_KCFD_VERSION1 1
-#define SIG_MAX_LENGTH 1024
-
-#define ELF_SIGNATURE_SECTION ".SUNW_signature"
-
-typedef struct kcf_door_arg_s {
- short da_version;
- boolean_t da_iskernel;
-
- union {
- char filename[MAXPATHLEN]; /* For request */
-
- struct kcf_door_result_s { /* For response */
- ELFsign_status_t status;
- uint32_t siglen;
- uchar_t signature[1];
- } result;
- } da_u;
-} kcf_door_arg_t;
-
-typedef uint32_t filesig_vers_t;
-
-/*
- * File Signature Structure
- * Applicable to ELF and other file formats
- */
-struct filesignatures {
- uint32_t filesig_cnt; /* count of signatures */
- uint32_t filesig_pad; /* unused */
- union {
- char filesig_data[1];
- struct filesig { /* one of these for each signature */
- uint32_t filesig_size;
- filesig_vers_t filesig_version;
- union {
- struct filesig_version1 {
- uint32_t filesig_v1_dnsize;
- uint32_t filesig_v1_sigsize;
- uint32_t filesig_v1_oidsize;
- char filesig_v1_data[1];
- } filesig_v1;
- struct filesig_version3 {
- uint64_t filesig_v3_time;
- uint32_t filesig_v3_dnsize;
- uint32_t filesig_v3_sigsize;
- uint32_t filesig_v3_oidsize;
- char filesig_v3_data[1];
- } filesig_v3;
- } _u2;
- } filesig_sig;
- uint64_t filesig_align;
- } _u1;
-};
-#define filesig_sig _u1.filesig_sig
-
-#define filesig_v1_dnsize _u2.filesig_v1.filesig_v1_dnsize
-#define filesig_v1_sigsize _u2.filesig_v1.filesig_v1_sigsize
-#define filesig_v1_oidsize _u2.filesig_v1.filesig_v1_oidsize
-#define filesig_v1_data _u2.filesig_v1.filesig_v1_data
-
-#define filesig_v3_time _u2.filesig_v3.filesig_v3_time
-#define filesig_v3_dnsize _u2.filesig_v3.filesig_v3_dnsize
-#define filesig_v3_sigsize _u2.filesig_v3.filesig_v3_sigsize
-#define filesig_v3_oidsize _u2.filesig_v3.filesig_v3_oidsize
-#define filesig_v3_data _u2.filesig_v3.filesig_v3_data
-
-#define filesig_ALIGN(s) (((s) + sizeof (uint64_t) - 1) & \
- (-sizeof (uint64_t)))
-#define filesig_next(ptr) (struct filesig *)((void *)((char *)(ptr) + \
- filesig_ALIGN((ptr)->filesig_size)))
-
-#define FILESIG_UNKNOWN 0 /* unrecognized version */
-#define FILESIG_VERSION1 1 /* version1, all but sig section */
-#define FILESIG_VERSION2 2 /* version1 format, SHF_ALLOC only */
-#define FILESIG_VERSION3 3 /* version3, all but sig section */
-#define FILESIG_VERSION4 4 /* version3 format, SHF_ALLOC only */
-
-#define _PATH_KCFD_DOOR "/etc/svc/volatile/kcfd_door"
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _SYS_CRYPTO_ELFSIGN_H */
diff --git a/sys/contrib/openzfs/module/icp/include/sys/crypto/impl.h b/sys/contrib/openzfs/module/icp/include/sys/crypto/impl.h
index 4906549b5687..dca7aa1b562f 100644
--- a/sys/contrib/openzfs/module/icp/include/sys/crypto/impl.h
+++ b/sys/contrib/openzfs/module/icp/include/sys/crypto/impl.h
@@ -34,79 +34,17 @@
#include <sys/crypto/common.h>
#include <sys/crypto/api.h>
#include <sys/crypto/spi.h>
+#include <sys/avl.h>
#ifdef __cplusplus
extern "C" {
#endif
-#define KCF_MODULE "kcf"
-
/*
* Prefixes convention: structures internal to the kernel cryptographic
* framework start with 'kcf_'. Exposed structure start with 'crypto_'.
*/
-/* Provider stats. Not protected. */
-typedef struct kcf_prov_stats {
- kstat_named_t ps_ops_total;
- kstat_named_t ps_ops_passed;
- kstat_named_t ps_ops_failed;
- kstat_named_t ps_ops_busy_rval;
-} kcf_prov_stats_t;
-
-/* Various kcf stats. Not protected. */
-typedef struct kcf_stats {
- kstat_named_t ks_thrs_in_pool;
- kstat_named_t ks_idle_thrs;
- kstat_named_t ks_minthrs;
- kstat_named_t ks_maxthrs;
- kstat_named_t ks_swq_njobs;
- kstat_named_t ks_swq_maxjobs;
- kstat_named_t ks_taskq_threads;
- kstat_named_t ks_taskq_minalloc;
- kstat_named_t ks_taskq_maxalloc;
-} kcf_stats_t;
-
-/*
- * Keep all the information needed by the scheduler from
- * this provider.
- */
-typedef struct kcf_sched_info {
- /* The number of operations dispatched. */
- uint64_t ks_ndispatches;
-
- /* The number of operations that failed. */
- uint64_t ks_nfails;
-
- /* The number of operations that returned CRYPTO_BUSY. */
- uint64_t ks_nbusy_rval;
-
- /* taskq used to dispatch crypto requests */
- taskq_t *ks_taskq;
-} kcf_sched_info_t;
-
-/*
- * pd_irefcnt approximates the number of inflight requests to the
- * provider. Though we increment this counter during registration for
- * other purposes, that base value is mostly same across all providers.
- * So, it is a good measure of the load on a provider when it is not
- * in a busy state. Once a provider notifies it is busy, requests
- * backup in the taskq. So, we use tq_nalloc in that case which gives
- * the number of task entries in the task queue. Note that we do not
- * acquire any locks here as it is not critical to get the exact number
- * and the lock contention may be too costly for this code path.
- */
-#define KCF_PROV_LOAD(pd) ((pd)->pd_state != KCF_PROV_BUSY ? \
- (pd)->pd_irefcnt : (pd)->pd_sched_info.ks_taskq->tq_nalloc)
-
-#define KCF_PROV_INCRSTATS(pd, error) { \
- (pd)->pd_sched_info.ks_ndispatches++; \
- if (error == CRYPTO_BUSY) \
- (pd)->pd_sched_info.ks_nbusy_rval++; \
- else if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED) \
- (pd)->pd_sched_info.ks_nfails++; \
-}
-
/*
* The following two macros should be
@@ -117,7 +55,7 @@ typedef struct kcf_sched_info {
* When impl.h is broken up (bug# 4703218), this will be done. For now,
* we hardcode these values.
*/
-#define KCF_OPS_CLASSSIZE 8
+#define KCF_OPS_CLASSSIZE 4
#define KCF_MAXMECHTAB 32
/*
@@ -125,21 +63,17 @@ typedef struct kcf_sched_info {
* the elements is important.
*
* Routines which get a provider or the list of providers
- * should pick only those that are either in KCF_PROV_READY state
- * or in KCF_PROV_BUSY state.
+ * should pick only those that are in KCF_PROV_READY state.
*/
typedef enum {
KCF_PROV_ALLOCATED = 1,
- KCF_PROV_UNVERIFIED,
- KCF_PROV_VERIFICATION_FAILED,
/*
* state < KCF_PROV_READY means the provider can not
* be used at all.
*/
KCF_PROV_READY,
- KCF_PROV_BUSY,
/*
- * state > KCF_PROV_BUSY means the provider can not
+ * state > KCF_PROV_READY means the provider can not
* be used for new requests.
*/
KCF_PROV_FAILED,
@@ -152,90 +86,46 @@ typedef enum {
KCF_PROV_FREED
} kcf_prov_state_t;
-#define KCF_IS_PROV_UNVERIFIED(pd) ((pd)->pd_state == KCF_PROV_UNVERIFIED)
-#define KCF_IS_PROV_USABLE(pd) ((pd)->pd_state == KCF_PROV_READY || \
- (pd)->pd_state == KCF_PROV_BUSY)
+#define KCF_IS_PROV_USABLE(pd) ((pd)->pd_state == KCF_PROV_READY)
#define KCF_IS_PROV_REMOVED(pd) ((pd)->pd_state >= KCF_PROV_REMOVED)
-/* Internal flags valid for pd_flags field */
-#define KCF_PROV_RESTRICTED 0x40000000
-#define KCF_LPROV_MEMBER 0x80000000 /* is member of a logical provider */
-
/*
* A provider descriptor structure. There is one such structure per
* provider. It is allocated and initialized at registration time and
* freed when the provider unregisters.
*
- * pd_prov_type: Provider type, hardware or software
- * pd_sid: Session ID of the provider used by kernel clients.
- * This is valid only for session-oriented providers.
* pd_refcnt: Reference counter to this provider descriptor
* pd_irefcnt: References held by the framework internal structs
- * pd_lock: lock protects pd_state and pd_provider_list
+ * pd_lock: lock protects pd_state
* pd_state: State value of the provider
- * pd_provider_list: Used to cross-reference logical providers and their
- * members. Not used for software providers.
- * pd_resume_cv: cv to wait for state to change from KCF_PROV_BUSY
- * pd_prov_handle: Provider handle specified by provider
* pd_ops_vector: The ops vector specified by Provider
* pd_mech_indx: Lookup table which maps a core framework mechanism
* number to an index in pd_mechanisms array
* pd_mechanisms: Array of mechanisms supported by the provider, specified
* by the provider during registration
- * pd_sched_info: Scheduling information associated with the provider
* pd_mech_list_count: The number of entries in pi_mechanisms, specified
* by the provider during registration
- * pd_name: Device name or module name
- * pd_instance: Device instance
- * pd_module_id: Module ID returned by modload
- * pd_mctlp: Pointer to modctl structure for this provider
* pd_remove_cv: cv to wait on while the provider queue drains
* pd_description: Provider description string
- * pd_flags bitwise OR of pi_flags from crypto_provider_info_t
- * and other internal flags defined above.
- * pd_hash_limit Maximum data size that hash mechanisms of this provider
- * can support.
* pd_kcf_prov_handle: KCF-private handle assigned by KCF
* pd_prov_id: Identification # assigned by KCF to provider
- * pd_kstat: kstat associated with the provider
- * pd_ks_data: kstat data
*/
typedef struct kcf_provider_desc {
- crypto_provider_type_t pd_prov_type;
- crypto_session_id_t pd_sid;
uint_t pd_refcnt;
uint_t pd_irefcnt;
kmutex_t pd_lock;
kcf_prov_state_t pd_state;
- struct kcf_provider_list *pd_provider_list;
- kcondvar_t pd_resume_cv;
- crypto_provider_handle_t pd_prov_handle;
const crypto_ops_t *pd_ops_vector;
ushort_t pd_mech_indx[KCF_OPS_CLASSSIZE]\
[KCF_MAXMECHTAB];
- crypto_mech_info_t *pd_mechanisms;
- kcf_sched_info_t pd_sched_info;
+ const crypto_mech_info_t *pd_mechanisms;
uint_t pd_mech_list_count;
- // char *pd_name;
- // uint_t pd_instance;
- // int pd_module_id;
- // struct modctl *pd_mctlp;
kcondvar_t pd_remove_cv;
- char *pd_description;
- uint_t pd_flags;
- uint_t pd_hash_limit;
+ const char *pd_description;
crypto_kcf_provider_handle_t pd_kcf_prov_handle;
crypto_provider_id_t pd_prov_id;
- kstat_t *pd_kstat;
- kcf_prov_stats_t pd_ks_data;
} kcf_provider_desc_t;
-/* useful for making a list of providers */
-typedef struct kcf_provider_list {
- struct kcf_provider_list *pl_next;
- struct kcf_provider_desc *pl_provider;
-} kcf_provider_list_t;
-
/* atomic operations in linux implicitly form a memory barrier */
#define membar_exit()
@@ -273,14 +163,6 @@ typedef struct kcf_provider_list {
}
-/* list of crypto_mech_info_t valid as the second mech in a dual operation */
-
-typedef struct crypto_mech_info_list {
- struct crypto_mech_info_list *ml_next;
- crypto_mech_type_t ml_kcf_mechid; /* KCF's id */
- crypto_mech_info_t ml_mech_info;
-} crypto_mech_info_list_t;
-
/*
* An element in a mechanism provider descriptors chain.
* The kcf_prov_mech_desc_t is duplicated in every chain the provider belongs
@@ -292,15 +174,9 @@ typedef struct kcf_prov_mech_desc {
struct kcf_mech_entry *pm_me; /* Back to the head */
struct kcf_prov_mech_desc *pm_next; /* Next in the chain */
crypto_mech_info_t pm_mech_info; /* Provider mech info */
- crypto_mech_info_list_t *pm_mi_list; /* list for duals */
kcf_provider_desc_t *pm_prov_desc; /* Common desc. */
} kcf_prov_mech_desc_t;
-/* and the notation shortcuts ... */
-#define pm_provider_type pm_prov_desc.pd_provider_type
-#define pm_provider_handle pm_prov_desc.pd_provider_handle
-#define pm_ops_vector pm_prov_desc.pd_ops_vector
-
/*
* A mechanism entry in an xxx_mech_tab[]. me_pad was deemed
* to be unnecessary and removed.
@@ -308,48 +184,11 @@ typedef struct kcf_prov_mech_desc {
typedef struct kcf_mech_entry {
crypto_mech_name_t me_name; /* mechanism name */
crypto_mech_type_t me_mechid; /* Internal id for mechanism */
- kmutex_t me_mutex; /* access protection */
- kcf_prov_mech_desc_t *me_hw_prov_chain; /* list of HW providers */
- kcf_prov_mech_desc_t *me_sw_prov; /* SW provider */
- /*
- * Number of HW providers in the chain. There is only one
- * SW provider. So, we need only a count of HW providers.
- */
- int me_num_hwprov;
- /*
- * When a SW provider is present, this is the generation number that
- * ensures no objects from old SW providers are used in the new one
- */
- uint32_t me_gen_swprov;
- /*
- * threshold for using hardware providers for this mech
- */
- size_t me_threshold;
+ kcf_prov_mech_desc_t *me_sw_prov; /* provider */
+ avl_node_t me_node;
} kcf_mech_entry_t;
/*
- * A policy descriptor structure. It is allocated and initialized
- * when administrative ioctls load disabled mechanisms.
- *
- * pd_prov_type: Provider type, hardware or software
- * pd_name: Device name or module name.
- * pd_instance: Device instance.
- * pd_refcnt: Reference counter for this policy descriptor
- * pd_mutex: Protects array and count of disabled mechanisms.
- * pd_disabled_count: Count of disabled mechanisms.
- * pd_disabled_mechs: Array of disabled mechanisms.
- */
-typedef struct kcf_policy_desc {
- crypto_provider_type_t pd_prov_type;
- char *pd_name;
- uint_t pd_instance;
- uint_t pd_refcnt;
- kmutex_t pd_mutex;
- uint_t pd_disabled_count;
- crypto_mech_name_t *pd_disabled_mechs;
-} kcf_policy_desc_t;
-
-/*
* If a component has a reference to a kcf_policy_desc_t,
* it REFHOLD()s. A new policy descriptor which is referenced only
* by the policy table has a reference count of one.
@@ -371,43 +210,28 @@ typedef struct kcf_policy_desc {
}
/*
- * This entry stores the name of a software module and its
- * mechanisms. The mechanisms are 'hints' that are used to
- * trigger loading of the module.
- */
-typedef struct kcf_soft_conf_entry {
- struct kcf_soft_conf_entry *ce_next;
- char *ce_name;
- crypto_mech_name_t *ce_mechs;
- uint_t ce_count;
-} kcf_soft_conf_entry_t;
-
-extern kmutex_t soft_config_mutex;
-extern kcf_soft_conf_entry_t *soft_config_list;
-
-/*
* Global tables. The sizes are from the predefined PKCS#11 v2.20 mechanisms,
* with a margin of few extra empty entry points
*/
#define KCF_MAXDIGEST 16 /* Digests */
-#define KCF_MAXCIPHER 64 /* Ciphers */
+#define KCF_MAXCIPHER 32 /* Ciphers */
#define KCF_MAXMAC 40 /* Message authentication codes */
-#define KCF_MAXSIGN 24 /* Sign/Verify */
-#define KCF_MAXKEYOPS 116 /* Key generation and derivation */
-#define KCF_MAXMISC 16 /* Others ... */
+
+_Static_assert(KCF_MAXCIPHER == KCF_MAXMECHTAB,
+ "KCF_MAXCIPHER != KCF_MAXMECHTAB"); /* See KCF_MAXMECHTAB comment */
typedef enum {
KCF_DIGEST_CLASS = 1,
KCF_CIPHER_CLASS,
KCF_MAC_CLASS,
- KCF_SIGN_CLASS,
- KCF_KEYOPS_CLASS,
- KCF_MISC_CLASS
} kcf_ops_class_t;
#define KCF_FIRST_OPSCLASS KCF_DIGEST_CLASS
-#define KCF_LAST_OPSCLASS KCF_MISC_CLASS
+#define KCF_LAST_OPSCLASS KCF_MAC_CLASS
+_Static_assert(
+ KCF_OPS_CLASSSIZE == (KCF_LAST_OPSCLASS - KCF_FIRST_OPSCLASS + 2),
+ "KCF_OPS_CLASSSIZE doesn't match kcf_ops_class_t!");
/* The table of all the kcf_xxx_mech_tab[]s, indexed by kcf_ops_class */
@@ -423,7 +247,7 @@ extern const kcf_mech_entry_tab_t kcf_mech_tabs_tab[];
#define KCF_MECH2CLASS(mech_type) ((kcf_ops_class_t)((mech_type) >> 32))
-#define KCF_MECH2INDEX(mech_type) ((int)(mech_type))
+#define KCF_MECH2INDEX(mech_type) ((int)((mech_type) & 0xFFFFFFFF))
#define KCF_TO_PROV_MECH_INDX(pd, mech_type) \
((pd)->pd_mech_indx[KCF_MECH2CLASS(mech_type)] \
@@ -435,58 +259,6 @@ extern const kcf_mech_entry_tab_t kcf_mech_tabs_tab[];
#define KCF_TO_PROV_MECHNUM(pd, mech_type) \
(KCF_TO_PROV_MECHINFO(pd, mech_type).cm_mech_number)
-#define KCF_CAN_SHARE_OPSTATE(pd, mech_type) \
- ((KCF_TO_PROV_MECHINFO(pd, mech_type).cm_mech_flags) & \
- CRYPTO_CAN_SHARE_OPSTATE)
-
-/* ps_refcnt is protected by cm_lock in the crypto_minor structure */
-typedef struct crypto_provider_session {
- struct crypto_provider_session *ps_next;
- crypto_session_id_t ps_session;
- kcf_provider_desc_t *ps_provider;
- kcf_provider_desc_t *ps_real_provider;
- uint_t ps_refcnt;
-} crypto_provider_session_t;
-
-typedef struct crypto_session_data {
- kmutex_t sd_lock;
- kcondvar_t sd_cv;
- uint32_t sd_flags;
- int sd_pre_approved_amount;
- crypto_ctx_t *sd_digest_ctx;
- crypto_ctx_t *sd_encr_ctx;
- crypto_ctx_t *sd_decr_ctx;
- crypto_ctx_t *sd_sign_ctx;
- crypto_ctx_t *sd_verify_ctx;
- crypto_ctx_t *sd_sign_recover_ctx;
- crypto_ctx_t *sd_verify_recover_ctx;
- kcf_provider_desc_t *sd_provider;
- void *sd_find_init_cookie;
- crypto_provider_session_t *sd_provider_session;
-} crypto_session_data_t;
-
-#define CRYPTO_SESSION_IN_USE 0x00000001
-#define CRYPTO_SESSION_IS_BUSY 0x00000002
-#define CRYPTO_SESSION_IS_CLOSED 0x00000004
-
-#define KCF_MAX_PIN_LEN 1024
-
-/*
- * Per-minor info.
- *
- * cm_lock protects everything in this structure except for cm_refcnt.
- */
-typedef struct crypto_minor {
- uint_t cm_refcnt;
- kmutex_t cm_lock;
- kcondvar_t cm_cv;
- crypto_session_data_t **cm_session_table;
- uint_t cm_session_table_count;
- kcf_provider_desc_t **cm_provider_array;
- uint_t cm_provider_count;
- crypto_provider_session_t *cm_provider_session;
-} crypto_minor_t;
-
/*
* Return codes for internal functions
*/
@@ -498,847 +270,118 @@ typedef struct crypto_minor {
#define KCF_INVALID_INDX ((ushort_t)-1)
/*
- * kCF internal mechanism and function group for tracking RNG providers.
- */
-#define SUN_RANDOM "random"
-#define CRYPTO_FG_RANDOM 0x80000000 /* generate_random() */
-
-/*
* Wrappers for ops vectors. In the wrapper definitions below, the pd
* argument always corresponds to a pointer to a provider descriptor
* of type kcf_prov_desc_t.
*/
-#define KCF_PROV_CONTROL_OPS(pd) ((pd)->pd_ops_vector->co_control_ops)
-#define KCF_PROV_CTX_OPS(pd) ((pd)->pd_ops_vector->co_ctx_ops)
#define KCF_PROV_DIGEST_OPS(pd) ((pd)->pd_ops_vector->co_digest_ops)
#define KCF_PROV_CIPHER_OPS(pd) ((pd)->pd_ops_vector->co_cipher_ops)
#define KCF_PROV_MAC_OPS(pd) ((pd)->pd_ops_vector->co_mac_ops)
-#define KCF_PROV_SIGN_OPS(pd) ((pd)->pd_ops_vector->co_sign_ops)
-#define KCF_PROV_VERIFY_OPS(pd) ((pd)->pd_ops_vector->co_verify_ops)
-#define KCF_PROV_DUAL_OPS(pd) ((pd)->pd_ops_vector->co_dual_ops)
-#define KCF_PROV_DUAL_CIPHER_MAC_OPS(pd) \
- ((pd)->pd_ops_vector->co_dual_cipher_mac_ops)
-#define KCF_PROV_RANDOM_OPS(pd) ((pd)->pd_ops_vector->co_random_ops)
-#define KCF_PROV_SESSION_OPS(pd) ((pd)->pd_ops_vector->co_session_ops)
-#define KCF_PROV_OBJECT_OPS(pd) ((pd)->pd_ops_vector->co_object_ops)
-#define KCF_PROV_KEY_OPS(pd) ((pd)->pd_ops_vector->co_key_ops)
-#define KCF_PROV_PROVIDER_OPS(pd) ((pd)->pd_ops_vector->co_provider_ops)
-#define KCF_PROV_MECH_OPS(pd) ((pd)->pd_ops_vector->co_mech_ops)
-#define KCF_PROV_NOSTORE_KEY_OPS(pd) \
- ((pd)->pd_ops_vector->co_nostore_key_ops)
-
-/*
- * Wrappers for crypto_control_ops(9S) entry points.
- */
-
-#define KCF_PROV_STATUS(pd, status) ( \
- (KCF_PROV_CONTROL_OPS(pd) && \
- KCF_PROV_CONTROL_OPS(pd)->provider_status) ? \
- KCF_PROV_CONTROL_OPS(pd)->provider_status( \
- (pd)->pd_prov_handle, status) : \
- CRYPTO_NOT_SUPPORTED)
-
-/*
- * Wrappers for crypto_ctx_ops(9S) entry points.
- */
-
-#define KCF_PROV_CREATE_CTX_TEMPLATE(pd, mech, key, template, size, req) ( \
- (KCF_PROV_CTX_OPS(pd) && KCF_PROV_CTX_OPS(pd)->create_ctx_template) ? \
- KCF_PROV_CTX_OPS(pd)->create_ctx_template( \
- (pd)->pd_prov_handle, mech, key, template, size, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_FREE_CONTEXT(pd, ctx) ( \
- (KCF_PROV_CTX_OPS(pd) && KCF_PROV_CTX_OPS(pd)->free_context) ? \
- KCF_PROV_CTX_OPS(pd)->free_context(ctx) : CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_COPYIN_MECH(pd, umech, kmech, errorp, mode) ( \
- (KCF_PROV_MECH_OPS(pd) && KCF_PROV_MECH_OPS(pd)->copyin_mechanism) ? \
- KCF_PROV_MECH_OPS(pd)->copyin_mechanism( \
- (pd)->pd_prov_handle, umech, kmech, errorp, mode) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_COPYOUT_MECH(pd, kmech, umech, errorp, mode) ( \
- (KCF_PROV_MECH_OPS(pd) && KCF_PROV_MECH_OPS(pd)->copyout_mechanism) ? \
- KCF_PROV_MECH_OPS(pd)->copyout_mechanism( \
- (pd)->pd_prov_handle, kmech, umech, errorp, mode) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_FREE_MECH(pd, prov_mech) ( \
- (KCF_PROV_MECH_OPS(pd) && KCF_PROV_MECH_OPS(pd)->free_mechanism) ? \
- KCF_PROV_MECH_OPS(pd)->free_mechanism( \
- (pd)->pd_prov_handle, prov_mech) : CRYPTO_NOT_SUPPORTED)
+#define KCF_PROV_CTX_OPS(pd) ((pd)->pd_ops_vector->co_ctx_ops)
/*
* Wrappers for crypto_digest_ops(9S) entry points.
*/
-#define KCF_PROV_DIGEST_INIT(pd, ctx, mech, req) ( \
+#define KCF_PROV_DIGEST_INIT(pd, ctx, mech) ( \
(KCF_PROV_DIGEST_OPS(pd) && KCF_PROV_DIGEST_OPS(pd)->digest_init) ? \
- KCF_PROV_DIGEST_OPS(pd)->digest_init(ctx, mech, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-/*
- * The _ (underscore) in _digest is needed to avoid replacing the
- * function digest().
- */
-#define KCF_PROV_DIGEST(pd, ctx, data, _digest, req) ( \
- (KCF_PROV_DIGEST_OPS(pd) && KCF_PROV_DIGEST_OPS(pd)->digest) ? \
- KCF_PROV_DIGEST_OPS(pd)->digest(ctx, data, _digest, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_DIGEST_UPDATE(pd, ctx, data, req) ( \
- (KCF_PROV_DIGEST_OPS(pd) && KCF_PROV_DIGEST_OPS(pd)->digest_update) ? \
- KCF_PROV_DIGEST_OPS(pd)->digest_update(ctx, data, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_DIGEST_KEY(pd, ctx, key, req) ( \
- (KCF_PROV_DIGEST_OPS(pd) && KCF_PROV_DIGEST_OPS(pd)->digest_key) ? \
- KCF_PROV_DIGEST_OPS(pd)->digest_key(ctx, key, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_DIGEST_FINAL(pd, ctx, digest, req) ( \
- (KCF_PROV_DIGEST_OPS(pd) && KCF_PROV_DIGEST_OPS(pd)->digest_final) ? \
- KCF_PROV_DIGEST_OPS(pd)->digest_final(ctx, digest, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_DIGEST_ATOMIC(pd, session, mech, data, digest, req) ( \
- (KCF_PROV_DIGEST_OPS(pd) && KCF_PROV_DIGEST_OPS(pd)->digest_atomic) ? \
- KCF_PROV_DIGEST_OPS(pd)->digest_atomic( \
- (pd)->pd_prov_handle, session, mech, data, digest, req) : \
+ KCF_PROV_DIGEST_OPS(pd)->digest_init(ctx, mech) : \
CRYPTO_NOT_SUPPORTED)
/*
* Wrappers for crypto_cipher_ops(9S) entry points.
*/
-#define KCF_PROV_ENCRYPT_INIT(pd, ctx, mech, key, template, req) ( \
+#define KCF_PROV_ENCRYPT_INIT(pd, ctx, mech, key, template) ( \
(KCF_PROV_CIPHER_OPS(pd) && KCF_PROV_CIPHER_OPS(pd)->encrypt_init) ? \
- KCF_PROV_CIPHER_OPS(pd)->encrypt_init(ctx, mech, key, template, \
- req) : \
+ KCF_PROV_CIPHER_OPS(pd)->encrypt_init(ctx, mech, key, template) : \
CRYPTO_NOT_SUPPORTED)
-#define KCF_PROV_ENCRYPT(pd, ctx, plaintext, ciphertext, req) ( \
- (KCF_PROV_CIPHER_OPS(pd) && KCF_PROV_CIPHER_OPS(pd)->encrypt) ? \
- KCF_PROV_CIPHER_OPS(pd)->encrypt(ctx, plaintext, ciphertext, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_ENCRYPT_UPDATE(pd, ctx, plaintext, ciphertext, req) ( \
- (KCF_PROV_CIPHER_OPS(pd) && KCF_PROV_CIPHER_OPS(pd)->encrypt_update) ? \
- KCF_PROV_CIPHER_OPS(pd)->encrypt_update(ctx, plaintext, \
- ciphertext, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_ENCRYPT_FINAL(pd, ctx, ciphertext, req) ( \
- (KCF_PROV_CIPHER_OPS(pd) && KCF_PROV_CIPHER_OPS(pd)->encrypt_final) ? \
- KCF_PROV_CIPHER_OPS(pd)->encrypt_final(ctx, ciphertext, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_ENCRYPT_ATOMIC(pd, session, mech, key, plaintext, ciphertext, \
- template, req) ( \
+#define KCF_PROV_ENCRYPT_ATOMIC(pd, mech, key, plaintext, ciphertext, \
+ template) ( \
(KCF_PROV_CIPHER_OPS(pd) && KCF_PROV_CIPHER_OPS(pd)->encrypt_atomic) ? \
KCF_PROV_CIPHER_OPS(pd)->encrypt_atomic( \
- (pd)->pd_prov_handle, session, mech, key, plaintext, ciphertext, \
- template, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_DECRYPT_INIT(pd, ctx, mech, key, template, req) ( \
- (KCF_PROV_CIPHER_OPS(pd) && KCF_PROV_CIPHER_OPS(pd)->decrypt_init) ? \
- KCF_PROV_CIPHER_OPS(pd)->decrypt_init(ctx, mech, key, template, \
- req) : \
+ mech, key, plaintext, ciphertext, template) : \
CRYPTO_NOT_SUPPORTED)
-#define KCF_PROV_DECRYPT(pd, ctx, ciphertext, plaintext, req) ( \
- (KCF_PROV_CIPHER_OPS(pd) && KCF_PROV_CIPHER_OPS(pd)->decrypt) ? \
- KCF_PROV_CIPHER_OPS(pd)->decrypt(ctx, ciphertext, plaintext, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_DECRYPT_UPDATE(pd, ctx, ciphertext, plaintext, req) ( \
- (KCF_PROV_CIPHER_OPS(pd) && KCF_PROV_CIPHER_OPS(pd)->decrypt_update) ? \
- KCF_PROV_CIPHER_OPS(pd)->decrypt_update(ctx, ciphertext, \
- plaintext, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_DECRYPT_FINAL(pd, ctx, plaintext, req) ( \
- (KCF_PROV_CIPHER_OPS(pd) && KCF_PROV_CIPHER_OPS(pd)->decrypt_final) ? \
- KCF_PROV_CIPHER_OPS(pd)->decrypt_final(ctx, plaintext, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_DECRYPT_ATOMIC(pd, session, mech, key, ciphertext, plaintext, \
- template, req) ( \
+#define KCF_PROV_DECRYPT_ATOMIC(pd, mech, key, ciphertext, plaintext, \
+ template) ( \
(KCF_PROV_CIPHER_OPS(pd) && KCF_PROV_CIPHER_OPS(pd)->decrypt_atomic) ? \
KCF_PROV_CIPHER_OPS(pd)->decrypt_atomic( \
- (pd)->pd_prov_handle, session, mech, key, ciphertext, plaintext, \
- template, req) : \
+ mech, key, ciphertext, plaintext, template) : \
CRYPTO_NOT_SUPPORTED)
/*
* Wrappers for crypto_mac_ops(9S) entry points.
*/
-#define KCF_PROV_MAC_INIT(pd, ctx, mech, key, template, req) ( \
+#define KCF_PROV_MAC_INIT(pd, ctx, mech, key, template) ( \
(KCF_PROV_MAC_OPS(pd) && KCF_PROV_MAC_OPS(pd)->mac_init) ? \
- KCF_PROV_MAC_OPS(pd)->mac_init(ctx, mech, key, template, req) \
+ KCF_PROV_MAC_OPS(pd)->mac_init(ctx, mech, key, template) \
: CRYPTO_NOT_SUPPORTED)
/*
* The _ (underscore) in _mac is needed to avoid replacing the
* function mac().
*/
-#define KCF_PROV_MAC(pd, ctx, data, _mac, req) ( \
- (KCF_PROV_MAC_OPS(pd) && KCF_PROV_MAC_OPS(pd)->mac) ? \
- KCF_PROV_MAC_OPS(pd)->mac(ctx, data, _mac, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_MAC_UPDATE(pd, ctx, data, req) ( \
+#define KCF_PROV_MAC_UPDATE(pd, ctx, data) ( \
(KCF_PROV_MAC_OPS(pd) && KCF_PROV_MAC_OPS(pd)->mac_update) ? \
- KCF_PROV_MAC_OPS(pd)->mac_update(ctx, data, req) : \
+ KCF_PROV_MAC_OPS(pd)->mac_update(ctx, data) : \
CRYPTO_NOT_SUPPORTED)
-#define KCF_PROV_MAC_FINAL(pd, ctx, mac, req) ( \
+#define KCF_PROV_MAC_FINAL(pd, ctx, mac) ( \
(KCF_PROV_MAC_OPS(pd) && KCF_PROV_MAC_OPS(pd)->mac_final) ? \
- KCF_PROV_MAC_OPS(pd)->mac_final(ctx, mac, req) : \
+ KCF_PROV_MAC_OPS(pd)->mac_final(ctx, mac) : \
CRYPTO_NOT_SUPPORTED)
-#define KCF_PROV_MAC_ATOMIC(pd, session, mech, key, data, mac, template, \
- req) ( \
+#define KCF_PROV_MAC_ATOMIC(pd, mech, key, data, mac, template) ( \
(KCF_PROV_MAC_OPS(pd) && KCF_PROV_MAC_OPS(pd)->mac_atomic) ? \
KCF_PROV_MAC_OPS(pd)->mac_atomic( \
- (pd)->pd_prov_handle, session, mech, key, data, mac, template, \
- req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_MAC_VERIFY_ATOMIC(pd, session, mech, key, data, mac, \
- template, req) ( \
- (KCF_PROV_MAC_OPS(pd) && KCF_PROV_MAC_OPS(pd)->mac_verify_atomic) ? \
- KCF_PROV_MAC_OPS(pd)->mac_verify_atomic( \
- (pd)->pd_prov_handle, session, mech, key, data, mac, template, \
- req) : \
- CRYPTO_NOT_SUPPORTED)
-
-/*
- * Wrappers for crypto_sign_ops(9S) entry points.
- */
-
-#define KCF_PROV_SIGN_INIT(pd, ctx, mech, key, template, req) ( \
- (KCF_PROV_SIGN_OPS(pd) && KCF_PROV_SIGN_OPS(pd)->sign_init) ? \
- KCF_PROV_SIGN_OPS(pd)->sign_init( \
- ctx, mech, key, template, req) : CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_SIGN(pd, ctx, data, sig, req) ( \
- (KCF_PROV_SIGN_OPS(pd) && KCF_PROV_SIGN_OPS(pd)->sign) ? \
- KCF_PROV_SIGN_OPS(pd)->sign(ctx, data, sig, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_SIGN_UPDATE(pd, ctx, data, req) ( \
- (KCF_PROV_SIGN_OPS(pd) && KCF_PROV_SIGN_OPS(pd)->sign_update) ? \
- KCF_PROV_SIGN_OPS(pd)->sign_update(ctx, data, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_SIGN_FINAL(pd, ctx, sig, req) ( \
- (KCF_PROV_SIGN_OPS(pd) && KCF_PROV_SIGN_OPS(pd)->sign_final) ? \
- KCF_PROV_SIGN_OPS(pd)->sign_final(ctx, sig, req) : \
+ mech, key, data, mac, template) : \
CRYPTO_NOT_SUPPORTED)
-#define KCF_PROV_SIGN_ATOMIC(pd, session, mech, key, data, template, \
- sig, req) ( \
- (KCF_PROV_SIGN_OPS(pd) && KCF_PROV_SIGN_OPS(pd)->sign_atomic) ? \
- KCF_PROV_SIGN_OPS(pd)->sign_atomic( \
- (pd)->pd_prov_handle, session, mech, key, data, sig, template, \
- req) : CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_SIGN_RECOVER_INIT(pd, ctx, mech, key, template, \
- req) ( \
- (KCF_PROV_SIGN_OPS(pd) && KCF_PROV_SIGN_OPS(pd)->sign_recover_init) ? \
- KCF_PROV_SIGN_OPS(pd)->sign_recover_init(ctx, mech, key, template, \
- req) : CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_SIGN_RECOVER(pd, ctx, data, sig, req) ( \
- (KCF_PROV_SIGN_OPS(pd) && KCF_PROV_SIGN_OPS(pd)->sign_recover) ? \
- KCF_PROV_SIGN_OPS(pd)->sign_recover(ctx, data, sig, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_SIGN_RECOVER_ATOMIC(pd, session, mech, key, data, template, \
- sig, req) ( \
- (KCF_PROV_SIGN_OPS(pd) && \
- KCF_PROV_SIGN_OPS(pd)->sign_recover_atomic) ? \
- KCF_PROV_SIGN_OPS(pd)->sign_recover_atomic( \
- (pd)->pd_prov_handle, session, mech, key, data, sig, template, \
- req) : CRYPTO_NOT_SUPPORTED)
-
/*
- * Wrappers for crypto_verify_ops(9S) entry points.
- */
-
-#define KCF_PROV_VERIFY_INIT(pd, ctx, mech, key, template, req) ( \
- (KCF_PROV_VERIFY_OPS(pd) && KCF_PROV_VERIFY_OPS(pd)->verify_init) ? \
- KCF_PROV_VERIFY_OPS(pd)->verify_init(ctx, mech, key, template, \
- req) : CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_VERIFY(pd, ctx, data, sig, req) ( \
- (KCF_PROV_VERIFY_OPS(pd) && KCF_PROV_VERIFY_OPS(pd)->do_verify) ? \
- KCF_PROV_VERIFY_OPS(pd)->do_verify(ctx, data, sig, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_VERIFY_UPDATE(pd, ctx, data, req) ( \
- (KCF_PROV_VERIFY_OPS(pd) && KCF_PROV_VERIFY_OPS(pd)->verify_update) ? \
- KCF_PROV_VERIFY_OPS(pd)->verify_update(ctx, data, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_VERIFY_FINAL(pd, ctx, sig, req) ( \
- (KCF_PROV_VERIFY_OPS(pd) && KCF_PROV_VERIFY_OPS(pd)->verify_final) ? \
- KCF_PROV_VERIFY_OPS(pd)->verify_final(ctx, sig, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_VERIFY_ATOMIC(pd, session, mech, key, data, template, sig, \
- req) ( \
- (KCF_PROV_VERIFY_OPS(pd) && KCF_PROV_VERIFY_OPS(pd)->verify_atomic) ? \
- KCF_PROV_VERIFY_OPS(pd)->verify_atomic( \
- (pd)->pd_prov_handle, session, mech, key, data, sig, template, \
- req) : CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_VERIFY_RECOVER_INIT(pd, ctx, mech, key, template, \
- req) ( \
- (KCF_PROV_VERIFY_OPS(pd) && \
- KCF_PROV_VERIFY_OPS(pd)->verify_recover_init) ? \
- KCF_PROV_VERIFY_OPS(pd)->verify_recover_init(ctx, mech, key, \
- template, req) : CRYPTO_NOT_SUPPORTED)
-
-/* verify_recover() CSPI routine has different argument order than verify() */
-#define KCF_PROV_VERIFY_RECOVER(pd, ctx, sig, data, req) ( \
- (KCF_PROV_VERIFY_OPS(pd) && KCF_PROV_VERIFY_OPS(pd)->verify_recover) ? \
- KCF_PROV_VERIFY_OPS(pd)->verify_recover(ctx, sig, data, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-/*
- * verify_recover_atomic() CSPI routine has different argument order
- * than verify_atomic().
- */
-#define KCF_PROV_VERIFY_RECOVER_ATOMIC(pd, session, mech, key, sig, \
- template, data, req) ( \
- (KCF_PROV_VERIFY_OPS(pd) && \
- KCF_PROV_VERIFY_OPS(pd)->verify_recover_atomic) ? \
- KCF_PROV_VERIFY_OPS(pd)->verify_recover_atomic( \
- (pd)->pd_prov_handle, session, mech, key, sig, data, template, \
- req) : CRYPTO_NOT_SUPPORTED)
-
-/*
- * Wrappers for crypto_dual_ops(9S) entry points.
- */
-
-#define KCF_PROV_DIGEST_ENCRYPT_UPDATE(digest_ctx, encrypt_ctx, plaintext, \
- ciphertext, req) ( \
- (KCF_PROV_DUAL_OPS(pd) && \
- KCF_PROV_DUAL_OPS(pd)->digest_encrypt_update) ? \
- KCF_PROV_DUAL_OPS(pd)->digest_encrypt_update( \
- digest_ctx, encrypt_ctx, plaintext, ciphertext, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_DECRYPT_DIGEST_UPDATE(decrypt_ctx, digest_ctx, ciphertext, \
- plaintext, req) ( \
- (KCF_PROV_DUAL_OPS(pd) && \
- KCF_PROV_DUAL_OPS(pd)->decrypt_digest_update) ? \
- KCF_PROV_DUAL_OPS(pd)->decrypt_digest_update( \
- decrypt_ctx, digest_ctx, ciphertext, plaintext, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_SIGN_ENCRYPT_UPDATE(sign_ctx, encrypt_ctx, plaintext, \
- ciphertext, req) ( \
- (KCF_PROV_DUAL_OPS(pd) && \
- KCF_PROV_DUAL_OPS(pd)->sign_encrypt_update) ? \
- KCF_PROV_DUAL_OPS(pd)->sign_encrypt_update( \
- sign_ctx, encrypt_ctx, plaintext, ciphertext, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_DECRYPT_VERIFY_UPDATE(decrypt_ctx, verify_ctx, ciphertext, \
- plaintext, req) ( \
- (KCF_PROV_DUAL_OPS(pd) && \
- KCF_PROV_DUAL_OPS(pd)->decrypt_verify_update) ? \
- KCF_PROV_DUAL_OPS(pd)->decrypt_verify_update( \
- decrypt_ctx, verify_ctx, ciphertext, plaintext, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-/*
- * Wrappers for crypto_dual_cipher_mac_ops(9S) entry points.
- */
-
-#define KCF_PROV_ENCRYPT_MAC_INIT(pd, ctx, encr_mech, encr_key, mac_mech, \
- mac_key, encr_ctx_template, mac_ctx_template, req) ( \
- (KCF_PROV_DUAL_CIPHER_MAC_OPS(pd) && \
- KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->encrypt_mac_init) ? \
- KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->encrypt_mac_init( \
- ctx, encr_mech, encr_key, mac_mech, mac_key, encr_ctx_template, \
- mac_ctx_template, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_ENCRYPT_MAC(pd, ctx, plaintext, ciphertext, mac, req) ( \
- (KCF_PROV_DUAL_CIPHER_MAC_OPS(pd) && \
- KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->encrypt_mac) ? \
- KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->encrypt_mac( \
- ctx, plaintext, ciphertext, mac, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_ENCRYPT_MAC_UPDATE(pd, ctx, plaintext, ciphertext, req) ( \
- (KCF_PROV_DUAL_CIPHER_MAC_OPS(pd) && \
- KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->encrypt_mac_update) ? \
- KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->encrypt_mac_update( \
- ctx, plaintext, ciphertext, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_ENCRYPT_MAC_FINAL(pd, ctx, ciphertext, mac, req) ( \
- (KCF_PROV_DUAL_CIPHER_MAC_OPS(pd) && \
- KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->encrypt_mac_final) ? \
- KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->encrypt_mac_final( \
- ctx, ciphertext, mac, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_ENCRYPT_MAC_ATOMIC(pd, session, encr_mech, encr_key, \
- mac_mech, mac_key, plaintext, ciphertext, mac, \
- encr_ctx_template, mac_ctx_template, req) ( \
- (KCF_PROV_DUAL_CIPHER_MAC_OPS(pd) && \
- KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->encrypt_mac_atomic) ? \
- KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->encrypt_mac_atomic( \
- (pd)->pd_prov_handle, session, encr_mech, encr_key, \
- mac_mech, mac_key, plaintext, ciphertext, mac, \
- encr_ctx_template, mac_ctx_template, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_MAC_DECRYPT_INIT(pd, ctx, mac_mech, mac_key, decr_mech, \
- decr_key, mac_ctx_template, decr_ctx_template, req) ( \
- (KCF_PROV_DUAL_CIPHER_MAC_OPS(pd) && \
- KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->mac_decrypt_init) ? \
- KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->mac_decrypt_init( \
- ctx, mac_mech, mac_key, decr_mech, decr_key, mac_ctx_template, \
- decr_ctx_template, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_MAC_DECRYPT(pd, ctx, ciphertext, mac, plaintext, req) ( \
- (KCF_PROV_DUAL_CIPHER_MAC_OPS(pd) && \
- KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->mac_decrypt) ? \
- KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->mac_decrypt( \
- ctx, ciphertext, mac, plaintext, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_MAC_DECRYPT_UPDATE(pd, ctx, ciphertext, plaintext, req) ( \
- (KCF_PROV_DUAL_CIPHER_MAC_OPS(pd) && \
- KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->mac_decrypt_update) ? \
- KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->mac_decrypt_update( \
- ctx, ciphertext, plaintext, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_MAC_DECRYPT_FINAL(pd, ctx, mac, plaintext, req) ( \
- (KCF_PROV_DUAL_CIPHER_MAC_OPS(pd) && \
- KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->mac_decrypt_final) ? \
- KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->mac_decrypt_final( \
- ctx, mac, plaintext, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_MAC_DECRYPT_ATOMIC(pd, session, mac_mech, mac_key, \
- decr_mech, decr_key, ciphertext, mac, plaintext, \
- mac_ctx_template, decr_ctx_template, req) ( \
- (KCF_PROV_DUAL_CIPHER_MAC_OPS(pd) && \
- KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->mac_decrypt_atomic) ? \
- KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->mac_decrypt_atomic( \
- (pd)->pd_prov_handle, session, mac_mech, mac_key, \
- decr_mech, decr_key, ciphertext, mac, plaintext, \
- mac_ctx_template, decr_ctx_template, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_MAC_VERIFY_DECRYPT_ATOMIC(pd, session, mac_mech, mac_key, \
- decr_mech, decr_key, ciphertext, mac, plaintext, \
- mac_ctx_template, decr_ctx_template, req) ( \
- (KCF_PROV_DUAL_CIPHER_MAC_OPS(pd) && \
- KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->mac_verify_decrypt_atomic \
- != NULL) ? \
- KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->mac_verify_decrypt_atomic( \
- (pd)->pd_prov_handle, session, mac_mech, mac_key, \
- decr_mech, decr_key, ciphertext, mac, plaintext, \
- mac_ctx_template, decr_ctx_template, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-/*
- * Wrappers for crypto_random_number_ops(9S) entry points.
- */
-
-#define KCF_PROV_SEED_RANDOM(pd, session, buf, len, est, flags, req) ( \
- (KCF_PROV_RANDOM_OPS(pd) && KCF_PROV_RANDOM_OPS(pd)->seed_random) ? \
- KCF_PROV_RANDOM_OPS(pd)->seed_random((pd)->pd_prov_handle, \
- session, buf, len, est, flags, req) : CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_GENERATE_RANDOM(pd, session, buf, len, req) ( \
- (KCF_PROV_RANDOM_OPS(pd) && \
- KCF_PROV_RANDOM_OPS(pd)->generate_random) ? \
- KCF_PROV_RANDOM_OPS(pd)->generate_random((pd)->pd_prov_handle, \
- session, buf, len, req) : CRYPTO_NOT_SUPPORTED)
-
-/*
- * Wrappers for crypto_session_ops(9S) entry points.
- *
- * ops_pd is the provider descriptor that supplies the ops_vector.
- * pd is the descriptor that supplies the provider handle.
- * Only session open/close needs two handles.
- */
-
-#define KCF_PROV_SESSION_OPEN(ops_pd, session, req, pd) ( \
- (KCF_PROV_SESSION_OPS(ops_pd) && \
- KCF_PROV_SESSION_OPS(ops_pd)->session_open) ? \
- KCF_PROV_SESSION_OPS(ops_pd)->session_open((pd)->pd_prov_handle, \
- session, req) : CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_SESSION_CLOSE(ops_pd, session, req, pd) ( \
- (KCF_PROV_SESSION_OPS(ops_pd) && \
- KCF_PROV_SESSION_OPS(ops_pd)->session_close) ? \
- KCF_PROV_SESSION_OPS(ops_pd)->session_close((pd)->pd_prov_handle, \
- session, req) : CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_SESSION_LOGIN(pd, session, user_type, pin, len, req) ( \
- (KCF_PROV_SESSION_OPS(pd) && \
- KCF_PROV_SESSION_OPS(pd)->session_login) ? \
- KCF_PROV_SESSION_OPS(pd)->session_login((pd)->pd_prov_handle, \
- session, user_type, pin, len, req) : CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_SESSION_LOGOUT(pd, session, req) ( \
- (KCF_PROV_SESSION_OPS(pd) && \
- KCF_PROV_SESSION_OPS(pd)->session_logout) ? \
- KCF_PROV_SESSION_OPS(pd)->session_logout((pd)->pd_prov_handle, \
- session, req) : CRYPTO_NOT_SUPPORTED)
-
-/*
- * Wrappers for crypto_object_ops(9S) entry points.
- */
-
-#define KCF_PROV_OBJECT_CREATE(pd, session, template, count, object, req) ( \
- (KCF_PROV_OBJECT_OPS(pd) && KCF_PROV_OBJECT_OPS(pd)->object_create) ? \
- KCF_PROV_OBJECT_OPS(pd)->object_create((pd)->pd_prov_handle, \
- session, template, count, object, req) : CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_OBJECT_COPY(pd, session, object, template, count, \
- new_object, req) ( \
- (KCF_PROV_OBJECT_OPS(pd) && KCF_PROV_OBJECT_OPS(pd)->object_copy) ? \
- KCF_PROV_OBJECT_OPS(pd)->object_copy((pd)->pd_prov_handle, \
- session, object, template, count, new_object, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_OBJECT_DESTROY(pd, session, object, req) ( \
- (KCF_PROV_OBJECT_OPS(pd) && KCF_PROV_OBJECT_OPS(pd)->object_destroy) ? \
- KCF_PROV_OBJECT_OPS(pd)->object_destroy((pd)->pd_prov_handle, \
- session, object, req) : CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_OBJECT_GET_SIZE(pd, session, object, size, req) ( \
- (KCF_PROV_OBJECT_OPS(pd) && \
- KCF_PROV_OBJECT_OPS(pd)->object_get_size) ? \
- KCF_PROV_OBJECT_OPS(pd)->object_get_size((pd)->pd_prov_handle, \
- session, object, size, req) : CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_OBJECT_GET_ATTRIBUTE_VALUE(pd, session, object, template, \
- count, req) ( \
- (KCF_PROV_OBJECT_OPS(pd) && \
- KCF_PROV_OBJECT_OPS(pd)->object_get_attribute_value) ? \
- KCF_PROV_OBJECT_OPS(pd)->object_get_attribute_value( \
- (pd)->pd_prov_handle, session, object, template, count, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_OBJECT_SET_ATTRIBUTE_VALUE(pd, session, object, template, \
- count, req) ( \
- (KCF_PROV_OBJECT_OPS(pd) && \
- KCF_PROV_OBJECT_OPS(pd)->object_set_attribute_value) ? \
- KCF_PROV_OBJECT_OPS(pd)->object_set_attribute_value( \
- (pd)->pd_prov_handle, session, object, template, count, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_OBJECT_FIND_INIT(pd, session, template, count, ppriv, \
- req) ( \
- (KCF_PROV_OBJECT_OPS(pd) && \
- KCF_PROV_OBJECT_OPS(pd)->object_find_init) ? \
- KCF_PROV_OBJECT_OPS(pd)->object_find_init((pd)->pd_prov_handle, \
- session, template, count, ppriv, req) : CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_OBJECT_FIND(pd, ppriv, objects, max_objects, object_count, \
- req) ( \
- (KCF_PROV_OBJECT_OPS(pd) && KCF_PROV_OBJECT_OPS(pd)->object_find) ? \
- KCF_PROV_OBJECT_OPS(pd)->object_find( \
- (pd)->pd_prov_handle, ppriv, objects, max_objects, object_count, \
- req) : CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_OBJECT_FIND_FINAL(pd, ppriv, req) ( \
- (KCF_PROV_OBJECT_OPS(pd) && \
- KCF_PROV_OBJECT_OPS(pd)->object_find_final) ? \
- KCF_PROV_OBJECT_OPS(pd)->object_find_final( \
- (pd)->pd_prov_handle, ppriv, req) : CRYPTO_NOT_SUPPORTED)
-
-/*
- * Wrappers for crypto_key_ops(9S) entry points.
+ * Wrappers for crypto_ctx_ops(9S) entry points.
*/
-#define KCF_PROV_KEY_GENERATE(pd, session, mech, template, count, object, \
- req) ( \
- (KCF_PROV_KEY_OPS(pd) && KCF_PROV_KEY_OPS(pd)->key_generate) ? \
- KCF_PROV_KEY_OPS(pd)->key_generate((pd)->pd_prov_handle, \
- session, mech, template, count, object, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_KEY_GENERATE_PAIR(pd, session, mech, pub_template, \
- pub_count, priv_template, priv_count, pub_key, priv_key, req) ( \
- (KCF_PROV_KEY_OPS(pd) && KCF_PROV_KEY_OPS(pd)->key_generate_pair) ? \
- KCF_PROV_KEY_OPS(pd)->key_generate_pair((pd)->pd_prov_handle, \
- session, mech, pub_template, pub_count, priv_template, \
- priv_count, pub_key, priv_key, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_KEY_WRAP(pd, session, mech, wrapping_key, key, wrapped_key, \
- wrapped_key_len, req) ( \
- (KCF_PROV_KEY_OPS(pd) && KCF_PROV_KEY_OPS(pd)->key_wrap) ? \
- KCF_PROV_KEY_OPS(pd)->key_wrap((pd)->pd_prov_handle, \
- session, mech, wrapping_key, key, wrapped_key, wrapped_key_len, \
- req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_KEY_UNWRAP(pd, session, mech, unwrapping_key, wrapped_key, \
- wrapped_key_len, template, count, key, req) ( \
- (KCF_PROV_KEY_OPS(pd) && KCF_PROV_KEY_OPS(pd)->key_unwrap) ? \
- KCF_PROV_KEY_OPS(pd)->key_unwrap((pd)->pd_prov_handle, \
- session, mech, unwrapping_key, wrapped_key, wrapped_key_len, \
- template, count, key, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_KEY_DERIVE(pd, session, mech, base_key, template, count, \
- key, req) ( \
- (KCF_PROV_KEY_OPS(pd) && KCF_PROV_KEY_OPS(pd)->key_derive) ? \
- KCF_PROV_KEY_OPS(pd)->key_derive((pd)->pd_prov_handle, \
- session, mech, base_key, template, count, key, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_KEY_CHECK(pd, mech, key) ( \
- (KCF_PROV_KEY_OPS(pd) && KCF_PROV_KEY_OPS(pd)->key_check) ? \
- KCF_PROV_KEY_OPS(pd)->key_check((pd)->pd_prov_handle, mech, key) : \
+#define KCF_PROV_CREATE_CTX_TEMPLATE(pd, mech, key, template, size) ( \
+ (KCF_PROV_CTX_OPS(pd) && KCF_PROV_CTX_OPS(pd)->create_ctx_template) ? \
+ KCF_PROV_CTX_OPS(pd)->create_ctx_template( \
+ mech, key, template, size) : \
CRYPTO_NOT_SUPPORTED)
-/*
- * Wrappers for crypto_provider_management_ops(9S) entry points.
- *
- * ops_pd is the provider descriptor that supplies the ops_vector.
- * pd is the descriptor that supplies the provider handle.
- * Only ext_info needs two handles.
- */
-
-#define KCF_PROV_EXT_INFO(ops_pd, provext_info, req, pd) ( \
- (KCF_PROV_PROVIDER_OPS(ops_pd) && \
- KCF_PROV_PROVIDER_OPS(ops_pd)->ext_info) ? \
- KCF_PROV_PROVIDER_OPS(ops_pd)->ext_info((pd)->pd_prov_handle, \
- provext_info, req) : CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_INIT_TOKEN(pd, pin, pin_len, label, req) ( \
- (KCF_PROV_PROVIDER_OPS(pd) && KCF_PROV_PROVIDER_OPS(pd)->init_token) ? \
- KCF_PROV_PROVIDER_OPS(pd)->init_token((pd)->pd_prov_handle, \
- pin, pin_len, label, req) : CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_INIT_PIN(pd, session, pin, pin_len, req) ( \
- (KCF_PROV_PROVIDER_OPS(pd) && KCF_PROV_PROVIDER_OPS(pd)->init_pin) ? \
- KCF_PROV_PROVIDER_OPS(pd)->init_pin((pd)->pd_prov_handle, \
- session, pin, pin_len, req) : CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_SET_PIN(pd, session, old_pin, old_len, new_pin, new_len, \
- req) ( \
- (KCF_PROV_PROVIDER_OPS(pd) && KCF_PROV_PROVIDER_OPS(pd)->set_pin) ? \
- KCF_PROV_PROVIDER_OPS(pd)->set_pin((pd)->pd_prov_handle, \
- session, old_pin, old_len, new_pin, new_len, req) : \
- CRYPTO_NOT_SUPPORTED)
-
-/*
- * Wrappers for crypto_nostore_key_ops(9S) entry points.
- */
-
-#define KCF_PROV_NOSTORE_KEY_GENERATE(pd, session, mech, template, count, \
- out_template, out_count, req) ( \
- (KCF_PROV_NOSTORE_KEY_OPS(pd) && \
- KCF_PROV_NOSTORE_KEY_OPS(pd)->nostore_key_generate) ? \
- KCF_PROV_NOSTORE_KEY_OPS(pd)->nostore_key_generate( \
- (pd)->pd_prov_handle, session, mech, template, count, \
- out_template, out_count, req) : CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_NOSTORE_KEY_GENERATE_PAIR(pd, session, mech, pub_template, \
- pub_count, priv_template, priv_count, out_pub_template, \
- out_pub_count, out_priv_template, out_priv_count, req) ( \
- (KCF_PROV_NOSTORE_KEY_OPS(pd) && \
- KCF_PROV_NOSTORE_KEY_OPS(pd)->nostore_key_generate_pair) ? \
- KCF_PROV_NOSTORE_KEY_OPS(pd)->nostore_key_generate_pair( \
- (pd)->pd_prov_handle, session, mech, pub_template, pub_count, \
- priv_template, priv_count, out_pub_template, out_pub_count, \
- out_priv_template, out_priv_count, req) : CRYPTO_NOT_SUPPORTED)
-
-#define KCF_PROV_NOSTORE_KEY_DERIVE(pd, session, mech, base_key, template, \
- count, out_template, out_count, req) ( \
- (KCF_PROV_NOSTORE_KEY_OPS(pd) && \
- KCF_PROV_NOSTORE_KEY_OPS(pd)->nostore_key_derive) ? \
- KCF_PROV_NOSTORE_KEY_OPS(pd)->nostore_key_derive( \
- (pd)->pd_prov_handle, session, mech, base_key, template, count, \
- out_template, out_count, req) : CRYPTO_NOT_SUPPORTED)
-
-/*
- * The following routines are exported by the kcf module (/kernel/misc/kcf)
- * to the crypto and cryptoadmin modules.
- */
-
-/* Digest/mac/cipher entry points that take a provider descriptor and session */
-extern int crypto_digest_single(crypto_context_t, crypto_data_t *,
- crypto_data_t *, crypto_call_req_t *);
-
-extern int crypto_mac_single(crypto_context_t, crypto_data_t *,
- crypto_data_t *, crypto_call_req_t *);
-
-extern int crypto_encrypt_single(crypto_context_t, crypto_data_t *,
- crypto_data_t *, crypto_call_req_t *);
-
-extern int crypto_decrypt_single(crypto_context_t, crypto_data_t *,
- crypto_data_t *, crypto_call_req_t *);
-
-
-/* Other private digest/mac/cipher entry points not exported through k-API */
-extern int crypto_digest_key_prov(crypto_context_t, crypto_key_t *,
- crypto_call_req_t *);
-
-/* Private sign entry points exported by KCF */
-extern int crypto_sign_single(crypto_context_t, crypto_data_t *,
- crypto_data_t *, crypto_call_req_t *);
-
-extern int crypto_sign_recover_single(crypto_context_t, crypto_data_t *,
- crypto_data_t *, crypto_call_req_t *);
-
-/* Private verify entry points exported by KCF */
-extern int crypto_verify_single(crypto_context_t, crypto_data_t *,
- crypto_data_t *, crypto_call_req_t *);
-
-extern int crypto_verify_recover_single(crypto_context_t, crypto_data_t *,
- crypto_data_t *, crypto_call_req_t *);
-
-/* Private dual operations entry points exported by KCF */
-extern int crypto_digest_encrypt_update(crypto_context_t, crypto_context_t,
- crypto_data_t *, crypto_data_t *, crypto_call_req_t *);
-extern int crypto_decrypt_digest_update(crypto_context_t, crypto_context_t,
- crypto_data_t *, crypto_data_t *, crypto_call_req_t *);
-extern int crypto_sign_encrypt_update(crypto_context_t, crypto_context_t,
- crypto_data_t *, crypto_data_t *, crypto_call_req_t *);
-extern int crypto_decrypt_verify_update(crypto_context_t, crypto_context_t,
- crypto_data_t *, crypto_data_t *, crypto_call_req_t *);
-
-/* Random Number Generation */
-int crypto_seed_random(crypto_provider_handle_t provider, uchar_t *buf,
- size_t len, crypto_call_req_t *req);
-int crypto_generate_random(crypto_provider_handle_t provider, uchar_t *buf,
- size_t len, crypto_call_req_t *req);
-
-/* Provider Management */
-int crypto_get_provider_info(crypto_provider_id_t id,
- crypto_provider_info_t **info, crypto_call_req_t *req);
-int crypto_get_provider_mechanisms(crypto_minor_t *, crypto_provider_id_t id,
- uint_t *count, crypto_mech_name_t **list);
-int crypto_init_token(crypto_provider_handle_t provider, char *pin,
- size_t pin_len, char *label, crypto_call_req_t *);
-int crypto_init_pin(crypto_provider_handle_t provider, char *pin,
- size_t pin_len, crypto_call_req_t *req);
-int crypto_set_pin(crypto_provider_handle_t provider, char *old_pin,
- size_t old_len, char *new_pin, size_t new_len, crypto_call_req_t *req);
-void crypto_free_provider_list(crypto_provider_entry_t *list, uint_t count);
-void crypto_free_provider_info(crypto_provider_info_t *info);
+#define KCF_PROV_FREE_CONTEXT(pd, ctx) ( \
+ (KCF_PROV_CTX_OPS(pd) && KCF_PROV_CTX_OPS(pd)->free_context) ? \
+ KCF_PROV_CTX_OPS(pd)->free_context(ctx) : CRYPTO_NOT_SUPPORTED)
-/* Administrative */
-int crypto_get_dev_list(uint_t *count, crypto_dev_list_entry_t **list);
-int crypto_get_soft_list(uint_t *count, char **list, size_t *len);
-int crypto_get_dev_info(char *name, uint_t instance, uint_t *count,
- crypto_mech_name_t **list);
-int crypto_get_soft_info(caddr_t name, uint_t *count,
- crypto_mech_name_t **list);
-int crypto_load_dev_disabled(char *name, uint_t instance, uint_t count,
- crypto_mech_name_t *list);
-int crypto_load_soft_disabled(caddr_t name, uint_t count,
- crypto_mech_name_t *list);
-int crypto_unload_soft_module(caddr_t path);
-int crypto_load_soft_config(caddr_t name, uint_t count,
- crypto_mech_name_t *list);
-int crypto_load_door(uint_t did);
-void crypto_free_mech_list(crypto_mech_name_t *list, uint_t count);
-void crypto_free_dev_list(crypto_dev_list_entry_t *list, uint_t count);
/* Miscellaneous */
-int crypto_get_mechanism_number(caddr_t name, crypto_mech_type_t *number);
-int crypto_build_permitted_mech_names(kcf_provider_desc_t *,
- crypto_mech_name_t **, uint_t *, int);
extern void kcf_destroy_mech_tabs(void);
extern void kcf_init_mech_tabs(void);
extern int kcf_add_mech_provider(short, kcf_provider_desc_t *,
kcf_prov_mech_desc_t **);
-extern void kcf_remove_mech_provider(char *, kcf_provider_desc_t *);
+extern void kcf_remove_mech_provider(const char *, kcf_provider_desc_t *);
extern int kcf_get_mech_entry(crypto_mech_type_t, kcf_mech_entry_t **);
-extern kcf_provider_desc_t *kcf_alloc_provider_desc(
- const crypto_provider_info_t *);
+extern kcf_provider_desc_t *kcf_alloc_provider_desc(void);
extern void kcf_provider_zero_refcnt(kcf_provider_desc_t *);
extern void kcf_free_provider_desc(kcf_provider_desc_t *);
-extern void kcf_soft_config_init(void);
-extern int get_sw_provider_for_mech(crypto_mech_name_t, char **);
-extern crypto_mech_type_t crypto_mech2id_common(const char *, boolean_t);
extern void undo_register_provider(kcf_provider_desc_t *, boolean_t);
-extern void redo_register_provider(kcf_provider_desc_t *);
-extern void kcf_rnd_init(void);
-extern boolean_t kcf_rngprov_check(void);
-extern int kcf_rnd_get_pseudo_bytes(uint8_t *, size_t);
-extern int kcf_rnd_get_bytes(uint8_t *, size_t, boolean_t, boolean_t);
-extern int random_add_pseudo_entropy(uint8_t *, size_t, uint_t);
-extern void kcf_rnd_schedule_timeout(boolean_t);
-extern int crypto_uio_data(crypto_data_t *, uchar_t *, int, cmd_type_t,
- void *, void (*update)(void));
-extern int crypto_mblk_data(crypto_data_t *, uchar_t *, int, cmd_type_t,
- void *, void (*update)(void));
extern int crypto_put_output_data(uchar_t *, crypto_data_t *, int);
-extern int crypto_get_input_data(crypto_data_t *, uchar_t **, uchar_t *);
-extern int crypto_copy_key_to_ctx(crypto_key_t *, crypto_key_t **, size_t *,
- int kmflag);
-extern int crypto_digest_data(crypto_data_t *, void *, uchar_t *,
- void (*update)(void), void (*final)(void), uchar_t);
extern int crypto_update_iov(void *, crypto_data_t *, crypto_data_t *,
- int (*cipher)(void *, caddr_t, size_t, crypto_data_t *),
- void (*copy_block)(uint8_t *, uint64_t *));
+ int (*cipher)(void *, caddr_t, size_t, crypto_data_t *));
extern int crypto_update_uio(void *, crypto_data_t *, crypto_data_t *,
- int (*cipher)(void *, caddr_t, size_t, crypto_data_t *),
- void (*copy_block)(uint8_t *, uint64_t *));
-extern int crypto_update_mp(void *, crypto_data_t *, crypto_data_t *,
- int (*cipher)(void *, caddr_t, size_t, crypto_data_t *),
- void (*copy_block)(uint8_t *, uint64_t *));
-extern int crypto_get_key_attr(crypto_key_t *, crypto_attr_type_t, uchar_t **,
- ssize_t *);
+ int (*cipher)(void *, caddr_t, size_t, crypto_data_t *));
/* Access to the provider's table */
extern void kcf_prov_tab_destroy(void);
extern void kcf_prov_tab_init(void);
extern int kcf_prov_tab_add_provider(kcf_provider_desc_t *);
extern int kcf_prov_tab_rem_provider(crypto_provider_id_t);
-extern kcf_provider_desc_t *kcf_prov_tab_lookup_by_name(char *);
-extern kcf_provider_desc_t *kcf_prov_tab_lookup_by_dev(char *, uint_t);
-extern int kcf_get_hw_prov_tab(uint_t *, kcf_provider_desc_t ***, int,
- char *, uint_t, boolean_t);
-extern int kcf_get_slot_list(uint_t *, kcf_provider_desc_t ***, boolean_t);
-extern void kcf_free_provider_tab(uint_t, kcf_provider_desc_t **);
extern kcf_provider_desc_t *kcf_prov_tab_lookup(crypto_provider_id_t);
extern int kcf_get_sw_prov(crypto_mech_type_t, kcf_provider_desc_t **,
kcf_mech_entry_t **, boolean_t);
-/* Access to the policy table */
-extern boolean_t is_mech_disabled(kcf_provider_desc_t *, crypto_mech_name_t);
-extern boolean_t is_mech_disabled_byname(crypto_provider_type_t, char *,
- uint_t, crypto_mech_name_t);
-extern void kcf_policy_tab_init(void);
-extern void kcf_policy_free_desc(kcf_policy_desc_t *);
-extern void kcf_policy_remove_by_name(char *, uint_t *, crypto_mech_name_t **);
-extern void kcf_policy_remove_by_dev(char *, uint_t, uint_t *,
- crypto_mech_name_t **);
-extern kcf_policy_desc_t *kcf_policy_lookup_by_name(char *);
-extern kcf_policy_desc_t *kcf_policy_lookup_by_dev(char *, uint_t);
-extern int kcf_policy_load_soft_disabled(char *, uint_t, crypto_mech_name_t *,
- uint_t *, crypto_mech_name_t **);
-extern int kcf_policy_load_dev_disabled(char *, uint_t, uint_t,
- crypto_mech_name_t *, uint_t *, crypto_mech_name_t **);
-extern boolean_t in_soft_config_list(char *);
-
#ifdef __cplusplus
}
diff --git a/sys/contrib/openzfs/module/icp/include/sys/crypto/ops_impl.h b/sys/contrib/openzfs/module/icp/include/sys/crypto/ops_impl.h
deleted file mode 100644
index 230d74b063fc..000000000000
--- a/sys/contrib/openzfs/module/icp/include/sys/crypto/ops_impl.h
+++ /dev/null
@@ -1,630 +0,0 @@
-/*
- * 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 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#ifndef _SYS_CRYPTO_OPS_IMPL_H
-#define _SYS_CRYPTO_OPS_IMPL_H
-
-/*
- * Scheduler internal structures.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <sys/zfs_context.h>
-#include <sys/crypto/api.h>
-#include <sys/crypto/spi.h>
-#include <sys/crypto/impl.h>
-#include <sys/crypto/common.h>
-
-/*
- * The parameters needed for each function group are batched
- * in one structure. This is much simpler than having a
- * separate structure for each function.
- *
- * In some cases, a field is generically named to keep the
- * structure small. The comments indicate these cases.
- */
-typedef struct kcf_digest_ops_params {
- crypto_session_id_t do_sid;
- crypto_mech_type_t do_framework_mechtype;
- crypto_mechanism_t do_mech;
- crypto_data_t *do_data;
- crypto_data_t *do_digest;
- crypto_key_t *do_digest_key; /* Argument for digest_key() */
-} kcf_digest_ops_params_t;
-
-typedef struct kcf_mac_ops_params {
- crypto_session_id_t mo_sid;
- crypto_mech_type_t mo_framework_mechtype;
- crypto_mechanism_t mo_mech;
- crypto_key_t *mo_key;
- crypto_data_t *mo_data;
- crypto_data_t *mo_mac;
- crypto_spi_ctx_template_t mo_templ;
-} kcf_mac_ops_params_t;
-
-typedef struct kcf_encrypt_ops_params {
- crypto_session_id_t eo_sid;
- crypto_mech_type_t eo_framework_mechtype;
- crypto_mechanism_t eo_mech;
- crypto_key_t *eo_key;
- crypto_data_t *eo_plaintext;
- crypto_data_t *eo_ciphertext;
- crypto_spi_ctx_template_t eo_templ;
-} kcf_encrypt_ops_params_t;
-
-typedef struct kcf_decrypt_ops_params {
- crypto_session_id_t dop_sid;
- crypto_mech_type_t dop_framework_mechtype;
- crypto_mechanism_t dop_mech;
- crypto_key_t *dop_key;
- crypto_data_t *dop_ciphertext;
- crypto_data_t *dop_plaintext;
- crypto_spi_ctx_template_t dop_templ;
-} kcf_decrypt_ops_params_t;
-
-typedef struct kcf_sign_ops_params {
- crypto_session_id_t so_sid;
- crypto_mech_type_t so_framework_mechtype;
- crypto_mechanism_t so_mech;
- crypto_key_t *so_key;
- crypto_data_t *so_data;
- crypto_data_t *so_signature;
- crypto_spi_ctx_template_t so_templ;
-} kcf_sign_ops_params_t;
-
-typedef struct kcf_verify_ops_params {
- crypto_session_id_t vo_sid;
- crypto_mech_type_t vo_framework_mechtype;
- crypto_mechanism_t vo_mech;
- crypto_key_t *vo_key;
- crypto_data_t *vo_data;
- crypto_data_t *vo_signature;
- crypto_spi_ctx_template_t vo_templ;
-} kcf_verify_ops_params_t;
-
-typedef struct kcf_encrypt_mac_ops_params {
- crypto_session_id_t em_sid;
- crypto_mech_type_t em_framework_encr_mechtype;
- crypto_mechanism_t em_encr_mech;
- crypto_key_t *em_encr_key;
- crypto_mech_type_t em_framework_mac_mechtype;
- crypto_mechanism_t em_mac_mech;
- crypto_key_t *em_mac_key;
- crypto_data_t *em_plaintext;
- crypto_dual_data_t *em_ciphertext;
- crypto_data_t *em_mac;
- crypto_spi_ctx_template_t em_encr_templ;
- crypto_spi_ctx_template_t em_mac_templ;
-} kcf_encrypt_mac_ops_params_t;
-
-typedef struct kcf_mac_decrypt_ops_params {
- crypto_session_id_t md_sid;
- crypto_mech_type_t md_framework_mac_mechtype;
- crypto_mechanism_t md_mac_mech;
- crypto_key_t *md_mac_key;
- crypto_mech_type_t md_framework_decr_mechtype;
- crypto_mechanism_t md_decr_mech;
- crypto_key_t *md_decr_key;
- crypto_dual_data_t *md_ciphertext;
- crypto_data_t *md_mac;
- crypto_data_t *md_plaintext;
- crypto_spi_ctx_template_t md_mac_templ;
- crypto_spi_ctx_template_t md_decr_templ;
-} kcf_mac_decrypt_ops_params_t;
-
-typedef struct kcf_random_number_ops_params {
- crypto_session_id_t rn_sid;
- uchar_t *rn_buf;
- size_t rn_buflen;
- uint_t rn_entropy_est;
- uint32_t rn_flags;
-} kcf_random_number_ops_params_t;
-
-/*
- * so_pd is useful when the provider descriptor (pd) supplying the
- * provider handle is different from the pd supplying the ops vector.
- * This is the case for session open/close where so_pd can be the pd
- * of a logical provider. The pd supplying the ops vector is passed
- * as an argument to kcf_submit_request().
- */
-typedef struct kcf_session_ops_params {
- crypto_session_id_t *so_sid_ptr;
- crypto_session_id_t so_sid;
- crypto_user_type_t so_user_type;
- char *so_pin;
- size_t so_pin_len;
- kcf_provider_desc_t *so_pd;
-} kcf_session_ops_params_t;
-
-typedef struct kcf_object_ops_params {
- crypto_session_id_t oo_sid;
- crypto_object_id_t oo_object_id;
- crypto_object_attribute_t *oo_template;
- uint_t oo_attribute_count;
- crypto_object_id_t *oo_object_id_ptr;
- size_t *oo_object_size;
- void **oo_find_init_pp_ptr;
- void *oo_find_pp;
- uint_t oo_max_object_count;
- uint_t *oo_object_count_ptr;
-} kcf_object_ops_params_t;
-
-/*
- * ko_key is used to encode wrapping key in key_wrap() and
- * unwrapping key in key_unwrap(). ko_key_template and
- * ko_key_attribute_count are used to encode public template
- * and public template attr count in key_generate_pair().
- * kops->ko_key_object_id_ptr is used to encode public key
- * in key_generate_pair().
- */
-typedef struct kcf_key_ops_params {
- crypto_session_id_t ko_sid;
- crypto_mech_type_t ko_framework_mechtype;
- crypto_mechanism_t ko_mech;
- crypto_object_attribute_t *ko_key_template;
- uint_t ko_key_attribute_count;
- crypto_object_id_t *ko_key_object_id_ptr;
- crypto_object_attribute_t *ko_private_key_template;
- uint_t ko_private_key_attribute_count;
- crypto_object_id_t *ko_private_key_object_id_ptr;
- crypto_key_t *ko_key;
- uchar_t *ko_wrapped_key;
- size_t *ko_wrapped_key_len_ptr;
- crypto_object_attribute_t *ko_out_template1;
- crypto_object_attribute_t *ko_out_template2;
- uint_t ko_out_attribute_count1;
- uint_t ko_out_attribute_count2;
-} kcf_key_ops_params_t;
-
-/*
- * po_pin and po_pin_len are used to encode new_pin and new_pin_len
- * when wrapping set_pin() function parameters.
- *
- * po_pd is useful when the provider descriptor (pd) supplying the
- * provider handle is different from the pd supplying the ops vector.
- * This is true for the ext_info provider entry point where po_pd
- * can be the pd of a logical provider. The pd supplying the ops vector
- * is passed as an argument to kcf_submit_request().
- */
-typedef struct kcf_provmgmt_ops_params {
- crypto_session_id_t po_sid;
- char *po_pin;
- size_t po_pin_len;
- char *po_old_pin;
- size_t po_old_pin_len;
- char *po_label;
- crypto_provider_ext_info_t *po_ext_info;
- kcf_provider_desc_t *po_pd;
-} kcf_provmgmt_ops_params_t;
-
-/*
- * The operation type within a function group.
- */
-typedef enum kcf_op_type {
- /* common ops for all mechanisms */
- KCF_OP_INIT = 1,
- KCF_OP_SINGLE, /* pkcs11 sense. So, INIT is already done */
- KCF_OP_UPDATE,
- KCF_OP_FINAL,
- KCF_OP_ATOMIC,
-
- /* digest_key op */
- KCF_OP_DIGEST_KEY,
-
- /* mac specific op */
- KCF_OP_MAC_VERIFY_ATOMIC,
-
- /* mac/cipher specific op */
- KCF_OP_MAC_VERIFY_DECRYPT_ATOMIC,
-
- /* sign_recover ops */
- KCF_OP_SIGN_RECOVER_INIT,
- KCF_OP_SIGN_RECOVER,
- KCF_OP_SIGN_RECOVER_ATOMIC,
-
- /* verify_recover ops */
- KCF_OP_VERIFY_RECOVER_INIT,
- KCF_OP_VERIFY_RECOVER,
- KCF_OP_VERIFY_RECOVER_ATOMIC,
-
- /* random number ops */
- KCF_OP_RANDOM_SEED,
- KCF_OP_RANDOM_GENERATE,
-
- /* session management ops */
- KCF_OP_SESSION_OPEN,
- KCF_OP_SESSION_CLOSE,
- KCF_OP_SESSION_LOGIN,
- KCF_OP_SESSION_LOGOUT,
-
- /* object management ops */
- KCF_OP_OBJECT_CREATE,
- KCF_OP_OBJECT_COPY,
- KCF_OP_OBJECT_DESTROY,
- KCF_OP_OBJECT_GET_SIZE,
- KCF_OP_OBJECT_GET_ATTRIBUTE_VALUE,
- KCF_OP_OBJECT_SET_ATTRIBUTE_VALUE,
- KCF_OP_OBJECT_FIND_INIT,
- KCF_OP_OBJECT_FIND,
- KCF_OP_OBJECT_FIND_FINAL,
-
- /* key management ops */
- KCF_OP_KEY_GENERATE,
- KCF_OP_KEY_GENERATE_PAIR,
- KCF_OP_KEY_WRAP,
- KCF_OP_KEY_UNWRAP,
- KCF_OP_KEY_DERIVE,
- KCF_OP_KEY_CHECK,
-
- /* provider management ops */
- KCF_OP_MGMT_EXTINFO,
- KCF_OP_MGMT_INITTOKEN,
- KCF_OP_MGMT_INITPIN,
- KCF_OP_MGMT_SETPIN
-} kcf_op_type_t;
-
-/*
- * The operation groups that need wrapping of parameters. This is somewhat
- * similar to the function group type in spi.h except that this also includes
- * all the functions that don't have a mechanism.
- *
- * The wrapper macros should never take these enum values as an argument.
- * Rather, they are assigned in the macro itself since they are known
- * from the macro name.
- */
-typedef enum kcf_op_group {
- KCF_OG_DIGEST = 1,
- KCF_OG_MAC,
- KCF_OG_ENCRYPT,
- KCF_OG_DECRYPT,
- KCF_OG_SIGN,
- KCF_OG_VERIFY,
- KCF_OG_ENCRYPT_MAC,
- KCF_OG_MAC_DECRYPT,
- KCF_OG_RANDOM,
- KCF_OG_SESSION,
- KCF_OG_OBJECT,
- KCF_OG_KEY,
- KCF_OG_PROVMGMT,
- KCF_OG_NOSTORE_KEY
-} kcf_op_group_t;
-
-/*
- * The kcf_op_type_t enum values used here should be only for those
- * operations for which there is a k-api routine in sys/crypto/api.h.
- */
-#define IS_INIT_OP(ftype) ((ftype) == KCF_OP_INIT)
-#define IS_SINGLE_OP(ftype) ((ftype) == KCF_OP_SINGLE)
-#define IS_UPDATE_OP(ftype) ((ftype) == KCF_OP_UPDATE)
-#define IS_FINAL_OP(ftype) ((ftype) == KCF_OP_FINAL)
-#define IS_ATOMIC_OP(ftype) ( \
- (ftype) == KCF_OP_ATOMIC || (ftype) == KCF_OP_MAC_VERIFY_ATOMIC || \
- (ftype) == KCF_OP_MAC_VERIFY_DECRYPT_ATOMIC || \
- (ftype) == KCF_OP_SIGN_RECOVER_ATOMIC || \
- (ftype) == KCF_OP_VERIFY_RECOVER_ATOMIC)
-
-/*
- * Keep the parameters associated with a request around.
- * We need to pass them to the SPI.
- */
-typedef struct kcf_req_params {
- kcf_op_group_t rp_opgrp;
- kcf_op_type_t rp_optype;
-
- union {
- kcf_digest_ops_params_t digest_params;
- kcf_mac_ops_params_t mac_params;
- kcf_encrypt_ops_params_t encrypt_params;
- kcf_decrypt_ops_params_t decrypt_params;
- kcf_sign_ops_params_t sign_params;
- kcf_verify_ops_params_t verify_params;
- kcf_encrypt_mac_ops_params_t encrypt_mac_params;
- kcf_mac_decrypt_ops_params_t mac_decrypt_params;
- kcf_random_number_ops_params_t random_number_params;
- kcf_session_ops_params_t session_params;
- kcf_object_ops_params_t object_params;
- kcf_key_ops_params_t key_params;
- kcf_provmgmt_ops_params_t provmgmt_params;
- } rp_u;
-} kcf_req_params_t;
-
-
-/*
- * The ioctl/k-api code should bundle the parameters into a kcf_req_params_t
- * structure before calling a scheduler routine. The following macros are
- * available for that purpose.
- *
- * For the most part, the macro arguments closely correspond to the
- * function parameters. In some cases, we use generic names. The comments
- * for the structure should indicate these cases.
- */
-#define KCF_WRAP_DIGEST_OPS_PARAMS(req, ftype, _sid, _mech, _key, \
- _data, _digest) { \
- kcf_digest_ops_params_t *dops = &(req)->rp_u.digest_params; \
- crypto_mechanism_t *mechp = _mech; \
- \
- (req)->rp_opgrp = KCF_OG_DIGEST; \
- (req)->rp_optype = ftype; \
- dops->do_sid = _sid; \
- if (mechp != NULL) { \
- dops->do_mech = *mechp; \
- dops->do_framework_mechtype = mechp->cm_type; \
- } \
- dops->do_digest_key = _key; \
- dops->do_data = _data; \
- dops->do_digest = _digest; \
-}
-
-#define KCF_WRAP_MAC_OPS_PARAMS(req, ftype, _sid, _mech, _key, \
- _data, _mac, _templ) { \
- kcf_mac_ops_params_t *mops = &(req)->rp_u.mac_params; \
- crypto_mechanism_t *mechp = _mech; \
- \
- (req)->rp_opgrp = KCF_OG_MAC; \
- (req)->rp_optype = ftype; \
- mops->mo_sid = _sid; \
- if (mechp != NULL) { \
- mops->mo_mech = *mechp; \
- mops->mo_framework_mechtype = mechp->cm_type; \
- } \
- mops->mo_key = _key; \
- mops->mo_data = _data; \
- mops->mo_mac = _mac; \
- mops->mo_templ = _templ; \
-}
-
-#define KCF_WRAP_ENCRYPT_OPS_PARAMS(req, ftype, _sid, _mech, _key, \
- _plaintext, _ciphertext, _templ) { \
- kcf_encrypt_ops_params_t *cops = &(req)->rp_u.encrypt_params; \
- crypto_mechanism_t *mechp = _mech; \
- \
- (req)->rp_opgrp = KCF_OG_ENCRYPT; \
- (req)->rp_optype = ftype; \
- cops->eo_sid = _sid; \
- if (mechp != NULL) { \
- cops->eo_mech = *mechp; \
- cops->eo_framework_mechtype = mechp->cm_type; \
- } \
- cops->eo_key = _key; \
- cops->eo_plaintext = _plaintext; \
- cops->eo_ciphertext = _ciphertext; \
- cops->eo_templ = _templ; \
-}
-
-#define KCF_WRAP_DECRYPT_OPS_PARAMS(req, ftype, _sid, _mech, _key, \
- _ciphertext, _plaintext, _templ) { \
- kcf_decrypt_ops_params_t *cops = &(req)->rp_u.decrypt_params; \
- crypto_mechanism_t *mechp = _mech; \
- \
- (req)->rp_opgrp = KCF_OG_DECRYPT; \
- (req)->rp_optype = ftype; \
- cops->dop_sid = _sid; \
- if (mechp != NULL) { \
- cops->dop_mech = *mechp; \
- cops->dop_framework_mechtype = mechp->cm_type; \
- } \
- cops->dop_key = _key; \
- cops->dop_ciphertext = _ciphertext; \
- cops->dop_plaintext = _plaintext; \
- cops->dop_templ = _templ; \
-}
-
-#define KCF_WRAP_SIGN_OPS_PARAMS(req, ftype, _sid, _mech, _key, \
- _data, _signature, _templ) { \
- kcf_sign_ops_params_t *sops = &(req)->rp_u.sign_params; \
- crypto_mechanism_t *mechp = _mech; \
- \
- (req)->rp_opgrp = KCF_OG_SIGN; \
- (req)->rp_optype = ftype; \
- sops->so_sid = _sid; \
- if (mechp != NULL) { \
- sops->so_mech = *mechp; \
- sops->so_framework_mechtype = mechp->cm_type; \
- } \
- sops->so_key = _key; \
- sops->so_data = _data; \
- sops->so_signature = _signature; \
- sops->so_templ = _templ; \
-}
-
-#define KCF_WRAP_VERIFY_OPS_PARAMS(req, ftype, _sid, _mech, _key, \
- _data, _signature, _templ) { \
- kcf_verify_ops_params_t *vops = &(req)->rp_u.verify_params; \
- crypto_mechanism_t *mechp = _mech; \
- \
- (req)->rp_opgrp = KCF_OG_VERIFY; \
- (req)->rp_optype = ftype; \
- vops->vo_sid = _sid; \
- if (mechp != NULL) { \
- vops->vo_mech = *mechp; \
- vops->vo_framework_mechtype = mechp->cm_type; \
- } \
- vops->vo_key = _key; \
- vops->vo_data = _data; \
- vops->vo_signature = _signature; \
- vops->vo_templ = _templ; \
-}
-
-#define KCF_WRAP_ENCRYPT_MAC_OPS_PARAMS(req, ftype, _sid, _encr_key, \
- _mac_key, _plaintext, _ciphertext, _mac, _encr_templ, _mac_templ) { \
- kcf_encrypt_mac_ops_params_t *cmops = &(req)->rp_u.encrypt_mac_params; \
- \
- (req)->rp_opgrp = KCF_OG_ENCRYPT_MAC; \
- (req)->rp_optype = ftype; \
- cmops->em_sid = _sid; \
- cmops->em_encr_key = _encr_key; \
- cmops->em_mac_key = _mac_key; \
- cmops->em_plaintext = _plaintext; \
- cmops->em_ciphertext = _ciphertext; \
- cmops->em_mac = _mac; \
- cmops->em_encr_templ = _encr_templ; \
- cmops->em_mac_templ = _mac_templ; \
-}
-
-#define KCF_WRAP_MAC_DECRYPT_OPS_PARAMS(req, ftype, _sid, _mac_key, \
- _decr_key, _ciphertext, _mac, _plaintext, _mac_templ, _decr_templ) { \
- kcf_mac_decrypt_ops_params_t *cmops = &(req)->rp_u.mac_decrypt_params; \
- \
- (req)->rp_opgrp = KCF_OG_MAC_DECRYPT; \
- (req)->rp_optype = ftype; \
- cmops->md_sid = _sid; \
- cmops->md_mac_key = _mac_key; \
- cmops->md_decr_key = _decr_key; \
- cmops->md_ciphertext = _ciphertext; \
- cmops->md_mac = _mac; \
- cmops->md_plaintext = _plaintext; \
- cmops->md_mac_templ = _mac_templ; \
- cmops->md_decr_templ = _decr_templ; \
-}
-
-#define KCF_WRAP_RANDOM_OPS_PARAMS(req, ftype, _sid, _buf, _buflen, \
- _est, _flags) { \
- kcf_random_number_ops_params_t *rops = \
- &(req)->rp_u.random_number_params; \
- \
- (req)->rp_opgrp = KCF_OG_RANDOM; \
- (req)->rp_optype = ftype; \
- rops->rn_sid = _sid; \
- rops->rn_buf = _buf; \
- rops->rn_buflen = _buflen; \
- rops->rn_entropy_est = _est; \
- rops->rn_flags = _flags; \
-}
-
-#define KCF_WRAP_SESSION_OPS_PARAMS(req, ftype, _sid_ptr, _sid, \
- _user_type, _pin, _pin_len, _pd) { \
- kcf_session_ops_params_t *sops = &(req)->rp_u.session_params; \
- \
- (req)->rp_opgrp = KCF_OG_SESSION; \
- (req)->rp_optype = ftype; \
- sops->so_sid_ptr = _sid_ptr; \
- sops->so_sid = _sid; \
- sops->so_user_type = _user_type; \
- sops->so_pin = _pin; \
- sops->so_pin_len = _pin_len; \
- sops->so_pd = _pd; \
-}
-
-#define KCF_WRAP_OBJECT_OPS_PARAMS(req, ftype, _sid, _object_id, \
- _template, _attribute_count, _object_id_ptr, _object_size, \
- _find_init_pp_ptr, _find_pp, _max_object_count, _object_count_ptr) { \
- kcf_object_ops_params_t *jops = &(req)->rp_u.object_params; \
- \
- (req)->rp_opgrp = KCF_OG_OBJECT; \
- (req)->rp_optype = ftype; \
- jops->oo_sid = _sid; \
- jops->oo_object_id = _object_id; \
- jops->oo_template = _template; \
- jops->oo_attribute_count = _attribute_count; \
- jops->oo_object_id_ptr = _object_id_ptr; \
- jops->oo_object_size = _object_size; \
- jops->oo_find_init_pp_ptr = _find_init_pp_ptr; \
- jops->oo_find_pp = _find_pp; \
- jops->oo_max_object_count = _max_object_count; \
- jops->oo_object_count_ptr = _object_count_ptr; \
-}
-
-#define KCF_WRAP_KEY_OPS_PARAMS(req, ftype, _sid, _mech, _key_template, \
- _key_attribute_count, _key_object_id_ptr, _private_key_template, \
- _private_key_attribute_count, _private_key_object_id_ptr, \
- _key, _wrapped_key, _wrapped_key_len_ptr) { \
- kcf_key_ops_params_t *kops = &(req)->rp_u.key_params; \
- crypto_mechanism_t *mechp = _mech; \
- \
- (req)->rp_opgrp = KCF_OG_KEY; \
- (req)->rp_optype = ftype; \
- kops->ko_sid = _sid; \
- if (mechp != NULL) { \
- kops->ko_mech = *mechp; \
- kops->ko_framework_mechtype = mechp->cm_type; \
- } \
- kops->ko_key_template = _key_template; \
- kops->ko_key_attribute_count = _key_attribute_count; \
- kops->ko_key_object_id_ptr = _key_object_id_ptr; \
- kops->ko_private_key_template = _private_key_template; \
- kops->ko_private_key_attribute_count = _private_key_attribute_count; \
- kops->ko_private_key_object_id_ptr = _private_key_object_id_ptr; \
- kops->ko_key = _key; \
- kops->ko_wrapped_key = _wrapped_key; \
- kops->ko_wrapped_key_len_ptr = _wrapped_key_len_ptr; \
-}
-
-#define KCF_WRAP_PROVMGMT_OPS_PARAMS(req, ftype, _sid, _old_pin, \
- _old_pin_len, _pin, _pin_len, _label, _ext_info, _pd) { \
- kcf_provmgmt_ops_params_t *pops = &(req)->rp_u.provmgmt_params; \
- \
- (req)->rp_opgrp = KCF_OG_PROVMGMT; \
- (req)->rp_optype = ftype; \
- pops->po_sid = _sid; \
- pops->po_pin = _pin; \
- pops->po_pin_len = _pin_len; \
- pops->po_old_pin = _old_pin; \
- pops->po_old_pin_len = _old_pin_len; \
- pops->po_label = _label; \
- pops->po_ext_info = _ext_info; \
- pops->po_pd = _pd; \
-}
-
-#define KCF_WRAP_NOSTORE_KEY_OPS_PARAMS(req, ftype, _sid, _mech, \
- _key_template, _key_attribute_count, _private_key_template, \
- _private_key_attribute_count, _key, _out_template1, \
- _out_attribute_count1, _out_template2, _out_attribute_count2) { \
- kcf_key_ops_params_t *kops = &(req)->rp_u.key_params; \
- crypto_mechanism_t *mechp = _mech; \
- \
- (req)->rp_opgrp = KCF_OG_NOSTORE_KEY; \
- (req)->rp_optype = ftype; \
- kops->ko_sid = _sid; \
- if (mechp != NULL) { \
- kops->ko_mech = *mechp; \
- kops->ko_framework_mechtype = mechp->cm_type; \
- } \
- kops->ko_key_template = _key_template; \
- kops->ko_key_attribute_count = _key_attribute_count; \
- kops->ko_key_object_id_ptr = NULL; \
- kops->ko_private_key_template = _private_key_template; \
- kops->ko_private_key_attribute_count = _private_key_attribute_count; \
- kops->ko_private_key_object_id_ptr = NULL; \
- kops->ko_key = _key; \
- kops->ko_wrapped_key = NULL; \
- kops->ko_wrapped_key_len_ptr = 0; \
- kops->ko_out_template1 = _out_template1; \
- kops->ko_out_template2 = _out_template2; \
- kops->ko_out_attribute_count1 = _out_attribute_count1; \
- kops->ko_out_attribute_count2 = _out_attribute_count2; \
-}
-
-#define KCF_SET_PROVIDER_MECHNUM(fmtype, pd, mechp) \
- (mechp)->cm_type = \
- KCF_TO_PROV_MECHNUM(pd, fmtype);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _SYS_CRYPTO_OPS_IMPL_H */
diff --git a/sys/contrib/openzfs/module/icp/include/sys/crypto/sched_impl.h b/sys/contrib/openzfs/module/icp/include/sys/crypto/sched_impl.h
index 29ef8021f0fc..1de4bd8b94f4 100644
--- a/sys/contrib/openzfs/module/icp/include/sys/crypto/sched_impl.h
+++ b/sys/contrib/openzfs/module/icp/include/sys/crypto/sched_impl.h
@@ -39,60 +39,6 @@ extern "C" {
#include <sys/crypto/spi.h>
#include <sys/crypto/impl.h>
#include <sys/crypto/common.h>
-#include <sys/crypto/ops_impl.h>
-
-typedef void (kcf_func_t)(void *, int);
-
-typedef enum kcf_req_status {
- REQ_ALLOCATED = 1,
- REQ_WAITING, /* At the framework level */
- REQ_INPROGRESS, /* At the provider level */
- REQ_DONE,
- REQ_CANCELED
-} kcf_req_status_t;
-
-typedef enum kcf_call_type {
- CRYPTO_SYNCH = 1,
- CRYPTO_ASYNCH
-} kcf_call_type_t;
-
-#define CHECK_RESTRICT(crq) (crq != NULL && \
- ((crq)->cr_flag & CRYPTO_RESTRICTED))
-
-#define CHECK_RESTRICT_FALSE B_FALSE
-
-#define CHECK_FASTPATH(crq, pd) ((crq) == NULL || \
- !((crq)->cr_flag & CRYPTO_ALWAYS_QUEUE)) && \
- (pd)->pd_prov_type == CRYPTO_SW_PROVIDER
-
-#define KCF_KMFLAG(crq) (((crq) == NULL) ? KM_SLEEP : KM_NOSLEEP)
-
-/*
- * The framework keeps an internal handle to use in the adaptive
- * asynchronous case. This is the case when a client has the
- * CRYPTO_ALWAYS_QUEUE bit clear and a software provider is used for
- * the request. The request is completed in the context of the calling
- * thread and kernel memory must be allocated with KM_NOSLEEP.
- *
- * The framework passes a pointer to the handle in crypto_req_handle_t
- * argument when it calls the SPI of the software provider. The macros
- * KCF_RHNDL() and KCF_SWFP_RHNDL() are used to do this.
- *
- * When a provider asks the framework for kmflag value via
- * crypto_kmflag(9S) we use REQHNDL2_KMFLAG() macro.
- */
-extern ulong_t kcf_swprov_hndl;
-#define KCF_RHNDL(kmflag) (((kmflag) == KM_SLEEP) ? NULL : &kcf_swprov_hndl)
-#define KCF_SWFP_RHNDL(crq) (((crq) == NULL) ? NULL : &kcf_swprov_hndl)
-#define REQHNDL2_KMFLAG(rhndl) \
- ((rhndl == &kcf_swprov_hndl) ? KM_NOSLEEP : KM_SLEEP)
-
-/* Internal call_req flags. They start after the public ones in api.h */
-
-#define CRYPTO_SETDUAL 0x00001000 /* Set the 'cont' boolean before */
- /* submitting the request */
-#define KCF_ISDUALREQ(crq) \
- (((crq) == NULL) ? B_FALSE : (crq->cr_flag & CRYPTO_SETDUAL))
typedef struct kcf_prov_tried {
kcf_provider_desc_t *pt_pd;
@@ -106,178 +52,8 @@ typedef struct kcf_prov_tried {
(tlist != NULL && is_in_triedlist(pd, tlist))
#define IS_RECOVERABLE(error) \
- (error == CRYPTO_BUFFER_TOO_BIG || \
- error == CRYPTO_BUSY || \
- error == CRYPTO_DEVICE_ERROR || \
- error == CRYPTO_DEVICE_MEMORY || \
- error == CRYPTO_KEY_SIZE_RANGE || \
- error == CRYPTO_NO_PERMISSION)
-
-#define KCF_ATOMIC_INCR(x) atomic_add_32(&(x), 1)
-#define KCF_ATOMIC_DECR(x) atomic_add_32(&(x), -1)
-
-/*
- * Node structure for synchronous requests.
- */
-typedef struct kcf_sreq_node {
- /* Should always be the first field in this structure */
- kcf_call_type_t sn_type;
- /*
- * sn_cv and sr_lock are used to wait for the
- * operation to complete. sn_lock also protects
- * the sn_state field.
- */
- kcondvar_t sn_cv;
- kmutex_t sn_lock;
- kcf_req_status_t sn_state;
-
- /*
- * Return value from the operation. This will be
- * one of the CRYPTO_* errors defined in common.h.
- */
- int sn_rv;
-
- /*
- * parameters to call the SPI with. This can be
- * a pointer as we know the caller context/stack stays.
- */
- struct kcf_req_params *sn_params;
-
- /* Internal context for this request */
- struct kcf_context *sn_context;
-
- /* Provider handling this request */
- kcf_provider_desc_t *sn_provider;
-} kcf_sreq_node_t;
-
-/*
- * Node structure for asynchronous requests. A node can be on
- * on a chain of requests hanging of the internal context
- * structure and can be in the global software provider queue.
- */
-typedef struct kcf_areq_node {
- /* Should always be the first field in this structure */
- kcf_call_type_t an_type;
-
- /* an_lock protects the field an_state */
- kmutex_t an_lock;
- kcf_req_status_t an_state;
- crypto_call_req_t an_reqarg;
-
- /*
- * parameters to call the SPI with. We need to
- * save the params since the caller stack can go away.
- */
- struct kcf_req_params an_params;
-
- /*
- * The next two fields should be NULL for operations that
- * don't need a context.
- */
- /* Internal context for this request */
- struct kcf_context *an_context;
-
- /* next in chain of requests for context */
- struct kcf_areq_node *an_ctxchain_next;
-
- kcondvar_t an_turn_cv;
- boolean_t an_is_my_turn;
- boolean_t an_isdual; /* for internal reuse */
-
- /*
- * Next and previous nodes in the global software
- * queue. These fields are NULL for a hardware
- * provider since we use a taskq there.
- */
- struct kcf_areq_node *an_next;
- struct kcf_areq_node *an_prev;
-
- /* Provider handling this request */
- kcf_provider_desc_t *an_provider;
- kcf_prov_tried_t *an_tried_plist;
-
- struct kcf_areq_node *an_idnext; /* Next in ID hash */
- struct kcf_areq_node *an_idprev; /* Prev in ID hash */
- kcondvar_t an_done; /* Signal request completion */
- uint_t an_refcnt;
-} kcf_areq_node_t;
-
-#define KCF_AREQ_REFHOLD(areq) { \
- atomic_add_32(&(areq)->an_refcnt, 1); \
- ASSERT((areq)->an_refcnt != 0); \
-}
-
-#define KCF_AREQ_REFRELE(areq) { \
- ASSERT((areq)->an_refcnt != 0); \
- membar_exit(); \
- if (atomic_add_32_nv(&(areq)->an_refcnt, -1) == 0) \
- kcf_free_req(areq); \
-}
-
-#define GET_REQ_TYPE(arg) *((kcf_call_type_t *)(arg))
-
-#define NOTIFY_CLIENT(areq, err) (*(areq)->an_reqarg.cr_callback_func)(\
- (areq)->an_reqarg.cr_callback_arg, err);
-
-/* For internally generated call requests for dual operations */
-typedef struct kcf_call_req {
- crypto_call_req_t kr_callreq; /* external client call req */
- kcf_req_params_t kr_params; /* Params saved for next call */
- kcf_areq_node_t *kr_areq; /* Use this areq */
- off_t kr_saveoffset;
- size_t kr_savelen;
-} kcf_dual_req_t;
-
-/*
- * The following are some what similar to macros in callo.h, which implement
- * callout tables.
- *
- * The lower four bits of the ID are used to encode the table ID to
- * index in to. The REQID_COUNTER_HIGH bit is used to avoid any check for
- * wrap around when generating ID. We assume that there won't be a request
- * which takes more time than 2^^(sizeof (long) - 5) other requests submitted
- * after it. This ensures there won't be any ID collision.
- */
-#define REQID_COUNTER_HIGH (1UL << (8 * sizeof (long) - 1))
-#define REQID_COUNTER_SHIFT 4
-#define REQID_COUNTER_LOW (1 << REQID_COUNTER_SHIFT)
-#define REQID_TABLES 16
-#define REQID_TABLE_MASK (REQID_TABLES - 1)
-
-#define REQID_BUCKETS 512
-#define REQID_BUCKET_MASK (REQID_BUCKETS - 1)
-#define REQID_HASH(id) (((id) >> REQID_COUNTER_SHIFT) & REQID_BUCKET_MASK)
-
-#define GET_REQID(areq) (areq)->an_reqarg.cr_reqid
-#define SET_REQID(areq, val) GET_REQID(areq) = val
-
-/*
- * Hash table for async requests.
- */
-typedef struct kcf_reqid_table {
- kmutex_t rt_lock;
- crypto_req_id_t rt_curid;
- kcf_areq_node_t *rt_idhash[REQID_BUCKETS];
-} kcf_reqid_table_t;
-
-/*
- * Global software provider queue structure. Requests to be
- * handled by a SW provider and have the ALWAYS_QUEUE flag set
- * get queued here.
- */
-typedef struct kcf_global_swq {
- /*
- * gs_cv and gs_lock are used to wait for new requests.
- * gs_lock protects the changes to the queue.
- */
- kcondvar_t gs_cv;
- kmutex_t gs_lock;
- uint_t gs_njobs;
- uint_t gs_maxjobs;
- kcf_areq_node_t *gs_first;
- kcf_areq_node_t *gs_last;
-} kcf_global_swq_t;
-
+ (error == CRYPTO_BUSY || \
+ error == CRYPTO_KEY_SIZE_RANGE)
/*
* Internal representation of a canonical context. We contain crypto_ctx_t
@@ -287,31 +63,11 @@ typedef struct kcf_global_swq {
typedef struct kcf_context {
crypto_ctx_t kc_glbl_ctx;
uint_t kc_refcnt;
- kmutex_t kc_in_use_lock;
- /*
- * kc_req_chain_first and kc_req_chain_last are used to chain
- * multiple async requests using the same context. They should be
- * NULL for sync requests.
- */
- kcf_areq_node_t *kc_req_chain_first;
- kcf_areq_node_t *kc_req_chain_last;
kcf_provider_desc_t *kc_prov_desc; /* Prov. descriptor */
kcf_provider_desc_t *kc_sw_prov_desc; /* Prov. descriptor */
- kcf_mech_entry_t *kc_mech;
- struct kcf_context *kc_secondctx; /* for dual contexts */
} kcf_context_t;
/*
- * Bump up the reference count on the framework private context. A
- * global context or a request that references this structure should
- * do a hold.
- */
-#define KCF_CONTEXT_REFHOLD(ictx) { \
- atomic_add_32(&(ictx)->kc_refcnt, 1); \
- ASSERT((ictx)->kc_refcnt != 0); \
-}
-
-/*
* Decrement the reference count on the framework private context.
* When the last reference is released, the framework private
* context structure is freed along with the global context.
@@ -324,10 +80,9 @@ typedef struct kcf_context {
}
/*
- * Check if we can release the context now. In case of CRYPTO_QUEUED
- * we do not release it as we can do it only after the provider notified
- * us. In case of CRYPTO_BUSY, the client can retry the request using
- * the context, so we do not release the context.
+ * Check if we can release the context now. In case of CRYPTO_BUSY,
+ * the client can retry the request using the context,
+ * so we do not release the context.
*
* This macro should be called only from the final routine in
* an init/update/final sequence. We do not release the context in case
@@ -345,182 +100,33 @@ typedef struct kcf_context {
* This macro determines whether we're done with a context.
*/
#define KCF_CONTEXT_DONE(rv) \
- ((rv) != CRYPTO_QUEUED && (rv) != CRYPTO_BUSY && \
- (rv) != CRYPTO_BUFFER_TOO_SMALL)
+ ((rv) != CRYPTO_BUSY && (rv) != CRYPTO_BUFFER_TOO_SMALL)
+
+
+#define KCF_SET_PROVIDER_MECHNUM(fmtype, pd, mechp) \
+ (mechp)->cm_type = \
+ KCF_TO_PROV_MECHNUM(pd, fmtype);
/*
* A crypto_ctx_template_t is internally a pointer to this struct
*/
typedef struct kcf_ctx_template {
- crypto_kcf_provider_handle_t ct_prov_handle; /* provider handle */
- uint_t ct_generation; /* generation # */
size_t ct_size; /* for freeing */
crypto_spi_ctx_template_t ct_prov_tmpl; /* context template */
- /* from the SW prov */
+ /* from the provider */
} kcf_ctx_template_t;
-/*
- * Structure for pool of threads working on global software queue.
- */
-typedef struct kcf_pool {
- uint32_t kp_threads; /* Number of threads in pool */
- uint32_t kp_idlethreads; /* Idle threads in pool */
- uint32_t kp_blockedthreads; /* Blocked threads in pool */
-
- /*
- * cv & lock to monitor the condition when no threads
- * are around. In this case the failover thread kicks in.
- */
- kcondvar_t kp_nothr_cv;
- kmutex_t kp_thread_lock;
-
- /* Userspace thread creator variables. */
- boolean_t kp_signal_create_thread; /* Create requested flag */
- int kp_nthrs; /* # of threads to create */
- boolean_t kp_user_waiting; /* Thread waiting for work */
-
- /*
- * cv & lock for the condition where more threads need to be
- * created. kp_user_lock also protects the three fields above.
- */
- kcondvar_t kp_user_cv; /* Creator cond. variable */
- kmutex_t kp_user_lock; /* Creator lock */
-} kcf_pool_t;
-
-
-/*
- * State of a crypto bufcall element.
- */
-typedef enum cbuf_state {
- CBUF_FREE = 1,
- CBUF_WAITING,
- CBUF_RUNNING
-} cbuf_state_t;
-
-/*
- * Structure of a crypto bufcall element.
- */
-typedef struct kcf_cbuf_elem {
- /*
- * lock and cv to wait for CBUF_RUNNING to be done
- * kc_lock also protects kc_state.
- */
- kmutex_t kc_lock;
- kcondvar_t kc_cv;
- cbuf_state_t kc_state;
-
- struct kcf_cbuf_elem *kc_next;
- struct kcf_cbuf_elem *kc_prev;
-
- void (*kc_func)(void *arg);
- void *kc_arg;
-} kcf_cbuf_elem_t;
-
-/*
- * State of a notify element.
- */
-typedef enum ntfy_elem_state {
- NTFY_WAITING = 1,
- NTFY_RUNNING
-} ntfy_elem_state_t;
-
-/*
- * Structure of a notify list element.
- */
-typedef struct kcf_ntfy_elem {
- /*
- * lock and cv to wait for NTFY_RUNNING to be done.
- * kn_lock also protects kn_state.
- */
- kmutex_t kn_lock;
- kcondvar_t kn_cv;
- ntfy_elem_state_t kn_state;
-
- struct kcf_ntfy_elem *kn_next;
- struct kcf_ntfy_elem *kn_prev;
-
- crypto_notify_callback_t kn_func;
- uint32_t kn_event_mask;
-} kcf_ntfy_elem_t;
-
-
-/*
- * The following values are based on the assumption that it would
- * take around eight cpus to load a hardware provider (This is true for
- * at least one product) and a kernel client may come from different
- * low-priority interrupt levels. We will have CRYPTO_TASKQ_MIN number
- * of cached taskq entries. The CRYPTO_TASKQ_MAX number is based on
- * a throughput of 1GB/s using 512-byte buffers. These are just
- * reasonable estimates and might need to change in future.
- */
-#define CRYPTO_TASKQ_THREADS 8
-#define CRYPTO_TASKQ_MIN 64
-#define CRYPTO_TASKQ_MAX 2 * 1024 * 1024
-
-extern const int crypto_taskq_threads;
-extern const int crypto_taskq_minalloc;
-extern const int crypto_taskq_maxalloc;
-
-/*
- * All pending crypto bufcalls are put on a list. cbuf_list_lock
- * protects changes to this list.
- */
-extern kmutex_t cbuf_list_lock;
-extern kcondvar_t cbuf_list_cv;
-/*
- * All event subscribers are put on a list. kcf_notify_list_lock
- * protects changes to this list.
- */
-extern kmutex_t ntfy_list_lock;
-extern kcondvar_t ntfy_list_cv;
-
-boolean_t kcf_get_next_logical_provider_member(kcf_provider_desc_t *,
- kcf_provider_desc_t *, kcf_provider_desc_t **);
-extern int kcf_get_hardware_provider(crypto_mech_type_t, crypto_mech_type_t,
- boolean_t, kcf_provider_desc_t *, kcf_provider_desc_t **,
- crypto_func_group_t);
-extern int kcf_get_hardware_provider_nomech(offset_t, offset_t,
- boolean_t, kcf_provider_desc_t *, kcf_provider_desc_t **);
extern void kcf_free_triedlist(kcf_prov_tried_t *);
extern kcf_prov_tried_t *kcf_insert_triedlist(kcf_prov_tried_t **,
kcf_provider_desc_t *, int);
extern kcf_provider_desc_t *kcf_get_mech_provider(crypto_mech_type_t,
- kcf_mech_entry_t **, int *, kcf_prov_tried_t *, crypto_func_group_t,
- boolean_t, size_t);
-extern kcf_provider_desc_t *kcf_get_dual_provider(crypto_mechanism_t *,
- crypto_mechanism_t *, kcf_mech_entry_t **, crypto_mech_type_t *,
- crypto_mech_type_t *, int *, kcf_prov_tried_t *,
- crypto_func_group_t, crypto_func_group_t, boolean_t, size_t);
-extern crypto_ctx_t *kcf_new_ctx(crypto_call_req_t *, kcf_provider_desc_t *,
- crypto_session_id_t);
-extern int kcf_submit_request(kcf_provider_desc_t *, crypto_ctx_t *,
- crypto_call_req_t *, kcf_req_params_t *, boolean_t);
+ kcf_mech_entry_t **, int *, kcf_prov_tried_t *, crypto_func_group_t);
+extern crypto_ctx_t *kcf_new_ctx(kcf_provider_desc_t *);
extern void kcf_sched_destroy(void);
extern void kcf_sched_init(void);
-extern void kcf_sched_start(void);
-extern void kcf_sop_done(kcf_sreq_node_t *, int);
-extern void kcf_aop_done(kcf_areq_node_t *, int);
-extern int common_submit_request(kcf_provider_desc_t *,
- crypto_ctx_t *, kcf_req_params_t *, crypto_req_handle_t);
extern void kcf_free_context(kcf_context_t *);
-extern int kcf_svc_wait(int *);
-extern int kcf_svc_do_run(void);
-extern int kcf_need_signature_verification(kcf_provider_desc_t *);
-extern void kcf_verify_signature(void *);
-extern struct modctl *kcf_get_modctl(crypto_provider_info_t *);
-extern void verify_unverified_providers(void);
-extern void kcf_free_req(kcf_areq_node_t *areq);
-extern void crypto_bufcall_service(void);
-
-extern void kcf_walk_ntfylist(uint32_t, void *);
-extern void kcf_do_notify(kcf_provider_desc_t *, boolean_t);
-
-extern kcf_dual_req_t *kcf_alloc_req(crypto_call_req_t *);
-extern void kcf_next_req(void *, int);
-extern void kcf_last_req(void *, int);
-
#ifdef __cplusplus
}
#endif
diff --git a/sys/contrib/openzfs/module/icp/include/sys/crypto/spi.h b/sys/contrib/openzfs/module/icp/include/sys/crypto/spi.h
index 0f1b455c808e..ef525265747e 100644
--- a/sys/contrib/openzfs/module/icp/include/sys/crypto/spi.h
+++ b/sys/contrib/openzfs/module/icp/include/sys/crypto/spi.h
@@ -43,39 +43,15 @@ extern "C" {
#define __no_const
#endif /* CONSTIFY_PLUGIN */
-#define CRYPTO_SPI_VERSION_1 1
-#define CRYPTO_SPI_VERSION_2 2
-#define CRYPTO_SPI_VERSION_3 3
-
-/*
- * Provider-private handle. This handle is specified by a provider
- * when it registers by means of the pi_provider_handle field of
- * the crypto_provider_info structure, and passed to the provider
- * when its entry points are invoked.
- */
-typedef void *crypto_provider_handle_t;
-
/*
- * Context templates can be used to by software providers to pre-process
+ * Context templates can be used to by providers to pre-process
* keying material, such as key schedules. They are allocated by
- * a software provider create_ctx_template(9E) entry point, and passed
+ * a provider create_ctx_template(9E) entry point, and passed
* as argument to initialization and atomic provider entry points.
*/
typedef void *crypto_spi_ctx_template_t;
/*
- * Request handles are used by the kernel to identify an asynchronous
- * request being processed by a provider. It is passed by the kernel
- * to a hardware provider when submitting a request, and must be
- * specified by a provider when calling crypto_op_notification(9F)
- */
-typedef void *crypto_req_handle_t;
-
-/* Values for cc_flags field */
-#define CRYPTO_INIT_OPSTATE 0x00000001 /* allocate and init cc_opstate */
-#define CRYPTO_USE_OPSTATE 0x00000002 /* .. start using it as context */
-
-/*
* The context structure is passed from the kernel to a provider.
* It contains the information needed to process a multi-part or
* single part operation. The context structure is not used
@@ -86,81 +62,24 @@ typedef void *crypto_req_handle_t;
* as separate arguments to Provider routines.
*/
typedef struct crypto_ctx {
- crypto_provider_handle_t cc_provider;
- crypto_session_id_t cc_session;
void *cc_provider_private; /* owned by provider */
void *cc_framework_private; /* owned by framework */
- uint32_t cc_flags; /* flags */
- void *cc_opstate; /* state */
} crypto_ctx_t;
/*
- * Extended provider information.
- */
-
-/*
- * valid values for ei_flags field of extended info structure
- * They match the RSA Security, Inc PKCS#11 tokenInfo flags.
- */
-#define CRYPTO_EXTF_RNG 0x00000001
-#define CRYPTO_EXTF_WRITE_PROTECTED 0x00000002
-#define CRYPTO_EXTF_LOGIN_REQUIRED 0x00000004
-#define CRYPTO_EXTF_USER_PIN_INITIALIZED 0x00000008
-#define CRYPTO_EXTF_CLOCK_ON_TOKEN 0x00000040
-#define CRYPTO_EXTF_PROTECTED_AUTHENTICATION_PATH 0x00000100
-#define CRYPTO_EXTF_DUAL_CRYPTO_OPERATIONS 0x00000200
-#define CRYPTO_EXTF_TOKEN_INITIALIZED 0x00000400
-#define CRYPTO_EXTF_USER_PIN_COUNT_LOW 0x00010000
-#define CRYPTO_EXTF_USER_PIN_FINAL_TRY 0x00020000
-#define CRYPTO_EXTF_USER_PIN_LOCKED 0x00040000
-#define CRYPTO_EXTF_USER_PIN_TO_BE_CHANGED 0x00080000
-#define CRYPTO_EXTF_SO_PIN_COUNT_LOW 0x00100000
-#define CRYPTO_EXTF_SO_PIN_FINAL_TRY 0x00200000
-#define CRYPTO_EXTF_SO_PIN_LOCKED 0x00400000
-#define CRYPTO_EXTF_SO_PIN_TO_BE_CHANGED 0x00800000
-
-/*
- * The crypto_control_ops structure contains pointers to control
- * operations for cryptographic providers. It is passed through
- * the crypto_ops(9S) structure when providers register with the
- * kernel using crypto_register_provider(9F).
- */
-typedef struct crypto_control_ops {
- void (*provider_status)(crypto_provider_handle_t, uint_t *);
-} __no_const crypto_control_ops_t;
-
-/*
- * The crypto_ctx_ops structure contains points to context and context
- * templates management operations for cryptographic providers. It is
- * passed through the crypto_ops(9S) structure when providers register
- * with the kernel using crypto_register_provider(9F).
- */
-typedef struct crypto_ctx_ops {
- int (*create_ctx_template)(crypto_provider_handle_t,
- crypto_mechanism_t *, crypto_key_t *,
- crypto_spi_ctx_template_t *, size_t *, crypto_req_handle_t);
- int (*free_context)(crypto_ctx_t *);
-} __no_const crypto_ctx_ops_t;
-
-/*
* The crypto_digest_ops structure contains pointers to digest
* operations for cryptographic providers. It is passed through
* the crypto_ops(9S) structure when providers register with the
* kernel using crypto_register_provider(9F).
*/
typedef struct crypto_digest_ops {
- int (*digest_init)(crypto_ctx_t *, crypto_mechanism_t *,
- crypto_req_handle_t);
- int (*digest)(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
- crypto_req_handle_t);
- int (*digest_update)(crypto_ctx_t *, crypto_data_t *,
- crypto_req_handle_t);
- int (*digest_key)(crypto_ctx_t *, crypto_key_t *, crypto_req_handle_t);
- int (*digest_final)(crypto_ctx_t *, crypto_data_t *,
- crypto_req_handle_t);
- int (*digest_atomic)(crypto_provider_handle_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_data_t *,
- crypto_data_t *, crypto_req_handle_t);
+ int (*digest_init)(crypto_ctx_t *, crypto_mechanism_t *);
+ int (*digest)(crypto_ctx_t *, crypto_data_t *, crypto_data_t *);
+ int (*digest_update)(crypto_ctx_t *, crypto_data_t *);
+ int (*digest_key)(crypto_ctx_t *, crypto_key_t *);
+ int (*digest_final)(crypto_ctx_t *, crypto_data_t *);
+ int (*digest_atomic)(crypto_mechanism_t *, crypto_data_t *,
+ crypto_data_t *);
} __no_const crypto_digest_ops_t;
/*
@@ -172,29 +91,27 @@ typedef struct crypto_digest_ops {
typedef struct crypto_cipher_ops {
int (*encrypt_init)(crypto_ctx_t *,
crypto_mechanism_t *, crypto_key_t *,
- crypto_spi_ctx_template_t, crypto_req_handle_t);
+ crypto_spi_ctx_template_t);
int (*encrypt)(crypto_ctx_t *,
- crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
+ crypto_data_t *, crypto_data_t *);
int (*encrypt_update)(crypto_ctx_t *,
- crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
+ crypto_data_t *, crypto_data_t *);
int (*encrypt_final)(crypto_ctx_t *,
- crypto_data_t *, crypto_req_handle_t);
- int (*encrypt_atomic)(crypto_provider_handle_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
- crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
+ crypto_data_t *);
+ int (*encrypt_atomic)(crypto_mechanism_t *, crypto_key_t *,
+ crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t);
int (*decrypt_init)(crypto_ctx_t *,
crypto_mechanism_t *, crypto_key_t *,
- crypto_spi_ctx_template_t, crypto_req_handle_t);
+ crypto_spi_ctx_template_t);
int (*decrypt)(crypto_ctx_t *,
- crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
+ crypto_data_t *, crypto_data_t *);
int (*decrypt_update)(crypto_ctx_t *,
- crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
+ crypto_data_t *, crypto_data_t *);
int (*decrypt_final)(crypto_ctx_t *,
- crypto_data_t *, crypto_req_handle_t);
- int (*decrypt_atomic)(crypto_provider_handle_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
- crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
+ crypto_data_t *);
+ int (*decrypt_atomic)(crypto_mechanism_t *, crypto_key_t *,
+ crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t);
} __no_const crypto_cipher_ops_t;
/*
@@ -206,289 +123,30 @@ typedef struct crypto_cipher_ops {
typedef struct crypto_mac_ops {
int (*mac_init)(crypto_ctx_t *,
crypto_mechanism_t *, crypto_key_t *,
- crypto_spi_ctx_template_t, crypto_req_handle_t);
+ crypto_spi_ctx_template_t);
int (*mac)(crypto_ctx_t *,
- crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
+ crypto_data_t *, crypto_data_t *);
int (*mac_update)(crypto_ctx_t *,
- crypto_data_t *, crypto_req_handle_t);
+ crypto_data_t *);
int (*mac_final)(crypto_ctx_t *,
- crypto_data_t *, crypto_req_handle_t);
- int (*mac_atomic)(crypto_provider_handle_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
- crypto_data_t *, crypto_spi_ctx_template_t,
- crypto_req_handle_t);
- int (*mac_verify_atomic)(crypto_provider_handle_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
- crypto_data_t *, crypto_spi_ctx_template_t,
- crypto_req_handle_t);
+ crypto_data_t *);
+ int (*mac_atomic)(crypto_mechanism_t *, crypto_key_t *,
+ crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t);
+ int (*mac_verify_atomic)(crypto_mechanism_t *, crypto_key_t *,
+ crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t);
} __no_const crypto_mac_ops_t;
/*
- * The crypto_sign_ops structure contains pointers to signing
- * operations for cryptographic providers. It is passed through
- * the crypto_ops(9S) structure when providers register with the
- * kernel using crypto_register_provider(9F).
- */
-typedef struct crypto_sign_ops {
- int (*sign_init)(crypto_ctx_t *,
- crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t,
- crypto_req_handle_t);
- int (*sign)(crypto_ctx_t *,
- crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
- int (*sign_update)(crypto_ctx_t *,
- crypto_data_t *, crypto_req_handle_t);
- int (*sign_final)(crypto_ctx_t *,
- crypto_data_t *, crypto_req_handle_t);
- int (*sign_atomic)(crypto_provider_handle_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
- crypto_data_t *, crypto_spi_ctx_template_t,
- crypto_req_handle_t);
- int (*sign_recover_init)(crypto_ctx_t *, crypto_mechanism_t *,
- crypto_key_t *, crypto_spi_ctx_template_t,
- crypto_req_handle_t);
- int (*sign_recover)(crypto_ctx_t *,
- crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
- int (*sign_recover_atomic)(crypto_provider_handle_t,
- crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *,
- crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t,
- crypto_req_handle_t);
-} __no_const crypto_sign_ops_t;
-
-/*
- * The crypto_verify_ops structure contains pointers to verify
- * operations for cryptographic providers. It is passed through
- * the crypto_ops(9S) structure when providers register with the
- * kernel using crypto_register_provider(9F).
- */
-typedef struct crypto_verify_ops {
- int (*verify_init)(crypto_ctx_t *,
- crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t,
- crypto_req_handle_t);
- int (*do_verify)(crypto_ctx_t *,
- crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
- int (*verify_update)(crypto_ctx_t *,
- crypto_data_t *, crypto_req_handle_t);
- int (*verify_final)(crypto_ctx_t *,
- crypto_data_t *, crypto_req_handle_t);
- int (*verify_atomic)(crypto_provider_handle_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
- crypto_data_t *, crypto_spi_ctx_template_t,
- crypto_req_handle_t);
- int (*verify_recover_init)(crypto_ctx_t *, crypto_mechanism_t *,
- crypto_key_t *, crypto_spi_ctx_template_t,
- crypto_req_handle_t);
- int (*verify_recover)(crypto_ctx_t *,
- crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
- int (*verify_recover_atomic)(crypto_provider_handle_t,
- crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *,
- crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t,
- crypto_req_handle_t);
-} __no_const crypto_verify_ops_t;
-
-/*
- * The crypto_dual_ops structure contains pointers to dual
- * cipher and sign/verify operations for cryptographic providers.
- * It is passed through the crypto_ops(9S) structure when
- * providers register with the kernel using
- * crypto_register_provider(9F).
- */
-typedef struct crypto_dual_ops {
- int (*digest_encrypt_update)(
- crypto_ctx_t *, crypto_ctx_t *, crypto_data_t *,
- crypto_data_t *, crypto_req_handle_t);
- int (*decrypt_digest_update)(
- crypto_ctx_t *, crypto_ctx_t *, crypto_data_t *,
- crypto_data_t *, crypto_req_handle_t);
- int (*sign_encrypt_update)(
- crypto_ctx_t *, crypto_ctx_t *, crypto_data_t *,
- crypto_data_t *, crypto_req_handle_t);
- int (*decrypt_verify_update)(
- crypto_ctx_t *, crypto_ctx_t *, crypto_data_t *,
- crypto_data_t *, crypto_req_handle_t);
-} __no_const crypto_dual_ops_t;
-
-/*
- * The crypto_dual_cipher_mac_ops structure contains pointers to dual
- * cipher and MAC operations for cryptographic providers.
- * It is passed through the crypto_ops(9S) structure when
- * providers register with the kernel using
- * crypto_register_provider(9F).
- */
-typedef struct crypto_dual_cipher_mac_ops {
- int (*encrypt_mac_init)(crypto_ctx_t *,
- crypto_mechanism_t *, crypto_key_t *, crypto_mechanism_t *,
- crypto_key_t *, crypto_spi_ctx_template_t,
- crypto_spi_ctx_template_t, crypto_req_handle_t);
- int (*encrypt_mac)(crypto_ctx_t *,
- crypto_data_t *, crypto_dual_data_t *, crypto_data_t *,
- crypto_req_handle_t);
- int (*encrypt_mac_update)(crypto_ctx_t *,
- crypto_data_t *, crypto_dual_data_t *, crypto_req_handle_t);
- int (*encrypt_mac_final)(crypto_ctx_t *,
- crypto_dual_data_t *, crypto_data_t *, crypto_req_handle_t);
- int (*encrypt_mac_atomic)(crypto_provider_handle_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_key_t *, crypto_mechanism_t *,
- crypto_key_t *, crypto_data_t *, crypto_dual_data_t *,
- crypto_data_t *, crypto_spi_ctx_template_t,
- crypto_spi_ctx_template_t, crypto_req_handle_t);
-
- int (*mac_decrypt_init)(crypto_ctx_t *,
- crypto_mechanism_t *, crypto_key_t *, crypto_mechanism_t *,
- crypto_key_t *, crypto_spi_ctx_template_t,
- crypto_spi_ctx_template_t, crypto_req_handle_t);
- int (*mac_decrypt)(crypto_ctx_t *,
- crypto_dual_data_t *, crypto_data_t *, crypto_data_t *,
- crypto_req_handle_t);
- int (*mac_decrypt_update)(crypto_ctx_t *,
- crypto_dual_data_t *, crypto_data_t *, crypto_req_handle_t);
- int (*mac_decrypt_final)(crypto_ctx_t *,
- crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
- int (*mac_decrypt_atomic)(crypto_provider_handle_t,
- crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *,
- crypto_mechanism_t *, crypto_key_t *, crypto_dual_data_t *,
- crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t,
- crypto_spi_ctx_template_t, crypto_req_handle_t);
- int (*mac_verify_decrypt_atomic)(crypto_provider_handle_t,
- crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *,
- crypto_mechanism_t *, crypto_key_t *, crypto_dual_data_t *,
- crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t,
- crypto_spi_ctx_template_t, crypto_req_handle_t);
-} __no_const crypto_dual_cipher_mac_ops_t;
-
-/*
- * The crypto_random_number_ops structure contains pointers to random
- * number operations for cryptographic providers. It is passed through
- * the crypto_ops(9S) structure when providers register with the
- * kernel using crypto_register_provider(9F).
- */
-typedef struct crypto_random_number_ops {
- int (*seed_random)(crypto_provider_handle_t, crypto_session_id_t,
- uchar_t *, size_t, uint_t, uint32_t, crypto_req_handle_t);
- int (*generate_random)(crypto_provider_handle_t, crypto_session_id_t,
- uchar_t *, size_t, crypto_req_handle_t);
-} __no_const crypto_random_number_ops_t;
-
-/*
- * Flag values for seed_random.
- */
-#define CRYPTO_SEED_NOW 0x00000001
-
-/*
- * The crypto_session_ops structure contains pointers to session
- * operations for cryptographic providers. It is passed through
- * the crypto_ops(9S) structure when providers register with the
- * kernel using crypto_register_provider(9F).
- */
-typedef struct crypto_session_ops {
- int (*session_open)(crypto_provider_handle_t, crypto_session_id_t *,
- crypto_req_handle_t);
- int (*session_close)(crypto_provider_handle_t, crypto_session_id_t,
- crypto_req_handle_t);
- int (*session_login)(crypto_provider_handle_t, crypto_session_id_t,
- crypto_user_type_t, char *, size_t, crypto_req_handle_t);
- int (*session_logout)(crypto_provider_handle_t, crypto_session_id_t,
- crypto_req_handle_t);
-} __no_const crypto_session_ops_t;
-
-/*
- * The crypto_object_ops structure contains pointers to object
- * operations for cryptographic providers. It is passed through
- * the crypto_ops(9S) structure when providers register with the
- * kernel using crypto_register_provider(9F).
- */
-typedef struct crypto_object_ops {
- int (*object_create)(crypto_provider_handle_t, crypto_session_id_t,
- crypto_object_attribute_t *, uint_t, crypto_object_id_t *,
- crypto_req_handle_t);
- int (*object_copy)(crypto_provider_handle_t, crypto_session_id_t,
- crypto_object_id_t, crypto_object_attribute_t *, uint_t,
- crypto_object_id_t *, crypto_req_handle_t);
- int (*object_destroy)(crypto_provider_handle_t, crypto_session_id_t,
- crypto_object_id_t, crypto_req_handle_t);
- int (*object_get_size)(crypto_provider_handle_t, crypto_session_id_t,
- crypto_object_id_t, size_t *, crypto_req_handle_t);
- int (*object_get_attribute_value)(crypto_provider_handle_t,
- crypto_session_id_t, crypto_object_id_t,
- crypto_object_attribute_t *, uint_t, crypto_req_handle_t);
- int (*object_set_attribute_value)(crypto_provider_handle_t,
- crypto_session_id_t, crypto_object_id_t,
- crypto_object_attribute_t *, uint_t, crypto_req_handle_t);
- int (*object_find_init)(crypto_provider_handle_t, crypto_session_id_t,
- crypto_object_attribute_t *, uint_t, void **,
- crypto_req_handle_t);
- int (*object_find)(crypto_provider_handle_t, void *,
- crypto_object_id_t *, uint_t, uint_t *, crypto_req_handle_t);
- int (*object_find_final)(crypto_provider_handle_t, void *,
- crypto_req_handle_t);
-} __no_const crypto_object_ops_t;
-
-/*
- * The crypto_key_ops structure contains pointers to key
- * operations for cryptographic providers. It is passed through
- * the crypto_ops(9S) structure when providers register with the
- * kernel using crypto_register_provider(9F).
- */
-typedef struct crypto_key_ops {
- int (*key_generate)(crypto_provider_handle_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_object_attribute_t *, uint_t,
- crypto_object_id_t *, crypto_req_handle_t);
- int (*key_generate_pair)(crypto_provider_handle_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_object_attribute_t *, uint_t,
- crypto_object_attribute_t *, uint_t, crypto_object_id_t *,
- crypto_object_id_t *, crypto_req_handle_t);
- int (*key_wrap)(crypto_provider_handle_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_key_t *, crypto_object_id_t *,
- uchar_t *, size_t *, crypto_req_handle_t);
- int (*key_unwrap)(crypto_provider_handle_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_key_t *, uchar_t *, size_t *,
- crypto_object_attribute_t *, uint_t,
- crypto_object_id_t *, crypto_req_handle_t);
- int (*key_derive)(crypto_provider_handle_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_key_t *, crypto_object_attribute_t *,
- uint_t, crypto_object_id_t *, crypto_req_handle_t);
- int (*key_check)(crypto_provider_handle_t, crypto_mechanism_t *,
- crypto_key_t *);
-} __no_const crypto_key_ops_t;
-
-/*
- * The crypto_provider_management_ops structure contains pointers
- * to management operations for cryptographic providers. It is passed
- * through the crypto_ops(9S) structure when providers register with the
- * kernel using crypto_register_provider(9F).
+ * The crypto_ctx_ops structure contains points to context and context
+ * templates management operations for cryptographic providers. It is
+ * passed through the crypto_ops(9S) structure when providers register
+ * with the kernel using crypto_register_provider(9F).
*/
-typedef struct crypto_provider_management_ops {
- int (*ext_info)(crypto_provider_handle_t,
- crypto_provider_ext_info_t *, crypto_req_handle_t);
- int (*init_token)(crypto_provider_handle_t, char *, size_t,
- char *, crypto_req_handle_t);
- int (*init_pin)(crypto_provider_handle_t, crypto_session_id_t,
- char *, size_t, crypto_req_handle_t);
- int (*set_pin)(crypto_provider_handle_t, crypto_session_id_t,
- char *, size_t, char *, size_t, crypto_req_handle_t);
-} __no_const crypto_provider_management_ops_t;
-
-typedef struct crypto_mech_ops {
- int (*copyin_mechanism)(crypto_provider_handle_t,
- crypto_mechanism_t *, crypto_mechanism_t *, int *, int);
- int (*copyout_mechanism)(crypto_provider_handle_t,
- crypto_mechanism_t *, crypto_mechanism_t *, int *, int);
- int (*free_mechanism)(crypto_provider_handle_t, crypto_mechanism_t *);
-} __no_const crypto_mech_ops_t;
-
-typedef struct crypto_nostore_key_ops {
- int (*nostore_key_generate)(crypto_provider_handle_t,
- crypto_session_id_t, crypto_mechanism_t *,
- crypto_object_attribute_t *, uint_t, crypto_object_attribute_t *,
- uint_t, crypto_req_handle_t);
- int (*nostore_key_generate_pair)(crypto_provider_handle_t,
- crypto_session_id_t, crypto_mechanism_t *,
- crypto_object_attribute_t *, uint_t, crypto_object_attribute_t *,
- uint_t, crypto_object_attribute_t *, uint_t,
- crypto_object_attribute_t *, uint_t, crypto_req_handle_t);
- int (*nostore_key_derive)(crypto_provider_handle_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_key_t *, crypto_object_attribute_t *,
- uint_t, crypto_object_attribute_t *, uint_t, crypto_req_handle_t);
-} __no_const crypto_nostore_key_ops_t;
+typedef struct crypto_ctx_ops {
+ int (*create_ctx_template)(crypto_mechanism_t *, crypto_key_t *,
+ crypto_spi_ctx_template_t *, size_t *);
+ int (*free_context)(crypto_ctx_t *);
+} __no_const crypto_ctx_ops_t;
/*
* The crypto_ops(9S) structure contains the structures containing
@@ -497,58 +155,13 @@ typedef struct crypto_nostore_key_ops {
* supplied by a provider when it registers with the kernel
* by calling crypto_register_provider(9F).
*/
-typedef struct crypto_ops_v1 {
- const crypto_control_ops_t *co_control_ops;
+typedef struct crypto_ops {
const crypto_digest_ops_t *co_digest_ops;
const crypto_cipher_ops_t *co_cipher_ops;
const crypto_mac_ops_t *co_mac_ops;
- crypto_sign_ops_t *co_sign_ops;
- crypto_verify_ops_t *co_verify_ops;
- crypto_dual_ops_t *co_dual_ops;
- crypto_dual_cipher_mac_ops_t *co_dual_cipher_mac_ops;
- crypto_random_number_ops_t *co_random_ops;
- crypto_session_ops_t *co_session_ops;
- crypto_object_ops_t *co_object_ops;
- crypto_key_ops_t *co_key_ops;
- crypto_provider_management_ops_t *co_provider_ops;
const crypto_ctx_ops_t *co_ctx_ops;
-} crypto_ops_v1_t;
-
-typedef struct crypto_ops_v2 {
- crypto_ops_v1_t v1_ops;
- crypto_mech_ops_t *co_mech_ops;
-} crypto_ops_v2_t;
-
-typedef struct crypto_ops_v3 {
- crypto_ops_v2_t v2_ops;
- crypto_nostore_key_ops_t *co_nostore_key_ops;
-} crypto_ops_v3_t;
-
-typedef struct crypto_ops {
- union {
- crypto_ops_v3_t cou_v3;
- crypto_ops_v2_t cou_v2;
- crypto_ops_v1_t cou_v1;
- } cou;
} crypto_ops_t;
-#define co_control_ops cou.cou_v1.co_control_ops
-#define co_digest_ops cou.cou_v1.co_digest_ops
-#define co_cipher_ops cou.cou_v1.co_cipher_ops
-#define co_mac_ops cou.cou_v1.co_mac_ops
-#define co_sign_ops cou.cou_v1.co_sign_ops
-#define co_verify_ops cou.cou_v1.co_verify_ops
-#define co_dual_ops cou.cou_v1.co_dual_ops
-#define co_dual_cipher_mac_ops cou.cou_v1.co_dual_cipher_mac_ops
-#define co_random_ops cou.cou_v1.co_random_ops
-#define co_session_ops cou.cou_v1.co_session_ops
-#define co_object_ops cou.cou_v1.co_object_ops
-#define co_key_ops cou.cou_v1.co_key_ops
-#define co_provider_ops cou.cou_v1.co_provider_ops
-#define co_ctx_ops cou.cou_v1.co_ctx_ops
-#define co_mech_ops cou.cou_v2.co_mech_ops
-#define co_nostore_key_ops cou.cou_v3.co_nostore_key_ops
-
/*
* The mechanism info structure crypto_mech_info_t contains a function group
* bit mask cm_func_group_mask. This field, of type crypto_func_group_t,
@@ -562,29 +175,11 @@ typedef uint32_t crypto_func_group_t;
#define CRYPTO_FG_ENCRYPT 0x00000001 /* encrypt_init() */
#define CRYPTO_FG_DECRYPT 0x00000002 /* decrypt_init() */
#define CRYPTO_FG_DIGEST 0x00000004 /* digest_init() */
-#define CRYPTO_FG_SIGN 0x00000008 /* sign_init() */
-#define CRYPTO_FG_SIGN_RECOVER 0x00000010 /* sign_recover_init() */
-#define CRYPTO_FG_VERIFY 0x00000020 /* verify_init() */
-#define CRYPTO_FG_VERIFY_RECOVER 0x00000040 /* verify_recover_init() */
-#define CRYPTO_FG_GENERATE 0x00000080 /* key_generate() */
-#define CRYPTO_FG_GENERATE_KEY_PAIR 0x00000100 /* key_generate_pair() */
-#define CRYPTO_FG_WRAP 0x00000200 /* key_wrap() */
-#define CRYPTO_FG_UNWRAP 0x00000400 /* key_unwrap() */
-#define CRYPTO_FG_DERIVE 0x00000800 /* key_derive() */
#define CRYPTO_FG_MAC 0x00001000 /* mac_init() */
-#define CRYPTO_FG_ENCRYPT_MAC 0x00002000 /* encrypt_mac_init() */
-#define CRYPTO_FG_MAC_DECRYPT 0x00004000 /* decrypt_mac_init() */
#define CRYPTO_FG_ENCRYPT_ATOMIC 0x00008000 /* encrypt_atomic() */
#define CRYPTO_FG_DECRYPT_ATOMIC 0x00010000 /* decrypt_atomic() */
#define CRYPTO_FG_MAC_ATOMIC 0x00020000 /* mac_atomic() */
#define CRYPTO_FG_DIGEST_ATOMIC 0x00040000 /* digest_atomic() */
-#define CRYPTO_FG_SIGN_ATOMIC 0x00080000 /* sign_atomic() */
-#define CRYPTO_FG_SIGN_RECOVER_ATOMIC 0x00100000 /* sign_recover_atomic() */
-#define CRYPTO_FG_VERIFY_ATOMIC 0x00200000 /* verify_atomic() */
-#define CRYPTO_FG_VERIFY_RECOVER_ATOMIC 0x00400000 /* verify_recover_atomic() */
-#define CRYPTO_FG_ENCRYPT_MAC_ATOMIC 0x00800000 /* encrypt_mac_atomic() */
-#define CRYPTO_FG_MAC_DECRYPT_ATOMIC 0x01000000 /* mac_decrypt_atomic() */
-#define CRYPTO_FG_RESERVED 0x80000000
/*
* Maximum length of the pi_provider_description field of the
@@ -593,21 +188,6 @@ typedef uint32_t crypto_func_group_t;
#define CRYPTO_PROVIDER_DESCR_MAX_LEN 64
-/* Bit mask for all the simple operations */
-#define CRYPTO_FG_SIMPLEOP_MASK (CRYPTO_FG_ENCRYPT | CRYPTO_FG_DECRYPT | \
- CRYPTO_FG_DIGEST | CRYPTO_FG_SIGN | CRYPTO_FG_VERIFY | CRYPTO_FG_MAC | \
- CRYPTO_FG_ENCRYPT_ATOMIC | CRYPTO_FG_DECRYPT_ATOMIC | \
- CRYPTO_FG_MAC_ATOMIC | CRYPTO_FG_DIGEST_ATOMIC | CRYPTO_FG_SIGN_ATOMIC | \
- CRYPTO_FG_VERIFY_ATOMIC)
-
-/* Bit mask for all the dual operations */
-#define CRYPTO_FG_MAC_CIPHER_MASK (CRYPTO_FG_ENCRYPT_MAC | \
- CRYPTO_FG_MAC_DECRYPT | CRYPTO_FG_ENCRYPT_MAC_ATOMIC | \
- CRYPTO_FG_MAC_DECRYPT_ATOMIC)
-
-/* Add other combos to CRYPTO_FG_DUAL_MASK */
-#define CRYPTO_FG_DUAL_MASK CRYPTO_FG_MAC_CIPHER_MASK
-
/*
* The crypto_mech_info structure specifies one of the mechanisms
* supported by a cryptographic provider. The pi_mechanisms field of
@@ -618,21 +198,8 @@ typedef struct crypto_mech_info {
crypto_mech_name_t cm_mech_name;
crypto_mech_type_t cm_mech_number;
crypto_func_group_t cm_func_group_mask;
- ssize_t cm_min_key_length;
- ssize_t cm_max_key_length;
- uint32_t cm_mech_flags;
} crypto_mech_info_t;
-/* Alias the old name to the new name for compatibility. */
-#define cm_keysize_unit cm_mech_flags
-
-/*
- * The following is used by a provider that sets
- * CRYPTO_HASH_NO_UPDATE. It needs to specify the maximum
- * input data size it can digest in this field.
- */
-#define cm_max_input_length cm_max_key_length
-
/*
* crypto_kcf_provider_handle_t is a handle allocated by the kernel.
* It is returned after the provider registers with
@@ -644,67 +211,15 @@ typedef uint_t crypto_kcf_provider_handle_t;
/*
* Provider information. Passed as argument to crypto_register_provider(9F).
- * Describes the provider and its capabilities. Multiple providers can
- * register for the same device instance. In this case, the same
- * pi_provider_dev must be specified with a different pi_provider_handle.
+ * Describes the provider and its capabilities.
*/
-typedef struct crypto_provider_info_v1 {
- uint_t pi_interface_version;
- char *pi_provider_description;
- crypto_provider_type_t pi_provider_type;
- crypto_provider_handle_t pi_provider_handle;
+typedef struct crypto_provider_info {
+ const char *pi_provider_description;
const crypto_ops_t *pi_ops_vector;
uint_t pi_mech_list_count;
const crypto_mech_info_t *pi_mechanisms;
- uint_t pi_logical_provider_count;
- crypto_kcf_provider_handle_t *pi_logical_providers;
-} crypto_provider_info_v1_t;
-
-typedef struct crypto_provider_info_v2 {
- crypto_provider_info_v1_t v1_info;
- uint_t pi_flags;
-} crypto_provider_info_v2_t;
-
-typedef struct crypto_provider_info {
- union {
- crypto_provider_info_v2_t piu_v2;
- crypto_provider_info_v1_t piu_v1;
- } piu;
} crypto_provider_info_t;
-#define pi_interface_version piu.piu_v1.pi_interface_version
-#define pi_provider_description piu.piu_v1.pi_provider_description
-#define pi_provider_type piu.piu_v1.pi_provider_type
-#define pi_provider_handle piu.piu_v1.pi_provider_handle
-#define pi_ops_vector piu.piu_v1.pi_ops_vector
-#define pi_mech_list_count piu.piu_v1.pi_mech_list_count
-#define pi_mechanisms piu.piu_v1.pi_mechanisms
-#define pi_logical_provider_count piu.piu_v1.pi_logical_provider_count
-#define pi_logical_providers piu.piu_v1.pi_logical_providers
-#define pi_flags piu.piu_v2.pi_flags
-
-/* hidden providers can only be accessed via a logical provider */
-#define CRYPTO_HIDE_PROVIDER 0x00000001
-/*
- * provider can not do multi-part digest (updates) and has a limit
- * on maximum input data that it can digest.
- */
-#define CRYPTO_HASH_NO_UPDATE 0x00000002
-
-/* provider can handle the request without returning a CRYPTO_QUEUED */
-#define CRYPTO_SYNCHRONOUS 0x00000004
-
-#define CRYPTO_PIFLAGS_RESERVED2 0x40000000
-#define CRYPTO_PIFLAGS_RESERVED1 0x80000000
-
-/*
- * Provider status passed by a provider to crypto_provider_notification(9F)
- * and returned by the provider_status(9E) entry point.
- */
-#define CRYPTO_PROVIDER_READY 0
-#define CRYPTO_PROVIDER_BUSY 1
-#define CRYPTO_PROVIDER_FAILED 2
-
/*
* Functions exported by Solaris to cryptographic providers. Providers
* call these functions to register and unregister, notify the kernel
@@ -714,9 +229,6 @@ typedef struct crypto_provider_info {
extern int crypto_register_provider(const crypto_provider_info_t *,
crypto_kcf_provider_handle_t *);
extern int crypto_unregister_provider(crypto_kcf_provider_handle_t);
-extern void crypto_provider_notification(crypto_kcf_provider_handle_t, uint_t);
-extern void crypto_op_notification(crypto_req_handle_t, int);
-extern int crypto_kmflag(crypto_req_handle_t);
#ifdef __cplusplus
diff --git a/sys/contrib/openzfs/module/icp/include/sys/ia32/asm_linkage.h b/sys/contrib/openzfs/module/icp/include/sys/ia32/asm_linkage.h
index f2dae7093b94..71588cb5ce5f 100644
--- a/sys/contrib/openzfs/module/icp/include/sys/ia32/asm_linkage.h
+++ b/sys/contrib/openzfs/module/icp/include/sys/ia32/asm_linkage.h
@@ -111,88 +111,6 @@ extern "C" {
#define XMM_SIZE 16
#define XMM_ALIGN 16
-#if defined(__amd64)
-
-#define SAVE_XMM_PROLOG(sreg, nreg) \
- subq $_CONST(_MUL(XMM_SIZE, nreg)), %rsp; \
- movq %rsp, sreg
-
-#define RSTOR_XMM_EPILOG(sreg, nreg) \
- addq $_CONST(_MUL(XMM_SIZE, nreg)), %rsp
-
-#elif defined(__i386)
-
-#define SAVE_XMM_PROLOG(sreg, nreg) \
- subl $_CONST(_MUL(XMM_SIZE, nreg) + XMM_ALIGN), %esp; \
- movl %esp, sreg; \
- addl $XMM_ALIGN, sreg; \
- andl $_BITNOT(XMM_ALIGN-1), sreg
-
-#define RSTOR_XMM_EPILOG(sreg, nreg) \
- addl $_CONST(_MUL(XMM_SIZE, nreg) + XMM_ALIGN), %esp;
-
-#endif /* __i386 */
-
-/*
- * profiling causes definitions of the MCOUNT and RTMCOUNT
- * particular to the type
- */
-#ifdef GPROF
-
-#define MCOUNT(x) \
- pushl %ebp; \
- movl %esp, %ebp; \
- call _mcount; \
- popl %ebp
-
-#endif /* GPROF */
-
-#ifdef PROF
-
-#define MCOUNT(x) \
-/* CSTYLED */ \
- .lcomm .L_/**/x/**/1, 4, 4; \
- pushl %ebp; \
- movl %esp, %ebp; \
-/* CSTYLED */ \
- movl $.L_/**/x/**/1, %edx; \
- call _mcount; \
- popl %ebp
-
-#endif /* PROF */
-
-/*
- * if we are not profiling, MCOUNT should be defined to nothing
- */
-#if !defined(PROF) && !defined(GPROF)
-#define MCOUNT(x)
-#endif /* !defined(PROF) && !defined(GPROF) */
-
-#define RTMCOUNT(x) MCOUNT(x)
-
-/*
- * Macro to define weak symbol aliases. These are similar to the ANSI-C
- * #pragma weak _name = name
- * except a compiler can determine type. The assembler must be told. Hence,
- * the second parameter must be the type of the symbol (i.e.: function,...)
- */
-#define ANSI_PRAGMA_WEAK(sym, stype) \
-/* CSTYLED */ \
- .weak _/**/sym; \
-/* CSTYLED */ \
- .type _/**/sym, @stype; \
-/* CSTYLED */ \
-_/**/sym = sym
-
-/*
- * Like ANSI_PRAGMA_WEAK(), but for unrelated names, as in:
- * #pragma weak sym1 = sym2
- */
-#define ANSI_PRAGMA_WEAK2(sym1, sym2, stype) \
- .weak sym1; \
- .type sym1, @stype; \
-sym1 = sym2
-
/*
* ENTRY provides the standard procedure entry code and an easy way to
* insert the calls to mcount for profiling. ENTRY_NP is identical, but
@@ -212,24 +130,16 @@ x: MCOUNT(x)
.type x, @function; \
x:
-#define RTENTRY(x) \
- .text; \
- .align ASM_ENTRY_ALIGN; \
- .globl x; \
- .type x, @function; \
-x: RTMCOUNT(x)
-
/*
* ENTRY2 is identical to ENTRY but provides two labels for the entry point.
*/
#define ENTRY2(x, y) \
- .text; \
+ .text; \
.align ASM_ENTRY_ALIGN; \
.globl x, y; \
.type x, @function; \
.type y, @function; \
-/* CSTYLED */ \
-x: ; \
+x:; \
y: MCOUNT(x)
#define ENTRY_NP2(x, y) \
@@ -238,66 +148,16 @@ y: MCOUNT(x)
.globl x, y; \
.type x, @function; \
.type y, @function; \
-/* CSTYLED */ \
-x: ; \
+x:; \
y:
/*
- * ALTENTRY provides for additional entry points.
- */
-#define ALTENTRY(x) \
- .globl x; \
- .type x, @function; \
-x:
-
-/*
- * DGDEF and DGDEF2 provide global data declarations.
- *
- * DGDEF provides a word aligned word of storage.
- *
- * DGDEF2 allocates "sz" bytes of storage with **NO** alignment. This
- * implies this macro is best used for byte arrays.
- *
- * DGDEF3 allocates "sz" bytes of storage with "algn" alignment.
- */
-#define DGDEF2(name, sz) \
- .data; \
- .globl name; \
- .type name, @object; \
- .size name, sz; \
-name:
-
-#define DGDEF3(name, sz, algn) \
- .data; \
- .align algn; \
- .globl name; \
- .type name, @object; \
- .size name, sz; \
-name:
-
-#define DGDEF(name) DGDEF3(name, 4, 4)
-
-/*
* SET_SIZE trails a function and set the size for the ELF symbol table.
*/
#define SET_SIZE(x) \
.size x, [.-x]
-/*
- * NWORD provides native word value.
- */
-#if defined(__amd64)
-
-/*CSTYLED*/
-#define NWORD quad
-
-#elif defined(__i386)
-
-#define NWORD long
-
-#endif /* __i386 */
-
#endif /* _ASM */
#ifdef __cplusplus
diff --git a/sys/contrib/openzfs/module/icp/include/sys/modhash.h b/sys/contrib/openzfs/module/icp/include/sys/modhash.h
deleted file mode 100644
index 06b52ff02604..000000000000
--- a/sys/contrib/openzfs/module/icp/include/sys/modhash.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * 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 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#ifndef _SYS_MODHASH_H
-#define _SYS_MODHASH_H
-
-/*
- * Generic hash implementation for the kernel.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <sys/zfs_context.h>
-
-/*
- * Opaque data types for storing keys and values
- */
-typedef void *mod_hash_val_t;
-typedef void *mod_hash_key_t;
-
-/*
- * Opaque data type for reservation
- */
-typedef void *mod_hash_hndl_t;
-
-/*
- * Opaque type for hash itself.
- */
-struct mod_hash;
-typedef struct mod_hash mod_hash_t;
-
-/*
- * String hash table
- */
-mod_hash_t *mod_hash_create_strhash_nodtr(char *, size_t,
- void (*)(mod_hash_val_t));
-mod_hash_t *mod_hash_create_strhash(char *, size_t, void (*)(mod_hash_val_t));
-void mod_hash_destroy_strhash(mod_hash_t *);
-int mod_hash_strkey_cmp(mod_hash_key_t, mod_hash_key_t);
-void mod_hash_strkey_dtor(mod_hash_key_t);
-void mod_hash_strval_dtor(mod_hash_val_t);
-uint_t mod_hash_bystr(void *, mod_hash_key_t);
-
-/*
- * Pointer hash table
- */
-mod_hash_t *mod_hash_create_ptrhash(char *, size_t, void (*)(mod_hash_val_t),
- size_t);
-void mod_hash_destroy_ptrhash(mod_hash_t *);
-int mod_hash_ptrkey_cmp(mod_hash_key_t, mod_hash_key_t);
-uint_t mod_hash_byptr(void *, mod_hash_key_t);
-
-/*
- * ID hash table
- */
-mod_hash_t *mod_hash_create_idhash(char *, size_t, void (*)(mod_hash_val_t));
-void mod_hash_destroy_idhash(mod_hash_t *);
-int mod_hash_idkey_cmp(mod_hash_key_t, mod_hash_key_t);
-uint_t mod_hash_byid(void *, mod_hash_key_t);
-uint_t mod_hash_iddata_gen(size_t);
-
-/*
- * Hash management functions
- */
-mod_hash_t *mod_hash_create_extended(char *, size_t, void (*)(mod_hash_key_t),
- void (*)(mod_hash_val_t), uint_t (*)(void *, mod_hash_key_t), void *,
- int (*)(mod_hash_key_t, mod_hash_key_t), int);
-
-void mod_hash_destroy_hash(mod_hash_t *);
-void mod_hash_clear(mod_hash_t *);
-
-/*
- * Null key and value destructors
- */
-void mod_hash_null_keydtor(mod_hash_key_t);
-void mod_hash_null_valdtor(mod_hash_val_t);
-
-/*
- * Basic hash operations
- */
-
-/*
- * Error codes for insert, remove, find, destroy.
- */
-#define MH_ERR_NOMEM -1
-#define MH_ERR_DUPLICATE -2
-#define MH_ERR_NOTFOUND -3
-
-/*
- * Return codes for hash walkers
- */
-#define MH_WALK_CONTINUE 0
-#define MH_WALK_TERMINATE 1
-
-/*
- * Basic hash operations
- */
-int mod_hash_insert(mod_hash_t *, mod_hash_key_t, mod_hash_val_t);
-int mod_hash_replace(mod_hash_t *, mod_hash_key_t, mod_hash_val_t);
-int mod_hash_remove(mod_hash_t *, mod_hash_key_t, mod_hash_val_t *);
-int mod_hash_destroy(mod_hash_t *, mod_hash_key_t);
-int mod_hash_find(mod_hash_t *, mod_hash_key_t, mod_hash_val_t *);
-int mod_hash_find_cb(mod_hash_t *, mod_hash_key_t, mod_hash_val_t *,
- void (*)(mod_hash_key_t, mod_hash_val_t));
-int mod_hash_find_cb_rval(mod_hash_t *, mod_hash_key_t, mod_hash_val_t *,
- int (*)(mod_hash_key_t, mod_hash_val_t), int *);
-void mod_hash_walk(mod_hash_t *,
- uint_t (*)(mod_hash_key_t, mod_hash_val_t *, void *), void *);
-
-/*
- * Reserving hash operations
- */
-int mod_hash_reserve(mod_hash_t *, mod_hash_hndl_t *);
-int mod_hash_reserve_nosleep(mod_hash_t *, mod_hash_hndl_t *);
-void mod_hash_cancel(mod_hash_t *, mod_hash_hndl_t *);
-int mod_hash_insert_reserve(mod_hash_t *, mod_hash_key_t, mod_hash_val_t,
- mod_hash_hndl_t);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _SYS_MODHASH_H */
diff --git a/sys/contrib/openzfs/module/icp/include/sys/modhash_impl.h b/sys/contrib/openzfs/module/icp/include/sys/modhash_impl.h
deleted file mode 100644
index 3130773aa196..000000000000
--- a/sys/contrib/openzfs/module/icp/include/sys/modhash_impl.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * 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 2006 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#ifndef _SYS_MODHASH_IMPL_H
-#define _SYS_MODHASH_IMPL_H
-
-/*
- * Internal details for the kernel's generic hash implementation.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <sys/zfs_context.h>
-#include <sys/modhash.h>
-
-struct mod_hash_entry {
- mod_hash_key_t mhe_key; /* stored hash key */
- mod_hash_val_t mhe_val; /* stored hash value */
- struct mod_hash_entry *mhe_next; /* next item in chain */
-};
-
-struct mod_hash_stat {
- ulong_t mhs_hit; /* tried a 'find' and it succeeded */
- ulong_t mhs_miss; /* tried a 'find' but it failed */
- ulong_t mhs_coll; /* occur when insert fails because of dup's */
- ulong_t mhs_nelems; /* total number of stored key/value pairs */
- ulong_t mhs_nomem; /* number of times kmem_alloc failed */
-};
-
-struct mod_hash {
- krwlock_t mh_contents; /* lock protecting contents */
- char *mh_name; /* hash name */
- int mh_sleep; /* kmem_alloc flag */
- size_t mh_nchains; /* # of elements in mh_entries */
-
- /* key and val destructor */
- void (*mh_kdtor)(mod_hash_key_t);
- void (*mh_vdtor)(mod_hash_val_t);
-
- /* key comparator */
- int (*mh_keycmp)(mod_hash_key_t, mod_hash_key_t);
-
- /* hash algorithm, and algorithm-private data */
- uint_t (*mh_hashalg)(void *, mod_hash_key_t);
- void *mh_hashalg_data;
-
- struct mod_hash *mh_next; /* next hash in list */
-
- struct mod_hash_stat mh_stat;
-
- struct mod_hash_entry *mh_entries[1];
-};
-
-/*
- * MH_SIZE()
- * Compute the size of a mod_hash_t, in bytes, given the number of
- * elements it contains.
- */
-#define MH_SIZE(n) \
- (sizeof (mod_hash_t) + ((n) - 1) * (sizeof (struct mod_hash_entry *)))
-
-/*
- * Module initialization; called once.
- */
-void mod_hash_fini(void);
-void mod_hash_init(void);
-
-/*
- * Internal routines. Use directly with care.
- */
-uint_t i_mod_hash(mod_hash_t *, mod_hash_key_t);
-int i_mod_hash_insert_nosync(mod_hash_t *, mod_hash_key_t, mod_hash_val_t,
- mod_hash_hndl_t);
-int i_mod_hash_remove_nosync(mod_hash_t *, mod_hash_key_t, mod_hash_val_t *);
-int i_mod_hash_find_nosync(mod_hash_t *, mod_hash_key_t, mod_hash_val_t *);
-void i_mod_hash_walk_nosync(mod_hash_t *, uint_t (*)(mod_hash_key_t,
- mod_hash_val_t *, void *), void *);
-void i_mod_hash_clear_nosync(mod_hash_t *hash);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _SYS_MODHASH_IMPL_H */
diff --git a/sys/contrib/openzfs/module/icp/io/aes.c b/sys/contrib/openzfs/module/icp/io/aes.c
index be1736864c0b..b0f51262dd07 100644
--- a/sys/contrib/openzfs/module/icp/io/aes.c
+++ b/sys/contrib/openzfs/module/icp/io/aes.c
@@ -43,72 +43,52 @@ static const crypto_mech_info_t aes_mech_info_tab[] = {
/* AES_ECB */
{SUN_CKM_AES_ECB, AES_ECB_MECH_INFO_TYPE,
CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
- CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC,
- AES_MIN_KEY_BYTES, AES_MAX_KEY_BYTES, CRYPTO_KEYSIZE_UNIT_IN_BYTES},
+ CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC},
/* AES_CBC */
{SUN_CKM_AES_CBC, AES_CBC_MECH_INFO_TYPE,
CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
- CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC,
- AES_MIN_KEY_BYTES, AES_MAX_KEY_BYTES, CRYPTO_KEYSIZE_UNIT_IN_BYTES},
+ CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC},
/* AES_CTR */
{SUN_CKM_AES_CTR, AES_CTR_MECH_INFO_TYPE,
CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
- CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC,
- AES_MIN_KEY_BYTES, AES_MAX_KEY_BYTES, CRYPTO_KEYSIZE_UNIT_IN_BYTES},
+ CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC},
/* AES_CCM */
{SUN_CKM_AES_CCM, AES_CCM_MECH_INFO_TYPE,
CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
- CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC,
- AES_MIN_KEY_BYTES, AES_MAX_KEY_BYTES, CRYPTO_KEYSIZE_UNIT_IN_BYTES},
+ CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC},
/* AES_GCM */
{SUN_CKM_AES_GCM, AES_GCM_MECH_INFO_TYPE,
CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
- CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC,
- AES_MIN_KEY_BYTES, AES_MAX_KEY_BYTES, CRYPTO_KEYSIZE_UNIT_IN_BYTES},
+ CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC},
/* AES_GMAC */
{SUN_CKM_AES_GMAC, AES_GMAC_MECH_INFO_TYPE,
CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC |
- CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC |
- CRYPTO_FG_SIGN | CRYPTO_FG_SIGN_ATOMIC |
- CRYPTO_FG_VERIFY | CRYPTO_FG_VERIFY_ATOMIC,
- AES_MIN_KEY_BYTES, AES_MAX_KEY_BYTES, CRYPTO_KEYSIZE_UNIT_IN_BYTES}
-};
-
-static void aes_provider_status(crypto_provider_handle_t, uint_t *);
-
-static const crypto_control_ops_t aes_control_ops = {
- aes_provider_status
+ CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC},
};
static int aes_encrypt_init(crypto_ctx_t *, crypto_mechanism_t *,
- crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
+ crypto_key_t *, crypto_spi_ctx_template_t);
static int aes_decrypt_init(crypto_ctx_t *, crypto_mechanism_t *,
- crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
+ crypto_key_t *, crypto_spi_ctx_template_t);
static int aes_common_init(crypto_ctx_t *, crypto_mechanism_t *,
- crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t, boolean_t);
+ crypto_key_t *, crypto_spi_ctx_template_t, boolean_t);
static int aes_common_init_ctx(aes_ctx_t *, crypto_spi_ctx_template_t *,
crypto_mechanism_t *, crypto_key_t *, int, boolean_t);
-static int aes_encrypt_final(crypto_ctx_t *, crypto_data_t *,
- crypto_req_handle_t);
-static int aes_decrypt_final(crypto_ctx_t *, crypto_data_t *,
- crypto_req_handle_t);
+static int aes_encrypt_final(crypto_ctx_t *, crypto_data_t *);
+static int aes_decrypt_final(crypto_ctx_t *, crypto_data_t *);
-static int aes_encrypt(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
- crypto_req_handle_t);
+static int aes_encrypt(crypto_ctx_t *, crypto_data_t *, crypto_data_t *);
static int aes_encrypt_update(crypto_ctx_t *, crypto_data_t *,
- crypto_data_t *, crypto_req_handle_t);
-static int aes_encrypt_atomic(crypto_provider_handle_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
- crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
+ crypto_data_t *);
+static int aes_encrypt_atomic(crypto_mechanism_t *, crypto_key_t *,
+ crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t);
-static int aes_decrypt(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
- crypto_req_handle_t);
+static int aes_decrypt(crypto_ctx_t *, crypto_data_t *, crypto_data_t *);
static int aes_decrypt_update(crypto_ctx_t *, crypto_data_t *,
- crypto_data_t *, crypto_req_handle_t);
-static int aes_decrypt_atomic(crypto_provider_handle_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
- crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
+ crypto_data_t *);
+static int aes_decrypt_atomic(crypto_mechanism_t *, crypto_key_t *,
+ crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t);
static const crypto_cipher_ops_t aes_cipher_ops = {
.encrypt_init = aes_encrypt_init,
@@ -123,12 +103,10 @@ static const crypto_cipher_ops_t aes_cipher_ops = {
.decrypt_atomic = aes_decrypt_atomic
};
-static int aes_mac_atomic(crypto_provider_handle_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
- crypto_spi_ctx_template_t, crypto_req_handle_t);
-static int aes_mac_verify_atomic(crypto_provider_handle_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
- crypto_spi_ctx_template_t, crypto_req_handle_t);
+static int aes_mac_atomic(crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
+ crypto_data_t *, crypto_spi_ctx_template_t);
+static int aes_mac_verify_atomic(crypto_mechanism_t *, crypto_key_t *,
+ crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t);
static const crypto_mac_ops_t aes_mac_ops = {
.mac_init = NULL,
@@ -139,9 +117,8 @@ static const crypto_mac_ops_t aes_mac_ops = {
.mac_verify_atomic = aes_mac_verify_atomic
};
-static int aes_create_ctx_template(crypto_provider_handle_t,
- crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t *,
- size_t *, crypto_req_handle_t);
+static int aes_create_ctx_template(crypto_mechanism_t *, crypto_key_t *,
+ crypto_spi_ctx_template_t *, size_t *);
static int aes_free_context(crypto_ctx_t *);
static const crypto_ctx_ops_t aes_ctx_ops = {
@@ -149,32 +126,19 @@ static const crypto_ctx_ops_t aes_ctx_ops = {
.free_context = aes_free_context
};
-static const crypto_ops_t aes_crypto_ops = {{{{{
- &aes_control_ops,
+static const crypto_ops_t aes_crypto_ops = {
NULL,
&aes_cipher_ops,
&aes_mac_ops,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- &aes_ctx_ops
-}}}}};
+ &aes_ctx_ops,
+};
-static const crypto_provider_info_t aes_prov_info = {{{{
- CRYPTO_SPI_VERSION_1,
+static const crypto_provider_info_t aes_prov_info = {
"AES Software Provider",
- CRYPTO_SW_PROVIDER,
- NULL,
&aes_crypto_ops,
sizeof (aes_mech_info_tab) / sizeof (crypto_mech_info_t),
aes_mech_info_tab
-}}}};
+};
static crypto_kcf_provider_handle_t aes_prov_handle = 0;
static crypto_data_t null_crypto_data = { CRYPTO_DATA_RAW };
@@ -208,7 +172,7 @@ aes_mod_fini(void)
}
static int
-aes_check_mech_param(crypto_mechanism_t *mechanism, aes_ctx_t **ctx, int kmflag)
+aes_check_mech_param(crypto_mechanism_t *mechanism, aes_ctx_t **ctx)
{
void *p = NULL;
boolean_t param_required = B_TRUE;
@@ -250,7 +214,7 @@ aes_check_mech_param(crypto_mechanism_t *mechanism, aes_ctx_t **ctx, int kmflag)
rv = CRYPTO_MECHANISM_PARAM_INVALID;
}
if (ctx != NULL) {
- p = (alloc_fun)(kmflag);
+ p = (alloc_fun)(KM_SLEEP);
*ctx = p;
}
return (rv);
@@ -262,52 +226,31 @@ aes_check_mech_param(crypto_mechanism_t *mechanism, aes_ctx_t **ctx, int kmflag)
static int
init_keysched(crypto_key_t *key, void *newbie)
{
- /*
- * Only keys by value are supported by this module.
- */
- switch (key->ck_format) {
- case CRYPTO_KEY_RAW:
- if (key->ck_length < AES_MINBITS ||
- key->ck_length > AES_MAXBITS) {
- return (CRYPTO_KEY_SIZE_RANGE);
- }
-
- /* key length must be either 128, 192, or 256 */
- if ((key->ck_length & 63) != 0)
- return (CRYPTO_KEY_SIZE_RANGE);
- break;
- default:
- return (CRYPTO_KEY_TYPE_INCONSISTENT);
+ if (key->ck_length < AES_MINBITS ||
+ key->ck_length > AES_MAXBITS) {
+ return (CRYPTO_KEY_SIZE_RANGE);
}
+ /* key length must be either 128, 192, or 256 */
+ if ((key->ck_length & 63) != 0)
+ return (CRYPTO_KEY_SIZE_RANGE);
+
aes_init_keysched(key->ck_data, key->ck_length, newbie);
return (CRYPTO_SUCCESS);
}
-/*
- * KCF software provider control entry points.
- */
-static void
-aes_provider_status(crypto_provider_handle_t provider, uint_t *status)
-{
- (void) provider;
- *status = CRYPTO_PROVIDER_READY;
-}
-
static int
aes_encrypt_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
- crypto_key_t *key, crypto_spi_ctx_template_t template,
- crypto_req_handle_t req)
+ crypto_key_t *key, crypto_spi_ctx_template_t template)
{
- return (aes_common_init(ctx, mechanism, key, template, req, B_TRUE));
+ return (aes_common_init(ctx, mechanism, key, template, B_TRUE));
}
static int
aes_decrypt_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
- crypto_key_t *key, crypto_spi_ctx_template_t template,
- crypto_req_handle_t req)
+ crypto_key_t *key, crypto_spi_ctx_template_t template)
{
- return (aes_common_init(ctx, mechanism, key, template, req, B_FALSE));
+ return (aes_common_init(ctx, mechanism, key, template, B_FALSE));
}
@@ -318,25 +261,16 @@ aes_decrypt_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
static int
aes_common_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
crypto_key_t *key, crypto_spi_ctx_template_t template,
- crypto_req_handle_t req, boolean_t is_encrypt_init)
+ boolean_t is_encrypt_init)
{
aes_ctx_t *aes_ctx;
int rv;
- int kmflag;
- /*
- * Only keys by value are supported by this module.
- */
- if (key->ck_format != CRYPTO_KEY_RAW) {
- return (CRYPTO_KEY_TYPE_INCONSISTENT);
- }
-
- kmflag = crypto_kmflag(req);
- if ((rv = aes_check_mech_param(mechanism, &aes_ctx, kmflag))
+ if ((rv = aes_check_mech_param(mechanism, &aes_ctx))
!= CRYPTO_SUCCESS)
return (rv);
- rv = aes_common_init_ctx(aes_ctx, template, mechanism, key, kmflag,
+ rv = aes_common_init_ctx(aes_ctx, template, mechanism, key, KM_SLEEP,
is_encrypt_init);
if (rv != CRYPTO_SUCCESS) {
crypto_free_mode_ctx(aes_ctx);
@@ -366,7 +300,7 @@ aes_copy_block64(uint8_t *in, uint64_t *out)
static int
aes_encrypt(crypto_ctx_t *ctx, crypto_data_t *plaintext,
- crypto_data_t *ciphertext, crypto_req_handle_t req)
+ crypto_data_t *ciphertext)
{
int ret = CRYPTO_FAILED;
@@ -418,7 +352,7 @@ aes_encrypt(crypto_ctx_t *ctx, crypto_data_t *plaintext,
/*
* Do an update on the specified input data.
*/
- ret = aes_encrypt_update(ctx, plaintext, ciphertext, req);
+ ret = aes_encrypt_update(ctx, plaintext, ciphertext);
if (ret != CRYPTO_SUCCESS) {
return (ret);
}
@@ -481,7 +415,7 @@ aes_encrypt(crypto_ctx_t *ctx, crypto_data_t *plaintext,
static int
aes_decrypt(crypto_ctx_t *ctx, crypto_data_t *ciphertext,
- crypto_data_t *plaintext, crypto_req_handle_t req)
+ crypto_data_t *plaintext)
{
int ret = CRYPTO_FAILED;
@@ -539,7 +473,7 @@ aes_decrypt(crypto_ctx_t *ctx, crypto_data_t *ciphertext,
/*
* Do an update on the specified input data.
*/
- ret = aes_decrypt_update(ctx, ciphertext, plaintext, req);
+ ret = aes_decrypt_update(ctx, ciphertext, plaintext);
if (ret != CRYPTO_SUCCESS) {
goto cleanup;
}
@@ -595,9 +529,8 @@ cleanup:
static int
aes_encrypt_update(crypto_ctx_t *ctx, crypto_data_t *plaintext,
- crypto_data_t *ciphertext, crypto_req_handle_t req)
+ crypto_data_t *ciphertext)
{
- (void) req;
off_t saved_offset;
size_t saved_length, out_len;
int ret = CRYPTO_SUCCESS;
@@ -628,13 +561,11 @@ aes_encrypt_update(crypto_ctx_t *ctx, crypto_data_t *plaintext,
switch (plaintext->cd_format) {
case CRYPTO_DATA_RAW:
ret = crypto_update_iov(ctx->cc_provider_private,
- plaintext, ciphertext, aes_encrypt_contiguous_blocks,
- aes_copy_block64);
+ plaintext, ciphertext, aes_encrypt_contiguous_blocks);
break;
case CRYPTO_DATA_UIO:
ret = crypto_update_uio(ctx->cc_provider_private,
- plaintext, ciphertext, aes_encrypt_contiguous_blocks,
- aes_copy_block64);
+ plaintext, ciphertext, aes_encrypt_contiguous_blocks);
break;
default:
ret = CRYPTO_ARGUMENTS_BAD;
@@ -666,7 +597,7 @@ aes_encrypt_update(crypto_ctx_t *ctx, crypto_data_t *plaintext,
static int
aes_decrypt_update(crypto_ctx_t *ctx, crypto_data_t *ciphertext,
- crypto_data_t *plaintext, crypto_req_handle_t req)
+ crypto_data_t *plaintext)
{
off_t saved_offset;
size_t saved_length, out_len;
@@ -698,22 +629,17 @@ aes_decrypt_update(crypto_ctx_t *ctx, crypto_data_t *ciphertext,
saved_offset = plaintext->cd_offset;
saved_length = plaintext->cd_length;
- if (aes_ctx->ac_flags & (GCM_MODE|GMAC_MODE))
- gcm_set_kmflag((gcm_ctx_t *)aes_ctx, crypto_kmflag(req));
-
/*
* Do the AES update on the specified input data.
*/
switch (ciphertext->cd_format) {
case CRYPTO_DATA_RAW:
ret = crypto_update_iov(ctx->cc_provider_private,
- ciphertext, plaintext, aes_decrypt_contiguous_blocks,
- aes_copy_block64);
+ ciphertext, plaintext, aes_decrypt_contiguous_blocks);
break;
case CRYPTO_DATA_UIO:
ret = crypto_update_uio(ctx->cc_provider_private,
- ciphertext, plaintext, aes_decrypt_contiguous_blocks,
- aes_copy_block64);
+ ciphertext, plaintext, aes_decrypt_contiguous_blocks);
break;
default:
ret = CRYPTO_ARGUMENTS_BAD;
@@ -746,10 +672,8 @@ aes_decrypt_update(crypto_ctx_t *ctx, crypto_data_t *ciphertext,
}
static int
-aes_encrypt_final(crypto_ctx_t *ctx, crypto_data_t *data,
- crypto_req_handle_t req)
+aes_encrypt_final(crypto_ctx_t *ctx, crypto_data_t *data)
{
- (void) req;
aes_ctx_t *aes_ctx;
int ret;
@@ -803,10 +727,8 @@ aes_encrypt_final(crypto_ctx_t *ctx, crypto_data_t *data,
}
static int
-aes_decrypt_final(crypto_ctx_t *ctx, crypto_data_t *data,
- crypto_req_handle_t req)
+aes_decrypt_final(crypto_ctx_t *ctx, crypto_data_t *data)
{
- (void) req;
aes_ctx_t *aes_ctx;
int ret;
off_t saved_offset;
@@ -906,12 +828,10 @@ aes_decrypt_final(crypto_ctx_t *ctx, crypto_data_t *data,
}
static int
-aes_encrypt_atomic(crypto_provider_handle_t provider,
- crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
+aes_encrypt_atomic(crypto_mechanism_t *mechanism,
crypto_key_t *key, crypto_data_t *plaintext, crypto_data_t *ciphertext,
- crypto_spi_ctx_template_t template, crypto_req_handle_t req)
+ crypto_spi_ctx_template_t template)
{
- (void) provider, (void) session_id;
aes_ctx_t aes_ctx; /* on the stack */
off_t saved_offset;
size_t saved_length;
@@ -935,13 +855,13 @@ aes_encrypt_atomic(crypto_provider_handle_t provider,
return (CRYPTO_DATA_LEN_RANGE);
}
- if ((ret = aes_check_mech_param(mechanism, NULL, 0)) != CRYPTO_SUCCESS)
+ if ((ret = aes_check_mech_param(mechanism, NULL)) != CRYPTO_SUCCESS)
return (ret);
bzero(&aes_ctx, sizeof (aes_ctx_t));
ret = aes_common_init_ctx(&aes_ctx, template, mechanism, key,
- crypto_kmflag(req), B_TRUE);
+ KM_SLEEP, B_TRUE);
if (ret != CRYPTO_SUCCESS)
return (ret);
@@ -952,7 +872,7 @@ aes_encrypt_atomic(crypto_provider_handle_t provider,
case AES_GMAC_MECH_INFO_TYPE:
if (plaintext->cd_length != 0)
return (CRYPTO_ARGUMENTS_BAD);
- fallthrough;
+ zfs_fallthrough;
case AES_GCM_MECH_INFO_TYPE:
length_needed = plaintext->cd_length + aes_ctx.ac_tag_len;
break;
@@ -976,11 +896,11 @@ aes_encrypt_atomic(crypto_provider_handle_t provider,
switch (plaintext->cd_format) {
case CRYPTO_DATA_RAW:
ret = crypto_update_iov(&aes_ctx, plaintext, ciphertext,
- aes_encrypt_contiguous_blocks, aes_copy_block64);
+ aes_encrypt_contiguous_blocks);
break;
case CRYPTO_DATA_UIO:
ret = crypto_update_uio(&aes_ctx, plaintext, ciphertext,
- aes_encrypt_contiguous_blocks, aes_copy_block64);
+ aes_encrypt_contiguous_blocks);
break;
default:
ret = CRYPTO_ARGUMENTS_BAD;
@@ -1042,12 +962,10 @@ out:
}
static int
-aes_decrypt_atomic(crypto_provider_handle_t provider,
- crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
+aes_decrypt_atomic(crypto_mechanism_t *mechanism,
crypto_key_t *key, crypto_data_t *ciphertext, crypto_data_t *plaintext,
- crypto_spi_ctx_template_t template, crypto_req_handle_t req)
+ crypto_spi_ctx_template_t template)
{
- (void) provider, (void) session_id;
aes_ctx_t aes_ctx; /* on the stack */
off_t saved_offset;
size_t saved_length;
@@ -1071,13 +989,13 @@ aes_decrypt_atomic(crypto_provider_handle_t provider,
return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
}
- if ((ret = aes_check_mech_param(mechanism, NULL, 0)) != CRYPTO_SUCCESS)
+ if ((ret = aes_check_mech_param(mechanism, NULL)) != CRYPTO_SUCCESS)
return (ret);
bzero(&aes_ctx, sizeof (aes_ctx_t));
ret = aes_common_init_ctx(&aes_ctx, template, mechanism, key,
- crypto_kmflag(req), B_FALSE);
+ KM_SLEEP, B_FALSE);
if (ret != CRYPTO_SUCCESS)
return (ret);
@@ -1107,21 +1025,17 @@ aes_decrypt_atomic(crypto_provider_handle_t provider,
saved_offset = plaintext->cd_offset;
saved_length = plaintext->cd_length;
- if (mechanism->cm_type == AES_GCM_MECH_INFO_TYPE ||
- mechanism->cm_type == AES_GMAC_MECH_INFO_TYPE)
- gcm_set_kmflag((gcm_ctx_t *)&aes_ctx, crypto_kmflag(req));
-
/*
* Do an update on the specified input data.
*/
switch (ciphertext->cd_format) {
case CRYPTO_DATA_RAW:
ret = crypto_update_iov(&aes_ctx, ciphertext, plaintext,
- aes_decrypt_contiguous_blocks, aes_copy_block64);
+ aes_decrypt_contiguous_blocks);
break;
case CRYPTO_DATA_UIO:
ret = crypto_update_uio(&aes_ctx, ciphertext, plaintext,
- aes_decrypt_contiguous_blocks, aes_copy_block64);
+ aes_decrypt_contiguous_blocks);
break;
default:
ret = CRYPTO_ARGUMENTS_BAD;
@@ -1212,11 +1126,9 @@ out:
* KCF software provider context template entry points.
*/
static int
-aes_create_ctx_template(crypto_provider_handle_t provider,
- crypto_mechanism_t *mechanism, crypto_key_t *key,
- crypto_spi_ctx_template_t *tmpl, size_t *tmpl_size, crypto_req_handle_t req)
+aes_create_ctx_template(crypto_mechanism_t *mechanism, crypto_key_t *key,
+ crypto_spi_ctx_template_t *tmpl, size_t *tmpl_size)
{
- (void) provider;
void *keysched;
size_t size;
int rv;
@@ -1229,8 +1141,7 @@ aes_create_ctx_template(crypto_provider_handle_t provider,
mechanism->cm_type != AES_GMAC_MECH_INFO_TYPE)
return (CRYPTO_MECHANISM_INVALID);
- if ((keysched = aes_alloc_keysched(&size,
- crypto_kmflag(req))) == NULL) {
+ if ((keysched = aes_alloc_keysched(&size, KM_SLEEP)) == NULL) {
return (CRYPTO_HOST_MEMORY);
}
@@ -1389,10 +1300,9 @@ process_gmac_mech(crypto_mechanism_t *mech, crypto_data_t *data,
}
static int
-aes_mac_atomic(crypto_provider_handle_t provider,
- crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
+aes_mac_atomic(crypto_mechanism_t *mechanism,
crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
- crypto_spi_ctx_template_t template, crypto_req_handle_t req)
+ crypto_spi_ctx_template_t template)
{
CK_AES_GCM_PARAMS gcm_params;
crypto_mechanism_t gcm_mech;
@@ -1406,15 +1316,13 @@ aes_mac_atomic(crypto_provider_handle_t provider,
gcm_mech.cm_param_len = sizeof (CK_AES_GCM_PARAMS);
gcm_mech.cm_param = (char *)&gcm_params;
- return (aes_encrypt_atomic(provider, session_id, &gcm_mech,
- key, &null_crypto_data, mac, template, req));
+ return (aes_encrypt_atomic(&gcm_mech,
+ key, &null_crypto_data, mac, template));
}
static int
-aes_mac_verify_atomic(crypto_provider_handle_t provider,
- crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
- crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
- crypto_spi_ctx_template_t template, crypto_req_handle_t req)
+aes_mac_verify_atomic(crypto_mechanism_t *mechanism, crypto_key_t *key,
+ crypto_data_t *data, crypto_data_t *mac, crypto_spi_ctx_template_t template)
{
CK_AES_GCM_PARAMS gcm_params;
crypto_mechanism_t gcm_mech;
@@ -1428,6 +1336,6 @@ aes_mac_verify_atomic(crypto_provider_handle_t provider,
gcm_mech.cm_param_len = sizeof (CK_AES_GCM_PARAMS);
gcm_mech.cm_param = (char *)&gcm_params;
- return (aes_decrypt_atomic(provider, session_id, &gcm_mech,
- key, mac, &null_crypto_data, template, req));
+ return (aes_decrypt_atomic(&gcm_mech,
+ key, mac, &null_crypto_data, template));
}
diff --git a/sys/contrib/openzfs/module/icp/io/sha2_mod.c b/sys/contrib/openzfs/module/icp/io/sha2_mod.c
index a43c7c5b7b8e..c586c3272647 100644
--- a/sys/contrib/openzfs/module/icp/io/sha2_mod.c
+++ b/sys/contrib/openzfs/module/icp/io/sha2_mod.c
@@ -63,86 +63,56 @@
static const crypto_mech_info_t sha2_mech_info_tab[] = {
/* SHA256 */
{SUN_CKM_SHA256, SHA256_MECH_INFO_TYPE,
- CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC,
- 0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS},
+ CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC},
/* SHA256-HMAC */
{SUN_CKM_SHA256_HMAC, SHA256_HMAC_MECH_INFO_TYPE,
- CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC,
- SHA2_HMAC_MIN_KEY_LEN, SHA2_HMAC_MAX_KEY_LEN,
- CRYPTO_KEYSIZE_UNIT_IN_BYTES},
+ CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC},
/* SHA256-HMAC GENERAL */
{SUN_CKM_SHA256_HMAC_GENERAL, SHA256_HMAC_GEN_MECH_INFO_TYPE,
- CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC,
- SHA2_HMAC_MIN_KEY_LEN, SHA2_HMAC_MAX_KEY_LEN,
- CRYPTO_KEYSIZE_UNIT_IN_BYTES},
+ CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC},
/* SHA384 */
{SUN_CKM_SHA384, SHA384_MECH_INFO_TYPE,
- CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC,
- 0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS},
+ CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC},
/* SHA384-HMAC */
{SUN_CKM_SHA384_HMAC, SHA384_HMAC_MECH_INFO_TYPE,
- CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC,
- SHA2_HMAC_MIN_KEY_LEN, SHA2_HMAC_MAX_KEY_LEN,
- CRYPTO_KEYSIZE_UNIT_IN_BYTES},
+ CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC},
/* SHA384-HMAC GENERAL */
{SUN_CKM_SHA384_HMAC_GENERAL, SHA384_HMAC_GEN_MECH_INFO_TYPE,
- CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC,
- SHA2_HMAC_MIN_KEY_LEN, SHA2_HMAC_MAX_KEY_LEN,
- CRYPTO_KEYSIZE_UNIT_IN_BYTES},
+ CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC},
/* SHA512 */
{SUN_CKM_SHA512, SHA512_MECH_INFO_TYPE,
- CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC,
- 0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS},
+ CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC},
/* SHA512-HMAC */
{SUN_CKM_SHA512_HMAC, SHA512_HMAC_MECH_INFO_TYPE,
- CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC,
- SHA2_HMAC_MIN_KEY_LEN, SHA2_HMAC_MAX_KEY_LEN,
- CRYPTO_KEYSIZE_UNIT_IN_BYTES},
+ CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC},
/* SHA512-HMAC GENERAL */
{SUN_CKM_SHA512_HMAC_GENERAL, SHA512_HMAC_GEN_MECH_INFO_TYPE,
- CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC,
- SHA2_HMAC_MIN_KEY_LEN, SHA2_HMAC_MAX_KEY_LEN,
- CRYPTO_KEYSIZE_UNIT_IN_BYTES}
+ CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC},
};
-static void sha2_provider_status(crypto_provider_handle_t, uint_t *);
-
-static const crypto_control_ops_t sha2_control_ops = {
- sha2_provider_status
-};
-
-static int sha2_digest_init(crypto_ctx_t *, crypto_mechanism_t *,
- crypto_req_handle_t);
-static int sha2_digest(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
- crypto_req_handle_t);
-static int sha2_digest_update(crypto_ctx_t *, crypto_data_t *,
- crypto_req_handle_t);
-static int sha2_digest_final(crypto_ctx_t *, crypto_data_t *,
- crypto_req_handle_t);
-static int sha2_digest_atomic(crypto_provider_handle_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_data_t *, crypto_data_t *,
- crypto_req_handle_t);
+static int sha2_digest_init(crypto_ctx_t *, crypto_mechanism_t *);
+static int sha2_digest(crypto_ctx_t *, crypto_data_t *, crypto_data_t *);
+static int sha2_digest_update(crypto_ctx_t *, crypto_data_t *);
+static int sha2_digest_final(crypto_ctx_t *, crypto_data_t *);
+static int sha2_digest_atomic(crypto_mechanism_t *, crypto_data_t *,
+ crypto_data_t *);
static const crypto_digest_ops_t sha2_digest_ops = {
.digest_init = sha2_digest_init,
.digest = sha2_digest,
.digest_update = sha2_digest_update,
- .digest_key = NULL,
.digest_final = sha2_digest_final,
.digest_atomic = sha2_digest_atomic
};
static int sha2_mac_init(crypto_ctx_t *, crypto_mechanism_t *, crypto_key_t *,
- crypto_spi_ctx_template_t, crypto_req_handle_t);
-static int sha2_mac_update(crypto_ctx_t *, crypto_data_t *,
- crypto_req_handle_t);
-static int sha2_mac_final(crypto_ctx_t *, crypto_data_t *, crypto_req_handle_t);
-static int sha2_mac_atomic(crypto_provider_handle_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
- crypto_spi_ctx_template_t, crypto_req_handle_t);
-static int sha2_mac_verify_atomic(crypto_provider_handle_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
- crypto_spi_ctx_template_t, crypto_req_handle_t);
+ crypto_spi_ctx_template_t);
+static int sha2_mac_update(crypto_ctx_t *, crypto_data_t *);
+static int sha2_mac_final(crypto_ctx_t *, crypto_data_t *);
+static int sha2_mac_atomic(crypto_mechanism_t *, crypto_key_t *,
+ crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t);
+static int sha2_mac_verify_atomic(crypto_mechanism_t *, crypto_key_t *,
+ crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t);
static const crypto_mac_ops_t sha2_mac_ops = {
.mac_init = sha2_mac_init,
@@ -153,9 +123,8 @@ static const crypto_mac_ops_t sha2_mac_ops = {
.mac_verify_atomic = sha2_mac_verify_atomic
};
-static int sha2_create_ctx_template(crypto_provider_handle_t,
- crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t *,
- size_t *, crypto_req_handle_t);
+static int sha2_create_ctx_template(crypto_mechanism_t *, crypto_key_t *,
+ crypto_spi_ctx_template_t *, size_t *);
static int sha2_free_context(crypto_ctx_t *);
static const crypto_ctx_ops_t sha2_ctx_ops = {
@@ -163,32 +132,19 @@ static const crypto_ctx_ops_t sha2_ctx_ops = {
.free_context = sha2_free_context
};
-static const crypto_ops_t sha2_crypto_ops = {{{{{
- &sha2_control_ops,
+static const crypto_ops_t sha2_crypto_ops = {
&sha2_digest_ops,
NULL,
&sha2_mac_ops,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- &sha2_ctx_ops
-}}}}};
+ &sha2_ctx_ops,
+};
-static const crypto_provider_info_t sha2_prov_info = {{{{
- CRYPTO_SPI_VERSION_1,
+static const crypto_provider_info_t sha2_prov_info = {
"SHA2 Software Provider",
- CRYPTO_SW_PROVIDER,
- NULL,
&sha2_crypto_ops,
sizeof (sha2_mech_info_tab) / sizeof (crypto_mech_info_t),
sha2_mech_info_tab
-}}}};
+};
static crypto_kcf_provider_handle_t sha2_prov_handle = 0;
@@ -230,29 +186,17 @@ sha2_mod_fini(void)
}
/*
- * KCF software provider control entry points.
- */
-static void
-sha2_provider_status(crypto_provider_handle_t provider, uint_t *status)
-{
- (void) provider;
- *status = CRYPTO_PROVIDER_READY;
-}
-
-/*
* KCF software provider digest entry points.
*/
static int
-sha2_digest_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
- crypto_req_handle_t req)
+sha2_digest_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism)
{
/*
* Allocate and initialize SHA2 context.
*/
- ctx->cc_provider_private = kmem_alloc(sizeof (sha2_ctx_t),
- crypto_kmflag(req));
+ ctx->cc_provider_private = kmem_alloc(sizeof (sha2_ctx_t), KM_SLEEP);
if (ctx->cc_provider_private == NULL)
return (CRYPTO_HOST_MEMORY);
@@ -417,10 +361,8 @@ sha2_digest_final_uio(SHA2_CTX *sha2_ctx, crypto_data_t *digest,
}
static int
-sha2_digest(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *digest,
- crypto_req_handle_t req)
+sha2_digest(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *digest)
{
- (void) req;
int ret = CRYPTO_SUCCESS;
uint_t sha_digest_len;
@@ -505,10 +447,8 @@ sha2_digest(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *digest,
}
static int
-sha2_digest_update(crypto_ctx_t *ctx, crypto_data_t *data,
- crypto_req_handle_t req)
+sha2_digest_update(crypto_ctx_t *ctx, crypto_data_t *data)
{
- (void) req;
int ret = CRYPTO_SUCCESS;
ASSERT(ctx->cc_provider_private != NULL);
@@ -534,10 +474,8 @@ sha2_digest_update(crypto_ctx_t *ctx, crypto_data_t *data,
}
static int
-sha2_digest_final(crypto_ctx_t *ctx, crypto_data_t *digest,
- crypto_req_handle_t req)
+sha2_digest_final(crypto_ctx_t *ctx, crypto_data_t *digest)
{
- (void) req;
int ret = CRYPTO_SUCCESS;
uint_t sha_digest_len;
@@ -597,12 +535,9 @@ sha2_digest_final(crypto_ctx_t *ctx, crypto_data_t *digest,
}
static int
-sha2_digest_atomic(crypto_provider_handle_t provider,
- crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
- crypto_data_t *data, crypto_data_t *digest,
- crypto_req_handle_t req)
+sha2_digest_atomic(crypto_mechanism_t *mechanism, crypto_data_t *data,
+ crypto_data_t *digest)
{
- (void) provider, (void) session_id, (void) req;
int ret = CRYPTO_SUCCESS;
SHA2_CTX sha2_ctx;
uint32_t sha_digest_len;
@@ -710,8 +645,13 @@ sha2_mac_init_ctx(sha2_hmac_ctx_t *ctx, void *keyval, uint_t length_in_bytes)
(void) bzero(ipad, block_size);
(void) bzero(opad, block_size);
- (void) bcopy(keyval, ipad, length_in_bytes);
- (void) bcopy(keyval, opad, length_in_bytes);
+
+ if (keyval != NULL) {
+ (void) bcopy(keyval, ipad, length_in_bytes);
+ (void) bcopy(keyval, opad, length_in_bytes);
+ } else {
+ ASSERT0(length_in_bytes);
+ }
/* XOR key with ipad (0x36) and opad (0x5c) */
for (i = 0; i < blocks_per_int64; i ++) {
@@ -733,8 +673,7 @@ sha2_mac_init_ctx(sha2_hmac_ctx_t *ctx, void *keyval, uint_t length_in_bytes)
*/
static int
sha2_mac_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
- crypto_key_t *key, crypto_spi_ctx_template_t ctx_template,
- crypto_req_handle_t req)
+ crypto_key_t *key, crypto_spi_ctx_template_t ctx_template)
{
int ret = CRYPTO_SUCCESS;
uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
@@ -761,11 +700,8 @@ sha2_mac_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
return (CRYPTO_MECHANISM_INVALID);
}
- if (key->ck_format != CRYPTO_KEY_RAW)
- return (CRYPTO_ARGUMENTS_BAD);
-
- ctx->cc_provider_private = kmem_alloc(sizeof (sha2_hmac_ctx_t),
- crypto_kmflag(req));
+ ctx->cc_provider_private =
+ kmem_alloc(sizeof (sha2_hmac_ctx_t), KM_SLEEP);
if (ctx->cc_provider_private == NULL)
return (CRYPTO_HOST_MEMORY);
@@ -819,10 +755,8 @@ sha2_mac_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
}
static int
-sha2_mac_update(crypto_ctx_t *ctx, crypto_data_t *data,
- crypto_req_handle_t req)
+sha2_mac_update(crypto_ctx_t *ctx, crypto_data_t *data)
{
- (void) req;
int ret = CRYPTO_SUCCESS;
ASSERT(ctx->cc_provider_private != NULL);
@@ -849,9 +783,8 @@ sha2_mac_update(crypto_ctx_t *ctx, crypto_data_t *data,
}
static int
-sha2_mac_final(crypto_ctx_t *ctx, crypto_data_t *mac, crypto_req_handle_t req)
+sha2_mac_final(crypto_ctx_t *ctx, crypto_data_t *mac)
{
- (void) req;
int ret = CRYPTO_SUCCESS;
uchar_t digest[SHA512_DIGEST_LENGTH];
uint32_t digest_len, sha_digest_len;
@@ -962,12 +895,10 @@ sha2_mac_final(crypto_ctx_t *ctx, crypto_data_t *mac, crypto_req_handle_t req)
}
static int
-sha2_mac_atomic(crypto_provider_handle_t provider,
- crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
+sha2_mac_atomic(crypto_mechanism_t *mechanism,
crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
- crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req)
+ crypto_spi_ctx_template_t ctx_template)
{
- (void) provider, (void) session_id, (void) req;
int ret = CRYPTO_SUCCESS;
uchar_t digest[SHA512_DIGEST_LENGTH];
sha2_hmac_ctx_t sha2_hmac_ctx;
@@ -995,10 +926,6 @@ sha2_mac_atomic(crypto_provider_handle_t provider,
return (CRYPTO_MECHANISM_INVALID);
}
- /* Add support for key by attributes (RFE 4706552) */
- if (key->ck_format != CRYPTO_KEY_RAW)
- return (CRYPTO_ARGUMENTS_BAD);
-
if (ctx_template != NULL) {
/* reuse context template */
bcopy(ctx_template, &sha2_hmac_ctx, sizeof (sha2_hmac_ctx_t));
@@ -1100,12 +1027,10 @@ bail:
}
static int
-sha2_mac_verify_atomic(crypto_provider_handle_t provider,
- crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
+sha2_mac_verify_atomic(crypto_mechanism_t *mechanism,
crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
- crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req)
+ crypto_spi_ctx_template_t ctx_template)
{
- (void) provider, (void) session_id, (void) req;
int ret = CRYPTO_SUCCESS;
uchar_t digest[SHA512_DIGEST_LENGTH];
sha2_hmac_ctx_t sha2_hmac_ctx;
@@ -1133,10 +1058,6 @@ sha2_mac_verify_atomic(crypto_provider_handle_t provider,
return (CRYPTO_MECHANISM_INVALID);
}
- /* Add support for key by attributes (RFE 4706552) */
- if (key->ck_format != CRYPTO_KEY_RAW)
- return (CRYPTO_ARGUMENTS_BAD);
-
if (ctx_template != NULL) {
/* reuse context template */
bcopy(ctx_template, &sha2_hmac_ctx, sizeof (sha2_hmac_ctx_t));
@@ -1280,12 +1201,9 @@ bail:
*/
static int
-sha2_create_ctx_template(crypto_provider_handle_t provider,
- crypto_mechanism_t *mechanism, crypto_key_t *key,
- crypto_spi_ctx_template_t *ctx_template, size_t *ctx_template_size,
- crypto_req_handle_t req)
+sha2_create_ctx_template(crypto_mechanism_t *mechanism, crypto_key_t *key,
+ crypto_spi_ctx_template_t *ctx_template, size_t *ctx_template_size)
{
- (void) provider;
sha2_hmac_ctx_t *sha2_hmac_ctx_tmpl;
uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
uint32_t sha_digest_len, sha_hmac_block_size;
@@ -1311,15 +1229,10 @@ sha2_create_ctx_template(crypto_provider_handle_t provider,
return (CRYPTO_MECHANISM_INVALID);
}
- /* Add support for key by attributes (RFE 4706552) */
- if (key->ck_format != CRYPTO_KEY_RAW)
- return (CRYPTO_ARGUMENTS_BAD);
-
/*
* Allocate and initialize SHA2 context.
*/
- sha2_hmac_ctx_tmpl = kmem_alloc(sizeof (sha2_hmac_ctx_t),
- crypto_kmflag(req));
+ sha2_hmac_ctx_tmpl = kmem_alloc(sizeof (sha2_hmac_ctx_t), KM_SLEEP);
if (sha2_hmac_ctx_tmpl == NULL)
return (CRYPTO_HOST_MEMORY);
diff --git a/sys/contrib/openzfs/module/icp/io/skein_mod.c b/sys/contrib/openzfs/module/icp/io/skein_mod.c
index d0917e71b12e..1d6969e68862 100644
--- a/sys/contrib/openzfs/module/icp/io/skein_mod.c
+++ b/sys/contrib/openzfs/module/icp/io/skein_mod.c
@@ -32,55 +32,38 @@
static const crypto_mech_info_t skein_mech_info_tab[] = {
{CKM_SKEIN_256, SKEIN_256_MECH_INFO_TYPE,
- CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC,
- 0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS},
+ CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC},
{CKM_SKEIN_256_MAC, SKEIN_256_MAC_MECH_INFO_TYPE,
- CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC, 1, INT_MAX,
- CRYPTO_KEYSIZE_UNIT_IN_BYTES},
+ CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC},
{CKM_SKEIN_512, SKEIN_512_MECH_INFO_TYPE,
- CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC,
- 0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS},
+ CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC},
{CKM_SKEIN_512_MAC, SKEIN_512_MAC_MECH_INFO_TYPE,
- CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC, 1, INT_MAX,
- CRYPTO_KEYSIZE_UNIT_IN_BYTES},
+ CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC},
{CKM_SKEIN1024, SKEIN1024_MECH_INFO_TYPE,
- CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC,
- 0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS},
+ CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC},
{CKM_SKEIN1024_MAC, SKEIN1024_MAC_MECH_INFO_TYPE,
- CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC, 1, INT_MAX,
- CRYPTO_KEYSIZE_UNIT_IN_BYTES}
+ CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC},
};
-static void skein_provider_status(crypto_provider_handle_t, uint_t *);
-
-static const crypto_control_ops_t skein_control_ops = {
- skein_provider_status
-};
-
-static int skein_digest_init(crypto_ctx_t *, crypto_mechanism_t *,
- crypto_req_handle_t);
-static int skein_digest(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
- crypto_req_handle_t);
-static int skein_update(crypto_ctx_t *, crypto_data_t *, crypto_req_handle_t);
-static int skein_final(crypto_ctx_t *, crypto_data_t *, crypto_req_handle_t);
-static int skein_digest_atomic(crypto_provider_handle_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_data_t *, crypto_data_t *,
- crypto_req_handle_t);
+static int skein_digest_init(crypto_ctx_t *, crypto_mechanism_t *);
+static int skein_digest(crypto_ctx_t *, crypto_data_t *, crypto_data_t *);
+static int skein_update(crypto_ctx_t *, crypto_data_t *);
+static int skein_final(crypto_ctx_t *, crypto_data_t *);
+static int skein_digest_atomic(crypto_mechanism_t *, crypto_data_t *,
+ crypto_data_t *);
static const crypto_digest_ops_t skein_digest_ops = {
.digest_init = skein_digest_init,
.digest = skein_digest,
.digest_update = skein_update,
- .digest_key = NULL,
.digest_final = skein_final,
.digest_atomic = skein_digest_atomic
};
static int skein_mac_init(crypto_ctx_t *, crypto_mechanism_t *, crypto_key_t *,
- crypto_spi_ctx_template_t, crypto_req_handle_t);
-static int skein_mac_atomic(crypto_provider_handle_t, crypto_session_id_t,
- crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
- crypto_spi_ctx_template_t, crypto_req_handle_t);
+ crypto_spi_ctx_template_t);
+static int skein_mac_atomic(crypto_mechanism_t *, crypto_key_t *,
+ crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t);
static const crypto_mac_ops_t skein_mac_ops = {
.mac_init = skein_mac_init,
@@ -91,9 +74,8 @@ static const crypto_mac_ops_t skein_mac_ops = {
.mac_verify_atomic = NULL
};
-static int skein_create_ctx_template(crypto_provider_handle_t,
- crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t *,
- size_t *, crypto_req_handle_t);
+static int skein_create_ctx_template(crypto_mechanism_t *, crypto_key_t *,
+ crypto_spi_ctx_template_t *, size_t *);
static int skein_free_context(crypto_ctx_t *);
static const crypto_ctx_ops_t skein_ctx_ops = {
@@ -101,32 +83,19 @@ static const crypto_ctx_ops_t skein_ctx_ops = {
.free_context = skein_free_context
};
-static const crypto_ops_t skein_crypto_ops = {{{{{
- &skein_control_ops,
+static const crypto_ops_t skein_crypto_ops = {
&skein_digest_ops,
NULL,
&skein_mac_ops,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
&skein_ctx_ops,
-}}}}};
+};
-static const crypto_provider_info_t skein_prov_info = {{{{
- CRYPTO_SPI_VERSION_1,
+static const crypto_provider_info_t skein_prov_info = {
"Skein Software Provider",
- CRYPTO_SW_PROVIDER,
- NULL,
&skein_crypto_ops,
sizeof (skein_mech_info_tab) / sizeof (crypto_mech_info_t),
skein_mech_info_tab
-}}}};
+};
static crypto_kcf_provider_handle_t skein_prov_handle = 0;
@@ -223,16 +192,6 @@ skein_mod_fini(void)
}
/*
- * KCF software provider control entry points.
- */
-static void
-skein_provider_status(crypto_provider_handle_t provider, uint_t *status)
-{
- (void) provider;
- *status = CRYPTO_PROVIDER_READY;
-}
-
-/*
* General Skein hashing helper functions.
*/
@@ -293,8 +252,7 @@ skein_digest_update_uio(skein_ctx_t *ctx, const crypto_data_t *data)
* Performs a Final on a context and writes to a uio digest output.
*/
static int
-skein_digest_final_uio(skein_ctx_t *ctx, crypto_data_t *digest,
- crypto_req_handle_t req)
+skein_digest_final_uio(skein_ctx_t *ctx, crypto_data_t *digest)
{
off_t offset = digest->cd_offset;
uint_t vec_idx = 0;
@@ -327,7 +285,7 @@ skein_digest_final_uio(skein_ctx_t *ctx, crypto_data_t *digest,
size_t cur_len;
digest_tmp = kmem_alloc(CRYPTO_BITS2BYTES(
- ctx->sc_digest_bitlen), crypto_kmflag(req));
+ ctx->sc_digest_bitlen), KM_SLEEP);
if (digest_tmp == NULL)
return (CRYPTO_HOST_MEMORY);
SKEIN_OP(ctx, Final, digest_tmp);
@@ -371,16 +329,14 @@ skein_digest_final_uio(skein_ctx_t *ctx, crypto_data_t *digest,
* for Skein-1024).
*/
static int
-skein_digest_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
- crypto_req_handle_t req)
+skein_digest_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism)
{
int error = CRYPTO_SUCCESS;
if (!VALID_SKEIN_DIGEST_MECH(mechanism->cm_type))
return (CRYPTO_MECHANISM_INVALID);
- SKEIN_CTX_LVALUE(ctx) = kmem_alloc(sizeof (*SKEIN_CTX(ctx)),
- crypto_kmflag(req));
+ SKEIN_CTX_LVALUE(ctx) = kmem_alloc(sizeof (*SKEIN_CTX(ctx)), KM_SLEEP);
if (SKEIN_CTX(ctx) == NULL)
return (CRYPTO_HOST_MEMORY);
@@ -405,8 +361,7 @@ errout:
* see what to pass here.
*/
static int
-skein_digest(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *digest,
- crypto_req_handle_t req)
+skein_digest(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *digest)
{
int error = CRYPTO_SUCCESS;
@@ -419,7 +374,7 @@ skein_digest(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *digest,
return (CRYPTO_BUFFER_TOO_SMALL);
}
- error = skein_update(ctx, data, req);
+ error = skein_update(ctx, data);
if (error != CRYPTO_SUCCESS) {
bzero(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
kmem_free(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
@@ -427,7 +382,7 @@ skein_digest(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *digest,
digest->cd_length = 0;
return (error);
}
- error = skein_final(ctx, digest, req);
+ error = skein_final(ctx, digest);
return (error);
}
@@ -438,9 +393,8 @@ skein_digest(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *digest,
* Supported input data formats are raw, uio and mblk.
*/
static int
-skein_update(crypto_ctx_t *ctx, crypto_data_t *data, crypto_req_handle_t req)
+skein_update(crypto_ctx_t *ctx, crypto_data_t *data)
{
- (void) req;
int error = CRYPTO_SUCCESS;
ASSERT(SKEIN_CTX(ctx) != NULL);
@@ -467,7 +421,7 @@ skein_update(crypto_ctx_t *ctx, crypto_data_t *data, crypto_req_handle_t req)
* Supported output digest formats are raw, uio and mblk.
*/
static int
-skein_final(crypto_ctx_t *ctx, crypto_data_t *digest, crypto_req_handle_t req)
+skein_final(crypto_ctx_t *ctx, crypto_data_t *digest)
{
int error = CRYPTO_SUCCESS;
@@ -486,7 +440,7 @@ skein_final(crypto_ctx_t *ctx, crypto_data_t *digest, crypto_req_handle_t req)
(uint8_t *)digest->cd_raw.iov_base + digest->cd_offset);
break;
case CRYPTO_DATA_UIO:
- error = skein_digest_final_uio(SKEIN_CTX(ctx), digest, req);
+ error = skein_digest_final_uio(SKEIN_CTX(ctx), digest);
break;
default:
error = CRYPTO_ARGUMENTS_BAD;
@@ -512,11 +466,9 @@ skein_final(crypto_ctx_t *ctx, crypto_data_t *digest, crypto_req_handle_t req)
* Supported input/output formats are raw, uio and mblk.
*/
static int
-skein_digest_atomic(crypto_provider_handle_t provider,
- crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
- crypto_data_t *data, crypto_data_t *digest, crypto_req_handle_t req)
+skein_digest_atomic(crypto_mechanism_t *mechanism, crypto_data_t *data,
+ crypto_data_t *digest)
{
- (void) provider, (void) session_id, (void) req;
int error;
skein_ctx_t skein_ctx;
crypto_ctx_t ctx;
@@ -531,9 +483,9 @@ skein_digest_atomic(crypto_provider_handle_t provider,
goto out;
SKEIN_OP(&skein_ctx, Init, skein_ctx.sc_digest_bitlen);
- if ((error = skein_update(&ctx, data, digest)) != CRYPTO_SUCCESS)
+ if ((error = skein_update(&ctx, data)) != CRYPTO_SUCCESS)
goto out;
- if ((error = skein_final(&ctx, data, digest)) != CRYPTO_SUCCESS)
+ if ((error = skein_final(&ctx, data)) != CRYPTO_SUCCESS)
goto out;
out:
@@ -559,8 +511,6 @@ skein_mac_ctx_build(skein_ctx_t *ctx, crypto_mechanism_t *mechanism,
if (!VALID_SKEIN_MAC_MECH(mechanism->cm_type))
return (CRYPTO_MECHANISM_INVALID);
- if (key->ck_format != CRYPTO_KEY_RAW)
- return (CRYPTO_ARGUMENTS_BAD);
ctx->sc_mech_type = mechanism->cm_type;
error = skein_get_digest_bitlen(mechanism, &ctx->sc_digest_bitlen);
if (error != CRYPTO_SUCCESS)
@@ -584,13 +534,11 @@ skein_mac_ctx_build(skein_ctx_t *ctx, crypto_mechanism_t *mechanism,
*/
static int
skein_mac_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
- crypto_key_t *key, crypto_spi_ctx_template_t ctx_template,
- crypto_req_handle_t req)
+ crypto_key_t *key, crypto_spi_ctx_template_t ctx_template)
{
int error;
- SKEIN_CTX_LVALUE(ctx) = kmem_alloc(sizeof (*SKEIN_CTX(ctx)),
- crypto_kmflag(req));
+ SKEIN_CTX_LVALUE(ctx) = kmem_alloc(sizeof (*SKEIN_CTX(ctx)), KM_SLEEP);
if (SKEIN_CTX(ctx) == NULL)
return (CRYPTO_HOST_MEMORY);
@@ -620,13 +568,11 @@ errout:
* function as to those of the partial operations above.
*/
static int
-skein_mac_atomic(crypto_provider_handle_t provider,
- crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
+skein_mac_atomic(crypto_mechanism_t *mechanism,
crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
- crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req)
+ crypto_spi_ctx_template_t ctx_template)
{
/* faux crypto context just for skein_digest_{update,final} */
- (void) provider, (void) session_id;
int error;
crypto_ctx_t ctx;
skein_ctx_t skein_ctx;
@@ -640,9 +586,9 @@ skein_mac_atomic(crypto_provider_handle_t provider,
goto errout;
}
- if ((error = skein_update(&ctx, data, req)) != CRYPTO_SUCCESS)
+ if ((error = skein_update(&ctx, data)) != CRYPTO_SUCCESS)
goto errout;
- if ((error = skein_final(&ctx, mac, req)) != CRYPTO_SUCCESS)
+ if ((error = skein_final(&ctx, mac)) != CRYPTO_SUCCESS)
goto errout;
return (CRYPTO_SUCCESS);
@@ -661,16 +607,13 @@ errout:
* skein_mac_init.
*/
static int
-skein_create_ctx_template(crypto_provider_handle_t provider,
- crypto_mechanism_t *mechanism, crypto_key_t *key,
- crypto_spi_ctx_template_t *ctx_template, size_t *ctx_template_size,
- crypto_req_handle_t req)
+skein_create_ctx_template(crypto_mechanism_t *mechanism, crypto_key_t *key,
+ crypto_spi_ctx_template_t *ctx_template, size_t *ctx_template_size)
{
- (void) provider;
int error;
skein_ctx_t *ctx_tmpl;
- ctx_tmpl = kmem_alloc(sizeof (*ctx_tmpl), crypto_kmflag(req));
+ ctx_tmpl = kmem_alloc(sizeof (*ctx_tmpl), KM_SLEEP);
if (ctx_tmpl == NULL)
return (CRYPTO_HOST_MEMORY);
error = skein_mac_ctx_build(ctx_tmpl, mechanism, key);
diff --git a/sys/contrib/openzfs/module/icp/os/modhash.c b/sys/contrib/openzfs/module/icp/os/modhash.c
deleted file mode 100644
index 8bd06973eff1..000000000000
--- a/sys/contrib/openzfs/module/icp/os/modhash.c
+++ /dev/null
@@ -1,927 +0,0 @@
-/*
- * 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 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * mod_hash: flexible hash table implementation.
- *
- * This is a reasonably fast, reasonably flexible hash table implementation
- * which features pluggable hash algorithms to support storing arbitrary keys
- * and values. It is designed to handle small (< 100,000 items) amounts of
- * data. The hash uses chaining to resolve collisions, and does not feature a
- * mechanism to grow the hash. Care must be taken to pick nchains to be large
- * enough for the application at hand, or lots of time will be wasted searching
- * hash chains.
- *
- * The client of the hash is required to supply a number of items to support
- * the various hash functions:
- *
- * - Destructor functions for the key and value being hashed.
- * A destructor is responsible for freeing an object when the hash
- * table is no longer storing it. Since keys and values can be of
- * arbitrary type, separate destructors for keys & values are used.
- * These may be mod_hash_null_keydtor and mod_hash_null_valdtor if no
- * destructor is needed for either a key or value.
- *
- * - A hashing algorithm which returns a uint_t representing a hash index
- * The number returned need _not_ be between 0 and nchains. The mod_hash
- * code will take care of doing that. The second argument (after the
- * key) to the hashing function is a void * that represents
- * hash_alg_data-- this is provided so that the hashing algorithm can
- * maintain some state across calls, or keep algorithm-specific
- * constants associated with the hash table.
- *
- * A pointer-hashing and a string-hashing algorithm are supplied in
- * this file.
- *
- * - A key comparator (a la qsort).
- * This is used when searching the hash chain. The key comparator
- * determines if two keys match. It should follow the return value
- * semantics of strcmp.
- *
- * string and pointer comparators are supplied in this file.
- *
- * mod_hash_create_strhash() and mod_hash_create_ptrhash() provide good
- * examples of how to create a customized hash table.
- *
- * Basic hash operations:
- *
- * mod_hash_create_strhash(name, nchains, dtor),
- * create a hash using strings as keys.
- * NOTE: This create a hash which automatically cleans up the string
- * values it is given for keys.
- *
- * mod_hash_create_ptrhash(name, nchains, dtor, key_elem_size):
- * create a hash using pointers as keys.
- *
- * mod_hash_create_extended(name, nchains, kdtor, vdtor,
- * hash_alg, hash_alg_data,
- * keycmp, sleep)
- * create a customized hash table.
- *
- * mod_hash_destroy_hash(hash):
- * destroy the given hash table, calling the key and value destructors
- * on each key-value pair stored in the hash.
- *
- * mod_hash_insert(hash, key, val):
- * place a key, value pair into the given hash.
- * duplicate keys are rejected.
- *
- * mod_hash_insert_reserve(hash, key, val, handle):
- * place a key, value pair into the given hash, using handle to indicate
- * the reserved storage for the pair. (no memory allocation is needed
- * during a mod_hash_insert_reserve.) duplicate keys are rejected.
- *
- * mod_hash_reserve(hash, *handle):
- * reserve storage for a key-value pair using the memory allocation
- * policy of 'hash', returning the storage handle in 'handle'.
- *
- * mod_hash_reserve_nosleep(hash, *handle): reserve storage for a key-value
- * pair ignoring the memory allocation policy of 'hash' and always without
- * sleep, returning the storage handle in 'handle'.
- *
- * mod_hash_remove(hash, key, *val):
- * remove a key-value pair with key 'key' from 'hash', destroying the
- * stored key, and returning the value in val.
- *
- * mod_hash_replace(hash, key, val)
- * atomically remove an existing key-value pair from a hash, and replace
- * the key and value with the ones supplied. The removed key and value
- * (if any) are destroyed.
- *
- * mod_hash_destroy(hash, key):
- * remove a key-value pair with key 'key' from 'hash', destroying both
- * stored key and stored value.
- *
- * mod_hash_find(hash, key, val):
- * find a value in the hash table corresponding to the given key.
- *
- * mod_hash_find_cb(hash, key, val, found_callback)
- * find a value in the hash table corresponding to the given key.
- * If a value is found, call specified callback passing key and val to it.
- * The callback is called with the hash lock held.
- * It is intended to be used in situations where the act of locating the
- * data must also modify it - such as in reference counting schemes.
- *
- * mod_hash_walk(hash, callback(key, elem, arg), arg)
- * walks all the elements in the hashtable and invokes the callback
- * function with the key/value pair for each element. the hashtable
- * is locked for readers so the callback function should not attempt
- * to do any updates to the hashable. the callback function should
- * return MH_WALK_CONTINUE to continue walking the hashtable or
- * MH_WALK_TERMINATE to abort the walk of the hashtable.
- *
- * mod_hash_clear(hash):
- * clears the given hash table of entries, calling the key and value
- * destructors for every element in the hash.
- */
-
-#include <sys/zfs_context.h>
-#include <sys/bitmap.h>
-#include <sys/modhash_impl.h>
-#include <sys/sysmacros.h>
-
-/*
- * MH_KEY_DESTROY()
- * Invoke the key destructor.
- */
-#define MH_KEY_DESTROY(hash, key) ((hash->mh_kdtor)(key))
-
-/*
- * MH_VAL_DESTROY()
- * Invoke the value destructor.
- */
-#define MH_VAL_DESTROY(hash, val) ((hash->mh_vdtor)(val))
-
-/*
- * MH_KEYCMP()
- * Call the key comparator for the given hash keys.
- */
-#define MH_KEYCMP(hash, key1, key2) ((hash->mh_keycmp)(key1, key2))
-
-/*
- * Cache for struct mod_hash_entry
- */
-kmem_cache_t *mh_e_cache = NULL;
-mod_hash_t *mh_head = NULL;
-kmutex_t mh_head_lock;
-
-/*
- * mod_hash_null_keydtor()
- * mod_hash_null_valdtor()
- * no-op key and value destructors.
- */
-void
-mod_hash_null_keydtor(mod_hash_key_t key)
-{
- (void) key;
-}
-
-void
-mod_hash_null_valdtor(mod_hash_val_t val)
-{
- (void) val;
-}
-
-/*
- * mod_hash_bystr()
- * mod_hash_strkey_cmp()
- * mod_hash_strkey_dtor()
- * mod_hash_strval_dtor()
- * Hash and key comparison routines for hashes with string keys.
- *
- * mod_hash_create_strhash()
- * Create a hash using strings as keys
- *
- * The string hashing algorithm is from the "Dragon Book" --
- * "Compilers: Principles, Tools & Techniques", by Aho, Sethi, Ullman
- */
-
-uint_t
-mod_hash_bystr(void *hash_data, mod_hash_key_t key)
-{
- (void) hash_data;
- uint_t hash = 0;
- uint_t g;
- char *p, *k = (char *)key;
-
- ASSERT(k);
- for (p = k; *p != '\0'; p++) {
- hash = (hash << 4) + *p;
- if ((g = (hash & 0xf0000000)) != 0) {
- hash ^= (g >> 24);
- hash ^= g;
- }
- }
- return (hash);
-}
-
-int
-mod_hash_strkey_cmp(mod_hash_key_t key1, mod_hash_key_t key2)
-{
- return (strcmp((char *)key1, (char *)key2));
-}
-
-void
-mod_hash_strkey_dtor(mod_hash_key_t key)
-{
- char *c = (char *)key;
- kmem_free(c, strlen(c) + 1);
-}
-
-void
-mod_hash_strval_dtor(mod_hash_val_t val)
-{
- char *c = (char *)val;
- kmem_free(c, strlen(c) + 1);
-}
-
-mod_hash_t *
-mod_hash_create_strhash_nodtr(char *name, size_t nchains,
- void (*val_dtor)(mod_hash_val_t))
-{
- return mod_hash_create_extended(name, nchains, mod_hash_null_keydtor,
- val_dtor, mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
-}
-
-mod_hash_t *
-mod_hash_create_strhash(char *name, size_t nchains,
- void (*val_dtor)(mod_hash_val_t))
-{
- return mod_hash_create_extended(name, nchains, mod_hash_strkey_dtor,
- val_dtor, mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
-}
-
-void
-mod_hash_destroy_strhash(mod_hash_t *strhash)
-{
- ASSERT(strhash);
- mod_hash_destroy_hash(strhash);
-}
-
-
-/*
- * mod_hash_byptr()
- * mod_hash_ptrkey_cmp()
- * Hash and key comparison routines for hashes with pointer keys.
- *
- * mod_hash_create_ptrhash()
- * mod_hash_destroy_ptrhash()
- * Create a hash that uses pointers as keys. This hash algorithm
- * picks an appropriate set of middle bits in the address to hash on
- * based on the size of the hash table and a hint about the size of
- * the items pointed at.
- */
-uint_t
-mod_hash_byptr(void *hash_data, mod_hash_key_t key)
-{
- uintptr_t k = (uintptr_t)key;
- k >>= (int)(uintptr_t)hash_data;
-
- return ((uint_t)k);
-}
-
-int
-mod_hash_ptrkey_cmp(mod_hash_key_t key1, mod_hash_key_t key2)
-{
- uintptr_t k1 = (uintptr_t)key1;
- uintptr_t k2 = (uintptr_t)key2;
- if (k1 > k2)
- return (-1);
- else if (k1 < k2)
- return (1);
- else
- return (0);
-}
-
-mod_hash_t *
-mod_hash_create_ptrhash(char *name, size_t nchains,
- void (*val_dtor)(mod_hash_val_t), size_t key_elem_size)
-{
- size_t rshift;
-
- /*
- * We want to hash on the bits in the middle of the address word
- * Bits far to the right in the word have little significance, and
- * are likely to all look the same (for example, an array of
- * 256-byte structures will have the bottom 8 bits of address
- * words the same). So we want to right-shift each address to
- * ignore the bottom bits.
- *
- * The high bits, which are also unused, will get taken out when
- * mod_hash takes hashkey % nchains.
- */
- rshift = highbit64(key_elem_size);
-
- return mod_hash_create_extended(name, nchains, mod_hash_null_keydtor,
- val_dtor, mod_hash_byptr, (void *)rshift, mod_hash_ptrkey_cmp,
- KM_SLEEP);
-}
-
-void
-mod_hash_destroy_ptrhash(mod_hash_t *hash)
-{
- ASSERT(hash);
- mod_hash_destroy_hash(hash);
-}
-
-/*
- * mod_hash_byid()
- * mod_hash_idkey_cmp()
- * Hash and key comparison routines for hashes with 32-bit unsigned keys.
- *
- * mod_hash_create_idhash()
- * mod_hash_destroy_idhash()
- * mod_hash_iddata_gen()
- * Create a hash that uses numeric keys.
- *
- * The hash algorithm is documented in "Introduction to Algorithms"
- * (Cormen, Leiserson, Rivest); when the hash table is created, it
- * attempts to find the next largest prime above the number of hash
- * slots. The hash index is then this number times the key modulo
- * the hash size, or (key * prime) % nchains.
- */
-uint_t
-mod_hash_byid(void *hash_data, mod_hash_key_t key)
-{
- uint_t kval = (uint_t)(uintptr_t)hash_data;
- return ((uint_t)(uintptr_t)key * (uint_t)kval);
-}
-
-int
-mod_hash_idkey_cmp(mod_hash_key_t key1, mod_hash_key_t key2)
-{
- return ((uint_t)(uintptr_t)key1 - (uint_t)(uintptr_t)key2);
-}
-
-/*
- * Generate the next largest prime number greater than nchains; this value
- * is intended to be later passed in to mod_hash_create_extended() as the
- * hash_data.
- */
-uint_t
-mod_hash_iddata_gen(size_t nchains)
-{
- uint_t kval, i, prime;
-
- /*
- * Pick the first (odd) prime greater than nchains. Make sure kval is
- * odd (so start with nchains +1 or +2 as appropriate).
- */
- kval = (nchains % 2 == 0) ? nchains + 1 : nchains + 2;
-
- for (;;) {
- prime = 1;
- for (i = 3; i * i <= kval; i += 2) {
- if (kval % i == 0)
- prime = 0;
- }
- if (prime == 1)
- break;
- kval += 2;
- }
- return (kval);
-}
-
-mod_hash_t *
-mod_hash_create_idhash(char *name, size_t nchains,
- void (*val_dtor)(mod_hash_val_t))
-{
- uint_t kval = mod_hash_iddata_gen(nchains);
-
- return (mod_hash_create_extended(name, nchains, mod_hash_null_keydtor,
- val_dtor, mod_hash_byid, (void *)(uintptr_t)kval,
- mod_hash_idkey_cmp, KM_SLEEP));
-}
-
-void
-mod_hash_destroy_idhash(mod_hash_t *hash)
-{
- ASSERT(hash);
- mod_hash_destroy_hash(hash);
-}
-
-void
-mod_hash_fini(void)
-{
- mutex_destroy(&mh_head_lock);
-
- if (mh_e_cache) {
- kmem_cache_destroy(mh_e_cache);
- mh_e_cache = NULL;
- }
-}
-
-/*
- * mod_hash_init()
- * sets up globals, etc for mod_hash_*
- */
-void
-mod_hash_init(void)
-{
- ASSERT(mh_e_cache == NULL);
- mh_e_cache = kmem_cache_create("mod_hash_entries",
- sizeof (struct mod_hash_entry), 0, NULL, NULL, NULL, NULL,
- NULL, 0);
-
- mutex_init(&mh_head_lock, NULL, MUTEX_DEFAULT, NULL);
-}
-
-/*
- * mod_hash_create_extended()
- * The full-blown hash creation function.
- *
- * notes:
- * nchains - how many hash slots to create. More hash slots will
- * result in shorter hash chains, but will consume
- * slightly more memory up front.
- * sleep - should be KM_SLEEP or KM_NOSLEEP, to indicate whether
- * to sleep for memory, or fail in low-memory conditions.
- *
- * Fails only if KM_NOSLEEP was specified, and no memory was available.
- */
-mod_hash_t *
-mod_hash_create_extended(
- char *hname, /* descriptive name for hash */
- size_t nchains, /* number of hash slots */
- void (*kdtor)(mod_hash_key_t), /* key destructor */
- void (*vdtor)(mod_hash_val_t), /* value destructor */
- uint_t (*hash_alg)(void *, mod_hash_key_t), /* hash algorithm */
- void *hash_alg_data, /* pass-thru arg for hash_alg */
- int (*keycmp)(mod_hash_key_t, mod_hash_key_t), /* key comparator */
- int sleep) /* whether to sleep for mem */
-{
- mod_hash_t *mod_hash;
- size_t size;
- ASSERT(hname && keycmp && hash_alg && vdtor && kdtor);
-
- if ((mod_hash = kmem_zalloc(MH_SIZE(nchains), sleep)) == NULL)
- return (NULL);
-
- size = strlen(hname) + 1;
- mod_hash->mh_name = kmem_alloc(size, sleep);
- if (mod_hash->mh_name == NULL) {
- kmem_free(mod_hash, MH_SIZE(nchains));
- return (NULL);
- }
- (void) strlcpy(mod_hash->mh_name, hname, size);
-
- rw_init(&mod_hash->mh_contents, NULL, RW_DEFAULT, NULL);
- mod_hash->mh_sleep = sleep;
- mod_hash->mh_nchains = nchains;
- mod_hash->mh_kdtor = kdtor;
- mod_hash->mh_vdtor = vdtor;
- mod_hash->mh_hashalg = hash_alg;
- mod_hash->mh_hashalg_data = hash_alg_data;
- mod_hash->mh_keycmp = keycmp;
-
- /*
- * Link the hash up on the list of hashes
- */
- mutex_enter(&mh_head_lock);
- mod_hash->mh_next = mh_head;
- mh_head = mod_hash;
- mutex_exit(&mh_head_lock);
-
- return (mod_hash);
-}
-
-/*
- * mod_hash_destroy_hash()
- * destroy a hash table, destroying all of its stored keys and values
- * as well.
- */
-void
-mod_hash_destroy_hash(mod_hash_t *hash)
-{
- mod_hash_t *mhp, *mhpp;
-
- mutex_enter(&mh_head_lock);
- /*
- * Remove the hash from the hash list
- */
- if (hash == mh_head) { /* removing 1st list elem */
- mh_head = mh_head->mh_next;
- } else {
- /*
- * mhpp can start out NULL since we know the 1st elem isn't the
- * droid we're looking for.
- */
- mhpp = NULL;
- for (mhp = mh_head; mhp != NULL; mhp = mhp->mh_next) {
- if (mhp == hash) {
- mhpp->mh_next = mhp->mh_next;
- break;
- }
- mhpp = mhp;
- }
- }
- mutex_exit(&mh_head_lock);
-
- /*
- * Clean out keys and values.
- */
- mod_hash_clear(hash);
-
- rw_destroy(&hash->mh_contents);
- kmem_free(hash->mh_name, strlen(hash->mh_name) + 1);
- kmem_free(hash, MH_SIZE(hash->mh_nchains));
-}
-
-/*
- * i_mod_hash()
- * Call the hashing algorithm for this hash table, with the given key.
- */
-uint_t
-i_mod_hash(mod_hash_t *hash, mod_hash_key_t key)
-{
- uint_t h;
- /*
- * Prevent div by 0 problems;
- * Also a nice shortcut when using a hash as a list
- */
- if (hash->mh_nchains == 1)
- return (0);
-
- h = (hash->mh_hashalg)(hash->mh_hashalg_data, key);
- return (h % (hash->mh_nchains - 1));
-}
-
-/*
- * i_mod_hash_insert_nosync()
- * mod_hash_insert()
- * mod_hash_insert_reserve()
- * insert 'val' into the hash table, using 'key' as its key. If 'key' is
- * already a key in the hash, an error will be returned, and the key-val
- * pair will not be inserted. i_mod_hash_insert_nosync() supports a simple
- * handle abstraction, allowing hash entry allocation to be separated from
- * the hash insertion. this abstraction allows simple use of the mod_hash
- * structure in situations where mod_hash_insert() with a KM_SLEEP
- * allocation policy would otherwise be unsafe.
- */
-int
-i_mod_hash_insert_nosync(mod_hash_t *hash, mod_hash_key_t key,
- mod_hash_val_t val, mod_hash_hndl_t handle)
-{
- uint_t hashidx;
- struct mod_hash_entry *entry;
-
- ASSERT(hash);
-
- /*
- * If we've not been given reserved storage, allocate storage directly,
- * using the hash's allocation policy.
- */
- if (handle == (mod_hash_hndl_t)0) {
- entry = kmem_cache_alloc(mh_e_cache, hash->mh_sleep);
- if (entry == NULL) {
- hash->mh_stat.mhs_nomem++;
- return (MH_ERR_NOMEM);
- }
- } else {
- entry = (struct mod_hash_entry *)handle;
- }
-
- hashidx = i_mod_hash(hash, key);
- entry->mhe_key = key;
- entry->mhe_val = val;
- entry->mhe_next = hash->mh_entries[hashidx];
-
- hash->mh_entries[hashidx] = entry;
- hash->mh_stat.mhs_nelems++;
-
- return (0);
-}
-
-int
-mod_hash_insert(mod_hash_t *hash, mod_hash_key_t key, mod_hash_val_t val)
-{
- int res;
- mod_hash_val_t v;
-
- rw_enter(&hash->mh_contents, RW_WRITER);
-
- /*
- * Disallow duplicate keys in the hash
- */
- if (i_mod_hash_find_nosync(hash, key, &v) == 0) {
- rw_exit(&hash->mh_contents);
- hash->mh_stat.mhs_coll++;
- return (MH_ERR_DUPLICATE);
- }
-
- res = i_mod_hash_insert_nosync(hash, key, val, (mod_hash_hndl_t)0);
- rw_exit(&hash->mh_contents);
-
- return (res);
-}
-
-int
-mod_hash_insert_reserve(mod_hash_t *hash, mod_hash_key_t key,
- mod_hash_val_t val, mod_hash_hndl_t handle)
-{
- int res;
- mod_hash_val_t v;
-
- rw_enter(&hash->mh_contents, RW_WRITER);
-
- /*
- * Disallow duplicate keys in the hash
- */
- if (i_mod_hash_find_nosync(hash, key, &v) == 0) {
- rw_exit(&hash->mh_contents);
- hash->mh_stat.mhs_coll++;
- return (MH_ERR_DUPLICATE);
- }
- res = i_mod_hash_insert_nosync(hash, key, val, handle);
- rw_exit(&hash->mh_contents);
-
- return (res);
-}
-
-/*
- * mod_hash_reserve()
- * mod_hash_reserve_nosleep()
- * mod_hash_cancel()
- * Make or cancel a mod_hash_entry_t reservation. Reservations are used in
- * mod_hash_insert_reserve() above.
- */
-int
-mod_hash_reserve(mod_hash_t *hash, mod_hash_hndl_t *handlep)
-{
- *handlep = kmem_cache_alloc(mh_e_cache, hash->mh_sleep);
- if (*handlep == NULL) {
- hash->mh_stat.mhs_nomem++;
- return (MH_ERR_NOMEM);
- }
-
- return (0);
-}
-
-int
-mod_hash_reserve_nosleep(mod_hash_t *hash, mod_hash_hndl_t *handlep)
-{
- *handlep = kmem_cache_alloc(mh_e_cache, KM_NOSLEEP);
- if (*handlep == NULL) {
- hash->mh_stat.mhs_nomem++;
- return (MH_ERR_NOMEM);
- }
-
- return (0);
-
-}
-
-void
-mod_hash_cancel(mod_hash_t *hash, mod_hash_hndl_t *handlep)
-{
- (void) hash;
- kmem_cache_free(mh_e_cache, *handlep);
- *handlep = (mod_hash_hndl_t)0;
-}
-
-/*
- * i_mod_hash_remove_nosync()
- * mod_hash_remove()
- * Remove an element from the hash table.
- */
-int
-i_mod_hash_remove_nosync(mod_hash_t *hash, mod_hash_key_t key,
- mod_hash_val_t *val)
-{
- int hashidx;
- struct mod_hash_entry *e, *ep;
-
- hashidx = i_mod_hash(hash, key);
- ep = NULL; /* e's parent */
-
- for (e = hash->mh_entries[hashidx]; e != NULL; e = e->mhe_next) {
- if (MH_KEYCMP(hash, e->mhe_key, key) == 0)
- break;
- ep = e;
- }
-
- if (e == NULL) { /* not found */
- return (MH_ERR_NOTFOUND);
- }
-
- if (ep == NULL) /* special case 1st element in bucket */
- hash->mh_entries[hashidx] = e->mhe_next;
- else
- ep->mhe_next = e->mhe_next;
-
- /*
- * Clean up resources used by the node's key.
- */
- MH_KEY_DESTROY(hash, e->mhe_key);
-
- *val = e->mhe_val;
- kmem_cache_free(mh_e_cache, e);
- hash->mh_stat.mhs_nelems--;
-
- return (0);
-}
-
-int
-mod_hash_remove(mod_hash_t *hash, mod_hash_key_t key, mod_hash_val_t *val)
-{
- int res;
-
- rw_enter(&hash->mh_contents, RW_WRITER);
- res = i_mod_hash_remove_nosync(hash, key, val);
- rw_exit(&hash->mh_contents);
-
- return (res);
-}
-
-/*
- * mod_hash_replace()
- * atomically remove an existing key-value pair from a hash, and replace
- * the key and value with the ones supplied. The removed key and value
- * (if any) are destroyed.
- */
-int
-mod_hash_replace(mod_hash_t *hash, mod_hash_key_t key, mod_hash_val_t val)
-{
- int res;
- mod_hash_val_t v;
-
- rw_enter(&hash->mh_contents, RW_WRITER);
-
- if (i_mod_hash_remove_nosync(hash, key, &v) == 0) {
- /*
- * mod_hash_remove() takes care of freeing up the key resources.
- */
- MH_VAL_DESTROY(hash, v);
- }
- res = i_mod_hash_insert_nosync(hash, key, val, (mod_hash_hndl_t)0);
-
- rw_exit(&hash->mh_contents);
-
- return (res);
-}
-
-/*
- * mod_hash_destroy()
- * Remove an element from the hash table matching 'key', and destroy it.
- */
-int
-mod_hash_destroy(mod_hash_t *hash, mod_hash_key_t key)
-{
- mod_hash_val_t val;
- int rv;
-
- rw_enter(&hash->mh_contents, RW_WRITER);
-
- if ((rv = i_mod_hash_remove_nosync(hash, key, &val)) == 0) {
- /*
- * mod_hash_remove() takes care of freeing up the key resources.
- */
- MH_VAL_DESTROY(hash, val);
- }
-
- rw_exit(&hash->mh_contents);
- return (rv);
-}
-
-/*
- * i_mod_hash_find_nosync()
- * mod_hash_find()
- * Find a value in the hash table corresponding to the given key.
- */
-int
-i_mod_hash_find_nosync(mod_hash_t *hash, mod_hash_key_t key,
- mod_hash_val_t *val)
-{
- uint_t hashidx;
- struct mod_hash_entry *e;
-
- hashidx = i_mod_hash(hash, key);
-
- for (e = hash->mh_entries[hashidx]; e != NULL; e = e->mhe_next) {
- if (MH_KEYCMP(hash, e->mhe_key, key) == 0) {
- *val = e->mhe_val;
- hash->mh_stat.mhs_hit++;
- return (0);
- }
- }
- hash->mh_stat.mhs_miss++;
- return (MH_ERR_NOTFOUND);
-}
-
-int
-mod_hash_find(mod_hash_t *hash, mod_hash_key_t key, mod_hash_val_t *val)
-{
- int res;
-
- rw_enter(&hash->mh_contents, RW_READER);
- res = i_mod_hash_find_nosync(hash, key, val);
- rw_exit(&hash->mh_contents);
-
- return (res);
-}
-
-int
-mod_hash_find_cb(mod_hash_t *hash, mod_hash_key_t key, mod_hash_val_t *val,
- void (*find_cb)(mod_hash_key_t, mod_hash_val_t))
-{
- int res;
-
- rw_enter(&hash->mh_contents, RW_READER);
- res = i_mod_hash_find_nosync(hash, key, val);
- if (res == 0) {
- find_cb(key, *val);
- }
- rw_exit(&hash->mh_contents);
-
- return (res);
-}
-
-int
-mod_hash_find_cb_rval(mod_hash_t *hash, mod_hash_key_t key, mod_hash_val_t *val,
- int (*find_cb)(mod_hash_key_t, mod_hash_val_t), int *cb_rval)
-{
- int res;
-
- rw_enter(&hash->mh_contents, RW_READER);
- res = i_mod_hash_find_nosync(hash, key, val);
- if (res == 0) {
- *cb_rval = find_cb(key, *val);
- }
- rw_exit(&hash->mh_contents);
-
- return (res);
-}
-
-void
-i_mod_hash_walk_nosync(mod_hash_t *hash,
- uint_t (*callback)(mod_hash_key_t, mod_hash_val_t *, void *), void *arg)
-{
- struct mod_hash_entry *e;
- uint_t hashidx;
- int res = MH_WALK_CONTINUE;
-
- for (hashidx = 0;
- (hashidx < (hash->mh_nchains - 1)) && (res == MH_WALK_CONTINUE);
- hashidx++) {
- e = hash->mh_entries[hashidx];
- while ((e != NULL) && (res == MH_WALK_CONTINUE)) {
- res = callback(e->mhe_key, e->mhe_val, arg);
- e = e->mhe_next;
- }
- }
-}
-
-/*
- * mod_hash_walk()
- * Walks all the elements in the hashtable and invokes the callback
- * function with the key/value pair for each element. The hashtable
- * is locked for readers so the callback function should not attempt
- * to do any updates to the hashable. The callback function should
- * return MH_WALK_CONTINUE to continue walking the hashtable or
- * MH_WALK_TERMINATE to abort the walk of the hashtable.
- */
-void
-mod_hash_walk(mod_hash_t *hash,
- uint_t (*callback)(mod_hash_key_t, mod_hash_val_t *, void *), void *arg)
-{
- rw_enter(&hash->mh_contents, RW_READER);
- i_mod_hash_walk_nosync(hash, callback, arg);
- rw_exit(&hash->mh_contents);
-}
-
-
-/*
- * i_mod_hash_clear_nosync()
- * mod_hash_clear()
- * Clears the given hash table by calling the destructor of every hash
- * element and freeing up all mod_hash_entry's.
- */
-void
-i_mod_hash_clear_nosync(mod_hash_t *hash)
-{
- int i;
- struct mod_hash_entry *e, *old_e;
-
- for (i = 0; i < hash->mh_nchains; i++) {
- e = hash->mh_entries[i];
- while (e != NULL) {
- MH_KEY_DESTROY(hash, e->mhe_key);
- MH_VAL_DESTROY(hash, e->mhe_val);
- old_e = e;
- e = e->mhe_next;
- kmem_cache_free(mh_e_cache, old_e);
- }
- hash->mh_entries[i] = NULL;
- }
- hash->mh_stat.mhs_nelems = 0;
-}
-
-void
-mod_hash_clear(mod_hash_t *hash)
-{
- ASSERT(hash);
- rw_enter(&hash->mh_contents, RW_WRITER);
- i_mod_hash_clear_nosync(hash);
- rw_exit(&hash->mh_contents);
-}
diff --git a/sys/contrib/openzfs/module/icp/spi/kcf_spi.c b/sys/contrib/openzfs/module/icp/spi/kcf_spi.c
index 25fe9b5b66be..87e765d4786c 100644
--- a/sys/contrib/openzfs/module/icp/spi/kcf_spi.c
+++ b/sys/contrib/openzfs/module/icp/spi/kcf_spi.c
@@ -36,145 +36,35 @@
#include <sys/crypto/sched_impl.h>
#include <sys/crypto/spi.h>
-/*
- * minalloc and maxalloc values to be used for taskq_create().
- */
-const int crypto_taskq_threads = CRYPTO_TASKQ_THREADS;
-const int crypto_taskq_minalloc = CRYPTO_TASKQ_MIN;
-const int crypto_taskq_maxalloc = CRYPTO_TASKQ_MAX;
-
-static void remove_provider(kcf_provider_desc_t *);
-static void process_logical_providers(const crypto_provider_info_t *,
- kcf_provider_desc_t *);
static int init_prov_mechs(const crypto_provider_info_t *,
kcf_provider_desc_t *);
-static int kcf_prov_kstat_update(kstat_t *, int);
-static void delete_kstat(kcf_provider_desc_t *);
-
-static const kcf_prov_stats_t kcf_stats_ks_data_template = {
- { "kcf_ops_total", KSTAT_DATA_UINT64 },
- { "kcf_ops_passed", KSTAT_DATA_UINT64 },
- { "kcf_ops_failed", KSTAT_DATA_UINT64 },
- { "kcf_ops_returned_busy", KSTAT_DATA_UINT64 }
-};
-
-#define KCF_SPI_COPY_OPS(src, dst, ops) if ((src)->ops != NULL) \
- memcpy((void *) (dst)->ops, (src)->ops, sizeof (*(src)->ops));
-
-/*
- * Copy an ops vector from src to dst. Used during provider registration
- * to copy the ops vector from the provider info structure to the
- * provider descriptor maintained by KCF.
- * Copying the ops vector specified by the provider is needed since the
- * framework does not require the provider info structure to be
- * persistent.
- */
-static void
-copy_ops_vector_v1(const crypto_ops_t *src_ops, crypto_ops_t *dst_ops)
-{
- KCF_SPI_COPY_OPS(src_ops, dst_ops, co_control_ops);
- KCF_SPI_COPY_OPS(src_ops, dst_ops, co_digest_ops);
- KCF_SPI_COPY_OPS(src_ops, dst_ops, co_cipher_ops);
- KCF_SPI_COPY_OPS(src_ops, dst_ops, co_mac_ops);
- KCF_SPI_COPY_OPS(src_ops, dst_ops, co_sign_ops);
- KCF_SPI_COPY_OPS(src_ops, dst_ops, co_verify_ops);
- KCF_SPI_COPY_OPS(src_ops, dst_ops, co_dual_ops);
- KCF_SPI_COPY_OPS(src_ops, dst_ops, co_dual_cipher_mac_ops);
- KCF_SPI_COPY_OPS(src_ops, dst_ops, co_random_ops);
- KCF_SPI_COPY_OPS(src_ops, dst_ops, co_session_ops);
- KCF_SPI_COPY_OPS(src_ops, dst_ops, co_object_ops);
- KCF_SPI_COPY_OPS(src_ops, dst_ops, co_key_ops);
- KCF_SPI_COPY_OPS(src_ops, dst_ops, co_provider_ops);
- KCF_SPI_COPY_OPS(src_ops, dst_ops, co_ctx_ops);
-}
-
-static void
-copy_ops_vector_v2(const crypto_ops_t *src_ops, crypto_ops_t *dst_ops)
-{
- KCF_SPI_COPY_OPS(src_ops, dst_ops, co_mech_ops);
-}
-
-static void
-copy_ops_vector_v3(const crypto_ops_t *src_ops, crypto_ops_t *dst_ops)
-{
- KCF_SPI_COPY_OPS(src_ops, dst_ops, co_nostore_key_ops);
-}
/*
* This routine is used to add cryptographic providers to the KEF framework.
* Providers pass a crypto_provider_info structure to crypto_register_provider()
* and get back a handle. The crypto_provider_info structure contains a
* list of mechanisms supported by the provider and an ops vector containing
- * provider entry points. Hardware providers call this routine in their attach
- * routines. Software providers call this routine in their _init() routine.
+ * provider entry points. Providers call this routine in their _init() routine.
*/
int
crypto_register_provider(const crypto_provider_info_t *info,
crypto_kcf_provider_handle_t *handle)
{
- char *ks_name;
-
kcf_provider_desc_t *prov_desc = NULL;
int ret = CRYPTO_ARGUMENTS_BAD;
- if (info->pi_interface_version > CRYPTO_SPI_VERSION_3)
- return (CRYPTO_VERSION_MISMATCH);
-
- /*
- * Check provider type, must be software, hardware, or logical.
- */
- if (info->pi_provider_type != CRYPTO_HW_PROVIDER &&
- info->pi_provider_type != CRYPTO_SW_PROVIDER &&
- info->pi_provider_type != CRYPTO_LOGICAL_PROVIDER)
- return (CRYPTO_ARGUMENTS_BAD);
-
/*
* Allocate and initialize a new provider descriptor. We also
* hold it and release it when done.
*/
- prov_desc = kcf_alloc_provider_desc(info);
+ prov_desc = kcf_alloc_provider_desc();
KCF_PROV_REFHOLD(prov_desc);
- prov_desc->pd_prov_type = info->pi_provider_type;
-
- /* provider-private handle, opaque to KCF */
- prov_desc->pd_prov_handle = info->pi_provider_handle;
-
/* copy provider description string */
- if (info->pi_provider_description != NULL) {
- /*
- * pi_provider_descriptor is a string that can contain
- * up to CRYPTO_PROVIDER_DESCR_MAX_LEN + 1 characters
- * INCLUDING the terminating null character. A bcopy()
- * is necessary here as pd_description should not have
- * a null character. See comments in kcf_alloc_provider_desc()
- * for details on pd_description field.
- */
- bcopy(info->pi_provider_description, prov_desc->pd_description,
- MIN(strlen(info->pi_provider_description),
- (size_t)CRYPTO_PROVIDER_DESCR_MAX_LEN));
- }
+ prov_desc->pd_description = info->pi_provider_description;
- if (info->pi_provider_type != CRYPTO_LOGICAL_PROVIDER) {
- if (info->pi_ops_vector == NULL) {
- goto bail;
- }
- crypto_ops_t *pvec = (crypto_ops_t *)prov_desc->pd_ops_vector;
- copy_ops_vector_v1(info->pi_ops_vector, pvec);
- if (info->pi_interface_version >= CRYPTO_SPI_VERSION_2) {
- copy_ops_vector_v2(info->pi_ops_vector, pvec);
- prov_desc->pd_flags = info->pi_flags;
- }
- if (info->pi_interface_version == CRYPTO_SPI_VERSION_3) {
- copy_ops_vector_v3(info->pi_ops_vector, pvec);
- }
- }
-
- /* object_ops and nostore_key_ops are mutually exclusive */
- if (prov_desc->pd_ops_vector->co_object_ops &&
- prov_desc->pd_ops_vector->co_nostore_key_ops) {
- goto bail;
- }
+ /* Change from Illumos: the ops vector is persistent. */
+ prov_desc->pd_ops_vector = info->pi_ops_vector;
/* process the mechanisms supported by the provider */
if ((ret = init_prov_mechs(info, prov_desc)) != CRYPTO_SUCCESS)
@@ -190,86 +80,15 @@ crypto_register_provider(const crypto_provider_info_t *info,
}
/*
- * We create a taskq only for a hardware provider. The global
- * software queue is used for software providers. We handle ordering
+ * The global queue is used for providers. We handle ordering
* of multi-part requests in the taskq routine. So, it is safe to
* have multiple threads for the taskq. We pass TASKQ_PREPOPULATE flag
* to keep some entries cached to improve performance.
*/
- if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
- prov_desc->pd_sched_info.ks_taskq = taskq_create("kcf_taskq",
- CRYPTO_TASKQ_THREADS, minclsyspri,
- CRYPTO_TASKQ_MIN, CRYPTO_TASKQ_MAX,
- TASKQ_PREPOPULATE);
- else
- prov_desc->pd_sched_info.ks_taskq = NULL;
-
- /* no kernel session to logical providers */
- if (prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
- /*
- * Open a session for session-oriented providers. This session
- * is used for all kernel consumers. This is fine as a provider
- * is required to support multiple thread access to a session.
- * We can do this only after the taskq has been created as we
- * do a kcf_submit_request() to open the session.
- */
- if (KCF_PROV_SESSION_OPS(prov_desc) != NULL) {
- kcf_req_params_t params;
-
- KCF_WRAP_SESSION_OPS_PARAMS(&params,
- KCF_OP_SESSION_OPEN, &prov_desc->pd_sid, 0,
- CRYPTO_USER, NULL, 0, prov_desc);
- ret = kcf_submit_request(prov_desc, NULL, NULL, &params,
- B_FALSE);
-
- if (ret != CRYPTO_SUCCESS) {
- undo_register_provider(prov_desc, B_TRUE);
- ret = CRYPTO_FAILED;
- goto bail;
- }
- }
- }
-
- if (prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
- /*
- * Create the kstat for this provider. There is a kstat
- * installed for each successfully registered provider.
- * This kstat is deleted, when the provider unregisters.
- */
- if (prov_desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
- ks_name = kmem_asprintf("%s_%s",
- "NONAME", "provider_stats");
- } else {
- ks_name = kmem_asprintf("%s_%d_%u_%s",
- "NONAME", 0, prov_desc->pd_prov_id,
- "provider_stats");
- }
-
- prov_desc->pd_kstat = kstat_create("kcf", 0, ks_name, "crypto",
- KSTAT_TYPE_NAMED, sizeof (kcf_prov_stats_t) /
- sizeof (kstat_named_t), KSTAT_FLAG_VIRTUAL);
-
- if (prov_desc->pd_kstat != NULL) {
- bcopy(&kcf_stats_ks_data_template,
- &prov_desc->pd_ks_data,
- sizeof (kcf_stats_ks_data_template));
- prov_desc->pd_kstat->ks_data = &prov_desc->pd_ks_data;
- KCF_PROV_REFHOLD(prov_desc);
- KCF_PROV_IREFHOLD(prov_desc);
- prov_desc->pd_kstat->ks_private = prov_desc;
- prov_desc->pd_kstat->ks_update = kcf_prov_kstat_update;
- kstat_install(prov_desc->pd_kstat);
- }
- kmem_strfree(ks_name);
- }
-
- if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
- process_logical_providers(info, prov_desc);
mutex_enter(&prov_desc->pd_lock);
prov_desc->pd_state = KCF_PROV_READY;
mutex_exit(&prov_desc->pd_lock);
- kcf_do_notify(prov_desc, B_TRUE);
*handle = prov_desc->pd_kcf_prov_handle;
ret = CRYPTO_SUCCESS;
@@ -281,8 +100,7 @@ bail:
/*
* This routine is used to notify the framework when a provider is being
- * removed. Hardware providers call this routine in their detach routines.
- * Software providers call this routine in their _fini() routine.
+ * removed. Providers call this routine in their _fini() routine.
*/
int
crypto_unregister_provider(crypto_kcf_provider_handle_t handle)
@@ -310,46 +128,30 @@ crypto_unregister_provider(crypto_kcf_provider_handle_t handle)
saved_state = desc->pd_state;
desc->pd_state = KCF_PROV_REMOVED;
- if (saved_state == KCF_PROV_BUSY) {
- /*
- * The per-provider taskq threads may be waiting. We
- * signal them so that they can start failing requests.
- */
- cv_broadcast(&desc->pd_resume_cv);
- }
-
- if (desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
+ /*
+ * Check if this provider is currently being used.
+ * pd_irefcnt is the number of holds from the internal
+ * structures. We add one to account for the above lookup.
+ */
+ if (desc->pd_refcnt > desc->pd_irefcnt + 1) {
+ desc->pd_state = saved_state;
+ mutex_exit(&desc->pd_lock);
+ /* Release reference held by kcf_prov_tab_lookup(). */
+ KCF_PROV_REFRELE(desc);
/*
- * Check if this provider is currently being used.
- * pd_irefcnt is the number of holds from the internal
- * structures. We add one to account for the above lookup.
+ * The administrator will presumably stop the clients,
+ * thus removing the holds, when they get the busy
+ * return value. Any retry will succeed then.
*/
- if (desc->pd_refcnt > desc->pd_irefcnt + 1) {
- desc->pd_state = saved_state;
- mutex_exit(&desc->pd_lock);
- /* Release reference held by kcf_prov_tab_lookup(). */
- KCF_PROV_REFRELE(desc);
- /*
- * The administrator presumably will stop the clients
- * thus removing the holds, when they get the busy
- * return value. Any retry will succeed then.
- */
- return (CRYPTO_BUSY);
- }
+ return (CRYPTO_BUSY);
}
mutex_exit(&desc->pd_lock);
- if (desc->pd_prov_type != CRYPTO_SW_PROVIDER) {
- remove_provider(desc);
- }
-
- if (desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
- /* remove the provider from the mechanisms tables */
- for (mech_idx = 0; mech_idx < desc->pd_mech_list_count;
- mech_idx++) {
- kcf_remove_mech_provider(
- desc->pd_mechanisms[mech_idx].cm_mech_name, desc);
- }
+ /* remove the provider from the mechanisms tables */
+ for (mech_idx = 0; mech_idx < desc->pd_mech_list_count;
+ mech_idx++) {
+ kcf_remove_mech_provider(
+ desc->pd_mechanisms[mech_idx].cm_mech_name, desc);
}
/* remove provider from providers table */
@@ -360,206 +162,34 @@ crypto_unregister_provider(crypto_kcf_provider_handle_t handle)
return (CRYPTO_UNKNOWN_PROVIDER);
}
- delete_kstat(desc);
-
- if (desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
- /* Release reference held by kcf_prov_tab_lookup(). */
- KCF_PROV_REFRELE(desc);
-
- /*
- * Wait till the existing requests complete.
- */
- mutex_enter(&desc->pd_lock);
- while (desc->pd_state != KCF_PROV_FREED)
- cv_wait(&desc->pd_remove_cv, &desc->pd_lock);
- mutex_exit(&desc->pd_lock);
- } else {
- /*
- * Wait until requests that have been sent to the provider
- * complete.
- */
- mutex_enter(&desc->pd_lock);
- while (desc->pd_irefcnt > 0)
- cv_wait(&desc->pd_remove_cv, &desc->pd_lock);
- mutex_exit(&desc->pd_lock);
- }
+ /* Release reference held by kcf_prov_tab_lookup(). */
+ KCF_PROV_REFRELE(desc);
- kcf_do_notify(desc, B_FALSE);
+ /*
+ * Wait till the existing requests complete.
+ */
+ mutex_enter(&desc->pd_lock);
+ while (desc->pd_state != KCF_PROV_FREED)
+ cv_wait(&desc->pd_remove_cv, &desc->pd_lock);
+ mutex_exit(&desc->pd_lock);
- if (desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
- /*
- * This is the only place where kcf_free_provider_desc()
- * is called directly. KCF_PROV_REFRELE() should free the
- * structure in all other places.
- */
- ASSERT(desc->pd_state == KCF_PROV_FREED &&
- desc->pd_refcnt == 0);
- kcf_free_provider_desc(desc);
- } else {
- KCF_PROV_REFRELE(desc);
- }
+ /*
+ * This is the only place where kcf_free_provider_desc()
+ * is called directly. KCF_PROV_REFRELE() should free the
+ * structure in all other places.
+ */
+ ASSERT(desc->pd_state == KCF_PROV_FREED &&
+ desc->pd_refcnt == 0);
+ kcf_free_provider_desc(desc);
return (CRYPTO_SUCCESS);
}
/*
- * This routine is used to notify the framework that the state of
- * a cryptographic provider has changed. Valid state codes are:
- *
- * CRYPTO_PROVIDER_READY
- * The provider indicates that it can process more requests. A provider
- * will notify with this event if it previously has notified us with a
- * CRYPTO_PROVIDER_BUSY.
- *
- * CRYPTO_PROVIDER_BUSY
- * The provider can not take more requests.
- *
- * CRYPTO_PROVIDER_FAILED
- * The provider encountered an internal error. The framework will not
- * be sending any more requests to the provider. The provider may notify
- * with a CRYPTO_PROVIDER_READY, if it is able to recover from the error.
- *
- * This routine can be called from user or interrupt context.
- */
-void
-crypto_provider_notification(crypto_kcf_provider_handle_t handle, uint_t state)
-{
- kcf_provider_desc_t *pd;
-
- /* lookup the provider from the given handle */
- if ((pd = kcf_prov_tab_lookup((crypto_provider_id_t)handle)) == NULL)
- return;
-
- mutex_enter(&pd->pd_lock);
-
- if (pd->pd_state <= KCF_PROV_VERIFICATION_FAILED)
- goto out;
-
- if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
- cmn_err(CE_WARN, "crypto_provider_notification: "
- "logical provider (%x) ignored\n", handle);
- goto out;
- }
- switch (state) {
- case CRYPTO_PROVIDER_READY:
- switch (pd->pd_state) {
- case KCF_PROV_BUSY:
- pd->pd_state = KCF_PROV_READY;
- /*
- * Signal the per-provider taskq threads that they
- * can start submitting requests.
- */
- cv_broadcast(&pd->pd_resume_cv);
- break;
-
- case KCF_PROV_FAILED:
- /*
- * The provider recovered from the error. Let us
- * use it now.
- */
- pd->pd_state = KCF_PROV_READY;
- break;
- default:
- break;
- }
- break;
-
- case CRYPTO_PROVIDER_BUSY:
- switch (pd->pd_state) {
- case KCF_PROV_READY:
- pd->pd_state = KCF_PROV_BUSY;
- break;
- default:
- break;
- }
- break;
-
- case CRYPTO_PROVIDER_FAILED:
- /*
- * We note the failure and return. The per-provider taskq
- * threads check this flag and start failing the
- * requests, if it is set. See process_req_hwp() for details.
- */
- switch (pd->pd_state) {
- case KCF_PROV_READY:
- pd->pd_state = KCF_PROV_FAILED;
- break;
-
- case KCF_PROV_BUSY:
- pd->pd_state = KCF_PROV_FAILED;
- /*
- * The per-provider taskq threads may be waiting. We
- * signal them so that they can start failing requests.
- */
- cv_broadcast(&pd->pd_resume_cv);
- break;
- default:
- break;
- }
- break;
- default:
- break;
- }
-out:
- mutex_exit(&pd->pd_lock);
- KCF_PROV_REFRELE(pd);
-}
-
-/*
- * This routine is used to notify the framework the result of
- * an asynchronous request handled by a provider. Valid error
- * codes are the same as the CRYPTO_* errors defined in common.h.
- *
- * This routine can be called from user or interrupt context.
- */
-void
-crypto_op_notification(crypto_req_handle_t handle, int error)
-{
- kcf_call_type_t ctype;
-
- if (handle == NULL)
- return;
-
- if ((ctype = GET_REQ_TYPE(handle)) == CRYPTO_SYNCH) {
- kcf_sreq_node_t *sreq = (kcf_sreq_node_t *)handle;
-
- if (error != CRYPTO_SUCCESS)
- sreq->sn_provider->pd_sched_info.ks_nfails++;
- KCF_PROV_IREFRELE(sreq->sn_provider);
- kcf_sop_done(sreq, error);
- } else {
- kcf_areq_node_t *areq = (kcf_areq_node_t *)handle;
-
- ASSERT(ctype == CRYPTO_ASYNCH);
- if (error != CRYPTO_SUCCESS)
- areq->an_provider->pd_sched_info.ks_nfails++;
- KCF_PROV_IREFRELE(areq->an_provider);
- kcf_aop_done(areq, error);
- }
-}
-
-/*
- * This routine is used by software providers to determine
- * whether to use KM_SLEEP or KM_NOSLEEP during memory allocation.
- * Note that hardware providers can always use KM_SLEEP. So,
- * they do not need to call this routine.
- *
- * This routine can be called from user or interrupt context.
- */
-int
-crypto_kmflag(crypto_req_handle_t handle)
-{
- return (REQHNDL2_KMFLAG(handle));
-}
-
-/*
* Process the mechanism info structures specified by the provider
* during registration. A NULL crypto_provider_info_t indicates
* an already initialized provider descriptor.
*
- * Mechanisms are not added to the kernel's mechanism table if the
- * provider is a logical provider.
- *
* Returns CRYPTO_SUCCESS on success, CRYPTO_ARGUMENTS if one
* of the specified mechanisms was malformed, or CRYPTO_HOST_MEMORY
* if the table of mechanisms is full.
@@ -572,16 +202,6 @@ init_prov_mechs(const crypto_provider_info_t *info, kcf_provider_desc_t *desc)
int err = CRYPTO_SUCCESS;
kcf_prov_mech_desc_t *pmd;
int desc_use_count = 0;
- int mcount = desc->pd_mech_list_count;
-
- if (desc->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
- if (info != NULL) {
- ASSERT(info->pi_mechanisms != NULL);
- bcopy(info->pi_mechanisms, desc->pd_mechanisms,
- sizeof (crypto_mech_info_t) * mcount);
- }
- return (CRYPTO_SUCCESS);
- }
/*
* Copy the mechanism list from the provider info to the provider
@@ -590,29 +210,9 @@ init_prov_mechs(const crypto_provider_info_t *info, kcf_provider_desc_t *desc)
* mechanism, SUN_RANDOM, in this case.
*/
if (info != NULL) {
- if (info->pi_ops_vector->co_random_ops != NULL) {
- crypto_mech_info_t *rand_mi;
-
- /*
- * Need the following check as it is possible to have
- * a provider that implements just random_ops and has
- * pi_mechanisms == NULL.
- */
- if (info->pi_mechanisms != NULL) {
- bcopy(info->pi_mechanisms, desc->pd_mechanisms,
- sizeof (crypto_mech_info_t) * (mcount - 1));
- }
- rand_mi = &desc->pd_mechanisms[mcount - 1];
-
- bzero(rand_mi, sizeof (crypto_mech_info_t));
- (void) strncpy(rand_mi->cm_mech_name, SUN_RANDOM,
- CRYPTO_MAX_MECH_NAME);
- rand_mi->cm_func_group_mask = CRYPTO_FG_RANDOM;
- } else {
- ASSERT(info->pi_mechanisms != NULL);
- bcopy(info->pi_mechanisms, desc->pd_mechanisms,
- sizeof (crypto_mech_info_t) * mcount);
- }
+ ASSERT(info->pi_mechanisms != NULL);
+ desc->pd_mech_list_count = info->pi_mech_list_count;
+ desc->pd_mechanisms = info->pi_mechanisms;
}
/*
@@ -620,32 +220,6 @@ init_prov_mechs(const crypto_provider_info_t *info, kcf_provider_desc_t *desc)
* to the corresponding KCF mechanism mech_entry chain.
*/
for (mech_idx = 0; mech_idx < desc->pd_mech_list_count; mech_idx++) {
- crypto_mech_info_t *mi = &desc->pd_mechanisms[mech_idx];
-
- if ((mi->cm_mech_flags & CRYPTO_KEYSIZE_UNIT_IN_BITS) &&
- (mi->cm_mech_flags & CRYPTO_KEYSIZE_UNIT_IN_BYTES)) {
- err = CRYPTO_ARGUMENTS_BAD;
- break;
- }
-
- if (desc->pd_flags & CRYPTO_HASH_NO_UPDATE &&
- mi->cm_func_group_mask & CRYPTO_FG_DIGEST) {
- /*
- * We ask the provider to specify the limit
- * per hash mechanism. But, in practice, a
- * hardware limitation means all hash mechanisms
- * will have the same maximum size allowed for
- * input data. So, we make it a per provider
- * limit to keep it simple.
- */
- if (mi->cm_max_input_length == 0) {
- err = CRYPTO_ARGUMENTS_BAD;
- break;
- } else {
- desc->pd_hash_limit = mi->cm_max_input_length;
- }
- }
-
if ((err = kcf_add_mech_provider(mech_idx, desc, &pmd)) !=
KCF_SUCCESS)
break;
@@ -658,12 +232,12 @@ init_prov_mechs(const crypto_provider_info_t *info, kcf_provider_desc_t *desc)
}
/*
- * Don't allow multiple software providers with disabled mechanisms
+ * Don't allow multiple providers with disabled mechanisms
* to register. Subsequent enabling of mechanisms will result in
- * an unsupported configuration, i.e. multiple software providers
+ * an unsupported configuration, i.e. multiple providers
* per mechanism.
*/
- if (desc_use_count == 0 && desc->pd_prov_type == CRYPTO_SW_PROVIDER)
+ if (desc_use_count == 0)
return (CRYPTO_ARGUMENTS_BAD);
if (err == KCF_SUCCESS)
@@ -685,35 +259,6 @@ init_prov_mechs(const crypto_provider_info_t *info, kcf_provider_desc_t *desc)
}
/*
- * Update routine for kstat. Only privileged users are allowed to
- * access this information, since this information is sensitive.
- * There are some cryptographic attacks (e.g. traffic analysis)
- * which can use this information.
- */
-static int
-kcf_prov_kstat_update(kstat_t *ksp, int rw)
-{
- kcf_prov_stats_t *ks_data;
- kcf_provider_desc_t *pd = (kcf_provider_desc_t *)ksp->ks_private;
-
- if (rw == KSTAT_WRITE)
- return (EACCES);
-
- ks_data = ksp->ks_data;
-
- ks_data->ps_ops_total.value.ui64 = pd->pd_sched_info.ks_ndispatches;
- ks_data->ps_ops_failed.value.ui64 = pd->pd_sched_info.ks_nfails;
- ks_data->ps_ops_busy_rval.value.ui64 = pd->pd_sched_info.ks_nbusy_rval;
- ks_data->ps_ops_passed.value.ui64 =
- pd->pd_sched_info.ks_ndispatches -
- pd->pd_sched_info.ks_nfails -
- pd->pd_sched_info.ks_nbusy_rval;
-
- return (0);
-}
-
-
-/*
* Utility routine called from failure paths in crypto_register_provider()
* and from crypto_load_soft_disabled().
*/
@@ -733,193 +278,3 @@ undo_register_provider(kcf_provider_desc_t *desc, boolean_t remove_prov)
if (remove_prov)
(void) kcf_prov_tab_rem_provider(desc->pd_prov_id);
}
-
-/*
- * Utility routine called from crypto_load_soft_disabled(). Callers
- * should have done a prior undo_register_provider().
- */
-void
-redo_register_provider(kcf_provider_desc_t *pd)
-{
- /* process the mechanisms supported by the provider */
- (void) init_prov_mechs(NULL, pd);
-
- /*
- * Hold provider in providers table. We should not call
- * kcf_prov_tab_add_provider() here as the provider descriptor
- * is still valid which means it has an entry in the provider
- * table.
- */
- KCF_PROV_REFHOLD(pd);
- KCF_PROV_IREFHOLD(pd);
-}
-
-/*
- * Add provider (p1) to another provider's array of providers (p2).
- * Hardware and logical providers use this array to cross-reference
- * each other.
- */
-static void
-add_provider_to_array(kcf_provider_desc_t *p1, kcf_provider_desc_t *p2)
-{
- kcf_provider_list_t *new;
-
- new = kmem_alloc(sizeof (kcf_provider_list_t), KM_SLEEP);
- mutex_enter(&p2->pd_lock);
- new->pl_next = p2->pd_provider_list;
- p2->pd_provider_list = new;
- KCF_PROV_IREFHOLD(p1);
- new->pl_provider = p1;
- mutex_exit(&p2->pd_lock);
-}
-
-/*
- * Remove provider (p1) from another provider's array of providers (p2).
- * Hardware and logical providers use this array to cross-reference
- * each other.
- */
-static void
-remove_provider_from_array(kcf_provider_desc_t *p1, kcf_provider_desc_t *p2)
-{
-
- kcf_provider_list_t *pl = NULL, **prev;
-
- mutex_enter(&p2->pd_lock);
- for (pl = p2->pd_provider_list, prev = &p2->pd_provider_list;
- pl != NULL; prev = &pl->pl_next, pl = pl->pl_next) {
- if (pl->pl_provider == p1) {
- break;
- }
- }
-
- if (p1 == NULL) {
- mutex_exit(&p2->pd_lock);
- return;
- }
-
- /* detach and free kcf_provider_list structure */
- KCF_PROV_IREFRELE(p1);
- *prev = pl->pl_next;
- kmem_free(pl, sizeof (*pl));
- mutex_exit(&p2->pd_lock);
-}
-
-/*
- * Convert an array of logical provider handles (crypto_provider_id)
- * stored in a crypto_provider_info structure into an array of provider
- * descriptors (kcf_provider_desc_t) attached to a logical provider.
- */
-static void
-process_logical_providers(const crypto_provider_info_t *info,
- kcf_provider_desc_t *hp)
-{
- kcf_provider_desc_t *lp;
- crypto_provider_id_t handle;
- int count = info->pi_logical_provider_count;
- int i;
-
- /* add hardware provider to each logical provider */
- for (i = 0; i < count; i++) {
- handle = info->pi_logical_providers[i];
- lp = kcf_prov_tab_lookup((crypto_provider_id_t)handle);
- if (lp == NULL) {
- continue;
- }
- add_provider_to_array(hp, lp);
- hp->pd_flags |= KCF_LPROV_MEMBER;
-
- /*
- * A hardware provider has to have the provider descriptor of
- * every logical provider it belongs to, so it can be removed
- * from the logical provider if the hardware provider
- * unregisters from the framework.
- */
- add_provider_to_array(lp, hp);
- KCF_PROV_REFRELE(lp);
- }
-}
-
-/*
- * This routine removes a provider from all of the logical or
- * hardware providers it belongs to, and frees the provider's
- * array of pointers to providers.
- */
-static void
-remove_provider(kcf_provider_desc_t *pp)
-{
- kcf_provider_desc_t *p;
- kcf_provider_list_t *e, *next;
-
- mutex_enter(&pp->pd_lock);
- for (e = pp->pd_provider_list; e != NULL; e = next) {
- p = e->pl_provider;
- remove_provider_from_array(pp, p);
- if (p->pd_prov_type == CRYPTO_HW_PROVIDER &&
- p->pd_provider_list == NULL)
- p->pd_flags &= ~KCF_LPROV_MEMBER;
- KCF_PROV_IREFRELE(p);
- next = e->pl_next;
- kmem_free(e, sizeof (*e));
- }
- pp->pd_provider_list = NULL;
- mutex_exit(&pp->pd_lock);
-}
-
-/*
- * Dispatch events as needed for a provider. is_added flag tells
- * whether the provider is registering or unregistering.
- */
-void
-kcf_do_notify(kcf_provider_desc_t *prov_desc, boolean_t is_added)
-{
- int i;
- crypto_notify_event_change_t ec;
-
- ASSERT(prov_desc->pd_state > KCF_PROV_VERIFICATION_FAILED);
-
- /*
- * Inform interested clients of the mechanisms becoming
- * available/unavailable. We skip this for logical providers
- * as they do not affect mechanisms.
- */
- if (prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
- ec.ec_provider_type = prov_desc->pd_prov_type;
- ec.ec_change = is_added ? CRYPTO_MECH_ADDED :
- CRYPTO_MECH_REMOVED;
- for (i = 0; i < prov_desc->pd_mech_list_count; i++) {
- (void) strlcpy(ec.ec_mech_name,
- prov_desc->pd_mechanisms[i].cm_mech_name,
- CRYPTO_MAX_MECH_NAME);
- kcf_walk_ntfylist(CRYPTO_EVENT_MECHS_CHANGED, &ec);
- }
-
- }
-
- /*
- * Inform interested clients about the new or departing provider.
- * In case of a logical provider, we need to notify the event only
- * for the logical provider and not for the underlying
- * providers which are known by the KCF_LPROV_MEMBER bit.
- */
- if (prov_desc->pd_prov_type == CRYPTO_LOGICAL_PROVIDER ||
- (prov_desc->pd_flags & KCF_LPROV_MEMBER) == 0) {
- kcf_walk_ntfylist(is_added ? CRYPTO_EVENT_PROVIDER_REGISTERED :
- CRYPTO_EVENT_PROVIDER_UNREGISTERED, prov_desc);
- }
-}
-
-static void
-delete_kstat(kcf_provider_desc_t *desc)
-{
- /* destroy the kstat created for this provider */
- if (desc->pd_kstat != NULL) {
- kcf_provider_desc_t *kspd = desc->pd_kstat->ks_private;
-
- /* release reference held by desc->pd_kstat->ks_private */
- ASSERT(desc == kspd);
- kstat_delete(kspd->pd_kstat);
- desc->pd_kstat = NULL;
- KCF_PROV_REFRELE(kspd);
- KCF_PROV_IREFRELE(kspd);
- }
-}
diff --git a/sys/contrib/openzfs/module/lua/lapi.c b/sys/contrib/openzfs/module/lua/lapi.c
index 6a845c461052..72b0037aa9a9 100644
--- a/sys/contrib/openzfs/module/lua/lapi.c
+++ b/sys/contrib/openzfs/module/lua/lapi.c
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lapi.c,v 2.171.1.1 2013/04/12 18:48:47 roberto Exp $
** Lua API
@@ -1296,7 +1295,6 @@ module_init(lua_init);
module_exit(lua_fini);
#endif
-/* END CSTYLED */
ZFS_MODULE_DESCRIPTION("Lua Interpreter for ZFS");
ZFS_MODULE_AUTHOR("Lua.org");
diff --git a/sys/contrib/openzfs/module/lua/lapi.h b/sys/contrib/openzfs/module/lua/lapi.h
index 509f46f692a7..c7d34ad84866 100644
--- a/sys/contrib/openzfs/module/lua/lapi.h
+++ b/sys/contrib/openzfs/module/lua/lapi.h
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lapi.h,v 2.7.1.1 2013/04/12 18:48:47 roberto Exp $
** Auxiliary functions from Lua API
@@ -23,4 +22,3 @@
#endif
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/lauxlib.c b/sys/contrib/openzfs/module/lua/lauxlib.c
index 1e0356e7c00e..6c5a69a31f94 100644
--- a/sys/contrib/openzfs/module/lua/lauxlib.c
+++ b/sys/contrib/openzfs/module/lua/lauxlib.c
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lauxlib.c,v 1.248.1.1 2013/04/12 18:48:47 roberto Exp $
** Auxiliary functions for building Lua libraries
@@ -797,4 +796,3 @@ EXPORT_SYMBOL(luaL_newmetatable);
EXPORT_SYMBOL(luaL_traceback);
#endif
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/lbaselib.c b/sys/contrib/openzfs/module/lua/lbaselib.c
index 854649a0fb4d..b3caea0f33c1 100644
--- a/sys/contrib/openzfs/module/lua/lbaselib.c
+++ b/sys/contrib/openzfs/module/lua/lbaselib.c
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lbaselib.c,v 1.276.1.1 2013/04/12 18:48:47 roberto Exp $
** Basic library
@@ -293,4 +292,3 @@ LUAMOD_API int luaopen_base (lua_State *L) {
EXPORT_SYMBOL(luaopen_base);
#endif
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/lcode.c b/sys/contrib/openzfs/module/lua/lcode.c
index 4d88c792a281..467af3020a45 100644
--- a/sys/contrib/openzfs/module/lua/lcode.c
+++ b/sys/contrib/openzfs/module/lua/lcode.c
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lcode.c,v 2.62.1.1 2013/04/12 18:48:47 roberto Exp $
** Code generator for Lua
@@ -885,4 +884,3 @@ void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) {
luaX_syntaxerror(fs->ls, "constructor too long");
fs->freereg = base + 1; /* free registers with list values */
}
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/lcode.h b/sys/contrib/openzfs/module/lua/lcode.h
index fd5fad00df3d..6a1424cf5a73 100644
--- a/sys/contrib/openzfs/module/lua/lcode.h
+++ b/sys/contrib/openzfs/module/lua/lcode.h
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lcode.h,v 1.58.1.1 2013/04/12 18:48:47 roberto Exp $
** Code generator for Lua
@@ -82,4 +81,3 @@ LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore);
#endif
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/lcorolib.c b/sys/contrib/openzfs/module/lua/lcorolib.c
index 0300e7ee17d5..a4d60ffd4548 100644
--- a/sys/contrib/openzfs/module/lua/lcorolib.c
+++ b/sys/contrib/openzfs/module/lua/lcorolib.c
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lcorolib.c,v 1.5.1.1 2013/04/12 18:48:47 roberto Exp $
** Coroutine Library
@@ -156,4 +155,3 @@ LUAMOD_API int luaopen_coroutine (lua_State *L) {
EXPORT_SYMBOL(luaopen_coroutine);
#endif
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/lctype.c b/sys/contrib/openzfs/module/lua/lctype.c
index 028d278ae4da..2c6e13469d4b 100644
--- a/sys/contrib/openzfs/module/lua/lctype.c
+++ b/sys/contrib/openzfs/module/lua/lctype.c
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lctype.c,v 1.11.1.1 2013/04/12 18:48:47 roberto Exp $
** 'ctype' functions for Lua
@@ -49,4 +48,3 @@ LUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = {
};
#endif /* } */
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/lctype.h b/sys/contrib/openzfs/module/lua/lctype.h
index b16b6bc7dab3..bd9f4c8685cd 100644
--- a/sys/contrib/openzfs/module/lua/lctype.h
+++ b/sys/contrib/openzfs/module/lua/lctype.h
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lctype.h,v 1.12.1.1 2013/04/12 18:48:47 roberto Exp $
** 'ctype' functions for Lua
@@ -91,4 +90,3 @@ LUAI_DDEC const lu_byte luai_ctype_[UCHAR_MAX + 2];
#endif /* } */
#endif
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/ldebug.c b/sys/contrib/openzfs/module/lua/ldebug.c
index da005c44376e..0092474c762d 100644
--- a/sys/contrib/openzfs/module/lua/ldebug.c
+++ b/sys/contrib/openzfs/module/lua/ldebug.c
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: ldebug.c,v 2.90.1.4 2015/02/19 17:05:13 roberto Exp $
** Debug Interface
@@ -605,4 +604,3 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
luaG_errormsg(L);
L->runerror--;
}
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/ldebug.h b/sys/contrib/openzfs/module/lua/ldebug.h
index 36ed396f26c9..6445c763ea51 100644
--- a/sys/contrib/openzfs/module/lua/ldebug.h
+++ b/sys/contrib/openzfs/module/lua/ldebug.h
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: ldebug.h,v 2.7.1.1 2013/04/12 18:48:47 roberto Exp $
** Auxiliary functions from Debug Interface module
@@ -33,4 +32,3 @@ LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...);
LUAI_FUNC l_noret luaG_errormsg (lua_State *L);
#endif
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/ldo.c b/sys/contrib/openzfs/module/lua/ldo.c
index f3c3dcb4d81a..2ee9f665d77e 100644
--- a/sys/contrib/openzfs/module/lua/ldo.c
+++ b/sys/contrib/openzfs/module/lua/ldo.c
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: ldo.c,v 2.108.1.3 2013/11/08 18:22:50 roberto Exp $
** Stack and Call structure of Lua
@@ -92,7 +91,7 @@ static intptr_t stack_remaining(void) {
typedef struct _label_t { long long unsigned val[JMP_BUF_CNT]; } label_t;
int setjmp(label_t *) __attribute__ ((__nothrow__));
-extern void longjmp(label_t *) __attribute__((__noreturn__));
+extern _Noreturn void longjmp(label_t *);
#define LUAI_THROW(L,c) longjmp(&(c)->b)
#define LUAI_TRY(L,c,a) if (setjmp(&(c)->b) == 0) { a }
@@ -746,4 +745,3 @@ int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
L->nny--;
return status;
}
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/ldo.h b/sys/contrib/openzfs/module/lua/ldo.h
index 2c0e1704d072..a6ca5e12e73f 100644
--- a/sys/contrib/openzfs/module/lua/ldo.h
+++ b/sys/contrib/openzfs/module/lua/ldo.h
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: ldo.h,v 2.20.1.1 2013/04/12 18:48:47 roberto Exp $
** Stack and Call structure of Lua
@@ -44,4 +43,3 @@ LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode);
LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);
#endif
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/lfunc.c b/sys/contrib/openzfs/module/lua/lfunc.c
index 1a510831259c..55b19c014494 100644
--- a/sys/contrib/openzfs/module/lua/lfunc.c
+++ b/sys/contrib/openzfs/module/lua/lfunc.c
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lfunc.c,v 2.30.1.1 2013/04/12 18:48:47 roberto Exp $
** Auxiliary functions to manipulate prototypes and closures
@@ -157,4 +156,3 @@ const char *luaF_getlocalname (const Proto *f, int local_number, int pc) {
}
return NULL; /* not found */
}
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/lfunc.h b/sys/contrib/openzfs/module/lua/lfunc.h
index 59a4fa75c46e..ca0d3a3e0b03 100644
--- a/sys/contrib/openzfs/module/lua/lfunc.h
+++ b/sys/contrib/openzfs/module/lua/lfunc.h
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lfunc.h,v 2.8.1.1 2013/04/12 18:48:47 roberto Exp $
** Auxiliary functions to manipulate prototypes and closures
@@ -32,4 +31,3 @@ LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
#endif
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/lgc.c b/sys/contrib/openzfs/module/lua/lgc.c
index 227ad723a0b8..0ec18ea4839f 100644
--- a/sys/contrib/openzfs/module/lua/lgc.c
+++ b/sys/contrib/openzfs/module/lua/lgc.c
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lgc.c,v 2.140.1.3 2014/09/01 16:55:08 roberto Exp $
** Garbage Collector
@@ -676,7 +675,7 @@ static void freeobj (lua_State *L, GCObject *o) {
case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break;
case LUA_TSHRSTR:
G(L)->strt.nuse--;
- fallthrough;
+ zfs_fallthrough;
case LUA_TLNGSTR: {
luaM_freemem(L, o, sizestring(gco2ts(o)));
break;
@@ -1215,4 +1214,3 @@ void luaC_fullgc (lua_State *L, int isemergency) {
}
/* }====================================================== */
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/lgc.h b/sys/contrib/openzfs/module/lua/lgc.h
index 34097a45edfc..84bb1cdf99fa 100644
--- a/sys/contrib/openzfs/module/lua/lgc.h
+++ b/sys/contrib/openzfs/module/lua/lgc.h
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lgc.h,v 2.58.1.1 2013/04/12 18:48:47 roberto Exp $
** Garbage Collector
@@ -156,4 +155,3 @@ LUAI_FUNC void luaC_checkupvalcolor (global_State *g, UpVal *uv);
LUAI_FUNC void luaC_changemode (lua_State *L, int mode);
#endif
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/llex.c b/sys/contrib/openzfs/module/lua/llex.c
index f2c9bf826c82..bcdda4ccf036 100644
--- a/sys/contrib/openzfs/module/lua/llex.c
+++ b/sys/contrib/openzfs/module/lua/llex.c
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: llex.c,v 2.63.1.3 2015/02/09 17:56:34 roberto Exp $
** Lexical Analyzer
@@ -477,7 +476,7 @@ static int llex (LexState *ls, SemInfo *seminfo) {
else if (!lisdigit(ls->current)) return '.';
/* else go through */
}
- fallthrough;
+ zfs_fallthrough;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': {
read_numeral(ls, seminfo);
@@ -528,4 +527,3 @@ int luaX_lookahead (LexState *ls) {
ls->lookahead.token = llex(ls, &ls->lookahead.seminfo);
return ls->lookahead.token;
}
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/llex.h b/sys/contrib/openzfs/module/lua/llex.h
index da58203e8dc8..43313451539f 100644
--- a/sys/contrib/openzfs/module/lua/llex.h
+++ b/sys/contrib/openzfs/module/lua/llex.h
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: llex.h,v 1.72.1.1 2013/04/12 18:48:47 roberto Exp $
** Lexical Analyzer
@@ -80,4 +79,3 @@ LUAI_FUNC const char *luaX_token2str (LexState *ls, int token);
#endif
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/llimits.h b/sys/contrib/openzfs/module/lua/llimits.h
index 177092fbc228..566313529058 100644
--- a/sys/contrib/openzfs/module/lua/llimits.h
+++ b/sys/contrib/openzfs/module/lua/llimits.h
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: llimits.h,v 1.103.1.1 2013/04/12 18:48:47 roberto Exp $
** Limits, basic types, and some other `installation-dependent' definitions
@@ -311,4 +310,3 @@ union luai_Cast { double l_d; LUA_INT32 l_p[2]; };
#endif
#endif
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/lmem.c b/sys/contrib/openzfs/module/lua/lmem.c
index 18bb2514cb01..1344099b449c 100644
--- a/sys/contrib/openzfs/module/lua/lmem.c
+++ b/sys/contrib/openzfs/module/lua/lmem.c
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lmem.c,v 1.84.1.1 2013/04/12 18:48:47 roberto Exp $
** Interface to Memory Manager
@@ -95,4 +94,3 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
g->GCdebt = (g->GCdebt + nsize) - realosize;
return newblock;
}
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/lmem.h b/sys/contrib/openzfs/module/lua/lmem.h
index 22c04c98c863..249a76f32974 100644
--- a/sys/contrib/openzfs/module/lua/lmem.h
+++ b/sys/contrib/openzfs/module/lua/lmem.h
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lmem.h,v 1.40.1.1 2013/04/12 18:48:47 roberto Exp $
** Interface to Memory Manager
@@ -53,4 +52,3 @@ LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int *size,
const char *what);
#endif
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/lobject.c b/sys/contrib/openzfs/module/lua/lobject.c
index 024d3199fe24..f74dacdf5faf 100644
--- a/sys/contrib/openzfs/module/lua/lobject.c
+++ b/sys/contrib/openzfs/module/lua/lobject.c
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lobject.c,v 2.58.1.1 2013/04/12 18:48:47 roberto Exp $
** Some generic functions over Lua objects
@@ -279,4 +278,3 @@ void luaO_chunkid (char *out, const char *source, size_t bufflen) {
memcpy(out, POS, (LL(POS) + 1) * sizeof(char));
}
}
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/lobject.h b/sys/contrib/openzfs/module/lua/lobject.h
index a16b8d62eb4b..d29d0068c7e6 100644
--- a/sys/contrib/openzfs/module/lua/lobject.h
+++ b/sys/contrib/openzfs/module/lua/lobject.h
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lobject.h,v 2.71.1.2 2014/05/07 14:14:58 roberto Exp $
** Type definitions for Lua objects
@@ -602,4 +601,3 @@ LUAI_FUNC void luaO_chunkid (char *out, const char *source, size_t len);
#endif
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/lopcodes.c b/sys/contrib/openzfs/module/lua/lopcodes.c
index 5f34e6d90515..16d1cfe8523e 100644
--- a/sys/contrib/openzfs/module/lua/lopcodes.c
+++ b/sys/contrib/openzfs/module/lua/lopcodes.c
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lopcodes.c,v 1.49.1.1 2013/04/12 18:48:47 roberto Exp $
** Opcodes for Lua virtual machine
@@ -105,4 +104,3 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_VARARG */
,opmode(0, 0, OpArgU, OpArgU, iAx) /* OP_EXTRAARG */
};
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/lopcodes.h b/sys/contrib/openzfs/module/lua/lopcodes.h
index 02eeec1ecd06..8e2f80a13141 100644
--- a/sys/contrib/openzfs/module/lua/lopcodes.h
+++ b/sys/contrib/openzfs/module/lua/lopcodes.h
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lopcodes.h,v 1.142.1.2 2014/10/20 18:32:09 roberto Exp $
** Opcodes for Lua virtual machine
@@ -287,4 +286,3 @@ LUAI_DDEC const char *const luaP_opnames[NUM_OPCODES+1]; /* opcode names */
#endif
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/lparser.c b/sys/contrib/openzfs/module/lua/lparser.c
index e1dd88f2f654..f3a1f772486b 100644
--- a/sys/contrib/openzfs/module/lua/lparser.c
+++ b/sys/contrib/openzfs/module/lua/lparser.c
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lparser.c,v 2.130.1.1 2013/04/12 18:48:47 roberto Exp $
** Lua Parser
@@ -1640,4 +1639,3 @@ Closure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0);
return cl; /* it's on the stack too */
}
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/lparser.h b/sys/contrib/openzfs/module/lua/lparser.h
index 8aea0523f3e3..0346e3c41a80 100644
--- a/sys/contrib/openzfs/module/lua/lparser.h
+++ b/sys/contrib/openzfs/module/lua/lparser.h
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lparser.h,v 1.70.1.1 2013/04/12 18:48:47 roberto Exp $
** Lua Parser
@@ -118,4 +117,3 @@ LUAI_FUNC Closure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
#endif
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/lstate.c b/sys/contrib/openzfs/module/lua/lstate.c
index 4d196eced6a3..5a46993938e6 100644
--- a/sys/contrib/openzfs/module/lua/lstate.c
+++ b/sys/contrib/openzfs/module/lua/lstate.c
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lstate.c,v 2.99.1.2 2013/11/08 17:45:31 roberto Exp $
** Global State
@@ -317,4 +316,3 @@ LUA_API void lua_close (lua_State *L) {
lua_lock(L);
close_state(L);
}
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/lstate.h b/sys/contrib/openzfs/module/lua/lstate.h
index b636396a6015..75c6ceda6d33 100644
--- a/sys/contrib/openzfs/module/lua/lstate.h
+++ b/sys/contrib/openzfs/module/lua/lstate.h
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lstate.h,v 2.82.1.1 2013/04/12 18:48:47 roberto Exp $
** Global State
@@ -227,4 +226,3 @@ LUAI_FUNC void luaE_freeCI (lua_State *L);
#endif
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/lstring.c b/sys/contrib/openzfs/module/lua/lstring.c
index 7fcef3d88aa3..15a73116bb77 100644
--- a/sys/contrib/openzfs/module/lua/lstring.c
+++ b/sys/contrib/openzfs/module/lua/lstring.c
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lstring.c,v 2.26.1.1 2013/04/12 18:48:47 roberto Exp $
** String table (keeps all strings handled by Lua)
@@ -183,4 +182,3 @@ Udata *luaS_newudata (lua_State *L, size_t s, Table *e) {
u->uv.env = e;
return u;
}
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/lstring.h b/sys/contrib/openzfs/module/lua/lstring.h
index 66e65379b8e7..260e7f169bd0 100644
--- a/sys/contrib/openzfs/module/lua/lstring.h
+++ b/sys/contrib/openzfs/module/lua/lstring.h
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lstring.h,v 1.49.1.1 2013/04/12 18:48:47 roberto Exp $
** String table (keep all strings handled by Lua)
@@ -45,4 +44,3 @@ LUAI_FUNC TString *luaS_new (lua_State *L, const char *str);
#endif
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/lstrlib.c b/sys/contrib/openzfs/module/lua/lstrlib.c
index 46e3d8fb35bb..902cc773e8aa 100644
--- a/sys/contrib/openzfs/module/lua/lstrlib.c
+++ b/sys/contrib/openzfs/module/lua/lstrlib.c
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lstrlib.c,v 1.178.1.1 2013/04/12 18:48:47 roberto Exp $
** Standard library for string operations and pattern-matching
@@ -501,7 +500,7 @@ static const char *match (MatchState *ms, const char *s, const char *p) {
}
case '+': /* 1 or more repetitions */
s++; /* 1 match already done */
- fallthrough;
+ zfs_fallthrough;
case '*': /* 0 or more repetitions */
s = max_expand(ms, s, p, ep);
break;
@@ -1037,4 +1036,3 @@ LUAMOD_API int luaopen_string (lua_State *L) {
EXPORT_SYMBOL(luaopen_string);
#endif
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/ltable.c b/sys/contrib/openzfs/module/lua/ltable.c
index f6872babc6e7..1227d99c7b4a 100644
--- a/sys/contrib/openzfs/module/lua/ltable.c
+++ b/sys/contrib/openzfs/module/lua/ltable.c
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: ltable.c,v 2.72.1.1 2013/04/12 18:48:47 roberto Exp $
** Lua tables (hash)
@@ -492,7 +491,7 @@ const TValue *luaH_get (Table *t, const TValue *key) {
return luaH_getint(t, k); /* use specialized version */
/* else go through */
}
- fallthrough;
+ zfs_fallthrough;
default: {
Node *n = mainposition(t, key);
do { /* check whether `key' is somewhere in the chain */
@@ -589,4 +588,3 @@ Node *luaH_mainposition (const Table *t, const TValue *key) {
int luaH_isdummy (Node *n) { return isdummy(n); }
#endif
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/ltable.h b/sys/contrib/openzfs/module/lua/ltable.h
index ea877ebf4eb0..3c66a2390d2c 100644
--- a/sys/contrib/openzfs/module/lua/ltable.h
+++ b/sys/contrib/openzfs/module/lua/ltable.h
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: ltable.h,v 2.16.1.2 2013/08/30 15:49:41 roberto Exp $
** Lua tables (hash)
@@ -44,4 +43,3 @@ LUAI_FUNC int luaH_isdummy (Node *n);
#endif
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/ltablib.c b/sys/contrib/openzfs/module/lua/ltablib.c
index 51cafffaafcd..a697d2194066 100644
--- a/sys/contrib/openzfs/module/lua/ltablib.c
+++ b/sys/contrib/openzfs/module/lua/ltablib.c
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: ltablib.c,v 1.65.1.2 2014/05/07 16:32:55 roberto Exp $
** Library for Table Manipulation
@@ -286,4 +285,3 @@ LUAMOD_API int luaopen_table (lua_State *L) {
EXPORT_SYMBOL(luaopen_table);
#endif
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/ltm.c b/sys/contrib/openzfs/module/lua/ltm.c
index 94f29f7d96d5..f86d97069d45 100644
--- a/sys/contrib/openzfs/module/lua/ltm.c
+++ b/sys/contrib/openzfs/module/lua/ltm.c
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: ltm.c,v 2.14.1.1 2013/04/12 18:48:47 roberto Exp $
** Tag methods
@@ -73,4 +72,3 @@ const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) {
}
return (mt ? luaH_getstr(mt, G(L)->tmname[event]) : luaO_nilobject);
}
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/ltm.h b/sys/contrib/openzfs/module/lua/ltm.h
index c056f4637353..7f89c841f9c0 100644
--- a/sys/contrib/openzfs/module/lua/ltm.h
+++ b/sys/contrib/openzfs/module/lua/ltm.h
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: ltm.h,v 2.11.1.1 2013/04/12 18:48:47 roberto Exp $
** Tag methods
@@ -56,4 +55,3 @@ LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o,
LUAI_FUNC void luaT_init (lua_State *L);
#endif
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/lvm.c b/sys/contrib/openzfs/module/lua/lvm.c
index 4685be52b449..b5545732535c 100644
--- a/sys/contrib/openzfs/module/lua/lvm.c
+++ b/sys/contrib/openzfs/module/lua/lvm.c
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lvm.c,v 2.155.1.1 2013/04/12 18:48:47 roberto Exp $
** Lua virtual machine
@@ -928,5 +927,3 @@ void luaV_execute (lua_State *L) {
}
}
}
-
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/lvm.h b/sys/contrib/openzfs/module/lua/lvm.h
index 2d2be9836f69..5380270da63d 100644
--- a/sys/contrib/openzfs/module/lua/lvm.h
+++ b/sys/contrib/openzfs/module/lua/lvm.h
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lvm.h,v 2.18.1.1 2013/04/12 18:48:47 roberto Exp $
** Lua virtual machine
@@ -43,4 +42,3 @@ LUAI_FUNC void luaV_arith (lua_State *L, StkId ra, const TValue *rb,
LUAI_FUNC void luaV_objlen (lua_State *L, StkId ra, const TValue *rb);
#endif
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/lzio.c b/sys/contrib/openzfs/module/lua/lzio.c
index bfbb41cf8ed3..7bd6badaa6ef 100644
--- a/sys/contrib/openzfs/module/lua/lzio.c
+++ b/sys/contrib/openzfs/module/lua/lzio.c
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lzio.c,v 1.35.1.1 2013/04/12 18:48:47 roberto Exp $
** Buffered streams
@@ -71,4 +70,3 @@ char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n) {
}
return buff->buffer;
}
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/lua/lzio.h b/sys/contrib/openzfs/module/lua/lzio.h
index 27908759d509..670e463c4f4f 100644
--- a/sys/contrib/openzfs/module/lua/lzio.h
+++ b/sys/contrib/openzfs/module/lua/lzio.h
@@ -1,4 +1,3 @@
-/* BEGIN CSTYLED */
/*
** $Id: lzio.h,v 1.26.1.1 2013/04/12 18:48:47 roberto Exp $
** Buffered streams
@@ -64,4 +63,3 @@ struct Zio {
LUAI_FUNC int luaZ_fill (ZIO *z);
#endif
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/os/freebsd/spl/callb.c b/sys/contrib/openzfs/module/os/freebsd/spl/callb.c
index 0b7fefc89a26..5db95bd9716e 100644
--- a/sys/contrib/openzfs/module/os/freebsd/spl/callb.c
+++ b/sys/contrib/openzfs/module/os/freebsd/spl/callb.c
@@ -338,10 +338,10 @@ callb_generic_cpr(void *arg, int code)
* The generic callback function associated with kernel threads which
* are always considered safe.
*/
-/* ARGSUSED */
boolean_t
callb_generic_cpr_safe(void *arg, int code)
{
+ (void) arg, (void) code;
return (B_TRUE);
}
/*
diff --git a/sys/contrib/openzfs/module/os/freebsd/spl/spl_zlib.c b/sys/contrib/openzfs/module/os/freebsd/spl/spl_zlib.c
index 3644eba77ca1..fa2b0a2b6903 100644
--- a/sys/contrib/openzfs/module/os/freebsd/spl/spl_zlib.c
+++ b/sys/contrib/openzfs/module/os/freebsd/spl/spl_zlib.c
@@ -40,19 +40,17 @@ __FBSDID("$FreeBSD$");
#include <sys/kobj.h>
-/*ARGSUSED*/
static void *
zcalloc(void *opaque, uint_t items, uint_t size)
{
-
+ (void) opaque;
return (malloc((size_t)items*size, M_SOLARIS, M_NOWAIT));
}
-/*ARGSUSED*/
static void
zcfree(void *opaque, void *ptr)
{
-
+ (void) opaque;
free(ptr, M_SOLARIS);
}
diff --git a/sys/contrib/openzfs/module/os/freebsd/zfs/arc_os.c b/sys/contrib/openzfs/module/os/freebsd/zfs/arc_os.c
index fddb1f0e87cb..b6f19207f324 100644
--- a/sys/contrib/openzfs/module/os/freebsd/zfs/arc_os.c
+++ b/sys/contrib/openzfs/module/os/freebsd/zfs/arc_os.c
@@ -93,12 +93,10 @@ sysctl_vfs_zfs_arc_free_target(SYSCTL_HANDLER_ARGS)
return (0);
}
SYSCTL_DECL(_vfs_zfs);
-/* BEGIN CSTYLED */
SYSCTL_PROC(_vfs_zfs, OID_AUTO, arc_free_target,
CTLTYPE_UINT | CTLFLAG_MPSAFE | CTLFLAG_RW, 0, sizeof (uint_t),
sysctl_vfs_zfs_arc_free_target, "IU",
- "Desired number of free pages below which ARC triggers reclaim");
-/* END CSTYLED */
+ "Desired number of free pages below which ARC triggers reclaim");
int64_t
arc_available_memory(void)
diff --git a/sys/contrib/openzfs/module/os/freebsd/zfs/crypto_os.c b/sys/contrib/openzfs/module/os/freebsd/zfs/crypto_os.c
index f971b62bd124..73083f59f532 100644
--- a/sys/contrib/openzfs/module/os/freebsd/zfs/crypto_os.c
+++ b/sys/contrib/openzfs/module/os/freebsd/zfs/crypto_os.c
@@ -210,12 +210,12 @@ freebsd_crypt_uio_debug_log(boolean_t encrypt,
uint8_t *p = NULL;
size_t total = 0;
- printf("%s(%s, %p, { %s, %d, %d, %s }, %p, { %d, %p, %u }, "
+ printf("%s(%s, %p, { %s, %d, %d, %s }, %p, { %p, %u }, "
"%p, %u, %u)\n",
__FUNCTION__, encrypt ? "encrypt" : "decrypt", input_sessionp,
c_info->ci_algname, c_info->ci_crypt_type,
(unsigned int)c_info->ci_keylen, c_info->ci_name,
- data_uio, key->ck_format, key->ck_data,
+ data_uio, key->ck_data,
(unsigned int)key->ck_length,
ivbuf, (unsigned int)datalen, (unsigned int)auth_len);
printf("\tkey = { ");
@@ -247,11 +247,11 @@ freebsd_crypt_newsession(freebsd_crypt_session_t *sessp,
int error = 0;
#ifdef FCRYPTO_DEBUG
- printf("%s(%p, { %s, %d, %d, %s }, { %d, %p, %u })\n",
+ printf("%s(%p, { %s, %d, %d, %s }, { %p, %u })\n",
__FUNCTION__, sessp,
c_info->ci_algname, c_info->ci_crypt_type,
(unsigned int)c_info->ci_keylen, c_info->ci_name,
- key->ck_format, key->ck_data, (unsigned int)key->ck_length);
+ key->ck_data, (unsigned int)key->ck_length);
printf("\tkey = { ");
for (int i = 0; i < key->ck_length / 8; i++) {
uint8_t *b = (uint8_t *)key->ck_data;
@@ -391,11 +391,11 @@ freebsd_crypt_newsession(freebsd_crypt_session_t *sessp,
crypto_session_t sid;
#ifdef FCRYPTO_DEBUG
- printf("%s(%p, { %s, %d, %d, %s }, { %d, %p, %u })\n",
+ printf("%s(%p, { %s, %d, %d, %s }, { %p, %u })\n",
__FUNCTION__, sessp,
c_info->ci_algname, c_info->ci_crypt_type,
(unsigned int)c_info->ci_keylen, c_info->ci_name,
- key->ck_format, key->ck_data, (unsigned int)key->ck_length);
+ key->ck_data, (unsigned int)key->ck_length);
printf("\tkey = { ");
for (int i = 0; i < key->ck_length / 8; i++) {
uint8_t *b = (uint8_t *)key->ck_data;
diff --git a/sys/contrib/openzfs/module/os/freebsd/zfs/hkdf.c b/sys/contrib/openzfs/module/os/freebsd/zfs/hkdf.c
index 8324ff2319b6..ad5d67541ad2 100644
--- a/sys/contrib/openzfs/module/os/freebsd/zfs/hkdf.c
+++ b/sys/contrib/openzfs/module/os/freebsd/zfs/hkdf.c
@@ -29,7 +29,6 @@ hkdf_sha512_extract(uint8_t *salt, uint_t salt_len, uint8_t *key_material,
crypto_key_t key;
/* initialize the salt as a crypto key */
- key.ck_format = CRYPTO_KEY_RAW;
key.ck_length = CRYPTO_BYTES2BITS(salt_len);
key.ck_data = salt;
@@ -53,7 +52,6 @@ hkdf_sha512_expand(uint8_t *extract_key, uint8_t *info, uint_t info_len,
return (SET_ERROR(EINVAL));
/* initialize the salt as a crypto key */
- key.ck_format = CRYPTO_KEY_RAW;
key.ck_length = CRYPTO_BYTES2BITS(SHA512_DIGEST_LENGTH);
key.ck_data = extract_key;
diff --git a/sys/contrib/openzfs/module/os/freebsd/zfs/spa_os.c b/sys/contrib/openzfs/module/os/freebsd/zfs/spa_os.c
index c8c833426131..6ebb4c285edd 100644
--- a/sys/contrib/openzfs/module/os/freebsd/zfs/spa_os.c
+++ b/sys/contrib/openzfs/module/os/freebsd/zfs/spa_os.c
@@ -268,3 +268,27 @@ spa_history_zone(void)
{
return ("freebsd");
}
+
+void
+spa_import_os(spa_t *spa)
+{
+ (void) spa;
+}
+
+void
+spa_export_os(spa_t *spa)
+{
+ (void) spa;
+}
+
+void
+spa_activate_os(spa_t *spa)
+{
+ (void) spa;
+}
+
+void
+spa_deactivate_os(spa_t *spa)
+{
+ (void) spa;
+}
diff --git a/sys/contrib/openzfs/module/os/freebsd/zfs/sysctl_os.c b/sys/contrib/openzfs/module/os/freebsd/zfs/sysctl_os.c
index 5315b60982df..c774f05ff706 100644
--- a/sys/contrib/openzfs/module/os/freebsd/zfs/sysctl_os.c
+++ b/sys/contrib/openzfs/module/os/freebsd/zfs/sysctl_os.c
@@ -92,12 +92,13 @@ __FBSDID("$FreeBSD$");
#include <sys/dsl_pool.h>
-/* BEGIN CSTYLED */
SYSCTL_DECL(_vfs_zfs);
-SYSCTL_NODE(_vfs_zfs, OID_AUTO, arc, CTLFLAG_RW, 0, "ZFS adaptive replacement cache");
+SYSCTL_NODE(_vfs_zfs, OID_AUTO, arc, CTLFLAG_RW, 0,
+ "ZFS adaptive replacement cache");
SYSCTL_NODE(_vfs_zfs, OID_AUTO, condense, CTLFLAG_RW, 0, "ZFS condense");
SYSCTL_NODE(_vfs_zfs, OID_AUTO, dbuf, CTLFLAG_RW, 0, "ZFS disk buf cache");
-SYSCTL_NODE(_vfs_zfs, OID_AUTO, dbuf_cache, CTLFLAG_RW, 0, "ZFS disk buf cache");
+SYSCTL_NODE(_vfs_zfs, OID_AUTO, dbuf_cache, CTLFLAG_RW, 0,
+ "ZFS disk buf cache");
SYSCTL_NODE(_vfs_zfs, OID_AUTO, deadman, CTLFLAG_RW, 0, "ZFS deadman");
SYSCTL_NODE(_vfs_zfs, OID_AUTO, dedup, CTLFLAG_RW, 0, "ZFS dedup");
SYSCTL_NODE(_vfs_zfs, OID_AUTO, l2arc, CTLFLAG_RW, 0, "ZFS l2arc");
@@ -105,7 +106,8 @@ SYSCTL_NODE(_vfs_zfs, OID_AUTO, livelist, CTLFLAG_RW, 0, "ZFS livelist");
SYSCTL_NODE(_vfs_zfs, OID_AUTO, lua, CTLFLAG_RW, 0, "ZFS lua");
SYSCTL_NODE(_vfs_zfs, OID_AUTO, metaslab, CTLFLAG_RW, 0, "ZFS metaslab");
SYSCTL_NODE(_vfs_zfs, OID_AUTO, mg, CTLFLAG_RW, 0, "ZFS metaslab group");
-SYSCTL_NODE(_vfs_zfs, OID_AUTO, multihost, CTLFLAG_RW, 0, "ZFS multihost protection");
+SYSCTL_NODE(_vfs_zfs, OID_AUTO, multihost, CTLFLAG_RW, 0,
+ "ZFS multihost protection");
SYSCTL_NODE(_vfs_zfs, OID_AUTO, prefetch, CTLFLAG_RW, 0, "ZFS prefetch");
SYSCTL_NODE(_vfs_zfs, OID_AUTO, reconstruct, CTLFLAG_RW, 0, "ZFS reconstruct");
SYSCTL_NODE(_vfs_zfs, OID_AUTO, recv, CTLFLAG_RW, 0, "ZFS receive");
@@ -120,15 +122,15 @@ SYSCTL_NODE(_vfs_zfs, OID_AUTO, zil, CTLFLAG_RW, 0, "ZFS ZIL");
SYSCTL_NODE(_vfs_zfs, OID_AUTO, zio, CTLFLAG_RW, 0, "ZFS ZIO");
SYSCTL_NODE(_vfs_zfs_livelist, OID_AUTO, condense, CTLFLAG_RW, 0,
- "ZFS livelist condense");
+ "ZFS livelist condense");
SYSCTL_NODE(_vfs_zfs_vdev, OID_AUTO, cache, CTLFLAG_RW, 0, "ZFS VDEV Cache");
SYSCTL_NODE(_vfs_zfs_vdev, OID_AUTO, file, CTLFLAG_RW, 0, "ZFS VDEV file");
SYSCTL_NODE(_vfs_zfs_vdev, OID_AUTO, mirror, CTLFLAG_RD, 0,
- "ZFS VDEV mirror");
+ "ZFS VDEV mirror");
SYSCTL_DECL(_vfs_zfs_version);
SYSCTL_CONST_STRING(_vfs_zfs_version, OID_AUTO, module, CTLFLAG_RD,
- (ZFS_META_VERSION "-" ZFS_META_RELEASE), "OpenZFS module version");
+ (ZFS_META_VERSION "-" ZFS_META_RELEASE), "OpenZFS module version");
extern arc_state_t ARC_anon;
extern arc_state_t ARC_mru;
@@ -204,76 +206,73 @@ extern int l2arc_noprefetch; /* don't cache prefetch bufs */
extern int l2arc_feed_again; /* turbo warmup */
extern int l2arc_norw; /* no reads during writes */
+/* BEGIN CSTYLED */
SYSCTL_UQUAD(_vfs_zfs, OID_AUTO, l2arc_write_max, CTLFLAG_RW,
- &l2arc_write_max, 0, "max write size (LEGACY)");
+ &l2arc_write_max, 0, "max write size (LEGACY)");
SYSCTL_UQUAD(_vfs_zfs, OID_AUTO, l2arc_write_boost, CTLFLAG_RW,
- &l2arc_write_boost, 0, "extra write during warmup (LEGACY)");
+ &l2arc_write_boost, 0, "extra write during warmup (LEGACY)");
SYSCTL_UQUAD(_vfs_zfs, OID_AUTO, l2arc_headroom, CTLFLAG_RW,
- &l2arc_headroom, 0, "number of dev writes (LEGACY)");
+ &l2arc_headroom, 0, "number of dev writes (LEGACY)");
SYSCTL_UQUAD(_vfs_zfs, OID_AUTO, l2arc_feed_secs, CTLFLAG_RW,
- &l2arc_feed_secs, 0, "interval seconds (LEGACY)");
+ &l2arc_feed_secs, 0, "interval seconds (LEGACY)");
SYSCTL_UQUAD(_vfs_zfs, OID_AUTO, l2arc_feed_min_ms, CTLFLAG_RW,
- &l2arc_feed_min_ms, 0, "min interval milliseconds (LEGACY)");
+ &l2arc_feed_min_ms, 0, "min interval milliseconds (LEGACY)");
SYSCTL_INT(_vfs_zfs, OID_AUTO, l2arc_noprefetch, CTLFLAG_RW,
- &l2arc_noprefetch, 0, "don't cache prefetch bufs (LEGACY)");
+ &l2arc_noprefetch, 0, "don't cache prefetch bufs (LEGACY)");
SYSCTL_INT(_vfs_zfs, OID_AUTO, l2arc_feed_again, CTLFLAG_RW,
- &l2arc_feed_again, 0, "turbo warmup (LEGACY)");
+ &l2arc_feed_again, 0, "turbo warmup (LEGACY)");
SYSCTL_INT(_vfs_zfs, OID_AUTO, l2arc_norw, CTLFLAG_RW,
- &l2arc_norw, 0, "no reads during writes (LEGACY)");
-#if 0
-extern int zfs_compressed_arc_enabled;
-SYSCTL_INT(_vfs_zfs, OID_AUTO, compressed_arc_enabled, CTLFLAG_RW,
- &zfs_compressed_arc_enabled, 1, "compressed arc buffers (LEGACY)");
-#endif
+ &l2arc_norw, 0, "no reads during writes (LEGACY)");
SYSCTL_UQUAD(_vfs_zfs, OID_AUTO, anon_size, CTLFLAG_RD,
- &ARC_anon.arcs_size.rc_count, 0, "size of anonymous state");
+ &ARC_anon.arcs_size.rc_count, 0, "size of anonymous state");
SYSCTL_UQUAD(_vfs_zfs, OID_AUTO, anon_metadata_esize, CTLFLAG_RD,
- &ARC_anon.arcs_esize[ARC_BUFC_METADATA].rc_count, 0,
- "size of anonymous state");
+ &ARC_anon.arcs_esize[ARC_BUFC_METADATA].rc_count, 0,
+ "size of anonymous state");
SYSCTL_UQUAD(_vfs_zfs, OID_AUTO, anon_data_esize, CTLFLAG_RD,
- &ARC_anon.arcs_esize[ARC_BUFC_DATA].rc_count, 0,
- "size of anonymous state");
+ &ARC_anon.arcs_esize[ARC_BUFC_DATA].rc_count, 0,
+ "size of anonymous state");
SYSCTL_UQUAD(_vfs_zfs, OID_AUTO, mru_size, CTLFLAG_RD,
- &ARC_mru.arcs_size.rc_count, 0, "size of mru state");
+ &ARC_mru.arcs_size.rc_count, 0, "size of mru state");
SYSCTL_UQUAD(_vfs_zfs, OID_AUTO, mru_metadata_esize, CTLFLAG_RD,
- &ARC_mru.arcs_esize[ARC_BUFC_METADATA].rc_count, 0,
- "size of metadata in mru state");
+ &ARC_mru.arcs_esize[ARC_BUFC_METADATA].rc_count, 0,
+ "size of metadata in mru state");
SYSCTL_UQUAD(_vfs_zfs, OID_AUTO, mru_data_esize, CTLFLAG_RD,
- &ARC_mru.arcs_esize[ARC_BUFC_DATA].rc_count, 0,
- "size of data in mru state");
+ &ARC_mru.arcs_esize[ARC_BUFC_DATA].rc_count, 0,
+ "size of data in mru state");
SYSCTL_UQUAD(_vfs_zfs, OID_AUTO, mru_ghost_size, CTLFLAG_RD,
- &ARC_mru_ghost.arcs_size.rc_count, 0, "size of mru ghost state");
+ &ARC_mru_ghost.arcs_size.rc_count, 0, "size of mru ghost state");
SYSCTL_UQUAD(_vfs_zfs, OID_AUTO, mru_ghost_metadata_esize, CTLFLAG_RD,
- &ARC_mru_ghost.arcs_esize[ARC_BUFC_METADATA].rc_count, 0,
- "size of metadata in mru ghost state");
+ &ARC_mru_ghost.arcs_esize[ARC_BUFC_METADATA].rc_count, 0,
+ "size of metadata in mru ghost state");
SYSCTL_UQUAD(_vfs_zfs, OID_AUTO, mru_ghost_data_esize, CTLFLAG_RD,
- &ARC_mru_ghost.arcs_esize[ARC_BUFC_DATA].rc_count, 0,
- "size of data in mru ghost state");
+ &ARC_mru_ghost.arcs_esize[ARC_BUFC_DATA].rc_count, 0,
+ "size of data in mru ghost state");
SYSCTL_UQUAD(_vfs_zfs, OID_AUTO, mfu_size, CTLFLAG_RD,
- &ARC_mfu.arcs_size.rc_count, 0, "size of mfu state");
+ &ARC_mfu.arcs_size.rc_count, 0, "size of mfu state");
SYSCTL_UQUAD(_vfs_zfs, OID_AUTO, mfu_metadata_esize, CTLFLAG_RD,
- &ARC_mfu.arcs_esize[ARC_BUFC_METADATA].rc_count, 0,
- "size of metadata in mfu state");
+ &ARC_mfu.arcs_esize[ARC_BUFC_METADATA].rc_count, 0,
+ "size of metadata in mfu state");
SYSCTL_UQUAD(_vfs_zfs, OID_AUTO, mfu_data_esize, CTLFLAG_RD,
- &ARC_mfu.arcs_esize[ARC_BUFC_DATA].rc_count, 0,
- "size of data in mfu state");
+ &ARC_mfu.arcs_esize[ARC_BUFC_DATA].rc_count, 0,
+ "size of data in mfu state");
SYSCTL_UQUAD(_vfs_zfs, OID_AUTO, mfu_ghost_size, CTLFLAG_RD,
- &ARC_mfu_ghost.arcs_size.rc_count, 0, "size of mfu ghost state");
+ &ARC_mfu_ghost.arcs_size.rc_count, 0, "size of mfu ghost state");
SYSCTL_UQUAD(_vfs_zfs, OID_AUTO, mfu_ghost_metadata_esize, CTLFLAG_RD,
- &ARC_mfu_ghost.arcs_esize[ARC_BUFC_METADATA].rc_count, 0,
- "size of metadata in mfu ghost state");
+ &ARC_mfu_ghost.arcs_esize[ARC_BUFC_METADATA].rc_count, 0,
+ "size of metadata in mfu ghost state");
SYSCTL_UQUAD(_vfs_zfs, OID_AUTO, mfu_ghost_data_esize, CTLFLAG_RD,
- &ARC_mfu_ghost.arcs_esize[ARC_BUFC_DATA].rc_count, 0,
- "size of data in mfu ghost state");
+ &ARC_mfu_ghost.arcs_esize[ARC_BUFC_DATA].rc_count, 0,
+ "size of data in mfu ghost state");
SYSCTL_UQUAD(_vfs_zfs, OID_AUTO, l2c_only_size, CTLFLAG_RD,
- &ARC_l2c_only.arcs_size.rc_count, 0, "size of mru state");
+ &ARC_l2c_only.arcs_size.rc_count, 0, "size of mru state");
+/* END CSTYLED */
static int
sysctl_vfs_zfs_arc_no_grow_shift(SYSCTL_HANDLER_ARGS)
@@ -285,7 +284,7 @@ sysctl_vfs_zfs_arc_no_grow_shift(SYSCTL_HANDLER_ARGS)
if (err != 0 || req->newptr == NULL)
return (err);
- if (val < 0 || val >= arc_shrink_shift)
+ if (val < 0 || val >= arc_shrink_shift)
return (EINVAL);
arc_no_grow_shift = val;
@@ -295,7 +294,7 @@ sysctl_vfs_zfs_arc_no_grow_shift(SYSCTL_HANDLER_ARGS)
SYSCTL_PROC(_vfs_zfs, OID_AUTO, arc_no_grow_shift,
CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, NULL, sizeof (int),
sysctl_vfs_zfs_arc_no_grow_shift, "I",
- "log2(fraction of ARC which must be free to allow growing)");
+ "log2(fraction of ARC which must be free to allow growing)");
int
param_set_arc_long(SYSCTL_HANDLER_ARGS)
@@ -325,14 +324,16 @@ param_set_arc_int(SYSCTL_HANDLER_ARGS)
return (0);
}
+/* BEGIN CSTYLED */
SYSCTL_PROC(_vfs_zfs, OID_AUTO, arc_min,
- CTLTYPE_ULONG | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
- &zfs_arc_min, sizeof (zfs_arc_min), param_set_arc_min, "LU",
- "min arc size (LEGACY)");
+ CTLTYPE_ULONG | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
+ &zfs_arc_min, sizeof (zfs_arc_min), param_set_arc_min, "LU",
+ "min arc size (LEGACY)");
SYSCTL_PROC(_vfs_zfs, OID_AUTO, arc_max,
- CTLTYPE_ULONG | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
- &zfs_arc_max, sizeof (zfs_arc_max), param_set_arc_max, "LU",
- "max arc size (LEGACY)");
+ CTLTYPE_ULONG | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
+ &zfs_arc_max, sizeof (zfs_arc_max), param_set_arc_max, "LU",
+ "max arc size (LEGACY)");
+/* END CSTYLED */
/* dbuf.c */
@@ -345,30 +346,33 @@ SYSCTL_NODE(_vfs_zfs, OID_AUTO, zfetch, CTLFLAG_RW, 0, "ZFS ZFETCH (LEGACY)");
/* max bytes to prefetch per stream (default 8MB) */
extern uint32_t zfetch_max_distance;
SYSCTL_UINT(_vfs_zfs_zfetch, OID_AUTO, max_distance, CTLFLAG_RWTUN,
- &zfetch_max_distance, 0, "Max bytes to prefetch per stream (LEGACY)");
+ &zfetch_max_distance, 0, "Max bytes to prefetch per stream (LEGACY)");
/* max bytes to prefetch indirects for per stream (default 64MB) */
extern uint32_t zfetch_max_idistance;
+/* BEGIN CSTYLED */
SYSCTL_UINT(_vfs_zfs_zfetch, OID_AUTO, max_idistance, CTLFLAG_RWTUN,
- &zfetch_max_idistance, 0,
- "Max bytes to prefetch indirects for per stream (LEGACY)");
+ &zfetch_max_idistance, 0,
+ "Max bytes to prefetch indirects for per stream (LEGACY)");
+/* END CSTYLED */
/* dsl_pool.c */
/* dnode.c */
extern int zfs_default_bs;
SYSCTL_INT(_vfs_zfs, OID_AUTO, default_bs, CTLFLAG_RWTUN,
- &zfs_default_bs, 0, "Default dnode block shift");
+ &zfs_default_bs, 0, "Default dnode block shift");
extern int zfs_default_ibs;
SYSCTL_INT(_vfs_zfs, OID_AUTO, default_ibs, CTLFLAG_RWTUN,
- &zfs_default_ibs, 0, "Default dnode indirect block shift");
+ &zfs_default_ibs, 0, "Default dnode indirect block shift");
/* dsl_scan.c */
/* metaslab.c */
+/* BEGIN CSTYLED */
/*
* In pools where the log space map feature is not enabled we touch
* multiple metaslabs (and their respective space maps) with each
@@ -379,9 +383,9 @@ SYSCTL_INT(_vfs_zfs, OID_AUTO, default_ibs, CTLFLAG_RWTUN,
*/
extern int zfs_metaslab_sm_blksz_no_log;
SYSCTL_INT(_vfs_zfs_metaslab, OID_AUTO, sm_blksz_no_log, CTLFLAG_RDTUN,
- &zfs_metaslab_sm_blksz_no_log, 0,
- "Block size for space map in pools with log space map disabled. "
- "Power of 2 and greater than 4096.");
+ &zfs_metaslab_sm_blksz_no_log, 0,
+ "Block size for space map in pools with log space map disabled. "
+ "Power of 2 greater than 4096.");
/*
* When the log space map feature is enabled, we accumulate a lot of
@@ -390,9 +394,9 @@ SYSCTL_INT(_vfs_zfs_metaslab, OID_AUTO, sm_blksz_no_log, CTLFLAG_RDTUN,
*/
extern int zfs_metaslab_sm_blksz_with_log;
SYSCTL_INT(_vfs_zfs_metaslab, OID_AUTO, sm_blksz_with_log, CTLFLAG_RDTUN,
- &zfs_metaslab_sm_blksz_with_log, 0,
- "Block size for space map in pools with log space map enabled. "
- "Power of 2 and greater than 4096.");
+ &zfs_metaslab_sm_blksz_with_log, 0,
+ "Block size for space map in pools with log space map enabled. "
+ "Power of 2 greater than 4096.");
/*
* The in-core space map representation is more compact than its on-disk form.
@@ -402,19 +406,19 @@ SYSCTL_INT(_vfs_zfs_metaslab, OID_AUTO, sm_blksz_with_log, CTLFLAG_RDTUN,
*/
extern int zfs_condense_pct;
SYSCTL_INT(_vfs_zfs, OID_AUTO, condense_pct, CTLFLAG_RWTUN,
- &zfs_condense_pct, 0,
- "Condense on-disk spacemap when it is more than this many percents"
- " of in-memory counterpart");
+ &zfs_condense_pct, 0,
+ "Condense on-disk spacemap when it is more than this many percents"
+ " of in-memory counterpart");
extern int zfs_remove_max_segment;
SYSCTL_INT(_vfs_zfs, OID_AUTO, remove_max_segment, CTLFLAG_RWTUN,
- &zfs_remove_max_segment, 0, "Largest contiguous segment ZFS will attempt to"
- " allocate when removing a device");
+ &zfs_remove_max_segment, 0, "Largest contiguous segment ZFS will"
+ " attempt to allocate when removing a device");
extern int zfs_removal_suspend_progress;
SYSCTL_INT(_vfs_zfs, OID_AUTO, removal_suspend_progress, CTLFLAG_RWTUN,
- &zfs_removal_suspend_progress, 0, "Ensures certain actions can happen while"
- " in the middle of a removal");
+ &zfs_removal_suspend_progress, 0,
+ "Ensures certain actions can happen while in the middle of a removal");
/*
@@ -425,8 +429,8 @@ SYSCTL_INT(_vfs_zfs, OID_AUTO, removal_suspend_progress, CTLFLAG_RWTUN,
*/
extern uint64_t metaslab_df_alloc_threshold;
SYSCTL_QUAD(_vfs_zfs_metaslab, OID_AUTO, df_alloc_threshold, CTLFLAG_RWTUN,
- &metaslab_df_alloc_threshold, 0,
- "Minimum size which forces the dynamic allocator to change it's allocation strategy");
+ &metaslab_df_alloc_threshold, 0, "Minimum size which forces the dynamic"
+ " allocator to change its allocation strategy");
/*
* The minimum free space, in percent, which must be available
@@ -436,41 +440,42 @@ SYSCTL_QUAD(_vfs_zfs_metaslab, OID_AUTO, df_alloc_threshold, CTLFLAG_RWTUN,
*/
extern int metaslab_df_free_pct;
SYSCTL_INT(_vfs_zfs_metaslab, OID_AUTO, df_free_pct, CTLFLAG_RWTUN,
- &metaslab_df_free_pct, 0,
- "The minimum free space, in percent, which must be available in a "
- "space map to continue allocations in a first-fit fashion");
+ &metaslab_df_free_pct, 0,
+ "The minimum free space, in percent, which must be available in a"
+ " space map to continue allocations in a first-fit fashion");
/*
* Percentage of all cpus that can be used by the metaslab taskq.
*/
extern int metaslab_load_pct;
SYSCTL_INT(_vfs_zfs_metaslab, OID_AUTO, load_pct, CTLFLAG_RWTUN,
- &metaslab_load_pct, 0,
- "Percentage of cpus that can be used by the metaslab taskq");
+ &metaslab_load_pct, 0,
+ "Percentage of cpus that can be used by the metaslab taskq");
/*
* Max number of metaslabs per group to preload.
*/
extern int metaslab_preload_limit;
SYSCTL_INT(_vfs_zfs_metaslab, OID_AUTO, preload_limit, CTLFLAG_RWTUN,
- &metaslab_preload_limit, 0,
- "Max number of metaslabs per group to preload");
+ &metaslab_preload_limit, 0,
+ "Max number of metaslabs per group to preload");
/* spa.c */
extern int zfs_ccw_retry_interval;
SYSCTL_INT(_vfs_zfs, OID_AUTO, ccw_retry_interval, CTLFLAG_RWTUN,
- &zfs_ccw_retry_interval, 0,
- "Configuration cache file write, retry after failure, interval (seconds)");
+ &zfs_ccw_retry_interval, 0, "Configuration cache file write,"
+ " retry after failure, interval (seconds)");
extern uint64_t zfs_max_missing_tvds_cachefile;
SYSCTL_UQUAD(_vfs_zfs, OID_AUTO, max_missing_tvds_cachefile, CTLFLAG_RWTUN,
- &zfs_max_missing_tvds_cachefile, 0,
- "allow importing pools with missing top-level vdevs in cache file");
+ &zfs_max_missing_tvds_cachefile, 0,
+ "allow importing pools with missing top-level vdevs in cache file");
extern uint64_t zfs_max_missing_tvds_scan;
SYSCTL_UQUAD(_vfs_zfs, OID_AUTO, max_missing_tvds_scan, CTLFLAG_RWTUN,
- &zfs_max_missing_tvds_scan, 0,
- "allow importing pools with missing top-level vdevs during scan");
+ &zfs_max_missing_tvds_scan, 0,
+ "allow importing pools with missing top-level vdevs during scan");
+/* END CSTYLED */
/* spa_misc.c */
extern int zfs_flags;
@@ -497,9 +502,11 @@ sysctl_vfs_zfs_debug_flags(SYSCTL_HANDLER_ARGS)
return (0);
}
+/* BEGIN CSTYLED */
SYSCTL_PROC(_vfs_zfs, OID_AUTO, debugflags,
- CTLTYPE_UINT | CTLFLAG_MPSAFE | CTLFLAG_RWTUN, NULL, 0,
- sysctl_vfs_zfs_debug_flags, "IU", "Debug flags for ZFS testing.");
+ CTLTYPE_UINT | CTLFLAG_MPSAFE | CTLFLAG_RWTUN, NULL, 0,
+ sysctl_vfs_zfs_debug_flags, "IU", "Debug flags for ZFS testing.");
+/* END CSTYLED */
int
param_set_deadman_synctime(SYSCTL_HANDLER_ARGS)
@@ -549,11 +556,11 @@ param_set_deadman_failmode(SYSCTL_HANDLER_ARGS)
return (rc);
if (strcmp(buf, zfs_deadman_failmode) == 0)
return (0);
- if (!strcmp(buf, "wait"))
+ if (strcmp(buf, "wait") == 0)
zfs_deadman_failmode = "wait";
- if (!strcmp(buf, "continue"))
+ if (strcmp(buf, "continue") == 0)
zfs_deadman_failmode = "continue";
- if (!strcmp(buf, "panic"))
+ if (strcmp(buf, "panic") == 0)
zfs_deadman_failmode = "panic";
return (-param_set_deadman_failmode_common(buf));
@@ -563,7 +570,7 @@ param_set_deadman_failmode(SYSCTL_HANDLER_ARGS)
/* spacemap.c */
extern int space_map_ibs;
SYSCTL_INT(_vfs_zfs, OID_AUTO, space_map_ibs, CTLFLAG_RWTUN,
- &space_map_ibs, 0, "Space map indirect block shift");
+ &space_map_ibs, 0, "Space map indirect block shift");
/* vdev.c */
@@ -605,17 +612,18 @@ param_set_max_auto_ashift(SYSCTL_HANDLER_ARGS)
return (0);
}
+/* BEGIN CSTYLED */
SYSCTL_PROC(_vfs_zfs, OID_AUTO, min_auto_ashift,
- CTLTYPE_U64 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
- &zfs_vdev_min_auto_ashift, sizeof (zfs_vdev_min_auto_ashift),
- param_set_min_auto_ashift, "QU",
- "Min ashift used when creating new top-level vdev. (LEGACY)");
+ CTLTYPE_U64 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
+ &zfs_vdev_min_auto_ashift, sizeof (zfs_vdev_min_auto_ashift),
+ param_set_min_auto_ashift, "QU",
+ "Min ashift used when creating new top-level vdev. (LEGACY)");
SYSCTL_PROC(_vfs_zfs, OID_AUTO, max_auto_ashift,
- CTLTYPE_U64 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
- &zfs_vdev_max_auto_ashift, sizeof (zfs_vdev_max_auto_ashift),
- param_set_max_auto_ashift, "QU",
- "Max ashift used when optimizing for logical -> physical sector size on "
- "new top-level vdevs. (LEGACY)");
+ CTLTYPE_U64 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
+ &zfs_vdev_max_auto_ashift, sizeof (zfs_vdev_max_auto_ashift),
+ param_set_max_auto_ashift, "QU",
+ "Max ashift used when optimizing for logical -> physical sector size on"
+ " new top-level vdevs. (LEGACY)");
/*
* Since the DTL space map of a vdev is not expected to have a lot of
@@ -623,8 +631,8 @@ SYSCTL_PROC(_vfs_zfs, OID_AUTO, max_auto_ashift,
*/
extern int zfs_vdev_dtl_sm_blksz;
SYSCTL_INT(_vfs_zfs, OID_AUTO, dtl_sm_blksz, CTLFLAG_RDTUN,
- &zfs_vdev_dtl_sm_blksz, 0,
- "Block size for DTL space map. Power of 2 and greater than 4096.");
+ &zfs_vdev_dtl_sm_blksz, 0,
+ "Block size for DTL space map. Power of 2 greater than 4096.");
/*
* vdev-wide space maps that have lots of entries written to them at
@@ -633,13 +641,13 @@ SYSCTL_INT(_vfs_zfs, OID_AUTO, dtl_sm_blksz, CTLFLAG_RDTUN,
*/
extern int zfs_vdev_standard_sm_blksz;
SYSCTL_INT(_vfs_zfs, OID_AUTO, standard_sm_blksz, CTLFLAG_RDTUN,
- &zfs_vdev_standard_sm_blksz, 0,
- "Block size for standard space map. Power of 2 and greater than 4096.");
+ &zfs_vdev_standard_sm_blksz, 0,
+ "Block size for standard space map. Power of 2 greater than 4096.");
+/* END CSTYLED */
extern int vdev_validate_skip;
SYSCTL_INT(_vfs_zfs, OID_AUTO, validate_skip, CTLFLAG_RDTUN,
- &vdev_validate_skip, 0,
- "Enable to bypass vdev_validate().");
+ &vdev_validate_skip, 0, "Enable to bypass vdev_validate().");
/* vdev_cache.c */
@@ -657,55 +665,23 @@ SYSCTL_INT(_vfs_zfs, OID_AUTO, validate_skip, CTLFLAG_RDTUN,
/* vdev_queue.c */
-#define ZFS_VDEV_QUEUE_KNOB_MIN(name) \
-extern uint32_t zfs_vdev_ ## name ## _min_active; \
-SYSCTL_UINT(_vfs_zfs_vdev, OID_AUTO, name ## _min_active, CTLFLAG_RWTUN,\
- &zfs_vdev_ ## name ## _min_active, 0, \
- "Initial number of I/O requests of type " #name \
- " active for each device");
-
-#define ZFS_VDEV_QUEUE_KNOB_MAX(name) \
-extern uint32_t zfs_vdev_ ## name ## _max_active; \
-SYSCTL_UINT(_vfs_zfs_vdev, OID_AUTO, name ## _max_active, CTLFLAG_RWTUN, \
- &zfs_vdev_ ## name ## _max_active, 0, \
- "Maximum number of I/O requests of type " #name \
- " active for each device");
-
-
-#undef ZFS_VDEV_QUEUE_KNOB
-
+/* BEGIN CSTYLED */
extern uint32_t zfs_vdev_max_active;
SYSCTL_UINT(_vfs_zfs, OID_AUTO, top_maxinflight, CTLFLAG_RWTUN,
- &zfs_vdev_max_active, 0,
- "The maximum number of I/Os of all types active for each device. (LEGACY)");
+ &zfs_vdev_max_active, 0,
+ "The maximum number of I/Os of all types active for each device."
+ " (LEGACY)");
extern int zfs_vdev_def_queue_depth;
SYSCTL_INT(_vfs_zfs_vdev, OID_AUTO, def_queue_depth, CTLFLAG_RWTUN,
- &zfs_vdev_def_queue_depth, 0,
- "Default queue depth for each allocator");
-
-/*extern uint64_t zfs_multihost_history;
-SYSCTL_UQUAD(_vfs_zfs, OID_AUTO, multihost_history, CTLFLAG_RWTUN,
- &zfs_multihost_history, 0,
- "Historical staticists for the last N multihost updates");*/
-
-#ifdef notyet
-SYSCTL_INT(_vfs_zfs_vdev, OID_AUTO, trim_on_init, CTLFLAG_RW,
- &vdev_trim_on_init, 0, "Enable/disable full vdev trim on initialisation");
-#endif
-
-
-/* zio.c */
-#if defined(__LP64__)
-int zio_use_uma = 1;
-#else
-int zio_use_uma = 0;
-#endif
-
-SYSCTL_INT(_vfs_zfs_zio, OID_AUTO, use_uma, CTLFLAG_RDTUN, &zio_use_uma, 0,
- "Use uma(9) for ZIO allocations");
-SYSCTL_INT(_vfs_zfs_zio, OID_AUTO, exclude_metadata, CTLFLAG_RDTUN, &zio_exclude_metadata, 0,
- "Exclude metadata buffers from dumps as well");
+ &zfs_vdev_def_queue_depth, 0,
+ "Default queue depth for each allocator");
+
+
+SYSCTL_INT(_vfs_zfs_zio, OID_AUTO, exclude_metadata, CTLFLAG_RDTUN,
+ &zio_exclude_metadata, 0,
+ "Exclude metadata buffers from dumps as well");
+/* END CSTYLED */
int
param_set_slop_shift(SYSCTL_HANDLER_ARGS)
diff --git a/sys/contrib/openzfs/module/os/freebsd/zfs/vdev_geom.c b/sys/contrib/openzfs/module/os/freebsd/zfs/vdev_geom.c
index 2ef4811a8a4e..914e0e6ded66 100644
--- a/sys/contrib/openzfs/module/os/freebsd/zfs/vdev_geom.c
+++ b/sys/contrib/openzfs/module/os/freebsd/zfs/vdev_geom.c
@@ -63,9 +63,9 @@ struct consumer_vdev_elem {
};
SLIST_HEAD(consumer_priv_t, consumer_vdev_elem);
-/* BEGIN CSTYLED */
-_Static_assert(sizeof (((struct g_consumer *)NULL)->private)
- == sizeof (struct consumer_priv_t*),
+_Static_assert(
+ sizeof (((struct g_consumer *)NULL)->private) ==
+ sizeof (struct consumer_priv_t *),
"consumer_priv_t* can't be stored in g_consumer.private");
DECLARE_GEOM_CLASS(zfs_vdev_class, zfs_vdev);
@@ -74,12 +74,11 @@ SYSCTL_DECL(_vfs_zfs_vdev);
/* Don't send BIO_FLUSH. */
static int vdev_geom_bio_flush_disable;
SYSCTL_INT(_vfs_zfs_vdev, OID_AUTO, bio_flush_disable, CTLFLAG_RWTUN,
- &vdev_geom_bio_flush_disable, 0, "Disable BIO_FLUSH");
+ &vdev_geom_bio_flush_disable, 0, "Disable BIO_FLUSH");
/* Don't send BIO_DELETE. */
static int vdev_geom_bio_delete_disable;
SYSCTL_INT(_vfs_zfs_vdev, OID_AUTO, bio_delete_disable, CTLFLAG_RWTUN,
- &vdev_geom_bio_delete_disable, 0, "Disable BIO_DELETE");
-/* END CSTYLED */
+ &vdev_geom_bio_delete_disable, 0, "Disable BIO_DELETE");
/* Declare local functions */
static void vdev_geom_detach(struct g_consumer *cp, boolean_t open_for_read);
diff --git a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_acl.c b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_acl.c
index bd22cda416bd..c0aa6732717c 100644
--- a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_acl.c
+++ b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_acl.c
@@ -144,10 +144,10 @@ zfs_ace_v0_set_who(void *acep, uint64_t who)
((zfs_oldace_t *)acep)->z_fuid = who;
}
-/*ARGSUSED*/
static size_t
zfs_ace_v0_size(void *acep)
{
+ (void) acep;
return (sizeof (zfs_oldace_t));
}
@@ -163,10 +163,10 @@ zfs_ace_v0_mask_off(void)
return (offsetof(zfs_oldace_t, z_access_mask));
}
-/*ARGSUSED*/
static int
zfs_ace_v0_data(void *acep, void **datap)
{
+ (void) acep;
*datap = NULL;
return (0);
}
@@ -269,7 +269,7 @@ zfs_ace_fuid_size(void *acep)
entry_type == OWNING_GROUP ||
entry_type == ACE_EVERYONE)
return (sizeof (zfs_ace_hdr_t));
- fallthrough;
+ zfs_fallthrough;
default:
return (sizeof (zfs_ace_t));
}
@@ -631,11 +631,11 @@ zfs_acl_next_ace(zfs_acl_t *aclp, void *start, uint64_t *who,
return (NULL);
}
-/*ARGSUSED*/
static uint64_t
zfs_ace_walk(void *datap, uint64_t cookie, int aclcnt,
uint16_t *flags, uint16_t *type, uint32_t *mask)
{
+ (void) aclcnt;
zfs_acl_t *aclp = datap;
zfs_ace_hdr_t *acep = (zfs_ace_hdr_t *)(uintptr_t)cookie;
uint64_t who;
@@ -1120,11 +1120,11 @@ done:
return (error);
}
-/*ARGSUSED*/
void
zfs_acl_data_locator(void **dataptr, uint32_t *length, uint32_t buflen,
boolean_t start, void *userdata)
{
+ (void) buflen;
zfs_acl_locator_cb_t *cb = (zfs_acl_locator_cb_t *)userdata;
if (start) {
@@ -2153,7 +2153,7 @@ zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode,
break;
case OWNING_GROUP:
who = gowner;
- fallthrough;
+ zfs_fallthrough;
case ACE_IDENTIFIER_GROUP:
checkit = zfs_groupmember(zfsvfs, who, cr);
break;
diff --git a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_ctldir.c b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_ctldir.c
index 206f65b08c56..6692e7b317ba 100644
--- a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_ctldir.c
+++ b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_ctldir.c
@@ -456,10 +456,10 @@ zfsctl_common_open(struct vop_open_args *ap)
/*
* Common close routine. Nothing to do here.
*/
-/* ARGSUSED */
static int
zfsctl_common_close(struct vop_close_args *ap)
{
+ (void) ap;
return (0);
}
@@ -685,7 +685,8 @@ zfsctl_root_readdir(struct vop_readdir_args *ap)
if (zfs_uio_offset(&uio) != dots_offset)
return (SET_ERROR(EINVAL));
- CTASSERT(sizeof (node->snapdir->sn_name) <= sizeof (entry.d_name));
+ _Static_assert(sizeof (node->snapdir->sn_name) <= sizeof (entry.d_name),
+ "node->snapdir->sn_name too big for entry.d_name");
entry.d_fileno = node->snapdir->sn_id;
entry.d_type = DT_DIR;
strcpy(entry.d_name, node->snapdir->sn_name);
diff --git a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_debug.c b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_debug.c
index 0ff22cfe79ec..60596aa912f2 100644
--- a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_debug.c
+++ b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_debug.c
@@ -245,10 +245,8 @@ zfs_dbgmsg_print(const char *tag)
}
#endif /* _KERNEL */
-/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs, zfs_, dbgmsg_enable, INT, ZMOD_RW,
- "Enable ZFS debug message log");
+ "Enable ZFS debug message log");
ZFS_MODULE_PARAM(zfs, zfs_, dbgmsg_maxsize, INT, ZMOD_RW,
- "Maximum ZFS debug log size");
-/* END CSTYLED */
+ "Maximum ZFS debug log size");
diff --git a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vfsops.c b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vfsops.c
index 23f3f62c37f4..b68d84e3b858 100644
--- a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vfsops.c
+++ b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vfsops.c
@@ -76,7 +76,6 @@
#define MNTK_NOMSYNC 8
#endif
-/* BEGIN CSTYLED */
struct mtx zfs_debug_mtx;
MTX_SYSINIT(zfs_debug_mtx, &zfs_debug_mtx, "zfs_debug", MTX_DEF);
@@ -84,7 +83,7 @@ SYSCTL_NODE(_vfs, OID_AUTO, zfs, CTLFLAG_RW, 0, "ZFS file system");
int zfs_super_owner;
SYSCTL_INT(_vfs_zfs, OID_AUTO, super_owner, CTLFLAG_RW, &zfs_super_owner, 0,
- "File system owner can perform privileged operation on his file systems");
+ "File system owners can perform privileged operation on file systems");
int zfs_debug_level;
SYSCTL_INT(_vfs_zfs, OID_AUTO, debug, CTLFLAG_RWTUN, &zfs_debug_level, 0,
@@ -93,14 +92,13 @@ SYSCTL_INT(_vfs_zfs, OID_AUTO, debug, CTLFLAG_RWTUN, &zfs_debug_level, 0,
SYSCTL_NODE(_vfs_zfs, OID_AUTO, version, CTLFLAG_RD, 0, "ZFS versions");
static int zfs_version_acl = ZFS_ACL_VERSION;
SYSCTL_INT(_vfs_zfs_version, OID_AUTO, acl, CTLFLAG_RD, &zfs_version_acl, 0,
- "ZFS_ACL_VERSION");
+ "ZFS_ACL_VERSION");
static int zfs_version_spa = SPA_VERSION;
SYSCTL_INT(_vfs_zfs_version, OID_AUTO, spa, CTLFLAG_RD, &zfs_version_spa, 0,
- "SPA_VERSION");
+ "SPA_VERSION");
static int zfs_version_zpl = ZPL_VERSION;
SYSCTL_INT(_vfs_zfs_version, OID_AUTO, zpl, CTLFLAG_RD, &zfs_version_zpl, 0,
- "ZPL_VERSION");
-/* END CSTYLED */
+ "ZPL_VERSION");
#if __FreeBSD_version >= 1400018
static int zfs_quotactl(vfs_t *vfsp, int cmds, uid_t id, void *arg,
@@ -399,7 +397,6 @@ zfs_is_readonly(zfsvfs_t *zfsvfs)
return (!!(zfsvfs->z_vfs->vfs_flag & VFS_RDONLY));
}
-/*ARGSUSED*/
static int
zfs_sync(vfs_t *vfsp, int waitfor)
{
@@ -1312,7 +1309,6 @@ fetch_osname_options(char *name, bool *checkpointrewind)
}
}
-/*ARGSUSED*/
static int
zfs_mount(vfs_t *vfsp)
{
@@ -1643,7 +1639,6 @@ zfsvfs_teardown(zfsvfs_t *zfsvfs, boolean_t unmounting)
return (0);
}
-/*ARGSUSED*/
static int
zfs_umount(vfs_t *vfsp, int fflag)
{
@@ -1779,8 +1774,10 @@ zfs_checkexp(vfs_t *vfsp, struct sockaddr *nam, int *extflagsp,
credanonp, numsecflavors, secflavors));
}
-CTASSERT(SHORT_FID_LEN <= sizeof (struct fid));
-CTASSERT(LONG_FID_LEN <= sizeof (struct fid));
+_Static_assert(sizeof (struct fid) >= SHORT_FID_LEN,
+ "struct fid bigger than SHORT_FID_LEN");
+_Static_assert(sizeof (struct fid) >= LONG_FID_LEN,
+ "struct fid bigger than LONG_FID_LEN");
static int
zfs_fhtovp(vfs_t *vfsp, fid_t *fidp, int flags, vnode_t **vpp)
diff --git a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vnops_os.c b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vnops_os.c
index 3db117525215..21d121a15846 100644
--- a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vnops_os.c
+++ b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vnops_os.c
@@ -220,11 +220,10 @@ typedef ulong_t cookie_t;
* ZFS_EXIT(zfsvfs); // finished in zfs
* return (error); // done, report error
*/
-
-/* ARGSUSED */
static int
zfs_open(vnode_t **vpp, int flag, cred_t *cr)
{
+ (void) cr;
znode_t *zp = VTOZ(*vpp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
@@ -245,10 +244,10 @@ zfs_open(vnode_t **vpp, int flag, cred_t *cr)
return (0);
}
-/* ARGSUSED */
static int
zfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
{
+ (void) offset, (void) cr;
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
@@ -263,11 +262,11 @@ zfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
return (0);
}
-/* ARGSUSED */
static int
zfs_ioctl(vnode_t *vp, ulong_t com, intptr_t data, int flag, cred_t *cred,
int *rvalp)
{
+ (void) flag, (void) cred, (void) rvalp;
loff_t off;
int error;
@@ -764,7 +763,6 @@ zfs_lookup_lock(vnode_t *dvp, vnode_t *vp, const char *name, int lkflags)
* Timestamps:
* NA
*/
-/* ARGSUSED */
static int
zfs_lookup(vnode_t *dvp, const char *nm, vnode_t **vpp,
struct componentname *cnp, int nameiop, cred_t *cr, int flags,
@@ -966,7 +964,7 @@ zfs_lookup(vnode_t *dvp, const char *nm, vnode_t **vpp,
cnp->cn_flags |= SAVENAME;
break;
}
- fallthrough;
+ zfs_fallthrough;
case DELETE:
if (error == 0)
cnp->cn_flags |= SAVENAME;
@@ -1034,12 +1032,11 @@ zfs_lookup(vnode_t *dvp, const char *nm, vnode_t **vpp,
* dvp - ctime|mtime updated if new entry created
* vp - ctime|mtime always, atime if new
*/
-
-/* ARGSUSED */
int
zfs_create(znode_t *dzp, const char *name, vattr_t *vap, int excl, int mode,
znode_t **zpp, cred_t *cr, int flag, vsecattr_t *vsecp)
{
+ (void) excl, (void) mode, (void) flag;
znode_t *zp;
zfsvfs_t *zfsvfs = dzp->z_zfsvfs;
zilog_t *zilog;
@@ -1201,8 +1198,6 @@ out:
* dvp - ctime|mtime
* vp - ctime (if nlink > 0)
*/
-
-/*ARGSUSED*/
static int
zfs_remove_(vnode_t *dvp, vnode_t *vp, const char *name, cred_t *cr)
{
@@ -1390,11 +1385,11 @@ zfs_remove(znode_t *dzp, const char *name, cred_t *cr, int flags)
* dvp - ctime|mtime updated
* vp - ctime|mtime|atime updated
*/
-/*ARGSUSED*/
int
zfs_mkdir(znode_t *dzp, const char *dirname, vattr_t *vap, znode_t **zpp,
cred_t *cr, int flags, vsecattr_t *vsecp)
{
+ (void) flags, (void) vsecp;
znode_t *zp;
zfsvfs_t *zfsvfs = dzp->z_zfsvfs;
zilog_t *zilog;
@@ -1567,7 +1562,6 @@ cache_vop_rmdir(struct vnode *dvp, struct vnode *vp)
* Timestamps:
* dvp - ctime|mtime updated
*/
-/*ARGSUSED*/
static int
zfs_rmdir_(vnode_t *dvp, vnode_t *vp, const char *name, cred_t *cr)
{
@@ -1668,7 +1662,6 @@ zfs_rmdir(znode_t *dzp, const char *name, znode_t *cwd, cred_t *cr, int flags)
* We use 0 for '.', and 1 for '..'. If this is the root of the filesystem,
* we use the offset 2 for the '.zfs' directory.
*/
-/* ARGSUSED */
static int
zfs_readdir(vnode_t *vp, zfs_uio_t *uio, cred_t *cr, int *eofp,
int *ncookies, cookie_t **cookies)
@@ -1994,7 +1987,6 @@ update:
*
* RETURN: 0 (always succeeds).
*/
-/* ARGSUSED */
static int
zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
{
@@ -2208,7 +2200,6 @@ zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
* Timestamps:
* vp - ctime updated, mtime updated if size changed.
*/
-/* ARGSUSED */
int
zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr)
{
@@ -3191,7 +3182,6 @@ zfs_do_rename_impl(vnode_t *sdvp, vnode_t **svpp, struct componentname *scnp,
* Timestamps:
* sdvp,tdvp - ctime|mtime updated
*/
-/*ARGSUSED*/
static int
zfs_do_rename(vnode_t *sdvp, vnode_t **svpp, struct componentname *scnp,
vnode_t *tdvp, vnode_t **tvpp, struct componentname *tcnp,
@@ -3514,11 +3504,11 @@ fail:
* Timestamps:
* dvp - ctime|mtime updated
*/
-/*ARGSUSED*/
int
zfs_symlink(znode_t *dzp, const char *name, vattr_t *vap,
const char *link, znode_t **zpp, cred_t *cr, int flags)
{
+ (void) flags;
znode_t *zp;
dmu_tx_t *tx;
zfsvfs_t *zfsvfs = dzp->z_zfsvfs;
@@ -3653,10 +3643,10 @@ zfs_symlink(znode_t *dzp, const char *name, vattr_t *vap,
* Timestamps:
* vp - atime updated
*/
-/* ARGSUSED */
static int
zfs_readlink(vnode_t *vp, zfs_uio_t *uio, cred_t *cr, caller_context_t *ct)
{
+ (void) cr, (void) ct;
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
int error;
@@ -3690,11 +3680,11 @@ zfs_readlink(vnode_t *vp, zfs_uio_t *uio, cred_t *cr, caller_context_t *ct)
* tdvp - ctime|mtime updated
* svp - ctime updated
*/
-/* ARGSUSED */
int
zfs_link(znode_t *tdzp, znode_t *szp, const char *name, cred_t *cr,
int flags)
{
+ (void) flags;
znode_t *tzp;
zfsvfs_t *zfsvfs = tdzp->z_zfsvfs;
zilog_t *zilog;
@@ -3839,11 +3829,11 @@ zfs_link(znode_t *tdzp, znode_t *szp, const char *name, cred_t *cr,
* Timestamps:
* ip - ctime|mtime updated
*/
-/* ARGSUSED */
int
zfs_space(znode_t *zp, int cmd, flock64_t *bfp, int flag,
offset_t offset, cred_t *cr)
{
+ (void) offset;
zfsvfs_t *zfsvfs = ZTOZSB(zp);
uint64_t off, len;
int error;
@@ -3890,10 +3880,10 @@ zfs_space(znode_t *zp, int cmd, flock64_t *bfp, int flag,
return (error);
}
-/*ARGSUSED*/
static void
zfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
+ (void) cr, (void) ct;
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
int error;
@@ -3937,13 +3927,15 @@ zfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
}
-CTASSERT(sizeof (struct zfid_short) <= sizeof (struct fid));
-CTASSERT(sizeof (struct zfid_long) <= sizeof (struct fid));
+_Static_assert(sizeof (struct zfid_short) <= sizeof (struct fid),
+ "struct zfid_short bigger than struct fid");
+_Static_assert(sizeof (struct zfid_long) <= sizeof (struct fid),
+ "struct zfid_long bigger than struct fid");
-/*ARGSUSED*/
static int
zfs_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct)
{
+ (void) ct;
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
uint32_t gen;
@@ -4127,6 +4119,9 @@ zfs_getpages(struct vnode *vp, vm_page_t *ma, int count, int *rbehind,
if (lr != NULL)
zfs_rangelock_exit(lr);
ZFS_ACCESSTIME_STAMP(zfsvfs, zp);
+
+ dataset_kstats_update_read_kstats(&zfsvfs->z_kstat, count*PAGE_SIZE);
+
ZFS_EXIT(zfsvfs);
if (error != 0)
@@ -4304,6 +4299,9 @@ out:
if ((flags & (zfs_vm_pagerput_sync | zfs_vm_pagerput_inval)) != 0 ||
zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS)
zil_commit(zfsvfs->z_log, zp->z_id);
+
+ dataset_kstats_update_write_kstats(&zfsvfs->z_kstat, len);
+
ZFS_EXIT(zfsvfs);
return (rtvals[0]);
}
@@ -5245,43 +5243,56 @@ zfs_freebsd_pathconf(struct vop_pathconf_args *ap)
}
}
+static int zfs_xattr_compat = 1;
+
+static int
+zfs_check_attrname(const char *name)
+{
+ /* We don't allow '/' character in attribute name. */
+ if (strchr(name, '/') != NULL)
+ return (SET_ERROR(EINVAL));
+ /* We don't allow attribute names that start with a namespace prefix. */
+ if (ZFS_XA_NS_PREFIX_FORBIDDEN(name))
+ return (SET_ERROR(EINVAL));
+ return (0);
+}
+
/*
* FreeBSD's extended attributes namespace defines file name prefix for ZFS'
* extended attribute name:
*
- * NAMESPACE PREFIX
- * system freebsd:system:
- * user (none, can be used to access ZFS fsattr(5) attributes
- * created on Solaris)
+ * NAMESPACE XATTR_COMPAT PREFIX
+ * system * freebsd:system:
+ * user 1 (none, can be used to access ZFS
+ * fsattr(5) attributes created on Solaris)
+ * user 0 user.
*/
static int
zfs_create_attrname(int attrnamespace, const char *name, char *attrname,
- size_t size)
+ size_t size, boolean_t compat)
{
const char *namespace, *prefix, *suffix;
- /* We don't allow '/' character in attribute name. */
- if (strchr(name, '/') != NULL)
- return (SET_ERROR(EINVAL));
- /* We don't allow attribute names that start with "freebsd:" string. */
- if (strncmp(name, "freebsd:", 8) == 0)
- return (SET_ERROR(EINVAL));
-
bzero(attrname, size);
switch (attrnamespace) {
case EXTATTR_NAMESPACE_USER:
-#if 0
- prefix = "freebsd:";
- namespace = EXTATTR_NAMESPACE_USER_STRING;
- suffix = ":";
-#else
- /*
- * This is the default namespace by which we can access all
- * attributes created on Solaris.
- */
- prefix = namespace = suffix = "";
-#endif
+ if (compat) {
+ /*
+ * This is the default namespace by which we can access
+ * all attributes created on Solaris.
+ */
+ prefix = namespace = suffix = "";
+ } else {
+ /*
+ * This is compatible with the user namespace encoding
+ * on Linux prior to xattr_compat, but nothing
+ * else.
+ */
+ prefix = "";
+ namespace = "user";
+ suffix = ".";
+ }
break;
case EXTATTR_NAMESPACE_SYSTEM:
prefix = "freebsd:";
@@ -5403,6 +5414,27 @@ zfs_getextattr_sa(struct vop_getextattr_args *ap, const char *attrname)
return (0);
}
+static int
+zfs_getextattr_impl(struct vop_getextattr_args *ap, boolean_t compat)
+{
+ znode_t *zp = VTOZ(ap->a_vp);
+ zfsvfs_t *zfsvfs = ZTOZSB(zp);
+ char attrname[EXTATTR_MAXNAMELEN+1];
+ int error;
+
+ error = zfs_create_attrname(ap->a_attrnamespace, ap->a_name, attrname,
+ sizeof (attrname), compat);
+ if (error != 0)
+ return (error);
+
+ error = ENOENT;
+ if (zfsvfs->z_use_sa && zp->z_is_sa)
+ error = zfs_getextattr_sa(ap, attrname);
+ if (error == ENOENT)
+ error = zfs_getextattr_dir(ap, attrname);
+ return (error);
+}
+
/*
* Vnode operation to retrieve a named extended attribute.
*/
@@ -5411,7 +5443,6 @@ zfs_getextattr(struct vop_getextattr_args *ap)
{
znode_t *zp = VTOZ(ap->a_vp);
zfsvfs_t *zfsvfs = ZTOZSB(zp);
- char attrname[EXTATTR_MAXNAMELEN+1];
int error;
/*
@@ -5425,8 +5456,7 @@ zfs_getextattr(struct vop_getextattr_args *ap)
if (error != 0)
return (SET_ERROR(error));
- error = zfs_create_attrname(ap->a_attrnamespace, ap->a_name, attrname,
- sizeof (attrname));
+ error = zfs_check_attrname(ap->a_name);
if (error != 0)
return (error);
@@ -5434,10 +5464,17 @@ zfs_getextattr(struct vop_getextattr_args *ap)
ZFS_ENTER(zfsvfs);
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);
- if (error == ENOENT)
- error = zfs_getextattr_dir(ap, attrname);
+
+ error = zfs_getextattr_impl(ap, zfs_xattr_compat);
+ if ((error == ENOENT || error == ENOATTR) &&
+ ap->a_attrnamespace == EXTATTR_NAMESPACE_USER) {
+ /*
+ * Fall back to the alternate namespace format if we failed to
+ * find a user xattr.
+ */
+ error = zfs_getextattr_impl(ap, !zfs_xattr_compat);
+ }
+
rw_exit(&zp->z_xattr_lock);
ZFS_EXIT(zfsvfs);
if (error == ENOENT)
@@ -5512,7 +5549,7 @@ zfs_deleteextattr_sa(struct vop_deleteextattr_args *ap, const char *attrname)
if (error != 0)
error = SET_ERROR(error);
else
- error = zfs_sa_set_xattr(zp);
+ error = zfs_sa_set_xattr(zp, attrname, NULL, 0);
if (error != 0) {
zp->z_xattr_cached = NULL;
nvlist_free(nvl);
@@ -5520,6 +5557,27 @@ zfs_deleteextattr_sa(struct vop_deleteextattr_args *ap, const char *attrname)
return (error);
}
+static int
+zfs_deleteextattr_impl(struct vop_deleteextattr_args *ap, boolean_t compat)
+{
+ znode_t *zp = VTOZ(ap->a_vp);
+ zfsvfs_t *zfsvfs = ZTOZSB(zp);
+ char attrname[EXTATTR_MAXNAMELEN+1];
+ int error;
+
+ error = zfs_create_attrname(ap->a_attrnamespace, ap->a_name, attrname,
+ sizeof (attrname), compat);
+ if (error != 0)
+ return (error);
+
+ error = ENOENT;
+ if (zfsvfs->z_use_sa && zp->z_is_sa)
+ error = zfs_deleteextattr_sa(ap, attrname);
+ if (error == ENOENT)
+ error = zfs_deleteextattr_dir(ap, attrname);
+ return (error);
+}
+
/*
* Vnode operation to remove a named attribute.
*/
@@ -5528,7 +5586,6 @@ zfs_deleteextattr(struct vop_deleteextattr_args *ap)
{
znode_t *zp = VTOZ(ap->a_vp);
zfsvfs_t *zfsvfs = ZTOZSB(zp);
- char attrname[EXTATTR_MAXNAMELEN+1];
int error;
/*
@@ -5542,32 +5599,24 @@ zfs_deleteextattr(struct vop_deleteextattr_args *ap)
if (error != 0)
return (SET_ERROR(error));
- error = zfs_create_attrname(ap->a_attrnamespace, ap->a_name, attrname,
- sizeof (attrname));
+ error = zfs_check_attrname(ap->a_name);
if (error != 0)
return (error);
- size_t size = 0;
- struct vop_getextattr_args vga = {
- .a_vp = ap->a_vp,
- .a_size = &size,
- .a_cred = ap->a_cred,
- .a_td = ap->a_td,
- };
- error = ENOENT;
ZFS_ENTER(zfsvfs);
ZFS_VERIFY_ZP(zp);
rw_enter(&zp->z_xattr_lock, RW_WRITER);
- if (zfsvfs->z_use_sa && zp->z_is_sa) {
- error = zfs_getextattr_sa(&vga, attrname);
- if (error == 0)
- error = zfs_deleteextattr_sa(ap, attrname);
- }
- if (error == ENOENT) {
- error = zfs_getextattr_dir(&vga, attrname);
- if (error == 0)
- error = zfs_deleteextattr_dir(ap, attrname);
+
+ error = zfs_deleteextattr_impl(ap, zfs_xattr_compat);
+ if ((error == ENOENT || error == ENOATTR) &&
+ ap->a_attrnamespace == EXTATTR_NAMESPACE_USER) {
+ /*
+ * Fall back to the alternate namespace format if we failed to
+ * find a user xattr.
+ */
+ error = zfs_deleteextattr_impl(ap, !zfs_xattr_compat);
}
+
rw_exit(&zp->z_xattr_lock);
ZFS_EXIT(zfsvfs);
if (error == ENOENT)
@@ -5657,9 +5706,9 @@ zfs_setextattr_sa(struct vop_setextattr_args *ap, const char *attrname)
if (error != 0)
error = SET_ERROR(error);
}
- kmem_free(buf, entry_size);
if (error == 0)
- error = zfs_sa_set_xattr(zp);
+ error = zfs_sa_set_xattr(zp, attrname, buf, entry_size);
+ kmem_free(buf, entry_size);
if (error != 0) {
zp->z_xattr_cached = NULL;
nvlist_free(nvl);
@@ -5667,60 +5716,87 @@ zfs_setextattr_sa(struct vop_setextattr_args *ap, const char *attrname)
return (error);
}
-/*
- * Vnode operation to set a named attribute.
- */
static int
-zfs_setextattr(struct vop_setextattr_args *ap)
+zfs_setextattr_impl(struct vop_setextattr_args *ap, boolean_t compat)
{
znode_t *zp = VTOZ(ap->a_vp);
zfsvfs_t *zfsvfs = ZTOZSB(zp);
char attrname[EXTATTR_MAXNAMELEN+1];
int error;
- /*
- * If the xattr property is off, refuse the request.
- */
- if (!(zfsvfs->z_flags & ZSB_XATTR))
- return (SET_ERROR(EOPNOTSUPP));
-
- error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
- ap->a_cred, ap->a_td, VWRITE);
- if (error != 0)
- return (SET_ERROR(error));
-
error = zfs_create_attrname(ap->a_attrnamespace, ap->a_name, attrname,
- sizeof (attrname));
+ sizeof (attrname), compat);
if (error != 0)
return (error);
struct vop_deleteextattr_args vda = {
.a_vp = ap->a_vp,
+ .a_attrnamespace = ap->a_attrnamespace,
+ .a_name = ap->a_name,
.a_cred = ap->a_cred,
.a_td = ap->a_td,
};
error = ENOENT;
- ZFS_ENTER(zfsvfs);
- ZFS_VERIFY_ZP(zp);
- rw_enter(&zp->z_xattr_lock, RW_WRITER);
if (zfsvfs->z_use_sa && zp->z_is_sa && zfsvfs->z_xattr_sa) {
error = zfs_setextattr_sa(ap, attrname);
- if (error == 0)
+ if (error == 0) {
/*
* Successfully put into SA, we need to clear the one
* in dir if present.
*/
zfs_deleteextattr_dir(&vda, attrname);
+ }
}
- if (error) {
+ if (error != 0) {
error = zfs_setextattr_dir(ap, attrname);
- if (error == 0 && zp->z_is_sa)
+ if (error == 0 && zp->z_is_sa) {
/*
* Successfully put into dir, we need to clear the one
* in SA if present.
*/
zfs_deleteextattr_sa(&vda, attrname);
+ }
+ }
+ if (error == 0 && ap->a_attrnamespace == EXTATTR_NAMESPACE_USER) {
+ /*
+ * Also clear all versions of the alternate compat name.
+ */
+ zfs_deleteextattr_impl(&vda, !compat);
}
+ return (error);
+}
+
+/*
+ * Vnode operation to set a named attribute.
+ */
+static int
+zfs_setextattr(struct vop_setextattr_args *ap)
+{
+ znode_t *zp = VTOZ(ap->a_vp);
+ zfsvfs_t *zfsvfs = ZTOZSB(zp);
+ int error;
+
+ /*
+ * If the xattr property is off, refuse the request.
+ */
+ if (!(zfsvfs->z_flags & ZSB_XATTR))
+ return (SET_ERROR(EOPNOTSUPP));
+
+ error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
+ ap->a_cred, ap->a_td, VWRITE);
+ if (error != 0)
+ return (SET_ERROR(error));
+
+ error = zfs_check_attrname(ap->a_name);
+ if (error != 0)
+ return (error);
+
+ ZFS_ENTER(zfsvfs);
+ ZFS_VERIFY_ZP(zp);
+ rw_enter(&zp->z_xattr_lock, RW_WRITER);
+
+ error = zfs_setextattr_impl(ap, zfs_xattr_compat);
+
rw_exit(&zp->z_xattr_lock);
ZFS_EXIT(zfsvfs);
return (error);
@@ -5800,7 +5876,7 @@ zfs_listextattr_dir(struct vop_listextattr_args *ap, const char *attrprefix)
if (dp->d_type != DT_REG && dp->d_type != DT_UNKNOWN)
continue;
else if (plen == 0 &&
- strncmp(dp->d_name, "freebsd:", 8) == 0)
+ ZFS_XA_NS_PREFIX_FORBIDDEN(dp->d_name))
continue;
else if (strncmp(dp->d_name, attrprefix, plen) != 0)
continue;
@@ -5848,7 +5924,7 @@ zfs_listextattr_sa(struct vop_listextattr_args *ap, const char *attrprefix)
ASSERT3U(nvpair_type(nvp), ==, DATA_TYPE_BYTE_ARRAY);
const char *name = nvpair_name(nvp);
- if (plen == 0 && strncmp(name, "freebsd:", 8) == 0)
+ if (plen == 0 && ZFS_XA_NS_PREFIX_FORBIDDEN(name))
continue;
else if (strncmp(name, attrprefix, plen) != 0)
continue;
@@ -5875,6 +5951,26 @@ zfs_listextattr_sa(struct vop_listextattr_args *ap, const char *attrprefix)
return (error);
}
+static int
+zfs_listextattr_impl(struct vop_listextattr_args *ap, boolean_t compat)
+{
+ znode_t *zp = VTOZ(ap->a_vp);
+ zfsvfs_t *zfsvfs = ZTOZSB(zp);
+ char attrprefix[16];
+ int error;
+
+ error = zfs_create_attrname(ap->a_attrnamespace, "", attrprefix,
+ sizeof (attrprefix), compat);
+ if (error != 0)
+ return (error);
+
+ if (zfsvfs->z_use_sa && zp->z_is_sa)
+ error = zfs_listextattr_sa(ap, attrprefix);
+ if (error == 0)
+ error = zfs_listextattr_dir(ap, attrprefix);
+ return (error);
+}
+
/*
* Vnode operation to retrieve extended attributes on a vnode.
*/
@@ -5883,7 +5979,6 @@ zfs_listextattr(struct vop_listextattr_args *ap)
{
znode_t *zp = VTOZ(ap->a_vp);
zfsvfs_t *zfsvfs = ZTOZSB(zp);
- char attrprefix[16];
int error;
if (ap->a_size != NULL)
@@ -5900,18 +5995,16 @@ zfs_listextattr(struct vop_listextattr_args *ap)
if (error != 0)
return (SET_ERROR(error));
- error = zfs_create_attrname(ap->a_attrnamespace, "", attrprefix,
- sizeof (attrprefix));
- if (error != 0)
- return (error);
-
ZFS_ENTER(zfsvfs);
ZFS_VERIFY_ZP(zp);
rw_enter(&zp->z_xattr_lock, RW_READER);
- if (zfsvfs->z_use_sa && zp->z_is_sa)
- error = zfs_listextattr_sa(ap, attrprefix);
- if (error == 0)
- error = zfs_listextattr_dir(ap, attrprefix);
+
+ error = zfs_listextattr_impl(ap, zfs_xattr_compat);
+ if (error == 0 && ap->a_attrnamespace == EXTATTR_NAMESPACE_USER) {
+ /* Also list user xattrs with the alternate format. */
+ error = zfs_listextattr_impl(ap, !zfs_xattr_compat);
+ }
+
rw_exit(&zp->z_xattr_lock);
ZFS_EXIT(zfsvfs);
return (error);
@@ -6249,3 +6342,6 @@ struct vop_vector zfs_shareops = {
#endif
};
VFS_VOP_VECTOR_REGISTER(zfs_shareops);
+
+ZFS_MODULE_PARAM(zfs, zfs_, xattr_compat, INT, ZMOD_RW,
+ "Use legacy ZFS xattr naming for writing new user namespace xattrs");
diff --git a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_znode.c b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_znode.c
index 5978a1232249..e03840166ba4 100644
--- a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_znode.c
+++ b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_znode.c
@@ -156,10 +156,10 @@ zfs_znode_cache_constructor(void *buf, void *arg, int kmflags)
return (0);
}
-/*ARGSUSED*/
static void
zfs_znode_cache_destructor(void *buf, void *arg)
{
+ (void) arg;
znode_t *zp = buf;
ASSERT(!POINTER_IS_VALID(zp->z_zfsvfs));
diff --git a/sys/contrib/openzfs/module/os/freebsd/zfs/zio_crypt.c b/sys/contrib/openzfs/module/os/freebsd/zfs/zio_crypt.c
index ea120bcb5b03..a50b8058a945 100644
--- a/sys/contrib/openzfs/module/os/freebsd/zfs/zio_crypt.c
+++ b/sys/contrib/openzfs/module/os/freebsd/zfs/zio_crypt.c
@@ -270,11 +270,9 @@ zio_crypt_key_init(uint64_t crypt, zio_crypt_key_t *key)
goto error;
/* initialize keys for the ICP */
- key->zk_current_key.ck_format = CRYPTO_KEY_RAW;
key->zk_current_key.ck_data = key->zk_current_keydata;
key->zk_current_key.ck_length = CRYPTO_BYTES2BITS(keydata_len);
- key->zk_hmac_key.ck_format = CRYPTO_KEY_RAW;
key->zk_hmac_key.ck_data = &key->zk_hmac_key;
key->zk_hmac_key.ck_length = CRYPTO_BYTES2BITS(SHA512_HMAC_KEYLEN);
@@ -437,7 +435,6 @@ zio_crypt_key_wrap(crypto_key_t *cwkey, zio_crypt_key_t *key, uint8_t *iv,
uint_t enc_len, keydata_len, aad_len;
ASSERT3U(crypt, <, ZIO_CRYPT_FUNCTIONS);
- ASSERT3U(cwkey->ck_format, ==, CRYPTO_KEY_RAW);
zfs_uio_init(&cuio, &cuio_s);
@@ -518,7 +515,6 @@ zio_crypt_key_unwrap(crypto_key_t *cwkey, uint64_t crypt, uint64_t version,
uint_t enc_len, keydata_len, aad_len;
ASSERT3U(crypt, <, ZIO_CRYPT_FUNCTIONS);
- ASSERT3U(cwkey->ck_format, ==, CRYPTO_KEY_RAW);
keydata_len = zio_crypt_table[crypt].ci_keylen;
rw_init(&key->zk_salt_lock, NULL, RW_DEFAULT, NULL);
@@ -586,11 +582,9 @@ zio_crypt_key_unwrap(crypto_key_t *cwkey, uint64_t crypt, uint64_t version,
goto error;
/* initialize keys for ICP */
- key->zk_current_key.ck_format = CRYPTO_KEY_RAW;
key->zk_current_key.ck_data = key->zk_current_keydata;
key->zk_current_key.ck_length = CRYPTO_BYTES2BITS(keydata_len);
- key->zk_hmac_key.ck_format = CRYPTO_KEY_RAW;
key->zk_hmac_key.ck_data = key->zk_hmac_keydata;
key->zk_hmac_key.ck_length = CRYPTO_BYTES2BITS(SHA512_HMAC_KEYLEN);
@@ -1727,7 +1721,6 @@ zio_do_crypt_data(boolean_t encrypt, zio_crypt_key_t *key,
salt, ZIO_DATA_SALT_LEN, enc_keydata, keydata_len);
if (ret != 0)
goto error;
- tmp_ckey.ck_format = CRYPTO_KEY_RAW;
tmp_ckey.ck_data = enc_keydata;
tmp_ckey.ck_length = CRYPTO_BYTES2BITS(keydata_len);
@@ -1821,9 +1814,8 @@ error:
}
#if defined(_KERNEL) && defined(HAVE_SPL)
-/* BEGIN CSTYLED */
+/* CSTYLED */
module_param(zfs_key_max_salt_uses, ulong, 0644);
MODULE_PARM_DESC(zfs_key_max_salt_uses, "Max number of times a salt value "
"can be used for generating encryption keys before it is rotated");
-/* END CSTYLED */
#endif
diff --git a/sys/contrib/openzfs/module/os/freebsd/zfs/zvol_os.c b/sys/contrib/openzfs/module/os/freebsd/zfs/zvol_os.c
index 06dd8cfdd790..487778472e79 100644
--- a/sys/contrib/openzfs/module/os/freebsd/zfs/zvol_os.c
+++ b/sys/contrib/openzfs/module/os/freebsd/zfs/zvol_os.c
@@ -203,7 +203,6 @@ static int zvol_geom_bio_getattr(struct bio *bp);
* GEOM mode implementation
*/
-/*ARGSUSED*/
static int
zvol_geom_open(struct g_provider *pp, int flag, int count)
{
@@ -336,10 +335,10 @@ out_locked:
return (err);
}
-/*ARGSUSED*/
static int
zvol_geom_close(struct g_provider *pp, int flag, int count)
{
+ (void) flag;
zvol_state_t *zv;
boolean_t drop_suspend = B_TRUE;
int new_open_count;
@@ -1196,7 +1195,7 @@ zvol_ensure_zilog(zvol_state_t *zv)
zv->zv_zilog = zil_open(zv->zv_objset,
zvol_get_data);
zv->zv_flags |= ZVOL_WRITTEN_TO;
- /* replay / destroy done in zvol_create_minor_impl() */
+ /* replay / destroy done in zvol_os_create_minor() */
VERIFY0(zv->zv_zilog->zl_header->zh_flags &
ZIL_REPLAY_NEEDED);
}
@@ -1204,14 +1203,14 @@ zvol_ensure_zilog(zvol_state_t *zv)
}
}
-static boolean_t
-zvol_is_zvol_impl(const char *device)
+boolean_t
+zvol_os_is_zvol(const char *device)
{
return (device && strncmp(device, ZVOL_DIR, strlen(ZVOL_DIR)) == 0);
}
-static void
-zvol_rename_minor(zvol_state_t *zv, const char *newname)
+void
+zvol_os_rename_minor(zvol_state_t *zv, const char *newname)
{
ASSERT(RW_LOCK_HELD(&zvol_state_lock));
ASSERT(MUTEX_HELD(&zv->zv_state_lock));
@@ -1282,8 +1281,8 @@ zvol_rename_minor(zvol_state_t *zv, const char *newname)
/*
* Remove minor node for the specified volume.
*/
-static void
-zvol_free(zvol_state_t *zv)
+void
+zvol_os_free(zvol_state_t *zv)
{
ASSERT(!RW_LOCK_HELD(&zv->zv_suspend_lock));
ASSERT(!MUTEX_HELD(&zv->zv_state_lock));
@@ -1324,8 +1323,8 @@ zvol_free(zvol_state_t *zv)
/*
* Create a minor node (plus a whole lot more) for the specified volume.
*/
-static int
-zvol_create_minor_impl(const char *name)
+int
+zvol_os_create_minor(const char *name)
{
zvol_state_t *zv;
objset_t *os;
@@ -1463,8 +1462,8 @@ out_doi:
return (error);
}
-static void
-zvol_clear_private(zvol_state_t *zv)
+void
+zvol_os_clear_private(zvol_state_t *zv)
{
ASSERT(RW_LOCK_HELD(&zvol_state_lock));
if (zv->zv_volmode == ZFS_VOLMODE_GEOM) {
@@ -1492,8 +1491,8 @@ zvol_clear_private(zvol_state_t *zv)
}
}
-static int
-zvol_update_volsize(zvol_state_t *zv, uint64_t volsize)
+int
+zvol_os_update_volsize(zvol_state_t *zv, uint64_t volsize)
{
zv->zv_volsize = volsize;
if (zv->zv_volmode == ZFS_VOLMODE_GEOM) {
@@ -1522,29 +1521,18 @@ zvol_update_volsize(zvol_state_t *zv, uint64_t volsize)
return (0);
}
-static void
-zvol_set_disk_ro_impl(zvol_state_t *zv, int flags)
+void
+zvol_os_set_disk_ro(zvol_state_t *zv, int flags)
{
// XXX? set_disk_ro(zv->zv_zso->zvo_disk, flags);
}
-static void
-zvol_set_capacity_impl(zvol_state_t *zv, uint64_t capacity)
+void
+zvol_os_set_capacity(zvol_state_t *zv, uint64_t capacity)
{
// XXX? set_capacity(zv->zv_zso->zvo_disk, capacity);
}
-const static zvol_platform_ops_t zvol_freebsd_ops = {
- .zv_free = zvol_free,
- .zv_rename_minor = zvol_rename_minor,
- .zv_create_minor = zvol_create_minor_impl,
- .zv_update_volsize = zvol_update_volsize,
- .zv_clear_private = zvol_clear_private,
- .zv_is_zvol = zvol_is_zvol_impl,
- .zv_set_disk_ro = zvol_set_disk_ro_impl,
- .zv_set_capacity = zvol_set_capacity_impl,
-};
-
/*
* Public interfaces
*/
@@ -1559,7 +1547,6 @@ int
zvol_init(void)
{
zvol_init_impl();
- zvol_register_ops(&zvol_freebsd_ops);
return (0);
}
diff --git a/sys/contrib/openzfs/module/os/linux/spl/spl-err.c b/sys/contrib/openzfs/module/os/linux/spl/spl-err.c
index 10b768d57360..c84c39b56bf7 100644
--- a/sys/contrib/openzfs/module/os/linux/spl/spl-err.c
+++ b/sys/contrib/openzfs/module/os/linux/spl/spl-err.c
@@ -32,11 +32,10 @@
* analysis and other such goodies.
* But we would still default to the current default of not to do that.
*/
-/* BEGIN CSTYLED */
unsigned int spl_panic_halt;
+/* CSTYLED */
module_param(spl_panic_halt, uint, 0644);
MODULE_PARM_DESC(spl_panic_halt, "Cause kernel panic on assertion failures");
-/* END CSTYLED */
void
spl_dumpstack(void)
@@ -101,6 +100,9 @@ vcmn_err(int ce, const char *fmt, va_list ap)
break;
case CE_PANIC:
printk(KERN_EMERG "PANIC: %s\n", msg);
+ if (spl_panic_halt)
+ panic("%s", msg);
+
spl_dumpstack();
/* Halt the thread to facilitate further debugging */
diff --git a/sys/contrib/openzfs/module/os/linux/spl/spl-generic.c b/sys/contrib/openzfs/module/os/linux/spl/spl-generic.c
index a7239385953e..5bf2f6912457 100644
--- a/sys/contrib/openzfs/module/os/linux/spl/spl-generic.c
+++ b/sys/contrib/openzfs/module/os/linux/spl/spl-generic.c
@@ -48,13 +48,12 @@
#include <sys/cred.h>
#include <sys/vnode.h>
-/* BEGIN CSTYLED */
unsigned long spl_hostid = 0;
EXPORT_SYMBOL(spl_hostid);
+/* CSTYLED */
module_param(spl_hostid, ulong, 0644);
MODULE_PARM_DESC(spl_hostid, "The system hostid.");
-/* END CSTYLED */
proc_t p0;
EXPORT_SYMBOL(p0);
@@ -268,11 +267,10 @@ __udivdi3(uint64_t u, uint64_t v)
}
EXPORT_SYMBOL(__udivdi3);
-/* BEGIN CSTYLED */
#ifndef abs64
+/* CSTYLED */
#define abs64(x) ({ uint64_t t = (x) >> 63; ((x) ^ t) - t; })
#endif
-/* END CSTYLED */
/*
* Implementation of 64-bit signed division for 32-bit machines.
@@ -384,11 +382,9 @@ __aeabi_uldivmod(uint64_t u, uint64_t v)
register uint32_t r2 asm("r2") = (mod & 0xFFFFFFFF);
register uint32_t r3 asm("r3") = (mod >> 32);
- /* BEGIN CSTYLED */
asm volatile(""
- : "+r"(r0), "+r"(r1), "+r"(r2),"+r"(r3) /* output */
- : "r"(r0), "r"(r1), "r"(r2), "r"(r3)); /* input */
- /* END CSTYLED */
+ : "+r"(r0), "+r"(r1), "+r"(r2), "+r"(r3) /* output */
+ : "r"(r0), "r"(r1), "r"(r2), "r"(r3)); /* input */
return; /* r0; */
}
@@ -409,11 +405,9 @@ __aeabi_ldivmod(int64_t u, int64_t v)
register uint32_t r2 asm("r2") = (mod & 0xFFFFFFFF);
register uint32_t r3 asm("r3") = (mod >> 32);
- /* BEGIN CSTYLED */
asm volatile(""
- : "+r"(r0), "+r"(r1), "+r"(r2),"+r"(r3) /* output */
- : "r"(r0), "r"(r1), "r"(r2), "r"(r3)); /* input */
- /* END CSTYLED */
+ : "+r"(r0), "+r"(r1), "+r"(r2), "+r"(r3) /* output */
+ : "r"(r0), "r"(r1), "r"(r2), "r"(r3)); /* input */
return; /* r0; */
}
diff --git a/sys/contrib/openzfs/module/os/linux/spl/spl-kmem-cache.c b/sys/contrib/openzfs/module/os/linux/spl/spl-kmem-cache.c
index 3d926173674d..bb2b56880646 100644
--- a/sys/contrib/openzfs/module/os/linux/spl/spl-kmem-cache.c
+++ b/sys/contrib/openzfs/module/os/linux/spl/spl-kmem-cache.c
@@ -57,7 +57,6 @@
#endif
/* BEGIN CSTYLED */
-
/*
* Cache magazines are an optimization designed to minimize the cost of
* allocating memory. They do this by keeping a per-cpu cache of recently
diff --git a/sys/contrib/openzfs/module/os/linux/spl/spl-kmem.c b/sys/contrib/openzfs/module/os/linux/spl/spl-kmem.c
index 2b342140d0e2..d85e2a7daa8d 100644
--- a/sys/contrib/openzfs/module/os/linux/spl/spl-kmem.c
+++ b/sys/contrib/openzfs/module/os/linux/spl/spl-kmem.c
@@ -26,6 +26,7 @@
#include <sys/kmem.h>
#include <sys/vmem.h>
+/* BEGIN CSTYLED */
/*
* As a general rule kmem_alloc() allocations should be small, preferably
* just a few pages since they must by physically contiguous. Therefore, a
@@ -41,7 +42,6 @@
* allocations are quickly caught. These warnings may be disabled by setting
* the threshold to zero.
*/
-/* BEGIN CSTYLED */
unsigned int spl_kmem_alloc_warn = MIN(16 * PAGE_SIZE, 64 * 1024);
module_param(spl_kmem_alloc_warn, uint, 0644);
MODULE_PARM_DESC(spl_kmem_alloc_warn,
diff --git a/sys/contrib/openzfs/module/os/linux/spl/spl-kstat.c b/sys/contrib/openzfs/module/os/linux/spl/spl-kstat.c
index a417d4d7c358..c6d3c8f4413f 100644
--- a/sys/contrib/openzfs/module/os/linux/spl/spl-kstat.c
+++ b/sys/contrib/openzfs/module/os/linux/spl/spl-kstat.c
@@ -418,7 +418,7 @@ proc_kstat_open(struct inode *inode, struct file *filp)
return (rc);
f = filp->private_data;
- f->private = PDE_DATA(inode);
+ f->private = SPL_PDE_DATA(inode);
return (0);
}
diff --git a/sys/contrib/openzfs/module/os/linux/spl/spl-proc.c b/sys/contrib/openzfs/module/os/linux/spl/spl-proc.c
index f500492eafdc..01f5619e1893 100644
--- a/sys/contrib/openzfs/module/os/linux/spl/spl-proc.c
+++ b/sys/contrib/openzfs/module/os/linux/spl/spl-proc.c
@@ -180,11 +180,10 @@ taskq_seq_show_headers(struct seq_file *f)
#define LHEAD_ACTIVE 4
#define LHEAD_SIZE 5
-/* BEGIN CSTYLED */
static unsigned int spl_max_show_tasks = 512;
+/* CSTYLED */
module_param(spl_max_show_tasks, uint, 0644);
MODULE_PARM_DESC(spl_max_show_tasks, "Max number of tasks shown in taskq proc");
-/* END CSTYLED */
static int
taskq_seq_show_impl(struct seq_file *f, void *p, boolean_t allflag)
diff --git a/sys/contrib/openzfs/module/os/linux/spl/spl-procfs-list.c b/sys/contrib/openzfs/module/os/linux/spl/spl-procfs-list.c
index 1922825c94a8..81501460f04f 100644
--- a/sys/contrib/openzfs/module/os/linux/spl/spl-procfs-list.c
+++ b/sys/contrib/openzfs/module/os/linux/spl/spl-procfs-list.c
@@ -175,7 +175,7 @@ procfs_list_open(struct inode *inode, struct file *filp)
struct seq_file *f = filp->private_data;
procfs_list_cursor_t *cursor = f->private;
- cursor->procfs_list = PDE_DATA(inode);
+ cursor->procfs_list = SPL_PDE_DATA(inode);
cursor->cached_node = NULL;
cursor->cached_pos = 0;
diff --git a/sys/contrib/openzfs/module/os/linux/spl/spl-thread.c b/sys/contrib/openzfs/module/os/linux/spl/spl-thread.c
index 834c527117a3..16d2ca1b133b 100644
--- a/sys/contrib/openzfs/module/os/linux/spl/spl-thread.c
+++ b/sys/contrib/openzfs/module/os/linux/spl/spl-thread.c
@@ -66,7 +66,7 @@ void
__thread_exit(void)
{
tsd_exit();
- complete_and_exit(NULL, 0);
+ SPL_KTHREAD_COMPLETE_AND_EXIT(NULL, 0);
/* Unreachable */
}
EXPORT_SYMBOL(__thread_exit);
@@ -188,7 +188,12 @@ issig(int why)
spin_lock_irq(&task->sighand->siglock);
int ret;
+#ifdef HAVE_DEQUEUE_SIGNAL_4ARG
+ enum pid_type __type;
+ if ((ret = dequeue_signal(task, &set, &__info, &__type)) != 0) {
+#else
if ((ret = dequeue_signal(task, &set, &__info)) != 0) {
+#endif
#ifdef HAVE_SIGNAL_STOP
spin_unlock_irq(&task->sighand->siglock);
kernel_signal_stop();
diff --git a/sys/contrib/openzfs/module/os/linux/zfs/arc_os.c b/sys/contrib/openzfs/module/os/linux/zfs/arc_os.c
index 3dc0b7106112..a95e9c334af9 100644
--- a/sys/contrib/openzfs/module/os/linux/zfs/arc_os.c
+++ b/sys/contrib/openzfs/module/os/linux/zfs/arc_os.c
@@ -536,7 +536,5 @@ arc_prune_async(int64_t adjust)
mutex_exit(&arc_prune_mtx);
}
-/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs_arc, zfs_arc_, shrinker_limit, INT, ZMOD_RW,
"Limit on number of pages that ARC shrinker can reclaim at once");
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/os/linux/zfs/spa_misc_os.c b/sys/contrib/openzfs/module/os/linux/zfs/spa_misc_os.c
index 5672cd6d5c5e..cbdc0f350ad8 100644
--- a/sys/contrib/openzfs/module/os/linux/zfs/spa_misc_os.c
+++ b/sys/contrib/openzfs/module/os/linux/zfs/spa_misc_os.c
@@ -108,3 +108,27 @@ spa_history_zone(void)
{
return ("linux");
}
+
+void
+spa_import_os(spa_t *spa)
+{
+ (void) spa;
+}
+
+void
+spa_export_os(spa_t *spa)
+{
+ (void) spa;
+}
+
+void
+spa_activate_os(spa_t *spa)
+{
+ (void) spa;
+}
+
+void
+spa_deactivate_os(spa_t *spa)
+{
+ (void) spa;
+}
diff --git a/sys/contrib/openzfs/module/os/linux/zfs/vdev_disk.c b/sys/contrib/openzfs/module/os/linux/zfs/vdev_disk.c
index c06ba613b16d..61518bad0b1c 100644
--- a/sys/contrib/openzfs/module/os/linux/zfs/vdev_disk.c
+++ b/sys/contrib/openzfs/module/os/linux/zfs/vdev_disk.c
@@ -446,7 +446,7 @@ vdev_submit_bio_impl(struct bio *bio)
#ifdef HAVE_1ARG_SUBMIT_BIO
(void) submit_bio(bio);
#else
- (void) submit_bio(0, bio);
+ (void) submit_bio(bio_data_dir(bio), bio);
#endif
}
diff --git a/sys/contrib/openzfs/module/os/linux/zfs/zfs_acl.c b/sys/contrib/openzfs/module/os/linux/zfs/zfs_acl.c
index 94b20dd6e582..1859ecd9913b 100644
--- a/sys/contrib/openzfs/module/os/linux/zfs/zfs_acl.c
+++ b/sys/contrib/openzfs/module/os/linux/zfs/zfs_acl.c
@@ -144,10 +144,10 @@ zfs_ace_v0_set_who(void *acep, uint64_t who)
((zfs_oldace_t *)acep)->z_fuid = who;
}
-/*ARGSUSED*/
static size_t
zfs_ace_v0_size(void *acep)
{
+ (void) acep;
return (sizeof (zfs_oldace_t));
}
@@ -163,10 +163,10 @@ zfs_ace_v0_mask_off(void)
return (offsetof(zfs_oldace_t, z_access_mask));
}
-/*ARGSUSED*/
static int
zfs_ace_v0_data(void *acep, void **datap)
{
+ (void) acep;
*datap = NULL;
return (0);
}
@@ -269,7 +269,7 @@ zfs_ace_fuid_size(void *acep)
entry_type == OWNING_GROUP ||
entry_type == ACE_EVERYONE)
return (sizeof (zfs_ace_hdr_t));
- fallthrough;
+ zfs_fallthrough;
default:
return (sizeof (zfs_ace_t));
}
@@ -629,11 +629,11 @@ zfs_acl_next_ace(zfs_acl_t *aclp, void *start, uint64_t *who,
return (NULL);
}
-/*ARGSUSED*/
static uint64_t
zfs_ace_walk(void *datap, uint64_t cookie, int aclcnt,
uint16_t *flags, uint16_t *type, uint32_t *mask)
{
+ (void) aclcnt;
zfs_acl_t *aclp = datap;
zfs_ace_hdr_t *acep = (zfs_ace_hdr_t *)(uintptr_t)cookie;
uint64_t who;
@@ -1130,11 +1130,11 @@ done:
return (error);
}
-/*ARGSUSED*/
void
zfs_acl_data_locator(void **dataptr, uint32_t *length, uint32_t buflen,
boolean_t start, void *userdata)
{
+ (void) buflen;
zfs_acl_locator_cb_t *cb = (zfs_acl_locator_cb_t *)userdata;
if (start) {
@@ -2317,7 +2317,7 @@ zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode,
break;
case OWNING_GROUP:
who = gowner;
- fallthrough;
+ zfs_fallthrough;
case ACE_IDENTIFIER_GROUP:
checkit = zfs_groupmember(zfsvfs, who, cr);
break;
diff --git a/sys/contrib/openzfs/module/os/linux/zfs/zfs_vfsops.c b/sys/contrib/openzfs/module/os/linux/zfs/zfs_vfsops.c
index acf8c7b89522..412af0e88931 100644
--- a/sys/contrib/openzfs/module/os/linux/zfs/zfs_vfsops.c
+++ b/sys/contrib/openzfs/module/os/linux/zfs/zfs_vfsops.c
@@ -256,10 +256,10 @@ zfs_is_readonly(zfsvfs_t *zfsvfs)
return (!!(zfsvfs->z_sb->s_flags & SB_RDONLY));
}
-/*ARGSUSED*/
int
zfs_sync(struct super_block *sb, int wait, cred_t *cr)
{
+ (void) cr;
zfsvfs_t *zfsvfs = sb->s_fs_info;
/*
@@ -1600,7 +1600,6 @@ zfs_preumount(struct super_block *sb)
* Called once all other unmount released tear down has occurred.
* It is our responsibility to release any remaining infrastructure.
*/
-/*ARGSUSED*/
int
zfs_umount(struct super_block *sb)
{
@@ -2128,7 +2127,6 @@ zfs_get_vfs_flag_unmounted(objset_t *os)
return (unmounted);
}
-/*ARGSUSED*/
void
zfsvfs_update_fromname(const char *oldname, const char *newname)
{
@@ -2136,6 +2134,7 @@ zfsvfs_update_fromname(const char *oldname, const char *newname)
* We don't need to do anything here, the devname is always current by
* virtue of zfsvfs->z_sb->s_op->show_devname.
*/
+ (void) oldname, (void) newname;
}
void
diff --git a/sys/contrib/openzfs/module/os/linux/zfs/zfs_vnops_os.c b/sys/contrib/openzfs/module/os/linux/zfs/zfs_vnops_os.c
index aff3c4ad4e4c..ece7c373e852 100644
--- a/sys/contrib/openzfs/module/os/linux/zfs/zfs_vnops_os.c
+++ b/sys/contrib/openzfs/module/os/linux/zfs/zfs_vnops_os.c
@@ -174,11 +174,10 @@
* ZFS_EXIT(zfsvfs); // finished in zfs
* return (error); // done, report error
*/
-
-/* ARGSUSED */
int
zfs_open(struct inode *ip, int mode, int flag, cred_t *cr)
{
+ (void) cr;
znode_t *zp = ITOZ(ip);
zfsvfs_t *zfsvfs = ITOZSB(ip);
@@ -200,10 +199,10 @@ zfs_open(struct inode *ip, int mode, int flag, cred_t *cr)
return (0);
}
-/* ARGSUSED */
int
zfs_close(struct inode *ip, int flag, cred_t *cr)
{
+ (void) cr;
znode_t *zp = ITOZ(ip);
zfsvfs_t *zfsvfs = ITOZSB(ip);
@@ -415,7 +414,6 @@ zfs_zrele_async(znode_t *zp)
* Timestamps:
* NA
*/
-/* ARGSUSED */
int
zfs_lookup(znode_t *zdp, char *nm, znode_t **zpp, int flags, cred_t *cr,
int *direntflags, pathname_t *realpnp)
@@ -535,8 +533,6 @@ zfs_lookup(znode_t *zdp, char *nm, znode_t **zpp, int flags, cred_t *cr,
* dzp - ctime|mtime updated if new entry created
* zp - ctime|mtime always, atime if new
*/
-
-/* ARGSUSED */
int
zfs_create(znode_t *dzp, char *name, vattr_t *vap, int excl,
int mode, znode_t **zpp, cred_t *cr, int flag, vsecattr_t *vsecp)
@@ -782,11 +778,11 @@ out:
return (error);
}
-/* ARGSUSED */
int
zfs_tmpfile(struct inode *dip, vattr_t *vap, int excl,
int mode, struct inode **ipp, cred_t *cr, int flag, vsecattr_t *vsecp)
{
+ (void) excl, (void) mode, (void) flag;
znode_t *zp = NULL, *dzp = ITOZ(dip);
zfsvfs_t *zfsvfs = ITOZSB(dip);
objset_t *os;
@@ -918,9 +914,8 @@ out:
* ip - ctime (if nlink > 0)
*/
-uint64_t null_xattr = 0;
+static uint64_t null_xattr = 0;
-/*ARGSUSED*/
int
zfs_remove(znode_t *dzp, char *name, cred_t *cr, int flags)
{
@@ -1160,7 +1155,6 @@ out:
* dzp - ctime|mtime updated
* zpp - ctime|mtime|atime updated
*/
-/*ARGSUSED*/
int
zfs_mkdir(znode_t *dzp, char *dirname, vattr_t *vap, znode_t **zpp,
cred_t *cr, int flags, vsecattr_t *vsecp)
@@ -1349,7 +1343,6 @@ out:
* Timestamps:
* dzp - ctime|mtime updated
*/
-/*ARGSUSED*/
int
zfs_rmdir(znode_t *dzp, char *name, znode_t *cwd, cred_t *cr,
int flags)
@@ -1482,10 +1475,10 @@ out:
* We use 0 for '.', and 1 for '..'. If this is the root of the filesystem,
* we use the offset 2 for the '.zfs' directory.
*/
-/* ARGSUSED */
int
zfs_readdir(struct inode *ip, zpl_dir_context_t *ctx, cred_t *cr)
{
+ (void) cr;
znode_t *zp = ITOZ(ip);
zfsvfs_t *zfsvfs = ITOZSB(ip);
objset_t *os;
@@ -1635,7 +1628,6 @@ out:
*
* RETURN: 0 (always succeeds)
*/
-/* ARGSUSED */
int
zfs_getattr_fast(struct user_namespace *user_ns, struct inode *ip,
struct kstat *sp)
@@ -1823,7 +1815,6 @@ next:
* Timestamps:
* ip - ctime updated, mtime updated if size changed.
*/
-/* ARGSUSED */
int
zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr)
{
@@ -2652,7 +2643,6 @@ zfs_rename_lock(znode_t *szp, znode_t *tdzp, znode_t *sdzp, zfs_zlock_t **zlpp)
* Timestamps:
* sdzp,tdzp - ctime|mtime updated
*/
-/*ARGSUSED*/
int
zfs_rename(znode_t *sdzp, char *snm, znode_t *tdzp, char *tnm,
cred_t *cr, int flags)
@@ -3020,7 +3010,6 @@ out:
* Timestamps:
* dip - ctime|mtime updated
*/
-/*ARGSUSED*/
int
zfs_symlink(znode_t *dzp, char *name, vattr_t *vap, char *link,
znode_t **zpp, cred_t *cr, int flags)
@@ -3188,10 +3177,10 @@ top:
* Timestamps:
* ip - atime updated
*/
-/* ARGSUSED */
int
zfs_readlink(struct inode *ip, zfs_uio_t *uio, cred_t *cr)
{
+ (void) cr;
znode_t *zp = ITOZ(ip);
zfsvfs_t *zfsvfs = ITOZSB(ip);
int error;
@@ -3227,7 +3216,6 @@ zfs_readlink(struct inode *ip, zfs_uio_t *uio, cred_t *cr)
* tdzp - ctime|mtime updated
* szp - ctime updated
*/
-/* ARGSUSED */
int
zfs_link(znode_t *tdzp, znode_t *szp, char *name, cred_t *cr,
int flags)
@@ -3430,7 +3418,6 @@ zfs_putpage_commit_cb(void *arg)
* Timestamps:
* ip - ctime|mtime updated
*/
-/* ARGSUSED */
int
zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc)
{
@@ -3610,6 +3597,8 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc)
zil_commit(zfsvfs->z_log, zp->z_id);
}
+ dataset_kstats_update_write_kstats(&zfsvfs->z_kstat, pglen);
+
ZFS_EXIT(zfsvfs);
return (err);
}
@@ -3685,7 +3674,6 @@ out:
return (error);
}
-/*ARGSUSED*/
void
zfs_inactive(struct inode *ip)
{
@@ -3789,7 +3777,6 @@ zfs_fillpage(struct inode *ip, struct page *pl[], int nr_pages)
* Timestamps:
* vp - atime updated
*/
-/* ARGSUSED */
int
zfs_getpage(struct inode *ip, struct page *pl[], int nr_pages)
{
@@ -3805,6 +3792,8 @@ zfs_getpage(struct inode *ip, struct page *pl[], int nr_pages)
err = zfs_fillpage(ip, pl, nr_pages);
+ dataset_kstats_update_read_kstats(&zfsvfs->z_kstat, nr_pages*PAGESIZE);
+
ZFS_EXIT(zfsvfs);
return (err);
}
@@ -3821,11 +3810,11 @@ zfs_getpage(struct inode *ip, struct page *pl[], int nr_pages)
* RETURN: 0 if success
* error code if failure
*/
-/*ARGSUSED*/
int
zfs_map(struct inode *ip, offset_t off, caddr_t *addrp, size_t len,
unsigned long vm_flags)
{
+ (void) addrp;
znode_t *zp = ITOZ(ip);
zfsvfs_t *zfsvfs = ITOZSB(ip);
@@ -3871,11 +3860,11 @@ zfs_map(struct inode *ip, offset_t off, caddr_t *addrp, size_t len,
* Timestamps:
* zp - ctime|mtime updated
*/
-/* ARGSUSED */
int
zfs_space(znode_t *zp, int cmd, flock64_t *bfp, int flag,
offset_t offset, cred_t *cr)
{
+ (void) offset;
zfsvfs_t *zfsvfs = ZTOZSB(zp);
uint64_t off, len;
int error;
@@ -3922,7 +3911,6 @@ zfs_space(znode_t *zp, int cmd, flock64_t *bfp, int flag,
return (error);
}
-/*ARGSUSED*/
int
zfs_fid(struct inode *ip, fid_t *fidp)
{
@@ -3995,9 +3983,8 @@ EXPORT_SYMBOL(zfs_putpage);
EXPORT_SYMBOL(zfs_dirty_inode);
EXPORT_SYMBOL(zfs_map);
-/* BEGIN CSTYLED */
+/* CSTYLED */
module_param(zfs_delete_blocks, ulong, 0644);
MODULE_PARM_DESC(zfs_delete_blocks, "Delete files larger than N blocks async");
-/* END CSTYLED */
#endif
diff --git a/sys/contrib/openzfs/module/os/linux/zfs/zfs_znode.c b/sys/contrib/openzfs/module/os/linux/zfs/zfs_znode.c
index 5b1573a6df1a..d65d75312828 100644
--- a/sys/contrib/openzfs/module/os/linux/zfs/zfs_znode.c
+++ b/sys/contrib/openzfs/module/os/linux/zfs/zfs_znode.c
@@ -113,10 +113,10 @@ zfs_rangelock_cb(zfs_locked_range_t *new, void *arg)
}
}
-/*ARGSUSED*/
static int
zfs_znode_cache_constructor(void *buf, void *arg, int kmflags)
{
+ (void) arg, (void) kmflags;
znode_t *zp = buf;
inode_init_once(ZTOI(zp));
@@ -137,10 +137,10 @@ zfs_znode_cache_constructor(void *buf, void *arg, int kmflags)
return (0);
}
-/*ARGSUSED*/
static void
zfs_znode_cache_destructor(void *buf, void *arg)
{
+ (void) arg;
znode_t *zp = buf;
ASSERT(!list_link_active(&zp->z_link_node));
@@ -159,6 +159,7 @@ zfs_znode_cache_destructor(void *buf, void *arg)
static int
zfs_znode_hold_cache_constructor(void *buf, void *arg, int kmflags)
{
+ (void) arg, (void) kmflags;
znode_hold_t *zh = buf;
mutex_init(&zh->zh_lock, NULL, MUTEX_DEFAULT, NULL);
@@ -171,6 +172,7 @@ zfs_znode_hold_cache_constructor(void *buf, void *arg, int kmflags)
static void
zfs_znode_hold_cache_destructor(void *buf, void *arg)
{
+ (void) arg;
znode_hold_t *zh = buf;
mutex_destroy(&zh->zh_lock);
@@ -430,7 +432,7 @@ zfs_inode_set_ops(zfsvfs_t *zfsvfs, struct inode *ip)
case S_IFBLK:
(void) sa_lookup(ITOZ(ip)->z_sa_hdl, SA_ZPL_RDEV(zfsvfs), &rdev,
sizeof (rdev));
- fallthrough;
+ zfs_fallthrough;
case S_IFIFO:
case S_IFSOCK:
init_special_inode(ip, ip->i_mode, rdev);
diff --git a/sys/contrib/openzfs/module/os/linux/zfs/zio_crypt.c b/sys/contrib/openzfs/module/os/linux/zfs/zio_crypt.c
index a979f7e20c1b..099d23484d32 100644
--- a/sys/contrib/openzfs/module/os/linux/zfs/zio_crypt.c
+++ b/sys/contrib/openzfs/module/os/linux/zfs/zio_crypt.c
@@ -257,11 +257,9 @@ zio_crypt_key_init(uint64_t crypt, zio_crypt_key_t *key)
goto error;
/* initialize keys for the ICP */
- key->zk_current_key.ck_format = CRYPTO_KEY_RAW;
key->zk_current_key.ck_data = key->zk_current_keydata;
key->zk_current_key.ck_length = CRYPTO_BYTES2BITS(keydata_len);
- key->zk_hmac_key.ck_format = CRYPTO_KEY_RAW;
key->zk_hmac_key.ck_data = &key->zk_hmac_key;
key->zk_hmac_key.ck_length = CRYPTO_BYTES2BITS(SHA512_HMAC_KEYLEN);
@@ -271,13 +269,13 @@ zio_crypt_key_init(uint64_t crypt, zio_crypt_key_t *key)
*/
mech.cm_type = crypto_mech2id(zio_crypt_table[crypt].ci_mechname);
ret = crypto_create_ctx_template(&mech, &key->zk_current_key,
- &key->zk_current_tmpl, KM_SLEEP);
+ &key->zk_current_tmpl);
if (ret != CRYPTO_SUCCESS)
key->zk_current_tmpl = NULL;
mech.cm_type = crypto_mech2id(SUN_CKM_SHA512_HMAC);
ret = crypto_create_ctx_template(&mech, &key->zk_hmac_key,
- &key->zk_hmac_tmpl, KM_SLEEP);
+ &key->zk_hmac_tmpl);
if (ret != CRYPTO_SUCCESS)
key->zk_hmac_tmpl = NULL;
@@ -325,7 +323,7 @@ zio_crypt_key_change_salt(zio_crypt_key_t *key)
/* destroy the old context template and create the new one */
crypto_destroy_ctx_template(key->zk_current_tmpl);
ret = crypto_create_ctx_template(&mech, &key->zk_current_key,
- &key->zk_current_tmpl, KM_SLEEP);
+ &key->zk_current_tmpl);
if (ret != CRYPTO_SUCCESS)
key->zk_current_tmpl = NULL;
@@ -387,7 +385,6 @@ zio_do_crypt_uio(boolean_t encrypt, uint64_t crypt, crypto_key_t *key,
uint_t plain_full_len, maclen;
ASSERT3U(crypt, <, ZIO_CRYPT_FUNCTIONS);
- ASSERT3U(key->ck_format, ==, CRYPTO_KEY_RAW);
/* lookup the encryption info */
crypt_info = zio_crypt_table[crypt];
@@ -441,26 +438,22 @@ zio_do_crypt_uio(boolean_t encrypt, uint64_t crypt, crypto_key_t *key,
plaindata.cd_format = CRYPTO_DATA_UIO;
plaindata.cd_offset = 0;
plaindata.cd_uio = puio;
- plaindata.cd_miscdata = NULL;
plaindata.cd_length = plain_full_len;
cipherdata.cd_format = CRYPTO_DATA_UIO;
cipherdata.cd_offset = 0;
cipherdata.cd_uio = cuio;
- cipherdata.cd_miscdata = NULL;
cipherdata.cd_length = datalen + maclen;
/* perform the actual encryption */
if (encrypt) {
- ret = crypto_encrypt(&mech, &plaindata, key, tmpl, &cipherdata,
- NULL);
+ ret = crypto_encrypt(&mech, &plaindata, key, tmpl, &cipherdata);
if (ret != CRYPTO_SUCCESS) {
ret = SET_ERROR(EIO);
goto error;
}
} else {
- ret = crypto_decrypt(&mech, &cipherdata, key, tmpl, &plaindata,
- NULL);
+ ret = crypto_decrypt(&mech, &cipherdata, key, tmpl, &plaindata);
if (ret != CRYPTO_SUCCESS) {
ASSERT3U(ret, ==, CRYPTO_INVALID_MAC);
ret = SET_ERROR(ECKSUM);
@@ -486,7 +479,6 @@ zio_crypt_key_wrap(crypto_key_t *cwkey, zio_crypt_key_t *key, uint8_t *iv,
uint_t enc_len, keydata_len, aad_len;
ASSERT3U(crypt, <, ZIO_CRYPT_FUNCTIONS);
- ASSERT3U(cwkey->ck_format, ==, CRYPTO_KEY_RAW);
keydata_len = zio_crypt_table[crypt].ci_keylen;
@@ -557,7 +549,6 @@ zio_crypt_key_unwrap(crypto_key_t *cwkey, uint64_t crypt, uint64_t version,
int ret;
ASSERT3U(crypt, <, ZIO_CRYPT_FUNCTIONS);
- ASSERT3U(cwkey->ck_format, ==, CRYPTO_KEY_RAW);
rw_init(&key->zk_salt_lock, NULL, RW_DEFAULT, NULL);
@@ -614,11 +605,9 @@ zio_crypt_key_unwrap(crypto_key_t *cwkey, uint64_t crypt, uint64_t version,
goto error;
/* initialize keys for ICP */
- key->zk_current_key.ck_format = CRYPTO_KEY_RAW;
key->zk_current_key.ck_data = key->zk_current_keydata;
key->zk_current_key.ck_length = CRYPTO_BYTES2BITS(keydata_len);
- key->zk_hmac_key.ck_format = CRYPTO_KEY_RAW;
key->zk_hmac_key.ck_data = key->zk_hmac_keydata;
key->zk_hmac_key.ck_length = CRYPTO_BYTES2BITS(SHA512_HMAC_KEYLEN);
@@ -628,13 +617,13 @@ zio_crypt_key_unwrap(crypto_key_t *cwkey, uint64_t crypt, uint64_t version,
*/
mech.cm_type = crypto_mech2id(zio_crypt_table[crypt].ci_mechname);
ret = crypto_create_ctx_template(&mech, &key->zk_current_key,
- &key->zk_current_tmpl, KM_SLEEP);
+ &key->zk_current_tmpl);
if (ret != CRYPTO_SUCCESS)
key->zk_current_tmpl = NULL;
mech.cm_type = crypto_mech2id(SUN_CKM_SHA512_HMAC);
ret = crypto_create_ctx_template(&mech, &key->zk_hmac_key,
- &key->zk_hmac_tmpl, KM_SLEEP);
+ &key->zk_hmac_tmpl);
if (ret != CRYPTO_SUCCESS)
key->zk_hmac_tmpl = NULL;
@@ -698,7 +687,7 @@ zio_crypt_do_hmac(zio_crypt_key_t *key, uint8_t *data, uint_t datalen,
/* generate the hmac */
ret = crypto_mac(&mech, &in_data, &key->zk_hmac_key, key->zk_hmac_tmpl,
- &digest_data, NULL);
+ &digest_data);
if (ret != CRYPTO_SUCCESS) {
ret = SET_ERROR(EIO);
goto error;
@@ -1004,7 +993,7 @@ zio_crypt_bp_do_hmac_updates(crypto_context_t ctx, uint64_t version,
cd.cd_raw.iov_base = (char *)&bab;
cd.cd_raw.iov_len = cd.cd_length;
- ret = crypto_mac_update(ctx, &cd, NULL);
+ ret = crypto_mac_update(ctx, &cd);
if (ret != CRYPTO_SUCCESS) {
ret = SET_ERROR(EIO);
goto error;
@@ -1075,7 +1064,7 @@ zio_crypt_do_dnode_hmac_updates(crypto_context_t ctx, uint64_t version,
cd.cd_raw.iov_base = (char *)adnp;
cd.cd_raw.iov_len = cd.cd_length;
- ret = crypto_mac_update(ctx, &cd, NULL);
+ ret = crypto_mac_update(ctx, &cd);
if (ret != CRYPTO_SUCCESS) {
ret = SET_ERROR(EIO);
goto error;
@@ -1148,7 +1137,7 @@ zio_crypt_do_objset_hmacs(zio_crypt_key_t *key, void *data, uint_t datalen,
cd.cd_offset = 0;
/* calculate the portable MAC from the portable fields and metadnode */
- ret = crypto_mac_init(&mech, &key->zk_hmac_key, NULL, &ctx, NULL);
+ ret = crypto_mac_init(&mech, &key->zk_hmac_key, NULL, &ctx);
if (ret != CRYPTO_SUCCESS) {
ret = SET_ERROR(EIO);
goto error;
@@ -1160,7 +1149,7 @@ zio_crypt_do_objset_hmacs(zio_crypt_key_t *key, void *data, uint_t datalen,
cd.cd_raw.iov_base = (char *)&intval;
cd.cd_raw.iov_len = cd.cd_length;
- ret = crypto_mac_update(ctx, &cd, NULL);
+ ret = crypto_mac_update(ctx, &cd);
if (ret != CRYPTO_SUCCESS) {
ret = SET_ERROR(EIO);
goto error;
@@ -1178,7 +1167,7 @@ zio_crypt_do_objset_hmacs(zio_crypt_key_t *key, void *data, uint_t datalen,
cd.cd_raw.iov_base = (char *)&intval;
cd.cd_raw.iov_len = cd.cd_length;
- ret = crypto_mac_update(ctx, &cd, NULL);
+ ret = crypto_mac_update(ctx, &cd);
if (ret != CRYPTO_SUCCESS) {
ret = SET_ERROR(EIO);
goto error;
@@ -1195,7 +1184,7 @@ zio_crypt_do_objset_hmacs(zio_crypt_key_t *key, void *data, uint_t datalen,
cd.cd_raw.iov_base = (char *)raw_portable_mac;
cd.cd_raw.iov_len = cd.cd_length;
- ret = crypto_mac_final(ctx, &cd, NULL);
+ ret = crypto_mac_final(ctx, &cd);
if (ret != CRYPTO_SUCCESS) {
ret = SET_ERROR(EIO);
goto error;
@@ -1235,7 +1224,7 @@ zio_crypt_do_objset_hmacs(zio_crypt_key_t *key, void *data, uint_t datalen,
}
/* calculate the local MAC from the userused and groupused dnodes */
- ret = crypto_mac_init(&mech, &key->zk_hmac_key, NULL, &ctx, NULL);
+ ret = crypto_mac_init(&mech, &key->zk_hmac_key, NULL, &ctx);
if (ret != CRYPTO_SUCCESS) {
ret = SET_ERROR(EIO);
goto error;
@@ -1253,7 +1242,7 @@ zio_crypt_do_objset_hmacs(zio_crypt_key_t *key, void *data, uint_t datalen,
cd.cd_raw.iov_base = (char *)&intval;
cd.cd_raw.iov_len = cd.cd_length;
- ret = crypto_mac_update(ctx, &cd, NULL);
+ ret = crypto_mac_update(ctx, &cd);
if (ret != CRYPTO_SUCCESS) {
ret = SET_ERROR(EIO);
goto error;
@@ -1287,7 +1276,7 @@ zio_crypt_do_objset_hmacs(zio_crypt_key_t *key, void *data, uint_t datalen,
cd.cd_raw.iov_base = (char *)raw_local_mac;
cd.cd_raw.iov_len = cd.cd_length;
- ret = crypto_mac_final(ctx, &cd, NULL);
+ ret = crypto_mac_final(ctx, &cd);
if (ret != CRYPTO_SUCCESS) {
ret = SET_ERROR(EIO);
goto error;
@@ -1921,7 +1910,6 @@ zio_do_crypt_data(boolean_t encrypt, zio_crypt_key_t *key,
if (ret != 0)
goto error;
- tmp_ckey.ck_format = CRYPTO_KEY_RAW;
tmp_ckey.ck_data = enc_keydata;
tmp_ckey.ck_length = CRYPTO_BYTES2BITS(keydata_len);
@@ -2051,9 +2039,8 @@ error:
}
#if defined(_KERNEL)
-/* BEGIN CSTYLED */
+/* CSTYLED */
module_param(zfs_key_max_salt_uses, ulong, 0644);
MODULE_PARM_DESC(zfs_key_max_salt_uses, "Max number of times a salt value "
"can be used for generating encryption keys before it is rotated");
-/* END CSTYLED */
#endif
diff --git a/sys/contrib/openzfs/module/os/linux/zfs/zpl_ctldir.c b/sys/contrib/openzfs/module/os/linux/zfs/zpl_ctldir.c
index a640930a02e1..f4e1ab7aef08 100644
--- a/sys/contrib/openzfs/module/os/linux/zfs/zpl_ctldir.c
+++ b/sys/contrib/openzfs/module/os/linux/zfs/zpl_ctldir.c
@@ -36,7 +36,6 @@
/*
* Common open routine. Disallow any write access.
*/
-/* ARGSUSED */
static int
zpl_common_open(struct inode *ip, struct file *filp)
{
@@ -99,7 +98,6 @@ zpl_root_readdir(struct file *filp, void *dirent, filldir_t filldir)
/*
* Get root directory attributes.
*/
-/* ARGSUSED */
static int
#ifdef HAVE_USERNS_IOPS_GETATTR
zpl_root_getattr_impl(struct user_namespace *user_ns,
@@ -110,11 +108,16 @@ zpl_root_getattr_impl(const struct path *path, struct kstat *stat,
u32 request_mask, unsigned int query_flags)
#endif
{
+ (void) request_mask, (void) query_flags;
struct inode *ip = path->dentry->d_inode;
-#if defined(HAVE_GENERIC_FILLATTR_USERNS) && defined(HAVE_USERNS_IOPS_GETATTR)
+#ifdef HAVE_USERNS_IOPS_GETATTR
+#ifdef HAVE_GENERIC_FILLATTR_USERNS
generic_fillattr(user_ns, ip, stat);
#else
+ (void) user_ns;
+#endif
+#else
generic_fillattr(ip, stat);
#endif
stat->atime = current_time(ip);
@@ -382,7 +385,6 @@ zpl_snapdir_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode)
/*
* Get snapshot directory attributes.
*/
-/* ARGSUSED */
static int
#ifdef HAVE_USERNS_IOPS_GETATTR
zpl_snapdir_getattr_impl(struct user_namespace *user_ns,
@@ -393,13 +395,18 @@ zpl_snapdir_getattr_impl(const struct path *path, struct kstat *stat,
u32 request_mask, unsigned int query_flags)
#endif
{
+ (void) request_mask, (void) query_flags;
struct inode *ip = path->dentry->d_inode;
zfsvfs_t *zfsvfs = ITOZSB(ip);
ZPL_ENTER(zfsvfs);
-#if defined(HAVE_GENERIC_FILLATTR_USERNS) && defined(HAVE_USERNS_IOPS_GETATTR)
+#ifdef HAVE_USERNS_IOPS_GETATTR
+#ifdef HAVE_GENERIC_FILLATTR_USERNS
generic_fillattr(user_ns, ip, stat);
#else
+ (void) user_ns;
+#endif
+#else
generic_fillattr(ip, stat);
#endif
@@ -524,7 +531,6 @@ zpl_shares_readdir(struct file *filp, void *dirent, filldir_t filldir)
}
#endif /* !HAVE_VFS_ITERATE && !HAVE_VFS_ITERATE_SHARED */
-/* ARGSUSED */
static int
#ifdef HAVE_USERNS_IOPS_GETATTR
zpl_shares_getattr_impl(struct user_namespace *user_ns,
@@ -535,6 +541,7 @@ zpl_shares_getattr_impl(const struct path *path, struct kstat *stat,
u32 request_mask, unsigned int query_flags)
#endif
{
+ (void) request_mask, (void) query_flags;
struct inode *ip = path->dentry->d_inode;
zfsvfs_t *zfsvfs = ITOZSB(ip);
znode_t *dzp;
@@ -543,9 +550,13 @@ zpl_shares_getattr_impl(const struct path *path, struct kstat *stat,
ZPL_ENTER(zfsvfs);
if (zfsvfs->z_shares_dir == 0) {
-#if defined(HAVE_GENERIC_FILLATTR_USERNS) && defined(HAVE_USERNS_IOPS_GETATTR)
+#ifdef HAVE_USERNS_IOPS_GETATTR
+#ifdef HAVE_GENERIC_FILLATTR_USERNS
generic_fillattr(user_ns, path->dentry->d_inode, stat);
#else
+ (void) user_ns;
+#endif
+#else
generic_fillattr(path->dentry->d_inode, stat);
#endif
stat->nlink = stat->size = 2;
@@ -556,9 +567,13 @@ zpl_shares_getattr_impl(const struct path *path, struct kstat *stat,
error = -zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp);
if (error == 0) {
-#if defined(HAVE_GENERIC_FILLATTR_USERNS) && defined(HAVE_USERNS_IOPS_GETATTR)
+#ifdef HAVE_USERNS_IOPS_GETATTR
+#ifdef HAVE_GENERIC_FILLATTR_USERNS
error = -zfs_getattr_fast(user_ns, ZTOI(dzp), stat);
#else
+ (void) user_ns;
+#endif
+#else
error = -zfs_getattr_fast(kcred->user_ns, ZTOI(dzp), stat);
#endif
iput(ZTOI(dzp));
diff --git a/sys/contrib/openzfs/module/os/linux/zfs/zpl_file.c b/sys/contrib/openzfs/module/os/linux/zfs/zpl_file.c
index 21926f170c5c..f78e50262af7 100644
--- a/sys/contrib/openzfs/module/os/linux/zfs/zpl_file.c
+++ b/sys/contrib/openzfs/module/os/linux/zfs/zpl_file.c
@@ -745,7 +745,12 @@ zpl_fallocate_common(struct inode *ip, int mode, loff_t offset, loff_t len)
fstrans_cookie_t cookie;
int error = 0;
- if ((mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE)) != 0)
+ int test_mode = FALLOC_FL_PUNCH_HOLE;
+#ifdef HAVE_FALLOC_FL_ZERO_RANGE
+ test_mode |= FALLOC_FL_ZERO_RANGE;
+#endif
+
+ if ((mode & ~(FALLOC_FL_KEEP_SIZE | test_mode)) != 0)
return (-EOPNOTSUPP);
if (offset < 0 || len <= 0)
@@ -756,7 +761,7 @@ zpl_fallocate_common(struct inode *ip, int mode, loff_t offset, loff_t len)
crhold(cr);
cookie = spl_fstrans_mark();
- if (mode & FALLOC_FL_PUNCH_HOLE) {
+ if (mode & (test_mode)) {
flock64_t bf;
if (offset > olen)
@@ -900,21 +905,24 @@ __zpl_ioctl_setflags(struct inode *ip, uint32_t ioctl_flags, xvattr_t *xva)
xva_init(xva);
xoap = xva_getxoptattr(xva);
- XVA_SET_REQ(xva, XAT_IMMUTABLE);
- if (ioctl_flags & FS_IMMUTABLE_FL)
- xoap->xoa_immutable = B_TRUE;
-
- XVA_SET_REQ(xva, XAT_APPENDONLY);
- if (ioctl_flags & FS_APPEND_FL)
- xoap->xoa_appendonly = B_TRUE;
-
- XVA_SET_REQ(xva, XAT_NODUMP);
- if (ioctl_flags & FS_NODUMP_FL)
- xoap->xoa_nodump = B_TRUE;
-
- XVA_SET_REQ(xva, XAT_PROJINHERIT);
- if (ioctl_flags & ZFS_PROJINHERIT_FL)
- xoap->xoa_projinherit = B_TRUE;
+#define FLAG_CHANGE(iflag, zflag, xflag, xfield) do { \
+ if (((ioctl_flags & (iflag)) && !(zfs_flags & (zflag))) || \
+ ((zfs_flags & (zflag)) && !(ioctl_flags & (iflag)))) { \
+ XVA_SET_REQ(xva, (xflag)); \
+ (xfield) = ((ioctl_flags & (iflag)) != 0); \
+ } \
+} while (0)
+
+ FLAG_CHANGE(FS_IMMUTABLE_FL, ZFS_IMMUTABLE, XAT_IMMUTABLE,
+ xoap->xoa_immutable);
+ FLAG_CHANGE(FS_APPEND_FL, ZFS_APPENDONLY, XAT_APPENDONLY,
+ xoap->xoa_appendonly);
+ FLAG_CHANGE(FS_NODUMP_FL, ZFS_NODUMP, XAT_NODUMP,
+ xoap->xoa_nodump);
+ FLAG_CHANGE(ZFS_PROJINHERIT_FL, ZFS_PROJINHERIT, XAT_PROJINHERIT,
+ xoap->xoa_projinherit);
+
+#undef FLAG_CHANGE
return (0);
}
@@ -993,6 +1001,94 @@ zpl_ioctl_setxattr(struct file *filp, void __user *arg)
return (err);
}
+/*
+ * Expose Additional File Level Attributes of ZFS.
+ */
+static int
+zpl_ioctl_getdosflags(struct file *filp, void __user *arg)
+{
+ struct inode *ip = file_inode(filp);
+ uint64_t dosflags = ITOZ(ip)->z_pflags;
+ dosflags &= ZFS_DOS_FL_USER_VISIBLE;
+ int err = copy_to_user(arg, &dosflags, sizeof (dosflags));
+
+ return (err);
+}
+
+static int
+__zpl_ioctl_setdosflags(struct inode *ip, uint64_t ioctl_flags, xvattr_t *xva)
+{
+ uint64_t zfs_flags = ITOZ(ip)->z_pflags;
+ xoptattr_t *xoap;
+
+ if (ioctl_flags & (~ZFS_DOS_FL_USER_VISIBLE))
+ return (-EOPNOTSUPP);
+
+ if ((fchange(ioctl_flags, zfs_flags, ZFS_IMMUTABLE, ZFS_IMMUTABLE) ||
+ fchange(ioctl_flags, zfs_flags, ZFS_APPENDONLY, ZFS_APPENDONLY)) &&
+ !capable(CAP_LINUX_IMMUTABLE))
+ return (-EPERM);
+
+ if (!zpl_inode_owner_or_capable(kcred->user_ns, ip))
+ return (-EACCES);
+
+ xva_init(xva);
+ xoap = xva_getxoptattr(xva);
+
+#define FLAG_CHANGE(iflag, xflag, xfield) do { \
+ if (((ioctl_flags & (iflag)) && !(zfs_flags & (iflag))) || \
+ ((zfs_flags & (iflag)) && !(ioctl_flags & (iflag)))) { \
+ XVA_SET_REQ(xva, (xflag)); \
+ (xfield) = ((ioctl_flags & (iflag)) != 0); \
+ } \
+} while (0)
+
+ FLAG_CHANGE(ZFS_IMMUTABLE, XAT_IMMUTABLE, xoap->xoa_immutable);
+ FLAG_CHANGE(ZFS_APPENDONLY, XAT_APPENDONLY, xoap->xoa_appendonly);
+ FLAG_CHANGE(ZFS_NODUMP, XAT_NODUMP, xoap->xoa_nodump);
+ FLAG_CHANGE(ZFS_READONLY, XAT_READONLY, xoap->xoa_readonly);
+ FLAG_CHANGE(ZFS_HIDDEN, XAT_HIDDEN, xoap->xoa_hidden);
+ FLAG_CHANGE(ZFS_SYSTEM, XAT_SYSTEM, xoap->xoa_system);
+ FLAG_CHANGE(ZFS_ARCHIVE, XAT_ARCHIVE, xoap->xoa_archive);
+ FLAG_CHANGE(ZFS_NOUNLINK, XAT_NOUNLINK, xoap->xoa_nounlink);
+ FLAG_CHANGE(ZFS_REPARSE, XAT_REPARSE, xoap->xoa_reparse);
+ FLAG_CHANGE(ZFS_OFFLINE, XAT_OFFLINE, xoap->xoa_offline);
+ FLAG_CHANGE(ZFS_SPARSE, XAT_SPARSE, xoap->xoa_sparse);
+
+#undef FLAG_CHANGE
+
+ return (0);
+}
+
+/*
+ * Set Additional File Level Attributes of ZFS.
+ */
+static int
+zpl_ioctl_setdosflags(struct file *filp, void __user *arg)
+{
+ struct inode *ip = file_inode(filp);
+ uint64_t dosflags;
+ cred_t *cr = CRED();
+ xvattr_t xva;
+ int err;
+ fstrans_cookie_t cookie;
+
+ if (copy_from_user(&dosflags, arg, sizeof (dosflags)))
+ return (-EFAULT);
+
+ err = __zpl_ioctl_setdosflags(ip, dosflags, &xva);
+ if (err)
+ return (err);
+
+ crhold(cr);
+ cookie = spl_fstrans_mark();
+ err = -zfs_setattr(ITOZ(ip), (vattr_t *)&xva, 0, cr);
+ spl_fstrans_unmark(cookie);
+ crfree(cr);
+
+ return (err);
+}
+
static long
zpl_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
@@ -1007,6 +1103,10 @@ zpl_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
return (zpl_ioctl_getxattr(filp, (void *)arg));
case ZFS_IOC_FSSETXATTR:
return (zpl_ioctl_setxattr(filp, (void *)arg));
+ case ZFS_IOC_GETDOSFLAGS:
+ return (zpl_ioctl_getdosflags(filp, (void *)arg));
+ case ZFS_IOC_SETDOSFLAGS:
+ return (zpl_ioctl_setdosflags(filp, (void *)arg));
default:
return (-ENOTTY);
}
@@ -1095,8 +1195,7 @@ const struct file_operations zpl_dir_file_operations = {
#endif
};
-/* BEGIN CSTYLED */
+/* CSTYLED */
module_param(zfs_fallocate_reserve_percent, uint, 0644);
MODULE_PARM_DESC(zfs_fallocate_reserve_percent,
- "Percentage of length to use for the available capacity check");
-/* END CSTYLED */
+ "Percentage of length to use for the available capacity check");
diff --git a/sys/contrib/openzfs/module/os/linux/zfs/zpl_xattr.c b/sys/contrib/openzfs/module/os/linux/zfs/zpl_xattr.c
index a1921ed08863..3b8ac517ada9 100644
--- a/sys/contrib/openzfs/module/os/linux/zfs/zpl_xattr.c
+++ b/sys/contrib/openzfs/module/os/linux/zfs/zpl_xattr.c
@@ -84,6 +84,12 @@
#include <sys/vfs.h>
#include <sys/zpl.h>
+enum xattr_permission {
+ XAPERM_DENY,
+ XAPERM_ALLOW,
+ XAPERM_COMPAT,
+};
+
typedef struct xattr_filldir {
size_t size;
size_t offset;
@@ -91,33 +97,10 @@ typedef struct xattr_filldir {
struct dentry *dentry;
} xattr_filldir_t;
-static const struct xattr_handler *zpl_xattr_handler(const char *);
-
-static int
-zpl_xattr_permission(xattr_filldir_t *xf, const char *name, int name_len)
-{
- static const struct xattr_handler *handler;
- struct dentry *d = xf->dentry;
-
- handler = zpl_xattr_handler(name);
- if (!handler)
- return (0);
-
- if (handler->list) {
-#if defined(HAVE_XATTR_LIST_SIMPLE)
- if (!handler->list(d))
- return (0);
-#elif defined(HAVE_XATTR_LIST_DENTRY)
- if (!handler->list(d, NULL, 0, name, name_len, 0))
- return (0);
-#elif defined(HAVE_XATTR_LIST_HANDLER)
- if (!handler->list(handler, d, NULL, 0, name, name_len))
- return (0);
-#endif
- }
+static enum xattr_permission zpl_xattr_permission(xattr_filldir_t *,
+ const char *, int);
- return (1);
-}
+static int zfs_xattr_compat = 0;
/*
* Determine is a given xattr name should be visible and if so copy it
@@ -126,10 +109,27 @@ zpl_xattr_permission(xattr_filldir_t *xf, const char *name, int name_len)
static int
zpl_xattr_filldir(xattr_filldir_t *xf, const char *name, int name_len)
{
+ enum xattr_permission perm;
+
/* Check permissions using the per-namespace list xattr handler. */
- if (!zpl_xattr_permission(xf, name, name_len))
+ perm = zpl_xattr_permission(xf, name, name_len);
+ if (perm == XAPERM_DENY)
return (0);
+ /* Prefix the name with "user." if it does not have a namespace. */
+ if (perm == XAPERM_COMPAT) {
+ if (xf->buf) {
+ if (xf->offset + XATTR_USER_PREFIX_LEN + 1 > xf->size)
+ return (-ERANGE);
+
+ memcpy(xf->buf + xf->offset, XATTR_USER_PREFIX,
+ XATTR_USER_PREFIX_LEN);
+ xf->buf[xf->offset + XATTR_USER_PREFIX_LEN] = '\0';
+ }
+
+ xf->offset += XATTR_USER_PREFIX_LEN;
+ }
+
/* When xf->buf is NULL only calculate the required size. */
if (xf->buf) {
if (xf->offset + name_len + 1 > xf->size)
@@ -578,7 +578,7 @@ zpl_xattr_set_sa(struct inode *ip, const char *name, const void *value,
* will be reconstructed from the ARC when next accessed.
*/
if (error == 0)
- error = -zfs_sa_set_xattr(zp);
+ error = -zfs_sa_set_xattr(zp, name, value, size);
if (error) {
nvlist_free(nvl);
@@ -706,19 +706,28 @@ static int
__zpl_xattr_user_get(struct inode *ip, const char *name,
void *value, size_t size)
{
- char *xattr_name;
int error;
/* xattr_resolve_name will do this for us if this is defined */
#ifndef HAVE_XATTR_HANDLER_NAME
if (strcmp(name, "") == 0)
return (-EINVAL);
#endif
+ if (ZFS_XA_NS_PREFIX_FORBIDDEN(name))
+ return (-EINVAL);
if (!(ITOZSB(ip)->z_flags & ZSB_XATTR))
return (-EOPNOTSUPP);
- xattr_name = kmem_asprintf("%s%s", XATTR_USER_PREFIX, name);
+ /*
+ * Try to look up the name with the namespace prefix first for
+ * compatibility with xattrs from this platform. If that fails,
+ * try again without the namespace prefix for compatibility with
+ * other platforms.
+ */
+ char *xattr_name = kmem_asprintf("%s%s", XATTR_USER_PREFIX, name);
error = zpl_xattr_get(ip, xattr_name, value, size);
kmem_strfree(xattr_name);
+ if (error == -ENODATA)
+ error = zpl_xattr_get(ip, name, value, size);
return (error);
}
@@ -728,20 +737,59 @@ static int
__zpl_xattr_user_set(struct inode *ip, const char *name,
const void *value, size_t size, int flags)
{
- char *xattr_name;
- int error;
+ int error = 0;
/* xattr_resolve_name will do this for us if this is defined */
#ifndef HAVE_XATTR_HANDLER_NAME
if (strcmp(name, "") == 0)
return (-EINVAL);
#endif
+ if (ZFS_XA_NS_PREFIX_FORBIDDEN(name))
+ return (-EINVAL);
if (!(ITOZSB(ip)->z_flags & ZSB_XATTR))
return (-EOPNOTSUPP);
- xattr_name = kmem_asprintf("%s%s", XATTR_USER_PREFIX, name);
- error = zpl_xattr_set(ip, xattr_name, value, size, flags);
- kmem_strfree(xattr_name);
-
+ /*
+ * Remove alternate compat version of the xattr so we only set the
+ * version specified by the zfs_xattr_compat tunable.
+ *
+ * The following flags must be handled correctly:
+ *
+ * XATTR_CREATE: fail if xattr already exists
+ * XATTR_REPLACE: fail if xattr does not exist
+ */
+ char *prefixed_name = kmem_asprintf("%s%s", XATTR_USER_PREFIX, name);
+ const char *clear_name, *set_name;
+ if (zfs_xattr_compat) {
+ clear_name = prefixed_name;
+ set_name = name;
+ } else {
+ clear_name = name;
+ set_name = prefixed_name;
+ }
+ /*
+ * Clear the old value with the alternative name format, if it exists.
+ */
+ error = zpl_xattr_set(ip, clear_name, NULL, 0, flags);
+ /*
+ * XATTR_CREATE was specified and we failed to clear the xattr
+ * because it already exists. Stop here.
+ */
+ if (error == -EEXIST)
+ goto out;
+ /*
+ * If XATTR_REPLACE was specified and we succeeded to clear
+ * an xattr, we don't need to replace anything when setting
+ * the new value. If we failed with -ENODATA that's fine,
+ * there was nothing to be cleared and we can ignore the error.
+ */
+ if (error == 0)
+ flags &= ~XATTR_REPLACE;
+ /*
+ * Set the new value with the configured name format.
+ */
+ error = zpl_xattr_set(ip, set_name, value, size, flags);
+out:
+ kmem_strfree(prefixed_name);
return (error);
}
ZPL_XATTR_SET_WRAPPER(zpl_xattr_user_set);
@@ -1411,6 +1459,42 @@ zpl_xattr_handler(const char *name)
return (NULL);
}
+static enum xattr_permission
+zpl_xattr_permission(xattr_filldir_t *xf, const char *name, int name_len)
+{
+ const struct xattr_handler *handler;
+ struct dentry *d __maybe_unused = xf->dentry;
+ enum xattr_permission perm = XAPERM_ALLOW;
+
+ handler = zpl_xattr_handler(name);
+ if (handler == NULL) {
+ /* Do not expose FreeBSD system namespace xattrs. */
+ if (ZFS_XA_NS_PREFIX_MATCH(FREEBSD, name))
+ return (XAPERM_DENY);
+ /*
+ * Anything that doesn't match a known namespace gets put in the
+ * user namespace for compatibility with other platforms.
+ */
+ perm = XAPERM_COMPAT;
+ handler = &zpl_xattr_user_handler;
+ }
+
+ if (handler->list) {
+#if defined(HAVE_XATTR_LIST_SIMPLE)
+ if (!handler->list(d))
+ return (XAPERM_DENY);
+#elif defined(HAVE_XATTR_LIST_DENTRY)
+ if (!handler->list(d, NULL, 0, name, name_len, 0))
+ return (XAPERM_DENY);
+#elif defined(HAVE_XATTR_LIST_HANDLER)
+ if (!handler->list(handler, d, NULL, 0, name, name_len))
+ return (XAPERM_DENY);
+#endif
+ }
+
+ return (perm);
+}
+
#if !defined(HAVE_POSIX_ACL_RELEASE) || defined(HAVE_POSIX_ACL_RELEASE_GPL_ONLY)
struct acl_rel_struct {
struct acl_rel_struct *next;
@@ -1510,3 +1594,6 @@ zpl_posix_acl_release_impl(struct posix_acl *acl)
NULL, TQ_SLEEP, ddi_get_lbolt() + ACL_REL_SCHED);
}
#endif
+
+ZFS_MODULE_PARAM(zfs, zfs_, xattr_compat, INT, ZMOD_RW,
+ "Use legacy ZFS xattr naming for writing new user namespace xattrs");
diff --git a/sys/contrib/openzfs/module/os/linux/zfs/zvol_os.c b/sys/contrib/openzfs/module/os/linux/zfs/zvol_os.c
index cef52e22483a..f772f416043e 100644
--- a/sys/contrib/openzfs/module/os/linux/zfs/zvol_os.c
+++ b/sys/contrib/openzfs/module/os/linux/zfs/zvol_os.c
@@ -86,8 +86,8 @@ zv_request_task_free(zv_request_task_t *task)
/*
* Given a path, return TRUE if path is a ZVOL.
*/
-static boolean_t
-zvol_is_zvol_impl(const char *path)
+boolean_t
+zvol_os_is_zvol(const char *path)
{
dev_t dev = 0;
@@ -507,7 +507,7 @@ retry:
/*
* Obtain a copy of private_data under the zvol_state_lock to make
* sure that either the result of zvol free code path setting
- * bdev->bd_disk->private_data to NULL is observed, or zvol_free()
+ * bdev->bd_disk->private_data to NULL is observed, or zvol_os_free()
* is not called on this zv because of the positive zv_open_count.
*/
zv = bdev->bd_disk->private_data;
@@ -747,8 +747,8 @@ zvol_revalidate_disk(struct gendisk *disk)
return (0);
}
-static int
-zvol_update_volsize(zvol_state_t *zv, uint64_t volsize)
+int
+zvol_os_update_volsize(zvol_state_t *zv, uint64_t volsize)
{
struct gendisk *disk = zv->zv_zso->zvo_disk;
@@ -762,8 +762,8 @@ zvol_update_volsize(zvol_state_t *zv, uint64_t volsize)
return (0);
}
-static void
-zvol_clear_private(zvol_state_t *zv)
+void
+zvol_os_clear_private(zvol_state_t *zv)
{
/*
* Cleared while holding zvol_state_lock as a writer
@@ -944,8 +944,8 @@ out_kmem:
* "del_gendisk". Thus, consumers need to be careful to account for this
* latency when calling this function.
*/
-static void
-zvol_free(zvol_state_t *zv)
+void
+zvol_os_free(zvol_state_t *zv)
{
ASSERT(!RW_LOCK_HELD(&zv->zv_suspend_lock));
@@ -985,7 +985,7 @@ zvol_wait_close(zvol_state_t *zv)
* and the specified volume. Once this function returns the block
* device is live and ready for use.
*/
-static int
+int
zvol_os_create_minor(const char *name)
{
zvol_state_t *zv;
@@ -1110,7 +1110,11 @@ out_doi:
rw_enter(&zvol_state_lock, RW_WRITER);
zvol_insert(zv);
rw_exit(&zvol_state_lock);
+#ifdef HAVE_ADD_DISK_RET
+ error = add_disk(zv->zv_zso->zvo_disk);
+#else
add_disk(zv->zv_zso->zvo_disk);
+#endif
} else {
ida_simple_remove(&zvol_ida, idx);
}
@@ -1118,8 +1122,8 @@ out_doi:
return (error);
}
-static void
-zvol_rename_minor(zvol_state_t *zv, const char *newname)
+void
+zvol_os_rename_minor(zvol_state_t *zv, const char *newname)
{
int readonly = get_disk_ro(zv->zv_zso->zvo_disk);
@@ -1145,31 +1149,20 @@ zvol_rename_minor(zvol_state_t *zv, const char *newname)
set_disk_ro(zv->zv_zso->zvo_disk, readonly);
}
-static void
-zvol_set_disk_ro_impl(zvol_state_t *zv, int flags)
+void
+zvol_os_set_disk_ro(zvol_state_t *zv, int flags)
{
set_disk_ro(zv->zv_zso->zvo_disk, flags);
}
-static void
-zvol_set_capacity_impl(zvol_state_t *zv, uint64_t capacity)
+void
+zvol_os_set_capacity(zvol_state_t *zv, uint64_t capacity)
{
set_capacity(zv->zv_zso->zvo_disk, capacity);
}
-const static zvol_platform_ops_t zvol_linux_ops = {
- .zv_free = zvol_free,
- .zv_rename_minor = zvol_rename_minor,
- .zv_create_minor = zvol_os_create_minor,
- .zv_update_volsize = zvol_update_volsize,
- .zv_clear_private = zvol_clear_private,
- .zv_is_zvol = zvol_is_zvol_impl,
- .zv_set_disk_ro = zvol_set_disk_ro_impl,
- .zv_set_capacity = zvol_set_capacity_impl,
-};
-
int
zvol_init(void)
{
@@ -1189,7 +1182,6 @@ zvol_init(void)
}
zvol_init_impl();
ida_init(&zvol_ida);
- zvol_register_ops(&zvol_linux_ops);
return (0);
}
diff --git a/sys/contrib/openzfs/module/zcommon/zfeature_common.c b/sys/contrib/openzfs/module/zcommon/zfeature_common.c
index 529c52316f3e..13dbccae2d4a 100644
--- a/sys/contrib/openzfs/module/zcommon/zfeature_common.c
+++ b/sys/contrib/openzfs/module/zcommon/zfeature_common.c
@@ -695,6 +695,18 @@ zpool_feature_init(void)
"org.openzfs:draid", "draid", "Support for distributed spare RAID",
ZFEATURE_FLAG_MOS, ZFEATURE_TYPE_BOOLEAN, NULL, sfeatures);
+ {
+ static const spa_feature_t zilsaxattr_deps[] = {
+ SPA_FEATURE_EXTENSIBLE_DATASET,
+ SPA_FEATURE_NONE
+ };
+ zfeature_register(SPA_FEATURE_ZILSAXATTR,
+ "org.openzfs:zilsaxattr", "zilsaxattr",
+ "Support for xattr=sa extended attribute logging in ZIL.",
+ ZFEATURE_FLAG_PER_DATASET | ZFEATURE_FLAG_READONLY_COMPAT,
+ ZFEATURE_TYPE_BOOLEAN, zilsaxattr_deps, sfeatures);
+ }
+
zfs_mod_list_supported_free(sfeatures);
}
diff --git a/sys/contrib/openzfs/module/zcommon/zfs_fletcher.c b/sys/contrib/openzfs/module/zcommon/zfs_fletcher.c
index e7a8553f3f39..16773d4de077 100644
--- a/sys/contrib/openzfs/module/zcommon/zfs_fletcher.c
+++ b/sys/contrib/openzfs/module/zcommon/zfs_fletcher.c
@@ -300,18 +300,21 @@ fletcher_2_byteswap(const void *buf, uint64_t size,
(void) fletcher_2_incremental_byteswap((void *) buf, size, zcp);
}
+ZFS_NO_SANITIZE_UNDEFINED
static void
fletcher_4_scalar_init(fletcher_4_ctx_t *ctx)
{
ZIO_SET_CHECKSUM(&ctx->scalar, 0, 0, 0, 0);
}
+ZFS_NO_SANITIZE_UNDEFINED
static void
fletcher_4_scalar_fini(fletcher_4_ctx_t *ctx, zio_cksum_t *zcp)
{
memcpy(zcp, &ctx->scalar, sizeof (zio_cksum_t));
}
+ZFS_NO_SANITIZE_UNDEFINED
static void
fletcher_4_scalar_native(fletcher_4_ctx_t *ctx, const void *buf,
uint64_t size)
@@ -335,6 +338,7 @@ fletcher_4_scalar_native(fletcher_4_ctx_t *ctx, const void *buf,
ZIO_SET_CHECKSUM(&ctx->scalar, a, b, c, d);
}
+ZFS_NO_SANITIZE_UNDEFINED
static void
fletcher_4_scalar_byteswap(fletcher_4_ctx_t *ctx, const void *buf,
uint64_t size)
@@ -968,11 +972,9 @@ fletcher_4_param(ZFS_MODULE_PARAM_ARGS)
* Users can choose "cycle" to exercise all implementations, but this is
* for testing purpose therefore it can only be set in user space.
*/
-/* BEGIN CSTYLED */
ZFS_MODULE_VIRTUAL_PARAM_CALL(zfs, zfs_, fletcher_4_impl,
- fletcher_4_param_set, fletcher_4_param_get, ZMOD_RW,
+ fletcher_4_param_set, fletcher_4_param_get, ZMOD_RW,
"Select fletcher 4 implementation.");
-/* END CSTYLED */
EXPORT_SYMBOL(fletcher_init);
EXPORT_SYMBOL(fletcher_2_incremental_native);
diff --git a/sys/contrib/openzfs/module/zcommon/zfs_fletcher_aarch64_neon.c b/sys/contrib/openzfs/module/zcommon/zfs_fletcher_aarch64_neon.c
index c95a71681584..e84d69eb3415 100644
--- a/sys/contrib/openzfs/module/zcommon/zfs_fletcher_aarch64_neon.c
+++ b/sys/contrib/openzfs/module/zcommon/zfs_fletcher_aarch64_neon.c
@@ -48,12 +48,14 @@
#include <sys/strings.h>
#include <zfs_fletcher.h>
+ZFS_NO_SANITIZE_UNDEFINED
static void
fletcher_4_aarch64_neon_init(fletcher_4_ctx_t *ctx)
{
bzero(ctx->aarch64_neon, 4 * sizeof (zfs_fletcher_aarch64_neon_t));
}
+ZFS_NO_SANITIZE_UNDEFINED
static void
fletcher_4_aarch64_neon_fini(fletcher_4_ctx_t *ctx, zio_cksum_t *zcp)
{
diff --git a/sys/contrib/openzfs/module/zcommon/zfs_fletcher_avx512.c b/sys/contrib/openzfs/module/zcommon/zfs_fletcher_avx512.c
index 963f089b04f5..8ee438ab9325 100644
--- a/sys/contrib/openzfs/module/zcommon/zfs_fletcher_avx512.c
+++ b/sys/contrib/openzfs/module/zcommon/zfs_fletcher_avx512.c
@@ -35,12 +35,14 @@
#define __asm __asm__ __volatile__
#endif
+ZFS_NO_SANITIZE_UNDEFINED
static void
fletcher_4_avx512f_init(fletcher_4_ctx_t *ctx)
{
bzero(ctx->avx512, 4 * sizeof (zfs_fletcher_avx512_t));
}
+ZFS_NO_SANITIZE_UNDEFINED
static void
fletcher_4_avx512f_fini(fletcher_4_ctx_t *ctx, zio_cksum_t *zcp)
{
diff --git a/sys/contrib/openzfs/module/zcommon/zfs_fletcher_intel.c b/sys/contrib/openzfs/module/zcommon/zfs_fletcher_intel.c
index 5136a01eca51..16e61a96f8b1 100644
--- a/sys/contrib/openzfs/module/zcommon/zfs_fletcher_intel.c
+++ b/sys/contrib/openzfs/module/zcommon/zfs_fletcher_intel.c
@@ -47,12 +47,14 @@
#include <sys/strings.h>
#include <zfs_fletcher.h>
+ZFS_NO_SANITIZE_UNDEFINED
static void
fletcher_4_avx2_init(fletcher_4_ctx_t *ctx)
{
bzero(ctx->avx, 4 * sizeof (zfs_fletcher_avx_t));
}
+ZFS_NO_SANITIZE_UNDEFINED
static void
fletcher_4_avx2_fini(fletcher_4_ctx_t *ctx, zio_cksum_t *zcp)
{
diff --git a/sys/contrib/openzfs/module/zcommon/zfs_fletcher_sse.c b/sys/contrib/openzfs/module/zcommon/zfs_fletcher_sse.c
index 15ce9b07ffbe..fc5938488e61 100644
--- a/sys/contrib/openzfs/module/zcommon/zfs_fletcher_sse.c
+++ b/sys/contrib/openzfs/module/zcommon/zfs_fletcher_sse.c
@@ -49,12 +49,14 @@
#include <sys/strings.h>
#include <zfs_fletcher.h>
+ZFS_NO_SANITIZE_UNDEFINED
static void
fletcher_4_sse2_init(fletcher_4_ctx_t *ctx)
{
bzero(ctx->sse, 4 * sizeof (zfs_fletcher_sse_t));
}
+ZFS_NO_SANITIZE_UNDEFINED
static void
fletcher_4_sse2_fini(fletcher_4_ctx_t *ctx, zio_cksum_t *zcp)
{
diff --git a/sys/contrib/openzfs/module/zcommon/zfs_fletcher_superscalar.c b/sys/contrib/openzfs/module/zcommon/zfs_fletcher_superscalar.c
index 153f5c7d75e3..73a74b9ae0ab 100644
--- a/sys/contrib/openzfs/module/zcommon/zfs_fletcher_superscalar.c
+++ b/sys/contrib/openzfs/module/zcommon/zfs_fletcher_superscalar.c
@@ -47,12 +47,14 @@
#include <sys/strings.h>
#include <zfs_fletcher.h>
+ZFS_NO_SANITIZE_UNDEFINED
static void
fletcher_4_superscalar_init(fletcher_4_ctx_t *ctx)
{
bzero(ctx->superscalar, 4 * sizeof (zfs_fletcher_superscalar_t));
}
+ZFS_NO_SANITIZE_UNDEFINED
static void
fletcher_4_superscalar_fini(fletcher_4_ctx_t *ctx, zio_cksum_t *zcp)
{
@@ -68,6 +70,7 @@ fletcher_4_superscalar_fini(fletcher_4_ctx_t *ctx, zio_cksum_t *zcp)
ZIO_SET_CHECKSUM(zcp, A, B, C, D);
}
+ZFS_NO_SANITIZE_UNDEFINED
static void
fletcher_4_superscalar_native(fletcher_4_ctx_t *ctx,
const void *buf, uint64_t size)
@@ -107,6 +110,7 @@ fletcher_4_superscalar_native(fletcher_4_ctx_t *ctx,
ctx->superscalar[3].v[1] = d2;
}
+ZFS_NO_SANITIZE_UNDEFINED
static void
fletcher_4_superscalar_byteswap(fletcher_4_ctx_t *ctx,
const void *buf, uint64_t size)
diff --git a/sys/contrib/openzfs/module/zcommon/zfs_fletcher_superscalar4.c b/sys/contrib/openzfs/module/zcommon/zfs_fletcher_superscalar4.c
index 75e6a3baf980..2dbf8bbb8146 100644
--- a/sys/contrib/openzfs/module/zcommon/zfs_fletcher_superscalar4.c
+++ b/sys/contrib/openzfs/module/zcommon/zfs_fletcher_superscalar4.c
@@ -47,12 +47,14 @@
#include <sys/strings.h>
#include <zfs_fletcher.h>
+ZFS_NO_SANITIZE_UNDEFINED
static void
fletcher_4_superscalar4_init(fletcher_4_ctx_t *ctx)
{
bzero(ctx->superscalar, 4 * sizeof (zfs_fletcher_superscalar_t));
}
+ZFS_NO_SANITIZE_UNDEFINED
static void
fletcher_4_superscalar4_fini(fletcher_4_ctx_t *ctx, zio_cksum_t *zcp)
{
@@ -82,6 +84,7 @@ fletcher_4_superscalar4_fini(fletcher_4_ctx_t *ctx, zio_cksum_t *zcp)
ZIO_SET_CHECKSUM(zcp, A, B, C, D);
}
+ZFS_NO_SANITIZE_UNDEFINED
static void
fletcher_4_superscalar4_native(fletcher_4_ctx_t *ctx,
const void *buf, uint64_t size)
@@ -147,6 +150,7 @@ fletcher_4_superscalar4_native(fletcher_4_ctx_t *ctx,
ctx->superscalar[3].v[3] = d4;
}
+ZFS_NO_SANITIZE_UNDEFINED
static void
fletcher_4_superscalar4_byteswap(fletcher_4_ctx_t *ctx,
const void *buf, uint64_t size)
diff --git a/sys/contrib/openzfs/module/zcommon/zfs_prop.c b/sys/contrib/openzfs/module/zcommon/zfs_prop.c
index 36f30859df04..0d573506681b 100644
--- a/sys/contrib/openzfs/module/zcommon/zfs_prop.c
+++ b/sys/contrib/openzfs/module/zcommon/zfs_prop.c
@@ -589,125 +589,132 @@ zfs_prop_init(void)
/* readonly number properties */
zprop_register_number(ZFS_PROP_USED, "used", 0, PROP_READONLY,
- ZFS_TYPE_DATASET, "<size>", "USED", sfeatures);
+ ZFS_TYPE_DATASET, "<size>", "USED", B_FALSE, sfeatures);
zprop_register_number(ZFS_PROP_AVAILABLE, "available", 0, PROP_READONLY,
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<size>", "AVAIL",
- sfeatures);
+ B_FALSE, sfeatures);
zprop_register_number(ZFS_PROP_REFERENCED, "referenced", 0,
PROP_READONLY, ZFS_TYPE_DATASET | ZFS_TYPE_BOOKMARK, "<size>",
- "REFER", sfeatures);
+ "REFER", B_FALSE, sfeatures);
zprop_register_number(ZFS_PROP_COMPRESSRATIO, "compressratio", 0,
PROP_READONLY, ZFS_TYPE_DATASET | ZFS_TYPE_BOOKMARK,
- "<1.00x or higher if compressed>", "RATIO", sfeatures);
+ "<1.00x or higher if compressed>", "RATIO", B_FALSE, sfeatures);
zprop_register_number(ZFS_PROP_REFRATIO, "refcompressratio", 0,
PROP_READONLY, ZFS_TYPE_DATASET,
- "<1.00x or higher if compressed>", "REFRATIO", sfeatures);
+ "<1.00x or higher if compressed>", "REFRATIO", B_FALSE, sfeatures);
zprop_register_number(ZFS_PROP_VOLBLOCKSIZE, "volblocksize",
ZVOL_DEFAULT_BLOCKSIZE, PROP_ONETIME,
- ZFS_TYPE_VOLUME, "512 to 128k, power of 2", "VOLBLOCK", sfeatures);
+ ZFS_TYPE_VOLUME, "512 to 128k, power of 2", "VOLBLOCK", B_FALSE,
+ sfeatures);
zprop_register_number(ZFS_PROP_USEDSNAP, "usedbysnapshots", 0,
PROP_READONLY, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<size>",
- "USEDSNAP", sfeatures);
+ "USEDSNAP", B_FALSE, sfeatures);
zprop_register_number(ZFS_PROP_USEDDS, "usedbydataset", 0,
PROP_READONLY, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<size>",
- "USEDDS", sfeatures);
+ "USEDDS", B_FALSE, sfeatures);
zprop_register_number(ZFS_PROP_USEDCHILD, "usedbychildren", 0,
PROP_READONLY, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<size>",
- "USEDCHILD", sfeatures);
+ "USEDCHILD", B_FALSE, sfeatures);
zprop_register_number(ZFS_PROP_USEDREFRESERV, "usedbyrefreservation", 0,
PROP_READONLY,
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<size>", "USEDREFRESERV",
- sfeatures);
+ B_FALSE, sfeatures);
zprop_register_number(ZFS_PROP_USERREFS, "userrefs", 0, PROP_READONLY,
- ZFS_TYPE_SNAPSHOT, "<count>", "USERREFS", sfeatures);
+ ZFS_TYPE_SNAPSHOT, "<count>", "USERREFS", B_FALSE, sfeatures);
zprop_register_number(ZFS_PROP_WRITTEN, "written", 0, PROP_READONLY,
- ZFS_TYPE_DATASET, "<size>", "WRITTEN", sfeatures);
+ ZFS_TYPE_DATASET, "<size>", "WRITTEN", B_FALSE, sfeatures);
zprop_register_number(ZFS_PROP_LOGICALUSED, "logicalused", 0,
PROP_READONLY, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<size>",
- "LUSED", sfeatures);
+ "LUSED", B_FALSE, sfeatures);
zprop_register_number(ZFS_PROP_LOGICALREFERENCED, "logicalreferenced",
0, PROP_READONLY, ZFS_TYPE_DATASET | ZFS_TYPE_BOOKMARK, "<size>",
- "LREFER", sfeatures);
+ "LREFER", B_FALSE, sfeatures);
zprop_register_number(ZFS_PROP_FILESYSTEM_COUNT, "filesystem_count",
UINT64_MAX, PROP_READONLY, ZFS_TYPE_FILESYSTEM,
- "<count>", "FSCOUNT", sfeatures);
+ "<count>", "FSCOUNT", B_FALSE, sfeatures);
zprop_register_number(ZFS_PROP_SNAPSHOT_COUNT, "snapshot_count",
UINT64_MAX, PROP_READONLY, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
- "<count>", "SSCOUNT", sfeatures);
+ "<count>", "SSCOUNT", B_FALSE, sfeatures);
zprop_register_number(ZFS_PROP_GUID, "guid", 0, PROP_READONLY,
ZFS_TYPE_DATASET | ZFS_TYPE_BOOKMARK, "<uint64>", "GUID",
- sfeatures);
+ B_TRUE, sfeatures);
zprop_register_number(ZFS_PROP_CREATETXG, "createtxg", 0, PROP_READONLY,
ZFS_TYPE_DATASET | ZFS_TYPE_BOOKMARK, "<uint64>", "CREATETXG",
- sfeatures);
+ B_TRUE, sfeatures);
zprop_register_number(ZFS_PROP_PBKDF2_ITERS, "pbkdf2iters",
0, PROP_ONETIME_DEFAULT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
- "<iters>", "PBKDF2ITERS", sfeatures);
+ "<iters>", "PBKDF2ITERS", B_TRUE, sfeatures);
zprop_register_number(ZFS_PROP_OBJSETID, "objsetid", 0,
- PROP_READONLY, ZFS_TYPE_DATASET, "<uint64>", "OBJSETID", sfeatures);
+ PROP_READONLY, ZFS_TYPE_DATASET, "<uint64>", "OBJSETID", B_TRUE,
+ sfeatures);
/* default number properties */
zprop_register_number(ZFS_PROP_QUOTA, "quota", 0, PROP_DEFAULT,
- ZFS_TYPE_FILESYSTEM, "<size> | none", "QUOTA", sfeatures);
+ ZFS_TYPE_FILESYSTEM, "<size> | none", "QUOTA", B_FALSE, sfeatures);
zprop_register_number(ZFS_PROP_RESERVATION, "reservation", 0,
PROP_DEFAULT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
- "<size> | none", "RESERV", sfeatures);
+ "<size> | none", "RESERV", B_FALSE, sfeatures);
zprop_register_number(ZFS_PROP_VOLSIZE, "volsize", 0, PROP_DEFAULT,
ZFS_TYPE_SNAPSHOT | ZFS_TYPE_VOLUME, "<size>", "VOLSIZE",
- sfeatures);
+ B_FALSE, sfeatures);
zprop_register_number(ZFS_PROP_REFQUOTA, "refquota", 0, PROP_DEFAULT,
- ZFS_TYPE_FILESYSTEM, "<size> | none", "REFQUOTA", sfeatures);
+ ZFS_TYPE_FILESYSTEM, "<size> | none", "REFQUOTA", B_FALSE,
+ sfeatures);
zprop_register_number(ZFS_PROP_REFRESERVATION, "refreservation", 0,
PROP_DEFAULT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
- "<size> | none", "REFRESERV", sfeatures);
+ "<size> | none", "REFRESERV", B_FALSE, sfeatures);
zprop_register_number(ZFS_PROP_FILESYSTEM_LIMIT, "filesystem_limit",
UINT64_MAX, PROP_DEFAULT, ZFS_TYPE_FILESYSTEM,
- "<count> | none", "FSLIMIT", sfeatures);
+ "<count> | none", "FSLIMIT", B_FALSE, sfeatures);
zprop_register_number(ZFS_PROP_SNAPSHOT_LIMIT, "snapshot_limit",
UINT64_MAX, PROP_DEFAULT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
- "<count> | none", "SSLIMIT", sfeatures);
+ "<count> | none", "SSLIMIT", B_FALSE, sfeatures);
/* inherit number properties */
zprop_register_number(ZFS_PROP_RECORDSIZE, "recordsize",
SPA_OLD_MAXBLOCKSIZE, PROP_INHERIT,
- ZFS_TYPE_FILESYSTEM, "512 to 1M, power of 2", "RECSIZE", sfeatures);
+ ZFS_TYPE_FILESYSTEM, "512 to 1M, power of 2", "RECSIZE", B_FALSE,
+ sfeatures);
zprop_register_number(ZFS_PROP_SPECIAL_SMALL_BLOCKS,
"special_small_blocks", 0, PROP_INHERIT, ZFS_TYPE_FILESYSTEM,
- "zero or 512 to 1M, power of 2", "SPECIAL_SMALL_BLOCKS", sfeatures);
+ "zero or 512 to 1M, power of 2", "SPECIAL_SMALL_BLOCKS", B_FALSE,
+ sfeatures);
/* hidden properties */
zprop_register_hidden(ZFS_PROP_NUMCLONES, "numclones", PROP_TYPE_NUMBER,
- PROP_READONLY, ZFS_TYPE_SNAPSHOT, "NUMCLONES", sfeatures);
+ PROP_READONLY, ZFS_TYPE_SNAPSHOT, "NUMCLONES", B_FALSE, sfeatures);
zprop_register_hidden(ZFS_PROP_NAME, "name", PROP_TYPE_STRING,
PROP_READONLY, ZFS_TYPE_DATASET | ZFS_TYPE_BOOKMARK, "NAME",
- sfeatures);
+ B_TRUE, sfeatures);
zprop_register_hidden(ZFS_PROP_ISCSIOPTIONS, "iscsioptions",
PROP_TYPE_STRING, PROP_INHERIT, ZFS_TYPE_VOLUME, "ISCSIOPTIONS",
- sfeatures);
+ B_TRUE, sfeatures);
zprop_register_hidden(ZFS_PROP_STMF_SHAREINFO, "stmf_sbd_lu",
PROP_TYPE_STRING, PROP_INHERIT, ZFS_TYPE_VOLUME,
- "STMF_SBD_LU", sfeatures);
+ "STMF_SBD_LU", B_TRUE, sfeatures);
zprop_register_hidden(ZFS_PROP_USERACCOUNTING, "useraccounting",
PROP_TYPE_NUMBER, PROP_READONLY, ZFS_TYPE_DATASET,
- "USERACCOUNTING", sfeatures);
+ "USERACCOUNTING", B_FALSE, sfeatures);
zprop_register_hidden(ZFS_PROP_UNIQUE, "unique", PROP_TYPE_NUMBER,
- PROP_READONLY, ZFS_TYPE_DATASET, "UNIQUE", sfeatures);
+ PROP_READONLY, ZFS_TYPE_DATASET, "UNIQUE", B_FALSE, sfeatures);
zprop_register_hidden(ZFS_PROP_INCONSISTENT, "inconsistent",
PROP_TYPE_NUMBER, PROP_READONLY, ZFS_TYPE_DATASET, "INCONSISTENT",
- sfeatures);
+ B_FALSE, sfeatures);
zprop_register_hidden(ZFS_PROP_IVSET_GUID, "ivsetguid",
PROP_TYPE_NUMBER, PROP_READONLY,
- ZFS_TYPE_DATASET | ZFS_TYPE_BOOKMARK, "IVSETGUID", sfeatures);
+ ZFS_TYPE_DATASET | ZFS_TYPE_BOOKMARK, "IVSETGUID", B_TRUE,
+ sfeatures);
zprop_register_hidden(ZFS_PROP_PREV_SNAP, "prevsnap", PROP_TYPE_STRING,
PROP_READONLY, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "PREVSNAP",
- sfeatures);
+ B_TRUE, sfeatures);
zprop_register_hidden(ZFS_PROP_PBKDF2_SALT, "pbkdf2salt",
PROP_TYPE_NUMBER, PROP_ONETIME_DEFAULT,
- ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "PBKDF2SALT", sfeatures);
+ ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "PBKDF2SALT", B_FALSE,
+ sfeatures);
zprop_register_hidden(ZFS_PROP_KEY_GUID, "keyguid", PROP_TYPE_NUMBER,
- PROP_READONLY, ZFS_TYPE_DATASET, "KEYGUID", sfeatures);
+ PROP_READONLY, ZFS_TYPE_DATASET, "KEYGUID", B_TRUE, sfeatures);
zprop_register_hidden(ZFS_PROP_REDACTED, "redacted", PROP_TYPE_NUMBER,
- PROP_READONLY, ZFS_TYPE_DATASET, "REDACTED", sfeatures);
+ PROP_READONLY, ZFS_TYPE_DATASET, "REDACTED", B_FALSE, sfeatures);
/*
* Properties that are obsolete and not used. These are retained so
@@ -715,12 +722,13 @@ zfs_prop_init(void)
* have NULL pointers in the zfs_prop_table[].
*/
zprop_register_hidden(ZFS_PROP_REMAPTXG, "remaptxg", PROP_TYPE_NUMBER,
- PROP_READONLY, ZFS_TYPE_DATASET, "REMAPTXG", sfeatures);
+ PROP_READONLY, ZFS_TYPE_DATASET, "REMAPTXG", B_FALSE, sfeatures);
/* oddball properties */
+ /* 'creation' is a number but displayed as human-readable => flex */
zprop_register_impl(ZFS_PROP_CREATION, "creation", PROP_TYPE_NUMBER, 0,
NULL, PROP_READONLY, ZFS_TYPE_DATASET | ZFS_TYPE_BOOKMARK,
- "<date>", "CREATION", B_FALSE, B_TRUE, NULL, sfeatures);
+ "<date>", "CREATION", B_FALSE, B_TRUE, B_TRUE, NULL, sfeatures);
zfs_mod_list_supported_free(sfeatures);
}
@@ -993,10 +1001,10 @@ zfs_prop_align_right(zfs_prop_t prop)
#include <sys/simd.h>
-#if defined(HAVE_KERNEL_FPU_INTERNAL)
+#if defined(HAVE_KERNEL_FPU_INTERNAL) || defined(HAVE_KERNEL_FPU_XSAVE_INTERNAL)
union fpregs_state **zfs_kfpu_fpregs;
EXPORT_SYMBOL(zfs_kfpu_fpregs);
-#endif /* HAVE_KERNEL_FPU_INTERNAL */
+#endif /* HAVE_KERNEL_FPU_INTERNAL || HAVE_KERNEL_FPU_XSAVE_INTERNAL */
static int __init
zcommon_init(void)
diff --git a/sys/contrib/openzfs/module/zcommon/zpool_prop.c b/sys/contrib/openzfs/module/zcommon/zpool_prop.c
index 44bfe4add230..853476a1fc16 100644
--- a/sys/contrib/openzfs/module/zcommon/zpool_prop.c
+++ b/sys/contrib/openzfs/module/zcommon/zpool_prop.c
@@ -85,39 +85,45 @@ zpool_prop_init(void)
/* readonly number properties */
zprop_register_number(ZPOOL_PROP_SIZE, "size", 0, PROP_READONLY,
- ZFS_TYPE_POOL, "<size>", "SIZE", sfeatures);
+ ZFS_TYPE_POOL, "<size>", "SIZE", B_FALSE, sfeatures);
zprop_register_number(ZPOOL_PROP_FREE, "free", 0, PROP_READONLY,
- ZFS_TYPE_POOL, "<size>", "FREE", sfeatures);
+ ZFS_TYPE_POOL, "<size>", "FREE", B_FALSE, sfeatures);
zprop_register_number(ZPOOL_PROP_FREEING, "freeing", 0, PROP_READONLY,
- ZFS_TYPE_POOL, "<size>", "FREEING", sfeatures);
+ ZFS_TYPE_POOL, "<size>", "FREEING", B_FALSE, sfeatures);
zprop_register_number(ZPOOL_PROP_CHECKPOINT, "checkpoint", 0,
- PROP_READONLY, ZFS_TYPE_POOL, "<size>", "CKPOINT", sfeatures);
+ PROP_READONLY, ZFS_TYPE_POOL, "<size>", "CKPOINT", B_FALSE,
+ sfeatures);
zprop_register_number(ZPOOL_PROP_LEAKED, "leaked", 0, PROP_READONLY,
- ZFS_TYPE_POOL, "<size>", "LEAKED", sfeatures);
+ ZFS_TYPE_POOL, "<size>", "LEAKED", B_FALSE, sfeatures);
zprop_register_number(ZPOOL_PROP_ALLOCATED, "allocated", 0,
- PROP_READONLY, ZFS_TYPE_POOL, "<size>", "ALLOC", sfeatures);
+ PROP_READONLY, ZFS_TYPE_POOL, "<size>", "ALLOC", B_FALSE,
+ sfeatures);
zprop_register_number(ZPOOL_PROP_EXPANDSZ, "expandsize", 0,
- PROP_READONLY, ZFS_TYPE_POOL, "<size>", "EXPANDSZ", sfeatures);
+ PROP_READONLY, ZFS_TYPE_POOL, "<size>", "EXPANDSZ", B_FALSE,
+ sfeatures);
zprop_register_number(ZPOOL_PROP_FRAGMENTATION, "fragmentation", 0,
- PROP_READONLY, ZFS_TYPE_POOL, "<percent>", "FRAG", sfeatures);
+ PROP_READONLY, ZFS_TYPE_POOL, "<percent>", "FRAG", B_FALSE,
+ sfeatures);
zprop_register_number(ZPOOL_PROP_CAPACITY, "capacity", 0, PROP_READONLY,
- ZFS_TYPE_POOL, "<size>", "CAP", sfeatures);
+ ZFS_TYPE_POOL, "<size>", "CAP", B_FALSE, sfeatures);
zprop_register_number(ZPOOL_PROP_GUID, "guid", 0, PROP_READONLY,
- ZFS_TYPE_POOL, "<guid>", "GUID", sfeatures);
+ ZFS_TYPE_POOL, "<guid>", "GUID", B_TRUE, sfeatures);
zprop_register_number(ZPOOL_PROP_LOAD_GUID, "load_guid", 0,
PROP_READONLY, ZFS_TYPE_POOL, "<load_guid>", "LOAD_GUID",
- sfeatures);
+ B_TRUE, sfeatures);
zprop_register_number(ZPOOL_PROP_HEALTH, "health", 0, PROP_READONLY,
- ZFS_TYPE_POOL, "<state>", "HEALTH", sfeatures);
+ ZFS_TYPE_POOL, "<state>", "HEALTH", B_FALSE, sfeatures);
zprop_register_number(ZPOOL_PROP_DEDUPRATIO, "dedupratio", 0,
PROP_READONLY, ZFS_TYPE_POOL, "<1.00x or higher if deduped>",
- "DEDUP", sfeatures);
+ "DEDUP", B_FALSE, sfeatures);
/* default number properties */
zprop_register_number(ZPOOL_PROP_VERSION, "version", SPA_VERSION,
- PROP_DEFAULT, ZFS_TYPE_POOL, "<version>", "VERSION", sfeatures);
+ PROP_DEFAULT, ZFS_TYPE_POOL, "<version>", "VERSION", B_FALSE,
+ sfeatures);
zprop_register_number(ZPOOL_PROP_ASHIFT, "ashift", 0, PROP_DEFAULT,
- ZFS_TYPE_POOL, "<ashift, 9-16, or 0=default>", "ASHIFT", sfeatures);
+ ZFS_TYPE_POOL, "<ashift, 9-16, or 0=default>", "ASHIFT", B_FALSE,
+ sfeatures);
/* default index (boolean) properties */
zprop_register_index(ZPOOL_PROP_DELEGATION, "delegation", 1,
@@ -150,18 +156,18 @@ zpool_prop_init(void)
/* hidden properties */
zprop_register_hidden(ZPOOL_PROP_NAME, "name", PROP_TYPE_STRING,
- PROP_READONLY, ZFS_TYPE_POOL, "NAME", sfeatures);
+ PROP_READONLY, ZFS_TYPE_POOL, "NAME", B_TRUE, sfeatures);
zprop_register_hidden(ZPOOL_PROP_MAXBLOCKSIZE, "maxblocksize",
PROP_TYPE_NUMBER, PROP_READONLY, ZFS_TYPE_POOL, "MAXBLOCKSIZE",
- sfeatures);
+ B_FALSE, sfeatures);
zprop_register_hidden(ZPOOL_PROP_TNAME, "tname", PROP_TYPE_STRING,
- PROP_ONETIME, ZFS_TYPE_POOL, "TNAME", sfeatures);
+ PROP_ONETIME, ZFS_TYPE_POOL, "TNAME", B_TRUE, sfeatures);
zprop_register_hidden(ZPOOL_PROP_MAXDNODESIZE, "maxdnodesize",
PROP_TYPE_NUMBER, PROP_READONLY, ZFS_TYPE_POOL, "MAXDNODESIZE",
- sfeatures);
+ B_FALSE, sfeatures);
zprop_register_hidden(ZPOOL_PROP_DEDUPDITTO, "dedupditto",
PROP_TYPE_NUMBER, PROP_DEFAULT, ZFS_TYPE_POOL, "DEDUPDITTO",
- sfeatures);
+ B_FALSE, sfeatures);
zfs_mod_list_supported_free(sfeatures);
}
@@ -323,67 +329,85 @@ vdev_prop_init(void)
/* readonly number properties */
zprop_register_number(VDEV_PROP_SIZE, "size", 0, PROP_READONLY,
- ZFS_TYPE_VDEV, "<size>", "SIZE", sfeatures);
+ ZFS_TYPE_VDEV, "<size>", "SIZE", B_FALSE, sfeatures);
zprop_register_number(VDEV_PROP_FREE, "free", 0, PROP_READONLY,
- ZFS_TYPE_VDEV, "<size>", "FREE", sfeatures);
+ ZFS_TYPE_VDEV, "<size>", "FREE", B_FALSE, sfeatures);
zprop_register_number(VDEV_PROP_ALLOCATED, "allocated", 0,
- PROP_READONLY, ZFS_TYPE_VDEV, "<size>", "ALLOC", sfeatures);
+ PROP_READONLY, ZFS_TYPE_VDEV, "<size>", "ALLOC", B_FALSE,
+ sfeatures);
zprop_register_number(VDEV_PROP_EXPANDSZ, "expandsize", 0,
- PROP_READONLY, ZFS_TYPE_VDEV, "<size>", "EXPANDSZ", sfeatures);
+ PROP_READONLY, ZFS_TYPE_VDEV, "<size>", "EXPANDSZ", B_FALSE,
+ sfeatures);
zprop_register_number(VDEV_PROP_FRAGMENTATION, "fragmentation", 0,
- PROP_READONLY, ZFS_TYPE_VDEV, "<percent>", "FRAG", sfeatures);
+ PROP_READONLY, ZFS_TYPE_VDEV, "<percent>", "FRAG", B_FALSE,
+ sfeatures);
zprop_register_number(VDEV_PROP_CAPACITY, "capacity", 0, PROP_READONLY,
- ZFS_TYPE_VDEV, "<size>", "CAP", sfeatures);
+ ZFS_TYPE_VDEV, "<size>", "CAP", B_FALSE, sfeatures);
zprop_register_number(VDEV_PROP_GUID, "guid", 0, PROP_READONLY,
- ZFS_TYPE_VDEV, "<guid>", "GUID", sfeatures);
+ ZFS_TYPE_VDEV, "<guid>", "GUID", B_TRUE, sfeatures);
zprop_register_number(VDEV_PROP_STATE, "state", 0, PROP_READONLY,
- ZFS_TYPE_VDEV, "<state>", "STATE", sfeatures);
+ ZFS_TYPE_VDEV, "<state>", "STATE", B_FALSE, sfeatures);
zprop_register_number(VDEV_PROP_BOOTSIZE, "bootsize", 0, PROP_READONLY,
- ZFS_TYPE_VDEV, "<size>", "BOOTSIZE", sfeatures);
+ ZFS_TYPE_VDEV, "<size>", "BOOTSIZE", B_FALSE, sfeatures);
zprop_register_number(VDEV_PROP_ASIZE, "asize", 0, PROP_READONLY,
- ZFS_TYPE_VDEV, "<asize>", "ASIZE", sfeatures);
+ ZFS_TYPE_VDEV, "<asize>", "ASIZE", B_FALSE, sfeatures);
zprop_register_number(VDEV_PROP_PSIZE, "psize", 0, PROP_READONLY,
- ZFS_TYPE_VDEV, "<psize>", "PSIZE", sfeatures);
+ ZFS_TYPE_VDEV, "<psize>", "PSIZE", B_FALSE, sfeatures);
zprop_register_number(VDEV_PROP_ASHIFT, "ashift", 0, PROP_READONLY,
- ZFS_TYPE_VDEV, "<ashift>", "ASHIFT", sfeatures);
+ ZFS_TYPE_VDEV, "<ashift>", "ASHIFT", B_FALSE, sfeatures);
zprop_register_number(VDEV_PROP_PARITY, "parity", 0, PROP_READONLY,
- ZFS_TYPE_VDEV, "<parity>", "PARITY", sfeatures);
+ ZFS_TYPE_VDEV, "<parity>", "PARITY", B_FALSE, sfeatures);
zprop_register_number(VDEV_PROP_NUMCHILDREN, "numchildren", 0,
PROP_READONLY, ZFS_TYPE_VDEV, "<number-of-children>", "NUMCHILD",
- sfeatures);
+ B_FALSE, sfeatures);
zprop_register_number(VDEV_PROP_READ_ERRORS, "read_errors", 0,
- PROP_READONLY, ZFS_TYPE_VDEV, "<errors>", "RDERR", sfeatures);
+ PROP_READONLY, ZFS_TYPE_VDEV, "<errors>", "RDERR", B_FALSE,
+ sfeatures);
zprop_register_number(VDEV_PROP_WRITE_ERRORS, "write_errors", 0,
- PROP_READONLY, ZFS_TYPE_VDEV, "<errors>", "WRERR", sfeatures);
+ PROP_READONLY, ZFS_TYPE_VDEV, "<errors>", "WRERR", B_FALSE,
+ sfeatures);
zprop_register_number(VDEV_PROP_CHECKSUM_ERRORS, "checksum_errors", 0,
- PROP_READONLY, ZFS_TYPE_VDEV, "<errors>", "CKERR", sfeatures);
+ PROP_READONLY, ZFS_TYPE_VDEV, "<errors>", "CKERR", B_FALSE,
+ sfeatures);
zprop_register_number(VDEV_PROP_INITIALIZE_ERRORS,
"initialize_errors", 0, PROP_READONLY, ZFS_TYPE_VDEV, "<errors>",
- "INITERR", sfeatures);
+ "INITERR", B_FALSE, sfeatures);
zprop_register_number(VDEV_PROP_OPS_NULL, "null_ops", 0,
- PROP_READONLY, ZFS_TYPE_VDEV, "<operations>", "NULLOP", sfeatures);
+ PROP_READONLY, ZFS_TYPE_VDEV, "<operations>", "NULLOP", B_FALSE,
+ sfeatures);
zprop_register_number(VDEV_PROP_OPS_READ, "read_ops", 0,
- PROP_READONLY, ZFS_TYPE_VDEV, "<operations>", "READOP", sfeatures);
+ PROP_READONLY, ZFS_TYPE_VDEV, "<operations>", "READOP", B_FALSE,
+ sfeatures);
zprop_register_number(VDEV_PROP_OPS_WRITE, "write_ops", 0,
- PROP_READONLY, ZFS_TYPE_VDEV, "<operations>", "WRITEOP", sfeatures);
+ PROP_READONLY, ZFS_TYPE_VDEV, "<operations>", "WRITEOP", B_FALSE,
+ sfeatures);
zprop_register_number(VDEV_PROP_OPS_FREE, "free_ops", 0,
- PROP_READONLY, ZFS_TYPE_VDEV, "<operations>", "FREEOP", sfeatures);
+ PROP_READONLY, ZFS_TYPE_VDEV, "<operations>", "FREEOP", B_FALSE,
+ sfeatures);
zprop_register_number(VDEV_PROP_OPS_CLAIM, "claim_ops", 0,
- PROP_READONLY, ZFS_TYPE_VDEV, "<operations>", "CLAIMOP", sfeatures);
+ PROP_READONLY, ZFS_TYPE_VDEV, "<operations>", "CLAIMOP", B_FALSE,
+ sfeatures);
zprop_register_number(VDEV_PROP_OPS_TRIM, "trim_ops", 0,
- PROP_READONLY, ZFS_TYPE_VDEV, "<operations>", "TRIMOP", sfeatures);
+ PROP_READONLY, ZFS_TYPE_VDEV, "<operations>", "TRIMOP", B_FALSE,
+ sfeatures);
zprop_register_number(VDEV_PROP_BYTES_NULL, "null_bytes", 0,
- PROP_READONLY, ZFS_TYPE_VDEV, "<bytes>", "NULLBYTE", sfeatures);
+ PROP_READONLY, ZFS_TYPE_VDEV, "<bytes>", "NULLBYTE", B_FALSE,
+ sfeatures);
zprop_register_number(VDEV_PROP_BYTES_READ, "read_bytes", 0,
- PROP_READONLY, ZFS_TYPE_VDEV, "<bytes>", "READBYTE", sfeatures);
+ PROP_READONLY, ZFS_TYPE_VDEV, "<bytes>", "READBYTE", B_FALSE,
+ sfeatures);
zprop_register_number(VDEV_PROP_BYTES_WRITE, "write_bytes", 0,
- PROP_READONLY, ZFS_TYPE_VDEV, "<bytes>", "WRITEBYTE", sfeatures);
+ PROP_READONLY, ZFS_TYPE_VDEV, "<bytes>", "WRITEBYTE", B_FALSE,
+ sfeatures);
zprop_register_number(VDEV_PROP_BYTES_FREE, "free_bytes", 0,
- PROP_READONLY, ZFS_TYPE_VDEV, "<bytes>", "FREEBYTE", sfeatures);
+ PROP_READONLY, ZFS_TYPE_VDEV, "<bytes>", "FREEBYTE", B_FALSE,
+ sfeatures);
zprop_register_number(VDEV_PROP_BYTES_CLAIM, "claim_bytes", 0,
- PROP_READONLY, ZFS_TYPE_VDEV, "<bytes>", "CLAIMBYTE", sfeatures);
+ PROP_READONLY, ZFS_TYPE_VDEV, "<bytes>", "CLAIMBYTE", B_FALSE,
+ sfeatures);
zprop_register_number(VDEV_PROP_BYTES_TRIM, "trim_bytes", 0,
- PROP_READONLY, ZFS_TYPE_VDEV, "<bytes>", "TRIMBYTE", sfeatures);
+ PROP_READONLY, ZFS_TYPE_VDEV, "<bytes>", "TRIMBYTE", B_FALSE,
+ sfeatures);
/* default numeric properties */
@@ -399,7 +423,7 @@ vdev_prop_init(void)
/* hidden properties */
zprop_register_hidden(VDEV_PROP_NAME, "name", PROP_TYPE_STRING,
- PROP_READONLY, ZFS_TYPE_VDEV, "NAME", sfeatures);
+ PROP_READONLY, ZFS_TYPE_VDEV, "NAME", B_TRUE, sfeatures);
zfs_mod_list_supported_free(sfeatures);
}
diff --git a/sys/contrib/openzfs/module/zcommon/zprop_common.c b/sys/contrib/openzfs/module/zcommon/zprop_common.c
index c32039c1b61d..0f496877577b 100644
--- a/sys/contrib/openzfs/module/zcommon/zprop_common.c
+++ b/sys/contrib/openzfs/module/zcommon/zprop_common.c
@@ -97,7 +97,8 @@ void
zprop_register_impl(int prop, const char *name, zprop_type_t type,
uint64_t numdefault, const char *strdefault, zprop_attr_t attr,
int objset_types, const char *values, const char *colname,
- boolean_t rightalign, boolean_t visible, const zprop_index_t *idx_tbl,
+ boolean_t rightalign, boolean_t visible, boolean_t flex,
+ const zprop_index_t *idx_tbl,
const struct zfs_mod_supported_features *sfeatures)
{
zprop_desc_t *prop_tbl = zprop_get_proptable(objset_types);
@@ -122,6 +123,7 @@ zprop_register_impl(int prop, const char *name, zprop_type_t type,
pd->pd_visible = visible;
pd->pd_zfs_mod_supported =
zfs_mod_supported_prop(name, objset_types, sfeatures);
+ pd->pd_always_flex = flex;
pd->pd_table = idx_tbl;
pd->pd_table_size = 0;
while (idx_tbl && (idx_tbl++)->pi_name != NULL)
@@ -134,17 +136,20 @@ zprop_register_string(int prop, const char *name, const char *def,
const char *colname, const struct zfs_mod_supported_features *sfeatures)
{
zprop_register_impl(prop, name, PROP_TYPE_STRING, 0, def, attr,
- objset_types, values, colname, B_FALSE, B_TRUE, NULL, sfeatures);
+ objset_types, values, colname, B_FALSE, B_TRUE, B_FALSE, NULL,
+ sfeatures);
}
void
zprop_register_number(int prop, const char *name, uint64_t def,
zprop_attr_t attr, int objset_types, const char *values,
- const char *colname, const struct zfs_mod_supported_features *sfeatures)
+ const char *colname, boolean_t flex,
+ const struct zfs_mod_supported_features *sfeatures)
{
zprop_register_impl(prop, name, PROP_TYPE_NUMBER, def, NULL, attr,
- objset_types, values, colname, B_TRUE, B_TRUE, NULL, sfeatures);
+ objset_types, values, colname, B_TRUE, B_TRUE, flex, NULL,
+ sfeatures);
}
void
@@ -154,17 +159,18 @@ zprop_register_index(int prop, const char *name, uint64_t def,
const struct zfs_mod_supported_features *sfeatures)
{
zprop_register_impl(prop, name, PROP_TYPE_INDEX, def, NULL, attr,
- objset_types, values, colname, B_FALSE, B_TRUE, idx_tbl, sfeatures);
+ objset_types, values, colname, B_FALSE, B_TRUE, B_FALSE, idx_tbl,
+ sfeatures);
}
void
zprop_register_hidden(int prop, const char *name, zprop_type_t type,
- zprop_attr_t attr, int objset_types, const char *colname,
+ zprop_attr_t attr, int objset_types, const char *colname, boolean_t flex,
const struct zfs_mod_supported_features *sfeatures)
{
zprop_register_impl(prop, name, type, 0, NULL, attr,
objset_types, NULL, colname,
- type == PROP_TYPE_NUMBER, B_FALSE, NULL, sfeatures);
+ type == PROP_TYPE_NUMBER, B_FALSE, flex, NULL, sfeatures);
}
@@ -437,7 +443,10 @@ zprop_width(int prop, boolean_t *fixed, zfs_type_t type)
prop_tbl = zprop_get_proptable(type);
pd = &prop_tbl[prop];
- *fixed = B_TRUE;
+ if (type != ZFS_TYPE_POOL && type != ZFS_TYPE_VDEV)
+ type = ZFS_TYPE_FILESYSTEM;
+
+ *fixed = !pd->pd_always_flex;
/*
* Start with the width of the column name.
@@ -457,18 +466,13 @@ zprop_width(int prop, boolean_t *fixed, zfs_type_t type)
if (ret < 5)
ret = 5;
/*
- * 'creation' is handled specially because it's a number
- * internally, but displayed as a date string.
- */
- if (prop == ZFS_PROP_CREATION)
- *fixed = B_FALSE;
- /*
* 'health' is handled specially because it's a number
* internally, but displayed as a fixed 8 character string.
*/
- if (prop == ZPOOL_PROP_HEALTH)
+ if (type == ZFS_TYPE_POOL && prop == ZPOOL_PROP_HEALTH)
ret = 8;
break;
+
case PROP_TYPE_INDEX:
idx = prop_tbl[prop].pd_table;
for (i = 0; idx[i].pi_name != NULL; i++) {
@@ -478,7 +482,6 @@ zprop_width(int prop, boolean_t *fixed, zfs_type_t type)
break;
case PROP_TYPE_STRING:
- *fixed = B_FALSE;
break;
}
diff --git a/sys/contrib/openzfs/module/zfs/abd.c b/sys/contrib/openzfs/module/zfs/abd.c
index 8ee8e7e57420..b6d7ac6407e3 100644
--- a/sys/contrib/openzfs/module/zfs/abd.c
+++ b/sys/contrib/openzfs/module/zfs/abd.c
@@ -1066,10 +1066,10 @@ abd_raidz_gen_iterate(abd_t **cabds, abd_t *dabd,
switch (parity) {
case 3:
len = MIN(caiters[2].iter_mapsize, len);
- fallthrough;
+ zfs_fallthrough;
case 2:
len = MIN(caiters[1].iter_mapsize, len);
- fallthrough;
+ zfs_fallthrough;
case 1:
len = MIN(caiters[0].iter_mapsize, len);
}
@@ -1179,11 +1179,11 @@ abd_raidz_rec_iterate(abd_t **cabds, abd_t **tabds,
case 3:
len = MIN(xiters[2].iter_mapsize, len);
len = MIN(citers[2].iter_mapsize, len);
- fallthrough;
+ zfs_fallthrough;
case 2:
len = MIN(xiters[1].iter_mapsize, len);
len = MIN(citers[1].iter_mapsize, len);
- fallthrough;
+ zfs_fallthrough;
case 1:
len = MIN(xiters[0].iter_mapsize, len);
len = MIN(citers[0].iter_mapsize, len);
diff --git a/sys/contrib/openzfs/module/zfs/arc.c b/sys/contrib/openzfs/module/zfs/arc.c
index 214c75fe6157..744df24235e4 100644
--- a/sys/contrib/openzfs/module/zfs/arc.c
+++ b/sys/contrib/openzfs/module/zfs/arc.c
@@ -928,7 +928,7 @@ static unsigned long l2arc_rebuild_blocks_min_l2size = 1024 * 1024 * 1024;
/* L2ARC persistence rebuild control routines. */
void l2arc_rebuild_vdev(vdev_t *vd, boolean_t reopen);
-static void l2arc_dev_rebuild_thread(void *arg);
+static _Noreturn void l2arc_dev_rebuild_thread(void *arg);
static int l2arc_rebuild(l2arc_dev_t *dev);
/* L2ARC persistence read I/O routines. */
@@ -9706,7 +9706,7 @@ l2arc_hdr_limit_reached(void)
* This thread feeds the L2ARC at regular intervals. This is the beating
* heart of the L2ARC.
*/
-static void
+static _Noreturn void
l2arc_feed_thread(void *unused)
{
(void) unused;
@@ -10145,7 +10145,7 @@ l2arc_spa_rebuild_start(spa_t *spa)
/*
* Main entry point for L2ARC rebuilding.
*/
-static void
+static _Noreturn void
l2arc_dev_rebuild_thread(void *arg)
{
l2arc_dev_t *dev = arg;
@@ -11043,7 +11043,6 @@ EXPORT_SYMBOL(arc_getbuf_func);
EXPORT_SYMBOL(arc_add_prune_callback);
EXPORT_SYMBOL(arc_remove_prune_callback);
-/* BEGIN CSTYLED */
ZFS_MODULE_PARAM_CALL(zfs_arc, zfs_arc_, min, param_set_arc_min,
param_get_long, ZMOD_RW, "Min arc size");
@@ -11054,7 +11053,7 @@ ZFS_MODULE_PARAM_CALL(zfs_arc, zfs_arc_, meta_limit, param_set_arc_long,
param_get_long, ZMOD_RW, "Metadata limit for arc size");
ZFS_MODULE_PARAM_CALL(zfs_arc, zfs_arc_, meta_limit_percent,
- param_set_arc_long, param_get_long, ZMOD_RW,
+ param_set_arc_long, param_get_long, ZMOD_RW,
"Percent of arc size for arc meta limit");
ZFS_MODULE_PARAM_CALL(zfs_arc, zfs_arc_, meta_min, param_set_arc_long,
@@ -11094,7 +11093,7 @@ ZFS_MODULE_PARAM_CALL(zfs_arc, zfs_arc_, min_prefetch_ms, param_set_arc_int,
param_get_int, ZMOD_RW, "Min life of prefetch block in ms");
ZFS_MODULE_PARAM_CALL(zfs_arc, zfs_arc_, min_prescient_prefetch_ms,
- param_set_arc_int, param_get_int, ZMOD_RW,
+ param_set_arc_int, param_get_int, ZMOD_RW,
"Min life of prescient prefetched block in ms");
ZFS_MODULE_PARAM(zfs_l2arc, l2arc_, write_max, ULONG, ZMOD_RW,
@@ -11140,8 +11139,7 @@ ZFS_MODULE_PARAM(zfs_l2arc, l2arc_, mfuonly, INT, ZMOD_RW,
"Cache only MFU data from ARC into L2ARC");
ZFS_MODULE_PARAM(zfs_l2arc, l2arc_, exclude_special, INT, ZMOD_RW,
- "If set to 1 exclude dbufs on special vdevs from being cached to "
- "L2ARC.");
+ "Exclude dbufs on special vdevs from being cached to L2ARC if set.");
ZFS_MODULE_PARAM_CALL(zfs_arc, zfs_arc_, lotsfree_percent, param_set_arc_int,
param_get_int, ZMOD_RW, "System free memory I/O throttle in bytes");
@@ -11153,7 +11151,7 @@ ZFS_MODULE_PARAM_CALL(zfs_arc, zfs_arc_, dnode_limit, param_set_arc_long,
param_get_long, ZMOD_RW, "Minimum bytes of dnodes in arc");
ZFS_MODULE_PARAM_CALL(zfs_arc, zfs_arc_, dnode_limit_percent,
- param_set_arc_long, param_get_long, ZMOD_RW,
+ param_set_arc_long, param_get_long, ZMOD_RW,
"Percent of ARC meta buffers for dnodes");
ZFS_MODULE_PARAM(zfs_arc, zfs_arc_, dnode_reduce_percent, ULONG, ZMOD_RW,
@@ -11167,4 +11165,3 @@ ZFS_MODULE_PARAM(zfs_arc, zfs_arc_, evict_batch_limit, INT, ZMOD_RW,
ZFS_MODULE_PARAM(zfs_arc, zfs_arc_, prune_task_threads, INT, ZMOD_RW,
"Number of arc_prune threads");
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/zfs/btree.c b/sys/contrib/openzfs/module/zfs/btree.c
index 57b9dbbb2b50..5bcf621d5994 100644
--- a/sys/contrib/openzfs/module/zfs/btree.c
+++ b/sys/contrib/openzfs/module/zfs/btree.c
@@ -536,7 +536,6 @@ zfs_btree_insert_into_parent(zfs_btree_t *tree, zfs_btree_hdr_t *old_node,
ASSERT3P(old_node->bth_parent, ==, new_node->bth_parent);
uint64_t size = tree->bt_elem_size;
zfs_btree_core_t *parent = old_node->bth_parent;
- zfs_btree_hdr_t *par_hdr = &parent->btc_hdr;
/*
* If this is the root node we were splitting, we create a new root
@@ -568,6 +567,7 @@ zfs_btree_insert_into_parent(zfs_btree_t *tree, zfs_btree_hdr_t *old_node,
* Since we have the new separator, binary search for where to put
* new_node.
*/
+ zfs_btree_hdr_t *par_hdr = &parent->btc_hdr;
zfs_btree_index_t idx;
ASSERT(par_hdr->bth_core);
VERIFY3P(zfs_btree_find_in_buf(tree, parent->btc_elems,
@@ -1898,7 +1898,8 @@ static uint64_t
zfs_btree_verify_counts_helper(zfs_btree_t *tree, zfs_btree_hdr_t *hdr)
{
if (!hdr->bth_core) {
- if (tree->bt_root != hdr && hdr != &tree->bt_bulk->btl_hdr) {
+ if (tree->bt_root != hdr && tree->bt_bulk &&
+ hdr != &tree->bt_bulk->btl_hdr) {
uint64_t capacity = P2ALIGN((BTREE_LEAF_SIZE -
sizeof (zfs_btree_hdr_t)) / tree->bt_elem_size, 2);
VERIFY3U(hdr->bth_count, >=, (capacity / 2) - 1);
diff --git a/sys/contrib/openzfs/module/zfs/dbuf.c b/sys/contrib/openzfs/module/zfs/dbuf.c
index 96dcb2564754..cb2b7e5a1def 100644
--- a/sys/contrib/openzfs/module/zfs/dbuf.c
+++ b/sys/contrib/openzfs/module/zfs/dbuf.c
@@ -171,11 +171,6 @@ static void dbuf_write(dbuf_dirty_record_t *dr, arc_buf_t *data, dmu_tx_t *tx);
static void dbuf_sync_leaf_verify_bonus_dnode(dbuf_dirty_record_t *dr);
static int dbuf_read_verify_dnode_crypt(dmu_buf_impl_t *db, uint32_t flags);
-extern inline void dmu_buf_init_user(dmu_buf_user_t *dbu,
- dmu_buf_evict_func_t *evict_func_sync,
- dmu_buf_evict_func_t *evict_func_async,
- dmu_buf_t **clear_on_evict_dbufp);
-
/*
* Global data structures and functions for the dbuf cache.
*/
@@ -783,7 +778,7 @@ dbuf_evict_one(void)
* of the dbuf cache is at or below the maximum size. Once the dbuf is aged
* out of the cache it is destroyed and becomes eligible for arc eviction.
*/
-static void
+static _Noreturn void
dbuf_evict_thread(void *unused)
{
(void) unused;
@@ -822,7 +817,7 @@ dbuf_evict_thread(void *unused)
/*
* Wake up the dbuf eviction thread if the dbuf cache is at its max size.
* If the dbuf cache is at its high water mark, then evict a dbuf from the
- * dbuf cache using the callers context.
+ * dbuf cache using the caller's context.
*/
static void
dbuf_evict_notify(uint64_t size)
@@ -5096,25 +5091,20 @@ EXPORT_SYMBOL(dmu_buf_set_user_ie);
EXPORT_SYMBOL(dmu_buf_get_user);
EXPORT_SYMBOL(dmu_buf_get_blkptr);
-/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs_dbuf_cache, dbuf_cache_, max_bytes, ULONG, ZMOD_RW,
"Maximum size in bytes of the dbuf cache.");
ZFS_MODULE_PARAM(zfs_dbuf_cache, dbuf_cache_, hiwater_pct, UINT, ZMOD_RW,
- "Percentage over dbuf_cache_max_bytes when dbufs must be evicted "
- "directly.");
+ "Percentage over dbuf_cache_max_bytes for direct dbuf eviction.");
ZFS_MODULE_PARAM(zfs_dbuf_cache, dbuf_cache_, lowater_pct, UINT, ZMOD_RW,
- "Percentage below dbuf_cache_max_bytes when the evict thread stops "
- "evicting dbufs.");
+ "Percentage below dbuf_cache_max_bytes when dbuf eviction stops.");
ZFS_MODULE_PARAM(zfs_dbuf, dbuf_, metadata_cache_max_bytes, ULONG, ZMOD_RW,
- "Maximum size in bytes of the dbuf metadata cache.");
+ "Maximum size in bytes of dbuf metadata cache.");
ZFS_MODULE_PARAM(zfs_dbuf, dbuf_, cache_shift, INT, ZMOD_RW,
- "Set the size of the dbuf cache to a log2 fraction of arc size.");
+ "Set size of dbuf cache to log2 fraction of arc size.");
ZFS_MODULE_PARAM(zfs_dbuf, dbuf_, metadata_cache_shift, INT, ZMOD_RW,
- "Set the size of the dbuf metadata cache to a log2 fraction of arc "
- "size.");
-/* END CSTYLED */
+ "Set size of dbuf metadata cache to log2 fraction of arc size.");
diff --git a/sys/contrib/openzfs/module/zfs/dbuf_stats.c b/sys/contrib/openzfs/module/zfs/dbuf_stats.c
index 12bb568a08cc..fa9a5f08060a 100644
--- a/sys/contrib/openzfs/module/zfs/dbuf_stats.c
+++ b/sys/contrib/openzfs/module/zfs/dbuf_stats.c
@@ -226,7 +226,5 @@ dbuf_stats_destroy(void)
dbuf_stats_hash_table_destroy();
}
-/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs, zfs_, dbuf_state_index, INT, ZMOD_RW,
"Calculate arc header index");
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/zfs/ddt.c b/sys/contrib/openzfs/module/zfs/ddt.c
index fe5a188f4da1..f1415353f4b2 100644
--- a/sys/contrib/openzfs/module/zfs/ddt.c
+++ b/sys/contrib/openzfs/module/zfs/ddt.c
@@ -1180,7 +1180,5 @@ ddt_walk(spa_t *spa, ddt_bookmark_t *ddb, ddt_entry_t *dde)
return (SET_ERROR(ENOENT));
}
-/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs_dedup, zfs_dedup_, prefetch, INT, ZMOD_RW,
"Enable prefetching dedup-ed blks");
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/zfs/dmu.c b/sys/contrib/openzfs/module/zfs/dmu.c
index d802ce557657..874ddc800870 100644
--- a/sys/contrib/openzfs/module/zfs/dmu.c
+++ b/sys/contrib/openzfs/module/zfs/dmu.c
@@ -2346,7 +2346,6 @@ EXPORT_SYMBOL(dmu_assign_arcbuf_by_dbuf);
EXPORT_SYMBOL(dmu_buf_hold);
EXPORT_SYMBOL(dmu_ot);
-/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs, zfs_, nopwrite_enabled, INT, ZMOD_RW,
"Enable NOP writes");
@@ -2356,6 +2355,6 @@ ZFS_MODULE_PARAM(zfs, zfs_, per_txg_dirty_frees_percent, ULONG, ZMOD_RW,
ZFS_MODULE_PARAM(zfs, zfs_, dmu_offset_next_sync, INT, ZMOD_RW,
"Enable forcing txg sync to find holes");
+/* CSTYLED */
ZFS_MODULE_PARAM(zfs, , dmu_prefetch_max, INT, ZMOD_RW,
"Limit one prefetch call to this size");
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/zfs/dmu_recv.c b/sys/contrib/openzfs/module/zfs/dmu_recv.c
index f132219c9e1d..b34c1bc6934e 100644
--- a/sys/contrib/openzfs/module/zfs/dmu_recv.c
+++ b/sys/contrib/openzfs/module/zfs/dmu_recv.c
@@ -597,7 +597,15 @@ dmu_recv_begin_check(void *arg, dmu_tx_t *tx)
if (!(flags & DRR_FLAG_SPILL_BLOCK))
return (SET_ERROR(ZFS_ERR_SPILL_BLOCK_FLAG_MISSING));
} else {
- dsflags |= DS_HOLD_FLAG_DECRYPT;
+ /*
+ * We support unencrypted datasets below encrypted ones now,
+ * so add the DS_HOLD_FLAG_DECRYPT flag only if we are dealing
+ * with a dataset we may encrypt.
+ */
+ if (drba->drba_dcp != NULL &&
+ drba->drba_dcp->cp_crypt != ZIO_CRYPT_OFF) {
+ dsflags |= DS_HOLD_FLAG_DECRYPT;
+ }
}
error = dsl_dataset_hold_flags(dp, tofs, dsflags, FTAG, &ds);
@@ -1820,7 +1828,6 @@ receive_object(struct receive_writer_arg *rwa, struct drr_object *drro,
return (0);
}
-/* ARGSUSED */
noinline static int
receive_freeobjects(struct receive_writer_arg *rwa,
struct drr_freeobjects *drrfo)
@@ -2222,7 +2229,6 @@ receive_spill(struct receive_writer_arg *rwa, struct drr_spill *drrs,
return (0);
}
-/* ARGSUSED */
noinline static int
receive_free(struct receive_writer_arg *rwa, struct drr_free *drrf)
{
@@ -2297,7 +2303,6 @@ receive_object_range(struct receive_writer_arg *rwa,
* Until we have the ability to redact large ranges of data efficiently, we
* process these records as frees.
*/
-/* ARGSUSED */
noinline static int
receive_redact(struct receive_writer_arg *rwa, struct drr_redact *drrr)
{
@@ -2446,7 +2451,6 @@ receive_read_payload_and_next_header(dmu_recv_cookie_t *drc, int len, void *buf)
* numbers in the ignore list. In practice, we receive up to 32 object records
* before receiving write records, so the list can have up to 32 nodes in it.
*/
-/* ARGSUSED */
static void
receive_read_prefetch(dmu_recv_cookie_t *drc, uint64_t object, uint64_t offset,
uint64_t length)
@@ -2798,7 +2802,7 @@ receive_process_record(struct receive_writer_arg *rwa,
* dmu_recv_stream's worker thread; pull records off the queue, and then call
* receive_process_record When we're done, signal the main thread and exit.
*/
-static void
+static _Noreturn void
receive_writer_thread(void *arg)
{
struct receive_writer_arg *rwa = arg;
@@ -3389,7 +3393,6 @@ dmu_objset_is_receiving(objset_t *os)
os->os_dsl_dataset->ds_owner == dmu_recv_tag);
}
-/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs_recv, zfs_recv_, queue_length, INT, ZMOD_RW,
"Maximum receive queue length");
@@ -3398,4 +3401,3 @@ ZFS_MODULE_PARAM(zfs_recv, zfs_recv_, queue_ff, INT, ZMOD_RW,
ZFS_MODULE_PARAM(zfs_recv, zfs_recv_, write_batch_size, INT, ZMOD_RW,
"Maximum amount of writes to batch into one transaction");
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/zfs/dmu_redact.c b/sys/contrib/openzfs/module/zfs/dmu_redact.c
index 46f4982894b5..ab2b5f23e3f7 100644
--- a/sys/contrib/openzfs/module/zfs/dmu_redact.c
+++ b/sys/contrib/openzfs/module/zfs/dmu_redact.c
@@ -351,7 +351,7 @@ redact_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
return (0);
}
-static void
+static _Noreturn void
redact_traverse_thread(void *arg)
{
struct redact_thread_arg *rt_arg = arg;
@@ -837,7 +837,7 @@ struct redact_merge_thread_arg {
int error_code;
};
-static void
+static _Noreturn void
redact_merge_thread(void *arg)
{
struct redact_merge_thread_arg *rmta = arg;
diff --git a/sys/contrib/openzfs/module/zfs/dmu_send.c b/sys/contrib/openzfs/module/zfs/dmu_send.c
index fbb1947a5dd3..021dffefa141 100644
--- a/sys/contrib/openzfs/module/zfs/dmu_send.c
+++ b/sys/contrib/openzfs/module/zfs/dmu_send.c
@@ -763,6 +763,8 @@ dump_dnode(dmu_send_cookie_t *dscp, const blkptr_t *bp, uint64_t object,
* to send it.
*/
if (bonuslen != 0) {
+ if (drro->drr_bonuslen > DN_MAX_BONUS_LEN(dnp))
+ return (SET_ERROR(EINVAL));
drro->drr_raw_bonuslen = DN_MAX_BONUS_LEN(dnp);
bonuslen = drro->drr_raw_bonuslen;
}
@@ -1232,7 +1234,7 @@ redact_list_cb(redact_block_phys_t *rb, void *arg)
* error code of the thread in case something goes wrong, and pushes the End of
* Stream record when the traverse_dataset call has finished.
*/
-static void
+static _Noreturn void
send_traverse_thread(void *arg)
{
struct send_thread_arg *st_arg = arg;
@@ -1322,7 +1324,7 @@ get_next_range(bqueue_t *bq, struct send_range *prev)
return (next);
}
-static void
+static _Noreturn void
redact_list_thread(void *arg)
{
struct redact_list_thread_arg *rlt_arg = arg;
@@ -1517,7 +1519,7 @@ find_next_range(struct send_range **ranges, bqueue_t **qs, uint64_t *out_mask)
* data from the redact_list_thread and use that to determine which blocks
* should be redacted.
*/
-static void
+static _Noreturn void
send_merge_thread(void *arg)
{
struct send_merge_thread_arg *smt_arg = arg;
@@ -1742,7 +1744,7 @@ enqueue_range(struct send_reader_thread_arg *srta, bqueue_t *q, dnode_t *dn,
* some indirect blocks can be discarded because they're not holes. Second,
* it issues prefetches for the data we need to send.
*/
-static void
+static _Noreturn void
send_reader_thread(void *arg)
{
struct send_reader_thread_arg *srta = arg;
@@ -3084,7 +3086,6 @@ out:
return (err);
}
-/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs_send, zfs_send_, corrupt_data, INT, ZMOD_RW,
"Allow sending corrupt data");
@@ -3105,4 +3106,3 @@ ZFS_MODULE_PARAM(zfs_send, zfs_send_, no_prefetch_queue_ff, INT, ZMOD_RW,
ZFS_MODULE_PARAM(zfs_send, zfs_, override_estimate_recordsize, INT, ZMOD_RW,
"Override block size estimate with fixed size");
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/zfs/dmu_traverse.c b/sys/contrib/openzfs/module/zfs/dmu_traverse.c
index 3763c17de820..8afcd776a9eb 100644
--- a/sys/contrib/openzfs/module/zfs/dmu_traverse.c
+++ b/sys/contrib/openzfs/module/zfs/dmu_traverse.c
@@ -809,7 +809,6 @@ traverse_pool(spa_t *spa, uint64_t txg_start, int flags,
EXPORT_SYMBOL(traverse_dataset);
EXPORT_SYMBOL(traverse_pool);
-/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs, zfs_, pd_bytes_max, INT, ZMOD_RW,
"Max number of bytes to prefetch");
@@ -822,6 +821,6 @@ MODULE_PARM_DESC(ignore_hole_birth,
"Alias for send_holes_without_birth_time");
#endif
+/* CSTYLED */
ZFS_MODULE_PARAM(zfs, , send_holes_without_birth_time, INT, ZMOD_RW,
"Ignore hole_birth txg for zfs send");
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/zfs/dmu_tx.c b/sys/contrib/openzfs/module/zfs/dmu_tx.c
index b4735bb7ff54..fe9860066d31 100644
--- a/sys/contrib/openzfs/module/zfs/dmu_tx.c
+++ b/sys/contrib/openzfs/module/zfs/dmu_tx.c
@@ -219,7 +219,6 @@ dmu_tx_check_ioerr(zio_t *zio, dnode_t *dn, int level, uint64_t blkid)
return (err);
}
-/* ARGSUSED */
static void
dmu_tx_count_write(dmu_tx_hold_t *txh, uint64_t off, uint64_t len)
{
diff --git a/sys/contrib/openzfs/module/zfs/dmu_zfetch.c b/sys/contrib/openzfs/module/zfs/dmu_zfetch.c
index fdf0a1759716..a6facdc65bb4 100644
--- a/sys/contrib/openzfs/module/zfs/dmu_zfetch.c
+++ b/sys/contrib/openzfs/module/zfs/dmu_zfetch.c
@@ -531,7 +531,6 @@ dmu_zfetch(zfetch_t *zf, uint64_t blkid, uint64_t nblks, boolean_t fetch_data,
dmu_zfetch_run(zs, missed, have_lock);
}
-/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs_prefetch, zfs_prefetch_, disable, INT, ZMOD_RW,
"Disable all ZFS prefetching");
@@ -549,4 +548,3 @@ ZFS_MODULE_PARAM(zfs_prefetch, zfetch_, max_idistance, UINT, ZMOD_RW,
ZFS_MODULE_PARAM(zfs_prefetch, zfetch_, array_rd_sz, ULONG, ZMOD_RW,
"Number of bytes in a array_read");
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/zfs/dnode_sync.c b/sys/contrib/openzfs/module/zfs/dnode_sync.c
index f574130e5049..12ab4bea145f 100644
--- a/sys/contrib/openzfs/module/zfs/dnode_sync.c
+++ b/sys/contrib/openzfs/module/zfs/dnode_sync.c
@@ -854,6 +854,8 @@ dnode_sync(dnode_t *dn, dmu_tx_t *tx)
dnode_rele(dn, (void *)(uintptr_t)tx->tx_txg);
}
+ ASSERT3U(dnp->dn_bonuslen, <=, DN_MAX_BONUS_LEN(dnp));
+
/*
* Although we have dropped our reference to the dnode, it
* can't be evicted until its written, and we haven't yet
diff --git a/sys/contrib/openzfs/module/zfs/dsl_crypt.c b/sys/contrib/openzfs/module/zfs/dsl_crypt.c
index 1ea184de338c..6330a44b4c39 100644
--- a/sys/contrib/openzfs/module/zfs/dsl_crypt.c
+++ b/sys/contrib/openzfs/module/zfs/dsl_crypt.c
@@ -119,7 +119,6 @@ dsl_wrapping_key_create(uint8_t *wkeydata, zfs_keyformat_t keyformat,
/* allocate and initialize the underlying crypto key */
wkey->wk_key.ck_data = kmem_alloc(WRAPPING_KEY_LEN, KM_SLEEP);
- wkey->wk_key.ck_format = CRYPTO_KEY_RAW;
wkey->wk_key.ck_length = CRYPTO_BYTES2BITS(WRAPPING_KEY_LEN);
bcopy(wkeydata, wkey->wk_key.ck_data, WRAPPING_KEY_LEN);
diff --git a/sys/contrib/openzfs/module/zfs/dsl_dataset.c b/sys/contrib/openzfs/module/zfs/dsl_dataset.c
index 115f3df5d539..85b48fd12b63 100644
--- a/sys/contrib/openzfs/module/zfs/dsl_dataset.c
+++ b/sys/contrib/openzfs/module/zfs/dsl_dataset.c
@@ -90,8 +90,6 @@ static int zfs_allow_redacted_dataset_mount = 0;
#define DS_REF_MAX (1ULL << 62)
-extern inline dsl_dataset_phys_t *dsl_dataset_phys(dsl_dataset_t *ds);
-
static void dsl_dataset_set_remap_deadlist_object(dsl_dataset_t *ds,
uint64_t obj, dmu_tx_t *tx);
static void dsl_dataset_unset_remap_deadlist_object(dsl_dataset_t *ds,
@@ -2331,161 +2329,147 @@ get_clones_stat(dsl_dataset_t *ds, nvlist_t *nv)
nvlist_free(propval);
}
-/*
- * Returns a string that represents the receive resume stats token. It should
- * be freed with strfree().
- */
-char *
-get_receive_resume_stats_impl(dsl_dataset_t *ds)
+static char *
+get_receive_resume_token_impl(dsl_dataset_t *ds)
{
+ if (!dsl_dataset_has_resume_receive_state(ds))
+ return (NULL);
+
dsl_pool_t *dp = ds->ds_dir->dd_pool;
+ char *str;
+ void *packed;
+ uint8_t *compressed;
+ uint64_t val;
+ nvlist_t *token_nv = fnvlist_alloc();
+ size_t packed_size, compressed_size;
+
+ if (zap_lookup(dp->dp_meta_objset, ds->ds_object,
+ DS_FIELD_RESUME_FROMGUID, sizeof (val), 1, &val) == 0) {
+ fnvlist_add_uint64(token_nv, "fromguid", val);
+ }
+ if (zap_lookup(dp->dp_meta_objset, ds->ds_object,
+ DS_FIELD_RESUME_OBJECT, sizeof (val), 1, &val) == 0) {
+ fnvlist_add_uint64(token_nv, "object", val);
+ }
+ if (zap_lookup(dp->dp_meta_objset, ds->ds_object,
+ DS_FIELD_RESUME_OFFSET, sizeof (val), 1, &val) == 0) {
+ fnvlist_add_uint64(token_nv, "offset", val);
+ }
+ if (zap_lookup(dp->dp_meta_objset, ds->ds_object,
+ DS_FIELD_RESUME_BYTES, sizeof (val), 1, &val) == 0) {
+ fnvlist_add_uint64(token_nv, "bytes", val);
+ }
+ if (zap_lookup(dp->dp_meta_objset, ds->ds_object,
+ DS_FIELD_RESUME_TOGUID, sizeof (val), 1, &val) == 0) {
+ fnvlist_add_uint64(token_nv, "toguid", val);
+ }
+ char buf[MAXNAMELEN];
+ if (zap_lookup(dp->dp_meta_objset, ds->ds_object,
+ DS_FIELD_RESUME_TONAME, 1, sizeof (buf), buf) == 0) {
+ fnvlist_add_string(token_nv, "toname", buf);
+ }
+ if (zap_contains(dp->dp_meta_objset, ds->ds_object,
+ DS_FIELD_RESUME_LARGEBLOCK) == 0) {
+ fnvlist_add_boolean(token_nv, "largeblockok");
+ }
+ if (zap_contains(dp->dp_meta_objset, ds->ds_object,
+ DS_FIELD_RESUME_EMBEDOK) == 0) {
+ fnvlist_add_boolean(token_nv, "embedok");
+ }
+ if (zap_contains(dp->dp_meta_objset, ds->ds_object,
+ DS_FIELD_RESUME_COMPRESSOK) == 0) {
+ fnvlist_add_boolean(token_nv, "compressok");
+ }
+ if (zap_contains(dp->dp_meta_objset, ds->ds_object,
+ DS_FIELD_RESUME_RAWOK) == 0) {
+ fnvlist_add_boolean(token_nv, "rawok");
+ }
+ if (dsl_dataset_feature_is_active(ds,
+ SPA_FEATURE_REDACTED_DATASETS)) {
+ uint64_t num_redact_snaps = 0;
+ uint64_t *redact_snaps = NULL;
+ VERIFY3B(dsl_dataset_get_uint64_array_feature(ds,
+ SPA_FEATURE_REDACTED_DATASETS, &num_redact_snaps,
+ &redact_snaps), ==, B_TRUE);
+ fnvlist_add_uint64_array(token_nv, "redact_snaps",
+ redact_snaps, num_redact_snaps);
+ }
+ if (zap_contains(dp->dp_meta_objset, ds->ds_object,
+ DS_FIELD_RESUME_REDACT_BOOKMARK_SNAPS) == 0) {
+ uint64_t num_redact_snaps = 0, int_size = 0;
+ uint64_t *redact_snaps = NULL;
+ VERIFY0(zap_length(dp->dp_meta_objset, ds->ds_object,
+ DS_FIELD_RESUME_REDACT_BOOKMARK_SNAPS, &int_size,
+ &num_redact_snaps));
+ ASSERT3U(int_size, ==, sizeof (uint64_t));
- if (dsl_dataset_has_resume_receive_state(ds)) {
- char *str;
- void *packed;
- uint8_t *compressed;
- uint64_t val;
- nvlist_t *token_nv = fnvlist_alloc();
- size_t packed_size, compressed_size;
-
- if (zap_lookup(dp->dp_meta_objset, ds->ds_object,
- DS_FIELD_RESUME_FROMGUID, sizeof (val), 1, &val) == 0) {
- fnvlist_add_uint64(token_nv, "fromguid", val);
- }
- if (zap_lookup(dp->dp_meta_objset, ds->ds_object,
- DS_FIELD_RESUME_OBJECT, sizeof (val), 1, &val) == 0) {
- fnvlist_add_uint64(token_nv, "object", val);
- }
- if (zap_lookup(dp->dp_meta_objset, ds->ds_object,
- DS_FIELD_RESUME_OFFSET, sizeof (val), 1, &val) == 0) {
- fnvlist_add_uint64(token_nv, "offset", val);
- }
- if (zap_lookup(dp->dp_meta_objset, ds->ds_object,
- DS_FIELD_RESUME_BYTES, sizeof (val), 1, &val) == 0) {
- fnvlist_add_uint64(token_nv, "bytes", val);
- }
- if (zap_lookup(dp->dp_meta_objset, ds->ds_object,
- DS_FIELD_RESUME_TOGUID, sizeof (val), 1, &val) == 0) {
- fnvlist_add_uint64(token_nv, "toguid", val);
- }
- char buf[MAXNAMELEN];
- if (zap_lookup(dp->dp_meta_objset, ds->ds_object,
- DS_FIELD_RESUME_TONAME, 1, sizeof (buf), buf) == 0) {
- fnvlist_add_string(token_nv, "toname", buf);
- }
- if (zap_contains(dp->dp_meta_objset, ds->ds_object,
- DS_FIELD_RESUME_LARGEBLOCK) == 0) {
- fnvlist_add_boolean(token_nv, "largeblockok");
- }
- if (zap_contains(dp->dp_meta_objset, ds->ds_object,
- DS_FIELD_RESUME_EMBEDOK) == 0) {
- fnvlist_add_boolean(token_nv, "embedok");
- }
- if (zap_contains(dp->dp_meta_objset, ds->ds_object,
- DS_FIELD_RESUME_COMPRESSOK) == 0) {
- fnvlist_add_boolean(token_nv, "compressok");
- }
- if (zap_contains(dp->dp_meta_objset, ds->ds_object,
- DS_FIELD_RESUME_RAWOK) == 0) {
- fnvlist_add_boolean(token_nv, "rawok");
- }
- if (dsl_dataset_feature_is_active(ds,
- SPA_FEATURE_REDACTED_DATASETS)) {
- uint64_t num_redact_snaps;
- uint64_t *redact_snaps;
- VERIFY(dsl_dataset_get_uint64_array_feature(ds,
- SPA_FEATURE_REDACTED_DATASETS, &num_redact_snaps,
- &redact_snaps));
- fnvlist_add_uint64_array(token_nv, "redact_snaps",
- redact_snaps, num_redact_snaps);
- }
- if (zap_contains(dp->dp_meta_objset, ds->ds_object,
- DS_FIELD_RESUME_REDACT_BOOKMARK_SNAPS) == 0) {
- uint64_t num_redact_snaps, int_size;
- uint64_t *redact_snaps;
- VERIFY0(zap_length(dp->dp_meta_objset, ds->ds_object,
- DS_FIELD_RESUME_REDACT_BOOKMARK_SNAPS, &int_size,
- &num_redact_snaps));
- ASSERT3U(int_size, ==, sizeof (uint64_t));
-
- redact_snaps = kmem_alloc(int_size * num_redact_snaps,
- KM_SLEEP);
- VERIFY0(zap_lookup(dp->dp_meta_objset, ds->ds_object,
- DS_FIELD_RESUME_REDACT_BOOKMARK_SNAPS, int_size,
- num_redact_snaps, redact_snaps));
- fnvlist_add_uint64_array(token_nv, "book_redact_snaps",
- redact_snaps, num_redact_snaps);
- kmem_free(redact_snaps, int_size * num_redact_snaps);
- }
- packed = fnvlist_pack(token_nv, &packed_size);
- fnvlist_free(token_nv);
- compressed = kmem_alloc(packed_size, KM_SLEEP);
-
- compressed_size = gzip_compress(packed, compressed,
- packed_size, packed_size, 6);
-
- zio_cksum_t cksum;
- fletcher_4_native_varsize(compressed, compressed_size, &cksum);
-
- size_t alloc_size = compressed_size * 2 + 1;
- str = kmem_alloc(alloc_size, KM_SLEEP);
- for (int i = 0; i < compressed_size; i++) {
- size_t offset = i * 2;
- (void) snprintf(str + offset, alloc_size - offset,
- "%02x", compressed[i]);
- }
- str[compressed_size * 2] = '\0';
- char *propval = kmem_asprintf("%u-%llx-%llx-%s",
- ZFS_SEND_RESUME_TOKEN_VERSION,
- (longlong_t)cksum.zc_word[0],
- (longlong_t)packed_size, str);
- kmem_free(packed, packed_size);
- kmem_free(str, alloc_size);
- kmem_free(compressed, packed_size);
- return (propval);
- }
- return (kmem_strdup(""));
+ redact_snaps = kmem_alloc(int_size * num_redact_snaps,
+ KM_SLEEP);
+ VERIFY0(zap_lookup(dp->dp_meta_objset, ds->ds_object,
+ DS_FIELD_RESUME_REDACT_BOOKMARK_SNAPS, int_size,
+ num_redact_snaps, redact_snaps));
+ fnvlist_add_uint64_array(token_nv, "book_redact_snaps",
+ redact_snaps, num_redact_snaps);
+ kmem_free(redact_snaps, int_size * num_redact_snaps);
+ }
+ packed = fnvlist_pack(token_nv, &packed_size);
+ fnvlist_free(token_nv);
+ compressed = kmem_alloc(packed_size, KM_SLEEP);
+
+ compressed_size = gzip_compress(packed, compressed,
+ packed_size, packed_size, 6);
+
+ zio_cksum_t cksum;
+ fletcher_4_native_varsize(compressed, compressed_size, &cksum);
+
+ size_t alloc_size = compressed_size * 2 + 1;
+ str = kmem_alloc(alloc_size, KM_SLEEP);
+ for (int i = 0; i < compressed_size; i++) {
+ size_t offset = i * 2;
+ (void) snprintf(str + offset, alloc_size - offset,
+ "%02x", compressed[i]);
+ }
+ str[compressed_size * 2] = '\0';
+ char *propval = kmem_asprintf("%u-%llx-%llx-%s",
+ ZFS_SEND_RESUME_TOKEN_VERSION,
+ (longlong_t)cksum.zc_word[0],
+ (longlong_t)packed_size, str);
+ kmem_free(packed, packed_size);
+ kmem_free(str, alloc_size);
+ kmem_free(compressed, packed_size);
+ return (propval);
}
/*
- * Returns a string that represents the receive resume stats token of the
- * dataset's child. It should be freed with strfree().
+ * Returns a string that represents the receive resume state token. It should
+ * be freed with strfree(). NULL is returned if no resume state is present.
*/
char *
-get_child_receive_stats(dsl_dataset_t *ds)
+get_receive_resume_token(dsl_dataset_t *ds)
{
- char recvname[ZFS_MAX_DATASET_NAME_LEN + 6];
+ /*
+ * A failed "newfs" (e.g. full) resumable receive leaves
+ * the stats set on this dataset. Check here for the prop.
+ */
+ char *token = get_receive_resume_token_impl(ds);
+ if (token != NULL)
+ return (token);
+ /*
+ * A failed incremental resumable receive leaves the
+ * stats set on our child named "%recv". Check the child
+ * for the prop.
+ */
+ /* 6 extra bytes for /%recv */
+ char name[ZFS_MAX_DATASET_NAME_LEN + 6];
dsl_dataset_t *recv_ds;
- dsl_dataset_name(ds, recvname);
- if (strlcat(recvname, "/", sizeof (recvname)) <
- sizeof (recvname) &&
- strlcat(recvname, recv_clone_name, sizeof (recvname)) <
- sizeof (recvname) &&
- dsl_dataset_hold(ds->ds_dir->dd_pool, recvname, FTAG,
- &recv_ds) == 0) {
- char *propval = get_receive_resume_stats_impl(recv_ds);
+ dsl_dataset_name(ds, name);
+ if (strlcat(name, "/", sizeof (name)) < sizeof (name) &&
+ strlcat(name, recv_clone_name, sizeof (name)) < sizeof (name) &&
+ dsl_dataset_hold(ds->ds_dir->dd_pool, name, FTAG, &recv_ds) == 0) {
+ token = get_receive_resume_token_impl(recv_ds);
dsl_dataset_rele(recv_ds, FTAG);
- return (propval);
}
- return (kmem_strdup(""));
-}
-
-static void
-get_receive_resume_stats(dsl_dataset_t *ds, nvlist_t *nv)
-{
- char *propval = get_receive_resume_stats_impl(ds);
- if (strcmp(propval, "") != 0) {
- dsl_prop_nvlist_add_string(nv,
- ZFS_PROP_RECEIVE_RESUME_TOKEN, propval);
- } else {
- char *childval = get_child_receive_stats(ds);
- if (strcmp(childval, "") != 0) {
- dsl_prop_nvlist_add_string(nv,
- ZFS_PROP_RECEIVE_RESUME_TOKEN, childval);
- }
- kmem_strfree(childval);
- }
- kmem_strfree(propval);
+ return (token);
}
uint64_t
@@ -2761,7 +2745,7 @@ dsl_get_mountpoint(dsl_dataset_t *ds, const char *dsname, char *value,
void
dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv)
{
- dsl_pool_t *dp = ds->ds_dir->dd_pool;
+ dsl_pool_t *dp __maybe_unused = ds->ds_dir->dd_pool;
ASSERT(dsl_pool_config_held(dp));
@@ -2823,28 +2807,11 @@ dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv)
}
if (!dsl_dataset_is_snapshot(ds)) {
- /*
- * A failed "newfs" (e.g. full) resumable receive leaves
- * the stats set on this dataset. Check here for the prop.
- */
- get_receive_resume_stats(ds, nv);
-
- /*
- * A failed incremental resumable receive leaves the
- * stats set on our child named "%recv". Check the child
- * for the prop.
- */
- /* 6 extra bytes for /%recv */
- char recvname[ZFS_MAX_DATASET_NAME_LEN + 6];
- dsl_dataset_t *recv_ds;
- dsl_dataset_name(ds, recvname);
- if (strlcat(recvname, "/", sizeof (recvname)) <
- sizeof (recvname) &&
- strlcat(recvname, recv_clone_name, sizeof (recvname)) <
- sizeof (recvname) &&
- dsl_dataset_hold(dp, recvname, FTAG, &recv_ds) == 0) {
- get_receive_resume_stats(recv_ds, nv);
- dsl_dataset_rele(recv_ds, FTAG);
+ char *token = get_receive_resume_token(ds);
+ if (token != NULL) {
+ dsl_prop_nvlist_add_string(nv,
+ ZFS_PROP_RECEIVE_RESUME_TOKEN, token);
+ kmem_strfree(token);
}
}
}
@@ -4957,7 +4924,6 @@ dsl_dataset_activate_redaction(dsl_dataset_t *ds, uint64_t *redact_snaps,
ds->ds_feature[SPA_FEATURE_REDACTED_DATASETS] = ftuaa;
}
-/* BEGIN CSTYLED */
#if defined(_LP64)
#define RECORDSIZE_PERM ZMOD_RW
#else
@@ -4969,7 +4935,6 @@ ZFS_MODULE_PARAM(zfs, zfs_, max_recordsize, INT, RECORDSIZE_PERM,
ZFS_MODULE_PARAM(zfs, zfs_, allow_redacted_dataset_mount, INT, ZMOD_RW,
"Allow mounting of redacted datasets");
-/* END CSTYLED */
EXPORT_SYMBOL(dsl_dataset_hold);
EXPORT_SYMBOL(dsl_dataset_hold_flags);
diff --git a/sys/contrib/openzfs/module/zfs/dsl_deadlist.c b/sys/contrib/openzfs/module/zfs/dsl_deadlist.c
index a77e381520db..e620510be6b1 100644
--- a/sys/contrib/openzfs/module/zfs/dsl_deadlist.c
+++ b/sys/contrib/openzfs/module/zfs/dsl_deadlist.c
@@ -1034,10 +1034,8 @@ dsl_process_sub_livelist(bpobj_t *bpobj, bplist_t *to_free, zthr_t *t,
return (err);
}
-/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs_livelist, zfs_livelist_, max_entries, ULONG, ZMOD_RW,
"Size to start the next sub-livelist in a livelist");
ZFS_MODULE_PARAM(zfs_livelist, zfs_livelist_, min_percent_shared, INT, ZMOD_RW,
"Threshold at which livelist is disabled");
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/zfs/dsl_dir.c b/sys/contrib/openzfs/module/zfs/dsl_dir.c
index bd5e0c2f627c..aca32ff9bbb9 100644
--- a/sys/contrib/openzfs/module/zfs/dsl_dir.c
+++ b/sys/contrib/openzfs/module/zfs/dsl_dir.c
@@ -121,8 +121,6 @@
* dsl_dir_init_fs_ss_count().
*/
-extern inline dsl_dir_phys_t *dsl_dir_phys(dsl_dir_t *dd);
-
static uint64_t dsl_dir_space_towrite(dsl_dir_t *dd);
typedef struct ddulrt_arg {
@@ -1322,7 +1320,6 @@ top_of_function:
* we're very close to full, this will allow a steady trickle of
* removes to get through.
*/
- uint64_t deferred = 0;
if (dd->dd_parent == NULL) {
uint64_t avail = dsl_pool_unreserved_space(dd->dd_pool,
(netfree) ?
@@ -1337,13 +1334,21 @@ top_of_function:
/*
* If they are requesting more space, and our current estimate
* is over quota, they get to try again unless the actual
- * on-disk is over quota and there are no pending changes (which
- * may free up space for us).
+ * on-disk is over quota and there are no pending changes
+ * or deferred frees (which may free up space for us).
*/
if (used_on_disk + est_inflight >= quota) {
- if (est_inflight > 0 || used_on_disk < quota ||
- (retval == ENOSPC && used_on_disk < quota + deferred))
- retval = ERESTART;
+ if (est_inflight > 0 || used_on_disk < quota) {
+ retval = SET_ERROR(ERESTART);
+ } else {
+ ASSERT3U(used_on_disk, >=, quota);
+
+ if (retval == ENOSPC && (used_on_disk - quota) <
+ dsl_pool_deferred_space(dd->dd_pool)) {
+ retval = SET_ERROR(ERESTART);
+ }
+ }
+
dprintf_dd(dd, "failing: used=%lluK inflight = %lluK "
"quota=%lluK tr=%lluK err=%d\n",
(u_longlong_t)used_on_disk>>10,
@@ -1351,7 +1356,7 @@ top_of_function:
(u_longlong_t)quota>>10, (u_longlong_t)asize>>10, retval);
mutex_exit(&dd->dd_lock);
DMU_TX_STAT_BUMP(dmu_tx_quota);
- return (SET_ERROR(retval));
+ return (retval);
}
/* We need to up our estimated delta before dropping dd_lock */
diff --git a/sys/contrib/openzfs/module/zfs/dsl_pool.c b/sys/contrib/openzfs/module/zfs/dsl_pool.c
index ef7e9d2d248a..c8766090558d 100644
--- a/sys/contrib/openzfs/module/zfs/dsl_pool.c
+++ b/sys/contrib/openzfs/module/zfs/dsl_pool.c
@@ -950,6 +950,12 @@ dsl_pool_unreserved_space(dsl_pool_t *dp, zfs_space_check_t slop_policy)
return (quota);
}
+uint64_t
+dsl_pool_deferred_space(dsl_pool_t *dp)
+{
+ return (metaslab_class_get_deferred(spa_normal_class(dp->dp_spa)));
+}
+
boolean_t
dsl_pool_need_dirty_delay(dsl_pool_t *dp)
{
@@ -1010,7 +1016,6 @@ dsl_pool_undirty_space(dsl_pool_t *dp, int64_t space, uint64_t txg)
mutex_exit(&dp->dp_lock);
}
-/* ARGSUSED */
static int
upgrade_clones_cb(dsl_pool_t *dp, dsl_dataset_t *hds, void *arg)
{
@@ -1101,7 +1106,6 @@ dsl_pool_upgrade_clones(dsl_pool_t *dp, dmu_tx_t *tx)
tx, DS_FIND_CHILDREN | DS_FIND_SERIALIZE));
}
-/* ARGSUSED */
static int
upgrade_dir_clones_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg)
{
@@ -1447,7 +1451,6 @@ dsl_pool_config_held_writer(dsl_pool_t *dp)
EXPORT_SYMBOL(dsl_pool_config_enter);
EXPORT_SYMBOL(dsl_pool_config_exit);
-/* BEGIN CSTYLED */
/* zfs_dirty_data_max_percent only applied at module load in arc_init(). */
ZFS_MODULE_PARAM(zfs, zfs_, dirty_data_max_percent, INT, ZMOD_RD,
"Max percent of RAM allowed to be dirty");
@@ -1486,4 +1489,3 @@ ZFS_MODULE_PARAM(zfs_zil, zfs_zil_, clean_taskq_minalloc, INT, ZMOD_RW,
ZFS_MODULE_PARAM(zfs_zil, zfs_zil_, clean_taskq_maxalloc, INT, ZMOD_RW,
"Max number of taskq entries that are cached");
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/zfs/dsl_prop.c b/sys/contrib/openzfs/module/zfs/dsl_prop.c
index 0089edf8683a..cfdafd2f4436 100644
--- a/sys/contrib/openzfs/module/zfs/dsl_prop.c
+++ b/sys/contrib/openzfs/module/zfs/dsl_prop.c
@@ -749,7 +749,7 @@ dsl_prop_set_sync_impl(dsl_dataset_t *ds, const char *propname,
ASSERT(err == 0 || err == ENOENT);
err = zap_remove(mos, zapobj, inheritstr, tx);
ASSERT(err == 0 || err == ENOENT);
- fallthrough;
+ zfs_fallthrough;
case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED):
/*
* remove propname$recvd
diff --git a/sys/contrib/openzfs/module/zfs/dsl_scan.c b/sys/contrib/openzfs/module/zfs/dsl_scan.c
index 677d320eddba..c6a5807c92f5 100644
--- a/sys/contrib/openzfs/module/zfs/dsl_scan.c
+++ b/sys/contrib/openzfs/module/zfs/dsl_scan.c
@@ -1827,6 +1827,19 @@ dsl_scan_recurse(dsl_scan_t *scn, dsl_dataset_t *ds, dmu_objset_type_t ostype,
ASSERT(!BP_IS_REDACTED(bp));
+ /*
+ * There is an unlikely case of encountering dnodes with contradicting
+ * dn_bonuslen and DNODE_FLAG_SPILL_BLKPTR flag before in files created
+ * or modified before commit 4254acb was merged. As it is not possible
+ * to know which of the two is correct, report an error.
+ */
+ if (dnp != NULL &&
+ dnp->dn_bonuslen > DN_MAX_BONUS_LEN(dnp)) {
+ scn->scn_phys.scn_errors++;
+ spa_log_error(dp->dp_spa, zb);
+ return (SET_ERROR(EINVAL));
+ }
+
if (BP_GET_LEVEL(bp) > 0) {
arc_flags_t flags = ARC_FLAG_WAIT;
int i;
@@ -4377,7 +4390,6 @@ dsl_scan_assess_vdev(dsl_pool_t *dp, vdev_t *vd)
spa_async_request(dp->dp_spa, SPA_ASYNC_RESILVER);
}
-/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs, zfs_, scan_vdev_limit, ULONG, ZMOD_RW,
"Max bytes in flight per leaf vdev for scrubs and resilvers");
@@ -4415,8 +4427,7 @@ ZFS_MODULE_PARAM(zfs, zfs_, scan_mem_lim_fact, INT, ZMOD_RW,
"Fraction of RAM for scan hard limit");
ZFS_MODULE_PARAM(zfs, zfs_, scan_issue_strategy, INT, ZMOD_RW,
- "IO issuing strategy during scrubbing. "
- "0 = default, 1 = LBA, 2 = size");
+ "IO issuing strategy during scrubbing. 0 = default, 1 = LBA, 2 = size");
ZFS_MODULE_PARAM(zfs, zfs_, scan_legacy, INT, ZMOD_RW,
"Scrub using legacy non-sequential method");
@@ -4438,4 +4449,3 @@ ZFS_MODULE_PARAM(zfs, zfs_, scan_fill_weight, INT, ZMOD_RW,
ZFS_MODULE_PARAM(zfs, zfs_, resilver_disable_defer, INT, ZMOD_RW,
"Process all resilvers immediately");
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/zfs/edonr_zfs.c b/sys/contrib/openzfs/module/zfs/edonr_zfs.c
index aa00e1c9417e..7c62e0be07eb 100644
--- a/sys/contrib/openzfs/module/zfs/edonr_zfs.c
+++ b/sys/contrib/openzfs/module/zfs/edonr_zfs.c
@@ -45,7 +45,6 @@ edonr_incremental(void *buf, size_t size, void *arg)
/*
* Native zio_checksum interface for the Edon-R hash function.
*/
-/*ARGSUSED*/
void
abd_checksum_edonr_native(abd_t *abd, uint64_t size,
const void *ctx_template, zio_cksum_t *zcp)
@@ -89,7 +88,8 @@ abd_checksum_edonr_tmpl_init(const zio_cksum_salt_t *salt)
* size by double-hashing it (the new salt block will be composed of
* H(salt) || H(H(salt))).
*/
- CTASSERT(EDONR_BLOCK_SIZE == 2 * (EDONR_MODE / 8));
+ _Static_assert(EDONR_BLOCK_SIZE == 2 * (EDONR_MODE / 8),
+ "Edon-R block size mismatch");
EdonRHash(EDONR_MODE, salt->zcs_bytes, sizeof (salt->zcs_bytes) * 8,
salt_block);
EdonRHash(EDONR_MODE, salt_block, EDONR_MODE, salt_block +
diff --git a/sys/contrib/openzfs/module/zfs/hkdf.c b/sys/contrib/openzfs/module/zfs/hkdf.c
index 14265472df7d..2c91401d5b4f 100644
--- a/sys/contrib/openzfs/module/zfs/hkdf.c
+++ b/sys/contrib/openzfs/module/zfs/hkdf.c
@@ -36,7 +36,6 @@ hkdf_sha512_extract(uint8_t *salt, uint_t salt_len, uint8_t *key_material,
mech.cm_param_len = 0;
/* initialize the salt as a crypto key */
- key.ck_format = CRYPTO_KEY_RAW;
key.ck_length = CRYPTO_BYTES2BITS(salt_len);
key.ck_data = salt;
@@ -53,7 +52,7 @@ hkdf_sha512_extract(uint8_t *salt, uint_t salt_len, uint8_t *key_material,
output_cd.cd_raw.iov_base = (char *)out_buf;
output_cd.cd_raw.iov_len = output_cd.cd_length;
- ret = crypto_mac(&mech, &input_cd, &key, NULL, &output_cd, NULL);
+ ret = crypto_mac(&mech, &input_cd, &key, NULL, &output_cd);
if (ret != CRYPTO_SUCCESS)
return (SET_ERROR(EIO));
@@ -83,7 +82,6 @@ hkdf_sha512_expand(uint8_t *extract_key, uint8_t *info, uint_t info_len,
mech.cm_param_len = 0;
/* initialize the salt as a crypto key */
- key.ck_format = CRYPTO_KEY_RAW;
key.ck_length = CRYPTO_BYTES2BITS(SHA512_DIGEST_LENGTH);
key.ck_data = extract_key;
@@ -110,19 +108,19 @@ hkdf_sha512_expand(uint8_t *extract_key, uint8_t *info, uint_t info_len,
T_cd.cd_length = T_len;
T_cd.cd_raw.iov_len = T_cd.cd_length;
- ret = crypto_mac_init(&mech, &key, NULL, &ctx, NULL);
+ ret = crypto_mac_init(&mech, &key, NULL, &ctx);
if (ret != CRYPTO_SUCCESS)
return (SET_ERROR(EIO));
- ret = crypto_mac_update(ctx, &T_cd, NULL);
+ ret = crypto_mac_update(ctx, &T_cd);
if (ret != CRYPTO_SUCCESS)
return (SET_ERROR(EIO));
- ret = crypto_mac_update(ctx, &info_cd, NULL);
+ ret = crypto_mac_update(ctx, &info_cd);
if (ret != CRYPTO_SUCCESS)
return (SET_ERROR(EIO));
- ret = crypto_mac_update(ctx, &c_cd, NULL);
+ ret = crypto_mac_update(ctx, &c_cd);
if (ret != CRYPTO_SUCCESS)
return (SET_ERROR(EIO));
@@ -130,7 +128,7 @@ hkdf_sha512_expand(uint8_t *extract_key, uint8_t *info, uint_t info_len,
T_cd.cd_length = T_len;
T_cd.cd_raw.iov_len = T_cd.cd_length;
- ret = crypto_mac_final(ctx, &T_cd, NULL);
+ ret = crypto_mac_final(ctx, &T_cd);
if (ret != CRYPTO_SUCCESS)
return (SET_ERROR(EIO));
diff --git a/sys/contrib/openzfs/module/zfs/metaslab.c b/sys/contrib/openzfs/module/zfs/metaslab.c
index 145f79fae3df..bd17c1fe862a 100644
--- a/sys/contrib/openzfs/module/zfs/metaslab.c
+++ b/sys/contrib/openzfs/module/zfs/metaslab.c
@@ -6210,13 +6210,14 @@ ZFS_MODULE_PARAM(zfs_mg, zfs_mg_, fragmentation_threshold, INT, ZMOD_RW,
"for allocations unless all metaslab groups within the metaslab class "
"have also crossed this threshold");
-ZFS_MODULE_PARAM(zfs_metaslab, zfs_metaslab_, fragmentation_threshold, INT,
- ZMOD_RW, "Fragmentation for metaslab to allow allocation");
-
-ZFS_MODULE_PARAM(zfs_metaslab, metaslab_, fragmentation_factor_enabled, INT, ZMOD_RW,
+ZFS_MODULE_PARAM(zfs_metaslab, metaslab_, fragmentation_factor_enabled, INT,
+ ZMOD_RW,
"Use the fragmentation metric to prefer less fragmented metaslabs");
/* END CSTYLED */
+ZFS_MODULE_PARAM(zfs_metaslab, zfs_metaslab_, fragmentation_threshold, INT,
+ ZMOD_RW, "Fragmentation for metaslab to allow allocation");
+
ZFS_MODULE_PARAM(zfs_metaslab, metaslab_, lba_weighting_enabled, INT, ZMOD_RW,
"Prefer metaslabs with lower LBAs");
diff --git a/sys/contrib/openzfs/module/zfs/mmp.c b/sys/contrib/openzfs/module/zfs/mmp.c
index abdce3a32e6a..f8ba2169591b 100644
--- a/sys/contrib/openzfs/module/zfs/mmp.c
+++ b/sys/contrib/openzfs/module/zfs/mmp.c
@@ -187,7 +187,7 @@ uint_t zfs_multihost_import_intervals = MMP_DEFAULT_IMPORT_INTERVALS;
uint_t zfs_multihost_fail_intervals = MMP_DEFAULT_FAIL_INTERVALS;
static void *const mmp_tag = "mmp_write_uberblock";
-static void mmp_thread(void *arg);
+static _Noreturn void mmp_thread(void *arg);
void
mmp_init(spa_t *spa)
@@ -217,7 +217,7 @@ mmp_thread_enter(mmp_thread_t *mmp, callb_cpr_t *cpr)
mutex_enter(&mmp->mmp_thread_lock);
}
-static void
+static _Noreturn void
mmp_thread_exit(mmp_thread_t *mmp, kthread_t **mpp, callb_cpr_t *cpr)
{
ASSERT(*mpp != NULL);
@@ -537,7 +537,7 @@ mmp_write_uberblock(spa_t *spa)
zio_nowait(zio);
}
-static void
+static _Noreturn void
mmp_thread(void *arg)
{
spa_t *spa = (spa_t *)arg;
diff --git a/sys/contrib/openzfs/module/zfs/multilist.c b/sys/contrib/openzfs/module/zfs/multilist.c
index bad1674d29f1..fdc5f07c47ea 100644
--- a/sys/contrib/openzfs/module/zfs/multilist.c
+++ b/sys/contrib/openzfs/module/zfs/multilist.c
@@ -425,7 +425,5 @@ multilist_link_active(multilist_node_t *link)
return (list_link_active(link));
}
-/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs, zfs_, multilist_num_sublists, INT, ZMOD_RW,
"Number of sublists used in each multilist");
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/zfs/skein_zfs.c b/sys/contrib/openzfs/module/zfs/skein_zfs.c
index 11b9940e027e..55c7ac2a50ad 100644
--- a/sys/contrib/openzfs/module/zfs/skein_zfs.c
+++ b/sys/contrib/openzfs/module/zfs/skein_zfs.c
@@ -41,7 +41,6 @@ skein_incremental(void *buf, size_t size, void *arg)
* function requires the presence of a ctx_template that should be allocated
* using abd_checksum_skein_tmpl_init.
*/
-/*ARGSUSED*/
void
abd_checksum_skein_native(abd_t *abd, uint64_t size,
const void *ctx_template, zio_cksum_t *zcp)
diff --git a/sys/contrib/openzfs/module/zfs/spa.c b/sys/contrib/openzfs/module/zfs/spa.c
index 01af91b7b18f..744bcb434f06 100644
--- a/sys/contrib/openzfs/module/zfs/spa.c
+++ b/sys/contrib/openzfs/module/zfs/spa.c
@@ -1315,6 +1315,8 @@ spa_activate(spa_t *spa, spa_mode_t mode)
spa_error_entry_compare, sizeof (spa_error_entry_t),
offsetof(spa_error_entry_t, se_avl));
+ spa_activate_os(spa);
+
spa_keystore_init(&spa->spa_keystore);
/*
@@ -1451,6 +1453,9 @@ spa_deactivate(spa_t *spa)
thread_join(spa->spa_did);
spa->spa_did = 0;
}
+
+ spa_deactivate_os(spa);
+
}
/*
@@ -1597,25 +1602,33 @@ spa_unload(spa_t *spa)
spa_wake_waiters(spa);
/*
- * If the log space map feature is enabled and the pool is getting
- * exported (but not destroyed), we want to spend some time flushing
- * as many metaslabs as we can in an attempt to destroy log space
- * maps and save import time.
+ * If we have set the spa_final_txg, we have already performed the
+ * tasks below in spa_export_common(). We should not redo it here since
+ * we delay the final TXGs beyond what spa_final_txg is set at.
*/
- if (spa_should_flush_logs_on_unload(spa))
- spa_unload_log_sm_flush_all(spa);
+ if (spa->spa_final_txg == UINT64_MAX) {
+ /*
+ * If the log space map feature is enabled and the pool is
+ * getting exported (but not destroyed), we want to spend some
+ * time flushing as many metaslabs as we can in an attempt to
+ * destroy log space maps and save import time.
+ */
+ if (spa_should_flush_logs_on_unload(spa))
+ spa_unload_log_sm_flush_all(spa);
- /*
- * Stop async tasks.
- */
- spa_async_suspend(spa);
+ /*
+ * Stop async tasks.
+ */
+ spa_async_suspend(spa);
- if (spa->spa_root_vdev) {
- vdev_t *root_vdev = spa->spa_root_vdev;
- vdev_initialize_stop_all(root_vdev, VDEV_INITIALIZE_ACTIVE);
- vdev_trim_stop_all(root_vdev, VDEV_TRIM_ACTIVE);
- vdev_autotrim_stop_all(spa);
- vdev_rebuild_stop_all(spa);
+ if (spa->spa_root_vdev) {
+ vdev_t *root_vdev = spa->spa_root_vdev;
+ vdev_initialize_stop_all(root_vdev,
+ VDEV_INITIALIZE_ACTIVE);
+ vdev_trim_stop_all(root_vdev, VDEV_TRIM_ACTIVE);
+ vdev_autotrim_stop_all(spa);
+ vdev_rebuild_stop_all(spa);
+ }
}
/*
@@ -2251,6 +2264,7 @@ spa_claim_notify(zio_t *zio)
}
typedef struct spa_load_error {
+ boolean_t sle_verify_data;
uint64_t sle_meta_count;
uint64_t sle_data_count;
} spa_load_error_t;
@@ -2291,6 +2305,9 @@ static int
spa_load_verify_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
const zbookmark_phys_t *zb, const dnode_phys_t *dnp, void *arg)
{
+ zio_t *rio = arg;
+ spa_load_error_t *sle = rio->io_private;
+
(void) zilog, (void) dnp;
if (zb->zb_level == ZB_DNODE_LEVEL || BP_IS_HOLE(bp) ||
@@ -2303,12 +2320,12 @@ spa_load_verify_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
*/
if (!spa_load_verify_metadata)
return (0);
- if (!BP_IS_METADATA(bp) && !spa_load_verify_data)
+ if (!BP_IS_METADATA(bp) &&
+ (!spa_load_verify_data || !sle->sle_verify_data))
return (0);
uint64_t maxinflight_bytes =
arc_target_bytes() >> spa_load_verify_shift;
- zio_t *rio = arg;
size_t size = BP_GET_PSIZE(bp);
mutex_enter(&spa->spa_scrub_lock);
@@ -2346,7 +2363,8 @@ spa_load_verify(spa_t *spa)
zpool_get_load_policy(spa->spa_config, &policy);
- if (policy.zlp_rewind & ZPOOL_NEVER_REWIND)
+ if (policy.zlp_rewind & ZPOOL_NEVER_REWIND ||
+ policy.zlp_maxmeta == UINT64_MAX)
return (0);
dsl_pool_config_enter(spa->spa_dsl_pool, FTAG);
@@ -2357,6 +2375,13 @@ spa_load_verify(spa_t *spa)
if (error != 0)
return (error);
+ /*
+ * Verify data only if we are rewinding or error limit was set.
+ * Otherwise nothing except dbgmsg care about it to waste time.
+ */
+ sle.sle_verify_data = (policy.zlp_rewind & ZPOOL_REWIND_MASK) ||
+ (policy.zlp_maxdata < UINT64_MAX);
+
rio = zio_root(spa, NULL, &sle,
ZIO_FLAG_CANFAIL | ZIO_FLAG_SPECULATIVE);
@@ -2401,6 +2426,8 @@ spa_load_verify(spa_t *spa)
fnvlist_add_int64(spa->spa_load_info, ZPOOL_CONFIG_REWIND_TIME,
loss);
fnvlist_add_uint64(spa->spa_load_info,
+ ZPOOL_CONFIG_LOAD_META_ERRORS, sle.sle_meta_count);
+ fnvlist_add_uint64(spa->spa_load_info,
ZPOOL_CONFIG_LOAD_DATA_ERRORS, sle.sle_data_count);
} else {
spa->spa_load_max_txg = spa->spa_uberblock.ub_txg;
@@ -6009,6 +6036,8 @@ spa_create(const char *pool, nvlist_t *nvroot, nvlist_t *props,
spa->spa_minref = zfs_refcount_count(&spa->spa_refcount);
spa->spa_load_state = SPA_LOAD_NONE;
+ spa_import_os(spa);
+
mutex_exit(&spa_namespace_lock);
return (0);
@@ -6192,6 +6221,8 @@ spa_import(char *pool, nvlist_t *config, nvlist_t *props, uint64_t flags)
zvol_create_minors_recursive(pool);
+ spa_import_os(spa);
+
return (0);
}
@@ -6413,14 +6444,34 @@ spa_export_common(const char *pool, int new_state, nvlist_t **oldconfig,
if (new_state != POOL_STATE_UNINITIALIZED && !hardforce) {
spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
spa->spa_state = new_state;
+ vdev_config_dirty(spa->spa_root_vdev);
+ spa_config_exit(spa, SCL_ALL, FTAG);
+ }
+
+ /*
+ * If the log space map feature is enabled and the pool is
+ * getting exported (but not destroyed), we want to spend some
+ * time flushing as many metaslabs as we can in an attempt to
+ * destroy log space maps and save import time. This has to be
+ * done before we set the spa_final_txg, otherwise
+ * spa_sync() -> spa_flush_metaslabs() may dirty the final TXGs.
+ * spa_should_flush_logs_on_unload() should be called after
+ * spa_state has been set to the new_state.
+ */
+ if (spa_should_flush_logs_on_unload(spa))
+ spa_unload_log_sm_flush_all(spa);
+
+ if (new_state != POOL_STATE_UNINITIALIZED && !hardforce) {
+ spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
spa->spa_final_txg = spa_last_synced_txg(spa) +
TXG_DEFER_SIZE + 1;
- vdev_config_dirty(spa->spa_root_vdev);
spa_config_exit(spa, SCL_ALL, FTAG);
}
}
export_spa:
+ spa_export_os(spa);
+
if (new_state == POOL_STATE_DESTROYED)
spa_event_notify(spa, NULL, NULL, ESC_ZFS_POOL_DESTROY);
else if (new_state == POOL_STATE_EXPORTED)
@@ -8088,7 +8139,7 @@ spa_async_autoexpand(spa_t *spa, vdev_t *vd)
spa_event_notify(vd->vdev_spa, vd, NULL, ESC_ZFS_VDEV_AUTOEXPAND);
}
-static void
+static _Noreturn void
spa_async_thread(void *arg)
{
spa_t *spa = (spa_t *)arg;
@@ -9715,7 +9766,7 @@ spa_activity_in_progress(spa_t *spa, zpool_wait_activity_t activity,
case ZPOOL_WAIT_RESILVER:
if ((*in_progress = vdev_rebuild_active(spa->spa_root_vdev)))
break;
- fallthrough;
+ zfs_fallthrough;
case ZPOOL_WAIT_SCRUB:
{
boolean_t scanning, paused, is_scrub;
@@ -9922,6 +9973,7 @@ EXPORT_SYMBOL(spa_event_notify);
ZFS_MODULE_PARAM(zfs_spa, spa_, load_verify_shift, INT, ZMOD_RW,
"log2 fraction of arc that can be used by inflight I/Os when "
"verifying pool during import");
+/* END CSTYLED */
ZFS_MODULE_PARAM(zfs_spa, spa_, load_verify_metadata, INT, ZMOD_RW,
"Set to traverse metadata on pool import");
@@ -9938,23 +9990,29 @@ ZFS_MODULE_PARAM(zfs_zio, zio_, taskq_batch_pct, UINT, ZMOD_RD,
ZFS_MODULE_PARAM(zfs_zio, zio_, taskq_batch_tpq, UINT, ZMOD_RD,
"Number of threads per IO worker taskqueue");
+/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs, zfs_, max_missing_tvds, ULONG, ZMOD_RW,
"Allow importing pool with up to this number of missing top-level "
"vdevs (in read-only mode)");
+/* END CSTYLED */
-ZFS_MODULE_PARAM(zfs_livelist_condense, zfs_livelist_condense_, zthr_pause, INT, ZMOD_RW,
- "Set the livelist condense zthr to pause");
+ZFS_MODULE_PARAM(zfs_livelist_condense, zfs_livelist_condense_, zthr_pause, INT,
+ ZMOD_RW, "Set the livelist condense zthr to pause");
-ZFS_MODULE_PARAM(zfs_livelist_condense, zfs_livelist_condense_, sync_pause, INT, ZMOD_RW,
- "Set the livelist condense synctask to pause");
+ZFS_MODULE_PARAM(zfs_livelist_condense, zfs_livelist_condense_, sync_pause, INT,
+ ZMOD_RW, "Set the livelist condense synctask to pause");
-ZFS_MODULE_PARAM(zfs_livelist_condense, zfs_livelist_condense_, sync_cancel, INT, ZMOD_RW,
+/* BEGIN CSTYLED */
+ZFS_MODULE_PARAM(zfs_livelist_condense, zfs_livelist_condense_, sync_cancel,
+ INT, ZMOD_RW,
"Whether livelist condensing was canceled in the synctask");
-ZFS_MODULE_PARAM(zfs_livelist_condense, zfs_livelist_condense_, zthr_cancel, INT, ZMOD_RW,
+ZFS_MODULE_PARAM(zfs_livelist_condense, zfs_livelist_condense_, zthr_cancel,
+ INT, ZMOD_RW,
"Whether livelist condensing was canceled in the zthr function");
-ZFS_MODULE_PARAM(zfs_livelist_condense, zfs_livelist_condense_, new_alloc, INT, ZMOD_RW,
+ZFS_MODULE_PARAM(zfs_livelist_condense, zfs_livelist_condense_, new_alloc, INT,
+ ZMOD_RW,
"Whether extra ALLOC blkptrs were added to a livelist entry while it "
"was being condensed");
/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/zfs/spa_config.c b/sys/contrib/openzfs/module/zfs/spa_config.c
index b9c6ac042f1f..254031f31aff 100644
--- a/sys/contrib/openzfs/module/zfs/spa_config.c
+++ b/sys/contrib/openzfs/module/zfs/spa_config.c
@@ -613,7 +613,6 @@ EXPORT_SYMBOL(spa_config_set);
EXPORT_SYMBOL(spa_config_generate);
EXPORT_SYMBOL(spa_config_update);
-/* BEGIN CSTYLED */
#ifdef __linux__
/* string sysctls require a char array on FreeBSD */
ZFS_MODULE_PARAM(zfs_spa, spa_, config_path, STRING, ZMOD_RD,
@@ -622,4 +621,3 @@ ZFS_MODULE_PARAM(zfs_spa, spa_, config_path, STRING, ZMOD_RD,
ZFS_MODULE_PARAM(zfs, zfs_, autoimport_disable, INT, ZMOD_RW,
"Disable pool import at module load");
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/zfs/spa_history.c b/sys/contrib/openzfs/module/zfs/spa_history.c
index dae06e46c316..c0e0d8eeee68 100644
--- a/sys/contrib/openzfs/module/zfs/spa_history.c
+++ b/sys/contrib/openzfs/module/zfs/spa_history.c
@@ -248,7 +248,6 @@ spa_history_log_notify(spa_t *spa, nvlist_t *nvl)
/*
* Write out a history event.
*/
-/*ARGSUSED*/
static void
spa_history_log_sync(void *arg, dmu_tx_t *tx)
{
diff --git a/sys/contrib/openzfs/module/zfs/spa_log_spacemap.c b/sys/contrib/openzfs/module/zfs/spa_log_spacemap.c
index 341917a6d402..110a4eab99f9 100644
--- a/sys/contrib/openzfs/module/zfs/spa_log_spacemap.c
+++ b/sys/contrib/openzfs/module/zfs/spa_log_spacemap.c
@@ -1284,39 +1284,39 @@ spa_ld_log_spacemaps(spa_t *spa)
/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs, zfs_, unflushed_max_mem_amt, ULONG, ZMOD_RW,
- "Specific hard-limit in memory that ZFS allows to be used for "
- "unflushed changes");
+ "Specific hard-limit in memory that ZFS allows to be used for "
+ "unflushed changes");
ZFS_MODULE_PARAM(zfs, zfs_, unflushed_max_mem_ppm, ULONG, ZMOD_RW,
- "Percentage of the overall system memory that ZFS allows to be "
- "used for unflushed changes (value is calculated over 1000000 for "
- "finer granularity)");
+ "Percentage of the overall system memory that ZFS allows to be "
+ "used for unflushed changes (value is calculated over 1000000 for "
+ "finer granularity)");
ZFS_MODULE_PARAM(zfs, zfs_, unflushed_log_block_max, ULONG, ZMOD_RW,
- "Hard limit (upper-bound) in the size of the space map log "
- "in terms of blocks.");
+ "Hard limit (upper-bound) in the size of the space map log "
+ "in terms of blocks.");
ZFS_MODULE_PARAM(zfs, zfs_, unflushed_log_block_min, ULONG, ZMOD_RW,
- "Lower-bound limit for the maximum amount of blocks allowed in "
- "log spacemap (see zfs_unflushed_log_block_max)");
+ "Lower-bound limit for the maximum amount of blocks allowed in "
+ "log spacemap (see zfs_unflushed_log_block_max)");
ZFS_MODULE_PARAM(zfs, zfs_, unflushed_log_block_pct, ULONG, ZMOD_RW,
- "Tunable used to determine the number of blocks that can be used for "
- "the spacemap log, expressed as a percentage of the total number of "
- "metaslabs in the pool (e.g. 400 means the number of log blocks is "
- "capped at 4 times the number of metaslabs)");
+ "Tunable used to determine the number of blocks that can be used for "
+ "the spacemap log, expressed as a percentage of the total number of "
+ "metaslabs in the pool (e.g. 400 means the number of log blocks is "
+ "capped at 4 times the number of metaslabs)");
ZFS_MODULE_PARAM(zfs, zfs_, max_log_walking, ULONG, ZMOD_RW,
- "The number of past TXGs that the flushing algorithm of the log "
- "spacemap feature uses to estimate incoming log blocks");
+ "The number of past TXGs that the flushing algorithm of the log "
+ "spacemap feature uses to estimate incoming log blocks");
+
+ZFS_MODULE_PARAM(zfs, zfs_, keep_log_spacemaps_at_export, INT, ZMOD_RW,
+ "Prevent the log spacemaps from being flushed and destroyed "
+ "during pool export/destroy");
+/* END CSTYLED */
ZFS_MODULE_PARAM(zfs, zfs_, max_logsm_summary_length, ULONG, ZMOD_RW,
- "Maximum number of rows allowed in the summary of the spacemap log");
+ "Maximum number of rows allowed in the summary of the spacemap log");
ZFS_MODULE_PARAM(zfs, zfs_, min_metaslabs_to_flush, ULONG, ZMOD_RW,
- "Minimum number of metaslabs to flush per dirty TXG");
-
-ZFS_MODULE_PARAM(zfs, zfs_, keep_log_spacemaps_at_export, INT, ZMOD_RW,
- "Prevent the log spacemaps from being flushed and destroyed "
- "during pool export/destroy");
-/* END CSTYLED */
+ "Minimum number of metaslabs to flush per dirty TXG");
diff --git a/sys/contrib/openzfs/module/zfs/spa_stats.c b/sys/contrib/openzfs/module/zfs/spa_stats.c
index d89f79480ce3..2a75b37f020e 100644
--- a/sys/contrib/openzfs/module/zfs/spa_stats.c
+++ b/sys/contrib/openzfs/module/zfs/spa_stats.c
@@ -964,16 +964,14 @@ spa_stats_destroy(spa_t *spa)
spa_mmp_history_destroy(spa);
}
-/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs, zfs_, read_history, INT, ZMOD_RW,
- "Historical statistics for the last N reads");
+ "Historical statistics for the last N reads");
ZFS_MODULE_PARAM(zfs, zfs_, read_history_hits, INT, ZMOD_RW,
- "Include cache hits in read history");
+ "Include cache hits in read history");
ZFS_MODULE_PARAM(zfs_txg, zfs_txg_, history, INT, ZMOD_RW,
- "Historical statistics for the last N txgs");
+ "Historical statistics for the last N txgs");
ZFS_MODULE_PARAM(zfs_multihost, zfs_multihost_, history, INT, ZMOD_RW,
- "Historical statistics for last N multihost writes");
-/* END CSTYLED */
+ "Historical statistics for last N multihost writes");
diff --git a/sys/contrib/openzfs/module/zfs/txg.c b/sys/contrib/openzfs/module/zfs/txg.c
index c9eb84bbdb12..7908183caee7 100644
--- a/sys/contrib/openzfs/module/zfs/txg.c
+++ b/sys/contrib/openzfs/module/zfs/txg.c
@@ -108,8 +108,8 @@
* now transition to the syncing state.
*/
-static void txg_sync_thread(void *arg);
-static void txg_quiesce_thread(void *arg);
+static _Noreturn void txg_sync_thread(void *arg);
+static _Noreturn void txg_quiesce_thread(void *arg);
int zfs_txg_timeout = 5; /* max seconds worth of delta per txg */
@@ -514,7 +514,7 @@ txg_has_quiesced_to_sync(dsl_pool_t *dp)
return (tx->tx_quiesced_txg != 0);
}
-static void
+static _Noreturn void
txg_sync_thread(void *arg)
{
dsl_pool_t *dp = arg;
@@ -605,7 +605,7 @@ txg_sync_thread(void *arg)
}
}
-static void
+static _Noreturn void
txg_quiesce_thread(void *arg)
{
dsl_pool_t *dp = arg;
@@ -1069,7 +1069,5 @@ EXPORT_SYMBOL(txg_wait_callbacks);
EXPORT_SYMBOL(txg_stalled);
EXPORT_SYMBOL(txg_sync_waiting);
-/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs_txg, zfs_txg_, timeout, INT, ZMOD_RW,
"Max seconds worth of delta per txg");
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/zfs/vdev.c b/sys/contrib/openzfs/module/zfs/vdev.c
index 5481902f2a6c..a844ee2a73c5 100644
--- a/sys/contrib/openzfs/module/zfs/vdev.c
+++ b/sys/contrib/openzfs/module/zfs/vdev.c
@@ -4531,8 +4531,8 @@ vdev_stat_update(zio_t *zio, uint64_t psize)
vdev_t *vd = zio->io_vd ? zio->io_vd : rvd;
vdev_t *pvd;
uint64_t txg = zio->io_txg;
- vdev_stat_t *vs = &vd->vdev_stat;
- vdev_stat_ex_t *vsx = &vd->vdev_stat_ex;
+ vdev_stat_t *vs = vd ? &vd->vdev_stat : NULL;
+ vdev_stat_ex_t *vsx = vd ? &vd->vdev_stat_ex : NULL;
zio_type_t type = zio->io_type;
int flags = zio->io_flags;
@@ -6038,7 +6038,6 @@ EXPORT_SYMBOL(vdev_online);
EXPORT_SYMBOL(vdev_offline);
EXPORT_SYMBOL(vdev_clear);
-/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs_vdev, zfs_vdev_, default_ms_count, INT, ZMOD_RW,
"Target number of metaslabs per top-level vdev");
@@ -6054,9 +6053,11 @@ ZFS_MODULE_PARAM(zfs_vdev, zfs_vdev_, ms_count_limit, INT, ZMOD_RW,
ZFS_MODULE_PARAM(zfs, zfs_, slow_io_events_per_second, UINT, ZMOD_RW,
"Rate limit slow IO (delay) events to this many per second");
+/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs, zfs_, checksum_events_per_second, UINT, ZMOD_RW,
"Rate limit checksum events to this many checksum errors per second "
- "(do not set below zed threshold).");
+ "(do not set below ZED threshold).");
+/* END CSTYLED */
ZFS_MODULE_PARAM(zfs, zfs_, scan_ignore_errors, INT, ZMOD_RW,
"Ignore errors during resilver/scrub");
@@ -6070,6 +6071,7 @@ ZFS_MODULE_PARAM(zfs, zfs_, nocacheflush, INT, ZMOD_RW,
ZFS_MODULE_PARAM(zfs, zfs_, embedded_slog_min_ms, INT, ZMOD_RW,
"Minimum number of metaslabs required to dedicate one for log blocks");
+/* BEGIN CSTYLED */
ZFS_MODULE_PARAM_CALL(zfs_vdev, zfs_vdev_, min_auto_ashift,
param_set_min_auto_ashift, param_get_ulong, ZMOD_RW,
"Minimum ashift used when creating new top-level vdevs");
diff --git a/sys/contrib/openzfs/module/zfs/vdev_cache.c b/sys/contrib/openzfs/module/zfs/vdev_cache.c
index b6e680334d5c..a3433311b381 100644
--- a/sys/contrib/openzfs/module/zfs/vdev_cache.c
+++ b/sys/contrib/openzfs/module/zfs/vdev_cache.c
@@ -83,13 +83,13 @@
* it by setting the zfs_vdev_cache_size to zero. Note that Solaris 11
* has made these same changes.
*/
-static int zfs_vdev_cache_max = 1<<14; /* 16KB */
+static int zfs_vdev_cache_max = 1 << 14; /* 16KB */
static int zfs_vdev_cache_size = 0;
static int zfs_vdev_cache_bshift = 16;
#define VCBS (1 << zfs_vdev_cache_bshift) /* 64KB */
-static kstat_t *vdc_ksp = NULL;
+static kstat_t *vdc_ksp = NULL;
typedef struct vdc_stats {
kstat_named_t vdc_stat_delegations;
@@ -426,7 +426,6 @@ vdev_cache_stat_fini(void)
}
}
-/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs_vdev, zfs_vdev_, cache_max, INT, ZMOD_RW,
"Inflate reads small than max");
@@ -435,4 +434,3 @@ ZFS_MODULE_PARAM(zfs_vdev, zfs_vdev_, cache_size, INT, ZMOD_RD,
ZFS_MODULE_PARAM(zfs_vdev, zfs_vdev_, cache_bshift, INT, ZMOD_RW,
"Shift size to inflate reads too");
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/zfs/vdev_indirect.c b/sys/contrib/openzfs/module/zfs/vdev_indirect.c
index aa4801e67442..aeba1e99e6e5 100644
--- a/sys/contrib/openzfs/module/zfs/vdev_indirect.c
+++ b/sys/contrib/openzfs/module/zfs/vdev_indirect.c
@@ -1883,23 +1883,28 @@ EXPORT_SYMBOL(vdev_obsolete_counts_are_precise);
EXPORT_SYMBOL(vdev_obsolete_sm_object);
/* BEGIN CSTYLED */
-ZFS_MODULE_PARAM(zfs_condense, zfs_condense_, indirect_vdevs_enable, INT, ZMOD_RW,
- "Whether to attempt condensing indirect vdev mappings");
+ZFS_MODULE_PARAM(zfs_condense, zfs_condense_, indirect_vdevs_enable, INT,
+ ZMOD_RW, "Whether to attempt condensing indirect vdev mappings");
-ZFS_MODULE_PARAM(zfs_condense, zfs_condense_, indirect_obsolete_pct, INT, ZMOD_RW,
- "Minimum obsolete percent of bytes in the mapping to attempt condensing");
+ZFS_MODULE_PARAM(zfs_condense, zfs_condense_, indirect_obsolete_pct, INT,
+ ZMOD_RW,
+ "Minimum obsolete percent of bytes in the mapping "
+ "to attempt condensing");
ZFS_MODULE_PARAM(zfs_condense, zfs_condense_, min_mapping_bytes, ULONG, ZMOD_RW,
"Don't bother condensing if the mapping uses less than this amount of "
"memory");
-ZFS_MODULE_PARAM(zfs_condense, zfs_condense_, max_obsolete_bytes, ULONG, ZMOD_RW,
+ZFS_MODULE_PARAM(zfs_condense, zfs_condense_, max_obsolete_bytes, ULONG,
+ ZMOD_RW,
"Minimum size obsolete spacemap to attempt condensing");
-ZFS_MODULE_PARAM(zfs_condense, zfs_condense_, indirect_commit_entry_delay_ms, INT, ZMOD_RW,
+ZFS_MODULE_PARAM(zfs_condense, zfs_condense_, indirect_commit_entry_delay_ms,
+ INT, ZMOD_RW,
"Used by tests to ensure certain actions happen in the middle of a "
"condense. A maximum value of 1 should be sufficient.");
-ZFS_MODULE_PARAM(zfs_reconstruct, zfs_reconstruct_, indirect_combinations_max, INT, ZMOD_RW,
+ZFS_MODULE_PARAM(zfs_reconstruct, zfs_reconstruct_, indirect_combinations_max,
+ INT, ZMOD_RW,
"Maximum number of combinations when reconstructing split segments");
/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/zfs/vdev_initialize.c b/sys/contrib/openzfs/module/zfs/vdev_initialize.c
index eda71faeacdc..6c4528e93ad6 100644
--- a/sys/contrib/openzfs/module/zfs/vdev_initialize.c
+++ b/sys/contrib/openzfs/module/zfs/vdev_initialize.c
@@ -488,7 +488,7 @@ vdev_initialize_range_add(void *arg, uint64_t start, uint64_t size)
vdev_xlate_walk(vd, &logical_rs, vdev_initialize_xlate_range_add, arg);
}
-static void
+static _Noreturn void
vdev_initialize_thread(void *arg)
{
vdev_t *vd = arg;
@@ -765,10 +765,8 @@ EXPORT_SYMBOL(vdev_initialize_stop_all);
EXPORT_SYMBOL(vdev_initialize_stop_wait);
EXPORT_SYMBOL(vdev_initialize_restart);
-/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs, zfs_, initialize_value, ULONG, ZMOD_RW,
"Value written during zpool initialize");
ZFS_MODULE_PARAM(zfs, zfs_, initialize_chunk_size, ULONG, ZMOD_RW,
"Size in bytes of writes by zpool initialize");
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/zfs/vdev_label.c b/sys/contrib/openzfs/module/zfs/vdev_label.c
index a62804ea8f49..29391af820ed 100644
--- a/sys/contrib/openzfs/module/zfs/vdev_label.c
+++ b/sys/contrib/openzfs/module/zfs/vdev_label.c
@@ -1324,7 +1324,7 @@ vdev_label_read_bootenv(vdev_t *rvd, nvlist_t *bootenv)
nvlist_free(config);
break;
}
- fallthrough;
+ zfs_fallthrough;
default:
/* Check for FreeBSD zfs bootonce command string */
buf = abd_to_buf(abd);
diff --git a/sys/contrib/openzfs/module/zfs/vdev_mirror.c b/sys/contrib/openzfs/module/zfs/vdev_mirror.c
index 30d0e7de54b0..25abe99e0749 100644
--- a/sys/contrib/openzfs/module/zfs/vdev_mirror.c
+++ b/sys/contrib/openzfs/module/zfs/vdev_mirror.c
@@ -963,20 +963,21 @@ vdev_ops_t vdev_spare_ops = {
.vdev_op_leaf = B_FALSE /* not a leaf vdev */
};
-/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs_vdev_mirror, zfs_vdev_mirror_, rotating_inc, INT, ZMOD_RW,
- "Rotating media load increment for non-seeking I/O's");
+ "Rotating media load increment for non-seeking I/Os");
-ZFS_MODULE_PARAM(zfs_vdev_mirror, zfs_vdev_mirror_, rotating_seek_inc, INT, ZMOD_RW,
- "Rotating media load increment for seeking I/O's");
+ZFS_MODULE_PARAM(zfs_vdev_mirror, zfs_vdev_mirror_, rotating_seek_inc, INT,
+ ZMOD_RW, "Rotating media load increment for seeking I/Os");
-ZFS_MODULE_PARAM(zfs_vdev_mirror, zfs_vdev_mirror_, rotating_seek_offset, INT, ZMOD_RW,
+/* BEGIN CSTYLED */
+ZFS_MODULE_PARAM(zfs_vdev_mirror, zfs_vdev_mirror_, rotating_seek_offset, INT,
+ ZMOD_RW,
"Offset in bytes from the last I/O which triggers "
"a reduced rotating media seek increment");
+/* END CSTYLED */
-ZFS_MODULE_PARAM(zfs_vdev_mirror, zfs_vdev_mirror_, non_rotating_inc, INT, ZMOD_RW,
- "Non-rotating media load increment for non-seeking I/O's");
+ZFS_MODULE_PARAM(zfs_vdev_mirror, zfs_vdev_mirror_, non_rotating_inc, INT,
+ ZMOD_RW, "Non-rotating media load increment for non-seeking I/Os");
-ZFS_MODULE_PARAM(zfs_vdev_mirror, zfs_vdev_mirror_, non_rotating_seek_inc, INT, ZMOD_RW,
- "Non-rotating media load increment for seeking I/O's");
-/* END CSTYLED */
+ZFS_MODULE_PARAM(zfs_vdev_mirror, zfs_vdev_mirror_, non_rotating_seek_inc, INT,
+ ZMOD_RW, "Non-rotating media load increment for seeking I/Os");
diff --git a/sys/contrib/openzfs/module/zfs/vdev_queue.c b/sys/contrib/openzfs/module/zfs/vdev_queue.c
index ae0a322f86c7..0cad5839bb34 100644
--- a/sys/contrib/openzfs/module/zfs/vdev_queue.c
+++ b/sys/contrib/openzfs/module/zfs/vdev_queue.c
@@ -1031,12 +1031,11 @@ vdev_queue_last_offset(vdev_t *vd)
return (vd->vdev_queue.vq_last_offset);
}
-/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs_vdev, zfs_vdev_, aggregation_limit, INT, ZMOD_RW,
"Max vdev I/O aggregation size");
-ZFS_MODULE_PARAM(zfs_vdev, zfs_vdev_, aggregation_limit_non_rotating, INT, ZMOD_RW,
- "Max vdev I/O aggregation size for non-rotating media");
+ZFS_MODULE_PARAM(zfs_vdev, zfs_vdev_, aggregation_limit_non_rotating, INT,
+ ZMOD_RW, "Max vdev I/O aggregation size for non-rotating media");
ZFS_MODULE_PARAM(zfs_vdev, zfs_vdev_, aggregate_trim, INT, ZMOD_RW,
"Allow TRIM I/O to be aggregated");
@@ -1050,11 +1049,11 @@ ZFS_MODULE_PARAM(zfs_vdev, zfs_vdev_, write_gap_limit, INT, ZMOD_RW,
ZFS_MODULE_PARAM(zfs_vdev, zfs_vdev_, max_active, INT, ZMOD_RW,
"Maximum number of active I/Os per vdev");
-ZFS_MODULE_PARAM(zfs_vdev, zfs_vdev_, async_write_active_max_dirty_percent, INT, ZMOD_RW,
- "Async write concurrency max threshold");
+ZFS_MODULE_PARAM(zfs_vdev, zfs_vdev_, async_write_active_max_dirty_percent, INT,
+ ZMOD_RW, "Async write concurrency max threshold");
-ZFS_MODULE_PARAM(zfs_vdev, zfs_vdev_, async_write_active_min_dirty_percent, INT, ZMOD_RW,
- "Async write concurrency min threshold");
+ZFS_MODULE_PARAM(zfs_vdev, zfs_vdev_, async_write_active_min_dirty_percent, INT,
+ ZMOD_RW, "Async write concurrency min threshold");
ZFS_MODULE_PARAM(zfs_vdev, zfs_vdev_, async_read_max_active, INT, ZMOD_RW,
"Max active async read I/Os per vdev");
@@ -1118,4 +1117,3 @@ ZFS_MODULE_PARAM(zfs_vdev, zfs_vdev_, nia_delay, INT, ZMOD_RW,
ZFS_MODULE_PARAM(zfs_vdev, zfs_vdev_, queue_depth_pct, INT, ZMOD_RW,
"Queue depth percentage for each top-level vdev");
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/zfs/vdev_raidz.c b/sys/contrib/openzfs/module/zfs/vdev_raidz.c
index 84e626b44db2..1d691c81b5d5 100644
--- a/sys/contrib/openzfs/module/zfs/vdev_raidz.c
+++ b/sys/contrib/openzfs/module/zfs/vdev_raidz.c
@@ -926,7 +926,6 @@ vdev_raidz_reconstruct_pq(raidz_row_t *rr, int *tgts, int ntgts)
rr->rr_col[VDEV_RAIDZ_Q].rc_abd = qdata;
}
-/* BEGIN CSTYLED */
/*
* In the general case of reconstruction, we must solve the system of linear
* equations defined by the coefficients used to generate parity as well as
@@ -1078,7 +1077,6 @@ vdev_raidz_reconstruct_pq(raidz_row_t *rr, int *tgts, int ntgts)
* that reason, we only build the coefficients in the rows that correspond to
* targeted columns.
*/
-/* END CSTYLED */
static void
vdev_raidz_matrix_init(raidz_row_t *rr, int n, int nmap, int *map,
diff --git a/sys/contrib/openzfs/module/zfs/vdev_raidz_math_scalar.c b/sys/contrib/openzfs/module/zfs/vdev_raidz_math_scalar.c
index 9e9c15ff4ba2..35fafe230ca1 100644
--- a/sys/contrib/openzfs/module/zfs/vdev_raidz_math_scalar.c
+++ b/sys/contrib/openzfs/module/zfs/vdev_raidz_math_scalar.c
@@ -142,7 +142,7 @@ static const struct {
a.b[6] = mul_lt[a.b[6]]; \
a.b[5] = mul_lt[a.b[5]]; \
a.b[4] = mul_lt[a.b[4]]; \
- fallthrough; \
+ zfs_fallthrough; \
case 4: \
a.b[3] = mul_lt[a.b[3]]; \
a.b[2] = mul_lt[a.b[2]]; \
diff --git a/sys/contrib/openzfs/module/zfs/vdev_rebuild.c b/sys/contrib/openzfs/module/zfs/vdev_rebuild.c
index fd2490c0aed6..510463b1f970 100644
--- a/sys/contrib/openzfs/module/zfs/vdev_rebuild.c
+++ b/sys/contrib/openzfs/module/zfs/vdev_rebuild.c
@@ -133,7 +133,7 @@ static int zfs_rebuild_scrub_enabled = 1;
/*
* For vdev_rebuild_initiate_sync() and vdev_rebuild_reset_sync().
*/
-static void vdev_rebuild_thread(void *arg);
+static _Noreturn void vdev_rebuild_thread(void *arg);
/*
* Clear the per-vdev rebuild bytes value for a vdev tree.
@@ -736,7 +736,7 @@ vdev_rebuild_load(vdev_t *vd)
* Each scan thread is responsible for rebuilding a top-level vdev. The
* rebuild progress in tracked on-disk in VDEV_TOP_ZAP_VDEV_REBUILD_PHYS.
*/
-static void
+static _Noreturn void
vdev_rebuild_thread(void *arg)
{
vdev_t *vd = arg;
@@ -1138,7 +1138,6 @@ vdev_rebuild_get_stats(vdev_t *tvd, vdev_rebuild_stat_t *vrs)
return (error);
}
-/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs, zfs_, rebuild_max_segment, ULONG, ZMOD_RW,
"Max segment size in bytes of rebuild reads");
@@ -1147,4 +1146,3 @@ ZFS_MODULE_PARAM(zfs, zfs_, rebuild_vdev_limit, ULONG, ZMOD_RW,
ZFS_MODULE_PARAM(zfs, zfs_, rebuild_scrub_enabled, INT, ZMOD_RW,
"Automatically scrub after sequential resilver completes");
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/zfs/vdev_removal.c b/sys/contrib/openzfs/module/zfs/vdev_removal.c
index 149de633dca8..6887b2f52377 100644
--- a/sys/contrib/openzfs/module/zfs/vdev_removal.c
+++ b/sys/contrib/openzfs/module/zfs/vdev_removal.c
@@ -140,7 +140,7 @@ int zfs_removal_suspend_progress = 0;
#define VDEV_REMOVAL_ZAP_OBJS "lzap"
-static void spa_vdev_remove_thread(void *arg);
+static _Noreturn void spa_vdev_remove_thread(void *arg);
static int spa_vdev_remove_cancel_impl(spa_t *spa);
static void
@@ -1589,7 +1589,7 @@ spa_remove_max_segment(spa_t *spa)
* TXG have completed (see spa_txg_zio) and writes the new mappings to disk
* (see vdev_mapping_sync()).
*/
-static void
+static _Noreturn void
spa_vdev_remove_thread(void *arg)
{
spa_t *spa = arg;
@@ -2544,7 +2544,6 @@ spa_removal_get_stats(spa_t *spa, pool_removal_stat_t *prs)
return (0);
}
-/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs_vdev, zfs_, removal_ignore_errors, INT, ZMOD_RW,
"Ignore hard IO errors when removing device");
@@ -2554,6 +2553,7 @@ ZFS_MODULE_PARAM(zfs_vdev, zfs_, remove_max_segment, INT, ZMOD_RW,
ZFS_MODULE_PARAM(zfs_vdev, vdev_, removal_max_span, INT, ZMOD_RW,
"Largest span of free chunks a remap segment can span");
+/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs_vdev, zfs_, removal_suspend_progress, INT, ZMOD_RW,
"Pause device removal after this many bytes are copied "
"(debug use only - causes removal to hang)");
diff --git a/sys/contrib/openzfs/module/zfs/vdev_trim.c b/sys/contrib/openzfs/module/zfs/vdev_trim.c
index 18aa2b3bfcb0..77f27406ea01 100644
--- a/sys/contrib/openzfs/module/zfs/vdev_trim.c
+++ b/sys/contrib/openzfs/module/zfs/vdev_trim.c
@@ -834,7 +834,7 @@ vdev_trim_range_add(void *arg, uint64_t start, uint64_t size)
* by its ms_allocatable. While a metaslab is undergoing trimming it is
* not eligible for new allocations.
*/
-static void
+static _Noreturn void
vdev_trim_thread(void *arg)
{
vdev_t *vd = arg;
@@ -1175,7 +1175,7 @@ vdev_trim_range_verify(void *arg, uint64_t start, uint64_t size)
* N.B. This behavior is different from a manual TRIM where a thread
* is created for each leaf vdev, instead of each top-level vdev.
*/
-static void
+static _Noreturn void
vdev_autotrim_thread(void *arg)
{
vdev_t *vd = arg;
@@ -1514,7 +1514,7 @@ vdev_autotrim_restart(spa_t *spa)
vdev_autotrim(spa);
}
-static void
+static _Noreturn void
vdev_trim_l2arc_thread(void *arg)
{
vdev_t *vd = arg;
@@ -1709,19 +1709,17 @@ EXPORT_SYMBOL(vdev_autotrim_restart);
EXPORT_SYMBOL(vdev_trim_l2arc);
EXPORT_SYMBOL(vdev_trim_simple);
-/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs_trim, zfs_trim_, extent_bytes_max, UINT, ZMOD_RW,
- "Max size of TRIM commands, larger will be split");
+ "Max size of TRIM commands, larger will be split");
ZFS_MODULE_PARAM(zfs_trim, zfs_trim_, extent_bytes_min, UINT, ZMOD_RW,
- "Min size of TRIM commands, smaller will be skipped");
+ "Min size of TRIM commands, smaller will be skipped");
ZFS_MODULE_PARAM(zfs_trim, zfs_trim_, metaslab_skip, UINT, ZMOD_RW,
- "Skip metaslabs which have never been initialized");
+ "Skip metaslabs which have never been initialized");
ZFS_MODULE_PARAM(zfs_trim, zfs_trim_, txg_batch, UINT, ZMOD_RW,
- "Min number of txgs to aggregate frees before issuing TRIM");
+ "Min number of txgs to aggregate frees before issuing TRIM");
ZFS_MODULE_PARAM(zfs_trim, zfs_trim_, queue_limit, UINT, ZMOD_RW,
- "Max queued TRIMs outstanding per leaf vdev");
-/* END CSTYLED */
+ "Max queued TRIMs outstanding per leaf vdev");
diff --git a/sys/contrib/openzfs/module/zfs/zap.c b/sys/contrib/openzfs/module/zfs/zap.c
index 98ed284c992c..d1d07f9fc804 100644
--- a/sys/contrib/openzfs/module/zfs/zap.c
+++ b/sys/contrib/openzfs/module/zfs/zap.c
@@ -80,8 +80,6 @@ static int zap_iterate_prefetch = B_TRUE;
int fzap_default_block_shift = 14; /* 16k blocksize */
-extern inline zap_phys_t *zap_f_phys(zap_t *zap);
-
static uint64_t zap_allocate_blocks(zap_t *zap, int nblocks);
void
@@ -1380,7 +1378,6 @@ fzap_get_stats(zap_t *zap, zap_stats_t *zs)
}
}
-/* BEGIN CSTYLED */
+/* CSTYLED */
ZFS_MODULE_PARAM(zfs, , zap_iterate_prefetch, INT, ZMOD_RW,
"When iterating ZAP object, prefetch it");
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/zfs/zap_leaf.c b/sys/contrib/openzfs/module/zfs/zap_leaf.c
index aa6c298c3b4b..aad923d512df 100644
--- a/sys/contrib/openzfs/module/zfs/zap_leaf.c
+++ b/sys/contrib/openzfs/module/zfs/zap_leaf.c
@@ -52,8 +52,6 @@ static uint16_t *zap_leaf_rehash_entry(zap_leaf_t *l, uint16_t entry);
#define LEAF_HASH_ENTPTR(l, h) (&zap_leaf_phys(l)->l_hash[LEAF_HASH(l, h)])
-extern inline zap_leaf_phys_t *zap_leaf_phys(zap_leaf_t *l);
-
static void
zap_memset(void *a, int c, size_t n)
{
diff --git a/sys/contrib/openzfs/module/zfs/zap_micro.c b/sys/contrib/openzfs/module/zfs/zap_micro.c
index b4611685b204..1f32e4450522 100644
--- a/sys/contrib/openzfs/module/zfs/zap_micro.c
+++ b/sys/contrib/openzfs/module/zfs/zap_micro.c
@@ -41,8 +41,6 @@
#include <sys/sunddi.h>
#endif
-extern inline mzap_phys_t *zap_m_phys(zap_t *zap);
-
static int mzap_upgrade(zap_t **zapp,
void *tag, dmu_tx_t *tx, zap_flags_t flags);
diff --git a/sys/contrib/openzfs/module/zfs/zcp.c b/sys/contrib/openzfs/module/zfs/zcp.c
index 0a79068384a5..dcfb55d3b3c4 100644
--- a/sys/contrib/openzfs/module/zfs/zcp.c
+++ b/sys/contrib/openzfs/module/zfs/zcp.c
@@ -1443,10 +1443,8 @@ zcp_parse_args(lua_State *state, const char *fname, const zcp_arg_t *pargs,
}
}
-/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs_lua, zfs_lua_, max_instrlimit, ULONG, ZMOD_RW,
"Max instruction limit that can be specified for a channel program");
ZFS_MODULE_PARAM(zfs_lua, zfs_lua_, max_memlimit, ULONG, ZMOD_RW,
"Max memory limit that can be specified for a channel program");
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/zfs/zcp_get.c b/sys/contrib/openzfs/module/zfs/zcp_get.c
index fe712afd7ade..af495ce85140 100644
--- a/sys/contrib/openzfs/module/zfs/zcp_get.c
+++ b/sys/contrib/openzfs/module/zfs/zcp_get.c
@@ -76,9 +76,8 @@ get_objset_type(dsl_dataset_t *ds, zfs_type_t *type)
static int
get_objset_type_name(dsl_dataset_t *ds, char *str)
{
- int error;
- zfs_type_t type;
- error = get_objset_type(ds, &type);
+ zfs_type_t type = ZFS_TYPE_INVALID;
+ int error = get_objset_type(ds, &type);
if (error != 0)
return (error);
switch (type) {
@@ -230,7 +229,7 @@ get_special_prop(lua_State *state, dsl_dataset_t *ds, const char *dsname,
char *strval = kmem_alloc(ZAP_MAXVALUELEN, KM_SLEEP);
char setpoint[ZFS_MAX_DATASET_NAME_LEN] =
"Internal error - setpoint not determined";
- zfs_type_t ds_type;
+ zfs_type_t ds_type = ZFS_TYPE_INVALID;
zprop_type_t prop_type = zfs_prop_get_type(zfs_prop);
(void) get_objset_type(ds, &ds_type);
@@ -344,19 +343,13 @@ get_special_prop(lua_State *state, dsl_dataset_t *ds, const char *dsname,
}
break;
case ZFS_PROP_RECEIVE_RESUME_TOKEN: {
- char *token = get_receive_resume_stats_impl(ds);
-
- (void) strlcpy(strval, token, ZAP_MAXVALUELEN);
- if (strcmp(strval, "") == 0) {
- char *childval = get_child_receive_stats(ds);
-
- (void) strlcpy(strval, childval, ZAP_MAXVALUELEN);
- if (strcmp(strval, "") == 0)
- error = ENOENT;
-
- kmem_strfree(childval);
+ char *token = get_receive_resume_token(ds);
+ if (token != NULL) {
+ (void) strlcpy(strval, token, ZAP_MAXVALUELEN);
+ kmem_strfree(token);
+ } else {
+ error = ENOENT;
}
- kmem_strfree(token);
break;
}
case ZFS_PROP_VOLSIZE:
@@ -503,8 +496,7 @@ get_zap_prop(lua_State *state, dsl_dataset_t *ds, zfs_prop_t zfs_prop)
boolean_t
prop_valid_for_ds(dsl_dataset_t *ds, zfs_prop_t zfs_prop)
{
- int error;
- zfs_type_t zfs_type;
+ zfs_type_t zfs_type = ZFS_TYPE_INVALID;
/* properties not supported */
if ((zfs_prop == ZFS_PROP_ISCSIOPTIONS) ||
@@ -515,7 +507,7 @@ prop_valid_for_ds(dsl_dataset_t *ds, zfs_prop_t zfs_prop)
if ((zfs_prop == ZFS_PROP_ORIGIN) && (!dsl_dir_is_clone(ds->ds_dir)))
return (B_FALSE);
- error = get_objset_type(ds, &zfs_type);
+ int error = get_objset_type(ds, &zfs_type);
if (error != 0)
return (B_FALSE);
return (zfs_prop_valid_for_type(zfs_prop, zfs_type, B_FALSE));
diff --git a/sys/contrib/openzfs/module/zfs/zfs_byteswap.c b/sys/contrib/openzfs/module/zfs/zfs_byteswap.c
index cd35849c3f37..fcedf295c1f7 100644
--- a/sys/contrib/openzfs/module/zfs/zfs_byteswap.c
+++ b/sys/contrib/openzfs/module/zfs/zfs_byteswap.c
@@ -36,9 +36,7 @@ static
void
zfs_oldace_byteswap(ace_t *ace, int ace_cnt)
{
- int i;
-
- for (i = 0; i != ace_cnt; i++, ace++) {
+ for (int i = 0; i != ace_cnt; i++, ace++) {
ace->a_who = BSWAP_32(ace->a_who);
ace->a_access_mask = BSWAP_32(ace->a_access_mask);
ace->a_flags = BSWAP_16(ace->a_flags);
@@ -138,23 +136,16 @@ zfs_ace_byteswap(void *buf, size_t size, boolean_t zfs_layout)
}
}
-/* ARGSUSED */
void
zfs_oldacl_byteswap(void *buf, size_t size)
{
- int cnt;
-
/*
* Arggh, since we don't know how many ACEs are in
* the array, we have to swap the entire block
*/
-
- cnt = size / sizeof (ace_t);
-
- zfs_oldace_byteswap((ace_t *)buf, cnt);
+ zfs_oldace_byteswap((ace_t *)buf, size / sizeof (ace_t));
}
-/* ARGSUSED */
void
zfs_acl_byteswap(void *buf, size_t size)
{
diff --git a/sys/contrib/openzfs/module/zfs/zfs_ioctl.c b/sys/contrib/openzfs/module/zfs/zfs_ioctl.c
index e592734eea09..a2824c5cc804 100644
--- a/sys/contrib/openzfs/module/zfs/zfs_ioctl.c
+++ b/sys/contrib/openzfs/module/zfs/zfs_ioctl.c
@@ -373,10 +373,10 @@ zfs_log_history(zfs_cmd_t *zc)
* Policy for top-level read operations (list pools). Requires no privileges,
* and can be used in the local zone, as there is no associated dataset.
*/
-/* ARGSUSED */
static int
zfs_secpolicy_none(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
{
+ (void) zc, (void) innvl, (void) cr;
return (0);
}
@@ -384,10 +384,10 @@ zfs_secpolicy_none(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
* Policy for dataset read operations (list children, get statistics). Requires
* no privileges, but must be visible in the local zone.
*/
-/* ARGSUSED */
static int
zfs_secpolicy_read(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
{
+ (void) innvl, (void) cr;
if (INGLOBALZONE(curproc) ||
zone_dataset_visible(zc->zc_name, NULL))
return (0);
@@ -656,35 +656,29 @@ zfs_secpolicy_setprop(const char *dsname, zfs_prop_t prop, nvpair_t *propval,
return (zfs_secpolicy_write_perms(dsname, zfs_prop_to_name(prop), cr));
}
-/* ARGSUSED */
static int
zfs_secpolicy_set_fsacl(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
{
- int error;
-
- error = zfs_dozonecheck(zc->zc_name, cr);
- if (error != 0)
- return (error);
-
/*
* permission to set permissions will be evaluated later in
* dsl_deleg_can_allow()
*/
- return (0);
+ (void) innvl;
+ return (zfs_dozonecheck(zc->zc_name, cr));
}
-/* ARGSUSED */
static int
zfs_secpolicy_rollback(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
{
+ (void) innvl;
return (zfs_secpolicy_write_perms(zc->zc_name,
ZFS_DELEG_PERM_ROLLBACK, cr));
}
-/* ARGSUSED */
static int
zfs_secpolicy_send(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
{
+ (void) innvl;
dsl_pool_t *dp;
dsl_dataset_t *ds;
const char *cp;
@@ -717,10 +711,10 @@ zfs_secpolicy_send(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
return (error);
}
-/* ARGSUSED */
static int
zfs_secpolicy_send_new(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
{
+ (void) innvl;
return (zfs_secpolicy_write_perms(zc->zc_name,
ZFS_DELEG_PERM_SEND, cr));
}
@@ -728,12 +722,14 @@ zfs_secpolicy_send_new(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
static int
zfs_secpolicy_share(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
{
+ (void) zc, (void) innvl, (void) cr;
return (SET_ERROR(ENOTSUP));
}
static int
zfs_secpolicy_smb_acl(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
{
+ (void) zc, (void) innvl, (void) cr;
return (SET_ERROR(ENOTSUP));
}
@@ -771,10 +767,10 @@ zfs_secpolicy_destroy_perms(const char *name, cred_t *cr)
return (zfs_secpolicy_write_perms(name, ZFS_DELEG_PERM_DESTROY, cr));
}
-/* ARGSUSED */
static int
zfs_secpolicy_destroy(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
{
+ (void) innvl;
return (zfs_secpolicy_destroy_perms(zc->zc_name, cr));
}
@@ -782,10 +778,10 @@ zfs_secpolicy_destroy(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
* Destroying snapshots with delegated permissions requires
* descendant mount and destroy permissions.
*/
-/* ARGSUSED */
static int
zfs_secpolicy_destroy_snaps(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
{
+ (void) zc;
nvlist_t *snaps;
nvpair_t *pair, *nextpair;
int error = 0;
@@ -844,17 +840,17 @@ zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr)
return (error);
}
-/* ARGSUSED */
static int
zfs_secpolicy_rename(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
{
+ (void) innvl;
return (zfs_secpolicy_rename_perms(zc->zc_name, zc->zc_value, cr));
}
-/* ARGSUSED */
static int
zfs_secpolicy_promote(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
{
+ (void) innvl;
dsl_pool_t *dp;
dsl_dataset_t *clone;
int error;
@@ -899,10 +895,10 @@ zfs_secpolicy_promote(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
return (error);
}
-/* ARGSUSED */
static int
zfs_secpolicy_recv(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
{
+ (void) innvl;
int error;
if ((error = zfs_secpolicy_write_perms(zc->zc_name,
@@ -917,13 +913,6 @@ zfs_secpolicy_recv(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
ZFS_DELEG_PERM_CREATE, cr));
}
-/* ARGSUSED */
-static int
-zfs_secpolicy_recv_new(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
-{
- return (zfs_secpolicy_recv(zc, innvl, cr));
-}
-
int
zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr)
{
@@ -934,10 +923,10 @@ zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr)
/*
* Check for permission to create each snapshot in the nvlist.
*/
-/* ARGSUSED */
static int
zfs_secpolicy_snapshot(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
{
+ (void) zc;
nvlist_t *snaps;
int error = 0;
nvpair_t *pair;
@@ -965,10 +954,10 @@ zfs_secpolicy_snapshot(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
/*
* Check for permission to create each bookmark in the nvlist.
*/
-/* ARGSUSED */
static int
zfs_secpolicy_bookmark(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
{
+ (void) zc;
int error = 0;
for (nvpair_t *pair = nvlist_next_nvpair(innvl, NULL);
@@ -990,10 +979,10 @@ zfs_secpolicy_bookmark(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
return (error);
}
-/* ARGSUSED */
static int
zfs_secpolicy_destroy_bookmarks(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
{
+ (void) zc;
nvpair_t *pair, *nextpair;
int error = 0;
@@ -1031,10 +1020,10 @@ zfs_secpolicy_destroy_bookmarks(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
return (error);
}
-/* ARGSUSED */
static int
zfs_secpolicy_log_history(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
{
+ (void) zc, (void) innvl, (void) cr;
/*
* Even root must have a proper TSD so that we know what pool
* to log to.
@@ -1072,10 +1061,11 @@ zfs_secpolicy_create_clone(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
* Policy for pool operations - create/destroy pools, add vdevs, etc. Requires
* SYS_CONFIG privilege, which is not available in a local zone.
*/
-/* ARGSUSED */
int
zfs_secpolicy_config(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
{
+ (void) zc, (void) innvl;
+
if (secpolicy_sys_config(cr, B_FALSE) != 0)
return (SET_ERROR(EPERM));
@@ -1085,10 +1075,10 @@ zfs_secpolicy_config(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
/*
* Policy for object to name lookups.
*/
-/* ARGSUSED */
static int
zfs_secpolicy_diff(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
{
+ (void) innvl;
int error;
if ((error = secpolicy_sys_config(cr, B_FALSE)) == 0)
@@ -1101,17 +1091,17 @@ zfs_secpolicy_diff(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
/*
* Policy for fault injection. Requires all privileges.
*/
-/* ARGSUSED */
static int
zfs_secpolicy_inject(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
{
+ (void) zc, (void) innvl;
return (secpolicy_zinject(cr));
}
-/* ARGSUSED */
static int
zfs_secpolicy_inherit_prop(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
{
+ (void) innvl;
zfs_prop_t prop = zfs_name_to_prop(zc->zc_value);
if (prop == ZPROP_INVAL) {
@@ -1174,18 +1164,18 @@ zfs_secpolicy_userspace_many(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
userquota_perms[zc->zc_objset_type], cr));
}
-/* ARGSUSED */
static int
zfs_secpolicy_userspace_upgrade(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
{
+ (void) innvl;
return (zfs_secpolicy_setprop(zc->zc_name, ZFS_PROP_VERSION,
NULL, cr));
}
-/* ARGSUSED */
static int
zfs_secpolicy_hold(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
{
+ (void) zc;
nvpair_t *pair;
nvlist_t *holds;
int error;
@@ -1206,10 +1196,10 @@ zfs_secpolicy_hold(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
return (0);
}
-/* ARGSUSED */
static int
zfs_secpolicy_release(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
{
+ (void) zc;
nvpair_t *pair;
int error;
@@ -2558,6 +2548,7 @@ zfs_set_prop_nvlist(const char *dsname, zprop_source_t source, nvlist_t *nvl,
nvpair_t *pair;
nvpair_t *propval;
int rv = 0;
+ int err;
uint64_t intval;
const char *strval;
boolean_t should_update_mount_cache = B_FALSE;
@@ -2569,7 +2560,7 @@ retry:
while ((pair = nvlist_next_nvpair(nvl, pair)) != NULL) {
const char *propname = nvpair_name(pair);
zfs_prop_t prop = zfs_name_to_prop(propname);
- int err = 0;
+ err = 0;
/* decode the property value */
propval = pair;
@@ -2668,47 +2659,53 @@ retry:
goto retry;
}
- if (!nvlist_empty(genericnvl) &&
- dsl_props_set(dsname, source, genericnvl) != 0) {
- /*
- * If this fails, we still want to set as many properties as we
- * can, so try setting them individually.
- */
- pair = NULL;
- while ((pair = nvlist_next_nvpair(genericnvl, pair)) != NULL) {
- const char *propname = nvpair_name(pair);
- int err = 0;
-
- propval = pair;
- if (nvpair_type(pair) == DATA_TYPE_NVLIST) {
- nvlist_t *attrs;
- attrs = fnvpair_value_nvlist(pair);
- propval = fnvlist_lookup_nvpair(attrs,
- ZPROP_VALUE);
- }
+ if (nvlist_empty(genericnvl))
+ goto out;
- if (nvpair_type(propval) == DATA_TYPE_STRING) {
- strval = fnvpair_value_string(propval);
- err = dsl_prop_set_string(dsname, propname,
- source, strval);
- } else if (nvpair_type(propval) == DATA_TYPE_BOOLEAN) {
- err = dsl_prop_inherit(dsname, propname,
- source);
- } else {
- intval = fnvpair_value_uint64(propval);
- err = dsl_prop_set_int(dsname, propname, source,
- intval);
- }
+ /*
+ * Try to set them all in one batch.
+ */
+ err = dsl_props_set(dsname, source, genericnvl);
+ if (err == 0)
+ goto out;
- if (err != 0) {
- if (errlist != NULL) {
- fnvlist_add_int32(errlist, propname,
- err);
- }
- rv = err;
+ /*
+ * If batching fails, we still want to set as many properties as we
+ * can, so try setting them individually.
+ */
+ pair = NULL;
+ while ((pair = nvlist_next_nvpair(genericnvl, pair)) != NULL) {
+ const char *propname = nvpair_name(pair);
+ err = 0;
+
+ propval = pair;
+ if (nvpair_type(pair) == DATA_TYPE_NVLIST) {
+ nvlist_t *attrs;
+ attrs = fnvpair_value_nvlist(pair);
+ propval = fnvlist_lookup_nvpair(attrs, ZPROP_VALUE);
+ }
+
+ if (nvpair_type(propval) == DATA_TYPE_STRING) {
+ strval = fnvpair_value_string(propval);
+ err = dsl_prop_set_string(dsname, propname,
+ source, strval);
+ } else if (nvpair_type(propval) == DATA_TYPE_BOOLEAN) {
+ err = dsl_prop_inherit(dsname, propname, source);
+ } else {
+ intval = fnvpair_value_uint64(propval);
+ err = dsl_prop_set_int(dsname, propname, source,
+ intval);
+ }
+
+ if (err != 0) {
+ if (errlist != NULL) {
+ fnvlist_add_int32(errlist, propname, err);
}
+ rv = err;
}
}
+
+out:
if (should_update_mount_cache)
zfs_ioctl_update_mount_cache(dsname);
@@ -3142,7 +3139,6 @@ zfs_ioc_get_fsacl(zfs_cmd_t *zc)
return (error);
}
-/* ARGSUSED */
static void
zfs_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx)
{
@@ -3504,11 +3500,11 @@ static const zfs_ioc_key_t zfs_keys_remap[] = {
/* no nvl keys */
};
-/* ARGSUSED */
static int
zfs_ioc_remap(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl)
{
/* This IOCTL is no longer supported. */
+ (void) fsname, (void) innvl, (void) outnvl;
return (0);
}
@@ -3596,10 +3592,10 @@ static const zfs_ioc_key_t zfs_keys_log_history[] = {
{"message", DATA_TYPE_STRING, 0},
};
-/* ARGSUSED */
static int
zfs_ioc_log_history(const char *unused, nvlist_t *innvl, nvlist_t *outnvl)
{
+ (void) unused, (void) outnvl;
const char *message;
char *poolname;
spa_t *spa;
@@ -3702,10 +3698,10 @@ zfs_unmount_snap(const char *snapname)
(void) zfsctl_snapshot_unmount(snapname, MNT_FORCE);
}
-/* ARGSUSED */
static int
zfs_unmount_snap_cb(const char *snapname, void *arg)
{
+ (void) arg;
zfs_unmount_snap(snapname);
return (0);
}
@@ -3749,7 +3745,6 @@ static const zfs_ioc_key_t zfs_keys_destroy_snaps[] = {
{"defer", DATA_TYPE_BOOLEAN, ZK_OPTIONAL},
};
-/* ARGSUSED */
static int
zfs_ioc_destroy_snaps(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
{
@@ -3802,10 +3797,10 @@ static const zfs_ioc_key_t zfs_keys_bookmark[] = {
{"<bookmark>...", DATA_TYPE_STRING, ZK_WILDCARDLIST},
};
-/* ARGSUSED */
static int
zfs_ioc_bookmark(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
{
+ (void) poolname;
return (dsl_bookmark_create(innvl, outnvl));
}
@@ -3842,11 +3837,11 @@ static const zfs_ioc_key_t zfs_keys_get_bookmark_props[] = {
/* no nvl keys */
};
-/* ARGSUSED */
static int
zfs_ioc_get_bookmark_props(const char *bookmark, nvlist_t *innvl,
nvlist_t *outnvl)
{
+ (void) innvl;
char fsname[ZFS_MAX_DATASET_NAME_LEN];
char *bmname;
@@ -3951,10 +3946,10 @@ static const zfs_ioc_key_t zfs_keys_pool_checkpoint[] = {
/* no nvl keys */
};
-/* ARGSUSED */
static int
zfs_ioc_pool_checkpoint(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
{
+ (void) innvl, (void) outnvl;
return (spa_checkpoint(poolname));
}
@@ -3966,11 +3961,11 @@ static const zfs_ioc_key_t zfs_keys_pool_discard_checkpoint[] = {
/* no nvl keys */
};
-/* ARGSUSED */
static int
zfs_ioc_pool_discard_checkpoint(const char *poolname, nvlist_t *innvl,
nvlist_t *outnvl)
{
+ (void) innvl, (void) outnvl;
return (spa_checkpoint_discard(poolname));
}
@@ -4332,7 +4327,6 @@ static const zfs_ioc_key_t zfs_keys_rollback[] = {
{"target", DATA_TYPE_STRING, ZK_OPTIONAL},
};
-/* ARGSUSED */
static int
zfs_ioc_rollback(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl)
{
@@ -4404,14 +4398,15 @@ recursive_unmount(const char *fsname, void *arg)
* outnvl is unused
*/
-/* ARGSUSED */
static const zfs_ioc_key_t zfs_keys_redact[] = {
{"bookname", DATA_TYPE_STRING, 0},
{"snapnv", DATA_TYPE_NVLIST, 0},
};
+
static int
zfs_ioc_redact(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl)
{
+ (void) outnvl;
nvlist_t *redactnvl = NULL;
char *redactbook = NULL;
@@ -5793,10 +5788,10 @@ static const zfs_ioc_key_t zfs_keys_pool_reopen[] = {
{"scrub_restart", DATA_TYPE_BOOLEAN_VALUE, ZK_OPTIONAL},
};
-/* ARGSUSED */
static int
zfs_ioc_pool_reopen(const char *pool, nvlist_t *innvl, nvlist_t *outnvl)
{
+ (void) outnvl;
spa_t *spa;
int error;
boolean_t rc, scrub_restart = B_TRUE;
@@ -6203,10 +6198,10 @@ static const zfs_ioc_key_t zfs_keys_hold[] = {
{"cleanup_fd", DATA_TYPE_INT32, ZK_OPTIONAL},
};
-/* ARGSUSED */
static int
zfs_ioc_hold(const char *pool, nvlist_t *args, nvlist_t *errlist)
{
+ (void) pool;
nvpair_t *pair;
nvlist_t *holds;
int cleanup_fd = -1;
@@ -6255,10 +6250,10 @@ static const zfs_ioc_key_t zfs_keys_get_holds[] = {
/* no nvl keys */
};
-/* ARGSUSED */
static int
zfs_ioc_get_holds(const char *snapname, nvlist_t *args, nvlist_t *outnvl)
{
+ (void) args;
return (dsl_dataset_get_holds(snapname, outnvl));
}
@@ -6277,10 +6272,10 @@ static const zfs_ioc_key_t zfs_keys_release[] = {
{"<snapname>...", DATA_TYPE_NVLIST, ZK_WILDCARDLIST},
};
-/* ARGSUSED */
static int
zfs_ioc_release(const char *pool, nvlist_t *holds, nvlist_t *errlist)
{
+ (void) pool;
return (dsl_dataset_user_release(holds, errlist));
}
@@ -6514,10 +6509,10 @@ static const zfs_ioc_key_t zfs_keys_send_new[] = {
{"redactbook", DATA_TYPE_STRING, ZK_OPTIONAL},
};
-/* ARGSUSED */
static int
zfs_ioc_send_new(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl)
{
+ (void) outnvl;
int error;
offset_t off;
char *fromname = NULL;
@@ -6564,11 +6559,12 @@ zfs_ioc_send_new(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl)
return (error);
}
-/* ARGSUSED */
static int
send_space_sum(objset_t *os, void *buf, int len, void *arg)
{
+ (void) os, (void) buf;
uint64_t *size = arg;
+
*size += len;
return (0);
}
@@ -6760,10 +6756,10 @@ static const zfs_ioc_key_t zfs_keys_pool_sync[] = {
{"force", DATA_TYPE_BOOLEAN_VALUE, 0},
};
-/* ARGSUSED */
static int
zfs_ioc_pool_sync(const char *pool, nvlist_t *innvl, nvlist_t *onvl)
{
+ (void) onvl;
int err;
boolean_t rc, force = B_FALSE;
spa_t *spa;
@@ -6803,10 +6799,10 @@ static const zfs_ioc_key_t zfs_keys_load_key[] = {
{"noop", DATA_TYPE_BOOLEAN, ZK_OPTIONAL},
};
-/* ARGSUSED */
static int
zfs_ioc_load_key(const char *dsname, nvlist_t *innvl, nvlist_t *outnvl)
{
+ (void) outnvl;
int ret;
dsl_crypto_params_t *dcp = NULL;
nvlist_t *hidden_args;
@@ -6845,10 +6841,10 @@ static const zfs_ioc_key_t zfs_keys_unload_key[] = {
/* no nvl keys */
};
-/* ARGSUSED */
static int
zfs_ioc_unload_key(const char *dsname, nvlist_t *innvl, nvlist_t *outnvl)
{
+ (void) innvl, (void) outnvl;
int ret = 0;
if (strchr(dsname, '@') != NULL || strchr(dsname, '%') != NULL) {
@@ -6866,7 +6862,7 @@ out:
/*
* Changes a user's wrapping key used to decrypt a dataset. The keyformat,
- * keylocation, pbkdf2salt, and pbkdf2iters properties can also be specified
+ * keylocation, pbkdf2salt, and pbkdf2iters properties can also be specified
* here to change how the key is derived in userspace.
*
* innvl: {
@@ -6883,10 +6879,10 @@ static const zfs_ioc_key_t zfs_keys_change_key[] = {
{"props", DATA_TYPE_NVLIST, ZK_OPTIONAL},
};
-/* ARGSUSED */
static int
zfs_ioc_change_key(const char *dsname, nvlist_t *innvl, nvlist_t *outnvl)
{
+ (void) outnvl;
int ret;
uint64_t cmd = DCP_CMD_NONE;
dsl_crypto_params_t *dcp = NULL;
@@ -7115,7 +7111,7 @@ zfs_ioctl_init(void)
ARRAY_SIZE(zfs_keys_destroy_bookmarks));
zfs_ioctl_register("receive", ZFS_IOC_RECV_NEW,
- zfs_ioc_recv_new, zfs_secpolicy_recv_new, DATASET_NAME,
+ zfs_ioc_recv_new, zfs_secpolicy_recv, DATASET_NAME,
POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE,
zfs_keys_recv_new, ARRAY_SIZE(zfs_keys_recv_new));
zfs_ioctl_register("load-key", ZFS_IOC_LOAD_KEY,
@@ -7862,10 +7858,8 @@ zfs_kmod_fini(void)
tsd_destroy(&zfs_allow_log_key);
}
-/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs, zfs_, max_nvlist_src_size, ULONG, ZMOD_RW,
- "Maximum size in bytes allowed for src nvlist passed with ZFS ioctls");
+ "Maximum size in bytes allowed for src nvlist passed with ZFS ioctls");
ZFS_MODULE_PARAM(zfs, zfs_, history_output_max, ULONG, ZMOD_RW,
- "Maximum size in bytes of ZFS ioctl output that will be logged");
-/* END CSTYLED */
+ "Maximum size in bytes of ZFS ioctl output that will be logged");
diff --git a/sys/contrib/openzfs/module/zfs/zfs_log.c b/sys/contrib/openzfs/module/zfs/zfs_log.c
index 2f3eab67993e..9df801870a4f 100644
--- a/sys/contrib/openzfs/module/zfs/zfs_log.c
+++ b/sys/contrib/openzfs/module/zfs/zfs_log.c
@@ -721,6 +721,40 @@ zfs_log_setattr(zilog_t *zilog, dmu_tx_t *tx, int txtype,
}
/*
+ * Handles TX_SETSAXATTR transactions.
+ */
+void
+zfs_log_setsaxattr(zilog_t *zilog, dmu_tx_t *tx, int txtype,
+ znode_t *zp, const char *name, const void *value, size_t size)
+{
+ itx_t *itx;
+ lr_setsaxattr_t *lr;
+ size_t recsize = sizeof (lr_setsaxattr_t);
+ void *xattrstart;
+ int namelen;
+
+ if (zil_replaying(zilog, tx) || zp->z_unlinked)
+ return;
+
+ namelen = strlen(name) + 1;
+ recsize += (namelen + size);
+ itx = zil_itx_create(txtype, recsize);
+ lr = (lr_setsaxattr_t *)&itx->itx_lr;
+ lr->lr_foid = zp->z_id;
+ xattrstart = (char *)(lr + 1);
+ bcopy(name, xattrstart, namelen);
+ if (value != NULL) {
+ bcopy(value, (char *)xattrstart + namelen, size);
+ lr->lr_size = size;
+ } else {
+ lr->lr_size = 0;
+ }
+
+ itx->itx_sync = (zp->z_sync_cnt != 0);
+ zil_itx_assign(zilog, itx, tx);
+}
+
+/*
* Handles TX_ACL transactions.
*/
void
@@ -786,7 +820,5 @@ zfs_log_acl(zilog_t *zilog, dmu_tx_t *tx, znode_t *zp,
zil_itx_assign(zilog, itx, tx);
}
-/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs, zfs_, immediate_write_sz, LONG, ZMOD_RW,
"Largest data block to write to zil");
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/zfs/zfs_replay.c b/sys/contrib/openzfs/module/zfs/zfs_replay.c
index f76725f0b716..3ccd96dc256d 100644
--- a/sys/contrib/openzfs/module/zfs/zfs_replay.c
+++ b/sys/contrib/openzfs/module/zfs/zfs_replay.c
@@ -47,6 +47,8 @@
#include <sys/atomic.h>
#include <sys/cred.h>
#include <sys/zpl.h>
+#include <sys/dmu_objset.h>
+#include <sys/zfeature.h>
/*
* NB: FreeBSD expects to be able to do vnode locking in lookup and
@@ -80,10 +82,10 @@ zfs_init_vattr(vattr_t *vap, uint64_t mask, uint64_t mode,
vap->va_nodeid = nodeid;
}
-/* ARGSUSED */
static int
zfs_replay_error(void *arg1, void *arg2, boolean_t byteswap)
{
+ (void) arg1, (void) arg2, (void) byteswap;
return (SET_ERROR(ENOTSUP));
}
@@ -362,7 +364,7 @@ zfs_replay_create_acl(void *arg1, void *arg2, boolean_t byteswap)
zfsvfs->z_fuid_replay = zfs_replay_fuids(fuidstart,
(void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt,
lr->lr_uid, lr->lr_gid);
- fallthrough;
+ zfs_fallthrough;
case TX_CREATE_ACL_ATTR:
if (name == NULL) {
lrattr = (lr_attr_t *)(caddr_t)(lracl + 1);
@@ -394,7 +396,7 @@ zfs_replay_create_acl(void *arg1, void *arg2, boolean_t byteswap)
zfsvfs->z_fuid_replay = zfs_replay_fuids(fuidstart,
(void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt,
lr->lr_uid, lr->lr_gid);
- fallthrough;
+ zfs_fallthrough;
case TX_MKDIR_ACL_ATTR:
if (name == NULL) {
lrattr = (lr_attr_t *)(caddr_t)(lracl + 1);
@@ -519,7 +521,7 @@ zfs_replay_create(void *arg1, void *arg2, boolean_t byteswap)
zfs_replay_fuid_domain(start, &start,
lr->lr_uid, lr->lr_gid);
name = (char *)start;
- fallthrough;
+ zfs_fallthrough;
case TX_CREATE:
if (name == NULL)
@@ -537,7 +539,7 @@ zfs_replay_create(void *arg1, void *arg2, boolean_t byteswap)
zfs_replay_fuid_domain(start, &start,
lr->lr_uid, lr->lr_gid);
name = (char *)start;
- fallthrough;
+ zfs_fallthrough;
case TX_MKDIR:
if (name == NULL)
@@ -869,6 +871,86 @@ zfs_replay_setattr(void *arg1, void *arg2, boolean_t byteswap)
}
static int
+zfs_replay_setsaxattr(void *arg1, void *arg2, boolean_t byteswap)
+{
+ zfsvfs_t *zfsvfs = arg1;
+ lr_setsaxattr_t *lr = arg2;
+ znode_t *zp;
+ nvlist_t *nvl;
+ size_t sa_size;
+ char *name;
+ char *value;
+ size_t size;
+ int error = 0;
+
+ ASSERT(spa_feature_is_active(zfsvfs->z_os->os_spa,
+ SPA_FEATURE_ZILSAXATTR));
+ if (byteswap)
+ byteswap_uint64_array(lr, sizeof (*lr));
+
+ if ((error = zfs_zget(zfsvfs, lr->lr_foid, &zp)) != 0)
+ return (error);
+
+ rw_enter(&zp->z_xattr_lock, RW_WRITER);
+ mutex_enter(&zp->z_lock);
+ if (zp->z_xattr_cached == NULL)
+ error = zfs_sa_get_xattr(zp);
+ mutex_exit(&zp->z_lock);
+
+ if (error)
+ goto out;
+
+ ASSERT(zp->z_xattr_cached);
+ nvl = zp->z_xattr_cached;
+
+ /* Get xattr name, value and size from log record */
+ size = lr->lr_size;
+ name = (char *)(lr + 1);
+ if (size == 0) {
+ value = NULL;
+ error = nvlist_remove(nvl, name, DATA_TYPE_BYTE_ARRAY);
+ } else {
+ value = name + strlen(name) + 1;
+ /* Limited to 32k to keep nvpair memory allocations small */
+ if (size > DXATTR_MAX_ENTRY_SIZE) {
+ error = SET_ERROR(EFBIG);
+ goto out;
+ }
+
+ /* Prevent the DXATTR SA from consuming the entire SA region */
+ error = nvlist_size(nvl, &sa_size, NV_ENCODE_XDR);
+ if (error)
+ goto out;
+
+ if (sa_size > DXATTR_MAX_SA_SIZE) {
+ error = SET_ERROR(EFBIG);
+ goto out;
+ }
+
+ error = nvlist_add_byte_array(nvl, name, (uchar_t *)value,
+ size);
+ }
+
+ /*
+ * Update the SA for additions, modifications, and removals. On
+ * error drop the inconsistent cached version of the nvlist, it
+ * will be reconstructed from the ARC when next accessed.
+ */
+ if (error == 0)
+ error = zfs_sa_set_xattr(zp, name, value, size);
+
+ if (error) {
+ nvlist_free(nvl);
+ zp->z_xattr_cached = NULL;
+ }
+
+out:
+ rw_exit(&zp->z_xattr_lock);
+ zrele(zp);
+ return (error);
+}
+
+static int
zfs_replay_acl_v0(void *arg1, void *arg2, boolean_t byteswap)
{
zfsvfs_t *zfsvfs = arg1;
@@ -989,4 +1071,5 @@ zil_replay_func_t *const zfs_replay_vector[TX_MAX_TYPE] = {
zfs_replay_create, /* TX_MKDIR_ATTR */
zfs_replay_create_acl, /* TX_MKDIR_ACL_ATTR */
zfs_replay_write2, /* TX_WRITE2 */
+ zfs_replay_setsaxattr, /* TX_SETSAXATTR */
};
diff --git a/sys/contrib/openzfs/module/zfs/zfs_sa.c b/sys/contrib/openzfs/module/zfs/zfs_sa.c
index 817f63048789..1f15cae00da8 100644
--- a/sys/contrib/openzfs/module/zfs/zfs_sa.c
+++ b/sys/contrib/openzfs/module/zfs/zfs_sa.c
@@ -29,6 +29,7 @@
#include <sys/zfs_sa.h>
#include <sys/dmu_objset.h>
#include <sys/sa_impl.h>
+#include <sys/zfeature.h>
/*
* ZPL attribute registration table.
@@ -69,7 +70,10 @@ const sa_attr_reg_t zfs_attr_table[ZPL_END+1] = {
{NULL, 0, 0, 0}
};
+
#ifdef _KERNEL
+static int zfs_zil_saxattr = 1;
+
int
zfs_sa_readlink(znode_t *zp, zfs_uio_t *uio)
{
@@ -219,13 +223,14 @@ zfs_sa_get_xattr(znode_t *zp)
}
int
-zfs_sa_set_xattr(znode_t *zp)
+zfs_sa_set_xattr(znode_t *zp, const char *name, const void *value, size_t vsize)
{
zfsvfs_t *zfsvfs = ZTOZSB(zp);
+ zilog_t *zilog;
dmu_tx_t *tx;
char *obj;
size_t size;
- int error;
+ int error, logsaxattr = 0;
ASSERT(RW_WRITE_HELD(&zp->z_xattr_lock));
ASSERT(zp->z_xattr_cached);
@@ -244,6 +249,17 @@ zfs_sa_set_xattr(znode_t *zp)
if (error)
goto out_free;
+ zilog = zfsvfs->z_log;
+
+ /*
+ * Users enable ZIL logging of xattr=sa operations by enabling the
+ * SPA_FEATURE_ZILSAXATTR feature on the pool. Feature is activated
+ * during zil_process_commit_list/zil_create, if enabled.
+ */
+ if (spa_feature_is_enabled(zfsvfs->z_os->os_spa,
+ SPA_FEATURE_ZILSAXATTR) && zfs_zil_saxattr)
+ logsaxattr = 1;
+
tx = dmu_tx_create(zfsvfs->z_os);
dmu_tx_hold_sa_create(tx, size);
dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_TRUE);
@@ -256,6 +272,10 @@ zfs_sa_set_xattr(znode_t *zp)
sa_bulk_attr_t bulk[2];
uint64_t ctime[2];
+ if (logsaxattr)
+ zfs_log_setsaxattr(zilog, tx, TX_SETSAXATTR, zp, name,
+ value, vsize);
+
zfs_tstamp_update_setup(zp, STATE_CHANGED, NULL, ctime);
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_DXATTR(zfsvfs),
NULL, obj, size);
@@ -264,6 +284,8 @@ zfs_sa_set_xattr(znode_t *zp)
VERIFY0(sa_bulk_update(zp->z_sa_hdl, bulk, count, tx));
dmu_tx_commit(tx);
+ if (logsaxattr && zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS)
+ zil_commit(zilog, 0);
}
out_free:
vmem_free(obj, size);
@@ -433,6 +455,9 @@ zfs_sa_upgrade_txholds(dmu_tx_t *tx, znode_t *zp)
}
}
+ZFS_MODULE_PARAM(zfs, zfs_, zil_saxattr, INT, ZMOD_RW,
+ "Disable xattr=sa extended attribute logging in ZIL by settng 0.");
+
EXPORT_SYMBOL(zfs_attr_table);
EXPORT_SYMBOL(zfs_sa_readlink);
EXPORT_SYMBOL(zfs_sa_symlink);
diff --git a/sys/contrib/openzfs/module/zfs/zfs_vnops.c b/sys/contrib/openzfs/module/zfs/zfs_vnops.c
index b7fdae926520..5d5b5f29a71d 100644
--- a/sys/contrib/openzfs/module/zfs/zfs_vnops.c
+++ b/sys/contrib/openzfs/module/zfs/zfs_vnops.c
@@ -154,7 +154,6 @@ zfs_holey(znode_t *zp, ulong_t cmd, loff_t *off)
}
#endif /* SEEK_HOLE && SEEK_DATA */
-/*ARGSUSED*/
int
zfs_access(znode_t *zp, int mode, int flag, cred_t *cr)
{
@@ -192,10 +191,10 @@ static unsigned long zfs_vnops_read_chunk_size = 1024 * 1024; /* Tunable */
* Side Effects:
* inode - atime updated if byte count > 0
*/
-/* ARGSUSED */
int
zfs_read(struct znode *zp, zfs_uio_t *uio, int ioflag, cred_t *cr)
{
+ (void) cr;
int error = 0;
boolean_t frsync = B_FALSE;
@@ -315,6 +314,62 @@ out:
return (error);
}
+static void
+zfs_clear_setid_bits_if_necessary(zfsvfs_t *zfsvfs, znode_t *zp, cred_t *cr,
+ uint64_t *clear_setid_bits_txgp, dmu_tx_t *tx)
+{
+ zilog_t *zilog = zfsvfs->z_log;
+ const uint64_t uid = KUID_TO_SUID(ZTOUID(zp));
+
+ ASSERT(clear_setid_bits_txgp != NULL);
+ ASSERT(tx != NULL);
+
+ /*
+ * Clear Set-UID/Set-GID bits on successful write if not
+ * privileged and at least one of the execute bits is set.
+ *
+ * It would be nice to do this after all writes have
+ * been done, but that would still expose the ISUID/ISGID
+ * to another app after the partial write is committed.
+ *
+ * Note: we don't call zfs_fuid_map_id() here because
+ * user 0 is not an ephemeral uid.
+ */
+ mutex_enter(&zp->z_acl_lock);
+ if ((zp->z_mode & (S_IXUSR | (S_IXUSR >> 3) | (S_IXUSR >> 6))) != 0 &&
+ (zp->z_mode & (S_ISUID | S_ISGID)) != 0 &&
+ secpolicy_vnode_setid_retain(zp, cr,
+ ((zp->z_mode & S_ISUID) != 0 && uid == 0)) != 0) {
+ uint64_t newmode;
+
+ zp->z_mode &= ~(S_ISUID | S_ISGID);
+ newmode = zp->z_mode;
+ (void) sa_update(zp->z_sa_hdl, SA_ZPL_MODE(zfsvfs),
+ (void *)&newmode, sizeof (uint64_t), tx);
+
+ mutex_exit(&zp->z_acl_lock);
+
+ /*
+ * Make sure SUID/SGID bits will be removed when we replay the
+ * log. If the setid bits are keep coming back, don't log more
+ * than one TX_SETATTR per transaction group.
+ */
+ if (*clear_setid_bits_txgp != dmu_tx_get_txg(tx)) {
+ vattr_t va;
+
+ bzero(&va, sizeof (va));
+ va.va_mask = AT_MODE;
+ va.va_nodeid = zp->z_id;
+ va.va_mode = newmode;
+ zfs_log_setattr(zilog, tx, TX_SETATTR, zp, &va, AT_MODE,
+ NULL);
+ *clear_setid_bits_txgp = dmu_tx_get_txg(tx);
+ }
+ } else {
+ mutex_exit(&zp->z_acl_lock);
+ }
+}
+
/*
* Write the bytes to a file.
*
@@ -333,13 +388,12 @@ out:
* Timestamps:
* ip - ctime|mtime updated if byte count > 0
*/
-
-/* ARGSUSED */
int
zfs_write(znode_t *zp, zfs_uio_t *uio, int ioflag, cred_t *cr)
{
int error = 0, error1;
ssize_t start_resid = zfs_uio_resid(uio);
+ uint64_t clear_setid_bits_txg = 0;
/*
* Fasttrack empty write
@@ -519,6 +573,11 @@ zfs_write(znode_t *zp, zfs_uio_t *uio, int ioflag, cred_t *cr)
}
/*
+ * NB: We must call zfs_clear_setid_bits_if_necessary before
+ * committing the transaction!
+ */
+
+ /*
* If rangelock_enter() over-locked we grow the blocksize
* and then reduce the lock range. This will only happen
* on the first iteration since rangelock_reduce() will
@@ -559,6 +618,8 @@ zfs_write(znode_t *zp, zfs_uio_t *uio, int ioflag, cred_t *cr)
zfs_uio_fault_disable(uio, B_FALSE);
#ifdef __linux__
if (error == EFAULT) {
+ zfs_clear_setid_bits_if_necessary(zfsvfs, zp,
+ cr, &clear_setid_bits_txg, tx);
dmu_tx_commit(tx);
/*
* Account for partial writes before
@@ -581,6 +642,8 @@ zfs_write(znode_t *zp, zfs_uio_t *uio, int ioflag, cred_t *cr)
* VFS, which will handle faulting and will retry.
*/
if (error != 0 && error != EFAULT) {
+ zfs_clear_setid_bits_if_necessary(zfsvfs, zp,
+ cr, &clear_setid_bits_txg, tx);
dmu_tx_commit(tx);
break;
}
@@ -605,6 +668,13 @@ zfs_write(znode_t *zp, zfs_uio_t *uio, int ioflag, cred_t *cr)
error = dmu_assign_arcbuf_by_dbuf(
sa_get_db(zp->z_sa_hdl), woff, abuf, tx);
if (error != 0) {
+ /*
+ * XXX This might not be necessary if
+ * dmu_assign_arcbuf_by_dbuf is guaranteed
+ * to be atomic.
+ */
+ zfs_clear_setid_bits_if_necessary(zfsvfs, zp,
+ cr, &clear_setid_bits_txg, tx);
dmu_return_arcbuf(abuf);
dmu_tx_commit(tx);
break;
@@ -630,30 +700,8 @@ zfs_write(znode_t *zp, zfs_uio_t *uio, int ioflag, cred_t *cr)
break;
}
- /*
- * Clear Set-UID/Set-GID bits on successful write if not
- * privileged and at least one of the execute bits is set.
- *
- * It would be nice to do this after all writes have
- * been done, but that would still expose the ISUID/ISGID
- * to another app after the partial write is committed.
- *
- * Note: we don't call zfs_fuid_map_id() here because
- * user 0 is not an ephemeral uid.
- */
- mutex_enter(&zp->z_acl_lock);
- if ((zp->z_mode & (S_IXUSR | (S_IXUSR >> 3) |
- (S_IXUSR >> 6))) != 0 &&
- (zp->z_mode & (S_ISUID | S_ISGID)) != 0 &&
- secpolicy_vnode_setid_retain(zp, cr,
- ((zp->z_mode & S_ISUID) != 0 && uid == 0)) != 0) {
- uint64_t newmode;
- zp->z_mode &= ~(S_ISUID | S_ISGID);
- newmode = zp->z_mode;
- (void) sa_update(zp->z_sa_hdl, SA_ZPL_MODE(zfsvfs),
- (void *)&newmode, sizeof (uint64_t), tx);
- }
- mutex_exit(&zp->z_acl_lock);
+ zfs_clear_setid_bits_if_necessary(zfsvfs, zp, cr,
+ &clear_setid_bits_txg, tx);
zfs_tstamp_update_setup(zp, CONTENT_MODIFIED, mtime, ctime);
@@ -679,8 +727,14 @@ zfs_write(znode_t *zp, zfs_uio_t *uio, int ioflag, cred_t *cr)
/* Avoid clobbering EFAULT. */
error = error1;
+ /*
+ * NB: During replay, the TX_SETATTR record logged by
+ * zfs_clear_setid_bits_if_necessary must precede any of
+ * the TX_WRITE records logged here.
+ */
zfs_log_write(zilog, tx, TX_WRITE, zp, woff, tx_bytes, ioflag,
NULL, NULL);
+
dmu_tx_commit(tx);
if (error != 0)
@@ -722,7 +776,6 @@ zfs_write(znode_t *zp, zfs_uio_t *uio, int ioflag, cred_t *cr)
return (0);
}
-/*ARGSUSED*/
int
zfs_getsecattr(znode_t *zp, vsecattr_t *vsecp, int flag, cred_t *cr)
{
@@ -738,7 +791,6 @@ zfs_getsecattr(znode_t *zp, vsecattr_t *vsecp, int flag, cred_t *cr)
return (error);
}
-/*ARGSUSED*/
int
zfs_setsecattr(znode_t *zp, vsecattr_t *vsecp, int flag, cred_t *cr)
{
@@ -908,10 +960,10 @@ zfs_get_data(void *arg, uint64_t gen, lr_write_t *lr, char *buf,
}
-/* ARGSUSED */
static void
zfs_get_done(zgd_t *zgd, int error)
{
+ (void) error;
znode_t *zp = zgd->zgd_private;
if (zgd->zgd_db)
diff --git a/sys/contrib/openzfs/module/zfs/zil.c b/sys/contrib/openzfs/module/zfs/zil.c
index 85a17f10b38f..10f89c916421 100644
--- a/sys/contrib/openzfs/module/zfs/zil.c
+++ b/sys/contrib/openzfs/module/zfs/zil.c
@@ -664,6 +664,38 @@ zilog_is_dirty(zilog_t *zilog)
}
/*
+ * Its called in zil_commit context (zil_process_commit_list()/zil_create()).
+ * It activates SPA_FEATURE_ZILSAXATTR feature, if its enabled.
+ * Check dsl_dataset_feature_is_active to avoid txg_wait_synced() on every
+ * zil_commit.
+ */
+static void
+zil_commit_activate_saxattr_feature(zilog_t *zilog)
+{
+ dsl_dataset_t *ds = dmu_objset_ds(zilog->zl_os);
+ uint64_t txg = 0;
+ dmu_tx_t *tx = NULL;
+
+ if (spa_feature_is_enabled(zilog->zl_spa,
+ SPA_FEATURE_ZILSAXATTR) &&
+ dmu_objset_type(zilog->zl_os) != DMU_OST_ZVOL &&
+ !dsl_dataset_feature_is_active(ds,
+ SPA_FEATURE_ZILSAXATTR)) {
+ tx = dmu_tx_create(zilog->zl_os);
+ VERIFY0(dmu_tx_assign(tx, TXG_WAIT));
+ dsl_dataset_dirty(ds, tx);
+ txg = dmu_tx_get_txg(tx);
+
+ mutex_enter(&ds->ds_lock);
+ ds->ds_feature_activation[SPA_FEATURE_ZILSAXATTR] =
+ (void *)B_TRUE;
+ mutex_exit(&ds->ds_lock);
+ dmu_tx_commit(tx);
+ txg_wait_synced(zilog->zl_dmu_pool, txg);
+ }
+}
+
+/*
* Create an on-disk intent log.
*/
static lwb_t *
@@ -677,6 +709,8 @@ zil_create(zilog_t *zilog)
int error = 0;
boolean_t fastwrite = FALSE;
boolean_t slog = FALSE;
+ dsl_dataset_t *ds = dmu_objset_ds(zilog->zl_os);
+
/*
* Wait for any previous destroy to complete.
@@ -724,9 +758,33 @@ zil_create(zilog_t *zilog)
* (zh is part of the MOS, so we cannot modify it in open context.)
*/
if (tx != NULL) {
+ /*
+ * If "zilsaxattr" feature is enabled on zpool, then activate
+ * it now when we're creating the ZIL chain. We can't wait with
+ * this until we write the first xattr log record because we
+ * need to wait for the feature activation to sync out.
+ */
+ if (spa_feature_is_enabled(zilog->zl_spa,
+ SPA_FEATURE_ZILSAXATTR) && dmu_objset_type(zilog->zl_os) !=
+ DMU_OST_ZVOL) {
+ mutex_enter(&ds->ds_lock);
+ ds->ds_feature_activation[SPA_FEATURE_ZILSAXATTR] =
+ (void *)B_TRUE;
+ mutex_exit(&ds->ds_lock);
+ }
+
dmu_tx_commit(tx);
txg_wait_synced(zilog->zl_dmu_pool, txg);
+ } else {
+ /*
+ * This branch covers the case where we enable the feature on a
+ * zpool that has existing ZIL headers.
+ */
+ zil_commit_activate_saxattr_feature(zilog);
}
+ IMPLY(spa_feature_is_enabled(zilog->zl_spa, SPA_FEATURE_ZILSAXATTR) &&
+ dmu_objset_type(zilog->zl_os) != DMU_OST_ZVOL,
+ dsl_dataset_feature_is_active(ds, SPA_FEATURE_ZILSAXATTR));
ASSERT(error != 0 || bcmp(&blk, &zh->zh_log, sizeof (blk)) == 0);
IMPLY(error == 0, lwb != NULL);
@@ -2297,6 +2355,11 @@ zil_process_commit_list(zilog_t *zilog)
if (lwb == NULL) {
lwb = zil_create(zilog);
} else {
+ /*
+ * Activate SPA_FEATURE_ZILSAXATTR for the cases where ZIL will
+ * have already been created (zl_lwb_list not empty).
+ */
+ zil_commit_activate_saxattr_feature(zilog);
ASSERT3S(lwb->lwb_state, !=, LWB_STATE_ISSUED);
ASSERT3S(lwb->lwb_state, !=, LWB_STATE_WRITE_DONE);
ASSERT3S(lwb->lwb_state, !=, LWB_STATE_FLUSH_DONE);
@@ -3075,6 +3138,7 @@ zil_sync(zilog_t *zilog, dmu_tx_t *tx)
if (zilog->zl_destroy_txg == txg) {
blkptr_t blk = zh->zh_log;
+ dsl_dataset_t *ds = dmu_objset_ds(zilog->zl_os);
ASSERT(list_head(&zilog->zl_lwb_list) == NULL);
@@ -3092,6 +3156,16 @@ zil_sync(zilog_t *zilog, dmu_tx_t *tx)
*/
zil_init_log_chain(zilog, &blk);
zh->zh_log = blk;
+ } else {
+ /*
+ * A destroyed ZIL chain can't contain any TX_SETSAXATTR
+ * records. So, deactivate the feature for this dataset.
+ * We activate it again when we start a new ZIL chain.
+ */
+ if (dsl_dataset_feature_is_active(ds,
+ SPA_FEATURE_ZILSAXATTR))
+ dsl_dataset_deactivate_feature(ds,
+ SPA_FEATURE_ZILSAXATTR, tx);
}
}
@@ -3717,7 +3791,6 @@ EXPORT_SYMBOL(zil_bp_tree_add);
EXPORT_SYMBOL(zil_set_sync);
EXPORT_SYMBOL(zil_set_logbias);
-/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs, zfs_, commit_timeout_pct, INT, ZMOD_RW,
"ZIL block open timeout percentage");
@@ -3732,4 +3805,3 @@ ZFS_MODULE_PARAM(zfs_zil, zil_, slog_bulk, ULONG, ZMOD_RW,
ZFS_MODULE_PARAM(zfs_zil, zil_, maxblocksize, INT, ZMOD_RW,
"Limit in bytes of ZIL log block size");
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/zfs/zio.c b/sys/contrib/openzfs/module/zfs/zio.c
index 92115488c544..04a76c682045 100644
--- a/sys/contrib/openzfs/module/zfs/zio.c
+++ b/sys/contrib/openzfs/module/zfs/zio.c
@@ -1773,7 +1773,13 @@ zio_write_compress(zio_t *zio)
zio->io_abd, NULL, lsize, zp->zp_complevel);
if (psize == 0 || psize >= lsize)
compress = ZIO_COMPRESS_OFF;
- } else if (zio->io_flags & ZIO_FLAG_RAW_COMPRESS) {
+ } else if (zio->io_flags & ZIO_FLAG_RAW_COMPRESS &&
+ !(zio->io_flags & ZIO_FLAG_RAW_ENCRYPT)) {
+ /*
+ * If we are raw receiving an encrypted dataset we should not
+ * take this codepath because it will change the on-disk block
+ * and decryption will fail.
+ */
size_t rounded = MIN((size_t)roundup(psize,
spa->spa_min_alloc), lsize);
@@ -5034,7 +5040,6 @@ EXPORT_SYMBOL(zio_data_buf_alloc);
EXPORT_SYMBOL(zio_buf_free);
EXPORT_SYMBOL(zio_data_buf_free);
-/* BEGIN CSTYLED */
ZFS_MODULE_PARAM(zfs_zio, zio_, slow_io_ms, INT, ZMOD_RW,
"Max I/O completion time (milliseconds) before marking it as slow");
@@ -5055,4 +5060,3 @@ ZFS_MODULE_PARAM(zfs_zio, zio_, dva_throttle_enabled, INT, ZMOD_RW,
ZFS_MODULE_PARAM(zfs_zio, zio_, deadman_log_all, INT, ZMOD_RW,
"Log all slow ZIOs, not just those with vdevs");
-/* END CSTYLED */
diff --git a/sys/contrib/openzfs/module/zfs/zio_inject.c b/sys/contrib/openzfs/module/zfs/zio_inject.c
index feaf41dc65e3..cfc2e8f5b1d4 100644
--- a/sys/contrib/openzfs/module/zfs/zio_inject.c
+++ b/sys/contrib/openzfs/module/zfs/zio_inject.c
@@ -341,15 +341,14 @@ zio_handle_label_injection(zio_t *zio, int error)
return (ret);
}
-/*ARGSUSED*/
static int
zio_inject_bitflip_cb(void *data, size_t len, void *private)
{
- zio_t *zio __maybe_unused = private;
+ zio_t *zio = private;
uint8_t *buffer = data;
uint_t byte = random_in_range(len);
- ASSERT(zio->io_type == ZIO_TYPE_READ);
+ ASSERT3U(zio->io_type, ==, ZIO_TYPE_READ);
/* flip a single random bit in an abd data buffer */
buffer[byte] ^= 1 << random_in_range(8);
diff --git a/sys/contrib/openzfs/module/zfs/zthr.c b/sys/contrib/openzfs/module/zfs/zthr.c
index 52ddffae7aaa..2cb600a7124e 100644
--- a/sys/contrib/openzfs/module/zfs/zthr.c
+++ b/sys/contrib/openzfs/module/zfs/zthr.c
@@ -231,7 +231,7 @@ struct zthr {
const char *zthr_name;
};
-static void
+static _Noreturn void
zthr_procedure(void *arg)
{
zthr_t *t = arg;
diff --git a/sys/contrib/openzfs/module/zfs/zvol.c b/sys/contrib/openzfs/module/zfs/zvol.c
index e7010e77a83a..eb68b05c567b 100644
--- a/sys/contrib/openzfs/module/zfs/zvol.c
+++ b/sys/contrib/openzfs/module/zfs/zvol.c
@@ -92,7 +92,6 @@ unsigned int zvol_volmode = ZFS_VOLMODE_GEOM;
struct hlist_head *zvol_htable;
static list_t zvol_state_list;
krwlock_t zvol_state_lock;
-static const zvol_platform_ops_t *ops;
typedef enum {
ZVOL_ASYNC_REMOVE_MINORS,
@@ -365,7 +364,7 @@ out:
mutex_exit(&zv->zv_state_lock);
if (error == 0 && zv != NULL)
- ops->zv_update_volsize(zv, volsize);
+ zvol_os_update_volsize(zv, volsize);
return (SET_ERROR(error));
}
@@ -614,10 +613,10 @@ zvol_log_truncate(zvol_state_t *zv, dmu_tx_t *tx, uint64_t off, uint64_t len,
}
-/* ARGSUSED */
static void
zvol_get_done(zgd_t *zgd, int error)
{
+ (void) error;
if (zgd->zgd_db)
dmu_buf_rele(zgd->zgd_db, zgd);
@@ -747,15 +746,15 @@ zvol_setup_zv(zvol_state_t *zv)
if (error)
return (SET_ERROR(error));
- ops->zv_set_capacity(zv, volsize >> 9);
+ zvol_os_set_capacity(zv, volsize >> 9);
zv->zv_volsize = volsize;
if (ro || dmu_objset_is_snapshot(os) ||
!spa_writeable(dmu_objset_spa(os))) {
- ops->zv_set_disk_ro(zv, 1);
+ zvol_os_set_disk_ro(zv, 1);
zv->zv_flags |= ZVOL_RDONLY;
} else {
- ops->zv_set_disk_ro(zv, 0);
+ zvol_os_set_disk_ro(zv, 0);
zv->zv_flags &= ~ZVOL_RDONLY;
}
return (0);
@@ -1119,7 +1118,7 @@ zvol_create_minors_recursive(const char *name)
* taskq_dispatch to parallel prefetch zvol dnodes. Note we don't need
* any lock because all list operation is done on the current thread.
*
- * We will use this list to do zvol_create_minor_impl after prefetch
+ * We will use this list to do zvol_os_create_minor after prefetch
* so we don't have to traverse using dmu_objset_find again.
*/
list_create(&minors_list, sizeof (minors_job_t),
@@ -1133,7 +1132,7 @@ zvol_create_minors_recursive(const char *name)
&snapdev, NULL);
if (error == 0 && snapdev == ZFS_SNAPDEV_VISIBLE)
- (void) ops->zv_create_minor(name);
+ (void) zvol_os_create_minor(name);
} else {
fstrans_cookie_t cookie = spl_fstrans_mark();
(void) dmu_objset_find(name, zvol_create_minors_cb,
@@ -1144,13 +1143,13 @@ zvol_create_minors_recursive(const char *name)
taskq_wait_outstanding(system_taskq, 0);
/*
- * Prefetch is completed, we can do zvol_create_minor_impl
+ * Prefetch is completed, we can do zvol_os_create_minor
* sequentially.
*/
while ((job = list_head(&minors_list)) != NULL) {
list_remove(&minors_list, job);
if (!job->error)
- (void) ops->zv_create_minor(job->name);
+ (void) zvol_os_create_minor(job->name);
kmem_strfree(job->name);
kmem_free(job, sizeof (minors_job_t));
}
@@ -1180,9 +1179,9 @@ zvol_create_minor(const char *name)
"snapdev", &snapdev, NULL);
if (error == 0 && snapdev == ZFS_SNAPDEV_VISIBLE)
- (void) ops->zv_create_minor(name);
+ (void) zvol_os_create_minor(name);
} else {
- (void) ops->zv_create_minor(name);
+ (void) zvol_os_create_minor(name);
}
}
@@ -1193,7 +1192,7 @@ zvol_create_minor(const char *name)
static void
zvol_free_task(void *arg)
{
- ops->zv_free(arg);
+ zvol_os_free(arg);
}
void
@@ -1238,7 +1237,7 @@ zvol_remove_minors_impl(const char *name)
* Cleared while holding zvol_state_lock as a writer
* which will prevent zvol_open() from opening it.
*/
- ops->zv_clear_private(zv);
+ zvol_os_clear_private(zv);
/* Drop zv_state_lock before zvol_free() */
mutex_exit(&zv->zv_state_lock);
@@ -1257,7 +1256,7 @@ zvol_remove_minors_impl(const char *name)
/* Drop zvol_state_lock before calling zvol_free() */
while ((zv = list_head(&free_list)) != NULL) {
list_remove(&free_list, zv);
- ops->zv_free(zv);
+ zvol_os_free(zv);
}
}
@@ -1290,7 +1289,7 @@ zvol_remove_minor_impl(const char *name)
}
zvol_remove(zv);
- ops->zv_clear_private(zv);
+ zvol_os_clear_private(zv);
mutex_exit(&zv->zv_state_lock);
break;
} else {
@@ -1302,7 +1301,7 @@ zvol_remove_minor_impl(const char *name)
rw_exit(&zvol_state_lock);
if (zv != NULL)
- ops->zv_free(zv);
+ zvol_os_free(zv);
}
/*
@@ -1327,14 +1326,14 @@ zvol_rename_minors_impl(const char *oldname, const char *newname)
mutex_enter(&zv->zv_state_lock);
if (strcmp(zv->zv_name, oldname) == 0) {
- ops->zv_rename_minor(zv, newname);
+ zvol_os_rename_minor(zv, newname);
} else if (strncmp(zv->zv_name, oldname, oldnamelen) == 0 &&
(zv->zv_name[oldnamelen] == '/' ||
zv->zv_name[oldnamelen] == '@')) {
char *name = kmem_asprintf("%s%c%s", newname,
zv->zv_name[oldnamelen],
zv->zv_name + oldnamelen + 1);
- ops->zv_rename_minor(zv, name);
+ zvol_os_rename_minor(zv, name);
kmem_strfree(name);
}
@@ -1358,7 +1357,7 @@ zvol_set_snapdev_cb(const char *dsname, void *param)
switch (arg->snapdev) {
case ZFS_SNAPDEV_VISIBLE:
- (void) ops->zv_create_minor(dsname);
+ (void) zvol_os_create_minor(dsname);
break;
case ZFS_SNAPDEV_HIDDEN:
(void) zvol_remove_minor_impl(dsname);
@@ -1415,14 +1414,14 @@ zvol_set_volmode_impl(char *name, uint64_t volmode)
case ZFS_VOLMODE_GEOM:
case ZFS_VOLMODE_DEV:
(void) zvol_remove_minor_impl(name);
- (void) ops->zv_create_minor(name);
+ (void) zvol_os_create_minor(name);
break;
case ZFS_VOLMODE_DEFAULT:
(void) zvol_remove_minor_impl(name);
if (zvol_volmode == ZFS_VOLMODE_NONE)
break;
else /* if zvol_volmode is invalid defaults to "geom" */
- (void) ops->zv_create_minor(name);
+ (void) zvol_os_create_minor(name);
break;
}
spl_fstrans_unmark(cookie);
@@ -1512,10 +1511,10 @@ zvol_set_snapdev_check(void *arg, dmu_tx_t *tx)
return (error);
}
-/* ARGSUSED */
static int
zvol_set_snapdev_sync_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg)
{
+ (void) arg;
char dsname[MAXNAMELEN];
zvol_task_t *task;
uint64_t snapdev;
@@ -1598,10 +1597,10 @@ zvol_set_volmode_check(void *arg, dmu_tx_t *tx)
return (error);
}
-/* ARGSUSED */
static int
zvol_set_volmode_sync_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg)
{
+ (void) arg;
char dsname[MAXNAMELEN];
zvol_task_t *task;
uint64_t volmode;
@@ -1699,13 +1698,7 @@ boolean_t
zvol_is_zvol(const char *name)
{
- return (ops->zv_is_zvol(name));
-}
-
-void
-zvol_register_ops(const zvol_platform_ops_t *zvol_ops)
-{
- ops = zvol_ops;
+ return (zvol_os_is_zvol(name));
}
int
diff --git a/sys/contrib/openzfs/module/zstd/Makefile.in b/sys/contrib/openzfs/module/zstd/Makefile.in
index 091f7cea3639..ec174e9b012e 100644
--- a/sys/contrib/openzfs/module/zstd/Makefile.in
+++ b/sys/contrib/openzfs/module/zstd/Makefile.in
@@ -18,22 +18,47 @@ ccflags-y += -O3
# -fno-tree-vectorize gets set for gcc in zstd/common/compiler.h
# Set it for other compilers, too.
-$(obj)/lib/zstd.o: c_flags += -fno-tree-vectorize
+common_flags := -fno-tree-vectorize
# SSE register return with SSE disabled if -march=znverX is passed
-$(obj)/lib/zstd.o: c_flags += -U__BMI__
+common_flags += -U__BMI__
# Quiet warnings about frame size due to unused code in unmodified zstd lib
-$(obj)/lib/zstd.o: c_flags += -Wframe-larger-than=20480
+common_flags += -Wframe-larger-than=20480
+
+ccflags-y += $(common_flags)
+
+vanilla-objs := lib/common/entropy_common.o \
+ lib/common/error_private.o \
+ lib/common/fse_decompress.o \
+ lib/common/pool.o \
+ lib/common/zstd_common.o \
+ lib/compress/fse_compress.o \
+ lib/compress/hist.o \
+ lib/compress/huf_compress.o \
+ lib/compress/zstd_compress_literals.o \
+ lib/compress/zstd_compress_sequences.o \
+ lib/compress/zstd_compress_superblock.o \
+ lib/compress/zstd_compress.o \
+ lib/compress/zstd_double_fast.o \
+ lib/compress/zstd_fast.o \
+ lib/compress/zstd_lazy.o \
+ lib/compress/zstd_ldm.o \
+ lib/compress/zstd_opt.o \
+ lib/decompress/huf_decompress.o \
+ lib/decompress/zstd_ddict.o \
+ lib/decompress/zstd_decompress.o \
+ lib/decompress/zstd_decompress_block.o
# Disable aarch64 neon SIMD instructions for kernel mode
-$(obj)/lib/zstd.o: c_flags += -include $(zstd_include)/aarch64_compat.h -include $(zstd_include)/zstd_compat_wrapper.h -Wp,-w
+$(addprefix $(obj)/,$(vanilla-objs)) : ccflags-y += -include $(zstd_include)/aarch64_compat.h -include $(zstd_include)/zstd_compat_wrapper.h -Wp,-w $(common_flags)
-$(obj)/zfs_zstd.o: c_flags += -include $(zstd_include)/zstd_compat_wrapper.h
+$(obj)/zfs_zstd.o: ccflags-y += -include $(zstd_include)/zstd_compat_wrapper.h $(common_flags)
$(MODULE)-objs += zfs_zstd.o
-$(MODULE)-objs += lib/zstd.o
$(MODULE)-objs += zstd_sparc.o
+$(MODULE)-objs += $(vanilla-objs)
all:
- mkdir -p lib
+ mkdir -p lib/common lib/compress lib/decompress
+
diff --git a/sys/contrib/openzfs/module/zstd/README.md b/sys/contrib/openzfs/module/zstd/README.md
index eed229e2f78f..26d618b61b6e 100644
--- a/sys/contrib/openzfs/module/zstd/README.md
+++ b/sys/contrib/openzfs/module/zstd/README.md
@@ -10,9 +10,8 @@ library, besides upgrading to a newer ZSTD release.
Tree structure:
* `zfs_zstd.c` is the actual `zzstd` kernel module.
-* `lib/` contains the unmodified, [_"amalgamated"_](https://github.com/facebook/zstd/blob/dev/contrib/single_file_libs/README.md)
- version of the `Zstandard` library, generated from our template file
-* `zstd-in.c` is our template file for generating the library
+* `lib/` contains the unmodified version of the `Zstandard` library
+* `zstd-in.c` is our template file for generating the single-file library
* `include/`: This directory contains supplemental includes for platform
compatibility, which are not expected to be used by ZFS elsewhere in the
future. Thus we keep them private to ZSTD.
@@ -22,36 +21,19 @@ Tree structure:
To update ZSTD the following steps need to be taken:
1. Grab the latest release of [ZSTD](https://github.com/facebook/zstd/releases).
-2. Update `module/zstd/zstd-in.c` if required. (see
- `zstd/contrib/single_file_libs/zstd-in.c` in the zstd repository)
-3. Generate the "single-file-library" and put it to `module/zstd/lib/`.
-4. Copy the following files to `module/zstd/lib/`:
- - `zstd/lib/zstd.h`
- - `zstd/lib/common/zstd_errors.h`
+2. Copy the files output by the following script to `module/zstd/lib/`:
+`grep include [path to zstd]/contrib/single_file_libs/zstd-in.c | awk '{ print $2 }'`
+3. Remove debug.c, threading.c, and zstdmt_compress.c.
+4. Update Makefiles with resulting file lists.
-This can be done using a few shell commands from inside the zfs repo:
-
-~~~sh
-cd PATH/TO/ZFS
-
-url="https://github.com/facebook/zstd"
-release="$(curl -s "${url}"/releases/latest | grep -oP '(?<=v)[\d\.]+')"
-zstd="/tmp/zstd-${release}/"
-
-wget -O /tmp/zstd.tar.gz \
- "${url}/releases/download/v${release}/zstd-${release}.tar.gz"
-tar -C /tmp -xzf /tmp/zstd.tar.gz
-
-cp ${zstd}/lib/zstd.h module/zstd/lib/
-cp ${zstd}/lib/zstd_errors.h module/zstd/lib/
-${zstd}/contrib/single_file_libs/combine.sh \
- -r ${zstd}/lib -o module/zstd/lib/zstd.c module/zstd/zstd-in.c
~~~
Note: if the zstd library for zfs is updated to a newer version,
the macro list in include/zstd_compat_wrapper.h 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
+script (on the object file generated from the "single-file library" script in zstd's
+contrib/single_file_libs):
+`nm zstd.o | awk '{print "#define "$3 " zfs_" $3}' > macrotable`
## Altering ZSTD and breaking changes
diff --git a/sys/contrib/openzfs/module/zstd/include/string.h b/sys/contrib/openzfs/module/zstd/include/string.h
index 78998d3c4655..7474e7f1af0f 100644
--- a/sys/contrib/openzfs/module/zstd/include/string.h
+++ b/sys/contrib/openzfs/module/zstd/include/string.h
@@ -44,6 +44,7 @@ extern "C" {
#ifdef _KERNEL
#if defined(__FreeBSD__)
+#include <sys/types.h> /* u_int, u_char */
#include <sys/systm.h> /* memcpy, memset */
#elif defined(__linux__)
#include <linux/string.h> /* memcpy, memset */
diff --git a/sys/contrib/openzfs/module/zstd/include/zstd_compat_wrapper.h b/sys/contrib/openzfs/module/zstd/include/zstd_compat_wrapper.h
index 339713590f96..c39dfa2db933 100644
--- a/sys/contrib/openzfs/module/zstd/include/zstd_compat_wrapper.h
+++ b/sys/contrib/openzfs/module/zstd/include/zstd_compat_wrapper.h
@@ -45,6 +45,20 @@
* nm zstd.o | awk '{print "#define "$3 " zfs_" $3}' > macrotable
*/
+#define MEM_MODULE
+#define XXH_NAMESPACE ZSTD_
+#define XXH_PRIVATE_API
+#define XXH_INLINE_ALL
+#define ZSTD_LEGACY_SUPPORT 0
+#define ZSTD_LIB_DICTBUILDER 0
+#define ZSTD_LIB_DEPRECATED 0
+#define ZSTD_NOBENCH
+#define DEBUGLEVEL 0
+#ifdef _KERNEL
+#define ZSTD_DEPS_ASSERT
+#endif
+
+
#define BIT_initDStream zfs_BIT_initDStream
#define BIT_mask zfs_BIT_mask
#define BIT_reloadDStream zfs_BIT_reloadDStream
diff --git a/sys/contrib/openzfs/module/zstd/lib/common/bitstream.h b/sys/contrib/openzfs/module/zstd/lib/common/bitstream.h
new file mode 100644
index 000000000000..37b99c01eed3
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/common/bitstream.h
@@ -0,0 +1,454 @@
+/* ******************************************************************
+ * bitstream
+ * Part of FSE library
+ * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ *
+ * You can contact the author at :
+ * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+****************************************************************** */
+#ifndef BITSTREAM_H_MODULE
+#define BITSTREAM_H_MODULE
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+/*
+* This API consists of small unitary functions, which must be inlined for best performance.
+* Since link-time-optimization is not available for all compilers,
+* these functions are defined into a .h to be included.
+*/
+
+/*-****************************************
+* Dependencies
+******************************************/
+#include "mem.h" /* unaligned access routines */
+#include "compiler.h" /* UNLIKELY() */
+#include "debug.h" /* assert(), DEBUGLOG(), RAWLOG() */
+#include "error_private.h" /* error codes and messages */
+
+
+/*=========================================
+* Target specific
+=========================================*/
+#if defined(__BMI__) && defined(__GNUC__)
+# include <immintrin.h> /* support for bextr (experimental) */
+#elif defined(__ICCARM__)
+# include <intrinsics.h>
+#endif
+
+#define STREAM_ACCUMULATOR_MIN_32 25
+#define STREAM_ACCUMULATOR_MIN_64 57
+#define STREAM_ACCUMULATOR_MIN ((U32)(MEM_32bits() ? STREAM_ACCUMULATOR_MIN_32 : STREAM_ACCUMULATOR_MIN_64))
+
+
+/*-******************************************
+* bitStream encoding API (write forward)
+********************************************/
+/* bitStream can mix input from multiple sources.
+ * A critical property of these streams is that they encode and decode in **reverse** direction.
+ * So the first bit sequence you add will be the last to be read, like a LIFO stack.
+ */
+typedef struct {
+ size_t bitContainer;
+ unsigned bitPos;
+ char* startPtr;
+ char* ptr;
+ char* endPtr;
+} BIT_CStream_t;
+
+MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, void* dstBuffer, size_t dstCapacity);
+MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits);
+MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC);
+MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC);
+
+/* Start with initCStream, providing the size of buffer to write into.
+* bitStream will never write outside of this buffer.
+* `dstCapacity` must be >= sizeof(bitD->bitContainer), otherwise @return will be an error code.
+*
+* bits are first added to a local register.
+* Local register is size_t, hence 64-bits on 64-bits systems, or 32-bits on 32-bits systems.
+* Writing data into memory is an explicit operation, performed by the flushBits function.
+* Hence keep track how many bits are potentially stored into local register to avoid register overflow.
+* After a flushBits, a maximum of 7 bits might still be stored into local register.
+*
+* Avoid storing elements of more than 24 bits if you want compatibility with 32-bits bitstream readers.
+*
+* Last operation is to close the bitStream.
+* The function returns the final size of CStream in bytes.
+* If data couldn't fit into `dstBuffer`, it will return a 0 ( == not storable)
+*/
+
+
+/*-********************************************
+* bitStream decoding API (read backward)
+**********************************************/
+typedef struct {
+ size_t bitContainer;
+ unsigned bitsConsumed;
+ const char* ptr;
+ const char* start;
+ const char* limitPtr;
+} BIT_DStream_t;
+
+typedef enum { BIT_DStream_unfinished = 0,
+ BIT_DStream_endOfBuffer = 1,
+ BIT_DStream_completed = 2,
+ BIT_DStream_overflow = 3 } BIT_DStream_status; /* result of BIT_reloadDStream() */
+ /* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */
+
+MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize);
+MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits);
+MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD);
+MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD);
+
+
+/* Start by invoking BIT_initDStream().
+* A chunk of the bitStream is then stored into a local register.
+* Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
+* You can then retrieve bitFields stored into the local register, **in reverse order**.
+* Local register is explicitly reloaded from memory by the BIT_reloadDStream() method.
+* A reload guarantee a minimum of ((8*sizeof(bitD->bitContainer))-7) bits when its result is BIT_DStream_unfinished.
+* Otherwise, it can be less than that, so proceed accordingly.
+* Checking if DStream has reached its end can be performed with BIT_endOfDStream().
+*/
+
+
+/*-****************************************
+* unsafe API
+******************************************/
+MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, size_t value, unsigned nbBits);
+/* faster, but works only if value is "clean", meaning all high bits above nbBits are 0 */
+
+MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC);
+/* unsafe version; does not check buffer overflow */
+
+MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits);
+/* faster, but works only if nbBits >= 1 */
+
+
+
+/*-**************************************************************
+* Internal functions
+****************************************************************/
+MEM_STATIC unsigned BIT_highbit32 (U32 val)
+{
+ assert(val != 0);
+ {
+# if defined(_MSC_VER) /* Visual */
+ unsigned long r=0;
+ return _BitScanReverse ( &r, val ) ? (unsigned)r : 0;
+# elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */
+ return __builtin_clz (val) ^ 31;
+# elif defined(__ICCARM__) /* IAR Intrinsic */
+ return 31 - __CLZ(val);
+# else /* Software version */
+ static const unsigned DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29,
+ 11, 14, 16, 18, 22, 25, 3, 30,
+ 8, 12, 20, 28, 15, 17, 24, 7,
+ 19, 27, 23, 6, 26, 5, 4, 31 };
+ U32 v = val;
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+ return DeBruijnClz[ (U32) (v * 0x07C4ACDDU) >> 27];
+# endif
+ }
+}
+
+/*===== Local Constants =====*/
+static const unsigned BIT_mask[] = {
+ 0, 1, 3, 7, 0xF, 0x1F,
+ 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF,
+ 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0x1FFFF,
+ 0x3FFFF, 0x7FFFF, 0xFFFFF, 0x1FFFFF, 0x3FFFFF, 0x7FFFFF,
+ 0xFFFFFF, 0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF, 0x1FFFFFFF,
+ 0x3FFFFFFF, 0x7FFFFFFF}; /* up to 31 bits */
+#define BIT_MASK_SIZE (sizeof(BIT_mask) / sizeof(BIT_mask[0]))
+
+/*-**************************************************************
+* bitStream encoding
+****************************************************************/
+/*! BIT_initCStream() :
+ * `dstCapacity` must be > sizeof(size_t)
+ * @return : 0 if success,
+ * otherwise an error code (can be tested using ERR_isError()) */
+MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC,
+ void* startPtr, size_t dstCapacity)
+{
+ bitC->bitContainer = 0;
+ bitC->bitPos = 0;
+ bitC->startPtr = (char*)startPtr;
+ bitC->ptr = bitC->startPtr;
+ bitC->endPtr = bitC->startPtr + dstCapacity - sizeof(bitC->bitContainer);
+ if (dstCapacity <= sizeof(bitC->bitContainer)) return ERROR(dstSize_tooSmall);
+ return 0;
+}
+
+/*! BIT_addBits() :
+ * can add up to 31 bits into `bitC`.
+ * Note : does not check for register overflow ! */
+MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC,
+ size_t value, unsigned nbBits)
+{
+ MEM_STATIC_ASSERT(BIT_MASK_SIZE == 32);
+ assert(nbBits < BIT_MASK_SIZE);
+ assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8);
+ bitC->bitContainer |= (value & BIT_mask[nbBits]) << bitC->bitPos;
+ bitC->bitPos += nbBits;
+}
+
+/*! BIT_addBitsFast() :
+ * works only if `value` is _clean_,
+ * meaning all high bits above nbBits are 0 */
+MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC,
+ size_t value, unsigned nbBits)
+{
+ assert((value>>nbBits) == 0);
+ assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8);
+ bitC->bitContainer |= value << bitC->bitPos;
+ bitC->bitPos += nbBits;
+}
+
+/*! BIT_flushBitsFast() :
+ * assumption : bitContainer has not overflowed
+ * unsafe version; does not check buffer overflow */
+MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC)
+{
+ size_t const nbBytes = bitC->bitPos >> 3;
+ assert(bitC->bitPos < sizeof(bitC->bitContainer) * 8);
+ assert(bitC->ptr <= bitC->endPtr);
+ MEM_writeLEST(bitC->ptr, bitC->bitContainer);
+ bitC->ptr += nbBytes;
+ bitC->bitPos &= 7;
+ bitC->bitContainer >>= nbBytes*8;
+}
+
+/*! BIT_flushBits() :
+ * assumption : bitContainer has not overflowed
+ * safe version; check for buffer overflow, and prevents it.
+ * note : does not signal buffer overflow.
+ * overflow will be revealed later on using BIT_closeCStream() */
+MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC)
+{
+ size_t const nbBytes = bitC->bitPos >> 3;
+ assert(bitC->bitPos < sizeof(bitC->bitContainer) * 8);
+ assert(bitC->ptr <= bitC->endPtr);
+ MEM_writeLEST(bitC->ptr, bitC->bitContainer);
+ bitC->ptr += nbBytes;
+ if (bitC->ptr > bitC->endPtr) bitC->ptr = bitC->endPtr;
+ bitC->bitPos &= 7;
+ bitC->bitContainer >>= nbBytes*8;
+}
+
+/*! BIT_closeCStream() :
+ * @return : size of CStream, in bytes,
+ * or 0 if it could not fit into dstBuffer */
+MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC)
+{
+ BIT_addBitsFast(bitC, 1, 1); /* endMark */
+ BIT_flushBits(bitC);
+ if (bitC->ptr >= bitC->endPtr) return 0; /* overflow detected */
+ return (bitC->ptr - bitC->startPtr) + (bitC->bitPos > 0);
+}
+
+
+/*-********************************************************
+* bitStream decoding
+**********************************************************/
+/*! BIT_initDStream() :
+ * Initialize a BIT_DStream_t.
+ * `bitD` : a pointer to an already allocated BIT_DStream_t structure.
+ * `srcSize` must be the *exact* size of the bitStream, in bytes.
+ * @return : size of stream (== srcSize), or an errorCode if a problem is detected
+ */
+MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize)
+{
+ if (srcSize < 1) { memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); }
+
+ bitD->start = (const char*)srcBuffer;
+ bitD->limitPtr = bitD->start + sizeof(bitD->bitContainer);
+
+ if (srcSize >= sizeof(bitD->bitContainer)) { /* normal case */
+ bitD->ptr = (const char*)srcBuffer + srcSize - sizeof(bitD->bitContainer);
+ bitD->bitContainer = MEM_readLEST(bitD->ptr);
+ { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];
+ bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; /* ensures bitsConsumed is always set */
+ if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ }
+ } else {
+ bitD->ptr = bitD->start;
+ bitD->bitContainer = *(const BYTE*)(bitD->start);
+ switch(srcSize)
+ {
+ case 7: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16);
+ /* fall-through */
+
+ case 6: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24);
+ /* fall-through */
+
+ case 5: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32);
+ /* fall-through */
+
+ case 4: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[3]) << 24;
+ /* fall-through */
+
+ case 3: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[2]) << 16;
+ /* fall-through */
+
+ case 2: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[1]) << 8;
+ /* fall-through */
+
+ default: break;
+ }
+ { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];
+ bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0;
+ if (lastByte == 0) return ERROR(corruption_detected); /* endMark not present */
+ }
+ bitD->bitsConsumed += (U32)(sizeof(bitD->bitContainer) - srcSize)*8;
+ }
+
+ return srcSize;
+}
+
+MEM_STATIC size_t BIT_getUpperBits(size_t bitContainer, U32 const start)
+{
+ return bitContainer >> start;
+}
+
+MEM_STATIC size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits)
+{
+ U32 const regMask = sizeof(bitContainer)*8 - 1;
+ /* if start > regMask, bitstream is corrupted, and result is undefined */
+ assert(nbBits < BIT_MASK_SIZE);
+ return (bitContainer >> (start & regMask)) & BIT_mask[nbBits];
+}
+
+MEM_STATIC size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits)
+{
+ assert(nbBits < BIT_MASK_SIZE);
+ return bitContainer & BIT_mask[nbBits];
+}
+
+/*! BIT_lookBits() :
+ * Provides next n bits from local register.
+ * local register is not modified.
+ * On 32-bits, maxNbBits==24.
+ * On 64-bits, maxNbBits==56.
+ * @return : value extracted */
+MEM_STATIC size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits)
+{
+ /* arbitrate between double-shift and shift+mask */
+#if 1
+ /* if bitD->bitsConsumed + nbBits > sizeof(bitD->bitContainer)*8,
+ * bitstream is likely corrupted, and result is undefined */
+ return BIT_getMiddleBits(bitD->bitContainer, (sizeof(bitD->bitContainer)*8) - bitD->bitsConsumed - nbBits, nbBits);
+#else
+ /* this code path is slower on my os-x laptop */
+ U32 const regMask = sizeof(bitD->bitContainer)*8 - 1;
+ return ((bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> 1) >> ((regMask-nbBits) & regMask);
+#endif
+}
+
+/*! BIT_lookBitsFast() :
+ * unsafe version; only works if nbBits >= 1 */
+MEM_STATIC size_t BIT_lookBitsFast(const BIT_DStream_t* bitD, U32 nbBits)
+{
+ U32 const regMask = sizeof(bitD->bitContainer)*8 - 1;
+ assert(nbBits >= 1);
+ return (bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> (((regMask+1)-nbBits) & regMask);
+}
+
+MEM_STATIC void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits)
+{
+ bitD->bitsConsumed += nbBits;
+}
+
+/*! BIT_readBits() :
+ * Read (consume) next n bits from local register and update.
+ * Pay attention to not read more than nbBits contained into local register.
+ * @return : extracted value. */
+MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits)
+{
+ size_t const value = BIT_lookBits(bitD, nbBits);
+ BIT_skipBits(bitD, nbBits);
+ return value;
+}
+
+/*! BIT_readBitsFast() :
+ * unsafe version; only works only if nbBits >= 1 */
+MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits)
+{
+ size_t const value = BIT_lookBitsFast(bitD, nbBits);
+ assert(nbBits >= 1);
+ BIT_skipBits(bitD, nbBits);
+ return value;
+}
+
+/*! BIT_reloadDStreamFast() :
+ * Similar to BIT_reloadDStream(), but with two differences:
+ * 1. bitsConsumed <= sizeof(bitD->bitContainer)*8 must hold!
+ * 2. Returns BIT_DStream_overflow when bitD->ptr < bitD->limitPtr, at this
+ * point you must use BIT_reloadDStream() to reload.
+ */
+MEM_STATIC BIT_DStream_status BIT_reloadDStreamFast(BIT_DStream_t* bitD)
+{
+ if (UNLIKELY(bitD->ptr < bitD->limitPtr))
+ return BIT_DStream_overflow;
+ assert(bitD->bitsConsumed <= sizeof(bitD->bitContainer)*8);
+ bitD->ptr -= bitD->bitsConsumed >> 3;
+ bitD->bitsConsumed &= 7;
+ bitD->bitContainer = MEM_readLEST(bitD->ptr);
+ return BIT_DStream_unfinished;
+}
+
+/*! BIT_reloadDStream() :
+ * Refill `bitD` from buffer previously set in BIT_initDStream() .
+ * This function is safe, it guarantees it will not read beyond src buffer.
+ * @return : status of `BIT_DStream_t` internal register.
+ * when status == BIT_DStream_unfinished, internal register is filled with at least 25 or 57 bits */
+MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD)
+{
+ if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* overflow detected, like end of stream */
+ return BIT_DStream_overflow;
+
+ if (bitD->ptr >= bitD->limitPtr) {
+ return BIT_reloadDStreamFast(bitD);
+ }
+ if (bitD->ptr == bitD->start) {
+ if (bitD->bitsConsumed < sizeof(bitD->bitContainer)*8) return BIT_DStream_endOfBuffer;
+ return BIT_DStream_completed;
+ }
+ /* start < ptr < limitPtr */
+ { U32 nbBytes = bitD->bitsConsumed >> 3;
+ BIT_DStream_status result = BIT_DStream_unfinished;
+ if (bitD->ptr - nbBytes < bitD->start) {
+ nbBytes = (U32)(bitD->ptr - bitD->start); /* ptr > start */
+ result = BIT_DStream_endOfBuffer;
+ }
+ bitD->ptr -= nbBytes;
+ bitD->bitsConsumed -= nbBytes*8;
+ bitD->bitContainer = MEM_readLEST(bitD->ptr); /* reminder : srcSize > sizeof(bitD->bitContainer), otherwise bitD->ptr == bitD->start */
+ return result;
+ }
+}
+
+/*! BIT_endOfDStream() :
+ * @return : 1 if DStream has _exactly_ reached its end (all bits consumed).
+ */
+MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* DStream)
+{
+ return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == sizeof(DStream->bitContainer)*8));
+}
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* BITSTREAM_H_MODULE */
diff --git a/sys/contrib/openzfs/module/zstd/lib/common/compiler.h b/sys/contrib/openzfs/module/zstd/lib/common/compiler.h
new file mode 100644
index 000000000000..95e9483521d4
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/common/compiler.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_COMPILER_H
+#define ZSTD_COMPILER_H
+
+/*-*******************************************************
+* Compiler specifics
+*********************************************************/
+/* force inlining */
+
+#if !defined(ZSTD_NO_INLINE)
+#if (defined(__GNUC__) && !defined(__STRICT_ANSI__)) || defined(__cplusplus) || defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
+# define INLINE_KEYWORD inline
+#else
+# define INLINE_KEYWORD
+#endif
+
+#if defined(__GNUC__) || defined(__ICCARM__)
+# define FORCE_INLINE_ATTR __attribute__((always_inline))
+#elif defined(_MSC_VER)
+# define FORCE_INLINE_ATTR __forceinline
+#else
+# define FORCE_INLINE_ATTR
+#endif
+
+#else
+
+#define INLINE_KEYWORD
+#define FORCE_INLINE_ATTR
+
+#endif
+
+/**
+ * FORCE_INLINE_TEMPLATE is used to define C "templates", which take constant
+ * parameters. They must be inlined for the compiler to eliminate the constant
+ * branches.
+ */
+#define FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR
+/**
+ * HINT_INLINE is used to help the compiler generate better code. It is *not*
+ * used for "templates", so it can be tweaked based on the compilers
+ * performance.
+ *
+ * gcc-4.8 and gcc-4.9 have been shown to benefit from leaving off the
+ * always_inline attribute.
+ *
+ * clang up to 5.0.0 (trunk) benefit tremendously from the always_inline
+ * attribute.
+ */
+#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8 && __GNUC__ < 5
+# define HINT_INLINE static INLINE_KEYWORD
+#else
+# define HINT_INLINE static INLINE_KEYWORD FORCE_INLINE_ATTR
+#endif
+
+/* UNUSED_ATTR tells the compiler it is okay if the function is unused. */
+#if defined(__GNUC__)
+# define UNUSED_ATTR __attribute__((unused))
+#else
+# define UNUSED_ATTR
+#endif
+
+/* force no inlining */
+#ifdef _MSC_VER
+# define FORCE_NOINLINE static __declspec(noinline)
+#else
+# if defined(__GNUC__) || defined(__ICCARM__)
+# define FORCE_NOINLINE static __attribute__((__noinline__))
+# else
+# define FORCE_NOINLINE static
+# endif
+#endif
+
+/* target attribute */
+#ifndef __has_attribute
+ #define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
+#endif
+#if defined(__GNUC__) || defined(__ICCARM__)
+# define TARGET_ATTRIBUTE(target) __attribute__((__target__(target)))
+#else
+# define TARGET_ATTRIBUTE(target)
+#endif
+
+/* Enable runtime BMI2 dispatch based on the CPU.
+ * Enabled for clang & gcc >=4.8 on x86 when BMI2 isn't enabled by default.
+ */
+#ifndef DYNAMIC_BMI2
+ #if ((defined(__clang__) && __has_attribute(__target__)) \
+ || (defined(__GNUC__) \
+ && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))) \
+ && (defined(__x86_64__) || defined(_M_X86)) \
+ && !defined(__BMI2__)
+ # define DYNAMIC_BMI2 1
+ #else
+ # define DYNAMIC_BMI2 0
+ #endif
+#endif
+
+/* prefetch
+ * can be disabled, by declaring NO_PREFETCH build macro */
+#if defined(NO_PREFETCH)
+# define PREFETCH_L1(ptr) (void)(ptr) /* disabled */
+# define PREFETCH_L2(ptr) (void)(ptr) /* disabled */
+#else
+# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) /* _mm_prefetch() is not defined outside of x86/x64 */
+# include <mmintrin.h> /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */
+# define PREFETCH_L1(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0)
+# define PREFETCH_L2(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T1)
+# elif defined(__aarch64__)
+# define PREFETCH_L1(ptr) __asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr)))
+# define PREFETCH_L2(ptr) __asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr)))
+# elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) )
+# define PREFETCH_L1(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */)
+# define PREFETCH_L2(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 2 /* locality */)
+# else
+# define PREFETCH_L1(ptr) (void)(ptr) /* disabled */
+# define PREFETCH_L2(ptr) (void)(ptr) /* disabled */
+# endif
+#endif /* NO_PREFETCH */
+
+#define CACHELINE_SIZE 64
+
+#define PREFETCH_AREA(p, s) { \
+ const char* const _ptr = (const char*)(p); \
+ size_t const _size = (size_t)(s); \
+ size_t _pos; \
+ for (_pos=0; _pos<_size; _pos+=CACHELINE_SIZE) { \
+ PREFETCH_L2(_ptr + _pos); \
+ } \
+}
+
+/* vectorization
+ * older GCC (pre gcc-4.3 picked as the cutoff) uses a different syntax */
+#if !defined(__INTEL_COMPILER) && !defined(__clang__) && defined(__GNUC__)
+# if (__GNUC__ == 4 && __GNUC_MINOR__ > 3) || (__GNUC__ >= 5)
+# define DONT_VECTORIZE __attribute__((optimize("no-tree-vectorize")))
+# else
+# define DONT_VECTORIZE _Pragma("GCC optimize(\"no-tree-vectorize\")")
+# endif
+#else
+# define DONT_VECTORIZE
+#endif
+
+/* Tell the compiler that a branch is likely or unlikely.
+ * Only use these macros if it causes the compiler to generate better code.
+ * If you can remove a LIKELY/UNLIKELY annotation without speed changes in gcc
+ * and clang, please do.
+ */
+#if defined(__GNUC__)
+#define LIKELY(x) (__builtin_expect((x), 1))
+#define UNLIKELY(x) (__builtin_expect((x), 0))
+#else
+#define LIKELY(x) (x)
+#define UNLIKELY(x) (x)
+#endif
+
+/* disable warnings */
+#ifdef _MSC_VER /* Visual Studio */
+# include <intrin.h> /* For Visual 2005 */
+# pragma warning(disable : 4100) /* disable: C4100: unreferenced formal parameter */
+# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
+# pragma warning(disable : 4204) /* disable: C4204: non-constant aggregate initializer */
+# pragma warning(disable : 4214) /* disable: C4214: non-int bitfields */
+# pragma warning(disable : 4324) /* disable: C4324: padded structure */
+#endif
+
+#endif /* ZSTD_COMPILER_H */
diff --git a/sys/contrib/openzfs/module/zstd/lib/common/cpu.h b/sys/contrib/openzfs/module/zstd/lib/common/cpu.h
new file mode 100644
index 000000000000..6e8a974f62d7
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/common/cpu.h
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2018-2020, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_COMMON_CPU_H
+#define ZSTD_COMMON_CPU_H
+
+/**
+ * Implementation taken from folly/CpuId.h
+ * https://github.com/facebook/folly/blob/master/folly/CpuId.h
+ */
+
+#include <string.h>
+
+#include "mem.h"
+
+#ifdef _MSC_VER
+#include <intrin.h>
+#endif
+
+typedef struct {
+ U32 f1c;
+ U32 f1d;
+ U32 f7b;
+ U32 f7c;
+} ZSTD_cpuid_t;
+
+MEM_STATIC ZSTD_cpuid_t ZSTD_cpuid(void) {
+ U32 f1c = 0;
+ U32 f1d = 0;
+ U32 f7b = 0;
+ U32 f7c = 0;
+#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86))
+ int reg[4];
+ __cpuid((int*)reg, 0);
+ {
+ int const n = reg[0];
+ if (n >= 1) {
+ __cpuid((int*)reg, 1);
+ f1c = (U32)reg[2];
+ f1d = (U32)reg[3];
+ }
+ if (n >= 7) {
+ __cpuidex((int*)reg, 7, 0);
+ f7b = (U32)reg[1];
+ f7c = (U32)reg[2];
+ }
+ }
+#elif defined(__i386__) && defined(__PIC__) && !defined(__clang__) && defined(__GNUC__)
+ /* The following block like the normal cpuid branch below, but gcc
+ * reserves ebx for use of its pic register so we must specially
+ * handle the save and restore to avoid clobbering the register
+ */
+ U32 n;
+ __asm__(
+ "pushl %%ebx\n\t"
+ "cpuid\n\t"
+ "popl %%ebx\n\t"
+ : "=a"(n)
+ : "a"(0)
+ : "ecx", "edx");
+ if (n >= 1) {
+ U32 f1a;
+ __asm__(
+ "pushl %%ebx\n\t"
+ "cpuid\n\t"
+ "popl %%ebx\n\t"
+ : "=a"(f1a), "=c"(f1c), "=d"(f1d)
+ : "a"(1));
+ }
+ if (n >= 7) {
+ __asm__(
+ "pushl %%ebx\n\t"
+ "cpuid\n\t"
+ "movl %%ebx, %%eax\n\t"
+ "popl %%ebx"
+ : "=a"(f7b), "=c"(f7c)
+ : "a"(7), "c"(0)
+ : "edx");
+ }
+#elif defined(__x86_64__) || defined(_M_X64) || defined(__i386__)
+ U32 n;
+ __asm__("cpuid" : "=a"(n) : "a"(0) : "ebx", "ecx", "edx");
+ if (n >= 1) {
+ U32 f1a;
+ __asm__("cpuid" : "=a"(f1a), "=c"(f1c), "=d"(f1d) : "a"(1) : "ebx");
+ }
+ if (n >= 7) {
+ U32 f7a;
+ __asm__("cpuid"
+ : "=a"(f7a), "=b"(f7b), "=c"(f7c)
+ : "a"(7), "c"(0)
+ : "edx");
+ }
+#endif
+ {
+ ZSTD_cpuid_t cpuid;
+ cpuid.f1c = f1c;
+ cpuid.f1d = f1d;
+ cpuid.f7b = f7b;
+ cpuid.f7c = f7c;
+ return cpuid;
+ }
+}
+
+#define X(name, r, bit) \
+ MEM_STATIC int ZSTD_cpuid_##name(ZSTD_cpuid_t const cpuid) { \
+ return ((cpuid.r) & (1U << bit)) != 0; \
+ }
+
+/* cpuid(1): Processor Info and Feature Bits. */
+#define C(name, bit) X(name, f1c, bit)
+ C(sse3, 0)
+ C(pclmuldq, 1)
+ C(dtes64, 2)
+ C(monitor, 3)
+ C(dscpl, 4)
+ C(vmx, 5)
+ C(smx, 6)
+ C(eist, 7)
+ C(tm2, 8)
+ C(ssse3, 9)
+ C(cnxtid, 10)
+ C(fma, 12)
+ C(cx16, 13)
+ C(xtpr, 14)
+ C(pdcm, 15)
+ C(pcid, 17)
+ C(dca, 18)
+ C(sse41, 19)
+ C(sse42, 20)
+ C(x2apic, 21)
+ C(movbe, 22)
+ C(popcnt, 23)
+ C(tscdeadline, 24)
+ C(aes, 25)
+ C(xsave, 26)
+ C(osxsave, 27)
+ C(avx, 28)
+ C(f16c, 29)
+ C(rdrand, 30)
+#undef C
+#define D(name, bit) X(name, f1d, bit)
+ D(fpu, 0)
+ D(vme, 1)
+ D(de, 2)
+ D(pse, 3)
+ D(tsc, 4)
+ D(msr, 5)
+ D(pae, 6)
+ D(mce, 7)
+ D(cx8, 8)
+ D(apic, 9)
+ D(sep, 11)
+ D(mtrr, 12)
+ D(pge, 13)
+ D(mca, 14)
+ D(cmov, 15)
+ D(pat, 16)
+ D(pse36, 17)
+ D(psn, 18)
+ D(clfsh, 19)
+ D(ds, 21)
+ D(acpi, 22)
+ D(mmx, 23)
+ D(fxsr, 24)
+ D(sse, 25)
+ D(sse2, 26)
+ D(ss, 27)
+ D(htt, 28)
+ D(tm, 29)
+ D(pbe, 31)
+#undef D
+
+/* cpuid(7): Extended Features. */
+#define B(name, bit) X(name, f7b, bit)
+ B(bmi1, 3)
+ B(hle, 4)
+ B(avx2, 5)
+ B(smep, 7)
+ B(bmi2, 8)
+ B(erms, 9)
+ B(invpcid, 10)
+ B(rtm, 11)
+ B(mpx, 14)
+ B(avx512f, 16)
+ B(avx512dq, 17)
+ B(rdseed, 18)
+ B(adx, 19)
+ B(smap, 20)
+ B(avx512ifma, 21)
+ B(pcommit, 22)
+ B(clflushopt, 23)
+ B(clwb, 24)
+ B(avx512pf, 26)
+ B(avx512er, 27)
+ B(avx512cd, 28)
+ B(sha, 29)
+ B(avx512bw, 30)
+ B(avx512vl, 31)
+#undef B
+#define C(name, bit) X(name, f7c, bit)
+ C(prefetchwt1, 0)
+ C(avx512vbmi, 1)
+#undef C
+
+#undef X
+
+#endif /* ZSTD_COMMON_CPU_H */
diff --git a/sys/contrib/openzfs/module/zstd/lib/common/debug.h b/sys/contrib/openzfs/module/zstd/lib/common/debug.h
new file mode 100644
index 000000000000..ac6224888d8b
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/common/debug.h
@@ -0,0 +1,114 @@
+/* ******************************************************************
+ * debug
+ * Part of FSE library
+ * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ *
+ * You can contact the author at :
+ * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+****************************************************************** */
+
+
+/*
+ * The purpose of this header is to enable debug functions.
+ * They regroup assert(), DEBUGLOG() and RAWLOG() for run-time,
+ * and DEBUG_STATIC_ASSERT() for compile-time.
+ *
+ * By default, DEBUGLEVEL==0, which means run-time debug is disabled.
+ *
+ * Level 1 enables assert() only.
+ * Starting level 2, traces can be generated and pushed to stderr.
+ * The higher the level, the more verbose the traces.
+ *
+ * It's possible to dynamically adjust level using variable g_debug_level,
+ * which is only declared if DEBUGLEVEL>=2,
+ * and is a global variable, not multi-thread protected (use with care)
+ */
+
+#ifndef DEBUG_H_12987983217
+#define DEBUG_H_12987983217
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+
+/* static assert is triggered at compile time, leaving no runtime artefact.
+ * static assert only works with compile-time constants.
+ * Also, this variant can only be used inside a function. */
+#define DEBUG_STATIC_ASSERT(c) (void)sizeof(char[(c) ? 1 : -1])
+
+
+/* DEBUGLEVEL is expected to be defined externally,
+ * typically through compiler command line.
+ * Value must be a number. */
+#ifndef DEBUGLEVEL
+# define DEBUGLEVEL 0
+#endif
+
+
+/* DEBUGFILE can be defined externally,
+ * typically through compiler command line.
+ * note : currently useless.
+ * Value must be stderr or stdout */
+#ifndef DEBUGFILE
+# define DEBUGFILE stderr
+#endif
+
+
+/* recommended values for DEBUGLEVEL :
+ * 0 : release mode, no debug, all run-time checks disabled
+ * 1 : enables assert() only, no display
+ * 2 : reserved, for currently active debug path
+ * 3 : events once per object lifetime (CCtx, CDict, etc.)
+ * 4 : events once per frame
+ * 5 : events once per block
+ * 6 : events once per sequence (verbose)
+ * 7+: events at every position (*very* verbose)
+ *
+ * It's generally inconvenient to output traces > 5.
+ * In which case, it's possible to selectively trigger high verbosity levels
+ * by modifying g_debug_level.
+ */
+
+#if (DEBUGLEVEL>=1)
+# include <assert.h>
+#else
+# ifndef assert /* assert may be already defined, due to prior #include <assert.h> */
+# define assert(condition) ((void)0) /* disable assert (default) */
+# endif
+#endif
+
+#if (DEBUGLEVEL>=2)
+# include <stdio.h>
+extern int g_debuglevel; /* the variable is only declared,
+ it actually lives in debug.c,
+ and is shared by the whole process.
+ It's not thread-safe.
+ It's useful when enabling very verbose levels
+ on selective conditions (such as position in src) */
+
+# define RAWLOG(l, ...) { \
+ if (l<=g_debuglevel) { \
+ fprintf(stderr, __VA_ARGS__); \
+ } }
+# define DEBUGLOG(l, ...) { \
+ if (l<=g_debuglevel) { \
+ fprintf(stderr, __FILE__ ": " __VA_ARGS__); \
+ fprintf(stderr, " \n"); \
+ } }
+#else
+# define RAWLOG(l, ...) {} /* disabled */
+# define DEBUGLOG(l, ...) {} /* disabled */
+#endif
+
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* DEBUG_H_12987983217 */
diff --git a/sys/contrib/openzfs/module/zstd/lib/common/entropy_common.c b/sys/contrib/openzfs/module/zstd/lib/common/entropy_common.c
new file mode 100644
index 000000000000..9d3e4e8e36ab
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/common/entropy_common.c
@@ -0,0 +1,216 @@
+/* ******************************************************************
+ * Common functions of New Generation Entropy library
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ *
+ * You can contact the author at :
+ * - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
+ * - Public forum : https://groups.google.com/forum/#!forum/lz4c
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+****************************************************************** */
+
+/* *************************************
+* Dependencies
+***************************************/
+#include "mem.h"
+#include "error_private.h" /* ERR_*, ERROR */
+#define FSE_STATIC_LINKING_ONLY /* FSE_MIN_TABLELOG */
+#include "fse.h"
+#define HUF_STATIC_LINKING_ONLY /* HUF_TABLELOG_ABSOLUTEMAX */
+#include "huf.h"
+
+
+/*=== Version ===*/
+unsigned FSE_versionNumber(void) { return FSE_VERSION_NUMBER; }
+
+
+/*=== Error Management ===*/
+unsigned FSE_isError(size_t code) { return ERR_isError(code); }
+const char* FSE_getErrorName(size_t code) { return ERR_getErrorName(code); }
+
+unsigned HUF_isError(size_t code) { return ERR_isError(code); }
+const char* HUF_getErrorName(size_t code) { return ERR_getErrorName(code); }
+
+
+/*-**************************************************************
+* FSE NCount encoding-decoding
+****************************************************************/
+size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
+ const void* headerBuffer, size_t hbSize)
+{
+ const BYTE* const istart = (const BYTE*) headerBuffer;
+ const BYTE* const iend = istart + hbSize;
+ const BYTE* ip = istart;
+ int nbBits;
+ int remaining;
+ int threshold;
+ U32 bitStream;
+ int bitCount;
+ unsigned charnum = 0;
+ int previous0 = 0;
+
+ if (hbSize < 4) {
+ /* This function only works when hbSize >= 4 */
+ char buffer[4];
+ memset(buffer, 0, sizeof(buffer));
+ memcpy(buffer, headerBuffer, hbSize);
+ { size_t const countSize = FSE_readNCount(normalizedCounter, maxSVPtr, tableLogPtr,
+ buffer, sizeof(buffer));
+ if (FSE_isError(countSize)) return countSize;
+ if (countSize > hbSize) return ERROR(corruption_detected);
+ return countSize;
+ } }
+ assert(hbSize >= 4);
+
+ /* init */
+ memset(normalizedCounter, 0, (*maxSVPtr+1) * sizeof(normalizedCounter[0])); /* all symbols not present in NCount have a frequency of 0 */
+ bitStream = MEM_readLE32(ip);
+ nbBits = (bitStream & 0xF) + FSE_MIN_TABLELOG; /* extract tableLog */
+ if (nbBits > FSE_TABLELOG_ABSOLUTE_MAX) return ERROR(tableLog_tooLarge);
+ bitStream >>= 4;
+ bitCount = 4;
+ *tableLogPtr = nbBits;
+ remaining = (1<<nbBits)+1;
+ threshold = 1<<nbBits;
+ nbBits++;
+
+ while ((remaining>1) & (charnum<=*maxSVPtr)) {
+ if (previous0) {
+ unsigned n0 = charnum;
+ while ((bitStream & 0xFFFF) == 0xFFFF) {
+ n0 += 24;
+ if (ip < iend-5) {
+ ip += 2;
+ bitStream = MEM_readLE32(ip) >> bitCount;
+ } else {
+ bitStream >>= 16;
+ bitCount += 16;
+ } }
+ while ((bitStream & 3) == 3) {
+ n0 += 3;
+ bitStream >>= 2;
+ bitCount += 2;
+ }
+ n0 += bitStream & 3;
+ bitCount += 2;
+ if (n0 > *maxSVPtr) return ERROR(maxSymbolValue_tooSmall);
+ while (charnum < n0) normalizedCounter[charnum++] = 0;
+ if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
+ assert((bitCount >> 3) <= 3); /* For first condition to work */
+ ip += bitCount>>3;
+ bitCount &= 7;
+ bitStream = MEM_readLE32(ip) >> bitCount;
+ } else {
+ bitStream >>= 2;
+ } }
+ { int const max = (2*threshold-1) - remaining;
+ int count;
+
+ if ((bitStream & (threshold-1)) < (U32)max) {
+ count = bitStream & (threshold-1);
+ bitCount += nbBits-1;
+ } else {
+ count = bitStream & (2*threshold-1);
+ if (count >= threshold) count -= max;
+ bitCount += nbBits;
+ }
+
+ count--; /* extra accuracy */
+ remaining -= count < 0 ? -count : count; /* -1 means +1 */
+ normalizedCounter[charnum++] = (short)count;
+ previous0 = !count;
+ while (remaining < threshold) {
+ nbBits--;
+ threshold >>= 1;
+ }
+
+ if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
+ ip += bitCount>>3;
+ bitCount &= 7;
+ } else {
+ bitCount -= (int)(8 * (iend - 4 - ip));
+ ip = iend - 4;
+ }
+ bitStream = MEM_readLE32(ip) >> (bitCount & 31);
+ } } /* while ((remaining>1) & (charnum<=*maxSVPtr)) */
+ if (remaining != 1) return ERROR(corruption_detected);
+ if (bitCount > 32) return ERROR(corruption_detected);
+ *maxSVPtr = charnum-1;
+
+ ip += (bitCount+7)>>3;
+ return ip-istart;
+}
+
+
+/*! HUF_readStats() :
+ Read compact Huffman tree, saved by HUF_writeCTable().
+ `huffWeight` is destination buffer.
+ `rankStats` is assumed to be a table of at least HUF_TABLELOG_MAX U32.
+ @return : size read from `src` , or an error Code .
+ Note : Needed by HUF_readCTable() and HUF_readDTableX?() .
+*/
+size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats,
+ U32* nbSymbolsPtr, U32* tableLogPtr,
+ const void* src, size_t srcSize)
+{
+ U32 weightTotal;
+ const BYTE* ip = (const BYTE*) src;
+ size_t iSize;
+ size_t oSize;
+
+ if (!srcSize) return ERROR(srcSize_wrong);
+ iSize = ip[0];
+ /* memset(huffWeight, 0, hwSize); *//* is not necessary, even though some analyzer complain ... */
+
+ if (iSize >= 128) { /* special header */
+ oSize = iSize - 127;
+ iSize = ((oSize+1)/2);
+ if (iSize+1 > srcSize) return ERROR(srcSize_wrong);
+ if (oSize >= hwSize) return ERROR(corruption_detected);
+ ip += 1;
+ { U32 n;
+ for (n=0; n<oSize; n+=2) {
+ huffWeight[n] = ip[n/2] >> 4;
+ huffWeight[n+1] = ip[n/2] & 15;
+ } } }
+ else { /* header compressed with FSE (normal case) */
+ FSE_DTable fseWorkspace[FSE_DTABLE_SIZE_U32(6)]; /* 6 is max possible tableLog for HUF header (maybe even 5, to be tested) */
+ if (iSize+1 > srcSize) return ERROR(srcSize_wrong);
+ oSize = FSE_decompress_wksp(huffWeight, hwSize-1, ip+1, iSize, fseWorkspace, 6); /* max (hwSize-1) values decoded, as last one is implied */
+ if (FSE_isError(oSize)) return oSize;
+ }
+
+ /* collect weight stats */
+ memset(rankStats, 0, (HUF_TABLELOG_MAX + 1) * sizeof(U32));
+ weightTotal = 0;
+ { U32 n; for (n=0; n<oSize; n++) {
+ if (huffWeight[n] >= HUF_TABLELOG_MAX) return ERROR(corruption_detected);
+ rankStats[huffWeight[n]]++;
+ weightTotal += (1 << huffWeight[n]) >> 1;
+ } }
+ if (weightTotal == 0) return ERROR(corruption_detected);
+
+ /* get last non-null symbol weight (implied, total must be 2^n) */
+ { U32 const tableLog = BIT_highbit32(weightTotal) + 1;
+ if (tableLog > HUF_TABLELOG_MAX) return ERROR(corruption_detected);
+ *tableLogPtr = tableLog;
+ /* determine last weight */
+ { U32 const total = 1 << tableLog;
+ U32 const rest = total - weightTotal;
+ U32 const verif = 1 << BIT_highbit32(rest);
+ U32 const lastWeight = BIT_highbit32(rest) + 1;
+ if (verif != rest) return ERROR(corruption_detected); /* last value must be a clean power of 2 */
+ huffWeight[oSize] = (BYTE)lastWeight;
+ rankStats[lastWeight]++;
+ } }
+
+ /* check tree construction validity */
+ if ((rankStats[1] < 2) || (rankStats[1] & 1)) return ERROR(corruption_detected); /* by construction : at least 2 elts of rank 1, must be even */
+
+ /* results */
+ *nbSymbolsPtr = (U32)(oSize+1);
+ return iSize+1;
+}
diff --git a/sys/contrib/openzfs/module/zstd/lib/common/error_private.c b/sys/contrib/openzfs/module/zstd/lib/common/error_private.c
new file mode 100644
index 000000000000..cd437529c12b
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/common/error_private.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/* The purpose of this file is to have a single list of error strings embedded in binary */
+
+#include "error_private.h"
+
+const char* ERR_getErrorString(ERR_enum code)
+{
+#ifdef ZSTD_STRIP_ERROR_STRINGS
+ (void)code;
+ return "Error strings stripped";
+#else
+ static const char* const notErrorCode = "Unspecified error code";
+ switch( code )
+ {
+ case PREFIX(no_error): return "No error detected";
+ case PREFIX(GENERIC): return "Error (generic)";
+ case PREFIX(prefix_unknown): return "Unknown frame descriptor";
+ case PREFIX(version_unsupported): return "Version not supported";
+ case PREFIX(frameParameter_unsupported): return "Unsupported frame parameter";
+ case PREFIX(frameParameter_windowTooLarge): return "Frame requires too much memory for decoding";
+ case PREFIX(corruption_detected): return "Corrupted block detected";
+ case PREFIX(checksum_wrong): return "Restored data doesn't match checksum";
+ case PREFIX(parameter_unsupported): return "Unsupported parameter";
+ case PREFIX(parameter_outOfBound): return "Parameter is out of bound";
+ case PREFIX(init_missing): return "Context should be init first";
+ case PREFIX(memory_allocation): return "Allocation error : not enough memory";
+ case PREFIX(workSpace_tooSmall): return "workSpace buffer is not large enough";
+ case PREFIX(stage_wrong): return "Operation not authorized at current processing stage";
+ case PREFIX(tableLog_tooLarge): return "tableLog requires too much memory : unsupported";
+ case PREFIX(maxSymbolValue_tooLarge): return "Unsupported max Symbol Value : too large";
+ case PREFIX(maxSymbolValue_tooSmall): return "Specified maxSymbolValue is too small";
+ case PREFIX(dictionary_corrupted): return "Dictionary is corrupted";
+ case PREFIX(dictionary_wrong): return "Dictionary mismatch";
+ case PREFIX(dictionaryCreation_failed): return "Cannot create Dictionary from provided samples";
+ case PREFIX(dstSize_tooSmall): return "Destination buffer is too small";
+ case PREFIX(srcSize_wrong): return "Src size is incorrect";
+ case PREFIX(dstBuffer_null): return "Operation on NULL destination buffer";
+ /* following error codes are not stable and may be removed or changed in a future version */
+ case PREFIX(frameIndex_tooLarge): return "Frame index is too large";
+ case PREFIX(seekableIO): return "An I/O error occurred when reading/seeking";
+ case PREFIX(dstBuffer_wrong): return "Destination buffer is wrong";
+ case PREFIX(maxCode):
+ default: return notErrorCode;
+ }
+#endif
+}
diff --git a/sys/contrib/openzfs/module/zstd/lib/common/error_private.h b/sys/contrib/openzfs/module/zstd/lib/common/error_private.h
new file mode 100644
index 000000000000..982cf8e9fe6f
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/common/error_private.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/* Note : this module is expected to remain private, do not expose it */
+
+#ifndef ERROR_H_MODULE
+#define ERROR_H_MODULE
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+
+/* ****************************************
+* Dependencies
+******************************************/
+#include <stddef.h> /* size_t */
+#include "zstd_errors.h" /* enum list */
+
+
+/* ****************************************
+* Compiler-specific
+******************************************/
+#if defined(__GNUC__)
+# define ERR_STATIC static __attribute__((unused))
+#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
+# define ERR_STATIC static inline
+#elif defined(_MSC_VER)
+# define ERR_STATIC static __inline
+#else
+# define ERR_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */
+#endif
+
+
+/*-****************************************
+* Customization (error_public.h)
+******************************************/
+typedef ZSTD_ErrorCode ERR_enum;
+#define PREFIX(name) ZSTD_error_##name
+
+
+/*-****************************************
+* Error codes handling
+******************************************/
+#undef ERROR /* already defined on Visual Studio */
+#define ERROR(name) ZSTD_ERROR(name)
+#define ZSTD_ERROR(name) ((size_t)-PREFIX(name))
+
+ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); }
+
+ERR_STATIC ERR_enum ERR_getErrorCode(size_t code) { if (!ERR_isError(code)) return (ERR_enum)0; return (ERR_enum) (0-code); }
+
+/* check and forward error code */
+#define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return e
+#define CHECK_F(f) { CHECK_V_F(_var_err__, f); }
+
+
+/*-****************************************
+* Error Strings
+******************************************/
+
+const char* ERR_getErrorString(ERR_enum code); /* error_private.c */
+
+ERR_STATIC const char* ERR_getErrorName(size_t code)
+{
+ return ERR_getErrorString(ERR_getErrorCode(code));
+}
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* ERROR_H_MODULE */
diff --git a/sys/contrib/openzfs/module/zstd/lib/common/fse.h b/sys/contrib/openzfs/module/zstd/lib/common/fse.h
new file mode 100644
index 000000000000..ff54e70ea75c
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/common/fse.h
@@ -0,0 +1,688 @@
+/* ******************************************************************
+ * FSE : Finite State Entropy codec
+ * Public Prototypes declaration
+ * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ *
+ * You can contact the author at :
+ * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+****************************************************************** */
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#ifndef FSE_H
+#define FSE_H
+
+
+/*-*****************************************
+* Dependencies
+******************************************/
+#include <stddef.h> /* size_t, ptrdiff_t */
+
+
+/*-*****************************************
+* FSE_PUBLIC_API : control library symbols visibility
+******************************************/
+#if defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) && defined(__GNUC__) && (__GNUC__ >= 4)
+# define FSE_PUBLIC_API __attribute__ ((visibility ("default")))
+#elif defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) /* Visual expected */
+# define FSE_PUBLIC_API __declspec(dllexport)
+#elif defined(FSE_DLL_IMPORT) && (FSE_DLL_IMPORT==1)
+# define FSE_PUBLIC_API __declspec(dllimport) /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/
+#else
+# define FSE_PUBLIC_API
+#endif
+
+/*------ Version ------*/
+#define FSE_VERSION_MAJOR 0
+#define FSE_VERSION_MINOR 9
+#define FSE_VERSION_RELEASE 0
+
+#define FSE_LIB_VERSION FSE_VERSION_MAJOR.FSE_VERSION_MINOR.FSE_VERSION_RELEASE
+#define FSE_QUOTE(str) #str
+#define FSE_EXPAND_AND_QUOTE(str) FSE_QUOTE(str)
+#define FSE_VERSION_STRING FSE_EXPAND_AND_QUOTE(FSE_LIB_VERSION)
+
+#define FSE_VERSION_NUMBER (FSE_VERSION_MAJOR *100*100 + FSE_VERSION_MINOR *100 + FSE_VERSION_RELEASE)
+FSE_PUBLIC_API unsigned FSE_versionNumber(void); /**< library version number; to be used when checking dll version */
+
+
+/*-****************************************
+* FSE simple functions
+******************************************/
+/*! FSE_compress() :
+ Compress content of buffer 'src', of size 'srcSize', into destination buffer 'dst'.
+ 'dst' buffer must be already allocated. Compression runs faster is dstCapacity >= FSE_compressBound(srcSize).
+ @return : size of compressed data (<= dstCapacity).
+ Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!!
+ if return == 1, srcData is a single byte symbol * srcSize times. Use RLE compression instead.
+ if FSE_isError(return), compression failed (more details using FSE_getErrorName())
+*/
+FSE_PUBLIC_API size_t FSE_compress(void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize);
+
+/*! FSE_decompress():
+ Decompress FSE data from buffer 'cSrc', of size 'cSrcSize',
+ into already allocated destination buffer 'dst', of size 'dstCapacity'.
+ @return : size of regenerated data (<= maxDstSize),
+ or an error code, which can be tested using FSE_isError() .
+
+ ** Important ** : FSE_decompress() does not decompress non-compressible nor RLE data !!!
+ Why ? : making this distinction requires a header.
+ Header management is intentionally delegated to the user layer, which can better manage special cases.
+*/
+FSE_PUBLIC_API size_t FSE_decompress(void* dst, size_t dstCapacity,
+ const void* cSrc, size_t cSrcSize);
+
+
+/*-*****************************************
+* Tool functions
+******************************************/
+FSE_PUBLIC_API size_t FSE_compressBound(size_t size); /* maximum compressed size */
+
+/* Error Management */
+FSE_PUBLIC_API unsigned FSE_isError(size_t code); /* tells if a return value is an error code */
+FSE_PUBLIC_API const char* FSE_getErrorName(size_t code); /* provides error code string (useful for debugging) */
+
+
+/*-*****************************************
+* FSE advanced functions
+******************************************/
+/*! FSE_compress2() :
+ Same as FSE_compress(), but allows the selection of 'maxSymbolValue' and 'tableLog'
+ Both parameters can be defined as '0' to mean : use default value
+ @return : size of compressed data
+ Special values : if return == 0, srcData is not compressible => Nothing is stored within cSrc !!!
+ if return == 1, srcData is a single byte symbol * srcSize times. Use RLE compression.
+ if FSE_isError(return), it's an error code.
+*/
+FSE_PUBLIC_API size_t FSE_compress2 (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog);
+
+
+/*-*****************************************
+* FSE detailed API
+******************************************/
+/*!
+FSE_compress() does the following:
+1. count symbol occurrence from source[] into table count[] (see hist.h)
+2. normalize counters so that sum(count[]) == Power_of_2 (2^tableLog)
+3. save normalized counters to memory buffer using writeNCount()
+4. build encoding table 'CTable' from normalized counters
+5. encode the data stream using encoding table 'CTable'
+
+FSE_decompress() does the following:
+1. read normalized counters with readNCount()
+2. build decoding table 'DTable' from normalized counters
+3. decode the data stream using decoding table 'DTable'
+
+The following API allows targeting specific sub-functions for advanced tasks.
+For example, it's possible to compress several blocks using the same 'CTable',
+or to save and provide normalized distribution using external method.
+*/
+
+/* *** COMPRESSION *** */
+
+/*! FSE_optimalTableLog():
+ dynamically downsize 'tableLog' when conditions are met.
+ It saves CPU time, by using smaller tables, while preserving or even improving compression ratio.
+ @return : recommended tableLog (necessarily <= 'maxTableLog') */
+FSE_PUBLIC_API unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue);
+
+/*! FSE_normalizeCount():
+ normalize counts so that sum(count[]) == Power_of_2 (2^tableLog)
+ 'normalizedCounter' is a table of short, of minimum size (maxSymbolValue+1).
+ @return : tableLog,
+ or an errorCode, which can be tested using FSE_isError() */
+FSE_PUBLIC_API size_t FSE_normalizeCount(short* normalizedCounter, unsigned tableLog,
+ const unsigned* count, size_t srcSize, unsigned maxSymbolValue);
+
+/*! FSE_NCountWriteBound():
+ Provides the maximum possible size of an FSE normalized table, given 'maxSymbolValue' and 'tableLog'.
+ Typically useful for allocation purpose. */
+FSE_PUBLIC_API size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog);
+
+/*! FSE_writeNCount():
+ Compactly save 'normalizedCounter' into 'buffer'.
+ @return : size of the compressed table,
+ or an errorCode, which can be tested using FSE_isError(). */
+FSE_PUBLIC_API size_t FSE_writeNCount (void* buffer, size_t bufferSize,
+ const short* normalizedCounter,
+ unsigned maxSymbolValue, unsigned tableLog);
+
+/*! Constructor and Destructor of FSE_CTable.
+ Note that FSE_CTable size depends on 'tableLog' and 'maxSymbolValue' */
+typedef unsigned FSE_CTable; /* don't allocate that. It's only meant to be more restrictive than void* */
+FSE_PUBLIC_API FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog);
+FSE_PUBLIC_API void FSE_freeCTable (FSE_CTable* ct);
+
+/*! FSE_buildCTable():
+ Builds `ct`, which must be already allocated, using FSE_createCTable().
+ @return : 0, or an errorCode, which can be tested using FSE_isError() */
+FSE_PUBLIC_API size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog);
+
+/*! FSE_compress_usingCTable():
+ Compress `src` using `ct` into `dst` which must be already allocated.
+ @return : size of compressed data (<= `dstCapacity`),
+ or 0 if compressed data could not fit into `dst`,
+ or an errorCode, which can be tested using FSE_isError() */
+FSE_PUBLIC_API size_t FSE_compress_usingCTable (void* dst, size_t dstCapacity, const void* src, size_t srcSize, const FSE_CTable* ct);
+
+/*!
+Tutorial :
+----------
+The first step is to count all symbols. FSE_count() does this job very fast.
+Result will be saved into 'count', a table of unsigned int, which must be already allocated, and have 'maxSymbolValuePtr[0]+1' cells.
+'src' is a table of bytes of size 'srcSize'. All values within 'src' MUST be <= maxSymbolValuePtr[0]
+maxSymbolValuePtr[0] will be updated, with its real value (necessarily <= original value)
+FSE_count() will return the number of occurrence of the most frequent symbol.
+This can be used to know if there is a single symbol within 'src', and to quickly evaluate its compressibility.
+If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError()).
+
+The next step is to normalize the frequencies.
+FSE_normalizeCount() will ensure that sum of frequencies is == 2 ^'tableLog'.
+It also guarantees a minimum of 1 to any Symbol with frequency >= 1.
+You can use 'tableLog'==0 to mean "use default tableLog value".
+If you are unsure of which tableLog value to use, you can ask FSE_optimalTableLog(),
+which will provide the optimal valid tableLog given sourceSize, maxSymbolValue, and a user-defined maximum (0 means "default").
+
+The result of FSE_normalizeCount() will be saved into a table,
+called 'normalizedCounter', which is a table of signed short.
+'normalizedCounter' must be already allocated, and have at least 'maxSymbolValue+1' cells.
+The return value is tableLog if everything proceeded as expected.
+It is 0 if there is a single symbol within distribution.
+If there is an error (ex: invalid tableLog value), the function will return an ErrorCode (which can be tested using FSE_isError()).
+
+'normalizedCounter' can be saved in a compact manner to a memory area using FSE_writeNCount().
+'buffer' must be already allocated.
+For guaranteed success, buffer size must be at least FSE_headerBound().
+The result of the function is the number of bytes written into 'buffer'.
+If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError(); ex : buffer size too small).
+
+'normalizedCounter' can then be used to create the compression table 'CTable'.
+The space required by 'CTable' must be already allocated, using FSE_createCTable().
+You can then use FSE_buildCTable() to fill 'CTable'.
+If there is an error, both functions will return an ErrorCode (which can be tested using FSE_isError()).
+
+'CTable' can then be used to compress 'src', with FSE_compress_usingCTable().
+Similar to FSE_count(), the convention is that 'src' is assumed to be a table of char of size 'srcSize'
+The function returns the size of compressed data (without header), necessarily <= `dstCapacity`.
+If it returns '0', compressed data could not fit into 'dst'.
+If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError()).
+*/
+
+
+/* *** DECOMPRESSION *** */
+
+/*! FSE_readNCount():
+ Read compactly saved 'normalizedCounter' from 'rBuffer'.
+ @return : size read from 'rBuffer',
+ or an errorCode, which can be tested using FSE_isError().
+ maxSymbolValuePtr[0] and tableLogPtr[0] will also be updated with their respective values */
+FSE_PUBLIC_API size_t FSE_readNCount (short* normalizedCounter,
+ unsigned* maxSymbolValuePtr, unsigned* tableLogPtr,
+ const void* rBuffer, size_t rBuffSize);
+
+/*! Constructor and Destructor of FSE_DTable.
+ Note that its size depends on 'tableLog' */
+typedef unsigned FSE_DTable; /* don't allocate that. It's just a way to be more restrictive than void* */
+FSE_PUBLIC_API FSE_DTable* FSE_createDTable(unsigned tableLog);
+FSE_PUBLIC_API void FSE_freeDTable(FSE_DTable* dt);
+
+/*! FSE_buildDTable():
+ Builds 'dt', which must be already allocated, using FSE_createDTable().
+ return : 0, or an errorCode, which can be tested using FSE_isError() */
+FSE_PUBLIC_API size_t FSE_buildDTable (FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog);
+
+/*! FSE_decompress_usingDTable():
+ Decompress compressed source `cSrc` of size `cSrcSize` using `dt`
+ into `dst` which must be already allocated.
+ @return : size of regenerated data (necessarily <= `dstCapacity`),
+ or an errorCode, which can be tested using FSE_isError() */
+FSE_PUBLIC_API size_t FSE_decompress_usingDTable(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, const FSE_DTable* dt);
+
+/*!
+Tutorial :
+----------
+(Note : these functions only decompress FSE-compressed blocks.
+ If block is uncompressed, use memcpy() instead
+ If block is a single repeated byte, use memset() instead )
+
+The first step is to obtain the normalized frequencies of symbols.
+This can be performed by FSE_readNCount() if it was saved using FSE_writeNCount().
+'normalizedCounter' must be already allocated, and have at least 'maxSymbolValuePtr[0]+1' cells of signed short.
+In practice, that means it's necessary to know 'maxSymbolValue' beforehand,
+or size the table to handle worst case situations (typically 256).
+FSE_readNCount() will provide 'tableLog' and 'maxSymbolValue'.
+The result of FSE_readNCount() is the number of bytes read from 'rBuffer'.
+Note that 'rBufferSize' must be at least 4 bytes, even if useful information is less than that.
+If there is an error, the function will return an error code, which can be tested using FSE_isError().
+
+The next step is to build the decompression tables 'FSE_DTable' from 'normalizedCounter'.
+This is performed by the function FSE_buildDTable().
+The space required by 'FSE_DTable' must be already allocated using FSE_createDTable().
+If there is an error, the function will return an error code, which can be tested using FSE_isError().
+
+`FSE_DTable` can then be used to decompress `cSrc`, with FSE_decompress_usingDTable().
+`cSrcSize` must be strictly correct, otherwise decompression will fail.
+FSE_decompress_usingDTable() result will tell how many bytes were regenerated (<=`dstCapacity`).
+If there is an error, the function will return an error code, which can be tested using FSE_isError(). (ex: dst buffer too small)
+*/
+
+#endif /* FSE_H */
+
+#if defined(FSE_STATIC_LINKING_ONLY) && !defined(FSE_H_FSE_STATIC_LINKING_ONLY)
+#define FSE_H_FSE_STATIC_LINKING_ONLY
+
+/* *** Dependency *** */
+#include "bitstream.h"
+
+
+/* *****************************************
+* Static allocation
+*******************************************/
+/* FSE buffer bounds */
+#define FSE_NCOUNTBOUND 512
+#define FSE_BLOCKBOUND(size) (size + (size>>7) + 4 /* fse states */ + sizeof(size_t) /* bitContainer */)
+#define FSE_COMPRESSBOUND(size) (FSE_NCOUNTBOUND + FSE_BLOCKBOUND(size)) /* Macro version, useful for static allocation */
+
+/* It is possible to statically allocate FSE CTable/DTable as a table of FSE_CTable/FSE_DTable using below macros */
+#define FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) (1 + (1<<(maxTableLog-1)) + ((maxSymbolValue+1)*2))
+#define FSE_DTABLE_SIZE_U32(maxTableLog) (1 + (1<<maxTableLog))
+
+/* or use the size to malloc() space directly. Pay attention to alignment restrictions though */
+#define FSE_CTABLE_SIZE(maxTableLog, maxSymbolValue) (FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) * sizeof(FSE_CTable))
+#define FSE_DTABLE_SIZE(maxTableLog) (FSE_DTABLE_SIZE_U32(maxTableLog) * sizeof(FSE_DTable))
+
+
+/* *****************************************
+ * FSE advanced API
+ ***************************************** */
+
+unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus);
+/**< same as FSE_optimalTableLog(), which used `minus==2` */
+
+/* FSE_compress_wksp() :
+ * Same as FSE_compress2(), but using an externally allocated scratch buffer (`workSpace`).
+ * FSE_WKSP_SIZE_U32() provides the minimum size required for `workSpace` as a table of FSE_CTable.
+ */
+#define FSE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) ( FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) + ((maxTableLog > 12) ? (1 << (maxTableLog - 2)) : 1024) )
+size_t FSE_compress_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize);
+
+size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits);
+/**< build a fake FSE_CTable, designed for a flat distribution, where each symbol uses nbBits */
+
+size_t FSE_buildCTable_rle (FSE_CTable* ct, unsigned char symbolValue);
+/**< build a fake FSE_CTable, designed to compress always the same symbolValue */
+
+/* FSE_buildCTable_wksp() :
+ * Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`).
+ * `wkspSize` must be >= `(1<<tableLog)`.
+ */
+size_t FSE_buildCTable_wksp(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize);
+
+size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits);
+/**< build a fake FSE_DTable, designed to read a flat distribution where each symbol uses nbBits */
+
+size_t FSE_buildDTable_rle (FSE_DTable* dt, unsigned char symbolValue);
+/**< build a fake FSE_DTable, designed to always generate the same symbolValue */
+
+size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, FSE_DTable* workSpace, unsigned maxLog);
+/**< same as FSE_decompress(), using an externally allocated `workSpace` produced with `FSE_DTABLE_SIZE_U32(maxLog)` */
+
+typedef enum {
+ FSE_repeat_none, /**< Cannot use the previous table */
+ FSE_repeat_check, /**< Can use the previous table but it must be checked */
+ FSE_repeat_valid /**< Can use the previous table and it is assumed to be valid */
+ } FSE_repeat;
+
+/* *****************************************
+* FSE symbol compression API
+*******************************************/
+/*!
+ This API consists of small unitary functions, which highly benefit from being inlined.
+ Hence their body are included in next section.
+*/
+typedef struct {
+ ptrdiff_t value;
+ const void* stateTable;
+ const void* symbolTT;
+ unsigned stateLog;
+} FSE_CState_t;
+
+static void FSE_initCState(FSE_CState_t* CStatePtr, const FSE_CTable* ct);
+
+static void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* CStatePtr, unsigned symbol);
+
+static void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* CStatePtr);
+
+/**<
+These functions are inner components of FSE_compress_usingCTable().
+They allow the creation of custom streams, mixing multiple tables and bit sources.
+
+A key property to keep in mind is that encoding and decoding are done **in reverse direction**.
+So the first symbol you will encode is the last you will decode, like a LIFO stack.
+
+You will need a few variables to track your CStream. They are :
+
+FSE_CTable ct; // Provided by FSE_buildCTable()
+BIT_CStream_t bitStream; // bitStream tracking structure
+FSE_CState_t state; // State tracking structure (can have several)
+
+
+The first thing to do is to init bitStream and state.
+ size_t errorCode = BIT_initCStream(&bitStream, dstBuffer, maxDstSize);
+ FSE_initCState(&state, ct);
+
+Note that BIT_initCStream() can produce an error code, so its result should be tested, using FSE_isError();
+You can then encode your input data, byte after byte.
+FSE_encodeSymbol() outputs a maximum of 'tableLog' bits at a time.
+Remember decoding will be done in reverse direction.
+ FSE_encodeByte(&bitStream, &state, symbol);
+
+At any time, you can also add any bit sequence.
+Note : maximum allowed nbBits is 25, for compatibility with 32-bits decoders
+ BIT_addBits(&bitStream, bitField, nbBits);
+
+The above methods don't commit data to memory, they just store it into local register, for speed.
+Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
+Writing data to memory is a manual operation, performed by the flushBits function.
+ BIT_flushBits(&bitStream);
+
+Your last FSE encoding operation shall be to flush your last state value(s).
+ FSE_flushState(&bitStream, &state);
+
+Finally, you must close the bitStream.
+The function returns the size of CStream in bytes.
+If data couldn't fit into dstBuffer, it will return a 0 ( == not compressible)
+If there is an error, it returns an errorCode (which can be tested using FSE_isError()).
+ size_t size = BIT_closeCStream(&bitStream);
+*/
+
+
+/* *****************************************
+* FSE symbol decompression API
+*******************************************/
+typedef struct {
+ size_t state;
+ const void* table; /* precise table may vary, depending on U16 */
+} FSE_DState_t;
+
+
+static void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt);
+
+static unsigned char FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD);
+
+static unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr);
+
+/**<
+Let's now decompose FSE_decompress_usingDTable() into its unitary components.
+You will decode FSE-encoded symbols from the bitStream,
+and also any other bitFields you put in, **in reverse order**.
+
+You will need a few variables to track your bitStream. They are :
+
+BIT_DStream_t DStream; // Stream context
+FSE_DState_t DState; // State context. Multiple ones are possible
+FSE_DTable* DTablePtr; // Decoding table, provided by FSE_buildDTable()
+
+The first thing to do is to init the bitStream.
+ errorCode = BIT_initDStream(&DStream, srcBuffer, srcSize);
+
+You should then retrieve your initial state(s)
+(in reverse flushing order if you have several ones) :
+ errorCode = FSE_initDState(&DState, &DStream, DTablePtr);
+
+You can then decode your data, symbol after symbol.
+For information the maximum number of bits read by FSE_decodeSymbol() is 'tableLog'.
+Keep in mind that symbols are decoded in reverse order, like a LIFO stack (last in, first out).
+ unsigned char symbol = FSE_decodeSymbol(&DState, &DStream);
+
+You can retrieve any bitfield you eventually stored into the bitStream (in reverse order)
+Note : maximum allowed nbBits is 25, for 32-bits compatibility
+ size_t bitField = BIT_readBits(&DStream, nbBits);
+
+All above operations only read from local register (which size depends on size_t).
+Refueling the register from memory is manually performed by the reload method.
+ endSignal = FSE_reloadDStream(&DStream);
+
+BIT_reloadDStream() result tells if there is still some more data to read from DStream.
+BIT_DStream_unfinished : there is still some data left into the DStream.
+BIT_DStream_endOfBuffer : Dstream reached end of buffer. Its container may no longer be completely filled.
+BIT_DStream_completed : Dstream reached its exact end, corresponding in general to decompression completed.
+BIT_DStream_tooFar : Dstream went too far. Decompression result is corrupted.
+
+When reaching end of buffer (BIT_DStream_endOfBuffer), progress slowly, notably if you decode multiple symbols per loop,
+to properly detect the exact end of stream.
+After each decoded symbol, check if DStream is fully consumed using this simple test :
+ BIT_reloadDStream(&DStream) >= BIT_DStream_completed
+
+When it's done, verify decompression is fully completed, by checking both DStream and the relevant states.
+Checking if DStream has reached its end is performed by :
+ BIT_endOfDStream(&DStream);
+Check also the states. There might be some symbols left there, if some high probability ones (>50%) are possible.
+ FSE_endOfDState(&DState);
+*/
+
+
+/* *****************************************
+* FSE unsafe API
+*******************************************/
+static unsigned char FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD);
+/* faster, but works only if nbBits is always >= 1 (otherwise, result will be corrupted) */
+
+
+/* *****************************************
+* Implementation of inlined functions
+*******************************************/
+typedef struct {
+ int deltaFindState;
+ U32 deltaNbBits;
+} FSE_symbolCompressionTransform; /* total 8 bytes */
+
+MEM_STATIC void FSE_initCState(FSE_CState_t* statePtr, const FSE_CTable* ct)
+{
+ const void* ptr = ct;
+ const U16* u16ptr = (const U16*) ptr;
+ const U32 tableLog = MEM_read16(ptr);
+ statePtr->value = (ptrdiff_t)1<<tableLog;
+ statePtr->stateTable = u16ptr+2;
+ statePtr->symbolTT = ct + 1 + (tableLog ? (1<<(tableLog-1)) : 1);
+ statePtr->stateLog = tableLog;
+}
+
+
+/*! FSE_initCState2() :
+* Same as FSE_initCState(), but the first symbol to include (which will be the last to be read)
+* uses the smallest state value possible, saving the cost of this symbol */
+MEM_STATIC void FSE_initCState2(FSE_CState_t* statePtr, const FSE_CTable* ct, U32 symbol)
+{
+ FSE_initCState(statePtr, ct);
+ { const FSE_symbolCompressionTransform symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol];
+ const U16* stateTable = (const U16*)(statePtr->stateTable);
+ U32 nbBitsOut = (U32)((symbolTT.deltaNbBits + (1<<15)) >> 16);
+ statePtr->value = (nbBitsOut << 16) - symbolTT.deltaNbBits;
+ statePtr->value = stateTable[(statePtr->value >> nbBitsOut) + symbolTT.deltaFindState];
+ }
+}
+
+MEM_STATIC void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* statePtr, unsigned symbol)
+{
+ FSE_symbolCompressionTransform const symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol];
+ const U16* const stateTable = (const U16*)(statePtr->stateTable);
+ U32 const nbBitsOut = (U32)((statePtr->value + symbolTT.deltaNbBits) >> 16);
+ BIT_addBits(bitC, statePtr->value, nbBitsOut);
+ statePtr->value = stateTable[ (statePtr->value >> nbBitsOut) + symbolTT.deltaFindState];
+}
+
+MEM_STATIC void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* statePtr)
+{
+ BIT_addBits(bitC, statePtr->value, statePtr->stateLog);
+ BIT_flushBits(bitC);
+}
+
+
+/* FSE_getMaxNbBits() :
+ * Approximate maximum cost of a symbol, in bits.
+ * Fractional get rounded up (i.e : a symbol with a normalized frequency of 3 gives the same result as a frequency of 2)
+ * note 1 : assume symbolValue is valid (<= maxSymbolValue)
+ * note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */
+MEM_STATIC U32 FSE_getMaxNbBits(const void* symbolTTPtr, U32 symbolValue)
+{
+ const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr;
+ return (symbolTT[symbolValue].deltaNbBits + ((1<<16)-1)) >> 16;
+}
+
+/* FSE_bitCost() :
+ * Approximate symbol cost, as fractional value, using fixed-point format (accuracyLog fractional bits)
+ * note 1 : assume symbolValue is valid (<= maxSymbolValue)
+ * note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */
+MEM_STATIC U32 FSE_bitCost(const void* symbolTTPtr, U32 tableLog, U32 symbolValue, U32 accuracyLog)
+{
+ const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr;
+ U32 const minNbBits = symbolTT[symbolValue].deltaNbBits >> 16;
+ U32 const threshold = (minNbBits+1) << 16;
+ assert(tableLog < 16);
+ assert(accuracyLog < 31-tableLog); /* ensure enough room for renormalization double shift */
+ { U32 const tableSize = 1 << tableLog;
+ U32 const deltaFromThreshold = threshold - (symbolTT[symbolValue].deltaNbBits + tableSize);
+ U32 const normalizedDeltaFromThreshold = (deltaFromThreshold << accuracyLog) >> tableLog; /* linear interpolation (very approximate) */
+ U32 const bitMultiplier = 1 << accuracyLog;
+ assert(symbolTT[symbolValue].deltaNbBits + tableSize <= threshold);
+ assert(normalizedDeltaFromThreshold <= bitMultiplier);
+ return (minNbBits+1)*bitMultiplier - normalizedDeltaFromThreshold;
+ }
+}
+
+
+/* ====== Decompression ====== */
+
+typedef struct {
+ U16 tableLog;
+ U16 fastMode;
+} FSE_DTableHeader; /* sizeof U32 */
+
+typedef struct
+{
+ unsigned short newState;
+ unsigned char symbol;
+ unsigned char nbBits;
+} FSE_decode_t; /* size == U32 */
+
+MEM_STATIC void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt)
+{
+ const void* ptr = dt;
+ const FSE_DTableHeader* const DTableH = (const FSE_DTableHeader*)ptr;
+ DStatePtr->state = BIT_readBits(bitD, DTableH->tableLog);
+ BIT_reloadDStream(bitD);
+ DStatePtr->table = dt + 1;
+}
+
+MEM_STATIC BYTE FSE_peekSymbol(const FSE_DState_t* DStatePtr)
+{
+ FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
+ return DInfo.symbol;
+}
+
+MEM_STATIC void FSE_updateState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
+{
+ FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
+ U32 const nbBits = DInfo.nbBits;
+ size_t const lowBits = BIT_readBits(bitD, nbBits);
+ DStatePtr->state = DInfo.newState + lowBits;
+}
+
+MEM_STATIC BYTE FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
+{
+ FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
+ U32 const nbBits = DInfo.nbBits;
+ BYTE const symbol = DInfo.symbol;
+ size_t const lowBits = BIT_readBits(bitD, nbBits);
+
+ DStatePtr->state = DInfo.newState + lowBits;
+ return symbol;
+}
+
+/*! FSE_decodeSymbolFast() :
+ unsafe, only works if no symbol has a probability > 50% */
+MEM_STATIC BYTE FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
+{
+ FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
+ U32 const nbBits = DInfo.nbBits;
+ BYTE const symbol = DInfo.symbol;
+ size_t const lowBits = BIT_readBitsFast(bitD, nbBits);
+
+ DStatePtr->state = DInfo.newState + lowBits;
+ return symbol;
+}
+
+MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr)
+{
+ return DStatePtr->state == 0;
+}
+
+
+
+#ifndef FSE_COMMONDEFS_ONLY
+
+/* **************************************************************
+* Tuning parameters
+****************************************************************/
+/*!MEMORY_USAGE :
+* Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
+* Increasing memory usage improves compression ratio
+* Reduced memory usage can improve speed, due to cache effect
+* Recommended max value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */
+#ifndef FSE_MAX_MEMORY_USAGE
+# define FSE_MAX_MEMORY_USAGE 14
+#endif
+#ifndef FSE_DEFAULT_MEMORY_USAGE
+# define FSE_DEFAULT_MEMORY_USAGE 13
+#endif
+
+/*!FSE_MAX_SYMBOL_VALUE :
+* Maximum symbol value authorized.
+* Required for proper stack allocation */
+#ifndef FSE_MAX_SYMBOL_VALUE
+# define FSE_MAX_SYMBOL_VALUE 255
+#endif
+
+/* **************************************************************
+* template functions type & suffix
+****************************************************************/
+#define FSE_FUNCTION_TYPE BYTE
+#define FSE_FUNCTION_EXTENSION
+#define FSE_DECODE_TYPE FSE_decode_t
+
+
+#endif /* !FSE_COMMONDEFS_ONLY */
+
+
+/* ***************************************************************
+* Constants
+*****************************************************************/
+#define FSE_MAX_TABLELOG (FSE_MAX_MEMORY_USAGE-2)
+#define FSE_MAX_TABLESIZE (1U<<FSE_MAX_TABLELOG)
+#define FSE_MAXTABLESIZE_MASK (FSE_MAX_TABLESIZE-1)
+#define FSE_DEFAULT_TABLELOG (FSE_DEFAULT_MEMORY_USAGE-2)
+#define FSE_MIN_TABLELOG 5
+
+#define FSE_TABLELOG_ABSOLUTE_MAX 15
+#if FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX
+# error "FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX is not supported"
+#endif
+
+#define FSE_TABLESTEP(tableSize) ((tableSize>>1) + (tableSize>>3) + 3)
+
+
+#endif /* FSE_STATIC_LINKING_ONLY */
+
+
+#if defined (__cplusplus)
+}
+#endif
diff --git a/sys/contrib/openzfs/module/zstd/lib/common/fse_decompress.c b/sys/contrib/openzfs/module/zstd/lib/common/fse_decompress.c
new file mode 100644
index 000000000000..bcc2223ccc65
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/common/fse_decompress.c
@@ -0,0 +1,286 @@
+/* ******************************************************************
+ * FSE : Finite State Entropy decoder
+ * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ *
+ * You can contact the author at :
+ * - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
+ * - Public forum : https://groups.google.com/forum/#!forum/lz4c
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+****************************************************************** */
+
+
+/* **************************************************************
+* Includes
+****************************************************************/
+#include <stdlib.h> /* malloc, free, qsort */
+#include <string.h> /* memcpy, memset */
+#include "bitstream.h"
+#include "compiler.h"
+#define FSE_STATIC_LINKING_ONLY
+#include "fse.h"
+#include "error_private.h"
+
+
+/* **************************************************************
+* Error Management
+****************************************************************/
+#define FSE_isError ERR_isError
+#define FSE_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) /* use only *after* variable declarations */
+
+
+/* **************************************************************
+* Templates
+****************************************************************/
+/*
+ designed to be included
+ for type-specific functions (template emulation in C)
+ Objective is to write these functions only once, for improved maintenance
+*/
+
+/* safety checks */
+#ifndef FSE_FUNCTION_EXTENSION
+# error "FSE_FUNCTION_EXTENSION must be defined"
+#endif
+#ifndef FSE_FUNCTION_TYPE
+# error "FSE_FUNCTION_TYPE must be defined"
+#endif
+
+/* Function names */
+#define FSE_CAT(X,Y) X##Y
+#define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y)
+#define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y)
+
+
+/* Function templates */
+FSE_DTable* FSE_createDTable (unsigned tableLog)
+{
+ if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX;
+ return (FSE_DTable*)malloc( FSE_DTABLE_SIZE_U32(tableLog) * sizeof (U32) );
+}
+
+void FSE_freeDTable (FSE_DTable* dt)
+{
+ free(dt);
+}
+
+size_t FSE_buildDTable(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)
+{
+ void* const tdPtr = dt+1; /* because *dt is unsigned, 32-bits aligned on 32-bits */
+ FSE_DECODE_TYPE* const tableDecode = (FSE_DECODE_TYPE*) (tdPtr);
+ U16 symbolNext[FSE_MAX_SYMBOL_VALUE+1];
+
+ U32 const maxSV1 = maxSymbolValue + 1;
+ U32 const tableSize = 1 << tableLog;
+ U32 highThreshold = tableSize-1;
+
+ /* Sanity Checks */
+ if (maxSymbolValue > FSE_MAX_SYMBOL_VALUE) return ERROR(maxSymbolValue_tooLarge);
+ if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge);
+
+ /* Init, lay down lowprob symbols */
+ { FSE_DTableHeader DTableH;
+ DTableH.tableLog = (U16)tableLog;
+ DTableH.fastMode = 1;
+ { S16 const largeLimit= (S16)(1 << (tableLog-1));
+ U32 s;
+ for (s=0; s<maxSV1; s++) {
+ if (normalizedCounter[s]==-1) {
+ tableDecode[highThreshold--].symbol = (FSE_FUNCTION_TYPE)s;
+ symbolNext[s] = 1;
+ } else {
+ if (normalizedCounter[s] >= largeLimit) DTableH.fastMode=0;
+ symbolNext[s] = normalizedCounter[s];
+ } } }
+ memcpy(dt, &DTableH, sizeof(DTableH));
+ }
+
+ /* Spread symbols */
+ { U32 const tableMask = tableSize-1;
+ U32 const step = FSE_TABLESTEP(tableSize);
+ U32 s, position = 0;
+ for (s=0; s<maxSV1; s++) {
+ int i;
+ for (i=0; i<normalizedCounter[s]; i++) {
+ tableDecode[position].symbol = (FSE_FUNCTION_TYPE)s;
+ position = (position + step) & tableMask;
+ while (position > highThreshold) position = (position + step) & tableMask; /* lowprob area */
+ } }
+ if (position!=0) return ERROR(GENERIC); /* position must reach all cells once, otherwise normalizedCounter is incorrect */
+ }
+
+ /* Build Decoding table */
+ { U32 u;
+ for (u=0; u<tableSize; u++) {
+ FSE_FUNCTION_TYPE const symbol = (FSE_FUNCTION_TYPE)(tableDecode[u].symbol);
+ U32 const nextState = symbolNext[symbol]++;
+ tableDecode[u].nbBits = (BYTE) (tableLog - BIT_highbit32(nextState) );
+ tableDecode[u].newState = (U16) ( (nextState << tableDecode[u].nbBits) - tableSize);
+ } }
+
+ return 0;
+}
+
+
+#ifndef FSE_COMMONDEFS_ONLY
+
+/*-*******************************************************
+* Decompression (Byte symbols)
+*********************************************************/
+size_t FSE_buildDTable_rle (FSE_DTable* dt, BYTE symbolValue)
+{
+ void* ptr = dt;
+ FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr;
+ void* dPtr = dt + 1;
+ FSE_decode_t* const cell = (FSE_decode_t*)dPtr;
+
+ DTableH->tableLog = 0;
+ DTableH->fastMode = 0;
+
+ cell->newState = 0;
+ cell->symbol = symbolValue;
+ cell->nbBits = 0;
+
+ return 0;
+}
+
+
+size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits)
+{
+ void* ptr = dt;
+ FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr;
+ void* dPtr = dt + 1;
+ FSE_decode_t* const dinfo = (FSE_decode_t*)dPtr;
+ const unsigned tableSize = 1 << nbBits;
+ const unsigned tableMask = tableSize - 1;
+ const unsigned maxSV1 = tableMask+1;
+ unsigned s;
+
+ /* Sanity checks */
+ if (nbBits < 1) return ERROR(GENERIC); /* min size */
+
+ /* Build Decoding Table */
+ DTableH->tableLog = (U16)nbBits;
+ DTableH->fastMode = 1;
+ for (s=0; s<maxSV1; s++) {
+ dinfo[s].newState = 0;
+ dinfo[s].symbol = (BYTE)s;
+ dinfo[s].nbBits = (BYTE)nbBits;
+ }
+
+ return 0;
+}
+
+FORCE_INLINE_TEMPLATE size_t FSE_decompress_usingDTable_generic(
+ void* dst, size_t maxDstSize,
+ const void* cSrc, size_t cSrcSize,
+ const FSE_DTable* dt, const unsigned fast)
+{
+ BYTE* const ostart = (BYTE*) dst;
+ BYTE* op = ostart;
+ BYTE* const omax = op + maxDstSize;
+ BYTE* const olimit = omax-3;
+
+ BIT_DStream_t bitD;
+ FSE_DState_t state1;
+ FSE_DState_t state2;
+
+ /* Init */
+ CHECK_F(BIT_initDStream(&bitD, cSrc, cSrcSize));
+
+ FSE_initDState(&state1, &bitD, dt);
+ FSE_initDState(&state2, &bitD, dt);
+
+#define FSE_GETSYMBOL(statePtr) fast ? FSE_decodeSymbolFast(statePtr, &bitD) : FSE_decodeSymbol(statePtr, &bitD)
+
+ /* 4 symbols per loop */
+ for ( ; (BIT_reloadDStream(&bitD)==BIT_DStream_unfinished) & (op<olimit) ; op+=4) {
+ op[0] = FSE_GETSYMBOL(&state1);
+
+ if (FSE_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */
+ BIT_reloadDStream(&bitD);
+
+ op[1] = FSE_GETSYMBOL(&state2);
+
+ if (FSE_MAX_TABLELOG*4+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */
+ { if (BIT_reloadDStream(&bitD) > BIT_DStream_unfinished) { op+=2; break; } }
+
+ op[2] = FSE_GETSYMBOL(&state1);
+
+ if (FSE_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */
+ BIT_reloadDStream(&bitD);
+
+ op[3] = FSE_GETSYMBOL(&state2);
+ }
+
+ /* tail */
+ /* note : BIT_reloadDStream(&bitD) >= FSE_DStream_partiallyFilled; Ends at exactly BIT_DStream_completed */
+ while (1) {
+ if (op>(omax-2)) return ERROR(dstSize_tooSmall);
+ *op++ = FSE_GETSYMBOL(&state1);
+ if (BIT_reloadDStream(&bitD)==BIT_DStream_overflow) {
+ *op++ = FSE_GETSYMBOL(&state2);
+ break;
+ }
+
+ if (op>(omax-2)) return ERROR(dstSize_tooSmall);
+ *op++ = FSE_GETSYMBOL(&state2);
+ if (BIT_reloadDStream(&bitD)==BIT_DStream_overflow) {
+ *op++ = FSE_GETSYMBOL(&state1);
+ break;
+ } }
+
+ return op-ostart;
+}
+
+
+size_t FSE_decompress_usingDTable(void* dst, size_t originalSize,
+ const void* cSrc, size_t cSrcSize,
+ const FSE_DTable* dt)
+{
+ const void* ptr = dt;
+ const FSE_DTableHeader* DTableH = (const FSE_DTableHeader*)ptr;
+ const U32 fastMode = DTableH->fastMode;
+
+ /* select fast mode (static) */
+ if (fastMode) return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 1);
+ return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 0);
+}
+
+
+size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, FSE_DTable* workSpace, unsigned maxLog)
+{
+ const BYTE* const istart = (const BYTE*)cSrc;
+ const BYTE* ip = istart;
+ short counting[FSE_MAX_SYMBOL_VALUE+1];
+ unsigned tableLog;
+ unsigned maxSymbolValue = FSE_MAX_SYMBOL_VALUE;
+
+ /* normal FSE decoding mode */
+ size_t const NCountLength = FSE_readNCount (counting, &maxSymbolValue, &tableLog, istart, cSrcSize);
+ if (FSE_isError(NCountLength)) return NCountLength;
+ /* if (NCountLength >= cSrcSize) return ERROR(srcSize_wrong); */ /* too small input size; supposed to be already checked in NCountLength, only remaining case : NCountLength==cSrcSize */
+ if (tableLog > maxLog) return ERROR(tableLog_tooLarge);
+ ip += NCountLength;
+ cSrcSize -= NCountLength;
+
+ CHECK_F( FSE_buildDTable (workSpace, counting, maxSymbolValue, tableLog) );
+
+ return FSE_decompress_usingDTable (dst, dstCapacity, ip, cSrcSize, workSpace); /* always return, even if it is an error code */
+}
+
+
+typedef FSE_DTable DTable_max_t[FSE_DTABLE_SIZE_U32(FSE_MAX_TABLELOG)];
+
+size_t FSE_decompress(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize)
+{
+ DTable_max_t dt; /* Static analyzer seems unable to understand this table will be properly initialized later */
+ return FSE_decompress_wksp(dst, dstCapacity, cSrc, cSrcSize, dt, FSE_MAX_TABLELOG);
+}
+
+
+
+#endif /* FSE_COMMONDEFS_ONLY */
diff --git a/sys/contrib/openzfs/module/zstd/lib/common/huf.h b/sys/contrib/openzfs/module/zstd/lib/common/huf.h
new file mode 100644
index 000000000000..ef432685dac8
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/common/huf.h
@@ -0,0 +1,340 @@
+/* ******************************************************************
+ * huff0 huffman codec,
+ * part of Finite State Entropy library
+ * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ *
+ * You can contact the author at :
+ * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+****************************************************************** */
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#ifndef HUF_H_298734234
+#define HUF_H_298734234
+
+/* *** Dependencies *** */
+#include <stddef.h> /* size_t */
+
+
+/* *** library symbols visibility *** */
+/* Note : when linking with -fvisibility=hidden on gcc, or by default on Visual,
+ * HUF symbols remain "private" (internal symbols for library only).
+ * Set macro FSE_DLL_EXPORT to 1 if you want HUF symbols visible on DLL interface */
+#if defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) && defined(__GNUC__) && (__GNUC__ >= 4)
+# define HUF_PUBLIC_API __attribute__ ((visibility ("default")))
+#elif defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) /* Visual expected */
+# define HUF_PUBLIC_API __declspec(dllexport)
+#elif defined(FSE_DLL_IMPORT) && (FSE_DLL_IMPORT==1)
+# define HUF_PUBLIC_API __declspec(dllimport) /* not required, just to generate faster code (saves a function pointer load from IAT and an indirect jump) */
+#else
+# define HUF_PUBLIC_API
+#endif
+
+
+/* ========================== */
+/* *** simple functions *** */
+/* ========================== */
+
+/** HUF_compress() :
+ * Compress content from buffer 'src', of size 'srcSize', into buffer 'dst'.
+ * 'dst' buffer must be already allocated.
+ * Compression runs faster if `dstCapacity` >= HUF_compressBound(srcSize).
+ * `srcSize` must be <= `HUF_BLOCKSIZE_MAX` == 128 KB.
+ * @return : size of compressed data (<= `dstCapacity`).
+ * Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!!
+ * if HUF_isError(return), compression failed (more details using HUF_getErrorName())
+ */
+HUF_PUBLIC_API size_t HUF_compress(void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize);
+
+/** HUF_decompress() :
+ * Decompress HUF data from buffer 'cSrc', of size 'cSrcSize',
+ * into already allocated buffer 'dst', of minimum size 'dstSize'.
+ * `originalSize` : **must** be the ***exact*** size of original (uncompressed) data.
+ * Note : in contrast with FSE, HUF_decompress can regenerate
+ * RLE (cSrcSize==1) and uncompressed (cSrcSize==dstSize) data,
+ * because it knows size to regenerate (originalSize).
+ * @return : size of regenerated data (== originalSize),
+ * or an error code, which can be tested using HUF_isError()
+ */
+HUF_PUBLIC_API size_t HUF_decompress(void* dst, size_t originalSize,
+ const void* cSrc, size_t cSrcSize);
+
+
+/* *** Tool functions *** */
+#define HUF_BLOCKSIZE_MAX (128 * 1024) /**< maximum input size for a single block compressed with HUF_compress */
+HUF_PUBLIC_API size_t HUF_compressBound(size_t size); /**< maximum compressed size (worst case) */
+
+/* Error Management */
+HUF_PUBLIC_API unsigned HUF_isError(size_t code); /**< tells if a return value is an error code */
+HUF_PUBLIC_API const char* HUF_getErrorName(size_t code); /**< provides error code string (useful for debugging) */
+
+
+/* *** Advanced function *** */
+
+/** HUF_compress2() :
+ * Same as HUF_compress(), but offers control over `maxSymbolValue` and `tableLog`.
+ * `maxSymbolValue` must be <= HUF_SYMBOLVALUE_MAX .
+ * `tableLog` must be `<= HUF_TABLELOG_MAX` . */
+HUF_PUBLIC_API size_t HUF_compress2 (void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ unsigned maxSymbolValue, unsigned tableLog);
+
+/** HUF_compress4X_wksp() :
+ * Same as HUF_compress2(), but uses externally allocated `workSpace`.
+ * `workspace` must have minimum alignment of 4, and be at least as large as HUF_WORKSPACE_SIZE */
+#define HUF_WORKSPACE_SIZE ((6 << 10) + 256)
+#define HUF_WORKSPACE_SIZE_U32 (HUF_WORKSPACE_SIZE / sizeof(U32))
+HUF_PUBLIC_API size_t HUF_compress4X_wksp (void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ unsigned maxSymbolValue, unsigned tableLog,
+ void* workSpace, size_t wkspSize);
+
+#endif /* HUF_H_298734234 */
+
+/* ******************************************************************
+ * WARNING !!
+ * The following section contains advanced and experimental definitions
+ * which shall never be used in the context of a dynamic library,
+ * because they are not guaranteed to remain stable in the future.
+ * Only consider them in association with static linking.
+ * *****************************************************************/
+#if defined(HUF_STATIC_LINKING_ONLY) && !defined(HUF_H_HUF_STATIC_LINKING_ONLY)
+#define HUF_H_HUF_STATIC_LINKING_ONLY
+
+/* *** Dependencies *** */
+#include "mem.h" /* U32 */
+
+
+/* *** Constants *** */
+#define HUF_TABLELOG_MAX 12 /* max runtime value of tableLog (due to static allocation); can be modified up to HUF_ABSOLUTEMAX_TABLELOG */
+#define HUF_TABLELOG_DEFAULT 11 /* default tableLog value when none specified */
+#define HUF_SYMBOLVALUE_MAX 255
+
+#define HUF_TABLELOG_ABSOLUTEMAX 15 /* absolute limit of HUF_MAX_TABLELOG. Beyond that value, code does not work */
+#if (HUF_TABLELOG_MAX > HUF_TABLELOG_ABSOLUTEMAX)
+# error "HUF_TABLELOG_MAX is too large !"
+#endif
+
+
+/* ****************************************
+* Static allocation
+******************************************/
+/* HUF buffer bounds */
+#define HUF_CTABLEBOUND 129
+#define HUF_BLOCKBOUND(size) (size + (size>>8) + 8) /* only true when incompressible is pre-filtered with fast heuristic */
+#define HUF_COMPRESSBOUND(size) (HUF_CTABLEBOUND + HUF_BLOCKBOUND(size)) /* Macro version, useful for static allocation */
+
+/* static allocation of HUF's Compression Table */
+#define HUF_CTABLE_SIZE_U32(maxSymbolValue) ((maxSymbolValue)+1) /* Use tables of U32, for proper alignment */
+#define HUF_CTABLE_SIZE(maxSymbolValue) (HUF_CTABLE_SIZE_U32(maxSymbolValue) * sizeof(U32))
+#define HUF_CREATE_STATIC_CTABLE(name, maxSymbolValue) \
+ U32 name##hb[HUF_CTABLE_SIZE_U32(maxSymbolValue)]; \
+ void* name##hv = &(name##hb); \
+ HUF_CElt* name = (HUF_CElt*)(name##hv) /* no final ; */
+
+/* static allocation of HUF's DTable */
+typedef U32 HUF_DTable;
+#define HUF_DTABLE_SIZE(maxTableLog) (1 + (1<<(maxTableLog)))
+#define HUF_CREATE_STATIC_DTABLEX1(DTable, maxTableLog) \
+ HUF_DTable DTable[HUF_DTABLE_SIZE((maxTableLog)-1)] = { ((U32)((maxTableLog)-1) * 0x01000001) }
+#define HUF_CREATE_STATIC_DTABLEX2(DTable, maxTableLog) \
+ HUF_DTable DTable[HUF_DTABLE_SIZE(maxTableLog)] = { ((U32)(maxTableLog) * 0x01000001) }
+
+
+/* ****************************************
+* Advanced decompression functions
+******************************************/
+size_t HUF_decompress4X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */
+#ifndef HUF_FORCE_DECOMPRESS_X1
+size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */
+#endif
+
+size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< decodes RLE and uncompressed */
+size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< considers RLE and uncompressed as errors */
+size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< considers RLE and uncompressed as errors */
+size_t HUF_decompress4X1_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */
+size_t HUF_decompress4X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< single-symbol decoder */
+#ifndef HUF_FORCE_DECOMPRESS_X1
+size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */
+size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< double-symbols decoder */
+#endif
+
+
+/* ****************************************
+ * HUF detailed API
+ * ****************************************/
+
+/*! HUF_compress() does the following:
+ * 1. count symbol occurrence from source[] into table count[] using FSE_count() (exposed within "fse.h")
+ * 2. (optional) refine tableLog using HUF_optimalTableLog()
+ * 3. build Huffman table from count using HUF_buildCTable()
+ * 4. save Huffman table to memory buffer using HUF_writeCTable()
+ * 5. encode the data stream using HUF_compress4X_usingCTable()
+ *
+ * The following API allows targeting specific sub-functions for advanced tasks.
+ * For example, it's possible to compress several blocks using the same 'CTable',
+ * or to save and regenerate 'CTable' using external methods.
+ */
+unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue);
+typedef struct HUF_CElt_s HUF_CElt; /* incomplete type */
+size_t HUF_buildCTable (HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue, unsigned maxNbBits); /* @return : maxNbBits; CTable and count can overlap. In which case, CTable will overwrite count content */
+size_t HUF_writeCTable (void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog);
+size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable);
+size_t HUF_estimateCompressedSize(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue);
+int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue);
+
+typedef enum {
+ HUF_repeat_none, /**< Cannot use the previous table */
+ HUF_repeat_check, /**< Can use the previous table but it must be checked. Note : The previous table must have been constructed by HUF_compress{1, 4}X_repeat */
+ HUF_repeat_valid /**< Can use the previous table and it is assumed to be valid */
+ } HUF_repeat;
+/** HUF_compress4X_repeat() :
+ * Same as HUF_compress4X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none.
+ * If it uses hufTable it does not modify hufTable or repeat.
+ * If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used.
+ * If preferRepeat then the old table will always be used if valid. */
+size_t HUF_compress4X_repeat(void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ unsigned maxSymbolValue, unsigned tableLog,
+ void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */
+ HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2);
+
+/** HUF_buildCTable_wksp() :
+ * Same as HUF_buildCTable(), but using externally allocated scratch buffer.
+ * `workSpace` must be aligned on 4-bytes boundaries, and its size must be >= HUF_CTABLE_WORKSPACE_SIZE.
+ */
+#define HUF_CTABLE_WORKSPACE_SIZE_U32 (2*HUF_SYMBOLVALUE_MAX +1 +1)
+#define HUF_CTABLE_WORKSPACE_SIZE (HUF_CTABLE_WORKSPACE_SIZE_U32 * sizeof(unsigned))
+size_t HUF_buildCTable_wksp (HUF_CElt* tree,
+ const unsigned* count, U32 maxSymbolValue, U32 maxNbBits,
+ void* workSpace, size_t wkspSize);
+
+/*! HUF_readStats() :
+ * Read compact Huffman tree, saved by HUF_writeCTable().
+ * `huffWeight` is destination buffer.
+ * @return : size read from `src` , or an error Code .
+ * Note : Needed by HUF_readCTable() and HUF_readDTableXn() . */
+size_t HUF_readStats(BYTE* huffWeight, size_t hwSize,
+ U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr,
+ const void* src, size_t srcSize);
+
+/** HUF_readCTable() :
+ * Loading a CTable saved with HUF_writeCTable() */
+size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned *hasZeroWeights);
+
+/** HUF_getNbBits() :
+ * Read nbBits from CTable symbolTable, for symbol `symbolValue` presumed <= HUF_SYMBOLVALUE_MAX
+ * Note 1 : is not inlined, as HUF_CElt definition is private
+ * Note 2 : const void* used, so that it can provide a statically allocated table as argument (which uses type U32) */
+U32 HUF_getNbBits(const void* symbolTable, U32 symbolValue);
+
+/*
+ * HUF_decompress() does the following:
+ * 1. select the decompression algorithm (X1, X2) based on pre-computed heuristics
+ * 2. build Huffman table from save, using HUF_readDTableX?()
+ * 3. decode 1 or 4 segments in parallel using HUF_decompress?X?_usingDTable()
+ */
+
+/** HUF_selectDecoder() :
+ * Tells which decoder is likely to decode faster,
+ * based on a set of pre-computed metrics.
+ * @return : 0==HUF_decompress4X1, 1==HUF_decompress4X2 .
+ * Assumption : 0 < dstSize <= 128 KB */
+U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize);
+
+/**
+ * The minimum workspace size for the `workSpace` used in
+ * HUF_readDTableX1_wksp() and HUF_readDTableX2_wksp().
+ *
+ * The space used depends on HUF_TABLELOG_MAX, ranging from ~1500 bytes when
+ * HUF_TABLE_LOG_MAX=12 to ~1850 bytes when HUF_TABLE_LOG_MAX=15.
+ * Buffer overflow errors may potentially occur if code modifications result in
+ * a required workspace size greater than that specified in the following
+ * macro.
+ */
+#define HUF_DECOMPRESS_WORKSPACE_SIZE (2 << 10)
+#define HUF_DECOMPRESS_WORKSPACE_SIZE_U32 (HUF_DECOMPRESS_WORKSPACE_SIZE / sizeof(U32))
+
+#ifndef HUF_FORCE_DECOMPRESS_X2
+size_t HUF_readDTableX1 (HUF_DTable* DTable, const void* src, size_t srcSize);
+size_t HUF_readDTableX1_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize);
+#endif
+#ifndef HUF_FORCE_DECOMPRESS_X1
+size_t HUF_readDTableX2 (HUF_DTable* DTable, const void* src, size_t srcSize);
+size_t HUF_readDTableX2_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize);
+#endif
+
+size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
+#ifndef HUF_FORCE_DECOMPRESS_X2
+size_t HUF_decompress4X1_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
+#endif
+#ifndef HUF_FORCE_DECOMPRESS_X1
+size_t HUF_decompress4X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
+#endif
+
+
+/* ====================== */
+/* single stream variants */
+/* ====================== */
+
+size_t HUF_compress1X (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog);
+size_t HUF_compress1X_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); /**< `workSpace` must be a table of at least HUF_WORKSPACE_SIZE_U32 unsigned */
+size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable);
+/** HUF_compress1X_repeat() :
+ * Same as HUF_compress1X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none.
+ * If it uses hufTable it does not modify hufTable or repeat.
+ * If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used.
+ * If preferRepeat then the old table will always be used if valid. */
+size_t HUF_compress1X_repeat(void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ unsigned maxSymbolValue, unsigned tableLog,
+ void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */
+ HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2);
+
+size_t HUF_decompress1X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* single-symbol decoder */
+#ifndef HUF_FORCE_DECOMPRESS_X1
+size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* double-symbol decoder */
+#endif
+
+size_t HUF_decompress1X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);
+size_t HUF_decompress1X_DCtx_wksp (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize);
+#ifndef HUF_FORCE_DECOMPRESS_X2
+size_t HUF_decompress1X1_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */
+size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< single-symbol decoder */
+#endif
+#ifndef HUF_FORCE_DECOMPRESS_X1
+size_t HUF_decompress1X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */
+size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< double-symbols decoder */
+#endif
+
+size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); /**< automatic selection of sing or double symbol decoder, based on DTable */
+#ifndef HUF_FORCE_DECOMPRESS_X2
+size_t HUF_decompress1X1_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
+#endif
+#ifndef HUF_FORCE_DECOMPRESS_X1
+size_t HUF_decompress1X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
+#endif
+
+/* BMI2 variants.
+ * If the CPU has BMI2 support, pass bmi2=1, otherwise pass bmi2=0.
+ */
+size_t HUF_decompress1X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2);
+#ifndef HUF_FORCE_DECOMPRESS_X2
+size_t HUF_decompress1X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2);
+#endif
+size_t HUF_decompress4X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2);
+size_t HUF_decompress4X_hufOnly_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2);
+
+#endif /* HUF_STATIC_LINKING_ONLY */
+
+#if defined (__cplusplus)
+}
+#endif
diff --git a/sys/contrib/openzfs/module/zstd/lib/common/mem.h b/sys/contrib/openzfs/module/zstd/lib/common/mem.h
new file mode 100644
index 000000000000..7fbb2e98215e
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/common/mem.h
@@ -0,0 +1,450 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef MEM_H_MODULE
+#define MEM_H_MODULE
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+/*-****************************************
+* Dependencies
+******************************************/
+#include <stddef.h> /* size_t, ptrdiff_t */
+#include <string.h> /* memcpy */
+
+
+/*-****************************************
+* Compiler specifics
+******************************************/
+#if defined(_MSC_VER) /* Visual Studio */
+# include <stdlib.h> /* _byteswap_ulong */
+# include <intrin.h> /* _byteswap_* */
+#endif
+#if defined(__GNUC__)
+# define MEM_STATIC static __inline __attribute__((unused))
+#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
+# define MEM_STATIC static inline
+#elif defined(_MSC_VER)
+# define MEM_STATIC static __inline
+#else
+# define MEM_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */
+#endif
+
+#ifndef __has_builtin
+# define __has_builtin(x) 0 /* compat. with non-clang compilers */
+#endif
+
+/* code only tested on 32 and 64 bits systems */
+#define MEM_STATIC_ASSERT(c) { enum { MEM_static_assert = 1/(int)(!!(c)) }; }
+MEM_STATIC void MEM_check(void) { MEM_STATIC_ASSERT((sizeof(size_t)==4) || (sizeof(size_t)==8)); }
+
+/* detects whether we are being compiled under msan */
+#if defined (__has_feature)
+# if __has_feature(memory_sanitizer)
+# define MEMORY_SANITIZER 1
+# endif
+#endif
+
+#if defined (MEMORY_SANITIZER)
+/* Not all platforms that support msan provide sanitizers/msan_interface.h.
+ * We therefore declare the functions we need ourselves, rather than trying to
+ * include the header file... */
+
+#include <stdint.h> /* intptr_t */
+
+/* Make memory region fully initialized (without changing its contents). */
+void __msan_unpoison(const volatile void *a, size_t size);
+
+/* Make memory region fully uninitialized (without changing its contents).
+ This is a legacy interface that does not update origin information. Use
+ __msan_allocated_memory() instead. */
+void __msan_poison(const volatile void *a, size_t size);
+
+/* Returns the offset of the first (at least partially) poisoned byte in the
+ memory range, or -1 if the whole range is good. */
+intptr_t __msan_test_shadow(const volatile void *x, size_t size);
+#endif
+
+/* detects whether we are being compiled under asan */
+#if defined (ZFS_ASAN_ENABLED)
+# define ADDRESS_SANITIZER 1
+# define ZSTD_ASAN_DONT_POISON_WORKSPACE
+#endif
+
+#if defined (ADDRESS_SANITIZER)
+/* Not all platforms that support asan provide sanitizers/asan_interface.h.
+ * We therefore declare the functions we need ourselves, rather than trying to
+ * include the header file... */
+
+/**
+ * Marks a memory region (<c>[addr, addr+size)</c>) as unaddressable.
+ *
+ * This memory must be previously allocated by your program. Instrumented
+ * code is forbidden from accessing addresses in this region until it is
+ * unpoisoned. This function is not guaranteed to poison the entire region -
+ * it could poison only a subregion of <c>[addr, addr+size)</c> due to ASan
+ * alignment restrictions.
+ *
+ * \note This function is not thread-safe because no two threads can poison or
+ * unpoison memory in the same memory region simultaneously.
+ *
+ * \param addr Start of memory region.
+ * \param size Size of memory region. */
+void __asan_poison_memory_region(void const volatile *addr, size_t size);
+
+/**
+ * Marks a memory region (<c>[addr, addr+size)</c>) as addressable.
+ *
+ * This memory must be previously allocated by your program. Accessing
+ * addresses in this region is allowed until this region is poisoned again.
+ * This function could unpoison a super-region of <c>[addr, addr+size)</c> due
+ * to ASan alignment restrictions.
+ *
+ * \note This function is not thread-safe because no two threads can
+ * poison or unpoison memory in the same memory region simultaneously.
+ *
+ * \param addr Start of memory region.
+ * \param size Size of memory region. */
+void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
+#endif
+
+
+/*-**************************************************************
+* Basic Types
+*****************************************************************/
+#if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
+# include <stdint.h>
+ typedef uint8_t BYTE;
+ typedef uint16_t U16;
+ typedef int16_t S16;
+ typedef uint32_t U32;
+ typedef int32_t S32;
+ typedef uint64_t U64;
+ typedef int64_t S64;
+#else
+# include <limits.h>
+#if CHAR_BIT != 8
+# error "this implementation requires char to be exactly 8-bit type"
+#endif
+ typedef unsigned char BYTE;
+#if USHRT_MAX != 65535
+# error "this implementation requires short to be exactly 16-bit type"
+#endif
+ typedef unsigned short U16;
+ typedef signed short S16;
+#if UINT_MAX != 4294967295
+# error "this implementation requires int to be exactly 32-bit type"
+#endif
+ typedef unsigned int U32;
+ typedef signed int S32;
+/* note : there are no limits defined for long long type in C90.
+ * limits exist in C99, however, in such case, <stdint.h> is preferred */
+ typedef unsigned long long U64;
+ typedef signed long long S64;
+#endif
+
+
+/*-**************************************************************
+* Memory I/O
+*****************************************************************/
+/* MEM_FORCE_MEMORY_ACCESS :
+ * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.
+ * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.
+ * The below switch allow to select different access method for improved performance.
+ * Method 0 (default) : use `memcpy()`. Safe and portable.
+ * Method 1 : `__packed` statement. It depends on compiler extension (i.e., not portable).
+ * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.
+ * Method 2 : direct access. This method is portable but violate C standard.
+ * It can generate buggy code on targets depending on alignment.
+ * In some circumstances, it's the only known way to get the most performance (i.e. GCC + ARMv6)
+ * See http://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details.
+ * Prefer these methods in priority order (0 > 1 > 2)
+ */
+#ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */
+# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) )
+# define MEM_FORCE_MEMORY_ACCESS 2
+# elif defined(__INTEL_COMPILER) || defined(__GNUC__) || defined(__ICCARM__)
+# define MEM_FORCE_MEMORY_ACCESS 1
+# endif
+#endif
+
+MEM_STATIC unsigned MEM_32bits(void) { return sizeof(size_t)==4; }
+MEM_STATIC unsigned MEM_64bits(void) { return sizeof(size_t)==8; }
+
+MEM_STATIC unsigned MEM_isLittleEndian(void)
+{
+ const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */
+ return one.c[0];
+}
+
+#if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2)
+
+/* violates C standard, by lying on structure alignment.
+Only use if no other choice to achieve best performance on target platform */
+MEM_STATIC U16 MEM_read16(const void* memPtr) { return *(const U16*) memPtr; }
+MEM_STATIC U32 MEM_read32(const void* memPtr) { return *(const U32*) memPtr; }
+MEM_STATIC U64 MEM_read64(const void* memPtr) { return *(const U64*) memPtr; }
+MEM_STATIC size_t MEM_readST(const void* memPtr) { return *(const size_t*) memPtr; }
+
+MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; }
+MEM_STATIC void MEM_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; }
+MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(U64*)memPtr = value; }
+
+#elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1)
+
+/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
+/* currently only defined for gcc and icc */
+#if defined(_MSC_VER) || (defined(__INTEL_COMPILER) && defined(WIN32))
+ __pragma( pack(push, 1) )
+ typedef struct { U16 v; } unalign16;
+ typedef struct { U32 v; } unalign32;
+ typedef struct { U64 v; } unalign64;
+ typedef struct { size_t v; } unalignArch;
+ __pragma( pack(pop) )
+#else
+ typedef struct { U16 v; } __attribute__((packed)) unalign16;
+ typedef struct { U32 v; } __attribute__((packed)) unalign32;
+ typedef struct { U64 v; } __attribute__((packed)) unalign64;
+ typedef struct { size_t v; } __attribute__((packed)) unalignArch;
+#endif
+
+MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign16*)ptr)->v; }
+MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign32*)ptr)->v; }
+MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign64*)ptr)->v; }
+MEM_STATIC size_t MEM_readST(const void* ptr) { return ((const unalignArch*)ptr)->v; }
+
+MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign16*)memPtr)->v = value; }
+MEM_STATIC void MEM_write32(void* memPtr, U32 value) { ((unalign32*)memPtr)->v = value; }
+MEM_STATIC void MEM_write64(void* memPtr, U64 value) { ((unalign64*)memPtr)->v = value; }
+
+#else
+
+/* default method, safe and standard.
+ can sometimes prove slower */
+
+MEM_STATIC U16 MEM_read16(const void* memPtr)
+{
+ U16 val; memcpy(&val, memPtr, sizeof(val)); return val;
+}
+
+MEM_STATIC U32 MEM_read32(const void* memPtr)
+{
+ U32 val; memcpy(&val, memPtr, sizeof(val)); return val;
+}
+
+MEM_STATIC U64 MEM_read64(const void* memPtr)
+{
+ U64 val; memcpy(&val, memPtr, sizeof(val)); return val;
+}
+
+MEM_STATIC size_t MEM_readST(const void* memPtr)
+{
+ size_t val; memcpy(&val, memPtr, sizeof(val)); return val;
+}
+
+MEM_STATIC void MEM_write16(void* memPtr, U16 value)
+{
+ memcpy(memPtr, &value, sizeof(value));
+}
+
+MEM_STATIC void MEM_write32(void* memPtr, U32 value)
+{
+ memcpy(memPtr, &value, sizeof(value));
+}
+
+MEM_STATIC void MEM_write64(void* memPtr, U64 value)
+{
+ memcpy(memPtr, &value, sizeof(value));
+}
+
+#endif /* MEM_FORCE_MEMORY_ACCESS */
+
+MEM_STATIC U32 MEM_swap32(U32 in)
+{
+#if defined(_MSC_VER) /* Visual Studio */
+ return _byteswap_ulong(in);
+#elif (defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) \
+ || (defined(__clang__) && __has_builtin(__builtin_bswap32))
+ return __builtin_bswap32(in);
+#else
+ return ((in << 24) & 0xff000000 ) |
+ ((in << 8) & 0x00ff0000 ) |
+ ((in >> 8) & 0x0000ff00 ) |
+ ((in >> 24) & 0x000000ff );
+#endif
+}
+
+MEM_STATIC U64 MEM_swap64(U64 in)
+{
+#if defined(_MSC_VER) /* Visual Studio */
+ return _byteswap_uint64(in);
+#elif (defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) \
+ || (defined(__clang__) && __has_builtin(__builtin_bswap64))
+ return __builtin_bswap64(in);
+#else
+ return ((in << 56) & 0xff00000000000000ULL) |
+ ((in << 40) & 0x00ff000000000000ULL) |
+ ((in << 24) & 0x0000ff0000000000ULL) |
+ ((in << 8) & 0x000000ff00000000ULL) |
+ ((in >> 8) & 0x00000000ff000000ULL) |
+ ((in >> 24) & 0x0000000000ff0000ULL) |
+ ((in >> 40) & 0x000000000000ff00ULL) |
+ ((in >> 56) & 0x00000000000000ffULL);
+#endif
+}
+
+MEM_STATIC size_t MEM_swapST(size_t in)
+{
+ if (MEM_32bits())
+ return (size_t)MEM_swap32((U32)in);
+ else
+ return (size_t)MEM_swap64((U64)in);
+}
+
+/*=== Little endian r/w ===*/
+
+MEM_STATIC U16 MEM_readLE16(const void* memPtr)
+{
+ if (MEM_isLittleEndian())
+ return MEM_read16(memPtr);
+ else {
+ const BYTE* p = (const BYTE*)memPtr;
+ return (U16)(p[0] + (p[1]<<8));
+ }
+}
+
+MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val)
+{
+ if (MEM_isLittleEndian()) {
+ MEM_write16(memPtr, val);
+ } else {
+ BYTE* p = (BYTE*)memPtr;
+ p[0] = (BYTE)val;
+ p[1] = (BYTE)(val>>8);
+ }
+}
+
+MEM_STATIC U32 MEM_readLE24(const void* memPtr)
+{
+ return MEM_readLE16(memPtr) + (((const BYTE*)memPtr)[2] << 16);
+}
+
+MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val)
+{
+ MEM_writeLE16(memPtr, (U16)val);
+ ((BYTE*)memPtr)[2] = (BYTE)(val>>16);
+}
+
+MEM_STATIC U32 MEM_readLE32(const void* memPtr)
+{
+ if (MEM_isLittleEndian())
+ return MEM_read32(memPtr);
+ else
+ return MEM_swap32(MEM_read32(memPtr));
+}
+
+MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32)
+{
+ if (MEM_isLittleEndian())
+ MEM_write32(memPtr, val32);
+ else
+ MEM_write32(memPtr, MEM_swap32(val32));
+}
+
+MEM_STATIC U64 MEM_readLE64(const void* memPtr)
+{
+ if (MEM_isLittleEndian())
+ return MEM_read64(memPtr);
+ else
+ return MEM_swap64(MEM_read64(memPtr));
+}
+
+MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64)
+{
+ if (MEM_isLittleEndian())
+ MEM_write64(memPtr, val64);
+ else
+ MEM_write64(memPtr, MEM_swap64(val64));
+}
+
+MEM_STATIC size_t MEM_readLEST(const void* memPtr)
+{
+ if (MEM_32bits())
+ return (size_t)MEM_readLE32(memPtr);
+ else
+ return (size_t)MEM_readLE64(memPtr);
+}
+
+MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val)
+{
+ if (MEM_32bits())
+ MEM_writeLE32(memPtr, (U32)val);
+ else
+ MEM_writeLE64(memPtr, (U64)val);
+}
+
+/*=== Big endian r/w ===*/
+
+MEM_STATIC U32 MEM_readBE32(const void* memPtr)
+{
+ if (MEM_isLittleEndian())
+ return MEM_swap32(MEM_read32(memPtr));
+ else
+ return MEM_read32(memPtr);
+}
+
+MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32)
+{
+ if (MEM_isLittleEndian())
+ MEM_write32(memPtr, MEM_swap32(val32));
+ else
+ MEM_write32(memPtr, val32);
+}
+
+MEM_STATIC U64 MEM_readBE64(const void* memPtr)
+{
+ if (MEM_isLittleEndian())
+ return MEM_swap64(MEM_read64(memPtr));
+ else
+ return MEM_read64(memPtr);
+}
+
+MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64)
+{
+ if (MEM_isLittleEndian())
+ MEM_write64(memPtr, MEM_swap64(val64));
+ else
+ MEM_write64(memPtr, val64);
+}
+
+MEM_STATIC size_t MEM_readBEST(const void* memPtr)
+{
+ if (MEM_32bits())
+ return (size_t)MEM_readBE32(memPtr);
+ else
+ return (size_t)MEM_readBE64(memPtr);
+}
+
+MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val)
+{
+ if (MEM_32bits())
+ MEM_writeBE32(memPtr, (U32)val);
+ else
+ MEM_writeBE64(memPtr, (U64)val);
+}
+
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* MEM_H_MODULE */
diff --git a/sys/contrib/openzfs/module/zstd/lib/common/pool.c b/sys/contrib/openzfs/module/zstd/lib/common/pool.c
new file mode 100644
index 000000000000..aa4b4de0d3f6
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/common/pool.c
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+
+/* ====== Dependencies ======= */
+#include <stddef.h> /* size_t */
+#include "debug.h" /* assert */
+#include "zstd_internal.h" /* ZSTD_malloc, ZSTD_free */
+#include "pool.h"
+
+/* ====== Compiler specifics ====== */
+#if defined(_MSC_VER)
+# pragma warning(disable : 4204) /* disable: C4204: non-constant aggregate initializer */
+#endif
+
+
+#ifdef ZSTD_MULTITHREAD
+
+#include "threading.h" /* pthread adaptation */
+
+/* A job is a function and an opaque argument */
+typedef struct POOL_job_s {
+ POOL_function function;
+ void *opaque;
+} POOL_job;
+
+struct POOL_ctx_s {
+ ZSTD_customMem customMem;
+ /* Keep track of the threads */
+ ZSTD_pthread_t* threads;
+ size_t threadCapacity;
+ size_t threadLimit;
+
+ /* The queue is a circular buffer */
+ POOL_job *queue;
+ size_t queueHead;
+ size_t queueTail;
+ size_t queueSize;
+
+ /* The number of threads working on jobs */
+ size_t numThreadsBusy;
+ /* Indicates if the queue is empty */
+ int queueEmpty;
+
+ /* The mutex protects the queue */
+ ZSTD_pthread_mutex_t queueMutex;
+ /* Condition variable for pushers to wait on when the queue is full */
+ ZSTD_pthread_cond_t queuePushCond;
+ /* Condition variables for poppers to wait on when the queue is empty */
+ ZSTD_pthread_cond_t queuePopCond;
+ /* Indicates if the queue is shutting down */
+ int shutdown;
+};
+
+/* POOL_thread() :
+ * Work thread for the thread pool.
+ * Waits for jobs and executes them.
+ * @returns : NULL on failure else non-null.
+ */
+static void* POOL_thread(void* opaque) {
+ POOL_ctx* const ctx = (POOL_ctx*)opaque;
+ if (!ctx) { return NULL; }
+ for (;;) {
+ /* Lock the mutex and wait for a non-empty queue or until shutdown */
+ ZSTD_pthread_mutex_lock(&ctx->queueMutex);
+
+ while ( ctx->queueEmpty
+ || (ctx->numThreadsBusy >= ctx->threadLimit) ) {
+ if (ctx->shutdown) {
+ /* even if !queueEmpty, (possible if numThreadsBusy >= threadLimit),
+ * a few threads will be shutdown while !queueEmpty,
+ * but enough threads will remain active to finish the queue */
+ ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+ return opaque;
+ }
+ ZSTD_pthread_cond_wait(&ctx->queuePopCond, &ctx->queueMutex);
+ }
+ /* Pop a job off the queue */
+ { POOL_job const job = ctx->queue[ctx->queueHead];
+ ctx->queueHead = (ctx->queueHead + 1) % ctx->queueSize;
+ ctx->numThreadsBusy++;
+ ctx->queueEmpty = ctx->queueHead == ctx->queueTail;
+ /* Unlock the mutex, signal a pusher, and run the job */
+ ZSTD_pthread_cond_signal(&ctx->queuePushCond);
+ ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+
+ job.function(job.opaque);
+
+ /* If the intended queue size was 0, signal after finishing job */
+ ZSTD_pthread_mutex_lock(&ctx->queueMutex);
+ ctx->numThreadsBusy--;
+ if (ctx->queueSize == 1) {
+ ZSTD_pthread_cond_signal(&ctx->queuePushCond);
+ }
+ ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+ }
+ } /* for (;;) */
+ assert(0); /* Unreachable */
+}
+
+POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) {
+ return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem);
+}
+
+POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize,
+ ZSTD_customMem customMem) {
+ POOL_ctx* ctx;
+ /* Check parameters */
+ if (!numThreads) { return NULL; }
+ /* Allocate the context and zero initialize */
+ ctx = (POOL_ctx*)ZSTD_calloc(sizeof(POOL_ctx), customMem);
+ if (!ctx) { return NULL; }
+ /* Initialize the job queue.
+ * It needs one extra space since one space is wasted to differentiate
+ * empty and full queues.
+ */
+ ctx->queueSize = queueSize + 1;
+ ctx->queue = (POOL_job*)ZSTD_malloc(ctx->queueSize * sizeof(POOL_job), customMem);
+ ctx->queueHead = 0;
+ ctx->queueTail = 0;
+ ctx->numThreadsBusy = 0;
+ ctx->queueEmpty = 1;
+ {
+ int error = 0;
+ error |= ZSTD_pthread_mutex_init(&ctx->queueMutex, NULL);
+ error |= ZSTD_pthread_cond_init(&ctx->queuePushCond, NULL);
+ error |= ZSTD_pthread_cond_init(&ctx->queuePopCond, NULL);
+ if (error) { POOL_free(ctx); return NULL; }
+ }
+ ctx->shutdown = 0;
+ /* Allocate space for the thread handles */
+ ctx->threads = (ZSTD_pthread_t*)ZSTD_malloc(numThreads * sizeof(ZSTD_pthread_t), customMem);
+ ctx->threadCapacity = 0;
+ ctx->customMem = customMem;
+ /* Check for errors */
+ if (!ctx->threads || !ctx->queue) { POOL_free(ctx); return NULL; }
+ /* Initialize the threads */
+ { size_t i;
+ for (i = 0; i < numThreads; ++i) {
+ if (ZSTD_pthread_create(&ctx->threads[i], NULL, &POOL_thread, ctx)) {
+ ctx->threadCapacity = i;
+ POOL_free(ctx);
+ return NULL;
+ } }
+ ctx->threadCapacity = numThreads;
+ ctx->threadLimit = numThreads;
+ }
+ return ctx;
+}
+
+/*! POOL_join() :
+ Shutdown the queue, wake any sleeping threads, and join all of the threads.
+*/
+static void POOL_join(POOL_ctx* ctx) {
+ /* Shut down the queue */
+ ZSTD_pthread_mutex_lock(&ctx->queueMutex);
+ ctx->shutdown = 1;
+ ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+ /* Wake up sleeping threads */
+ ZSTD_pthread_cond_broadcast(&ctx->queuePushCond);
+ ZSTD_pthread_cond_broadcast(&ctx->queuePopCond);
+ /* Join all of the threads */
+ { size_t i;
+ for (i = 0; i < ctx->threadCapacity; ++i) {
+ ZSTD_pthread_join(ctx->threads[i], NULL); /* note : could fail */
+ } }
+}
+
+void POOL_free(POOL_ctx *ctx) {
+ if (!ctx) { return; }
+ POOL_join(ctx);
+ ZSTD_pthread_mutex_destroy(&ctx->queueMutex);
+ ZSTD_pthread_cond_destroy(&ctx->queuePushCond);
+ ZSTD_pthread_cond_destroy(&ctx->queuePopCond);
+ ZSTD_free(ctx->queue, ctx->customMem);
+ ZSTD_free(ctx->threads, ctx->customMem);
+ ZSTD_free(ctx, ctx->customMem);
+}
+
+
+
+size_t POOL_sizeof(POOL_ctx *ctx) {
+ if (ctx==NULL) return 0; /* supports sizeof NULL */
+ return sizeof(*ctx)
+ + ctx->queueSize * sizeof(POOL_job)
+ + ctx->threadCapacity * sizeof(ZSTD_pthread_t);
+}
+
+
+/* @return : 0 on success, 1 on error */
+static int POOL_resize_internal(POOL_ctx* ctx, size_t numThreads)
+{
+ if (numThreads <= ctx->threadCapacity) {
+ if (!numThreads) return 1;
+ ctx->threadLimit = numThreads;
+ return 0;
+ }
+ /* numThreads > threadCapacity */
+ { ZSTD_pthread_t* const threadPool = (ZSTD_pthread_t*)ZSTD_malloc(numThreads * sizeof(ZSTD_pthread_t), ctx->customMem);
+ if (!threadPool) return 1;
+ /* replace existing thread pool */
+ memcpy(threadPool, ctx->threads, ctx->threadCapacity * sizeof(*threadPool));
+ ZSTD_free(ctx->threads, ctx->customMem);
+ ctx->threads = threadPool;
+ /* Initialize additional threads */
+ { size_t threadId;
+ for (threadId = ctx->threadCapacity; threadId < numThreads; ++threadId) {
+ if (ZSTD_pthread_create(&threadPool[threadId], NULL, &POOL_thread, ctx)) {
+ ctx->threadCapacity = threadId;
+ return 1;
+ } }
+ } }
+ /* successfully expanded */
+ ctx->threadCapacity = numThreads;
+ ctx->threadLimit = numThreads;
+ return 0;
+}
+
+/* @return : 0 on success, 1 on error */
+int POOL_resize(POOL_ctx* ctx, size_t numThreads)
+{
+ int result;
+ if (ctx==NULL) return 1;
+ ZSTD_pthread_mutex_lock(&ctx->queueMutex);
+ result = POOL_resize_internal(ctx, numThreads);
+ ZSTD_pthread_cond_broadcast(&ctx->queuePopCond);
+ ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+ return result;
+}
+
+/**
+ * Returns 1 if the queue is full and 0 otherwise.
+ *
+ * When queueSize is 1 (pool was created with an intended queueSize of 0),
+ * then a queue is empty if there is a thread free _and_ no job is waiting.
+ */
+static int isQueueFull(POOL_ctx const* ctx) {
+ if (ctx->queueSize > 1) {
+ return ctx->queueHead == ((ctx->queueTail + 1) % ctx->queueSize);
+ } else {
+ return (ctx->numThreadsBusy == ctx->threadLimit) ||
+ !ctx->queueEmpty;
+ }
+}
+
+
+static void POOL_add_internal(POOL_ctx* ctx, POOL_function function, void *opaque)
+{
+ POOL_job const job = {function, opaque};
+ assert(ctx != NULL);
+ if (ctx->shutdown) return;
+
+ ctx->queueEmpty = 0;
+ ctx->queue[ctx->queueTail] = job;
+ ctx->queueTail = (ctx->queueTail + 1) % ctx->queueSize;
+ ZSTD_pthread_cond_signal(&ctx->queuePopCond);
+}
+
+void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque)
+{
+ assert(ctx != NULL);
+ ZSTD_pthread_mutex_lock(&ctx->queueMutex);
+ /* Wait until there is space in the queue for the new job */
+ while (isQueueFull(ctx) && (!ctx->shutdown)) {
+ ZSTD_pthread_cond_wait(&ctx->queuePushCond, &ctx->queueMutex);
+ }
+ POOL_add_internal(ctx, function, opaque);
+ ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+}
+
+
+int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque)
+{
+ assert(ctx != NULL);
+ ZSTD_pthread_mutex_lock(&ctx->queueMutex);
+ if (isQueueFull(ctx)) {
+ ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+ return 0;
+ }
+ POOL_add_internal(ctx, function, opaque);
+ ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+ return 1;
+}
+
+
+#else /* ZSTD_MULTITHREAD not defined */
+
+/* ========================== */
+/* No multi-threading support */
+/* ========================== */
+
+
+/* We don't need any data, but if it is empty, malloc() might return NULL. */
+struct POOL_ctx_s {
+ int dummy;
+};
+static POOL_ctx g_ctx;
+
+POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) {
+ return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem);
+}
+
+POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customMem customMem) {
+ (void)numThreads;
+ (void)queueSize;
+ (void)customMem;
+ return &g_ctx;
+}
+
+void POOL_free(POOL_ctx* ctx) {
+ assert(!ctx || ctx == &g_ctx);
+ (void)ctx;
+}
+
+int POOL_resize(POOL_ctx* ctx, size_t numThreads) {
+ (void)ctx; (void)numThreads;
+ return 0;
+}
+
+void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque) {
+ (void)ctx;
+ function(opaque);
+}
+
+int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque) {
+ (void)ctx;
+ function(opaque);
+ return 1;
+}
+
+size_t POOL_sizeof(POOL_ctx* ctx) {
+ if (ctx==NULL) return 0; /* supports sizeof NULL */
+ assert(ctx == &g_ctx);
+ return sizeof(*ctx);
+}
+
+#endif /* ZSTD_MULTITHREAD */
diff --git a/sys/contrib/openzfs/module/zstd/lib/common/pool.h b/sys/contrib/openzfs/module/zstd/lib/common/pool.h
new file mode 100644
index 000000000000..259bafc97570
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/common/pool.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef POOL_H
+#define POOL_H
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+
+#include <stddef.h> /* size_t */
+#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_customMem */
+#include "../zstd.h"
+
+typedef struct POOL_ctx_s POOL_ctx;
+
+/*! POOL_create() :
+ * Create a thread pool with at most `numThreads` threads.
+ * `numThreads` must be at least 1.
+ * The maximum number of queued jobs before blocking is `queueSize`.
+ * @return : POOL_ctx pointer on success, else NULL.
+*/
+POOL_ctx* POOL_create(size_t numThreads, size_t queueSize);
+
+POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize,
+ ZSTD_customMem customMem);
+
+/*! POOL_free() :
+ * Free a thread pool returned by POOL_create().
+ */
+void POOL_free(POOL_ctx* ctx);
+
+/*! POOL_resize() :
+ * Expands or shrinks pool's number of threads.
+ * This is more efficient than releasing + creating a new context,
+ * since it tries to preserve and re-use existing threads.
+ * `numThreads` must be at least 1.
+ * @return : 0 when resize was successful,
+ * !0 (typically 1) if there is an error.
+ * note : only numThreads can be resized, queueSize remains unchanged.
+ */
+int POOL_resize(POOL_ctx* ctx, size_t numThreads);
+
+/*! POOL_sizeof() :
+ * @return threadpool memory usage
+ * note : compatible with NULL (returns 0 in this case)
+ */
+size_t POOL_sizeof(POOL_ctx* ctx);
+
+/*! POOL_function :
+ * The function type that can be added to a thread pool.
+ */
+typedef void (*POOL_function)(void*);
+
+/*! POOL_add() :
+ * Add the job `function(opaque)` to the thread pool. `ctx` must be valid.
+ * Possibly blocks until there is room in the queue.
+ * Note : The function may be executed asynchronously,
+ * therefore, `opaque` must live until function has been completed.
+ */
+void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque);
+
+
+/*! POOL_tryAdd() :
+ * Add the job `function(opaque)` to thread pool _if_ a worker is available.
+ * Returns immediately even if not (does not block).
+ * @return : 1 if successful, 0 if not.
+ */
+int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque);
+
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif
diff --git a/sys/contrib/openzfs/module/zstd/lib/common/xxhash.c b/sys/contrib/openzfs/module/zstd/lib/common/xxhash.c
new file mode 100644
index 000000000000..597de18fc895
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/common/xxhash.c
@@ -0,0 +1,864 @@
+/*
+ * xxHash - Fast Hash algorithm
+ * Copyright (c) 2012-2020, Yann Collet, Facebook, Inc.
+ *
+ * You can contact the author at :
+ * - xxHash homepage: http://www.xxhash.com
+ * - xxHash source repository : https://github.com/Cyan4973/xxHash
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+*/
+
+
+/* *************************************
+* Tuning parameters
+***************************************/
+/*!XXH_FORCE_MEMORY_ACCESS :
+ * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.
+ * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.
+ * The below switch allow to select different access method for improved performance.
+ * Method 0 (default) : use `memcpy()`. Safe and portable.
+ * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable).
+ * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.
+ * Method 2 : direct access. This method doesn't depend on compiler but violate C standard.
+ * It can generate buggy code on targets which do not support unaligned memory accesses.
+ * But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6)
+ * See http://stackoverflow.com/a/32095106/646947 for details.
+ * Prefer these methods in priority order (0 > 1 > 2)
+ */
+#ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */
+# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) )
+# define XXH_FORCE_MEMORY_ACCESS 2
+# elif (defined(__INTEL_COMPILER) && !defined(WIN32)) || \
+ (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) )) || \
+ defined(__ICCARM__)
+# define XXH_FORCE_MEMORY_ACCESS 1
+# endif
+#endif
+
+/*!XXH_ACCEPT_NULL_INPUT_POINTER :
+ * If the input pointer is a null pointer, xxHash default behavior is to trigger a memory access error, since it is a bad pointer.
+ * When this option is enabled, xxHash output for null input pointers will be the same as a null-length input.
+ * By default, this option is disabled. To enable it, uncomment below define :
+ */
+/* #define XXH_ACCEPT_NULL_INPUT_POINTER 1 */
+
+/*!XXH_FORCE_NATIVE_FORMAT :
+ * By default, xxHash library provides endian-independent Hash values, based on little-endian convention.
+ * Results are therefore identical for little-endian and big-endian CPU.
+ * This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format.
+ * Should endian-independence be of no importance for your application, you may set the #define below to 1,
+ * to improve speed for Big-endian CPU.
+ * This option has no impact on Little_Endian CPU.
+ */
+#ifndef XXH_FORCE_NATIVE_FORMAT /* can be defined externally */
+# define XXH_FORCE_NATIVE_FORMAT 0
+#endif
+
+/*!XXH_FORCE_ALIGN_CHECK :
+ * This is a minor performance trick, only useful with lots of very small keys.
+ * It means : check for aligned/unaligned input.
+ * The check costs one initial branch per hash; set to 0 when the input data
+ * is guaranteed to be aligned.
+ */
+#ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */
+# if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)
+# define XXH_FORCE_ALIGN_CHECK 0
+# else
+# define XXH_FORCE_ALIGN_CHECK 1
+# endif
+#endif
+
+
+/* *************************************
+* Includes & Memory related functions
+***************************************/
+/* Modify the local functions below should you wish to use some other memory routines */
+/* for malloc(), free() */
+#include <stdlib.h>
+#include <stddef.h> /* size_t */
+static void* XXH_malloc(size_t s) { return malloc(s); }
+static void XXH_free (void* p) { free(p); }
+/* for memcpy() */
+#include <string.h>
+static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcpy(dest,src,size); }
+
+#ifndef XXH_STATIC_LINKING_ONLY
+# define XXH_STATIC_LINKING_ONLY
+#endif
+#include "xxhash.h"
+
+
+/* *************************************
+* Compiler Specific Options
+***************************************/
+#if (defined(__GNUC__) && !defined(__STRICT_ANSI__)) || defined(__cplusplus) || defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
+# define INLINE_KEYWORD inline
+#else
+# define INLINE_KEYWORD
+#endif
+
+#if defined(__GNUC__) || defined(__ICCARM__)
+# define FORCE_INLINE_ATTR __attribute__((always_inline))
+#elif defined(_MSC_VER)
+# define FORCE_INLINE_ATTR __forceinline
+#else
+# define FORCE_INLINE_ATTR
+#endif
+
+#define FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR
+
+
+#ifdef _MSC_VER
+# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
+#endif
+
+
+/* *************************************
+* Basic Types
+***************************************/
+#ifndef MEM_MODULE
+# define MEM_MODULE
+# if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
+# include <stdint.h>
+ typedef uint8_t BYTE;
+ typedef uint16_t U16;
+ typedef uint32_t U32;
+ typedef int32_t S32;
+ typedef uint64_t U64;
+# else
+ typedef unsigned char BYTE;
+ typedef unsigned short U16;
+ typedef unsigned int U32;
+ typedef signed int S32;
+ typedef unsigned long long U64; /* if your compiler doesn't support unsigned long long, replace by another 64-bit type here. Note that xxhash.h will also need to be updated. */
+# endif
+#endif
+
+
+#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2))
+
+/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */
+static U32 XXH_read32(const void* memPtr) { return *(const U32*) memPtr; }
+static U64 XXH_read64(const void* memPtr) { return *(const U64*) memPtr; }
+
+#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))
+
+/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
+/* currently only defined for gcc and icc */
+typedef union { U32 u32; U64 u64; } __attribute__((packed)) unalign;
+
+static U32 XXH_read32(const void* ptr) { return ((const unalign*)ptr)->u32; }
+static U64 XXH_read64(const void* ptr) { return ((const unalign*)ptr)->u64; }
+
+#else
+
+/* portable and safe solution. Generally efficient.
+ * see : http://stackoverflow.com/a/32095106/646947
+ */
+
+static U32 XXH_read32(const void* memPtr)
+{
+ U32 val;
+ memcpy(&val, memPtr, sizeof(val));
+ return val;
+}
+
+static U64 XXH_read64(const void* memPtr)
+{
+ U64 val;
+ memcpy(&val, memPtr, sizeof(val));
+ return val;
+}
+
+#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */
+
+
+/* ****************************************
+* Compiler-specific Functions and Macros
+******************************************/
+#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
+
+/* Note : although _rotl exists for minGW (GCC under windows), performance seems poor */
+#if defined(_MSC_VER)
+# define XXH_rotl32(x,r) _rotl(x,r)
+# define XXH_rotl64(x,r) _rotl64(x,r)
+#else
+#if defined(__ICCARM__)
+# include <intrinsics.h>
+# define XXH_rotl32(x,r) __ROR(x,(32 - r))
+#else
+# define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r)))
+#endif
+# define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r)))
+#endif
+
+#if defined(_MSC_VER) /* Visual Studio */
+# define XXH_swap32 _byteswap_ulong
+# define XXH_swap64 _byteswap_uint64
+#elif GCC_VERSION >= 403
+# define XXH_swap32 __builtin_bswap32
+# define XXH_swap64 __builtin_bswap64
+#else
+static U32 XXH_swap32 (U32 x)
+{
+ return ((x << 24) & 0xff000000 ) |
+ ((x << 8) & 0x00ff0000 ) |
+ ((x >> 8) & 0x0000ff00 ) |
+ ((x >> 24) & 0x000000ff );
+}
+static U64 XXH_swap64 (U64 x)
+{
+ return ((x << 56) & 0xff00000000000000ULL) |
+ ((x << 40) & 0x00ff000000000000ULL) |
+ ((x << 24) & 0x0000ff0000000000ULL) |
+ ((x << 8) & 0x000000ff00000000ULL) |
+ ((x >> 8) & 0x00000000ff000000ULL) |
+ ((x >> 24) & 0x0000000000ff0000ULL) |
+ ((x >> 40) & 0x000000000000ff00ULL) |
+ ((x >> 56) & 0x00000000000000ffULL);
+}
+#endif
+
+
+/* *************************************
+* Architecture Macros
+***************************************/
+typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess;
+
+/* XXH_CPU_LITTLE_ENDIAN can be defined externally, for example on the compiler command line */
+#ifndef XXH_CPU_LITTLE_ENDIAN
+ static const int g_one = 1;
+# define XXH_CPU_LITTLE_ENDIAN (*(const char*)(&g_one))
+#endif
+
+
+/* ***************************
+* Memory reads
+*****************************/
+typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment;
+
+FORCE_INLINE_TEMPLATE U32 XXH_readLE32_align(const void* ptr, XXH_endianess endian, XXH_alignment align)
+{
+ if (align==XXH_unaligned)
+ return endian==XXH_littleEndian ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr));
+ else
+ return endian==XXH_littleEndian ? *(const U32*)ptr : XXH_swap32(*(const U32*)ptr);
+}
+
+FORCE_INLINE_TEMPLATE U32 XXH_readLE32(const void* ptr, XXH_endianess endian)
+{
+ return XXH_readLE32_align(ptr, endian, XXH_unaligned);
+}
+
+static U32 XXH_readBE32(const void* ptr)
+{
+ return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr);
+}
+
+FORCE_INLINE_TEMPLATE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align)
+{
+ if (align==XXH_unaligned)
+ return endian==XXH_littleEndian ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr));
+ else
+ return endian==XXH_littleEndian ? *(const U64*)ptr : XXH_swap64(*(const U64*)ptr);
+}
+
+FORCE_INLINE_TEMPLATE U64 XXH_readLE64(const void* ptr, XXH_endianess endian)
+{
+ return XXH_readLE64_align(ptr, endian, XXH_unaligned);
+}
+
+static U64 XXH_readBE64(const void* ptr)
+{
+ return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr);
+}
+
+
+/* *************************************
+* Macros
+***************************************/
+#define XXH_STATIC_ASSERT(c) { enum { XXH_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */
+
+
+/* *************************************
+* Constants
+***************************************/
+static const U32 PRIME32_1 = 2654435761U;
+static const U32 PRIME32_2 = 2246822519U;
+static const U32 PRIME32_3 = 3266489917U;
+static const U32 PRIME32_4 = 668265263U;
+static const U32 PRIME32_5 = 374761393U;
+
+static const U64 PRIME64_1 = 11400714785074694791ULL;
+static const U64 PRIME64_2 = 14029467366897019727ULL;
+static const U64 PRIME64_3 = 1609587929392839161ULL;
+static const U64 PRIME64_4 = 9650029242287828579ULL;
+static const U64 PRIME64_5 = 2870177450012600261ULL;
+
+XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; }
+
+
+/* **************************
+* Utils
+****************************/
+XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* restrict dstState, const XXH32_state_t* restrict srcState)
+{
+ memcpy(dstState, srcState, sizeof(*dstState));
+}
+
+XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* restrict dstState, const XXH64_state_t* restrict srcState)
+{
+ memcpy(dstState, srcState, sizeof(*dstState));
+}
+
+
+/* ***************************
+* Simple Hash Functions
+*****************************/
+
+static U32 XXH32_round(U32 seed, U32 input)
+{
+ seed += input * PRIME32_2;
+ seed = XXH_rotl32(seed, 13);
+ seed *= PRIME32_1;
+ return seed;
+}
+
+FORCE_INLINE_TEMPLATE U32 XXH32_endian_align(const void* input, size_t len, U32 seed, XXH_endianess endian, XXH_alignment align)
+{
+ const BYTE* p = (const BYTE*)input;
+ const BYTE* bEnd = p + len;
+ U32 h32;
+#define XXH_get32bits(p) XXH_readLE32_align(p, endian, align)
+
+#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
+ if (p==NULL) {
+ len=0;
+ bEnd=p=(const BYTE*)(size_t)16;
+ }
+#endif
+
+ if (len>=16) {
+ const BYTE* const limit = bEnd - 16;
+ U32 v1 = seed + PRIME32_1 + PRIME32_2;
+ U32 v2 = seed + PRIME32_2;
+ U32 v3 = seed + 0;
+ U32 v4 = seed - PRIME32_1;
+
+ do {
+ v1 = XXH32_round(v1, XXH_get32bits(p)); p+=4;
+ v2 = XXH32_round(v2, XXH_get32bits(p)); p+=4;
+ v3 = XXH32_round(v3, XXH_get32bits(p)); p+=4;
+ v4 = XXH32_round(v4, XXH_get32bits(p)); p+=4;
+ } while (p<=limit);
+
+ h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18);
+ } else {
+ h32 = seed + PRIME32_5;
+ }
+
+ h32 += (U32) len;
+
+ while (p+4<=bEnd) {
+ h32 += XXH_get32bits(p) * PRIME32_3;
+ h32 = XXH_rotl32(h32, 17) * PRIME32_4 ;
+ p+=4;
+ }
+
+ while (p<bEnd) {
+ h32 += (*p) * PRIME32_5;
+ h32 = XXH_rotl32(h32, 11) * PRIME32_1 ;
+ p++;
+ }
+
+ h32 ^= h32 >> 15;
+ h32 *= PRIME32_2;
+ h32 ^= h32 >> 13;
+ h32 *= PRIME32_3;
+ h32 ^= h32 >> 16;
+
+ return h32;
+}
+
+
+XXH_PUBLIC_API unsigned int XXH32 (const void* input, size_t len, unsigned int seed)
+{
+#if 0
+ /* Simple version, good for code maintenance, but unfortunately slow for small inputs */
+ XXH32_CREATESTATE_STATIC(state);
+ XXH32_reset(state, seed);
+ XXH32_update(state, input, len);
+ return XXH32_digest(state);
+#else
+ XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
+
+ if (XXH_FORCE_ALIGN_CHECK) {
+ if ((((size_t)input) & 3) == 0) { /* Input is 4-bytes aligned, leverage the speed benefit */
+ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+ return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
+ else
+ return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
+ } }
+
+ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+ return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
+ else
+ return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
+#endif
+}
+
+
+static U64 XXH64_round(U64 acc, U64 input)
+{
+ acc += input * PRIME64_2;
+ acc = XXH_rotl64(acc, 31);
+ acc *= PRIME64_1;
+ return acc;
+}
+
+static U64 XXH64_mergeRound(U64 acc, U64 val)
+{
+ val = XXH64_round(0, val);
+ acc ^= val;
+ acc = acc * PRIME64_1 + PRIME64_4;
+ return acc;
+}
+
+FORCE_INLINE_TEMPLATE U64 XXH64_endian_align(const void* input, size_t len, U64 seed, XXH_endianess endian, XXH_alignment align)
+{
+ const BYTE* p = (const BYTE*)input;
+ const BYTE* const bEnd = p + len;
+ U64 h64;
+#define XXH_get64bits(p) XXH_readLE64_align(p, endian, align)
+
+#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
+ if (p==NULL) {
+ len=0;
+ bEnd=p=(const BYTE*)(size_t)32;
+ }
+#endif
+
+ if (len>=32) {
+ const BYTE* const limit = bEnd - 32;
+ U64 v1 = seed + PRIME64_1 + PRIME64_2;
+ U64 v2 = seed + PRIME64_2;
+ U64 v3 = seed + 0;
+ U64 v4 = seed - PRIME64_1;
+
+ do {
+ v1 = XXH64_round(v1, XXH_get64bits(p)); p+=8;
+ v2 = XXH64_round(v2, XXH_get64bits(p)); p+=8;
+ v3 = XXH64_round(v3, XXH_get64bits(p)); p+=8;
+ v4 = XXH64_round(v4, XXH_get64bits(p)); p+=8;
+ } while (p<=limit);
+
+ h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
+ h64 = XXH64_mergeRound(h64, v1);
+ h64 = XXH64_mergeRound(h64, v2);
+ h64 = XXH64_mergeRound(h64, v3);
+ h64 = XXH64_mergeRound(h64, v4);
+
+ } else {
+ h64 = seed + PRIME64_5;
+ }
+
+ h64 += (U64) len;
+
+ while (p+8<=bEnd) {
+ U64 const k1 = XXH64_round(0, XXH_get64bits(p));
+ h64 ^= k1;
+ h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4;
+ p+=8;
+ }
+
+ if (p+4<=bEnd) {
+ h64 ^= (U64)(XXH_get32bits(p)) * PRIME64_1;
+ h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
+ p+=4;
+ }
+
+ while (p<bEnd) {
+ h64 ^= (*p) * PRIME64_5;
+ h64 = XXH_rotl64(h64, 11) * PRIME64_1;
+ p++;
+ }
+
+ h64 ^= h64 >> 33;
+ h64 *= PRIME64_2;
+ h64 ^= h64 >> 29;
+ h64 *= PRIME64_3;
+ h64 ^= h64 >> 32;
+
+ return h64;
+}
+
+
+XXH_PUBLIC_API unsigned long long XXH64 (const void* input, size_t len, unsigned long long seed)
+{
+#if 0
+ /* Simple version, good for code maintenance, but unfortunately slow for small inputs */
+ XXH64_CREATESTATE_STATIC(state);
+ XXH64_reset(state, seed);
+ XXH64_update(state, input, len);
+ return XXH64_digest(state);
+#else
+ XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
+
+ if (XXH_FORCE_ALIGN_CHECK) {
+ if ((((size_t)input) & 7)==0) { /* Input is aligned, let's leverage the speed advantage */
+ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+ return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
+ else
+ return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
+ } }
+
+ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+ return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
+ else
+ return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
+#endif
+}
+
+
+/* **************************************************
+* Advanced Hash Functions
+****************************************************/
+
+XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void)
+{
+ return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t));
+}
+XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr)
+{
+ XXH_free(statePtr);
+ return XXH_OK;
+}
+
+XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void)
+{
+ return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t));
+}
+XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr)
+{
+ XXH_free(statePtr);
+ return XXH_OK;
+}
+
+
+/*** Hash feed ***/
+
+XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, unsigned int seed)
+{
+ XXH32_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */
+ memset(&state, 0, sizeof(state)-4); /* do not write into reserved, for future removal */
+ state.v1 = seed + PRIME32_1 + PRIME32_2;
+ state.v2 = seed + PRIME32_2;
+ state.v3 = seed + 0;
+ state.v4 = seed - PRIME32_1;
+ memcpy(statePtr, &state, sizeof(state));
+ return XXH_OK;
+}
+
+
+XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, unsigned long long seed)
+{
+ XXH64_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */
+ memset(&state, 0, sizeof(state)-8); /* do not write into reserved, for future removal */
+ state.v1 = seed + PRIME64_1 + PRIME64_2;
+ state.v2 = seed + PRIME64_2;
+ state.v3 = seed + 0;
+ state.v4 = seed - PRIME64_1;
+ memcpy(statePtr, &state, sizeof(state));
+ return XXH_OK;
+}
+
+
+FORCE_INLINE_TEMPLATE XXH_errorcode XXH32_update_endian (XXH32_state_t* state, const void* input, size_t len, XXH_endianess endian)
+{
+ const BYTE* p = (const BYTE*)input;
+ const BYTE* const bEnd = p + len;
+
+#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
+ if (input==NULL) return XXH_ERROR;
+#endif
+
+ state->total_len_32 += (unsigned)len;
+ state->large_len |= (len>=16) | (state->total_len_32>=16);
+
+ if (state->memsize + len < 16) { /* fill in tmp buffer */
+ XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, len);
+ state->memsize += (unsigned)len;
+ return XXH_OK;
+ }
+
+ if (state->memsize) { /* some data left from previous update */
+ XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, 16-state->memsize);
+ { const U32* p32 = state->mem32;
+ state->v1 = XXH32_round(state->v1, XXH_readLE32(p32, endian)); p32++;
+ state->v2 = XXH32_round(state->v2, XXH_readLE32(p32, endian)); p32++;
+ state->v3 = XXH32_round(state->v3, XXH_readLE32(p32, endian)); p32++;
+ state->v4 = XXH32_round(state->v4, XXH_readLE32(p32, endian)); p32++;
+ }
+ p += 16-state->memsize;
+ state->memsize = 0;
+ }
+
+ if (p <= bEnd-16) {
+ const BYTE* const limit = bEnd - 16;
+ U32 v1 = state->v1;
+ U32 v2 = state->v2;
+ U32 v3 = state->v3;
+ U32 v4 = state->v4;
+
+ do {
+ v1 = XXH32_round(v1, XXH_readLE32(p, endian)); p+=4;
+ v2 = XXH32_round(v2, XXH_readLE32(p, endian)); p+=4;
+ v3 = XXH32_round(v3, XXH_readLE32(p, endian)); p+=4;
+ v4 = XXH32_round(v4, XXH_readLE32(p, endian)); p+=4;
+ } while (p<=limit);
+
+ state->v1 = v1;
+ state->v2 = v2;
+ state->v3 = v3;
+ state->v4 = v4;
+ }
+
+ if (p < bEnd) {
+ XXH_memcpy(state->mem32, p, (size_t)(bEnd-p));
+ state->memsize = (unsigned)(bEnd-p);
+ }
+
+ return XXH_OK;
+}
+
+XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* state_in, const void* input, size_t len)
+{
+ XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
+
+ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+ return XXH32_update_endian(state_in, input, len, XXH_littleEndian);
+ else
+ return XXH32_update_endian(state_in, input, len, XXH_bigEndian);
+}
+
+
+
+FORCE_INLINE_TEMPLATE U32 XXH32_digest_endian (const XXH32_state_t* state, XXH_endianess endian)
+{
+ const BYTE * p = (const BYTE*)state->mem32;
+ const BYTE* const bEnd = (const BYTE*)(state->mem32) + state->memsize;
+ U32 h32;
+
+ if (state->large_len) {
+ h32 = XXH_rotl32(state->v1, 1) + XXH_rotl32(state->v2, 7) + XXH_rotl32(state->v3, 12) + XXH_rotl32(state->v4, 18);
+ } else {
+ h32 = state->v3 /* == seed */ + PRIME32_5;
+ }
+
+ h32 += state->total_len_32;
+
+ while (p+4<=bEnd) {
+ h32 += XXH_readLE32(p, endian) * PRIME32_3;
+ h32 = XXH_rotl32(h32, 17) * PRIME32_4;
+ p+=4;
+ }
+
+ while (p<bEnd) {
+ h32 += (*p) * PRIME32_5;
+ h32 = XXH_rotl32(h32, 11) * PRIME32_1;
+ p++;
+ }
+
+ h32 ^= h32 >> 15;
+ h32 *= PRIME32_2;
+ h32 ^= h32 >> 13;
+ h32 *= PRIME32_3;
+ h32 ^= h32 >> 16;
+
+ return h32;
+}
+
+
+XXH_PUBLIC_API unsigned int XXH32_digest (const XXH32_state_t* state_in)
+{
+ XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
+
+ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+ return XXH32_digest_endian(state_in, XXH_littleEndian);
+ else
+ return XXH32_digest_endian(state_in, XXH_bigEndian);
+}
+
+
+
+/* **** XXH64 **** */
+
+FORCE_INLINE_TEMPLATE XXH_errorcode XXH64_update_endian (XXH64_state_t* state, const void* input, size_t len, XXH_endianess endian)
+{
+ const BYTE* p = (const BYTE*)input;
+ const BYTE* const bEnd = p + len;
+
+#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
+ if (input==NULL) return XXH_ERROR;
+#endif
+
+ state->total_len += len;
+
+ if (state->memsize + len < 32) { /* fill in tmp buffer */
+ if (input != NULL) {
+ XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, len);
+ }
+ state->memsize += (U32)len;
+ return XXH_OK;
+ }
+
+ if (state->memsize) { /* tmp buffer is full */
+ XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, 32-state->memsize);
+ state->v1 = XXH64_round(state->v1, XXH_readLE64(state->mem64+0, endian));
+ state->v2 = XXH64_round(state->v2, XXH_readLE64(state->mem64+1, endian));
+ state->v3 = XXH64_round(state->v3, XXH_readLE64(state->mem64+2, endian));
+ state->v4 = XXH64_round(state->v4, XXH_readLE64(state->mem64+3, endian));
+ p += 32-state->memsize;
+ state->memsize = 0;
+ }
+
+ if (p+32 <= bEnd) {
+ const BYTE* const limit = bEnd - 32;
+ U64 v1 = state->v1;
+ U64 v2 = state->v2;
+ U64 v3 = state->v3;
+ U64 v4 = state->v4;
+
+ do {
+ v1 = XXH64_round(v1, XXH_readLE64(p, endian)); p+=8;
+ v2 = XXH64_round(v2, XXH_readLE64(p, endian)); p+=8;
+ v3 = XXH64_round(v3, XXH_readLE64(p, endian)); p+=8;
+ v4 = XXH64_round(v4, XXH_readLE64(p, endian)); p+=8;
+ } while (p<=limit);
+
+ state->v1 = v1;
+ state->v2 = v2;
+ state->v3 = v3;
+ state->v4 = v4;
+ }
+
+ if (p < bEnd) {
+ XXH_memcpy(state->mem64, p, (size_t)(bEnd-p));
+ state->memsize = (unsigned)(bEnd-p);
+ }
+
+ return XXH_OK;
+}
+
+XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* state_in, const void* input, size_t len)
+{
+ XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
+
+ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+ return XXH64_update_endian(state_in, input, len, XXH_littleEndian);
+ else
+ return XXH64_update_endian(state_in, input, len, XXH_bigEndian);
+}
+
+
+
+FORCE_INLINE_TEMPLATE U64 XXH64_digest_endian (const XXH64_state_t* state, XXH_endianess endian)
+{
+ const BYTE * p = (const BYTE*)state->mem64;
+ const BYTE* const bEnd = (const BYTE*)state->mem64 + state->memsize;
+ U64 h64;
+
+ if (state->total_len >= 32) {
+ U64 const v1 = state->v1;
+ U64 const v2 = state->v2;
+ U64 const v3 = state->v3;
+ U64 const v4 = state->v4;
+
+ h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
+ h64 = XXH64_mergeRound(h64, v1);
+ h64 = XXH64_mergeRound(h64, v2);
+ h64 = XXH64_mergeRound(h64, v3);
+ h64 = XXH64_mergeRound(h64, v4);
+ } else {
+ h64 = state->v3 + PRIME64_5;
+ }
+
+ h64 += (U64) state->total_len;
+
+ while (p+8<=bEnd) {
+ U64 const k1 = XXH64_round(0, XXH_readLE64(p, endian));
+ h64 ^= k1;
+ h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4;
+ p+=8;
+ }
+
+ if (p+4<=bEnd) {
+ h64 ^= (U64)(XXH_readLE32(p, endian)) * PRIME64_1;
+ h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
+ p+=4;
+ }
+
+ while (p<bEnd) {
+ h64 ^= (*p) * PRIME64_5;
+ h64 = XXH_rotl64(h64, 11) * PRIME64_1;
+ p++;
+ }
+
+ h64 ^= h64 >> 33;
+ h64 *= PRIME64_2;
+ h64 ^= h64 >> 29;
+ h64 *= PRIME64_3;
+ h64 ^= h64 >> 32;
+
+ return h64;
+}
+
+
+XXH_PUBLIC_API unsigned long long XXH64_digest (const XXH64_state_t* state_in)
+{
+ XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
+
+ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+ return XXH64_digest_endian(state_in, XXH_littleEndian);
+ else
+ return XXH64_digest_endian(state_in, XXH_bigEndian);
+}
+
+
+/* **************************
+* Canonical representation
+****************************/
+
+/*! Default XXH result types are basic unsigned 32 and 64 bits.
+* The canonical representation follows human-readable write convention, aka big-endian (large digits first).
+* These functions allow transformation of hash result into and from its canonical format.
+* This way, hash values can be written into a file or buffer, and remain comparable across different systems and programs.
+*/
+
+XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash)
+{
+ XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t));
+ if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash);
+ memcpy(dst, &hash, sizeof(*dst));
+}
+
+XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash)
+{
+ XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t));
+ if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash);
+ memcpy(dst, &hash, sizeof(*dst));
+}
+
+XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src)
+{
+ return XXH_readBE32(src);
+}
+
+XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src)
+{
+ return XXH_readBE64(src);
+}
diff --git a/sys/contrib/openzfs/module/zstd/lib/common/xxhash.h b/sys/contrib/openzfs/module/zstd/lib/common/xxhash.h
new file mode 100644
index 000000000000..4207eba8328f
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/common/xxhash.h
@@ -0,0 +1,285 @@
+/*
+ * xxHash - Extremely Fast Hash algorithm
+ * Header File
+ * Copyright (c) 2012-2020, Yann Collet, Facebook, Inc.
+ *
+ * You can contact the author at :
+ * - xxHash source repository : https://github.com/Cyan4973/xxHash
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+*/
+
+/* Notice extracted from xxHash homepage :
+
+xxHash is an extremely fast Hash algorithm, running at RAM speed limits.
+It also successfully passes all tests from the SMHasher suite.
+
+Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz)
+
+Name Speed Q.Score Author
+xxHash 5.4 GB/s 10
+CrapWow 3.2 GB/s 2 Andrew
+MumurHash 3a 2.7 GB/s 10 Austin Appleby
+SpookyHash 2.0 GB/s 10 Bob Jenkins
+SBox 1.4 GB/s 9 Bret Mulvey
+Lookup3 1.2 GB/s 9 Bob Jenkins
+SuperFastHash 1.2 GB/s 1 Paul Hsieh
+CityHash64 1.05 GB/s 10 Pike & Alakuijala
+FNV 0.55 GB/s 5 Fowler, Noll, Vo
+CRC32 0.43 GB/s 9
+MD5-32 0.33 GB/s 10 Ronald L. Rivest
+SHA1-32 0.28 GB/s 10
+
+Q.Score is a measure of quality of the hash function.
+It depends on successfully passing SMHasher test set.
+10 is a perfect score.
+
+A 64-bits version, named XXH64, is available since r35.
+It offers much better speed, but for 64-bits applications only.
+Name Speed on 64 bits Speed on 32 bits
+XXH64 13.8 GB/s 1.9 GB/s
+XXH32 6.8 GB/s 6.0 GB/s
+*/
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#ifndef XXHASH_H_5627135585666179
+#define XXHASH_H_5627135585666179 1
+
+
+/* ****************************
+* Definitions
+******************************/
+#include <stddef.h> /* size_t */
+typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode;
+
+
+/* ****************************
+* API modifier
+******************************/
+/** XXH_PRIVATE_API
+* This is useful if you want to include xxhash functions in `static` mode
+* in order to inline them, and remove their symbol from the public list.
+* Methodology :
+* #define XXH_PRIVATE_API
+* #include "xxhash.h"
+* `xxhash.c` is automatically included.
+* It's not useful to compile and link it as a separate module anymore.
+*/
+#ifdef XXH_PRIVATE_API
+# ifndef XXH_STATIC_LINKING_ONLY
+# define XXH_STATIC_LINKING_ONLY
+# endif
+# if defined(__GNUC__)
+# define XXH_PUBLIC_API static __inline __attribute__((unused))
+# elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
+# define XXH_PUBLIC_API static inline
+# elif defined(_MSC_VER)
+# define XXH_PUBLIC_API static __inline
+# else
+# define XXH_PUBLIC_API static /* this version may generate warnings for unused static functions; disable the relevant warning */
+# endif
+#else
+# define XXH_PUBLIC_API /* do nothing */
+#endif /* XXH_PRIVATE_API */
+
+/*!XXH_NAMESPACE, aka Namespace Emulation :
+
+If you want to include _and expose_ xxHash functions from within your own library,
+but also want to avoid symbol collisions with another library which also includes xxHash,
+
+you can use XXH_NAMESPACE, to automatically prefix any public symbol from xxhash library
+with the value of XXH_NAMESPACE (so avoid to keep it NULL and avoid numeric values).
+
+Note that no change is required within the calling program as long as it includes `xxhash.h` :
+regular symbol name will be automatically translated by this header.
+*/
+#ifdef XXH_NAMESPACE
+# define XXH_CAT(A,B) A##B
+# define XXH_NAME2(A,B) XXH_CAT(A,B)
+# define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32)
+# define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64)
+# define XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber)
+# define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState)
+# define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState)
+# define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState)
+# define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState)
+# define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset)
+# define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset)
+# define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update)
+# define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update)
+# define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest)
+# define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest)
+# define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState)
+# define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState)
+# define XXH32_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash)
+# define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash)
+# define XXH32_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical)
+# define XXH64_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH64_hashFromCanonical)
+#endif
+
+
+/* *************************************
+* Version
+***************************************/
+#define XXH_VERSION_MAJOR 0
+#define XXH_VERSION_MINOR 6
+#define XXH_VERSION_RELEASE 2
+#define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE)
+XXH_PUBLIC_API unsigned XXH_versionNumber (void);
+
+
+/* ****************************
+* Simple Hash Functions
+******************************/
+typedef unsigned int XXH32_hash_t;
+typedef unsigned long long XXH64_hash_t;
+
+XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, unsigned int seed);
+XXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t length, unsigned long long seed);
+
+/*!
+XXH32() :
+ Calculate the 32-bits hash of sequence "length" bytes stored at memory address "input".
+ The memory between input & input+length must be valid (allocated and read-accessible).
+ "seed" can be used to alter the result predictably.
+ Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s
+XXH64() :
+ Calculate the 64-bits hash of sequence of length "len" stored at memory address "input".
+ "seed" can be used to alter the result predictably.
+ This function runs 2x faster on 64-bits systems, but slower on 32-bits systems (see benchmark).
+*/
+
+
+/* ****************************
+* Streaming Hash Functions
+******************************/
+typedef struct XXH32_state_s XXH32_state_t; /* incomplete type */
+typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */
+
+/*! State allocation, compatible with dynamic libraries */
+
+XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void);
+XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr);
+
+XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void);
+XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr);
+
+
+/* hash streaming */
+
+XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, unsigned int seed);
+XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length);
+XXH_PUBLIC_API XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr);
+
+XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, unsigned long long seed);
+XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length);
+XXH_PUBLIC_API XXH64_hash_t XXH64_digest (const XXH64_state_t* statePtr);
+
+/*
+These functions generate the xxHash of an input provided in multiple segments.
+Note that, for small input, they are slower than single-call functions, due to state management.
+For small input, prefer `XXH32()` and `XXH64()` .
+
+XXH state must first be allocated, using XXH*_createState() .
+
+Start a new hash by initializing state with a seed, using XXH*_reset().
+
+Then, feed the hash state by calling XXH*_update() as many times as necessary.
+Obviously, input must be allocated and read accessible.
+The function returns an error code, with 0 meaning OK, and any other value meaning there is an error.
+
+Finally, a hash value can be produced anytime, by using XXH*_digest().
+This function returns the nn-bits hash as an int or long long.
+
+It's still possible to continue inserting input into the hash state after a digest,
+and generate some new hashes later on, by calling again XXH*_digest().
+
+When done, free XXH state space if it was allocated dynamically.
+*/
+
+
+/* **************************
+* Utils
+****************************/
+#if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) /* ! C99 */
+# define restrict /* disable restrict */
+#endif
+
+XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* restrict dst_state, const XXH32_state_t* restrict src_state);
+XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* restrict dst_state, const XXH64_state_t* restrict src_state);
+
+
+/* **************************
+* Canonical representation
+****************************/
+/* Default result type for XXH functions are primitive unsigned 32 and 64 bits.
+* The canonical representation uses human-readable write convention, aka big-endian (large digits first).
+* These functions allow transformation of hash result into and from its canonical format.
+* This way, hash values can be written into a file / memory, and remain comparable on different systems and programs.
+*/
+typedef struct { unsigned char digest[4]; } XXH32_canonical_t;
+typedef struct { unsigned char digest[8]; } XXH64_canonical_t;
+
+XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash);
+XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash);
+
+XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src);
+XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src);
+
+#endif /* XXHASH_H_5627135585666179 */
+
+
+
+/* ================================================================================================
+ This section contains definitions which are not guaranteed to remain stable.
+ They may change in future versions, becoming incompatible with a different version of the library.
+ They shall only be used with static linking.
+ Never use these definitions in association with dynamic linking !
+=================================================================================================== */
+#if defined(XXH_STATIC_LINKING_ONLY) && !defined(XXH_STATIC_H_3543687687345)
+#define XXH_STATIC_H_3543687687345
+
+/* These definitions are only meant to allow allocation of XXH state
+ statically, on stack, or in a struct for example.
+ Do not use members directly. */
+
+ struct XXH32_state_s {
+ unsigned total_len_32;
+ unsigned large_len;
+ unsigned v1;
+ unsigned v2;
+ unsigned v3;
+ unsigned v4;
+ unsigned mem32[4]; /* buffer defined as U32 for alignment */
+ unsigned memsize;
+ unsigned reserved; /* never read nor write, will be removed in a future version */
+ }; /* typedef'd to XXH32_state_t */
+
+ struct XXH64_state_s {
+ unsigned long long total_len;
+ unsigned long long v1;
+ unsigned long long v2;
+ unsigned long long v3;
+ unsigned long long v4;
+ unsigned long long mem64[4]; /* buffer defined as U64 for alignment */
+ unsigned memsize;
+ unsigned reserved[2]; /* never read nor write, will be removed in a future version */
+ }; /* typedef'd to XXH64_state_t */
+
+
+# ifdef XXH_PRIVATE_API
+# include "xxhash.c" /* include xxhash functions as `static`, for inlining */
+# endif
+
+#endif /* XXH_STATIC_LINKING_ONLY && XXH_STATIC_H_3543687687345 */
+
+
+#if defined (__cplusplus)
+}
+#endif
diff --git a/sys/contrib/openzfs/module/zstd/lib/common/zstd_common.c b/sys/contrib/openzfs/module/zstd/lib/common/zstd_common.c
new file mode 100644
index 000000000000..935670b1dce3
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/common/zstd_common.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+
+
+/*-*************************************
+* Dependencies
+***************************************/
+#include <stdlib.h> /* malloc, calloc, free */
+#include <string.h> /* memset */
+#include "error_private.h"
+#include "zstd_internal.h"
+
+
+/*-****************************************
+* Version
+******************************************/
+unsigned ZSTD_versionNumber(void) { return ZSTD_VERSION_NUMBER; }
+
+const char* ZSTD_versionString(void) { return ZSTD_VERSION_STRING; }
+
+
+/*-****************************************
+* ZSTD Error Management
+******************************************/
+
+/*! ZSTD_isError() :
+ * tells if a return value is an error code
+ * symbol is required for external callers */
+unsigned ZSTD_isError(size_t code) { return ERR_isError(code); }
+
+/*! ZSTD_getErrorName() :
+ * provides error code string from function result (useful for debugging) */
+const char* ZSTD_getErrorName(size_t code) { return ERR_getErrorName(code); }
+
+/*! ZSTD_getError() :
+ * convert a `size_t` function result into a proper ZSTD_errorCode enum */
+ZSTD_ErrorCode ZSTD_getErrorCode(size_t code) { return ERR_getErrorCode(code); }
+
+/*! ZSTD_getErrorString() :
+ * provides error code string from enum */
+const char* ZSTD_getErrorString(ZSTD_ErrorCode code) { return ERR_getErrorString(code); }
+
+
+
+/*=**************************************************************
+* Custom allocator
+****************************************************************/
+void* ZSTD_malloc(size_t size, ZSTD_customMem customMem)
+{
+ if (customMem.customAlloc)
+ return customMem.customAlloc(customMem.opaque, size);
+ return malloc(size);
+}
+
+void* ZSTD_calloc(size_t size, ZSTD_customMem customMem)
+{
+ if (customMem.customAlloc) {
+ /* calloc implemented as malloc+memset;
+ * not as efficient as calloc, but next best guess for custom malloc */
+ void* const ptr = customMem.customAlloc(customMem.opaque, size);
+ memset(ptr, 0, size);
+ return ptr;
+ }
+ return calloc(1, size);
+}
+
+void ZSTD_free(void* ptr, ZSTD_customMem customMem)
+{
+ if (ptr!=NULL) {
+ if (customMem.customFree)
+ customMem.customFree(customMem.opaque, ptr);
+ else
+ free(ptr);
+ }
+}
diff --git a/sys/contrib/openzfs/module/zstd/lib/zstd_errors.h b/sys/contrib/openzfs/module/zstd/lib/common/zstd_errors.h
index 998398e7e57f..998398e7e57f 100644
--- a/sys/contrib/openzfs/module/zstd/lib/zstd_errors.h
+++ b/sys/contrib/openzfs/module/zstd/lib/common/zstd_errors.h
diff --git a/sys/contrib/openzfs/module/zstd/lib/common/zstd_internal.h b/sys/contrib/openzfs/module/zstd/lib/common/zstd_internal.h
new file mode 100644
index 000000000000..4a86d186a967
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/common/zstd_internal.h
@@ -0,0 +1,446 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_CCOMMON_H_MODULE
+#define ZSTD_CCOMMON_H_MODULE
+
+/* this module contains definitions which must be identical
+ * across compression, decompression and dictBuilder.
+ * It also contains a few functions useful to at least 2 of them
+ * and which benefit from being inlined */
+
+/*-*************************************
+* Dependencies
+***************************************/
+#if !defined(ZSTD_NO_INTRINSICS) && defined(__ARM_NEON)
+#include <arm_neon.h>
+#endif
+#include "compiler.h"
+#include "mem.h"
+#include "debug.h" /* assert, DEBUGLOG, RAWLOG, g_debuglevel */
+#include "error_private.h"
+#define ZSTD_STATIC_LINKING_ONLY
+#include "../zstd.h"
+#define FSE_STATIC_LINKING_ONLY
+#include "fse.h"
+#define HUF_STATIC_LINKING_ONLY
+#include "huf.h"
+#ifndef XXH_STATIC_LINKING_ONLY
+# define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */
+#endif
+#include "xxhash.h" /* XXH_reset, update, digest */
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+/* ---- static assert (debug) --- */
+#define ZSTD_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c)
+#define FSE_isError ERR_isError
+#define HUF_isError ERR_isError
+
+
+/*-*************************************
+* shared macros
+***************************************/
+#undef MIN
+#undef MAX
+#define MIN(a,b) ((a)<(b) ? (a) : (b))
+#define MAX(a,b) ((a)>(b) ? (a) : (b))
+
+/**
+ * Ignore: this is an internal helper.
+ *
+ * This is a helper function to help force C99-correctness during compilation.
+ * Under strict compilation modes, variadic macro arguments can't be empty.
+ * However, variadic function arguments can be. Using a function therefore lets
+ * us statically check that at least one (string) argument was passed,
+ * independent of the compilation flags.
+ */
+static INLINE_KEYWORD UNUSED_ATTR
+void _force_has_format_string(const char *format, ...) {
+ (void)format;
+}
+
+/**
+ * Ignore: this is an internal helper.
+ *
+ * We want to force this function invocation to be syntactically correct, but
+ * we don't want to force runtime evaluation of its arguments.
+ */
+#define _FORCE_HAS_FORMAT_STRING(...) \
+ if (0) { \
+ _force_has_format_string(__VA_ARGS__); \
+ }
+
+/**
+ * Return the specified error if the condition evaluates to true.
+ *
+ * In debug modes, prints additional information.
+ * In order to do that (particularly, printing the conditional that failed),
+ * this can't just wrap RETURN_ERROR().
+ */
+#define RETURN_ERROR_IF(cond, err, ...) \
+ if (cond) { \
+ RAWLOG(3, "%s:%d: ERROR!: check %s failed, returning %s", \
+ __FILE__, __LINE__, ZSTD_QUOTE(cond), ZSTD_QUOTE(ERROR(err))); \
+ _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \
+ RAWLOG(3, ": " __VA_ARGS__); \
+ RAWLOG(3, "\n"); \
+ return ERROR(err); \
+ }
+
+/**
+ * Unconditionally return the specified error.
+ *
+ * In debug modes, prints additional information.
+ */
+#define RETURN_ERROR(err, ...) \
+ do { \
+ RAWLOG(3, "%s:%d: ERROR!: unconditional check failed, returning %s", \
+ __FILE__, __LINE__, ZSTD_QUOTE(ERROR(err))); \
+ _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \
+ RAWLOG(3, ": " __VA_ARGS__); \
+ RAWLOG(3, "\n"); \
+ return ERROR(err); \
+ } while(0);
+
+/**
+ * If the provided expression evaluates to an error code, returns that error code.
+ *
+ * In debug modes, prints additional information.
+ */
+#define FORWARD_IF_ERROR(err, ...) \
+ do { \
+ size_t const err_code = (err); \
+ if (ERR_isError(err_code)) { \
+ RAWLOG(3, "%s:%d: ERROR!: forwarding error in %s: %s", \
+ __FILE__, __LINE__, ZSTD_QUOTE(err), ERR_getErrorName(err_code)); \
+ _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \
+ RAWLOG(3, ": " __VA_ARGS__); \
+ RAWLOG(3, "\n"); \
+ return err_code; \
+ } \
+ } while(0);
+
+
+/*-*************************************
+* Common constants
+***************************************/
+#define ZSTD_OPT_NUM (1<<12)
+
+#define ZSTD_REP_NUM 3 /* number of repcodes */
+#define ZSTD_REP_MOVE (ZSTD_REP_NUM-1)
+static const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 };
+
+#define KB *(1 <<10)
+#define MB *(1 <<20)
+#define GB *(1U<<30)
+
+#define BIT7 128
+#define BIT6 64
+#define BIT5 32
+#define BIT4 16
+#define BIT1 2
+#define BIT0 1
+
+#define ZSTD_WINDOWLOG_ABSOLUTEMIN 10
+static const size_t ZSTD_fcs_fieldSize[4] = { 0, 2, 4, 8 };
+static const size_t ZSTD_did_fieldSize[4] = { 0, 1, 2, 4 };
+
+#define ZSTD_FRAMEIDSIZE 4 /* magic number size */
+
+#define ZSTD_BLOCKHEADERSIZE 3 /* C standard doesn't allow `static const` variable to be init using another `static const` variable */
+static const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE;
+typedef enum { bt_raw, bt_rle, bt_compressed, bt_reserved } blockType_e;
+
+#define ZSTD_FRAMECHECKSUMSIZE 4
+
+#define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */
+#define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */) /* for a non-null block */
+
+#define HufLog 12
+typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingType_e;
+
+#define LONGNBSEQ 0x7F00
+
+#define MINMATCH 3
+
+#define Litbits 8
+#define MaxLit ((1<<Litbits) - 1)
+#define MaxML 52
+#define MaxLL 35
+#define DefaultMaxOff 28
+#define MaxOff 31
+#define MaxSeq MAX(MaxLL, MaxML) /* Assumption : MaxOff < MaxLL,MaxML */
+#define MLFSELog 9
+#define LLFSELog 9
+#define OffFSELog 8
+#define MaxFSELog MAX(MAX(MLFSELog, LLFSELog), OffFSELog)
+
+static const U32 LL_bits[MaxLL+1] = { 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 2, 2, 3, 3,
+ 4, 6, 7, 8, 9,10,11,12,
+ 13,14,15,16 };
+static const S16 LL_defaultNorm[MaxLL+1] = { 4, 3, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 3, 2, 1, 1, 1, 1, 1,
+ -1,-1,-1,-1 };
+#define LL_DEFAULTNORMLOG 6 /* for static allocation */
+static const U32 LL_defaultNormLog = LL_DEFAULTNORMLOG;
+
+static const U32 ML_bits[MaxML+1] = { 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 2, 2, 3, 3,
+ 4, 4, 5, 7, 8, 9,10,11,
+ 12,13,14,15,16 };
+static const S16 ML_defaultNorm[MaxML+1] = { 1, 4, 3, 2, 2, 2, 2, 2,
+ 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1,-1,-1,
+ -1,-1,-1,-1,-1 };
+#define ML_DEFAULTNORMLOG 6 /* for static allocation */
+static const U32 ML_defaultNormLog = ML_DEFAULTNORMLOG;
+
+static const S16 OF_defaultNorm[DefaultMaxOff+1] = { 1, 1, 1, 1, 1, 1, 2, 2,
+ 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ -1,-1,-1,-1,-1 };
+#define OF_DEFAULTNORMLOG 5 /* for static allocation */
+static const U32 OF_defaultNormLog = OF_DEFAULTNORMLOG;
+
+
+/*-*******************************************
+* Shared functions to include for inlining
+*********************************************/
+static void ZSTD_copy8(void* dst, const void* src) {
+#if !defined(ZSTD_NO_INTRINSICS) && defined(__ARM_NEON)
+ vst1_u8((uint8_t*)dst, vld1_u8((const uint8_t*)src));
+#else
+ memcpy(dst, src, 8);
+#endif
+}
+
+#define COPY8(d,s) { ZSTD_copy8(d,s); d+=8; s+=8; }
+static void ZSTD_copy16(void* dst, const void* src) {
+#if !defined(ZSTD_NO_INTRINSICS) && defined(__ARM_NEON)
+ vst1q_u8((uint8_t*)dst, vld1q_u8((const uint8_t*)src));
+#else
+ memcpy(dst, src, 16);
+#endif
+}
+#define COPY16(d,s) { ZSTD_copy16(d,s); d+=16; s+=16; }
+
+#define WILDCOPY_OVERLENGTH 32
+#define WILDCOPY_VECLEN 16
+
+typedef enum {
+ ZSTD_no_overlap,
+ ZSTD_overlap_src_before_dst
+ /* ZSTD_overlap_dst_before_src, */
+} ZSTD_overlap_e;
+
+/*! ZSTD_wildcopy() :
+ * Custom version of memcpy(), can over read/write up to WILDCOPY_OVERLENGTH bytes (if length==0)
+ * @param ovtype controls the overlap detection
+ * - ZSTD_no_overlap: The source and destination are guaranteed to be at least WILDCOPY_VECLEN bytes apart.
+ * - ZSTD_overlap_src_before_dst: The src and dst may overlap, but they MUST be at least 8 bytes apart.
+ * The src buffer must be before the dst buffer.
+ */
+MEM_STATIC FORCE_INLINE_ATTR
+void ZSTD_wildcopy(void* dst, const void* src, ptrdiff_t length, ZSTD_overlap_e const ovtype)
+{
+ ptrdiff_t diff = (BYTE*)dst - (const BYTE*)src;
+ const BYTE* ip = (const BYTE*)src;
+ BYTE* op = (BYTE*)dst;
+ BYTE* const oend = op + length;
+
+ assert(diff >= 8 || (ovtype == ZSTD_no_overlap && diff <= -WILDCOPY_VECLEN));
+
+ if (ovtype == ZSTD_overlap_src_before_dst && diff < WILDCOPY_VECLEN) {
+ /* Handle short offset copies. */
+ do {
+ COPY8(op, ip)
+ } while (op < oend);
+ } else {
+ assert(diff >= WILDCOPY_VECLEN || diff <= -WILDCOPY_VECLEN);
+ /* Separate out the first COPY16() call because the copy length is
+ * almost certain to be short, so the branches have different
+ * probabilities. Since it is almost certain to be short, only do
+ * one COPY16() in the first call. Then, do two calls per loop since
+ * at that point it is more likely to have a high trip count.
+ */
+#ifndef __aarch64__
+ do {
+ COPY16(op, ip);
+ }
+ while (op < oend);
+#else
+ COPY16(op, ip);
+ if (op >= oend) return;
+ do {
+ COPY16(op, ip);
+ COPY16(op, ip);
+ }
+ while (op < oend);
+#endif
+ }
+}
+
+MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+{
+ size_t const length = MIN(dstCapacity, srcSize);
+ if (length > 0) {
+ memcpy(dst, src, length);
+ }
+ return length;
+}
+
+/* define "workspace is too large" as this number of times larger than needed */
+#define ZSTD_WORKSPACETOOLARGE_FACTOR 3
+
+/* when workspace is continuously too large
+ * during at least this number of times,
+ * context's memory usage is considered wasteful,
+ * because it's sized to handle a worst case scenario which rarely happens.
+ * In which case, resize it down to free some memory */
+#define ZSTD_WORKSPACETOOLARGE_MAXDURATION 128
+
+
+/*-*******************************************
+* Private declarations
+*********************************************/
+typedef struct seqDef_s {
+ U32 offset;
+ U16 litLength;
+ U16 matchLength;
+} seqDef;
+
+typedef struct {
+ seqDef* sequencesStart;
+ seqDef* sequences;
+ BYTE* litStart;
+ BYTE* lit;
+ BYTE* llCode;
+ BYTE* mlCode;
+ BYTE* ofCode;
+ size_t maxNbSeq;
+ size_t maxNbLit;
+ U32 longLengthID; /* 0 == no longLength; 1 == Lit.longLength; 2 == Match.longLength; */
+ U32 longLengthPos;
+} seqStore_t;
+
+typedef struct {
+ U32 litLength;
+ U32 matchLength;
+} ZSTD_sequenceLength;
+
+/**
+ * Returns the ZSTD_sequenceLength for the given sequences. It handles the decoding of long sequences
+ * indicated by longLengthPos and longLengthID, and adds MINMATCH back to matchLength.
+ */
+MEM_STATIC ZSTD_sequenceLength ZSTD_getSequenceLength(seqStore_t const* seqStore, seqDef const* seq)
+{
+ ZSTD_sequenceLength seqLen;
+ seqLen.litLength = seq->litLength;
+ seqLen.matchLength = seq->matchLength + MINMATCH;
+ if (seqStore->longLengthPos == (U32)(seq - seqStore->sequencesStart)) {
+ if (seqStore->longLengthID == 1) {
+ seqLen.litLength += 0xFFFF;
+ }
+ if (seqStore->longLengthID == 2) {
+ seqLen.matchLength += 0xFFFF;
+ }
+ }
+ return seqLen;
+}
+
+/**
+ * Contains the compressed frame size and an upper-bound for the decompressed frame size.
+ * Note: before using `compressedSize`, check for errors using ZSTD_isError().
+ * similarly, before using `decompressedBound`, check for errors using:
+ * `decompressedBound != ZSTD_CONTENTSIZE_ERROR`
+ */
+typedef struct {
+ size_t compressedSize;
+ unsigned long long decompressedBound;
+} ZSTD_frameSizeInfo; /* decompress & legacy */
+
+const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx); /* compress & dictBuilder */
+void ZSTD_seqToCodes(const seqStore_t* seqStorePtr); /* compress, dictBuilder, decodeCorpus (shouldn't get its definition from here) */
+
+/* custom memory allocation functions */
+void* ZSTD_malloc(size_t size, ZSTD_customMem customMem);
+void* ZSTD_calloc(size_t size, ZSTD_customMem customMem);
+void ZSTD_free(void* ptr, ZSTD_customMem customMem);
+
+
+MEM_STATIC U32 ZSTD_highbit32(U32 val) /* compress, dictBuilder, decodeCorpus */
+{
+ assert(val != 0);
+ {
+# if defined(_MSC_VER) /* Visual */
+ unsigned long r=0;
+ return _BitScanReverse(&r, val) ? (unsigned)r : 0;
+# elif defined(__GNUC__) && (__GNUC__ >= 3) /* GCC Intrinsic */
+ return __builtin_clz (val) ^ 31;
+# elif defined(__ICCARM__) /* IAR Intrinsic */
+ return 31 - __CLZ(val);
+# else /* Software version */
+ static const U32 DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 };
+ U32 v = val;
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+ return DeBruijnClz[(v * 0x07C4ACDDU) >> 27];
+# endif
+ }
+}
+
+
+/* ZSTD_invalidateRepCodes() :
+ * ensures next compression will not use repcodes from previous block.
+ * Note : only works with regular variant;
+ * do not use with extDict variant ! */
+void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx); /* zstdmt, adaptive_compression (shouldn't get this definition from here) */
+
+
+typedef struct {
+ blockType_e blockType;
+ U32 lastBlock;
+ U32 origSize;
+} blockProperties_t; /* declared here for decompress and fullbench */
+
+/*! ZSTD_getcBlockSize() :
+ * Provides the size of compressed block from block header `src` */
+/* Used by: decompress, fullbench (does not get its definition from here) */
+size_t ZSTD_getcBlockSize(const void* src, size_t srcSize,
+ blockProperties_t* bpPtr);
+
+/*! ZSTD_decodeSeqHeaders() :
+ * decode sequence header from src */
+/* Used by: decompress, fullbench (does not get its definition from here) */
+size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr,
+ const void* src, size_t srcSize);
+
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* ZSTD_CCOMMON_H_MODULE */
diff --git a/sys/contrib/openzfs/module/zstd/lib/compress/fse_compress.c b/sys/contrib/openzfs/module/zstd/lib/compress/fse_compress.c
new file mode 100644
index 000000000000..a42759814fdd
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/compress/fse_compress.c
@@ -0,0 +1,698 @@
+/* ******************************************************************
+ * FSE : Finite State Entropy encoder
+ * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ *
+ * You can contact the author at :
+ * - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
+ * - Public forum : https://groups.google.com/forum/#!forum/lz4c
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+****************************************************************** */
+
+/* **************************************************************
+* Includes
+****************************************************************/
+#include <stdlib.h> /* malloc, free, qsort */
+#include <string.h> /* memcpy, memset */
+#include "../common/compiler.h"
+#include "../common/mem.h" /* U32, U16, etc. */
+#include "../common/debug.h" /* assert, DEBUGLOG */
+#include "hist.h" /* HIST_count_wksp */
+#include "../common/bitstream.h"
+#define FSE_STATIC_LINKING_ONLY
+#include "../common/fse.h"
+#include "../common/error_private.h"
+
+
+/* **************************************************************
+* Error Management
+****************************************************************/
+#define FSE_isError ERR_isError
+
+
+/* **************************************************************
+* Templates
+****************************************************************/
+/*
+ designed to be included
+ for type-specific functions (template emulation in C)
+ Objective is to write these functions only once, for improved maintenance
+*/
+
+/* safety checks */
+#ifndef FSE_FUNCTION_EXTENSION
+# error "FSE_FUNCTION_EXTENSION must be defined"
+#endif
+#ifndef FSE_FUNCTION_TYPE
+# error "FSE_FUNCTION_TYPE must be defined"
+#endif
+
+/* Function names */
+#define FSE_CAT(X,Y) X##Y
+#define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y)
+#define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y)
+
+
+/* Function templates */
+
+/* FSE_buildCTable_wksp() :
+ * Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`).
+ * wkspSize should be sized to handle worst case situation, which is `1<<max_tableLog * sizeof(FSE_FUNCTION_TYPE)`
+ * workSpace must also be properly aligned with FSE_FUNCTION_TYPE requirements
+ */
+size_t FSE_buildCTable_wksp(FSE_CTable* ct,
+ const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog,
+ void* workSpace, size_t wkspSize)
+{
+ U32 const tableSize = 1 << tableLog;
+ U32 const tableMask = tableSize - 1;
+ void* const ptr = ct;
+ U16* const tableU16 = ( (U16*) ptr) + 2;
+ void* const FSCT = ((U32*)ptr) + 1 /* header */ + (tableLog ? tableSize>>1 : 1) ;
+ FSE_symbolCompressionTransform* const symbolTT = (FSE_symbolCompressionTransform*) (FSCT);
+ U32 const step = FSE_TABLESTEP(tableSize);
+ U32 cumul[FSE_MAX_SYMBOL_VALUE+2];
+
+ FSE_FUNCTION_TYPE* const tableSymbol = (FSE_FUNCTION_TYPE*)workSpace;
+ U32 highThreshold = tableSize-1;
+
+ /* CTable header */
+ if (((size_t)1 << tableLog) * sizeof(FSE_FUNCTION_TYPE) > wkspSize) return ERROR(tableLog_tooLarge);
+ tableU16[-2] = (U16) tableLog;
+ tableU16[-1] = (U16) maxSymbolValue;
+ assert(tableLog < 16); /* required for threshold strategy to work */
+
+ /* For explanations on how to distribute symbol values over the table :
+ * http://fastcompression.blogspot.fr/2014/02/fse-distributing-symbol-values.html */
+
+ #ifdef __clang_analyzer__
+ memset(tableSymbol, 0, sizeof(*tableSymbol) * tableSize); /* useless initialization, just to keep scan-build happy */
+ #endif
+
+ /* symbol start positions */
+ { U32 u;
+ cumul[0] = 0;
+ for (u=1; u <= maxSymbolValue+1; u++) {
+ if (normalizedCounter[u-1]==-1) { /* Low proba symbol */
+ cumul[u] = cumul[u-1] + 1;
+ tableSymbol[highThreshold--] = (FSE_FUNCTION_TYPE)(u-1);
+ } else {
+ cumul[u] = cumul[u-1] + normalizedCounter[u-1];
+ } }
+ cumul[maxSymbolValue+1] = tableSize+1;
+ }
+
+ /* Spread symbols */
+ { U32 position = 0;
+ U32 symbol;
+ for (symbol=0; symbol<=maxSymbolValue; symbol++) {
+ int nbOccurrences;
+ int const freq = normalizedCounter[symbol];
+ for (nbOccurrences=0; nbOccurrences<freq; nbOccurrences++) {
+ tableSymbol[position] = (FSE_FUNCTION_TYPE)symbol;
+ position = (position + step) & tableMask;
+ while (position > highThreshold)
+ position = (position + step) & tableMask; /* Low proba area */
+ } }
+
+ assert(position==0); /* Must have initialized all positions */
+ }
+
+ /* Build table */
+ { U32 u; for (u=0; u<tableSize; u++) {
+ FSE_FUNCTION_TYPE s = tableSymbol[u]; /* note : static analyzer may not understand tableSymbol is properly initialized */
+ tableU16[cumul[s]++] = (U16) (tableSize+u); /* TableU16 : sorted by symbol order; gives next state value */
+ } }
+
+ /* Build Symbol Transformation Table */
+ { unsigned total = 0;
+ unsigned s;
+ for (s=0; s<=maxSymbolValue; s++) {
+ switch (normalizedCounter[s])
+ {
+ case 0:
+ /* filling nonetheless, for compatibility with FSE_getMaxNbBits() */
+ symbolTT[s].deltaNbBits = ((tableLog+1) << 16) - (1<<tableLog);
+ break;
+
+ case -1:
+ case 1:
+ symbolTT[s].deltaNbBits = (tableLog << 16) - (1<<tableLog);
+ symbolTT[s].deltaFindState = total - 1;
+ total ++;
+ break;
+ default :
+ {
+ U32 const maxBitsOut = tableLog - BIT_highbit32 (normalizedCounter[s]-1);
+ U32 const minStatePlus = normalizedCounter[s] << maxBitsOut;
+ symbolTT[s].deltaNbBits = (maxBitsOut << 16) - minStatePlus;
+ symbolTT[s].deltaFindState = total - normalizedCounter[s];
+ total += normalizedCounter[s];
+ } } } }
+
+#if 0 /* debug : symbol costs */
+ DEBUGLOG(5, "\n --- table statistics : ");
+ { U32 symbol;
+ for (symbol=0; symbol<=maxSymbolValue; symbol++) {
+ DEBUGLOG(5, "%3u: w=%3i, maxBits=%u, fracBits=%.2f",
+ symbol, normalizedCounter[symbol],
+ FSE_getMaxNbBits(symbolTT, symbol),
+ (double)FSE_bitCost(symbolTT, tableLog, symbol, 8) / 256);
+ }
+ }
+#endif
+
+ return 0;
+}
+
+
+size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)
+{
+ FSE_FUNCTION_TYPE tableSymbol[FSE_MAX_TABLESIZE]; /* memset() is not necessary, even if static analyzer complain about it */
+ return FSE_buildCTable_wksp(ct, normalizedCounter, maxSymbolValue, tableLog, tableSymbol, sizeof(tableSymbol));
+}
+
+
+
+#ifndef FSE_COMMONDEFS_ONLY
+
+
+/*-**************************************************************
+* FSE NCount encoding
+****************************************************************/
+size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog)
+{
+ size_t const maxHeaderSize = (((maxSymbolValue+1) * tableLog) >> 3) + 3;
+ return maxSymbolValue ? maxHeaderSize : FSE_NCOUNTBOUND; /* maxSymbolValue==0 ? use default */
+}
+
+static size_t
+FSE_writeNCount_generic (void* header, size_t headerBufferSize,
+ const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog,
+ unsigned writeIsSafe)
+{
+ BYTE* const ostart = (BYTE*) header;
+ BYTE* out = ostart;
+ BYTE* const oend = ostart + headerBufferSize;
+ int nbBits;
+ const int tableSize = 1 << tableLog;
+ int remaining;
+ int threshold;
+ U32 bitStream = 0;
+ int bitCount = 0;
+ unsigned symbol = 0;
+ unsigned const alphabetSize = maxSymbolValue + 1;
+ int previousIs0 = 0;
+
+ /* Table Size */
+ bitStream += (tableLog-FSE_MIN_TABLELOG) << bitCount;
+ bitCount += 4;
+
+ /* Init */
+ remaining = tableSize+1; /* +1 for extra accuracy */
+ threshold = tableSize;
+ nbBits = tableLog+1;
+
+ while ((symbol < alphabetSize) && (remaining>1)) { /* stops at 1 */
+ if (previousIs0) {
+ unsigned start = symbol;
+ while ((symbol < alphabetSize) && !normalizedCounter[symbol]) symbol++;
+ if (symbol == alphabetSize) break; /* incorrect distribution */
+ while (symbol >= start+24) {
+ start+=24;
+ bitStream += 0xFFFFU << bitCount;
+ if ((!writeIsSafe) && (out > oend-2))
+ return ERROR(dstSize_tooSmall); /* Buffer overflow */
+ out[0] = (BYTE) bitStream;
+ out[1] = (BYTE)(bitStream>>8);
+ out+=2;
+ bitStream>>=16;
+ }
+ while (symbol >= start+3) {
+ start+=3;
+ bitStream += 3 << bitCount;
+ bitCount += 2;
+ }
+ bitStream += (symbol-start) << bitCount;
+ bitCount += 2;
+ if (bitCount>16) {
+ if ((!writeIsSafe) && (out > oend - 2))
+ return ERROR(dstSize_tooSmall); /* Buffer overflow */
+ out[0] = (BYTE)bitStream;
+ out[1] = (BYTE)(bitStream>>8);
+ out += 2;
+ bitStream >>= 16;
+ bitCount -= 16;
+ } }
+ { int count = normalizedCounter[symbol++];
+ int const max = (2*threshold-1) - remaining;
+ remaining -= count < 0 ? -count : count;
+ count++; /* +1 for extra accuracy */
+ if (count>=threshold)
+ count += max; /* [0..max[ [max..threshold[ (...) [threshold+max 2*threshold[ */
+ bitStream += count << bitCount;
+ bitCount += nbBits;
+ bitCount -= (count<max);
+ previousIs0 = (count==1);
+ if (remaining<1) return ERROR(GENERIC);
+ while (remaining<threshold) { nbBits--; threshold>>=1; }
+ }
+ if (bitCount>16) {
+ if ((!writeIsSafe) && (out > oend - 2))
+ return ERROR(dstSize_tooSmall); /* Buffer overflow */
+ out[0] = (BYTE)bitStream;
+ out[1] = (BYTE)(bitStream>>8);
+ out += 2;
+ bitStream >>= 16;
+ bitCount -= 16;
+ } }
+
+ if (remaining != 1)
+ return ERROR(GENERIC); /* incorrect normalized distribution */
+ assert(symbol <= alphabetSize);
+
+ /* flush remaining bitStream */
+ if ((!writeIsSafe) && (out > oend - 2))
+ return ERROR(dstSize_tooSmall); /* Buffer overflow */
+ out[0] = (BYTE)bitStream;
+ out[1] = (BYTE)(bitStream>>8);
+ out+= (bitCount+7) /8;
+
+ return (out-ostart);
+}
+
+
+size_t FSE_writeNCount (void* buffer, size_t bufferSize,
+ const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)
+{
+ if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); /* Unsupported */
+ if (tableLog < FSE_MIN_TABLELOG) return ERROR(GENERIC); /* Unsupported */
+
+ if (bufferSize < FSE_NCountWriteBound(maxSymbolValue, tableLog))
+ return FSE_writeNCount_generic(buffer, bufferSize, normalizedCounter, maxSymbolValue, tableLog, 0);
+
+ return FSE_writeNCount_generic(buffer, bufferSize, normalizedCounter, maxSymbolValue, tableLog, 1 /* write in buffer is safe */);
+}
+
+
+/*-**************************************************************
+* FSE Compression Code
+****************************************************************/
+
+FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog)
+{
+ size_t size;
+ 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);
+}
+
+void FSE_freeCTable (FSE_CTable* ct) { free(ct); }
+
+/* provides the minimum logSize to safely represent a distribution */
+static unsigned FSE_minTableLog(size_t srcSize, unsigned maxSymbolValue)
+{
+ U32 minBitsSrc = BIT_highbit32((U32)(srcSize)) + 1;
+ U32 minBitsSymbols = BIT_highbit32(maxSymbolValue) + 2;
+ U32 minBits = minBitsSrc < minBitsSymbols ? minBitsSrc : minBitsSymbols;
+ assert(srcSize > 1); /* Not supported, RLE should be used instead */
+ return minBits;
+}
+
+unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus)
+{
+ U32 maxBitsSrc = BIT_highbit32((U32)(srcSize - 1)) - minus;
+ U32 tableLog = maxTableLog;
+ U32 minBits = FSE_minTableLog(srcSize, maxSymbolValue);
+ assert(srcSize > 1); /* Not supported, RLE should be used instead */
+ if (tableLog==0) tableLog = FSE_DEFAULT_TABLELOG;
+ if (maxBitsSrc < tableLog) tableLog = maxBitsSrc; /* Accuracy can be reduced */
+ if (minBits > tableLog) tableLog = minBits; /* Need a minimum to safely represent all symbol values */
+ if (tableLog < FSE_MIN_TABLELOG) tableLog = FSE_MIN_TABLELOG;
+ if (tableLog > FSE_MAX_TABLELOG) tableLog = FSE_MAX_TABLELOG;
+ return tableLog;
+}
+
+unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue)
+{
+ return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 2);
+}
+
+
+/* Secondary normalization method.
+ To be used when primary method fails. */
+
+static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, size_t total, U32 maxSymbolValue)
+{
+ short const NOT_YET_ASSIGNED = -2;
+ U32 s;
+ U32 distributed = 0;
+ U32 ToDistribute;
+
+ /* Init */
+ U32 const lowThreshold = (U32)(total >> tableLog);
+ U32 lowOne = (U32)((total * 3) >> (tableLog + 1));
+
+ for (s=0; s<=maxSymbolValue; s++) {
+ if (count[s] == 0) {
+ norm[s]=0;
+ continue;
+ }
+ if (count[s] <= lowThreshold) {
+ norm[s] = -1;
+ distributed++;
+ total -= count[s];
+ continue;
+ }
+ if (count[s] <= lowOne) {
+ norm[s] = 1;
+ distributed++;
+ total -= count[s];
+ continue;
+ }
+
+ norm[s]=NOT_YET_ASSIGNED;
+ }
+ ToDistribute = (1 << tableLog) - distributed;
+
+ if (ToDistribute == 0)
+ return 0;
+
+ if ((total / ToDistribute) > lowOne) {
+ /* risk of rounding to zero */
+ lowOne = (U32)((total * 3) / (ToDistribute * 2));
+ for (s=0; s<=maxSymbolValue; s++) {
+ if ((norm[s] == NOT_YET_ASSIGNED) && (count[s] <= lowOne)) {
+ norm[s] = 1;
+ distributed++;
+ total -= count[s];
+ continue;
+ } }
+ ToDistribute = (1 << tableLog) - distributed;
+ }
+
+ if (distributed == maxSymbolValue+1) {
+ /* all values are pretty poor;
+ probably incompressible data (should have already been detected);
+ find max, then give all remaining points to max */
+ U32 maxV = 0, maxC = 0;
+ for (s=0; s<=maxSymbolValue; s++)
+ if (count[s] > maxC) { maxV=s; maxC=count[s]; }
+ norm[maxV] += (short)ToDistribute;
+ return 0;
+ }
+
+ if (total == 0) {
+ /* all of the symbols were low enough for the lowOne or lowThreshold */
+ for (s=0; ToDistribute > 0; s = (s+1)%(maxSymbolValue+1))
+ if (norm[s] > 0) { ToDistribute--; norm[s]++; }
+ return 0;
+ }
+
+ { U64 const vStepLog = 62 - tableLog;
+ U64 const mid = (1ULL << (vStepLog-1)) - 1;
+ U64 const rStep = ((((U64)1<<vStepLog) * ToDistribute) + mid) / total; /* scale on remaining */
+ U64 tmpTotal = mid;
+ for (s=0; s<=maxSymbolValue; s++) {
+ if (norm[s]==NOT_YET_ASSIGNED) {
+ U64 const end = tmpTotal + (count[s] * rStep);
+ U32 const sStart = (U32)(tmpTotal >> vStepLog);
+ U32 const sEnd = (U32)(end >> vStepLog);
+ U32 const weight = sEnd - sStart;
+ if (weight < 1)
+ return ERROR(GENERIC);
+ norm[s] = (short)weight;
+ tmpTotal = end;
+ } } }
+
+ return 0;
+}
+
+
+size_t FSE_normalizeCount (short* normalizedCounter, unsigned tableLog,
+ const unsigned* count, size_t total,
+ unsigned maxSymbolValue)
+{
+ /* Sanity checks */
+ if (tableLog==0) tableLog = FSE_DEFAULT_TABLELOG;
+ if (tableLog < FSE_MIN_TABLELOG) return ERROR(GENERIC); /* Unsupported size */
+ if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); /* Unsupported size */
+ if (tableLog < FSE_minTableLog(total, maxSymbolValue)) return ERROR(GENERIC); /* Too small tableLog, compression potentially impossible */
+
+ { static U32 const rtbTable[] = { 0, 473195, 504333, 520860, 550000, 700000, 750000, 830000 };
+ U64 const scale = 62 - tableLog;
+ U64 const step = ((U64)1<<62) / total; /* <== here, one division ! */
+ U64 const vStep = 1ULL<<(scale-20);
+ int stillToDistribute = 1<<tableLog;
+ unsigned s;
+ unsigned largest=0;
+ short largestP=0;
+ U32 lowThreshold = (U32)(total >> tableLog);
+
+ for (s=0; s<=maxSymbolValue; s++) {
+ if (count[s] == total) return 0; /* rle special case */
+ if (count[s] == 0) { normalizedCounter[s]=0; continue; }
+ if (count[s] <= lowThreshold) {
+ normalizedCounter[s] = -1;
+ stillToDistribute--;
+ } else {
+ short proba = (short)((count[s]*step) >> scale);
+ if (proba<8) {
+ U64 restToBeat = vStep * rtbTable[proba];
+ proba += (count[s]*step) - ((U64)proba<<scale) > restToBeat;
+ }
+ if (proba > largestP) { largestP=proba; largest=s; }
+ normalizedCounter[s] = proba;
+ stillToDistribute -= proba;
+ } }
+ if (-stillToDistribute >= (normalizedCounter[largest] >> 1)) {
+ /* corner case, need another normalization method */
+ size_t const errorCode = FSE_normalizeM2(normalizedCounter, tableLog, count, total, maxSymbolValue);
+ if (FSE_isError(errorCode)) return errorCode;
+ }
+ else normalizedCounter[largest] += (short)stillToDistribute;
+ }
+
+#if 0
+ { /* Print Table (debug) */
+ U32 s;
+ U32 nTotal = 0;
+ for (s=0; s<=maxSymbolValue; s++)
+ RAWLOG(2, "%3i: %4i \n", s, normalizedCounter[s]);
+ for (s=0; s<=maxSymbolValue; s++)
+ nTotal += abs(normalizedCounter[s]);
+ if (nTotal != (1U<<tableLog))
+ RAWLOG(2, "Warning !!! Total == %u != %u !!!", nTotal, 1U<<tableLog);
+ getchar();
+ }
+#endif
+
+ return tableLog;
+}
+
+
+/* fake FSE_CTable, for raw (uncompressed) input */
+size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits)
+{
+ const unsigned tableSize = 1 << nbBits;
+ const unsigned tableMask = tableSize - 1;
+ const unsigned maxSymbolValue = tableMask;
+ void* const ptr = ct;
+ U16* const tableU16 = ( (U16*) ptr) + 2;
+ void* const FSCT = ((U32*)ptr) + 1 /* header */ + (tableSize>>1); /* assumption : tableLog >= 1 */
+ FSE_symbolCompressionTransform* const symbolTT = (FSE_symbolCompressionTransform*) (FSCT);
+ unsigned s;
+
+ /* Sanity checks */
+ if (nbBits < 1) return ERROR(GENERIC); /* min size */
+
+ /* header */
+ tableU16[-2] = (U16) nbBits;
+ tableU16[-1] = (U16) maxSymbolValue;
+
+ /* Build table */
+ for (s=0; s<tableSize; s++)
+ tableU16[s] = (U16)(tableSize + s);
+
+ /* Build Symbol Transformation Table */
+ { const U32 deltaNbBits = (nbBits << 16) - (1 << nbBits);
+ for (s=0; s<=maxSymbolValue; s++) {
+ symbolTT[s].deltaNbBits = deltaNbBits;
+ symbolTT[s].deltaFindState = s-1;
+ } }
+
+ return 0;
+}
+
+/* fake FSE_CTable, for rle input (always same symbol) */
+size_t FSE_buildCTable_rle (FSE_CTable* ct, BYTE symbolValue)
+{
+ void* ptr = ct;
+ U16* tableU16 = ( (U16*) ptr) + 2;
+ void* FSCTptr = (U32*)ptr + 2;
+ FSE_symbolCompressionTransform* symbolTT = (FSE_symbolCompressionTransform*) FSCTptr;
+
+ /* header */
+ tableU16[-2] = (U16) 0;
+ tableU16[-1] = (U16) symbolValue;
+
+ /* Build table */
+ tableU16[0] = 0;
+ tableU16[1] = 0; /* just in case */
+
+ /* Build Symbol Transformation Table */
+ symbolTT[symbolValue].deltaNbBits = 0;
+ symbolTT[symbolValue].deltaFindState = 0;
+
+ return 0;
+}
+
+
+static size_t FSE_compress_usingCTable_generic (void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ const FSE_CTable* ct, const unsigned fast)
+{
+ const BYTE* const istart = (const BYTE*) src;
+ const BYTE* const iend = istart + srcSize;
+ const BYTE* ip=iend;
+
+ BIT_CStream_t bitC;
+ FSE_CState_t CState1, CState2;
+
+ /* init */
+ if (srcSize <= 2) return 0;
+ { size_t const initError = BIT_initCStream(&bitC, dst, dstSize);
+ if (FSE_isError(initError)) return 0; /* not enough space available to write a bitstream */ }
+
+#define FSE_FLUSHBITS(s) (fast ? BIT_flushBitsFast(s) : BIT_flushBits(s))
+
+ if (srcSize & 1) {
+ FSE_initCState2(&CState1, ct, *--ip);
+ FSE_initCState2(&CState2, ct, *--ip);
+ FSE_encodeSymbol(&bitC, &CState1, *--ip);
+ FSE_FLUSHBITS(&bitC);
+ } else {
+ FSE_initCState2(&CState2, ct, *--ip);
+ FSE_initCState2(&CState1, ct, *--ip);
+ }
+
+ /* join to mod 4 */
+ srcSize -= 2;
+ if ((sizeof(bitC.bitContainer)*8 > FSE_MAX_TABLELOG*4+7 ) && (srcSize & 2)) { /* test bit 2 */
+ FSE_encodeSymbol(&bitC, &CState2, *--ip);
+ FSE_encodeSymbol(&bitC, &CState1, *--ip);
+ FSE_FLUSHBITS(&bitC);
+ }
+
+ /* 2 or 4 encoding per loop */
+ while ( ip>istart ) {
+
+ FSE_encodeSymbol(&bitC, &CState2, *--ip);
+
+ if (sizeof(bitC.bitContainer)*8 < FSE_MAX_TABLELOG*2+7 ) /* this test must be static */
+ FSE_FLUSHBITS(&bitC);
+
+ FSE_encodeSymbol(&bitC, &CState1, *--ip);
+
+ if (sizeof(bitC.bitContainer)*8 > FSE_MAX_TABLELOG*4+7 ) { /* this test must be static */
+ FSE_encodeSymbol(&bitC, &CState2, *--ip);
+ FSE_encodeSymbol(&bitC, &CState1, *--ip);
+ }
+
+ FSE_FLUSHBITS(&bitC);
+ }
+
+ FSE_flushCState(&bitC, &CState2);
+ FSE_flushCState(&bitC, &CState1);
+ return BIT_closeCStream(&bitC);
+}
+
+size_t FSE_compress_usingCTable (void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ const FSE_CTable* ct)
+{
+ unsigned const fast = (dstSize >= FSE_BLOCKBOUND(srcSize));
+
+ if (fast)
+ return FSE_compress_usingCTable_generic(dst, dstSize, src, srcSize, ct, 1);
+ else
+ return FSE_compress_usingCTable_generic(dst, dstSize, src, srcSize, ct, 0);
+}
+
+
+size_t FSE_compressBound(size_t size) { return FSE_COMPRESSBOUND(size); }
+
+/* FSE_compress_wksp() :
+ * Same as FSE_compress2(), but using an externally allocated scratch buffer (`workSpace`).
+ * `wkspSize` size must be `(1<<tableLog)`.
+ */
+size_t FSE_compress_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize)
+{
+ BYTE* const ostart = (BYTE*) dst;
+ BYTE* op = ostart;
+ BYTE* const oend = ostart + dstSize;
+
+ unsigned count[FSE_MAX_SYMBOL_VALUE+1];
+ S16 norm[FSE_MAX_SYMBOL_VALUE+1];
+ FSE_CTable* CTable = (FSE_CTable*)workSpace;
+ size_t const CTableSize = FSE_CTABLE_SIZE_U32(tableLog, maxSymbolValue);
+ void* scratchBuffer = (void*)(CTable + CTableSize);
+ size_t const scratchBufferSize = wkspSize - (CTableSize * sizeof(FSE_CTable));
+
+ /* init conditions */
+ if (wkspSize < FSE_WKSP_SIZE_U32(tableLog, maxSymbolValue)) return ERROR(tableLog_tooLarge);
+ if (srcSize <= 1) return 0; /* Not compressible */
+ if (!maxSymbolValue) maxSymbolValue = FSE_MAX_SYMBOL_VALUE;
+ if (!tableLog) tableLog = FSE_DEFAULT_TABLELOG;
+
+ /* Scan input and build symbol stats */
+ { CHECK_V_F(maxCount, HIST_count_wksp(count, &maxSymbolValue, src, srcSize, scratchBuffer, scratchBufferSize) );
+ if (maxCount == srcSize) return 1; /* only a single symbol in src : rle */
+ if (maxCount == 1) return 0; /* each symbol present maximum once => not compressible */
+ if (maxCount < (srcSize >> 7)) return 0; /* Heuristic : not compressible enough */
+ }
+
+ tableLog = FSE_optimalTableLog(tableLog, srcSize, maxSymbolValue);
+ CHECK_F( FSE_normalizeCount(norm, tableLog, count, srcSize, maxSymbolValue) );
+
+ /* Write table description header */
+ { CHECK_V_F(nc_err, FSE_writeNCount(op, oend-op, norm, maxSymbolValue, tableLog) );
+ op += nc_err;
+ }
+
+ /* Compress */
+ CHECK_F( FSE_buildCTable_wksp(CTable, norm, maxSymbolValue, tableLog, scratchBuffer, scratchBufferSize) );
+ { CHECK_V_F(cSize, FSE_compress_usingCTable(op, oend - op, src, srcSize, CTable) );
+ if (cSize == 0) return 0; /* not enough space for compressed data */
+ op += cSize;
+ }
+
+ /* check compressibility */
+ if ( (size_t)(op-ostart) >= srcSize-1 ) return 0;
+
+ return op-ostart;
+}
+
+typedef struct {
+ FSE_CTable CTable_max[FSE_CTABLE_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)];
+ BYTE scratchBuffer[1 << FSE_MAX_TABLELOG];
+} fseWkspMax_t;
+
+size_t FSE_compress2 (void* dst, size_t dstCapacity, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog)
+{
+ fseWkspMax_t scratchBuffer;
+ DEBUG_STATIC_ASSERT(sizeof(scratchBuffer) >= FSE_WKSP_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)); /* compilation failures here means scratchBuffer is not large enough */
+ if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge);
+ return FSE_compress_wksp(dst, dstCapacity, src, srcSize, maxSymbolValue, tableLog, &scratchBuffer, sizeof(scratchBuffer));
+}
+
+size_t FSE_compress (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+{
+ return FSE_compress2(dst, dstCapacity, src, srcSize, FSE_MAX_SYMBOL_VALUE, FSE_DEFAULT_TABLELOG);
+}
+
+
+#endif /* FSE_COMMONDEFS_ONLY */
diff --git a/sys/contrib/openzfs/module/zstd/lib/compress/hist.c b/sys/contrib/openzfs/module/zstd/lib/compress/hist.c
new file mode 100644
index 000000000000..61e08c7968be
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/compress/hist.c
@@ -0,0 +1,183 @@
+/* ******************************************************************
+ * hist : Histogram functions
+ * part of Finite State Entropy project
+ * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ *
+ * You can contact the author at :
+ * - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
+ * - Public forum : https://groups.google.com/forum/#!forum/lz4c
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+****************************************************************** */
+
+/* --- dependencies --- */
+#include "../common/mem.h" /* U32, BYTE, etc. */
+#include "../common/debug.h" /* assert, DEBUGLOG */
+#include "../common/error_private.h" /* ERROR */
+#include "hist.h"
+
+
+/* --- Error management --- */
+unsigned HIST_isError(size_t code) { return ERR_isError(code); }
+
+/*-**************************************************************
+ * Histogram functions
+ ****************************************************************/
+unsigned HIST_count_simple(unsigned* count, unsigned* maxSymbolValuePtr,
+ const void* src, size_t srcSize)
+{
+ const BYTE* ip = (const BYTE*)src;
+ const BYTE* const end = ip + srcSize;
+ unsigned maxSymbolValue = *maxSymbolValuePtr;
+ unsigned largestCount=0;
+
+ memset(count, 0, (maxSymbolValue+1) * sizeof(*count));
+ if (srcSize==0) { *maxSymbolValuePtr = 0; return 0; }
+
+ while (ip<end) {
+ assert(*ip <= maxSymbolValue);
+ count[*ip++]++;
+ }
+
+ while (!count[maxSymbolValue]) maxSymbolValue--;
+ *maxSymbolValuePtr = maxSymbolValue;
+
+ { U32 s;
+ for (s=0; s<=maxSymbolValue; s++)
+ if (count[s] > largestCount) largestCount = count[s];
+ }
+
+ return largestCount;
+}
+
+typedef enum { trustInput, checkMaxSymbolValue } HIST_checkInput_e;
+
+/* HIST_count_parallel_wksp() :
+ * store histogram into 4 intermediate tables, recombined at the end.
+ * this design makes better use of OoO cpus,
+ * and is noticeably faster when some values are heavily repeated.
+ * But it needs some additional workspace for intermediate tables.
+ * `workSpace` size must be a table of size >= HIST_WKSP_SIZE_U32.
+ * @return : largest histogram frequency,
+ * or an error code (notably when histogram would be larger than *maxSymbolValuePtr). */
+static size_t HIST_count_parallel_wksp(
+ unsigned* count, unsigned* maxSymbolValuePtr,
+ const void* source, size_t sourceSize,
+ HIST_checkInput_e check,
+ U32* const workSpace)
+{
+ const BYTE* ip = (const BYTE*)source;
+ const BYTE* const iend = ip+sourceSize;
+ unsigned maxSymbolValue = *maxSymbolValuePtr;
+ unsigned max=0;
+ U32* const Counting1 = workSpace;
+ U32* const Counting2 = Counting1 + 256;
+ U32* const Counting3 = Counting2 + 256;
+ U32* const Counting4 = Counting3 + 256;
+
+ memset(workSpace, 0, 4*256*sizeof(unsigned));
+
+ /* safety checks */
+ if (!sourceSize) {
+ memset(count, 0, maxSymbolValue + 1);
+ *maxSymbolValuePtr = 0;
+ return 0;
+ }
+ if (!maxSymbolValue) maxSymbolValue = 255; /* 0 == default */
+
+ /* by stripes of 16 bytes */
+ { U32 cached = MEM_read32(ip); ip += 4;
+ while (ip < iend-15) {
+ U32 c = cached; cached = MEM_read32(ip); ip += 4;
+ Counting1[(BYTE) c ]++;
+ Counting2[(BYTE)(c>>8) ]++;
+ Counting3[(BYTE)(c>>16)]++;
+ Counting4[ c>>24 ]++;
+ c = cached; cached = MEM_read32(ip); ip += 4;
+ Counting1[(BYTE) c ]++;
+ Counting2[(BYTE)(c>>8) ]++;
+ Counting3[(BYTE)(c>>16)]++;
+ Counting4[ c>>24 ]++;
+ c = cached; cached = MEM_read32(ip); ip += 4;
+ Counting1[(BYTE) c ]++;
+ Counting2[(BYTE)(c>>8) ]++;
+ Counting3[(BYTE)(c>>16)]++;
+ Counting4[ c>>24 ]++;
+ c = cached; cached = MEM_read32(ip); ip += 4;
+ Counting1[(BYTE) c ]++;
+ Counting2[(BYTE)(c>>8) ]++;
+ Counting3[(BYTE)(c>>16)]++;
+ Counting4[ c>>24 ]++;
+ }
+ ip-=4;
+ }
+
+ /* finish last symbols */
+ while (ip<iend) Counting1[*ip++]++;
+
+ if (check) { /* verify stats will fit into destination table */
+ U32 s; for (s=255; s>maxSymbolValue; s--) {
+ Counting1[s] += Counting2[s] + Counting3[s] + Counting4[s];
+ if (Counting1[s]) return ERROR(maxSymbolValue_tooSmall);
+ } }
+
+ { U32 s;
+ if (maxSymbolValue > 255) maxSymbolValue = 255;
+ for (s=0; s<=maxSymbolValue; s++) {
+ count[s] = Counting1[s] + Counting2[s] + Counting3[s] + Counting4[s];
+ if (count[s] > max) max = count[s];
+ } }
+
+ while (!count[maxSymbolValue]) maxSymbolValue--;
+ *maxSymbolValuePtr = maxSymbolValue;
+ return (size_t)max;
+}
+
+/* HIST_countFast_wksp() :
+ * Same as HIST_countFast(), but using an externally provided scratch buffer.
+ * `workSpace` is a writable buffer which must be 4-bytes aligned,
+ * `workSpaceSize` must be >= HIST_WKSP_SIZE
+ */
+size_t HIST_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
+ const void* source, size_t sourceSize,
+ void* workSpace, size_t workSpaceSize)
+{
+ if (sourceSize < 1500) /* heuristic threshold */
+ return HIST_count_simple(count, maxSymbolValuePtr, source, sourceSize);
+ if ((size_t)workSpace & 3) return ERROR(GENERIC); /* must be aligned on 4-bytes boundaries */
+ if (workSpaceSize < HIST_WKSP_SIZE) return ERROR(workSpace_tooSmall);
+ return HIST_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, trustInput, (U32*)workSpace);
+}
+
+/* fast variant (unsafe : won't check if src contains values beyond count[] limit) */
+size_t HIST_countFast(unsigned* count, unsigned* maxSymbolValuePtr,
+ const void* source, size_t sourceSize)
+{
+ unsigned tmpCounters[HIST_WKSP_SIZE_U32];
+ return HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, tmpCounters, sizeof(tmpCounters));
+}
+
+/* HIST_count_wksp() :
+ * Same as HIST_count(), but using an externally provided scratch buffer.
+ * `workSpace` size must be table of >= HIST_WKSP_SIZE_U32 unsigned */
+size_t HIST_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
+ const void* source, size_t sourceSize,
+ void* workSpace, size_t workSpaceSize)
+{
+ if ((size_t)workSpace & 3) return ERROR(GENERIC); /* must be aligned on 4-bytes boundaries */
+ if (workSpaceSize < HIST_WKSP_SIZE) return ERROR(workSpace_tooSmall);
+ if (*maxSymbolValuePtr < 255)
+ return HIST_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, checkMaxSymbolValue, (U32*)workSpace);
+ *maxSymbolValuePtr = 255;
+ return HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, workSpace, workSpaceSize);
+}
+
+size_t HIST_count(unsigned* count, unsigned* maxSymbolValuePtr,
+ const void* src, size_t srcSize)
+{
+ unsigned tmpCounters[HIST_WKSP_SIZE_U32];
+ return HIST_count_wksp(count, maxSymbolValuePtr, src, srcSize, tmpCounters, sizeof(tmpCounters));
+}
diff --git a/sys/contrib/openzfs/module/zstd/lib/compress/hist.h b/sys/contrib/openzfs/module/zstd/lib/compress/hist.h
new file mode 100644
index 000000000000..77e3ec4fb192
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/compress/hist.h
@@ -0,0 +1,75 @@
+/* ******************************************************************
+ * hist : Histogram functions
+ * part of Finite State Entropy project
+ * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ *
+ * You can contact the author at :
+ * - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
+ * - Public forum : https://groups.google.com/forum/#!forum/lz4c
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+****************************************************************** */
+
+/* --- dependencies --- */
+#include <stddef.h> /* size_t */
+
+
+/* --- simple histogram functions --- */
+
+/*! HIST_count():
+ * Provides the precise count of each byte within a table 'count'.
+ * 'count' is a table of unsigned int, of minimum size (*maxSymbolValuePtr+1).
+ * Updates *maxSymbolValuePtr with actual largest symbol value detected.
+ * @return : count of the most frequent symbol (which isn't identified).
+ * or an error code, which can be tested using HIST_isError().
+ * note : if return == srcSize, there is only one symbol.
+ */
+size_t HIST_count(unsigned* count, unsigned* maxSymbolValuePtr,
+ const void* src, size_t srcSize);
+
+unsigned HIST_isError(size_t code); /**< tells if a return value is an error code */
+
+
+/* --- advanced histogram functions --- */
+
+#define HIST_WKSP_SIZE_U32 1024
+#define HIST_WKSP_SIZE (HIST_WKSP_SIZE_U32 * sizeof(unsigned))
+/** HIST_count_wksp() :
+ * Same as HIST_count(), but using an externally provided scratch buffer.
+ * Benefit is this function will use very little stack space.
+ * `workSpace` is a writable buffer which must be 4-bytes aligned,
+ * `workSpaceSize` must be >= HIST_WKSP_SIZE
+ */
+size_t HIST_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
+ const void* src, size_t srcSize,
+ void* workSpace, size_t workSpaceSize);
+
+/** HIST_countFast() :
+ * same as HIST_count(), but blindly trusts that all byte values within src are <= *maxSymbolValuePtr.
+ * This function is unsafe, and will segfault if any value within `src` is `> *maxSymbolValuePtr`
+ */
+size_t HIST_countFast(unsigned* count, unsigned* maxSymbolValuePtr,
+ const void* src, size_t srcSize);
+
+/** HIST_countFast_wksp() :
+ * Same as HIST_countFast(), but using an externally provided scratch buffer.
+ * `workSpace` is a writable buffer which must be 4-bytes aligned,
+ * `workSpaceSize` must be >= HIST_WKSP_SIZE
+ */
+size_t HIST_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
+ const void* src, size_t srcSize,
+ void* workSpace, size_t workSpaceSize);
+
+/*! HIST_count_simple() :
+ * Same as HIST_countFast(), this function is unsafe,
+ * and will segfault if any value within `src` is `> *maxSymbolValuePtr`.
+ * It is also a bit slower for large inputs.
+ * However, it does not need any additional memory (not even on stack).
+ * @return : count of the most frequent symbol.
+ * Note this function doesn't produce any error (i.e. it must succeed).
+ */
+unsigned HIST_count_simple(unsigned* count, unsigned* maxSymbolValuePtr,
+ const void* src, size_t srcSize);
diff --git a/sys/contrib/openzfs/module/zstd/lib/compress/huf_compress.c b/sys/contrib/openzfs/module/zstd/lib/compress/huf_compress.c
new file mode 100644
index 000000000000..546879868a53
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/compress/huf_compress.c
@@ -0,0 +1,798 @@
+/* ******************************************************************
+ * Huffman encoder, part of New Generation Entropy library
+ * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ *
+ * You can contact the author at :
+ * - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
+ * - Public forum : https://groups.google.com/forum/#!forum/lz4c
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+****************************************************************** */
+
+/* **************************************************************
+* Compiler specifics
+****************************************************************/
+#ifdef _MSC_VER /* Visual Studio */
+# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
+#endif
+
+
+/* **************************************************************
+* Includes
+****************************************************************/
+#include <string.h> /* memcpy, memset */
+#include <stdio.h> /* printf (debug) */
+#include "../common/compiler.h"
+#include "../common/bitstream.h"
+#include "hist.h"
+#define FSE_STATIC_LINKING_ONLY /* FSE_optimalTableLog_internal */
+#include "../common/fse.h" /* header compression */
+#define HUF_STATIC_LINKING_ONLY
+#include "../common/huf.h"
+#include "../common/error_private.h"
+
+
+/* **************************************************************
+* Error Management
+****************************************************************/
+#define HUF_isError ERR_isError
+#define HUF_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) /* use only *after* variable declarations */
+
+
+/* **************************************************************
+* Utils
+****************************************************************/
+unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue)
+{
+ return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 1);
+}
+
+
+/* *******************************************************
+* HUF : Huffman block compression
+*********************************************************/
+/* HUF_compressWeights() :
+ * Same as FSE_compress(), but dedicated to huff0's weights compression.
+ * The use case needs much less stack memory.
+ * Note : all elements within weightTable are supposed to be <= HUF_TABLELOG_MAX.
+ */
+#define MAX_FSE_TABLELOG_FOR_HUFF_HEADER 6
+static size_t HUF_compressWeights (void* dst, size_t dstSize, const void* weightTable, size_t wtSize)
+{
+ BYTE* const ostart = (BYTE*) dst;
+ BYTE* op = ostart;
+ BYTE* const oend = ostart + dstSize;
+
+ unsigned maxSymbolValue = HUF_TABLELOG_MAX;
+ U32 tableLog = MAX_FSE_TABLELOG_FOR_HUFF_HEADER;
+
+ FSE_CTable CTable[FSE_CTABLE_SIZE_U32(MAX_FSE_TABLELOG_FOR_HUFF_HEADER, HUF_TABLELOG_MAX)];
+ BYTE scratchBuffer[1<<MAX_FSE_TABLELOG_FOR_HUFF_HEADER];
+
+ unsigned count[HUF_TABLELOG_MAX+1];
+ S16 norm[HUF_TABLELOG_MAX+1];
+
+ /* init conditions */
+ if (wtSize <= 1) return 0; /* Not compressible */
+
+ /* Scan input and build symbol stats */
+ { unsigned const maxCount = HIST_count_simple(count, &maxSymbolValue, weightTable, wtSize); /* never fails */
+ if (maxCount == wtSize) return 1; /* only a single symbol in src : rle */
+ if (maxCount == 1) return 0; /* each symbol present maximum once => not compressible */
+ }
+
+ tableLog = FSE_optimalTableLog(tableLog, wtSize, maxSymbolValue);
+ CHECK_F( FSE_normalizeCount(norm, tableLog, count, wtSize, maxSymbolValue) );
+
+ /* Write table description header */
+ { CHECK_V_F(hSize, FSE_writeNCount(op, (size_t)(oend-op), norm, maxSymbolValue, tableLog) );
+ op += hSize;
+ }
+
+ /* Compress */
+ CHECK_F( FSE_buildCTable_wksp(CTable, norm, maxSymbolValue, tableLog, scratchBuffer, sizeof(scratchBuffer)) );
+ { CHECK_V_F(cSize, FSE_compress_usingCTable(op, (size_t)(oend - op), weightTable, wtSize, CTable) );
+ if (cSize == 0) return 0; /* not enough space for compressed data */
+ op += cSize;
+ }
+
+ return (size_t)(op-ostart);
+}
+
+
+struct HUF_CElt_s {
+ U16 val;
+ BYTE nbBits;
+}; /* typedef'd to HUF_CElt within "huf.h" */
+
+/*! HUF_writeCTable() :
+ `CTable` : Huffman tree to save, using huf representation.
+ @return : size of saved CTable */
+size_t HUF_writeCTable (void* dst, size_t maxDstSize,
+ const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog)
+{
+ BYTE bitsToWeight[HUF_TABLELOG_MAX + 1]; /* precomputed conversion table */
+ BYTE huffWeight[HUF_SYMBOLVALUE_MAX];
+ BYTE* op = (BYTE*)dst;
+ U32 n;
+
+ /* check conditions */
+ if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(maxSymbolValue_tooLarge);
+
+ /* convert to weight */
+ bitsToWeight[0] = 0;
+ for (n=1; n<huffLog+1; n++)
+ bitsToWeight[n] = (BYTE)(huffLog + 1 - n);
+ for (n=0; n<maxSymbolValue; n++)
+ huffWeight[n] = bitsToWeight[CTable[n].nbBits];
+
+ /* attempt weights compression by FSE */
+ { CHECK_V_F(hSize, HUF_compressWeights(op+1, maxDstSize-1, huffWeight, maxSymbolValue) );
+ if ((hSize>1) & (hSize < maxSymbolValue/2)) { /* FSE compressed */
+ op[0] = (BYTE)hSize;
+ return hSize+1;
+ } }
+
+ /* write raw values as 4-bits (max : 15) */
+ if (maxSymbolValue > (256-128)) return ERROR(GENERIC); /* should not happen : likely means source cannot be compressed */
+ if (((maxSymbolValue+1)/2) + 1 > maxDstSize) return ERROR(dstSize_tooSmall); /* not enough space within dst buffer */
+ op[0] = (BYTE)(128 /*special case*/ + (maxSymbolValue-1));
+ huffWeight[maxSymbolValue] = 0; /* to be sure it doesn't cause msan issue in final combination */
+ for (n=0; n<maxSymbolValue; n+=2)
+ op[(n/2)+1] = (BYTE)((huffWeight[n] << 4) + huffWeight[n+1]);
+ return ((maxSymbolValue+1)/2) + 1;
+}
+
+
+size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned* hasZeroWeights)
+{
+ BYTE huffWeight[HUF_SYMBOLVALUE_MAX + 1]; /* init not required, even though some static analyzer may complain */
+ U32 rankVal[HUF_TABLELOG_ABSOLUTEMAX + 1]; /* large enough for values from 0 to 16 */
+ U32 tableLog = 0;
+ U32 nbSymbols = 0;
+
+ /* get symbol weights */
+ CHECK_V_F(readSize, HUF_readStats(huffWeight, HUF_SYMBOLVALUE_MAX+1, rankVal, &nbSymbols, &tableLog, src, srcSize));
+
+ /* check result */
+ if (tableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge);
+ if (nbSymbols > *maxSymbolValuePtr+1) return ERROR(maxSymbolValue_tooSmall);
+
+ /* Prepare base value per rank */
+ { U32 n, nextRankStart = 0;
+ for (n=1; n<=tableLog; n++) {
+ U32 current = nextRankStart;
+ nextRankStart += (rankVal[n] << (n-1));
+ rankVal[n] = current;
+ } }
+
+ /* fill nbBits */
+ *hasZeroWeights = 0;
+ { U32 n; for (n=0; n<nbSymbols; n++) {
+ const U32 w = huffWeight[n];
+ *hasZeroWeights |= (w == 0);
+ CTable[n].nbBits = (BYTE)(tableLog + 1 - w) & -(w != 0);
+ } }
+
+ /* fill val */
+ { U16 nbPerRank[HUF_TABLELOG_MAX+2] = {0}; /* support w=0=>n=tableLog+1 */
+ U16 valPerRank[HUF_TABLELOG_MAX+2] = {0};
+ { U32 n; for (n=0; n<nbSymbols; n++) nbPerRank[CTable[n].nbBits]++; }
+ /* determine stating value per rank */
+ valPerRank[tableLog+1] = 0; /* for w==0 */
+ { U16 min = 0;
+ U32 n; for (n=tableLog; n>0; n--) { /* start at n=tablelog <-> w=1 */
+ valPerRank[n] = min; /* get starting value within each rank */
+ min += nbPerRank[n];
+ min >>= 1;
+ } }
+ /* assign value within rank, symbol order */
+ { U32 n; for (n=0; n<nbSymbols; n++) CTable[n].val = valPerRank[CTable[n].nbBits]++; }
+ }
+
+ *maxSymbolValuePtr = nbSymbols - 1;
+ return readSize;
+}
+
+U32 HUF_getNbBits(const void* symbolTable, U32 symbolValue)
+{
+ const HUF_CElt* table = (const HUF_CElt*)symbolTable;
+ assert(symbolValue <= HUF_SYMBOLVALUE_MAX);
+ return table[symbolValue].nbBits;
+}
+
+
+typedef struct nodeElt_s {
+ U32 count;
+ U16 parent;
+ BYTE byte;
+ BYTE nbBits;
+} nodeElt;
+
+static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits)
+{
+ const U32 largestBits = huffNode[lastNonNull].nbBits;
+ if (largestBits <= maxNbBits) return largestBits; /* early exit : no elt > maxNbBits */
+
+ /* there are several too large elements (at least >= 2) */
+ { int totalCost = 0;
+ const U32 baseCost = 1 << (largestBits - maxNbBits);
+ int n = (int)lastNonNull;
+
+ while (huffNode[n].nbBits > maxNbBits) {
+ totalCost += baseCost - (1 << (largestBits - huffNode[n].nbBits));
+ huffNode[n].nbBits = (BYTE)maxNbBits;
+ n --;
+ } /* n stops at huffNode[n].nbBits <= maxNbBits */
+ while (huffNode[n].nbBits == maxNbBits) n--; /* n end at index of smallest symbol using < maxNbBits */
+
+ /* renorm totalCost */
+ totalCost >>= (largestBits - maxNbBits); /* note : totalCost is necessarily a multiple of baseCost */
+
+ /* repay normalized cost */
+ { U32 const noSymbol = 0xF0F0F0F0;
+ U32 rankLast[HUF_TABLELOG_MAX+2];
+
+ /* Get pos of last (smallest) symbol per rank */
+ memset(rankLast, 0xF0, sizeof(rankLast));
+ { U32 currentNbBits = maxNbBits;
+ int pos;
+ for (pos=n ; pos >= 0; pos--) {
+ if (huffNode[pos].nbBits >= currentNbBits) continue;
+ currentNbBits = huffNode[pos].nbBits; /* < maxNbBits */
+ rankLast[maxNbBits-currentNbBits] = (U32)pos;
+ } }
+
+ while (totalCost > 0) {
+ U32 nBitsToDecrease = BIT_highbit32((U32)totalCost) + 1;
+ for ( ; nBitsToDecrease > 1; nBitsToDecrease--) {
+ U32 const highPos = rankLast[nBitsToDecrease];
+ U32 const lowPos = rankLast[nBitsToDecrease-1];
+ if (highPos == noSymbol) continue;
+ if (lowPos == noSymbol) break;
+ { U32 const highTotal = huffNode[highPos].count;
+ U32 const lowTotal = 2 * huffNode[lowPos].count;
+ if (highTotal <= lowTotal) break;
+ } }
+ /* only triggered when no more rank 1 symbol left => find closest one (note : there is necessarily at least one !) */
+ /* HUF_MAX_TABLELOG test just to please gcc 5+; but it should not be necessary */
+ while ((nBitsToDecrease<=HUF_TABLELOG_MAX) && (rankLast[nBitsToDecrease] == noSymbol))
+ nBitsToDecrease ++;
+ totalCost -= 1 << (nBitsToDecrease-1);
+ if (rankLast[nBitsToDecrease-1] == noSymbol)
+ rankLast[nBitsToDecrease-1] = rankLast[nBitsToDecrease]; /* this rank is no longer empty */
+ huffNode[rankLast[nBitsToDecrease]].nbBits ++;
+ if (rankLast[nBitsToDecrease] == 0) /* special case, reached largest symbol */
+ rankLast[nBitsToDecrease] = noSymbol;
+ else {
+ rankLast[nBitsToDecrease]--;
+ if (huffNode[rankLast[nBitsToDecrease]].nbBits != maxNbBits-nBitsToDecrease)
+ rankLast[nBitsToDecrease] = noSymbol; /* this rank is now empty */
+ } } /* while (totalCost > 0) */
+
+ while (totalCost < 0) { /* Sometimes, cost correction overshoot */
+ if (rankLast[1] == noSymbol) { /* special case : no rank 1 symbol (using maxNbBits-1); let's create one from largest rank 0 (using maxNbBits) */
+ while (huffNode[n].nbBits == maxNbBits) n--;
+ huffNode[n+1].nbBits--;
+ assert(n >= 0);
+ rankLast[1] = (U32)(n+1);
+ totalCost++;
+ continue;
+ }
+ huffNode[ rankLast[1] + 1 ].nbBits--;
+ rankLast[1]++;
+ totalCost ++;
+ } } } /* there are several too large elements (at least >= 2) */
+
+ return maxNbBits;
+}
+
+typedef struct {
+ U32 base;
+ U32 current;
+} rankPos;
+
+typedef nodeElt huffNodeTable[HUF_CTABLE_WORKSPACE_SIZE_U32];
+
+#define RANK_POSITION_TABLE_SIZE 32
+
+typedef struct {
+ huffNodeTable huffNodeTbl;
+ rankPos rankPosition[RANK_POSITION_TABLE_SIZE];
+} HUF_buildCTable_wksp_tables;
+
+static void HUF_sort(nodeElt* huffNode, const unsigned* count, U32 maxSymbolValue, rankPos* rankPosition)
+{
+ U32 n;
+
+ memset(rankPosition, 0, sizeof(*rankPosition) * RANK_POSITION_TABLE_SIZE);
+ for (n=0; n<=maxSymbolValue; n++) {
+ U32 r = BIT_highbit32(count[n] + 1);
+ rankPosition[r].base ++;
+ }
+ for (n=30; n>0; n--) rankPosition[n-1].base += rankPosition[n].base;
+ for (n=0; n<32; n++) rankPosition[n].current = rankPosition[n].base;
+ for (n=0; n<=maxSymbolValue; n++) {
+ U32 const c = count[n];
+ U32 const r = BIT_highbit32(c+1) + 1;
+ U32 pos = rankPosition[r].current++;
+ while ((pos > rankPosition[r].base) && (c > huffNode[pos-1].count)) {
+ huffNode[pos] = huffNode[pos-1];
+ pos--;
+ }
+ huffNode[pos].count = c;
+ huffNode[pos].byte = (BYTE)n;
+ }
+}
+
+
+/** HUF_buildCTable_wksp() :
+ * Same as HUF_buildCTable(), but using externally allocated scratch buffer.
+ * `workSpace` must be aligned on 4-bytes boundaries, and be at least as large as sizeof(HUF_buildCTable_wksp_tables).
+ */
+#define STARTNODE (HUF_SYMBOLVALUE_MAX+1)
+
+size_t HUF_buildCTable_wksp (HUF_CElt* tree, const unsigned* count, U32 maxSymbolValue, U32 maxNbBits, void* workSpace, size_t wkspSize)
+{
+ HUF_buildCTable_wksp_tables* const wksp_tables = (HUF_buildCTable_wksp_tables*)workSpace;
+ nodeElt* const huffNode0 = wksp_tables->huffNodeTbl;
+ nodeElt* const huffNode = huffNode0+1;
+ int nonNullRank;
+ int lowS, lowN;
+ int nodeNb = STARTNODE;
+ int n, nodeRoot;
+
+ /* safety checks */
+ if (((size_t)workSpace & 3) != 0) return ERROR(GENERIC); /* must be aligned on 4-bytes boundaries */
+ if (wkspSize < sizeof(HUF_buildCTable_wksp_tables))
+ return ERROR(workSpace_tooSmall);
+ if (maxNbBits == 0) maxNbBits = HUF_TABLELOG_DEFAULT;
+ if (maxSymbolValue > HUF_SYMBOLVALUE_MAX)
+ return ERROR(maxSymbolValue_tooLarge);
+ memset(huffNode0, 0, sizeof(huffNodeTable));
+
+ /* sort, decreasing order */
+ HUF_sort(huffNode, count, maxSymbolValue, wksp_tables->rankPosition);
+
+ /* init for parents */
+ nonNullRank = (int)maxSymbolValue;
+ while(huffNode[nonNullRank].count == 0) nonNullRank--;
+ lowS = nonNullRank; nodeRoot = nodeNb + lowS - 1; lowN = nodeNb;
+ huffNode[nodeNb].count = huffNode[lowS].count + huffNode[lowS-1].count;
+ huffNode[lowS].parent = huffNode[lowS-1].parent = (U16)nodeNb;
+ nodeNb++; lowS-=2;
+ for (n=nodeNb; n<=nodeRoot; n++) huffNode[n].count = (U32)(1U<<30);
+ huffNode0[0].count = (U32)(1U<<31); /* fake entry, strong barrier */
+
+ /* create parents */
+ while (nodeNb <= nodeRoot) {
+ int const n1 = (huffNode[lowS].count < huffNode[lowN].count) ? lowS-- : lowN++;
+ int const n2 = (huffNode[lowS].count < huffNode[lowN].count) ? lowS-- : lowN++;
+ huffNode[nodeNb].count = huffNode[n1].count + huffNode[n2].count;
+ huffNode[n1].parent = huffNode[n2].parent = (U16)nodeNb;
+ nodeNb++;
+ }
+
+ /* distribute weights (unlimited tree height) */
+ huffNode[nodeRoot].nbBits = 0;
+ for (n=nodeRoot-1; n>=STARTNODE; n--)
+ huffNode[n].nbBits = huffNode[ huffNode[n].parent ].nbBits + 1;
+ for (n=0; n<=nonNullRank; n++)
+ huffNode[n].nbBits = huffNode[ huffNode[n].parent ].nbBits + 1;
+
+ /* enforce maxTableLog */
+ maxNbBits = HUF_setMaxHeight(huffNode, (U32)nonNullRank, maxNbBits);
+
+ /* fill result into tree (val, nbBits) */
+ { U16 nbPerRank[HUF_TABLELOG_MAX+1] = {0};
+ U16 valPerRank[HUF_TABLELOG_MAX+1] = {0};
+ int const alphabetSize = (int)(maxSymbolValue + 1);
+ if (maxNbBits > HUF_TABLELOG_MAX) return ERROR(GENERIC); /* check fit into table */
+ for (n=0; n<=nonNullRank; n++)
+ nbPerRank[huffNode[n].nbBits]++;
+ /* determine stating value per rank */
+ { U16 min = 0;
+ for (n=(int)maxNbBits; n>0; n--) {
+ valPerRank[n] = min; /* get starting value within each rank */
+ min += nbPerRank[n];
+ min >>= 1;
+ } }
+ for (n=0; n<alphabetSize; n++)
+ tree[huffNode[n].byte].nbBits = huffNode[n].nbBits; /* push nbBits per symbol, symbol order */
+ for (n=0; n<alphabetSize; n++)
+ tree[n].val = valPerRank[tree[n].nbBits]++; /* assign value within rank, symbol order */
+ }
+
+ return maxNbBits;
+}
+
+/** HUF_buildCTable() :
+ * @return : maxNbBits
+ * Note : count is used before tree is written, so they can safely overlap
+ */
+size_t HUF_buildCTable (HUF_CElt* tree, const unsigned* count, unsigned maxSymbolValue, unsigned maxNbBits)
+{
+ HUF_buildCTable_wksp_tables workspace;
+ return HUF_buildCTable_wksp(tree, count, maxSymbolValue, maxNbBits, &workspace, sizeof(workspace));
+}
+
+size_t HUF_estimateCompressedSize(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue)
+{
+ size_t nbBits = 0;
+ int s;
+ for (s = 0; s <= (int)maxSymbolValue; ++s) {
+ nbBits += CTable[s].nbBits * count[s];
+ }
+ return nbBits >> 3;
+}
+
+int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue) {
+ int bad = 0;
+ int s;
+ for (s = 0; s <= (int)maxSymbolValue; ++s) {
+ bad |= (count[s] != 0) & (CTable[s].nbBits == 0);
+ }
+ return !bad;
+}
+
+size_t HUF_compressBound(size_t size) { return HUF_COMPRESSBOUND(size); }
+
+FORCE_INLINE_TEMPLATE void
+HUF_encodeSymbol(BIT_CStream_t* bitCPtr, U32 symbol, const HUF_CElt* CTable)
+{
+ BIT_addBitsFast(bitCPtr, CTable[symbol].val, CTable[symbol].nbBits);
+}
+
+#define HUF_FLUSHBITS(s) BIT_flushBits(s)
+
+#define HUF_FLUSHBITS_1(stream) \
+ if (sizeof((stream)->bitContainer)*8 < HUF_TABLELOG_MAX*2+7) HUF_FLUSHBITS(stream)
+
+#define HUF_FLUSHBITS_2(stream) \
+ if (sizeof((stream)->bitContainer)*8 < HUF_TABLELOG_MAX*4+7) HUF_FLUSHBITS(stream)
+
+FORCE_INLINE_TEMPLATE size_t
+HUF_compress1X_usingCTable_internal_body(void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ const HUF_CElt* CTable)
+{
+ const BYTE* ip = (const BYTE*) src;
+ BYTE* const ostart = (BYTE*)dst;
+ BYTE* const oend = ostart + dstSize;
+ BYTE* op = ostart;
+ size_t n;
+ BIT_CStream_t bitC;
+
+ /* init */
+ if (dstSize < 8) return 0; /* not enough space to compress */
+ { size_t const initErr = BIT_initCStream(&bitC, op, (size_t)(oend-op));
+ if (HUF_isError(initErr)) return 0; }
+
+ n = srcSize & ~3; /* join to mod 4 */
+ switch (srcSize & 3)
+ {
+ case 3 : HUF_encodeSymbol(&bitC, ip[n+ 2], CTable);
+ HUF_FLUSHBITS_2(&bitC);
+ /* fall-through */
+ case 2 : HUF_encodeSymbol(&bitC, ip[n+ 1], CTable);
+ HUF_FLUSHBITS_1(&bitC);
+ /* fall-through */
+ case 1 : HUF_encodeSymbol(&bitC, ip[n+ 0], CTable);
+ HUF_FLUSHBITS(&bitC);
+ /* fall-through */
+ case 0 : /* fall-through */
+ default: break;
+ }
+
+ for (; n>0; n-=4) { /* note : n&3==0 at this stage */
+ HUF_encodeSymbol(&bitC, ip[n- 1], CTable);
+ HUF_FLUSHBITS_1(&bitC);
+ HUF_encodeSymbol(&bitC, ip[n- 2], CTable);
+ HUF_FLUSHBITS_2(&bitC);
+ HUF_encodeSymbol(&bitC, ip[n- 3], CTable);
+ HUF_FLUSHBITS_1(&bitC);
+ HUF_encodeSymbol(&bitC, ip[n- 4], CTable);
+ HUF_FLUSHBITS(&bitC);
+ }
+
+ return BIT_closeCStream(&bitC);
+}
+
+#if DYNAMIC_BMI2
+
+static TARGET_ATTRIBUTE("bmi2") size_t
+HUF_compress1X_usingCTable_internal_bmi2(void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ const HUF_CElt* CTable)
+{
+ return HUF_compress1X_usingCTable_internal_body(dst, dstSize, src, srcSize, CTable);
+}
+
+static size_t
+HUF_compress1X_usingCTable_internal_default(void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ const HUF_CElt* CTable)
+{
+ return HUF_compress1X_usingCTable_internal_body(dst, dstSize, src, srcSize, CTable);
+}
+
+static size_t
+HUF_compress1X_usingCTable_internal(void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ const HUF_CElt* CTable, const int bmi2)
+{
+ if (bmi2) {
+ return HUF_compress1X_usingCTable_internal_bmi2(dst, dstSize, src, srcSize, CTable);
+ }
+ return HUF_compress1X_usingCTable_internal_default(dst, dstSize, src, srcSize, CTable);
+}
+
+#else
+
+static size_t
+HUF_compress1X_usingCTable_internal(void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ const HUF_CElt* CTable, const int bmi2)
+{
+ (void)bmi2;
+ return HUF_compress1X_usingCTable_internal_body(dst, dstSize, src, srcSize, CTable);
+}
+
+#endif
+
+size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable)
+{
+ return HUF_compress1X_usingCTable_internal(dst, dstSize, src, srcSize, CTable, /* bmi2 */ 0);
+}
+
+
+static size_t
+HUF_compress4X_usingCTable_internal(void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ const HUF_CElt* CTable, int bmi2)
+{
+ size_t const segmentSize = (srcSize+3)/4; /* first 3 segments */
+ const BYTE* ip = (const BYTE*) src;
+ const BYTE* const iend = ip + srcSize;
+ BYTE* const ostart = (BYTE*) dst;
+ BYTE* const oend = ostart + dstSize;
+ BYTE* op = ostart;
+
+ if (dstSize < 6 + 1 + 1 + 1 + 8) return 0; /* minimum space to compress successfully */
+ if (srcSize < 12) return 0; /* no saving possible : too small input */
+ op += 6; /* jumpTable */
+
+ assert(op <= oend);
+ { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, segmentSize, CTable, bmi2) );
+ if (cSize==0) return 0;
+ assert(cSize <= 65535);
+ MEM_writeLE16(ostart, (U16)cSize);
+ op += cSize;
+ }
+
+ ip += segmentSize;
+ assert(op <= oend);
+ { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, segmentSize, CTable, bmi2) );
+ if (cSize==0) return 0;
+ assert(cSize <= 65535);
+ MEM_writeLE16(ostart+2, (U16)cSize);
+ op += cSize;
+ }
+
+ ip += segmentSize;
+ assert(op <= oend);
+ { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, segmentSize, CTable, bmi2) );
+ if (cSize==0) return 0;
+ assert(cSize <= 65535);
+ MEM_writeLE16(ostart+4, (U16)cSize);
+ op += cSize;
+ }
+
+ ip += segmentSize;
+ assert(op <= oend);
+ assert(ip <= iend);
+ { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, (size_t)(iend-ip), CTable, bmi2) );
+ if (cSize==0) return 0;
+ op += cSize;
+ }
+
+ return (size_t)(op-ostart);
+}
+
+size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable)
+{
+ return HUF_compress4X_usingCTable_internal(dst, dstSize, src, srcSize, CTable, /* bmi2 */ 0);
+}
+
+typedef enum { HUF_singleStream, HUF_fourStreams } HUF_nbStreams_e;
+
+static size_t HUF_compressCTable_internal(
+ BYTE* const ostart, BYTE* op, BYTE* const oend,
+ const void* src, size_t srcSize,
+ HUF_nbStreams_e nbStreams, const HUF_CElt* CTable, const int bmi2)
+{
+ size_t const cSize = (nbStreams==HUF_singleStream) ?
+ HUF_compress1X_usingCTable_internal(op, (size_t)(oend - op), src, srcSize, CTable, bmi2) :
+ HUF_compress4X_usingCTable_internal(op, (size_t)(oend - op), src, srcSize, CTable, bmi2);
+ if (HUF_isError(cSize)) { return cSize; }
+ if (cSize==0) { return 0; } /* uncompressible */
+ op += cSize;
+ /* check compressibility */
+ assert(op >= ostart);
+ if ((size_t)(op-ostart) >= srcSize-1) { return 0; }
+ return (size_t)(op-ostart);
+}
+
+typedef struct {
+ unsigned count[HUF_SYMBOLVALUE_MAX + 1];
+ HUF_CElt CTable[HUF_SYMBOLVALUE_MAX + 1];
+ HUF_buildCTable_wksp_tables buildCTable_wksp;
+} HUF_compress_tables_t;
+
+/* HUF_compress_internal() :
+ * `workSpace` must a table of at least HUF_WORKSPACE_SIZE_U32 unsigned */
+static size_t
+HUF_compress_internal (void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ unsigned maxSymbolValue, unsigned huffLog,
+ HUF_nbStreams_e nbStreams,
+ void* workSpace, size_t wkspSize,
+ HUF_CElt* oldHufTable, HUF_repeat* repeat, int preferRepeat,
+ const int bmi2)
+{
+ HUF_compress_tables_t* const table = (HUF_compress_tables_t*)workSpace;
+ BYTE* const ostart = (BYTE*)dst;
+ BYTE* const oend = ostart + dstSize;
+ BYTE* op = ostart;
+
+ HUF_STATIC_ASSERT(sizeof(*table) <= HUF_WORKSPACE_SIZE);
+
+ /* checks & inits */
+ if (((size_t)workSpace & 3) != 0) return ERROR(GENERIC); /* must be aligned on 4-bytes boundaries */
+ if (wkspSize < HUF_WORKSPACE_SIZE) return ERROR(workSpace_tooSmall);
+ if (!srcSize) return 0; /* Uncompressed */
+ if (!dstSize) return 0; /* cannot fit anything within dst budget */
+ if (srcSize > HUF_BLOCKSIZE_MAX) return ERROR(srcSize_wrong); /* current block size limit */
+ if (huffLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge);
+ if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(maxSymbolValue_tooLarge);
+ if (!maxSymbolValue) maxSymbolValue = HUF_SYMBOLVALUE_MAX;
+ if (!huffLog) huffLog = HUF_TABLELOG_DEFAULT;
+
+ /* Heuristic : If old table is valid, use it for small inputs */
+ if (preferRepeat && repeat && *repeat == HUF_repeat_valid) {
+ return HUF_compressCTable_internal(ostart, op, oend,
+ src, srcSize,
+ nbStreams, oldHufTable, bmi2);
+ }
+
+ /* Scan input and build symbol stats */
+ { CHECK_V_F(largest, HIST_count_wksp (table->count, &maxSymbolValue, (const BYTE*)src, srcSize, workSpace, wkspSize) );
+ if (largest == srcSize) { *ostart = ((const BYTE*)src)[0]; return 1; } /* single symbol, rle */
+ if (largest <= (srcSize >> 7)+4) return 0; /* heuristic : probably not compressible enough */
+ }
+
+ /* Check validity of previous table */
+ if ( repeat
+ && *repeat == HUF_repeat_check
+ && !HUF_validateCTable(oldHufTable, table->count, maxSymbolValue)) {
+ *repeat = HUF_repeat_none;
+ }
+ /* Heuristic : use existing table for small inputs */
+ if (preferRepeat && repeat && *repeat != HUF_repeat_none) {
+ return HUF_compressCTable_internal(ostart, op, oend,
+ src, srcSize,
+ nbStreams, oldHufTable, bmi2);
+ }
+
+ /* Build Huffman Tree */
+ huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue);
+ { size_t const maxBits = HUF_buildCTable_wksp(table->CTable, table->count,
+ maxSymbolValue, huffLog,
+ &table->buildCTable_wksp, sizeof(table->buildCTable_wksp));
+ CHECK_F(maxBits);
+ huffLog = (U32)maxBits;
+ /* Zero unused symbols in CTable, so we can check it for validity */
+ memset(table->CTable + (maxSymbolValue + 1), 0,
+ sizeof(table->CTable) - ((maxSymbolValue + 1) * sizeof(HUF_CElt)));
+ }
+
+ /* Write table description header */
+ { CHECK_V_F(hSize, HUF_writeCTable (op, dstSize, table->CTable, maxSymbolValue, huffLog) );
+ /* Check if using previous huffman table is beneficial */
+ if (repeat && *repeat != HUF_repeat_none) {
+ size_t const oldSize = HUF_estimateCompressedSize(oldHufTable, table->count, maxSymbolValue);
+ size_t const newSize = HUF_estimateCompressedSize(table->CTable, table->count, maxSymbolValue);
+ if (oldSize <= hSize + newSize || hSize + 12 >= srcSize) {
+ return HUF_compressCTable_internal(ostart, op, oend,
+ src, srcSize,
+ nbStreams, oldHufTable, bmi2);
+ } }
+
+ /* Use the new huffman table */
+ if (hSize + 12ul >= srcSize) { return 0; }
+ op += hSize;
+ if (repeat) { *repeat = HUF_repeat_none; }
+ if (oldHufTable)
+ memcpy(oldHufTable, table->CTable, sizeof(table->CTable)); /* Save new table */
+ }
+ return HUF_compressCTable_internal(ostart, op, oend,
+ src, srcSize,
+ nbStreams, table->CTable, bmi2);
+}
+
+
+size_t HUF_compress1X_wksp (void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ unsigned maxSymbolValue, unsigned huffLog,
+ void* workSpace, size_t wkspSize)
+{
+ return HUF_compress_internal(dst, dstSize, src, srcSize,
+ maxSymbolValue, huffLog, HUF_singleStream,
+ workSpace, wkspSize,
+ NULL, NULL, 0, 0 /*bmi2*/);
+}
+
+size_t HUF_compress1X_repeat (void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ unsigned maxSymbolValue, unsigned huffLog,
+ void* workSpace, size_t wkspSize,
+ HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2)
+{
+ return HUF_compress_internal(dst, dstSize, src, srcSize,
+ maxSymbolValue, huffLog, HUF_singleStream,
+ workSpace, wkspSize, hufTable,
+ repeat, preferRepeat, bmi2);
+}
+
+size_t HUF_compress1X (void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ unsigned maxSymbolValue, unsigned huffLog)
+{
+ unsigned workSpace[HUF_WORKSPACE_SIZE_U32];
+ return HUF_compress1X_wksp(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, workSpace, sizeof(workSpace));
+}
+
+/* HUF_compress4X_repeat():
+ * compress input using 4 streams.
+ * provide workspace to generate compression tables */
+size_t HUF_compress4X_wksp (void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ unsigned maxSymbolValue, unsigned huffLog,
+ void* workSpace, size_t wkspSize)
+{
+ return HUF_compress_internal(dst, dstSize, src, srcSize,
+ maxSymbolValue, huffLog, HUF_fourStreams,
+ workSpace, wkspSize,
+ NULL, NULL, 0, 0 /*bmi2*/);
+}
+
+/* HUF_compress4X_repeat():
+ * compress input using 4 streams.
+ * re-use an existing huffman compression table */
+size_t HUF_compress4X_repeat (void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ unsigned maxSymbolValue, unsigned huffLog,
+ void* workSpace, size_t wkspSize,
+ HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2)
+{
+ return HUF_compress_internal(dst, dstSize, src, srcSize,
+ maxSymbolValue, huffLog, HUF_fourStreams,
+ workSpace, wkspSize,
+ hufTable, repeat, preferRepeat, bmi2);
+}
+
+size_t HUF_compress2 (void* dst, size_t dstSize,
+ const void* src, size_t srcSize,
+ unsigned maxSymbolValue, unsigned huffLog)
+{
+ unsigned workSpace[HUF_WORKSPACE_SIZE_U32];
+ return HUF_compress4X_wksp(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, workSpace, sizeof(workSpace));
+}
+
+size_t HUF_compress (void* dst, size_t maxDstSize, const void* src, size_t srcSize)
+{
+ return HUF_compress2(dst, maxDstSize, src, srcSize, 255, HUF_TABLELOG_DEFAULT);
+}
diff --git a/sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress.c b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress.c
new file mode 100644
index 000000000000..3f963b1cfff8
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress.c
@@ -0,0 +1,4278 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/*-*************************************
+* Dependencies
+***************************************/
+#include <limits.h> /* INT_MAX */
+#include <string.h> /* memset */
+#include "../common/cpu.h"
+#include "../common/mem.h"
+#include "hist.h" /* HIST_countFast_wksp */
+#define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */
+#include "../common/fse.h"
+#define HUF_STATIC_LINKING_ONLY
+#include "../common/huf.h"
+#include "zstd_compress_internal.h"
+#include "zstd_compress_sequences.h"
+#include "zstd_compress_literals.h"
+#include "zstd_fast.h"
+#include "zstd_double_fast.h"
+#include "zstd_lazy.h"
+#include "zstd_opt.h"
+#include "zstd_ldm.h"
+#include "zstd_compress_superblock.h"
+
+
+/*-*************************************
+* Helper functions
+***************************************/
+/* ZSTD_compressBound()
+ * Note that the result from this function is only compatible with the "normal"
+ * full-block strategy.
+ * When there are a lot of small blocks due to frequent flush in streaming mode
+ * the overhead of headers can make the compressed data to be larger than the
+ * return value of ZSTD_compressBound().
+ */
+size_t ZSTD_compressBound(size_t srcSize) {
+ return ZSTD_COMPRESSBOUND(srcSize);
+}
+
+
+/*-*************************************
+* Context memory management
+***************************************/
+struct ZSTD_CDict_s {
+ const void* dictContent;
+ size_t dictContentSize;
+ U32* entropyWorkspace; /* entropy workspace of HUF_WORKSPACE_SIZE bytes */
+ ZSTD_cwksp workspace;
+ ZSTD_matchState_t matchState;
+ ZSTD_compressedBlockState_t cBlockState;
+ ZSTD_customMem customMem;
+ U32 dictID;
+ int compressionLevel; /* 0 indicates that advanced API was used to select CDict params */
+}; /* typedef'd to ZSTD_CDict within "zstd.h" */
+
+ZSTD_CCtx* ZSTD_createCCtx(void)
+{
+ return ZSTD_createCCtx_advanced(ZSTD_defaultCMem);
+}
+
+static void ZSTD_initCCtx(ZSTD_CCtx* cctx, ZSTD_customMem memManager)
+{
+ assert(cctx != NULL);
+ memset(cctx, 0, sizeof(*cctx));
+ cctx->customMem = memManager;
+ cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
+ { size_t const err = ZSTD_CCtx_reset(cctx, ZSTD_reset_parameters);
+ assert(!ZSTD_isError(err));
+ (void)err;
+ }
+}
+
+ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
+{
+ ZSTD_STATIC_ASSERT(zcss_init==0);
+ ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1));
+ if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
+ { ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_malloc(sizeof(ZSTD_CCtx), customMem);
+ if (!cctx) return NULL;
+ ZSTD_initCCtx(cctx, customMem);
+ return cctx;
+ }
+}
+
+ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize)
+{
+ ZSTD_cwksp ws;
+ ZSTD_CCtx* cctx;
+ if (workspaceSize <= sizeof(ZSTD_CCtx)) return NULL; /* minimum size */
+ if ((size_t)workspace & 7) return NULL; /* must be 8-aligned */
+ ZSTD_cwksp_init(&ws, workspace, workspaceSize);
+
+ cctx = (ZSTD_CCtx*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CCtx));
+ if (cctx == NULL) return NULL;
+
+ memset(cctx, 0, sizeof(ZSTD_CCtx));
+ ZSTD_cwksp_move(&cctx->workspace, &ws);
+ cctx->staticSize = workspaceSize;
+
+ /* statically sized space. entropyWorkspace never moves (but prev/next block swap places) */
+ if (!ZSTD_cwksp_check_available(&cctx->workspace, HUF_WORKSPACE_SIZE + 2 * sizeof(ZSTD_compressedBlockState_t))) return NULL;
+ cctx->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)ZSTD_cwksp_reserve_object(&cctx->workspace, sizeof(ZSTD_compressedBlockState_t));
+ cctx->blockState.nextCBlock = (ZSTD_compressedBlockState_t*)ZSTD_cwksp_reserve_object(&cctx->workspace, sizeof(ZSTD_compressedBlockState_t));
+ cctx->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object(&cctx->workspace, HUF_WORKSPACE_SIZE);
+ cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
+ return cctx;
+}
+
+/**
+ * Clears and frees all of the dictionaries in the CCtx.
+ */
+static void ZSTD_clearAllDicts(ZSTD_CCtx* cctx)
+{
+ ZSTD_free(cctx->localDict.dictBuffer, cctx->customMem);
+ ZSTD_freeCDict(cctx->localDict.cdict);
+ memset(&cctx->localDict, 0, sizeof(cctx->localDict));
+ memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict));
+ cctx->cdict = NULL;
+}
+
+static size_t ZSTD_sizeof_localDict(ZSTD_localDict dict)
+{
+ size_t const bufferSize = dict.dictBuffer != NULL ? dict.dictSize : 0;
+ size_t const cdictSize = ZSTD_sizeof_CDict(dict.cdict);
+ return bufferSize + cdictSize;
+}
+
+static void ZSTD_freeCCtxContent(ZSTD_CCtx* cctx)
+{
+ assert(cctx != NULL);
+ assert(cctx->staticSize == 0);
+ ZSTD_clearAllDicts(cctx);
+#ifdef ZSTD_MULTITHREAD
+ ZSTDMT_freeCCtx(cctx->mtctx); cctx->mtctx = NULL;
+#endif
+ ZSTD_cwksp_free(&cctx->workspace, cctx->customMem);
+}
+
+size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
+{
+ if (cctx==NULL) return 0; /* support free on NULL */
+ RETURN_ERROR_IF(cctx->staticSize, memory_allocation,
+ "not compatible with static CCtx");
+ {
+ int cctxInWorkspace = ZSTD_cwksp_owns_buffer(&cctx->workspace, cctx);
+ ZSTD_freeCCtxContent(cctx);
+ if (!cctxInWorkspace) {
+ ZSTD_free(cctx, cctx->customMem);
+ }
+ }
+ return 0;
+}
+
+
+static size_t ZSTD_sizeof_mtctx(const ZSTD_CCtx* cctx)
+{
+#ifdef ZSTD_MULTITHREAD
+ return ZSTDMT_sizeof_CCtx(cctx->mtctx);
+#else
+ (void)cctx;
+ return 0;
+#endif
+}
+
+
+size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)
+{
+ if (cctx==NULL) return 0; /* support sizeof on NULL */
+ /* cctx may be in the workspace */
+ return (cctx->workspace.workspace == cctx ? 0 : sizeof(*cctx))
+ + ZSTD_cwksp_sizeof(&cctx->workspace)
+ + ZSTD_sizeof_localDict(cctx->localDict)
+ + ZSTD_sizeof_mtctx(cctx);
+}
+
+size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
+{
+ return ZSTD_sizeof_CCtx(zcs); /* same object */
+}
+
+/* private API call, for dictBuilder only */
+const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); }
+
+static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams(
+ ZSTD_compressionParameters cParams)
+{
+ ZSTD_CCtx_params cctxParams;
+ memset(&cctxParams, 0, sizeof(cctxParams));
+ cctxParams.cParams = cParams;
+ cctxParams.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */
+ assert(!ZSTD_checkCParams(cParams));
+ cctxParams.fParams.contentSizeFlag = 1;
+ return cctxParams;
+}
+
+static ZSTD_CCtx_params* ZSTD_createCCtxParams_advanced(
+ ZSTD_customMem customMem)
+{
+ ZSTD_CCtx_params* params;
+ if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
+ params = (ZSTD_CCtx_params*)ZSTD_calloc(
+ sizeof(ZSTD_CCtx_params), customMem);
+ if (!params) { return NULL; }
+ params->customMem = customMem;
+ params->compressionLevel = ZSTD_CLEVEL_DEFAULT;
+ params->fParams.contentSizeFlag = 1;
+ return params;
+}
+
+ZSTD_CCtx_params* ZSTD_createCCtxParams(void)
+{
+ return ZSTD_createCCtxParams_advanced(ZSTD_defaultCMem);
+}
+
+size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params)
+{
+ if (params == NULL) { return 0; }
+ ZSTD_free(params, params->customMem);
+ return 0;
+}
+
+size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params)
+{
+ return ZSTD_CCtxParams_init(params, ZSTD_CLEVEL_DEFAULT);
+}
+
+size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel) {
+ RETURN_ERROR_IF(!cctxParams, GENERIC, "NULL pointer!");
+ memset(cctxParams, 0, sizeof(*cctxParams));
+ cctxParams->compressionLevel = compressionLevel;
+ cctxParams->fParams.contentSizeFlag = 1;
+ return 0;
+}
+
+size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params)
+{
+ RETURN_ERROR_IF(!cctxParams, GENERIC, "NULL pointer!");
+ FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) , "");
+ memset(cctxParams, 0, sizeof(*cctxParams));
+ assert(!ZSTD_checkCParams(params.cParams));
+ cctxParams->cParams = params.cParams;
+ cctxParams->fParams = params.fParams;
+ cctxParams->compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */
+ return 0;
+}
+
+/* ZSTD_assignParamsToCCtxParams() :
+ * params is presumed valid at this stage */
+static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams(
+ const ZSTD_CCtx_params* cctxParams, const ZSTD_parameters* params)
+{
+ ZSTD_CCtx_params ret = *cctxParams;
+ assert(!ZSTD_checkCParams(params->cParams));
+ ret.cParams = params->cParams;
+ ret.fParams = params->fParams;
+ ret.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */
+ return ret;
+}
+
+ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param)
+{
+ ZSTD_bounds bounds = { 0, 0, 0 };
+
+ switch(param)
+ {
+ case ZSTD_c_compressionLevel:
+ bounds.lowerBound = ZSTD_minCLevel();
+ bounds.upperBound = ZSTD_maxCLevel();
+ return bounds;
+
+ case ZSTD_c_windowLog:
+ bounds.lowerBound = ZSTD_WINDOWLOG_MIN;
+ bounds.upperBound = ZSTD_WINDOWLOG_MAX;
+ return bounds;
+
+ case ZSTD_c_hashLog:
+ bounds.lowerBound = ZSTD_HASHLOG_MIN;
+ bounds.upperBound = ZSTD_HASHLOG_MAX;
+ return bounds;
+
+ case ZSTD_c_chainLog:
+ bounds.lowerBound = ZSTD_CHAINLOG_MIN;
+ bounds.upperBound = ZSTD_CHAINLOG_MAX;
+ return bounds;
+
+ case ZSTD_c_searchLog:
+ bounds.lowerBound = ZSTD_SEARCHLOG_MIN;
+ bounds.upperBound = ZSTD_SEARCHLOG_MAX;
+ return bounds;
+
+ case ZSTD_c_minMatch:
+ bounds.lowerBound = ZSTD_MINMATCH_MIN;
+ bounds.upperBound = ZSTD_MINMATCH_MAX;
+ return bounds;
+
+ case ZSTD_c_targetLength:
+ bounds.lowerBound = ZSTD_TARGETLENGTH_MIN;
+ bounds.upperBound = ZSTD_TARGETLENGTH_MAX;
+ return bounds;
+
+ case ZSTD_c_strategy:
+ bounds.lowerBound = ZSTD_STRATEGY_MIN;
+ bounds.upperBound = ZSTD_STRATEGY_MAX;
+ return bounds;
+
+ case ZSTD_c_contentSizeFlag:
+ bounds.lowerBound = 0;
+ bounds.upperBound = 1;
+ return bounds;
+
+ case ZSTD_c_checksumFlag:
+ bounds.lowerBound = 0;
+ bounds.upperBound = 1;
+ return bounds;
+
+ case ZSTD_c_dictIDFlag:
+ bounds.lowerBound = 0;
+ bounds.upperBound = 1;
+ return bounds;
+
+ case ZSTD_c_nbWorkers:
+ bounds.lowerBound = 0;
+#ifdef ZSTD_MULTITHREAD
+ bounds.upperBound = ZSTDMT_NBWORKERS_MAX;
+#else
+ bounds.upperBound = 0;
+#endif
+ return bounds;
+
+ case ZSTD_c_jobSize:
+ bounds.lowerBound = 0;
+#ifdef ZSTD_MULTITHREAD
+ bounds.upperBound = ZSTDMT_JOBSIZE_MAX;
+#else
+ bounds.upperBound = 0;
+#endif
+ return bounds;
+
+ case ZSTD_c_overlapLog:
+#ifdef ZSTD_MULTITHREAD
+ bounds.lowerBound = ZSTD_OVERLAPLOG_MIN;
+ bounds.upperBound = ZSTD_OVERLAPLOG_MAX;
+#else
+ bounds.lowerBound = 0;
+ bounds.upperBound = 0;
+#endif
+ return bounds;
+
+ case ZSTD_c_enableLongDistanceMatching:
+ bounds.lowerBound = 0;
+ bounds.upperBound = 1;
+ return bounds;
+
+ case ZSTD_c_ldmHashLog:
+ bounds.lowerBound = ZSTD_LDM_HASHLOG_MIN;
+ bounds.upperBound = ZSTD_LDM_HASHLOG_MAX;
+ return bounds;
+
+ case ZSTD_c_ldmMinMatch:
+ bounds.lowerBound = ZSTD_LDM_MINMATCH_MIN;
+ bounds.upperBound = ZSTD_LDM_MINMATCH_MAX;
+ return bounds;
+
+ case ZSTD_c_ldmBucketSizeLog:
+ bounds.lowerBound = ZSTD_LDM_BUCKETSIZELOG_MIN;
+ bounds.upperBound = ZSTD_LDM_BUCKETSIZELOG_MAX;
+ return bounds;
+
+ case ZSTD_c_ldmHashRateLog:
+ bounds.lowerBound = ZSTD_LDM_HASHRATELOG_MIN;
+ bounds.upperBound = ZSTD_LDM_HASHRATELOG_MAX;
+ return bounds;
+
+ /* experimental parameters */
+ case ZSTD_c_rsyncable:
+ bounds.lowerBound = 0;
+ bounds.upperBound = 1;
+ return bounds;
+
+ case ZSTD_c_forceMaxWindow :
+ bounds.lowerBound = 0;
+ bounds.upperBound = 1;
+ return bounds;
+
+ case ZSTD_c_format:
+ ZSTD_STATIC_ASSERT(ZSTD_f_zstd1 < ZSTD_f_zstd1_magicless);
+ bounds.lowerBound = ZSTD_f_zstd1;
+ bounds.upperBound = ZSTD_f_zstd1_magicless; /* note : how to ensure at compile time that this is the highest value enum ? */
+ return bounds;
+
+ case ZSTD_c_forceAttachDict:
+ ZSTD_STATIC_ASSERT(ZSTD_dictDefaultAttach < ZSTD_dictForceCopy);
+ bounds.lowerBound = ZSTD_dictDefaultAttach;
+ bounds.upperBound = ZSTD_dictForceLoad; /* note : how to ensure at compile time that this is the highest value enum ? */
+ return bounds;
+
+ case ZSTD_c_literalCompressionMode:
+ ZSTD_STATIC_ASSERT(ZSTD_lcm_auto < ZSTD_lcm_huffman && ZSTD_lcm_huffman < ZSTD_lcm_uncompressed);
+ bounds.lowerBound = ZSTD_lcm_auto;
+ bounds.upperBound = ZSTD_lcm_uncompressed;
+ return bounds;
+
+ case ZSTD_c_targetCBlockSize:
+ bounds.lowerBound = ZSTD_TARGETCBLOCKSIZE_MIN;
+ bounds.upperBound = ZSTD_TARGETCBLOCKSIZE_MAX;
+ return bounds;
+
+ case ZSTD_c_srcSizeHint:
+ bounds.lowerBound = ZSTD_SRCSIZEHINT_MIN;
+ bounds.upperBound = ZSTD_SRCSIZEHINT_MAX;
+ return bounds;
+
+ default:
+ bounds.error = ERROR(parameter_unsupported);
+ return bounds;
+ }
+}
+
+/* ZSTD_cParam_clampBounds:
+ * Clamps the value into the bounded range.
+ */
+static size_t ZSTD_cParam_clampBounds(ZSTD_cParameter cParam, int* value)
+{
+ ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam);
+ if (ZSTD_isError(bounds.error)) return bounds.error;
+ if (*value < bounds.lowerBound) *value = bounds.lowerBound;
+ if (*value > bounds.upperBound) *value = bounds.upperBound;
+ return 0;
+}
+
+#define BOUNDCHECK(cParam, val) { \
+ RETURN_ERROR_IF(!ZSTD_cParam_withinBounds(cParam,val), \
+ parameter_outOfBound, "Param out of bounds"); \
+}
+
+
+static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param)
+{
+ switch(param)
+ {
+ case ZSTD_c_compressionLevel:
+ case ZSTD_c_hashLog:
+ case ZSTD_c_chainLog:
+ case ZSTD_c_searchLog:
+ case ZSTD_c_minMatch:
+ case ZSTD_c_targetLength:
+ case ZSTD_c_strategy:
+ return 1;
+
+ case ZSTD_c_format:
+ case ZSTD_c_windowLog:
+ case ZSTD_c_contentSizeFlag:
+ case ZSTD_c_checksumFlag:
+ case ZSTD_c_dictIDFlag:
+ case ZSTD_c_forceMaxWindow :
+ case ZSTD_c_nbWorkers:
+ case ZSTD_c_jobSize:
+ case ZSTD_c_overlapLog:
+ case ZSTD_c_rsyncable:
+ case ZSTD_c_enableLongDistanceMatching:
+ case ZSTD_c_ldmHashLog:
+ case ZSTD_c_ldmMinMatch:
+ case ZSTD_c_ldmBucketSizeLog:
+ case ZSTD_c_ldmHashRateLog:
+ case ZSTD_c_forceAttachDict:
+ case ZSTD_c_literalCompressionMode:
+ case ZSTD_c_targetCBlockSize:
+ case ZSTD_c_srcSizeHint:
+ default:
+ return 0;
+ }
+}
+
+size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value)
+{
+ DEBUGLOG(4, "ZSTD_CCtx_setParameter (%i, %i)", (int)param, value);
+ if (cctx->streamStage != zcss_init) {
+ if (ZSTD_isUpdateAuthorized(param)) {
+ cctx->cParamsChanged = 1;
+ } else {
+ RETURN_ERROR(stage_wrong, "can only set params in ctx init stage");
+ } }
+
+ switch(param)
+ {
+ case ZSTD_c_nbWorkers:
+ RETURN_ERROR_IF((value!=0) && cctx->staticSize, parameter_unsupported,
+ "MT not compatible with static alloc");
+ break;
+
+ case ZSTD_c_compressionLevel:
+ case ZSTD_c_windowLog:
+ case ZSTD_c_hashLog:
+ case ZSTD_c_chainLog:
+ case ZSTD_c_searchLog:
+ case ZSTD_c_minMatch:
+ case ZSTD_c_targetLength:
+ case ZSTD_c_strategy:
+ case ZSTD_c_ldmHashRateLog:
+ case ZSTD_c_format:
+ case ZSTD_c_contentSizeFlag:
+ case ZSTD_c_checksumFlag:
+ case ZSTD_c_dictIDFlag:
+ case ZSTD_c_forceMaxWindow:
+ case ZSTD_c_forceAttachDict:
+ case ZSTD_c_literalCompressionMode:
+ case ZSTD_c_jobSize:
+ case ZSTD_c_overlapLog:
+ case ZSTD_c_rsyncable:
+ case ZSTD_c_enableLongDistanceMatching:
+ case ZSTD_c_ldmHashLog:
+ case ZSTD_c_ldmMinMatch:
+ case ZSTD_c_ldmBucketSizeLog:
+ case ZSTD_c_targetCBlockSize:
+ case ZSTD_c_srcSizeHint:
+ break;
+
+ default: RETURN_ERROR(parameter_unsupported, "unknown parameter");
+ }
+ return ZSTD_CCtxParams_setParameter(&cctx->requestedParams, param, value);
+}
+
+size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams,
+ ZSTD_cParameter param, int value)
+{
+ DEBUGLOG(4, "ZSTD_CCtxParams_setParameter (%i, %i)", (int)param, value);
+ switch(param)
+ {
+ case ZSTD_c_format :
+ BOUNDCHECK(ZSTD_c_format, value);
+ CCtxParams->format = (ZSTD_format_e)value;
+ return (size_t)CCtxParams->format;
+
+ case ZSTD_c_compressionLevel : {
+ FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value), "");
+ if (value) { /* 0 : does not change current level */
+ CCtxParams->compressionLevel = value;
+ }
+ if (CCtxParams->compressionLevel >= 0) return (size_t)CCtxParams->compressionLevel;
+ return 0; /* return type (size_t) cannot represent negative values */
+ }
+
+ case ZSTD_c_windowLog :
+ if (value!=0) /* 0 => use default */
+ BOUNDCHECK(ZSTD_c_windowLog, value);
+ CCtxParams->cParams.windowLog = (U32)value;
+ return CCtxParams->cParams.windowLog;
+
+ case ZSTD_c_hashLog :
+ if (value!=0) /* 0 => use default */
+ BOUNDCHECK(ZSTD_c_hashLog, value);
+ CCtxParams->cParams.hashLog = (U32)value;
+ return CCtxParams->cParams.hashLog;
+
+ case ZSTD_c_chainLog :
+ if (value!=0) /* 0 => use default */
+ BOUNDCHECK(ZSTD_c_chainLog, value);
+ CCtxParams->cParams.chainLog = (U32)value;
+ return CCtxParams->cParams.chainLog;
+
+ case ZSTD_c_searchLog :
+ if (value!=0) /* 0 => use default */
+ BOUNDCHECK(ZSTD_c_searchLog, value);
+ CCtxParams->cParams.searchLog = (U32)value;
+ return (size_t)value;
+
+ case ZSTD_c_minMatch :
+ if (value!=0) /* 0 => use default */
+ BOUNDCHECK(ZSTD_c_minMatch, value);
+ CCtxParams->cParams.minMatch = value;
+ return CCtxParams->cParams.minMatch;
+
+ case ZSTD_c_targetLength :
+ BOUNDCHECK(ZSTD_c_targetLength, value);
+ CCtxParams->cParams.targetLength = value;
+ return CCtxParams->cParams.targetLength;
+
+ case ZSTD_c_strategy :
+ if (value!=0) /* 0 => use default */
+ BOUNDCHECK(ZSTD_c_strategy, value);
+ CCtxParams->cParams.strategy = (ZSTD_strategy)value;
+ return (size_t)CCtxParams->cParams.strategy;
+
+ case ZSTD_c_contentSizeFlag :
+ /* Content size written in frame header _when known_ (default:1) */
+ DEBUGLOG(4, "set content size flag = %u", (value!=0));
+ CCtxParams->fParams.contentSizeFlag = value != 0;
+ return CCtxParams->fParams.contentSizeFlag;
+
+ case ZSTD_c_checksumFlag :
+ /* A 32-bits content checksum will be calculated and written at end of frame (default:0) */
+ CCtxParams->fParams.checksumFlag = value != 0;
+ return CCtxParams->fParams.checksumFlag;
+
+ case ZSTD_c_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */
+ DEBUGLOG(4, "set dictIDFlag = %u", (value!=0));
+ CCtxParams->fParams.noDictIDFlag = !value;
+ return !CCtxParams->fParams.noDictIDFlag;
+
+ case ZSTD_c_forceMaxWindow :
+ CCtxParams->forceWindow = (value != 0);
+ return CCtxParams->forceWindow;
+
+ case ZSTD_c_forceAttachDict : {
+ const ZSTD_dictAttachPref_e pref = (ZSTD_dictAttachPref_e)value;
+ BOUNDCHECK(ZSTD_c_forceAttachDict, pref);
+ CCtxParams->attachDictPref = pref;
+ return CCtxParams->attachDictPref;
+ }
+
+ case ZSTD_c_literalCompressionMode : {
+ const ZSTD_literalCompressionMode_e lcm = (ZSTD_literalCompressionMode_e)value;
+ BOUNDCHECK(ZSTD_c_literalCompressionMode, lcm);
+ CCtxParams->literalCompressionMode = lcm;
+ return CCtxParams->literalCompressionMode;
+ }
+
+ case ZSTD_c_nbWorkers :
+#ifndef ZSTD_MULTITHREAD
+ RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading");
+ return 0;
+#else
+ FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value), "");
+ CCtxParams->nbWorkers = value;
+ return CCtxParams->nbWorkers;
+#endif
+
+ case ZSTD_c_jobSize :
+#ifndef ZSTD_MULTITHREAD
+ RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading");
+ return 0;
+#else
+ /* Adjust to the minimum non-default value. */
+ if (value != 0 && value < ZSTDMT_JOBSIZE_MIN)
+ value = ZSTDMT_JOBSIZE_MIN;
+ FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value), "");
+ assert(value >= 0);
+ CCtxParams->jobSize = value;
+ return CCtxParams->jobSize;
+#endif
+
+ case ZSTD_c_overlapLog :
+#ifndef ZSTD_MULTITHREAD
+ RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading");
+ return 0;
+#else
+ FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(ZSTD_c_overlapLog, &value), "");
+ CCtxParams->overlapLog = value;
+ return CCtxParams->overlapLog;
+#endif
+
+ case ZSTD_c_rsyncable :
+#ifndef ZSTD_MULTITHREAD
+ RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading");
+ return 0;
+#else
+ FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(ZSTD_c_overlapLog, &value), "");
+ CCtxParams->rsyncable = value;
+ return CCtxParams->rsyncable;
+#endif
+
+ case ZSTD_c_enableLongDistanceMatching :
+ CCtxParams->ldmParams.enableLdm = (value!=0);
+ return CCtxParams->ldmParams.enableLdm;
+
+ case ZSTD_c_ldmHashLog :
+ if (value!=0) /* 0 ==> auto */
+ BOUNDCHECK(ZSTD_c_ldmHashLog, value);
+ CCtxParams->ldmParams.hashLog = value;
+ return CCtxParams->ldmParams.hashLog;
+
+ case ZSTD_c_ldmMinMatch :
+ if (value!=0) /* 0 ==> default */
+ BOUNDCHECK(ZSTD_c_ldmMinMatch, value);
+ CCtxParams->ldmParams.minMatchLength = value;
+ return CCtxParams->ldmParams.minMatchLength;
+
+ case ZSTD_c_ldmBucketSizeLog :
+ if (value!=0) /* 0 ==> default */
+ BOUNDCHECK(ZSTD_c_ldmBucketSizeLog, value);
+ CCtxParams->ldmParams.bucketSizeLog = value;
+ return CCtxParams->ldmParams.bucketSizeLog;
+
+ case ZSTD_c_ldmHashRateLog :
+ RETURN_ERROR_IF(value > ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN,
+ parameter_outOfBound, "Param out of bounds!");
+ CCtxParams->ldmParams.hashRateLog = value;
+ return CCtxParams->ldmParams.hashRateLog;
+
+ case ZSTD_c_targetCBlockSize :
+ if (value!=0) /* 0 ==> default */
+ BOUNDCHECK(ZSTD_c_targetCBlockSize, value);
+ CCtxParams->targetCBlockSize = value;
+ return CCtxParams->targetCBlockSize;
+
+ case ZSTD_c_srcSizeHint :
+ if (value!=0) /* 0 ==> default */
+ BOUNDCHECK(ZSTD_c_srcSizeHint, value);
+ CCtxParams->srcSizeHint = value;
+ return CCtxParams->srcSizeHint;
+
+ default: RETURN_ERROR(parameter_unsupported, "unknown parameter");
+ }
+}
+
+size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value)
+{
+ return ZSTD_CCtxParams_getParameter(&cctx->requestedParams, param, value);
+}
+
+size_t ZSTD_CCtxParams_getParameter(
+ ZSTD_CCtx_params* CCtxParams, ZSTD_cParameter param, int* value)
+{
+ switch(param)
+ {
+ case ZSTD_c_format :
+ *value = CCtxParams->format;
+ break;
+ case ZSTD_c_compressionLevel :
+ *value = CCtxParams->compressionLevel;
+ break;
+ case ZSTD_c_windowLog :
+ *value = (int)CCtxParams->cParams.windowLog;
+ break;
+ case ZSTD_c_hashLog :
+ *value = (int)CCtxParams->cParams.hashLog;
+ break;
+ case ZSTD_c_chainLog :
+ *value = (int)CCtxParams->cParams.chainLog;
+ break;
+ case ZSTD_c_searchLog :
+ *value = CCtxParams->cParams.searchLog;
+ break;
+ case ZSTD_c_minMatch :
+ *value = CCtxParams->cParams.minMatch;
+ break;
+ case ZSTD_c_targetLength :
+ *value = CCtxParams->cParams.targetLength;
+ break;
+ case ZSTD_c_strategy :
+ *value = (unsigned)CCtxParams->cParams.strategy;
+ break;
+ case ZSTD_c_contentSizeFlag :
+ *value = CCtxParams->fParams.contentSizeFlag;
+ break;
+ case ZSTD_c_checksumFlag :
+ *value = CCtxParams->fParams.checksumFlag;
+ break;
+ case ZSTD_c_dictIDFlag :
+ *value = !CCtxParams->fParams.noDictIDFlag;
+ break;
+ case ZSTD_c_forceMaxWindow :
+ *value = CCtxParams->forceWindow;
+ break;
+ case ZSTD_c_forceAttachDict :
+ *value = CCtxParams->attachDictPref;
+ break;
+ case ZSTD_c_literalCompressionMode :
+ *value = CCtxParams->literalCompressionMode;
+ break;
+ case ZSTD_c_nbWorkers :
+#ifndef ZSTD_MULTITHREAD
+ assert(CCtxParams->nbWorkers == 0);
+#endif
+ *value = CCtxParams->nbWorkers;
+ break;
+ case ZSTD_c_jobSize :
+#ifndef ZSTD_MULTITHREAD
+ RETURN_ERROR(parameter_unsupported, "not compiled with multithreading");
+#else
+ assert(CCtxParams->jobSize <= INT_MAX);
+ *value = (int)CCtxParams->jobSize;
+ break;
+#endif
+ case ZSTD_c_overlapLog :
+#ifndef ZSTD_MULTITHREAD
+ RETURN_ERROR(parameter_unsupported, "not compiled with multithreading");
+#else
+ *value = CCtxParams->overlapLog;
+ break;
+#endif
+ case ZSTD_c_rsyncable :
+#ifndef ZSTD_MULTITHREAD
+ RETURN_ERROR(parameter_unsupported, "not compiled with multithreading");
+#else
+ *value = CCtxParams->rsyncable;
+ break;
+#endif
+ case ZSTD_c_enableLongDistanceMatching :
+ *value = CCtxParams->ldmParams.enableLdm;
+ break;
+ case ZSTD_c_ldmHashLog :
+ *value = CCtxParams->ldmParams.hashLog;
+ break;
+ case ZSTD_c_ldmMinMatch :
+ *value = CCtxParams->ldmParams.minMatchLength;
+ break;
+ case ZSTD_c_ldmBucketSizeLog :
+ *value = CCtxParams->ldmParams.bucketSizeLog;
+ break;
+ case ZSTD_c_ldmHashRateLog :
+ *value = CCtxParams->ldmParams.hashRateLog;
+ break;
+ case ZSTD_c_targetCBlockSize :
+ *value = (int)CCtxParams->targetCBlockSize;
+ break;
+ case ZSTD_c_srcSizeHint :
+ *value = (int)CCtxParams->srcSizeHint;
+ break;
+ default: RETURN_ERROR(parameter_unsupported, "unknown parameter");
+ }
+ return 0;
+}
+
+/** ZSTD_CCtx_setParametersUsingCCtxParams() :
+ * just applies `params` into `cctx`
+ * no action is performed, parameters are merely stored.
+ * If ZSTDMT is enabled, parameters are pushed to cctx->mtctx.
+ * This is possible even if a compression is ongoing.
+ * In which case, new parameters will be applied on the fly, starting with next compression job.
+ */
+size_t ZSTD_CCtx_setParametersUsingCCtxParams(
+ ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params)
+{
+ DEBUGLOG(4, "ZSTD_CCtx_setParametersUsingCCtxParams");
+ RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
+ "The context is in the wrong stage!");
+ RETURN_ERROR_IF(cctx->cdict, stage_wrong,
+ "Can't override parameters with cdict attached (some must "
+ "be inherited from the cdict).");
+
+ cctx->requestedParams = *params;
+ return 0;
+}
+
+ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize)
+{
+ DEBUGLOG(4, "ZSTD_CCtx_setPledgedSrcSize to %u bytes", (U32)pledgedSrcSize);
+ RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
+ "Can't set pledgedSrcSize when not in init stage.");
+ cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1;
+ return 0;
+}
+
+/**
+ * Initializes the local dict using the requested parameters.
+ * NOTE: This does not use the pledged src size, because it may be used for more
+ * than one compression.
+ */
+static size_t ZSTD_initLocalDict(ZSTD_CCtx* cctx)
+{
+ ZSTD_localDict* const dl = &cctx->localDict;
+ ZSTD_compressionParameters const cParams = ZSTD_getCParamsFromCCtxParams(
+ &cctx->requestedParams, ZSTD_CONTENTSIZE_UNKNOWN, dl->dictSize);
+ if (dl->dict == NULL) {
+ /* No local dictionary. */
+ assert(dl->dictBuffer == NULL);
+ assert(dl->cdict == NULL);
+ assert(dl->dictSize == 0);
+ return 0;
+ }
+ if (dl->cdict != NULL) {
+ assert(cctx->cdict == dl->cdict);
+ /* Local dictionary already initialized. */
+ return 0;
+ }
+ assert(dl->dictSize > 0);
+ assert(cctx->cdict == NULL);
+ assert(cctx->prefixDict.dict == NULL);
+
+ dl->cdict = ZSTD_createCDict_advanced(
+ dl->dict,
+ dl->dictSize,
+ ZSTD_dlm_byRef,
+ dl->dictContentType,
+ cParams,
+ cctx->customMem);
+ RETURN_ERROR_IF(!dl->cdict, memory_allocation, "ZSTD_createCDict_advanced failed");
+ cctx->cdict = dl->cdict;
+ return 0;
+}
+
+size_t ZSTD_CCtx_loadDictionary_advanced(
+ ZSTD_CCtx* cctx, const void* dict, size_t dictSize,
+ ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType)
+{
+ RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
+ "Can't load a dictionary when ctx is not in init stage.");
+ RETURN_ERROR_IF(cctx->staticSize, memory_allocation,
+ "no malloc for static CCtx");
+ DEBUGLOG(4, "ZSTD_CCtx_loadDictionary_advanced (size: %u)", (U32)dictSize);
+ ZSTD_clearAllDicts(cctx); /* in case one already exists */
+ if (dict == NULL || dictSize == 0) /* no dictionary mode */
+ return 0;
+ if (dictLoadMethod == ZSTD_dlm_byRef) {
+ cctx->localDict.dict = dict;
+ } else {
+ void* dictBuffer = ZSTD_malloc(dictSize, cctx->customMem);
+ RETURN_ERROR_IF(!dictBuffer, memory_allocation, "NULL pointer!");
+ memcpy(dictBuffer, dict, dictSize);
+ cctx->localDict.dictBuffer = dictBuffer;
+ cctx->localDict.dict = dictBuffer;
+ }
+ cctx->localDict.dictSize = dictSize;
+ cctx->localDict.dictContentType = dictContentType;
+ return 0;
+}
+
+ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference(
+ ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
+{
+ return ZSTD_CCtx_loadDictionary_advanced(
+ cctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto);
+}
+
+ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
+{
+ return ZSTD_CCtx_loadDictionary_advanced(
+ cctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto);
+}
+
+
+size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
+{
+ RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
+ "Can't ref a dict when ctx not in init stage.");
+ /* Free the existing local cdict (if any) to save memory. */
+ ZSTD_clearAllDicts(cctx);
+ cctx->cdict = cdict;
+ return 0;
+}
+
+size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize)
+{
+ return ZSTD_CCtx_refPrefix_advanced(cctx, prefix, prefixSize, ZSTD_dct_rawContent);
+}
+
+size_t ZSTD_CCtx_refPrefix_advanced(
+ ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType)
+{
+ RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
+ "Can't ref a prefix when ctx not in init stage.");
+ ZSTD_clearAllDicts(cctx);
+ if (prefix != NULL && prefixSize > 0) {
+ cctx->prefixDict.dict = prefix;
+ cctx->prefixDict.dictSize = prefixSize;
+ cctx->prefixDict.dictContentType = dictContentType;
+ }
+ return 0;
+}
+
+/*! ZSTD_CCtx_reset() :
+ * Also dumps dictionary */
+size_t ZSTD_CCtx_reset(ZSTD_CCtx* cctx, ZSTD_ResetDirective reset)
+{
+ if ( (reset == ZSTD_reset_session_only)
+ || (reset == ZSTD_reset_session_and_parameters) ) {
+ cctx->streamStage = zcss_init;
+ cctx->pledgedSrcSizePlusOne = 0;
+ }
+ if ( (reset == ZSTD_reset_parameters)
+ || (reset == ZSTD_reset_session_and_parameters) ) {
+ RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
+ "Can't reset parameters only when not in init stage.");
+ ZSTD_clearAllDicts(cctx);
+ return ZSTD_CCtxParams_reset(&cctx->requestedParams);
+ }
+ return 0;
+}
+
+
+/** ZSTD_checkCParams() :
+ control CParam values remain within authorized range.
+ @return : 0, or an error code if one value is beyond authorized range */
+size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
+{
+ BOUNDCHECK(ZSTD_c_windowLog, (int)cParams.windowLog);
+ BOUNDCHECK(ZSTD_c_chainLog, (int)cParams.chainLog);
+ BOUNDCHECK(ZSTD_c_hashLog, (int)cParams.hashLog);
+ BOUNDCHECK(ZSTD_c_searchLog, (int)cParams.searchLog);
+ BOUNDCHECK(ZSTD_c_minMatch, (int)cParams.minMatch);
+ BOUNDCHECK(ZSTD_c_targetLength,(int)cParams.targetLength);
+ BOUNDCHECK(ZSTD_c_strategy, cParams.strategy);
+ return 0;
+}
+
+/** ZSTD_clampCParams() :
+ * make CParam values within valid range.
+ * @return : valid CParams */
+static ZSTD_compressionParameters
+ZSTD_clampCParams(ZSTD_compressionParameters cParams)
+{
+# define CLAMP_TYPE(cParam, val, type) { \
+ ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam); \
+ if ((int)val<bounds.lowerBound) val=(type)bounds.lowerBound; \
+ else if ((int)val>bounds.upperBound) val=(type)bounds.upperBound; \
+ }
+# define CLAMP(cParam, val) CLAMP_TYPE(cParam, val, unsigned)
+ CLAMP(ZSTD_c_windowLog, cParams.windowLog);
+ CLAMP(ZSTD_c_chainLog, cParams.chainLog);
+ CLAMP(ZSTD_c_hashLog, cParams.hashLog);
+ CLAMP(ZSTD_c_searchLog, cParams.searchLog);
+ CLAMP(ZSTD_c_minMatch, cParams.minMatch);
+ CLAMP(ZSTD_c_targetLength,cParams.targetLength);
+ CLAMP_TYPE(ZSTD_c_strategy,cParams.strategy, ZSTD_strategy);
+ return cParams;
+}
+
+/** ZSTD_cycleLog() :
+ * condition for correct operation : hashLog > 1 */
+U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
+{
+ U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2);
+ return hashLog - btScale;
+}
+
+/** ZSTD_adjustCParams_internal() :
+ * optimize `cPar` for a specified input (`srcSize` and `dictSize`).
+ * mostly downsize to reduce memory consumption and initialization latency.
+ * `srcSize` can be ZSTD_CONTENTSIZE_UNKNOWN when not known.
+ * note : `srcSize==0` means 0!
+ * condition : cPar is presumed validated (can be checked using ZSTD_checkCParams()). */
+static ZSTD_compressionParameters
+ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar,
+ unsigned long long srcSize,
+ size_t dictSize)
+{
+ static const U64 minSrcSize = 513; /* (1<<9) + 1 */
+ static const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1);
+ assert(ZSTD_checkCParams(cPar)==0);
+
+ if (dictSize && srcSize == ZSTD_CONTENTSIZE_UNKNOWN)
+ srcSize = minSrcSize;
+
+ /* resize windowLog if input is small enough, to use less memory */
+ if ( (srcSize < maxWindowResize)
+ && (dictSize < maxWindowResize) ) {
+ U32 const tSize = (U32)(srcSize + dictSize);
+ static U32 const hashSizeMin = 1 << ZSTD_HASHLOG_MIN;
+ U32 const srcLog = (tSize < hashSizeMin) ? ZSTD_HASHLOG_MIN :
+ ZSTD_highbit32(tSize-1) + 1;
+ if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
+ }
+ if (cPar.hashLog > cPar.windowLog+1) cPar.hashLog = cPar.windowLog+1;
+ { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
+ if (cycleLog > cPar.windowLog)
+ cPar.chainLog -= (cycleLog - cPar.windowLog);
+ }
+
+ if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN)
+ cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* minimum wlog required for valid frame header */
+
+ return cPar;
+}
+
+ZSTD_compressionParameters
+ZSTD_adjustCParams(ZSTD_compressionParameters cPar,
+ unsigned long long srcSize,
+ size_t dictSize)
+{
+ cPar = ZSTD_clampCParams(cPar); /* resulting cPar is necessarily valid (all parameters within range) */
+ if (srcSize == 0) srcSize = ZSTD_CONTENTSIZE_UNKNOWN;
+ return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize);
+}
+
+static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize);
+static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize);
+
+ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams(
+ const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize)
+{
+ ZSTD_compressionParameters cParams;
+ if (srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN && CCtxParams->srcSizeHint > 0) {
+ srcSizeHint = CCtxParams->srcSizeHint;
+ }
+ cParams = ZSTD_getCParams_internal(CCtxParams->compressionLevel, srcSizeHint, dictSize);
+ if (CCtxParams->ldmParams.enableLdm) cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG;
+ if (CCtxParams->cParams.windowLog) cParams.windowLog = CCtxParams->cParams.windowLog;
+ if (CCtxParams->cParams.hashLog) cParams.hashLog = CCtxParams->cParams.hashLog;
+ if (CCtxParams->cParams.chainLog) cParams.chainLog = CCtxParams->cParams.chainLog;
+ if (CCtxParams->cParams.searchLog) cParams.searchLog = CCtxParams->cParams.searchLog;
+ if (CCtxParams->cParams.minMatch) cParams.minMatch = CCtxParams->cParams.minMatch;
+ if (CCtxParams->cParams.targetLength) cParams.targetLength = CCtxParams->cParams.targetLength;
+ if (CCtxParams->cParams.strategy) cParams.strategy = CCtxParams->cParams.strategy;
+ assert(!ZSTD_checkCParams(cParams));
+ /* srcSizeHint == 0 means 0 */
+ return ZSTD_adjustCParams_internal(cParams, srcSizeHint, dictSize);
+}
+
+static size_t
+ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams,
+ const U32 forCCtx)
+{
+ size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog);
+ size_t const hSize = ((size_t)1) << cParams->hashLog;
+ U32 const hashLog3 = (forCCtx && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0;
+ size_t const h3Size = hashLog3 ? ((size_t)1) << hashLog3 : 0;
+ /* We don't use ZSTD_cwksp_alloc_size() here because the tables aren't
+ * surrounded by redzones in ASAN. */
+ size_t const tableSpace = chainSize * sizeof(U32)
+ + hSize * sizeof(U32)
+ + h3Size * sizeof(U32);
+ size_t const optPotentialSpace =
+ ZSTD_cwksp_alloc_size((MaxML+1) * sizeof(U32))
+ + ZSTD_cwksp_alloc_size((MaxLL+1) * sizeof(U32))
+ + ZSTD_cwksp_alloc_size((MaxOff+1) * sizeof(U32))
+ + ZSTD_cwksp_alloc_size((1<<Litbits) * sizeof(U32))
+ + ZSTD_cwksp_alloc_size((ZSTD_OPT_NUM+1) * sizeof(ZSTD_match_t))
+ + ZSTD_cwksp_alloc_size((ZSTD_OPT_NUM+1) * sizeof(ZSTD_optimal_t));
+ size_t const optSpace = (forCCtx && (cParams->strategy >= ZSTD_btopt))
+ ? optPotentialSpace
+ : 0;
+ DEBUGLOG(4, "chainSize: %u - hSize: %u - h3Size: %u",
+ (U32)chainSize, (U32)hSize, (U32)h3Size);
+ return tableSpace + optSpace;
+}
+
+size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params)
+{
+ RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only.");
+ { ZSTD_compressionParameters const cParams =
+ ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0);
+ size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
+ U32 const divider = (cParams.minMatch==3) ? 3 : 4;
+ size_t const maxNbSeq = blockSize / divider;
+ size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize)
+ + ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(seqDef))
+ + 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE));
+ size_t const entropySpace = ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE);
+ size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t));
+ size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 1);
+
+ size_t const ldmSpace = ZSTD_ldm_getTableSize(params->ldmParams);
+ size_t const ldmSeqSpace = ZSTD_cwksp_alloc_size(ZSTD_ldm_getMaxNbSeq(params->ldmParams, blockSize) * sizeof(rawSeq));
+
+ /* estimateCCtxSize is for one-shot compression. So no buffers should
+ * be needed. However, we still allocate two 0-sized buffers, which can
+ * take space under ASAN. */
+ size_t const bufferSpace = ZSTD_cwksp_alloc_size(0)
+ + ZSTD_cwksp_alloc_size(0);
+
+ size_t const cctxSpace = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx));
+
+ size_t const neededSpace =
+ cctxSpace +
+ entropySpace +
+ blockStateSpace +
+ ldmSpace +
+ ldmSeqSpace +
+ matchStateSize +
+ tokenSpace +
+ bufferSpace;
+
+ DEBUGLOG(5, "estimate workspace : %u", (U32)neededSpace);
+ return neededSpace;
+ }
+}
+
+size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams)
+{
+ ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams);
+ return ZSTD_estimateCCtxSize_usingCCtxParams(&params);
+}
+
+static size_t ZSTD_estimateCCtxSize_internal(int compressionLevel)
+{
+ ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0);
+ return ZSTD_estimateCCtxSize_usingCParams(cParams);
+}
+
+size_t ZSTD_estimateCCtxSize(int compressionLevel)
+{
+ int level;
+ size_t memBudget = 0;
+ for (level=MIN(compressionLevel, 1); level<=compressionLevel; level++) {
+ size_t const newMB = ZSTD_estimateCCtxSize_internal(level);
+ if (newMB > memBudget) memBudget = newMB;
+ }
+ return memBudget;
+}
+
+size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params)
+{
+ RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only.");
+ { ZSTD_compressionParameters const cParams =
+ ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0);
+ size_t const CCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params);
+ size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
+ size_t const inBuffSize = ((size_t)1 << cParams.windowLog) + blockSize;
+ size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1;
+ size_t const streamingSize = ZSTD_cwksp_alloc_size(inBuffSize)
+ + ZSTD_cwksp_alloc_size(outBuffSize);
+
+ return CCtxSize + streamingSize;
+ }
+}
+
+size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams)
+{
+ ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams);
+ return ZSTD_estimateCStreamSize_usingCCtxParams(&params);
+}
+
+static size_t ZSTD_estimateCStreamSize_internal(int compressionLevel)
+{
+ ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0);
+ return ZSTD_estimateCStreamSize_usingCParams(cParams);
+}
+
+size_t ZSTD_estimateCStreamSize(int compressionLevel)
+{
+ int level;
+ size_t memBudget = 0;
+ for (level=MIN(compressionLevel, 1); level<=compressionLevel; level++) {
+ size_t const newMB = ZSTD_estimateCStreamSize_internal(level);
+ if (newMB > memBudget) memBudget = newMB;
+ }
+ return memBudget;
+}
+
+/* ZSTD_getFrameProgression():
+ * tells how much data has been consumed (input) and produced (output) for current frame.
+ * able to count progression inside worker threads (non-blocking mode).
+ */
+ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx)
+{
+#ifdef ZSTD_MULTITHREAD
+ if (cctx->appliedParams.nbWorkers > 0) {
+ return ZSTDMT_getFrameProgression(cctx->mtctx);
+ }
+#endif
+ { ZSTD_frameProgression fp;
+ size_t const buffered = (cctx->inBuff == NULL) ? 0 :
+ cctx->inBuffPos - cctx->inToCompress;
+ if (buffered) assert(cctx->inBuffPos >= cctx->inToCompress);
+ assert(buffered <= ZSTD_BLOCKSIZE_MAX);
+ fp.ingested = cctx->consumedSrcSize + buffered;
+ fp.consumed = cctx->consumedSrcSize;
+ fp.produced = cctx->producedCSize;
+ fp.flushed = cctx->producedCSize; /* simplified; some data might still be left within streaming output buffer */
+ fp.currentJobID = 0;
+ fp.nbActiveWorkers = 0;
+ return fp;
+} }
+
+/*! ZSTD_toFlushNow()
+ * Only useful for multithreading scenarios currently (nbWorkers >= 1).
+ */
+size_t ZSTD_toFlushNow(ZSTD_CCtx* cctx)
+{
+#ifdef ZSTD_MULTITHREAD
+ if (cctx->appliedParams.nbWorkers > 0) {
+ return ZSTDMT_toFlushNow(cctx->mtctx);
+ }
+#endif
+ (void)cctx;
+ return 0; /* over-simplification; could also check if context is currently running in streaming mode, and in which case, report how many bytes are left to be flushed within output buffer */
+}
+
+static void ZSTD_assertEqualCParams(ZSTD_compressionParameters cParams1,
+ ZSTD_compressionParameters cParams2)
+{
+ (void)cParams1;
+ (void)cParams2;
+ assert(cParams1.windowLog == cParams2.windowLog);
+ assert(cParams1.chainLog == cParams2.chainLog);
+ assert(cParams1.hashLog == cParams2.hashLog);
+ assert(cParams1.searchLog == cParams2.searchLog);
+ assert(cParams1.minMatch == cParams2.minMatch);
+ assert(cParams1.targetLength == cParams2.targetLength);
+ assert(cParams1.strategy == cParams2.strategy);
+}
+
+void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs)
+{
+ int i;
+ for (i = 0; i < ZSTD_REP_NUM; ++i)
+ bs->rep[i] = repStartValue[i];
+ bs->entropy.huf.repeatMode = HUF_repeat_none;
+ bs->entropy.fse.offcode_repeatMode = FSE_repeat_none;
+ bs->entropy.fse.matchlength_repeatMode = FSE_repeat_none;
+ bs->entropy.fse.litlength_repeatMode = FSE_repeat_none;
+}
+
+/*! ZSTD_invalidateMatchState()
+ * Invalidate all the matches in the match finder tables.
+ * Requires nextSrc and base to be set (can be NULL).
+ */
+static void ZSTD_invalidateMatchState(ZSTD_matchState_t* ms)
+{
+ ZSTD_window_clear(&ms->window);
+
+ ms->nextToUpdate = ms->window.dictLimit;
+ ms->loadedDictEnd = 0;
+ ms->opt.litLengthSum = 0; /* force reset of btopt stats */
+ ms->dictMatchState = NULL;
+}
+
+/**
+ * Indicates whether this compression proceeds directly from user-provided
+ * source buffer to user-provided destination buffer (ZSTDb_not_buffered), or
+ * whether the context needs to buffer the input/output (ZSTDb_buffered).
+ */
+typedef enum {
+ ZSTDb_not_buffered,
+ ZSTDb_buffered
+} ZSTD_buffered_policy_e;
+
+/**
+ * Controls, for this matchState reset, whether the tables need to be cleared /
+ * prepared for the coming compression (ZSTDcrp_makeClean), or whether the
+ * tables can be left unclean (ZSTDcrp_leaveDirty), because we know that a
+ * subsequent operation will overwrite the table space anyways (e.g., copying
+ * the matchState contents in from a CDict).
+ */
+typedef enum {
+ ZSTDcrp_makeClean,
+ ZSTDcrp_leaveDirty
+} ZSTD_compResetPolicy_e;
+
+/**
+ * Controls, for this matchState reset, whether indexing can continue where it
+ * left off (ZSTDirp_continue), or whether it needs to be restarted from zero
+ * (ZSTDirp_reset).
+ */
+typedef enum {
+ ZSTDirp_continue,
+ ZSTDirp_reset
+} ZSTD_indexResetPolicy_e;
+
+typedef enum {
+ ZSTD_resetTarget_CDict,
+ ZSTD_resetTarget_CCtx
+} ZSTD_resetTarget_e;
+
+static size_t
+ZSTD_reset_matchState(ZSTD_matchState_t* ms,
+ ZSTD_cwksp* ws,
+ const ZSTD_compressionParameters* cParams,
+ const ZSTD_compResetPolicy_e crp,
+ const ZSTD_indexResetPolicy_e forceResetIndex,
+ const ZSTD_resetTarget_e forWho)
+{
+ size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog);
+ size_t const hSize = ((size_t)1) << cParams->hashLog;
+ U32 const hashLog3 = ((forWho == ZSTD_resetTarget_CCtx) && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0;
+ size_t const h3Size = hashLog3 ? ((size_t)1) << hashLog3 : 0;
+
+ DEBUGLOG(4, "reset indices : %u", forceResetIndex == ZSTDirp_reset);
+ if (forceResetIndex == ZSTDirp_reset) {
+ ZSTD_window_init(&ms->window);
+ ZSTD_cwksp_mark_tables_dirty(ws);
+ }
+
+ ms->hashLog3 = hashLog3;
+
+ ZSTD_invalidateMatchState(ms);
+
+ assert(!ZSTD_cwksp_reserve_failed(ws)); /* check that allocation hasn't already failed */
+
+ ZSTD_cwksp_clear_tables(ws);
+
+ DEBUGLOG(5, "reserving table space");
+ /* table Space */
+ ms->hashTable = (U32*)ZSTD_cwksp_reserve_table(ws, hSize * sizeof(U32));
+ ms->chainTable = (U32*)ZSTD_cwksp_reserve_table(ws, chainSize * sizeof(U32));
+ ms->hashTable3 = (U32*)ZSTD_cwksp_reserve_table(ws, h3Size * sizeof(U32));
+ RETURN_ERROR_IF(ZSTD_cwksp_reserve_failed(ws), memory_allocation,
+ "failed a workspace allocation in ZSTD_reset_matchState");
+
+ DEBUGLOG(4, "reset table : %u", crp!=ZSTDcrp_leaveDirty);
+ if (crp!=ZSTDcrp_leaveDirty) {
+ /* reset tables only */
+ ZSTD_cwksp_clean_tables(ws);
+ }
+
+ /* opt parser space */
+ if ((forWho == ZSTD_resetTarget_CCtx) && (cParams->strategy >= ZSTD_btopt)) {
+ DEBUGLOG(4, "reserving optimal parser space");
+ ms->opt.litFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (1<<Litbits) * sizeof(unsigned));
+ ms->opt.litLengthFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (MaxLL+1) * sizeof(unsigned));
+ ms->opt.matchLengthFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (MaxML+1) * sizeof(unsigned));
+ ms->opt.offCodeFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (MaxOff+1) * sizeof(unsigned));
+ ms->opt.matchTable = (ZSTD_match_t*)ZSTD_cwksp_reserve_aligned(ws, (ZSTD_OPT_NUM+1) * sizeof(ZSTD_match_t));
+ ms->opt.priceTable = (ZSTD_optimal_t*)ZSTD_cwksp_reserve_aligned(ws, (ZSTD_OPT_NUM+1) * sizeof(ZSTD_optimal_t));
+ }
+
+ ms->cParams = *cParams;
+
+ RETURN_ERROR_IF(ZSTD_cwksp_reserve_failed(ws), memory_allocation,
+ "failed a workspace allocation in ZSTD_reset_matchState");
+
+ return 0;
+}
+
+/* ZSTD_indexTooCloseToMax() :
+ * minor optimization : prefer memset() rather than reduceIndex()
+ * which is measurably slow in some circumstances (reported for Visual Studio).
+ * Works when re-using a context for a lot of smallish inputs :
+ * if all inputs are smaller than ZSTD_INDEXOVERFLOW_MARGIN,
+ * memset() will be triggered before reduceIndex().
+ */
+#define ZSTD_INDEXOVERFLOW_MARGIN (16 MB)
+static int ZSTD_indexTooCloseToMax(ZSTD_window_t w)
+{
+ return (size_t)(w.nextSrc - w.base) > (ZSTD_CURRENT_MAX - ZSTD_INDEXOVERFLOW_MARGIN);
+}
+
+/*! ZSTD_resetCCtx_internal() :
+ note : `params` are assumed fully validated at this stage */
+static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
+ ZSTD_CCtx_params params,
+ U64 const pledgedSrcSize,
+ ZSTD_compResetPolicy_e const crp,
+ ZSTD_buffered_policy_e const zbuff)
+{
+ ZSTD_cwksp* const ws = &zc->workspace;
+ DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u",
+ (U32)pledgedSrcSize, params.cParams.windowLog);
+ assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
+
+ zc->isFirstBlock = 1;
+
+ if (params.ldmParams.enableLdm) {
+ /* Adjust long distance matching parameters */
+ ZSTD_ldm_adjustParameters(&params.ldmParams, &params.cParams);
+ assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog);
+ assert(params.ldmParams.hashRateLog < 32);
+ zc->ldmState.hashPower = ZSTD_rollingHash_primePower(params.ldmParams.minMatchLength);
+ }
+
+ { size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize));
+ size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
+ U32 const divider = (params.cParams.minMatch==3) ? 3 : 4;
+ size_t const maxNbSeq = blockSize / divider;
+ size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize)
+ + ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(seqDef))
+ + 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE));
+ size_t const buffOutSize = (zbuff==ZSTDb_buffered) ? ZSTD_compressBound(blockSize)+1 : 0;
+ size_t const buffInSize = (zbuff==ZSTDb_buffered) ? windowSize + blockSize : 0;
+ size_t const matchStateSize = ZSTD_sizeof_matchState(&params.cParams, /* forCCtx */ 1);
+ size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params.ldmParams, blockSize);
+
+ ZSTD_indexResetPolicy_e needsIndexReset = zc->initialized ? ZSTDirp_continue : ZSTDirp_reset;
+
+ if (ZSTD_indexTooCloseToMax(zc->blockState.matchState.window)) {
+ needsIndexReset = ZSTDirp_reset;
+ }
+
+ if (!zc->staticSize) ZSTD_cwksp_bump_oversized_duration(ws, 0);
+
+ /* Check if workspace is large enough, alloc a new one if needed */
+ { size_t const cctxSpace = zc->staticSize ? ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx)) : 0;
+ size_t const entropySpace = ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE);
+ size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t));
+ size_t const bufferSpace = ZSTD_cwksp_alloc_size(buffInSize) + ZSTD_cwksp_alloc_size(buffOutSize);
+ size_t const ldmSpace = ZSTD_ldm_getTableSize(params.ldmParams);
+ size_t const ldmSeqSpace = ZSTD_cwksp_alloc_size(maxNbLdmSeq * sizeof(rawSeq));
+
+ size_t const neededSpace =
+ cctxSpace +
+ entropySpace +
+ blockStateSpace +
+ ldmSpace +
+ ldmSeqSpace +
+ matchStateSize +
+ tokenSpace +
+ bufferSpace;
+
+ int const workspaceTooSmall = ZSTD_cwksp_sizeof(ws) < neededSpace;
+ int const workspaceWasteful = ZSTD_cwksp_check_wasteful(ws, neededSpace);
+
+ DEBUGLOG(4, "Need %zuKB workspace, including %zuKB for match state, and %zuKB for buffers",
+ neededSpace>>10, matchStateSize>>10, bufferSpace>>10);
+ DEBUGLOG(4, "windowSize: %zu - blockSize: %zu", windowSize, blockSize);
+
+ if (workspaceTooSmall || workspaceWasteful) {
+ DEBUGLOG(4, "Resize workspaceSize from %zuKB to %zuKB",
+ ZSTD_cwksp_sizeof(ws) >> 10,
+ neededSpace >> 10);
+
+ RETURN_ERROR_IF(zc->staticSize, memory_allocation, "static cctx : no resize");
+
+ needsIndexReset = ZSTDirp_reset;
+
+ ZSTD_cwksp_free(ws, zc->customMem);
+ FORWARD_IF_ERROR(ZSTD_cwksp_create(ws, neededSpace, zc->customMem), "");
+
+ DEBUGLOG(5, "reserving object space");
+ /* Statically sized space.
+ * entropyWorkspace never moves,
+ * though prev/next block swap places */
+ assert(ZSTD_cwksp_check_available(ws, 2 * sizeof(ZSTD_compressedBlockState_t)));
+ zc->blockState.prevCBlock = (ZSTD_compressedBlockState_t*) ZSTD_cwksp_reserve_object(ws, sizeof(ZSTD_compressedBlockState_t));
+ RETURN_ERROR_IF(zc->blockState.prevCBlock == NULL, memory_allocation, "couldn't allocate prevCBlock");
+ zc->blockState.nextCBlock = (ZSTD_compressedBlockState_t*) ZSTD_cwksp_reserve_object(ws, sizeof(ZSTD_compressedBlockState_t));
+ RETURN_ERROR_IF(zc->blockState.nextCBlock == NULL, memory_allocation, "couldn't allocate nextCBlock");
+ zc->entropyWorkspace = (U32*) ZSTD_cwksp_reserve_object(ws, HUF_WORKSPACE_SIZE);
+ RETURN_ERROR_IF(zc->blockState.nextCBlock == NULL, memory_allocation, "couldn't allocate entropyWorkspace");
+ } }
+
+ ZSTD_cwksp_clear(ws);
+
+ /* init params */
+ zc->appliedParams = params;
+ zc->blockState.matchState.cParams = params.cParams;
+ zc->pledgedSrcSizePlusOne = pledgedSrcSize+1;
+ zc->consumedSrcSize = 0;
+ zc->producedCSize = 0;
+ if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)
+ zc->appliedParams.fParams.contentSizeFlag = 0;
+ DEBUGLOG(4, "pledged content size : %u ; flag : %u",
+ (unsigned)pledgedSrcSize, zc->appliedParams.fParams.contentSizeFlag);
+ zc->blockSize = blockSize;
+
+ XXH64_reset(&zc->xxhState, 0);
+ zc->stage = ZSTDcs_init;
+ zc->dictID = 0;
+
+ ZSTD_reset_compressedBlockState(zc->blockState.prevCBlock);
+
+ /* ZSTD_wildcopy() is used to copy into the literals buffer,
+ * so we have to oversize the buffer by WILDCOPY_OVERLENGTH bytes.
+ */
+ zc->seqStore.litStart = ZSTD_cwksp_reserve_buffer(ws, blockSize + WILDCOPY_OVERLENGTH);
+ zc->seqStore.maxNbLit = blockSize;
+
+ /* buffers */
+ zc->inBuffSize = buffInSize;
+ zc->inBuff = (char*)ZSTD_cwksp_reserve_buffer(ws, buffInSize);
+ zc->outBuffSize = buffOutSize;
+ zc->outBuff = (char*)ZSTD_cwksp_reserve_buffer(ws, buffOutSize);
+
+ /* ldm bucketOffsets table */
+ if (params.ldmParams.enableLdm) {
+ /* TODO: avoid memset? */
+ size_t const ldmBucketSize =
+ ((size_t)1) << (params.ldmParams.hashLog -
+ params.ldmParams.bucketSizeLog);
+ zc->ldmState.bucketOffsets = ZSTD_cwksp_reserve_buffer(ws, ldmBucketSize);
+ memset(zc->ldmState.bucketOffsets, 0, ldmBucketSize);
+ }
+
+ /* sequences storage */
+ ZSTD_referenceExternalSequences(zc, NULL, 0);
+ zc->seqStore.maxNbSeq = maxNbSeq;
+ zc->seqStore.llCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE));
+ zc->seqStore.mlCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE));
+ zc->seqStore.ofCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE));
+ zc->seqStore.sequencesStart = (seqDef*)ZSTD_cwksp_reserve_aligned(ws, maxNbSeq * sizeof(seqDef));
+
+ FORWARD_IF_ERROR(ZSTD_reset_matchState(
+ &zc->blockState.matchState,
+ ws,
+ &params.cParams,
+ crp,
+ needsIndexReset,
+ ZSTD_resetTarget_CCtx), "");
+
+ /* ldm hash table */
+ if (params.ldmParams.enableLdm) {
+ /* TODO: avoid memset? */
+ size_t const ldmHSize = ((size_t)1) << params.ldmParams.hashLog;
+ zc->ldmState.hashTable = (ldmEntry_t*)ZSTD_cwksp_reserve_aligned(ws, ldmHSize * sizeof(ldmEntry_t));
+ memset(zc->ldmState.hashTable, 0, ldmHSize * sizeof(ldmEntry_t));
+ zc->ldmSequences = (rawSeq*)ZSTD_cwksp_reserve_aligned(ws, maxNbLdmSeq * sizeof(rawSeq));
+ zc->maxNbLdmSequences = maxNbLdmSeq;
+
+ ZSTD_window_init(&zc->ldmState.window);
+ ZSTD_window_clear(&zc->ldmState.window);
+ zc->ldmState.loadedDictEnd = 0;
+ }
+
+ DEBUGLOG(3, "wksp: finished allocating, %zd bytes remain available", ZSTD_cwksp_available_space(ws));
+ zc->initialized = 1;
+
+ return 0;
+ }
+}
+
+/* ZSTD_invalidateRepCodes() :
+ * ensures next compression will not use repcodes from previous block.
+ * Note : only works with regular variant;
+ * do not use with extDict variant ! */
+void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
+ int i;
+ for (i=0; i<ZSTD_REP_NUM; i++) cctx->blockState.prevCBlock->rep[i] = 0;
+ assert(!ZSTD_window_hasExtDict(cctx->blockState.matchState.window));
+}
+
+/* These are the approximate sizes for each strategy past which copying the
+ * dictionary tables into the working context is faster than using them
+ * in-place.
+ */
+static const size_t attachDictSizeCutoffs[ZSTD_STRATEGY_MAX+1] = {
+ 8 KB, /* unused */
+ 8 KB, /* ZSTD_fast */
+ 16 KB, /* ZSTD_dfast */
+ 32 KB, /* ZSTD_greedy */
+ 32 KB, /* ZSTD_lazy */
+ 32 KB, /* ZSTD_lazy2 */
+ 32 KB, /* ZSTD_btlazy2 */
+ 32 KB, /* ZSTD_btopt */
+ 8 KB, /* ZSTD_btultra */
+ 8 KB /* ZSTD_btultra2 */
+};
+
+static int ZSTD_shouldAttachDict(const ZSTD_CDict* cdict,
+ const ZSTD_CCtx_params* params,
+ U64 pledgedSrcSize)
+{
+ size_t cutoff = attachDictSizeCutoffs[cdict->matchState.cParams.strategy];
+ return ( pledgedSrcSize <= cutoff
+ || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN
+ || params->attachDictPref == ZSTD_dictForceAttach )
+ && params->attachDictPref != ZSTD_dictForceCopy
+ && !params->forceWindow; /* dictMatchState isn't correctly
+ * handled in _enforceMaxDist */
+}
+
+static size_t
+ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx,
+ const ZSTD_CDict* cdict,
+ ZSTD_CCtx_params params,
+ U64 pledgedSrcSize,
+ ZSTD_buffered_policy_e zbuff)
+{
+ { const ZSTD_compressionParameters* const cdict_cParams = &cdict->matchState.cParams;
+ unsigned const windowLog = params.cParams.windowLog;
+ assert(windowLog != 0);
+ /* Resize working context table params for input only, since the dict
+ * has its own tables. */
+ /* pledgeSrcSize == 0 means 0! */
+ params.cParams = ZSTD_adjustCParams_internal(*cdict_cParams, pledgedSrcSize, 0);
+ params.cParams.windowLog = windowLog;
+ FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
+ ZSTDcrp_makeClean, zbuff), "");
+ assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy);
+ }
+
+ { const U32 cdictEnd = (U32)( cdict->matchState.window.nextSrc
+ - cdict->matchState.window.base);
+ const U32 cdictLen = cdictEnd - cdict->matchState.window.dictLimit;
+ if (cdictLen == 0) {
+ /* don't even attach dictionaries with no contents */
+ DEBUGLOG(4, "skipping attaching empty dictionary");
+ } else {
+ DEBUGLOG(4, "attaching dictionary into context");
+ cctx->blockState.matchState.dictMatchState = &cdict->matchState;
+
+ /* prep working match state so dict matches never have negative indices
+ * when they are translated to the working context's index space. */
+ if (cctx->blockState.matchState.window.dictLimit < cdictEnd) {
+ cctx->blockState.matchState.window.nextSrc =
+ cctx->blockState.matchState.window.base + cdictEnd;
+ ZSTD_window_clear(&cctx->blockState.matchState.window);
+ }
+ /* loadedDictEnd is expressed within the referential of the active context */
+ cctx->blockState.matchState.loadedDictEnd = cctx->blockState.matchState.window.dictLimit;
+ } }
+
+ cctx->dictID = cdict->dictID;
+
+ /* copy block state */
+ memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState));
+
+ return 0;
+}
+
+static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx,
+ const ZSTD_CDict* cdict,
+ ZSTD_CCtx_params params,
+ U64 pledgedSrcSize,
+ ZSTD_buffered_policy_e zbuff)
+{
+ const ZSTD_compressionParameters *cdict_cParams = &cdict->matchState.cParams;
+
+ DEBUGLOG(4, "copying dictionary into context");
+
+ { unsigned const windowLog = params.cParams.windowLog;
+ assert(windowLog != 0);
+ /* Copy only compression parameters related to tables. */
+ params.cParams = *cdict_cParams;
+ params.cParams.windowLog = windowLog;
+ FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
+ ZSTDcrp_leaveDirty, zbuff), "");
+ assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy);
+ assert(cctx->appliedParams.cParams.hashLog == cdict_cParams->hashLog);
+ assert(cctx->appliedParams.cParams.chainLog == cdict_cParams->chainLog);
+ }
+
+ ZSTD_cwksp_mark_tables_dirty(&cctx->workspace);
+
+ /* copy tables */
+ { size_t const chainSize = (cdict_cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cdict_cParams->chainLog);
+ size_t const hSize = (size_t)1 << cdict_cParams->hashLog;
+
+ memcpy(cctx->blockState.matchState.hashTable,
+ cdict->matchState.hashTable,
+ hSize * sizeof(U32));
+ memcpy(cctx->blockState.matchState.chainTable,
+ cdict->matchState.chainTable,
+ chainSize * sizeof(U32));
+ }
+
+ /* Zero the hashTable3, since the cdict never fills it */
+ { int const h3log = cctx->blockState.matchState.hashLog3;
+ size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0;
+ assert(cdict->matchState.hashLog3 == 0);
+ memset(cctx->blockState.matchState.hashTable3, 0, h3Size * sizeof(U32));
+ }
+
+ ZSTD_cwksp_mark_tables_clean(&cctx->workspace);
+
+ /* copy dictionary offsets */
+ { ZSTD_matchState_t const* srcMatchState = &cdict->matchState;
+ ZSTD_matchState_t* dstMatchState = &cctx->blockState.matchState;
+ dstMatchState->window = srcMatchState->window;
+ dstMatchState->nextToUpdate = srcMatchState->nextToUpdate;
+ dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd;
+ }
+
+ cctx->dictID = cdict->dictID;
+
+ /* copy block state */
+ memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState));
+
+ return 0;
+}
+
+/* We have a choice between copying the dictionary context into the working
+ * context, or referencing the dictionary context from the working context
+ * in-place. We decide here which strategy to use. */
+static size_t ZSTD_resetCCtx_usingCDict(ZSTD_CCtx* cctx,
+ const ZSTD_CDict* cdict,
+ const ZSTD_CCtx_params* params,
+ U64 pledgedSrcSize,
+ ZSTD_buffered_policy_e zbuff)
+{
+
+ DEBUGLOG(4, "ZSTD_resetCCtx_usingCDict (pledgedSrcSize=%u)",
+ (unsigned)pledgedSrcSize);
+
+ if (ZSTD_shouldAttachDict(cdict, params, pledgedSrcSize)) {
+ return ZSTD_resetCCtx_byAttachingCDict(
+ cctx, cdict, *params, pledgedSrcSize, zbuff);
+ } else {
+ return ZSTD_resetCCtx_byCopyingCDict(
+ cctx, cdict, *params, pledgedSrcSize, zbuff);
+ }
+}
+
+/*! ZSTD_copyCCtx_internal() :
+ * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
+ * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
+ * The "context", in this case, refers to the hash and chain tables,
+ * entropy tables, and dictionary references.
+ * `windowLog` value is enforced if != 0, otherwise value is copied from srcCCtx.
+ * @return : 0, or an error code */
+static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
+ const ZSTD_CCtx* srcCCtx,
+ ZSTD_frameParameters fParams,
+ U64 pledgedSrcSize,
+ ZSTD_buffered_policy_e zbuff)
+{
+ DEBUGLOG(5, "ZSTD_copyCCtx_internal");
+ RETURN_ERROR_IF(srcCCtx->stage!=ZSTDcs_init, stage_wrong,
+ "Can't copy a ctx that's not in init stage.");
+
+ memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
+ { ZSTD_CCtx_params params = dstCCtx->requestedParams;
+ /* Copy only compression parameters related to tables. */
+ params.cParams = srcCCtx->appliedParams.cParams;
+ params.fParams = fParams;
+ ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize,
+ ZSTDcrp_leaveDirty, zbuff);
+ assert(dstCCtx->appliedParams.cParams.windowLog == srcCCtx->appliedParams.cParams.windowLog);
+ assert(dstCCtx->appliedParams.cParams.strategy == srcCCtx->appliedParams.cParams.strategy);
+ assert(dstCCtx->appliedParams.cParams.hashLog == srcCCtx->appliedParams.cParams.hashLog);
+ assert(dstCCtx->appliedParams.cParams.chainLog == srcCCtx->appliedParams.cParams.chainLog);
+ assert(dstCCtx->blockState.matchState.hashLog3 == srcCCtx->blockState.matchState.hashLog3);
+ }
+
+ ZSTD_cwksp_mark_tables_dirty(&dstCCtx->workspace);
+
+ /* copy tables */
+ { size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog);
+ size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog;
+ int const h3log = srcCCtx->blockState.matchState.hashLog3;
+ size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0;
+
+ memcpy(dstCCtx->blockState.matchState.hashTable,
+ srcCCtx->blockState.matchState.hashTable,
+ hSize * sizeof(U32));
+ memcpy(dstCCtx->blockState.matchState.chainTable,
+ srcCCtx->blockState.matchState.chainTable,
+ chainSize * sizeof(U32));
+ memcpy(dstCCtx->blockState.matchState.hashTable3,
+ srcCCtx->blockState.matchState.hashTable3,
+ h3Size * sizeof(U32));
+ }
+
+ ZSTD_cwksp_mark_tables_clean(&dstCCtx->workspace);
+
+ /* copy dictionary offsets */
+ {
+ const ZSTD_matchState_t* srcMatchState = &srcCCtx->blockState.matchState;
+ ZSTD_matchState_t* dstMatchState = &dstCCtx->blockState.matchState;
+ dstMatchState->window = srcMatchState->window;
+ dstMatchState->nextToUpdate = srcMatchState->nextToUpdate;
+ dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd;
+ }
+ dstCCtx->dictID = srcCCtx->dictID;
+
+ /* copy block state */
+ memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock));
+
+ return 0;
+}
+
+/*! ZSTD_copyCCtx() :
+ * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
+ * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
+ * pledgedSrcSize==0 means "unknown".
+* @return : 0, or an error code */
+size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize)
+{
+ ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
+ ZSTD_buffered_policy_e const zbuff = (ZSTD_buffered_policy_e)(srcCCtx->inBuffSize>0);
+ ZSTD_STATIC_ASSERT((U32)ZSTDb_buffered==1);
+ if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;
+ fParams.contentSizeFlag = (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN);
+
+ return ZSTD_copyCCtx_internal(dstCCtx, srcCCtx,
+ fParams, pledgedSrcSize,
+ zbuff);
+}
+
+
+#define ZSTD_ROWSIZE 16
+/*! ZSTD_reduceTable() :
+ * reduce table indexes by `reducerValue`, or squash to zero.
+ * PreserveMark preserves "unsorted mark" for btlazy2 strategy.
+ * It must be set to a clear 0/1 value, to remove branch during inlining.
+ * Presume table size is a multiple of ZSTD_ROWSIZE
+ * to help auto-vectorization */
+FORCE_INLINE_TEMPLATE void
+ZSTD_reduceTable_internal (U32* const table, U32 const size, U32 const reducerValue, int const preserveMark)
+{
+ int const nbRows = (int)size / ZSTD_ROWSIZE;
+ int cellNb = 0;
+ int rowNb;
+ assert((size & (ZSTD_ROWSIZE-1)) == 0); /* multiple of ZSTD_ROWSIZE */
+ assert(size < (1U<<31)); /* can be casted to int */
+
+#if defined (MEMORY_SANITIZER) && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE)
+ /* To validate that the table re-use logic is sound, and that we don't
+ * access table space that we haven't cleaned, we re-"poison" the table
+ * space every time we mark it dirty.
+ *
+ * This function however is intended to operate on those dirty tables and
+ * re-clean them. So when this function is used correctly, we can unpoison
+ * the memory it operated on. This introduces a blind spot though, since
+ * if we now try to operate on __actually__ poisoned memory, we will not
+ * detect that. */
+ __msan_unpoison(table, size * sizeof(U32));
+#endif
+
+ for (rowNb=0 ; rowNb < nbRows ; rowNb++) {
+ int column;
+ for (column=0; column<ZSTD_ROWSIZE; column++) {
+ if (preserveMark) {
+ U32 const adder = (table[cellNb] == ZSTD_DUBT_UNSORTED_MARK) ? reducerValue : 0;
+ table[cellNb] += adder;
+ }
+ if (table[cellNb] < reducerValue) table[cellNb] = 0;
+ else table[cellNb] -= reducerValue;
+ cellNb++;
+ } }
+}
+
+static void ZSTD_reduceTable(U32* const table, U32 const size, U32 const reducerValue)
+{
+ ZSTD_reduceTable_internal(table, size, reducerValue, 0);
+}
+
+static void ZSTD_reduceTable_btlazy2(U32* const table, U32 const size, U32 const reducerValue)
+{
+ ZSTD_reduceTable_internal(table, size, reducerValue, 1);
+}
+
+/*! ZSTD_reduceIndex() :
+* rescale all indexes to avoid future overflow (indexes are U32) */
+static void ZSTD_reduceIndex (ZSTD_matchState_t* ms, ZSTD_CCtx_params const* params, const U32 reducerValue)
+{
+ { U32 const hSize = (U32)1 << params->cParams.hashLog;
+ ZSTD_reduceTable(ms->hashTable, hSize, reducerValue);
+ }
+
+ if (params->cParams.strategy != ZSTD_fast) {
+ U32 const chainSize = (U32)1 << params->cParams.chainLog;
+ if (params->cParams.strategy == ZSTD_btlazy2)
+ ZSTD_reduceTable_btlazy2(ms->chainTable, chainSize, reducerValue);
+ else
+ ZSTD_reduceTable(ms->chainTable, chainSize, reducerValue);
+ }
+
+ if (ms->hashLog3) {
+ U32 const h3Size = (U32)1 << ms->hashLog3;
+ ZSTD_reduceTable(ms->hashTable3, h3Size, reducerValue);
+ }
+}
+
+
+/*-*******************************************************
+* Block entropic compression
+*********************************************************/
+
+/* See doc/zstd_compression_format.md for detailed format description */
+
+void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
+{
+ const seqDef* const sequences = seqStorePtr->sequencesStart;
+ BYTE* const llCodeTable = seqStorePtr->llCode;
+ BYTE* const ofCodeTable = seqStorePtr->ofCode;
+ BYTE* const mlCodeTable = seqStorePtr->mlCode;
+ U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
+ U32 u;
+ assert(nbSeq <= seqStorePtr->maxNbSeq);
+ for (u=0; u<nbSeq; u++) {
+ U32 const llv = sequences[u].litLength;
+ U32 const mlv = sequences[u].matchLength;
+ llCodeTable[u] = (BYTE)ZSTD_LLcode(llv);
+ ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset);
+ mlCodeTable[u] = (BYTE)ZSTD_MLcode(mlv);
+ }
+ if (seqStorePtr->longLengthID==1)
+ llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
+ if (seqStorePtr->longLengthID==2)
+ mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
+}
+
+/* ZSTD_useTargetCBlockSize():
+ * Returns if target compressed block size param is being used.
+ * If used, compression will do best effort to make a compressed block size to be around targetCBlockSize.
+ * Returns 1 if true, 0 otherwise. */
+static int ZSTD_useTargetCBlockSize(const ZSTD_CCtx_params* cctxParams)
+{
+ DEBUGLOG(5, "ZSTD_useTargetCBlockSize (targetCBlockSize=%zu)", cctxParams->targetCBlockSize);
+ return (cctxParams->targetCBlockSize != 0);
+}
+
+/* ZSTD_compressSequences_internal():
+ * actually compresses both literals and sequences */
+MEM_STATIC size_t
+ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
+ const ZSTD_entropyCTables_t* prevEntropy,
+ ZSTD_entropyCTables_t* nextEntropy,
+ const ZSTD_CCtx_params* cctxParams,
+ void* dst, size_t dstCapacity,
+ void* entropyWorkspace, size_t entropyWkspSize,
+ const int bmi2)
+{
+ const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN;
+ ZSTD_strategy const strategy = cctxParams->cParams.strategy;
+ unsigned count[MaxSeq+1];
+ FSE_CTable* CTable_LitLength = nextEntropy->fse.litlengthCTable;
+ FSE_CTable* CTable_OffsetBits = nextEntropy->fse.offcodeCTable;
+ FSE_CTable* CTable_MatchLength = nextEntropy->fse.matchlengthCTable;
+ U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
+ const seqDef* const sequences = seqStorePtr->sequencesStart;
+ const BYTE* const ofCodeTable = seqStorePtr->ofCode;
+ const BYTE* const llCodeTable = seqStorePtr->llCode;
+ const BYTE* const mlCodeTable = seqStorePtr->mlCode;
+ BYTE* const ostart = (BYTE*)dst;
+ BYTE* const oend = ostart + dstCapacity;
+ BYTE* op = ostart;
+ size_t const nbSeq = (size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
+ BYTE* seqHead;
+ BYTE* lastNCount = NULL;
+
+ DEBUGLOG(5, "ZSTD_compressSequences_internal (nbSeq=%zu)", nbSeq);
+ ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog)));
+
+ /* Compress literals */
+ { const BYTE* const literals = seqStorePtr->litStart;
+ size_t const litSize = (size_t)(seqStorePtr->lit - literals);
+ size_t const cSize = ZSTD_compressLiterals(
+ &prevEntropy->huf, &nextEntropy->huf,
+ cctxParams->cParams.strategy,
+ ZSTD_disableLiteralsCompression(cctxParams),
+ op, dstCapacity,
+ literals, litSize,
+ entropyWorkspace, entropyWkspSize,
+ bmi2);
+ FORWARD_IF_ERROR(cSize, "ZSTD_compressLiterals failed");
+ assert(cSize <= dstCapacity);
+ op += cSize;
+ }
+
+ /* Sequences Header */
+ RETURN_ERROR_IF((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead*/,
+ dstSize_tooSmall, "Can't fit seq hdr in output buf!");
+ if (nbSeq < 128) {
+ *op++ = (BYTE)nbSeq;
+ } else if (nbSeq < LONGNBSEQ) {
+ op[0] = (BYTE)((nbSeq>>8) + 0x80);
+ op[1] = (BYTE)nbSeq;
+ op+=2;
+ } else {
+ op[0]=0xFF;
+ MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ));
+ op+=3;
+ }
+ assert(op <= oend);
+ if (nbSeq==0) {
+ /* Copy the old tables over as if we repeated them */
+ memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse));
+ return (size_t)(op - ostart);
+ }
+
+ /* seqHead : flags for FSE encoding type */
+ seqHead = op++;
+ assert(op <= oend);
+
+ /* convert length/distances into codes */
+ ZSTD_seqToCodes(seqStorePtr);
+ /* build CTable for Literal Lengths */
+ { unsigned max = MaxLL;
+ size_t const mostFrequent = HIST_countFast_wksp(count, &max, llCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */
+ DEBUGLOG(5, "Building LL table");
+ nextEntropy->fse.litlength_repeatMode = prevEntropy->fse.litlength_repeatMode;
+ LLtype = ZSTD_selectEncodingType(&nextEntropy->fse.litlength_repeatMode,
+ count, max, mostFrequent, nbSeq,
+ LLFSELog, prevEntropy->fse.litlengthCTable,
+ LL_defaultNorm, LL_defaultNormLog,
+ ZSTD_defaultAllowed, strategy);
+ assert(set_basic < set_compressed && set_rle < set_compressed);
+ assert(!(LLtype < set_compressed && nextEntropy->fse.litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
+ { size_t const countSize = ZSTD_buildCTable(
+ op, (size_t)(oend - op),
+ CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype,
+ count, max, llCodeTable, nbSeq,
+ LL_defaultNorm, LL_defaultNormLog, MaxLL,
+ prevEntropy->fse.litlengthCTable,
+ sizeof(prevEntropy->fse.litlengthCTable),
+ entropyWorkspace, entropyWkspSize);
+ FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for LitLens failed");
+ if (LLtype == set_compressed)
+ lastNCount = op;
+ op += countSize;
+ assert(op <= oend);
+ } }
+ /* build CTable for Offsets */
+ { unsigned max = MaxOff;
+ size_t const mostFrequent = HIST_countFast_wksp(
+ count, &max, ofCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */
+ /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */
+ ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed;
+ DEBUGLOG(5, "Building OF table");
+ nextEntropy->fse.offcode_repeatMode = prevEntropy->fse.offcode_repeatMode;
+ Offtype = ZSTD_selectEncodingType(&nextEntropy->fse.offcode_repeatMode,
+ count, max, mostFrequent, nbSeq,
+ OffFSELog, prevEntropy->fse.offcodeCTable,
+ OF_defaultNorm, OF_defaultNormLog,
+ defaultPolicy, strategy);
+ assert(!(Offtype < set_compressed && nextEntropy->fse.offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */
+ { size_t const countSize = ZSTD_buildCTable(
+ op, (size_t)(oend - op),
+ CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype,
+ count, max, ofCodeTable, nbSeq,
+ OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
+ prevEntropy->fse.offcodeCTable,
+ sizeof(prevEntropy->fse.offcodeCTable),
+ entropyWorkspace, entropyWkspSize);
+ FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for Offsets failed");
+ if (Offtype == set_compressed)
+ lastNCount = op;
+ op += countSize;
+ assert(op <= oend);
+ } }
+ /* build CTable for MatchLengths */
+ { unsigned max = MaxML;
+ size_t const mostFrequent = HIST_countFast_wksp(
+ count, &max, mlCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */
+ DEBUGLOG(5, "Building ML table (remaining space : %i)", (int)(oend-op));
+ nextEntropy->fse.matchlength_repeatMode = prevEntropy->fse.matchlength_repeatMode;
+ MLtype = ZSTD_selectEncodingType(&nextEntropy->fse.matchlength_repeatMode,
+ count, max, mostFrequent, nbSeq,
+ MLFSELog, prevEntropy->fse.matchlengthCTable,
+ ML_defaultNorm, ML_defaultNormLog,
+ ZSTD_defaultAllowed, strategy);
+ assert(!(MLtype < set_compressed && nextEntropy->fse.matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
+ { size_t const countSize = ZSTD_buildCTable(
+ op, (size_t)(oend - op),
+ CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype,
+ count, max, mlCodeTable, nbSeq,
+ ML_defaultNorm, ML_defaultNormLog, MaxML,
+ prevEntropy->fse.matchlengthCTable,
+ sizeof(prevEntropy->fse.matchlengthCTable),
+ entropyWorkspace, entropyWkspSize);
+ FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for MatchLengths failed");
+ if (MLtype == set_compressed)
+ lastNCount = op;
+ op += countSize;
+ assert(op <= oend);
+ } }
+
+ *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
+
+ { size_t const bitstreamSize = ZSTD_encodeSequences(
+ op, (size_t)(oend - op),
+ CTable_MatchLength, mlCodeTable,
+ CTable_OffsetBits, ofCodeTable,
+ CTable_LitLength, llCodeTable,
+ sequences, nbSeq,
+ longOffsets, bmi2);
+ FORWARD_IF_ERROR(bitstreamSize, "ZSTD_encodeSequences failed");
+ op += bitstreamSize;
+ assert(op <= oend);
+ /* zstd versions <= 1.3.4 mistakenly report corruption when
+ * FSE_readNCount() receives a buffer < 4 bytes.
+ * Fixed by https://github.com/facebook/zstd/pull/1146.
+ * This can happen when the last set_compressed table present is 2
+ * bytes and the bitstream is only one byte.
+ * In this exceedingly rare case, we will simply emit an uncompressed
+ * block, since it isn't worth optimizing.
+ */
+ if (lastNCount && (op - lastNCount) < 4) {
+ /* NCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */
+ assert(op - lastNCount == 3);
+ DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.3.4 by "
+ "emitting an uncompressed block.");
+ return 0;
+ }
+ }
+
+ DEBUGLOG(5, "compressed block size : %u", (unsigned)(op - ostart));
+ return (size_t)(op - ostart);
+}
+
+MEM_STATIC size_t
+ZSTD_compressSequences(seqStore_t* seqStorePtr,
+ const ZSTD_entropyCTables_t* prevEntropy,
+ ZSTD_entropyCTables_t* nextEntropy,
+ const ZSTD_CCtx_params* cctxParams,
+ void* dst, size_t dstCapacity,
+ size_t srcSize,
+ void* entropyWorkspace, size_t entropyWkspSize,
+ int bmi2)
+{
+ size_t const cSize = ZSTD_compressSequences_internal(
+ seqStorePtr, prevEntropy, nextEntropy, cctxParams,
+ dst, dstCapacity,
+ entropyWorkspace, entropyWkspSize, bmi2);
+ if (cSize == 0) return 0;
+ /* When srcSize <= dstCapacity, there is enough space to write a raw uncompressed block.
+ * Since we ran out of space, block must be not compressible, so fall back to raw uncompressed block.
+ */
+ if ((cSize == ERROR(dstSize_tooSmall)) & (srcSize <= dstCapacity))
+ return 0; /* block not compressed */
+ FORWARD_IF_ERROR(cSize, "ZSTD_compressSequences_internal failed");
+
+ /* Check compressibility */
+ { size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, cctxParams->cParams.strategy);
+ if (cSize >= maxCSize) return 0; /* block not compressed */
+ }
+
+ return cSize;
+}
+
+/* ZSTD_selectBlockCompressor() :
+ * Not static, but internal use only (used by long distance matcher)
+ * assumption : strat is a valid strategy */
+ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode)
+{
+ static const ZSTD_blockCompressor blockCompressor[3][ZSTD_STRATEGY_MAX+1] = {
+ { ZSTD_compressBlock_fast /* default for 0 */,
+ ZSTD_compressBlock_fast,
+ ZSTD_compressBlock_doubleFast,
+ ZSTD_compressBlock_greedy,
+ ZSTD_compressBlock_lazy,
+ ZSTD_compressBlock_lazy2,
+ ZSTD_compressBlock_btlazy2,
+ ZSTD_compressBlock_btopt,
+ ZSTD_compressBlock_btultra,
+ ZSTD_compressBlock_btultra2 },
+ { ZSTD_compressBlock_fast_extDict /* default for 0 */,
+ ZSTD_compressBlock_fast_extDict,
+ ZSTD_compressBlock_doubleFast_extDict,
+ ZSTD_compressBlock_greedy_extDict,
+ ZSTD_compressBlock_lazy_extDict,
+ ZSTD_compressBlock_lazy2_extDict,
+ ZSTD_compressBlock_btlazy2_extDict,
+ ZSTD_compressBlock_btopt_extDict,
+ ZSTD_compressBlock_btultra_extDict,
+ ZSTD_compressBlock_btultra_extDict },
+ { ZSTD_compressBlock_fast_dictMatchState /* default for 0 */,
+ ZSTD_compressBlock_fast_dictMatchState,
+ ZSTD_compressBlock_doubleFast_dictMatchState,
+ ZSTD_compressBlock_greedy_dictMatchState,
+ ZSTD_compressBlock_lazy_dictMatchState,
+ ZSTD_compressBlock_lazy2_dictMatchState,
+ ZSTD_compressBlock_btlazy2_dictMatchState,
+ ZSTD_compressBlock_btopt_dictMatchState,
+ ZSTD_compressBlock_btultra_dictMatchState,
+ ZSTD_compressBlock_btultra_dictMatchState }
+ };
+ ZSTD_blockCompressor selectedCompressor;
+ ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1);
+
+ assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, strat));
+ selectedCompressor = blockCompressor[(int)dictMode][(int)strat];
+ assert(selectedCompressor != NULL);
+ return selectedCompressor;
+}
+
+static void ZSTD_storeLastLiterals(seqStore_t* seqStorePtr,
+ const BYTE* anchor, size_t lastLLSize)
+{
+ memcpy(seqStorePtr->lit, anchor, lastLLSize);
+ seqStorePtr->lit += lastLLSize;
+}
+
+void ZSTD_resetSeqStore(seqStore_t* ssPtr)
+{
+ ssPtr->lit = ssPtr->litStart;
+ ssPtr->sequences = ssPtr->sequencesStart;
+ ssPtr->longLengthID = 0;
+}
+
+typedef enum { ZSTDbss_compress, ZSTDbss_noCompress } ZSTD_buildSeqStore_e;
+
+static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize)
+{
+ ZSTD_matchState_t* const ms = &zc->blockState.matchState;
+ DEBUGLOG(5, "ZSTD_buildSeqStore (srcSize=%zu)", srcSize);
+ assert(srcSize <= ZSTD_BLOCKSIZE_MAX);
+ /* Assert that we have correctly flushed the ctx params into the ms's copy */
+ ZSTD_assertEqualCParams(zc->appliedParams.cParams, ms->cParams);
+ if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) {
+ ZSTD_ldm_skipSequences(&zc->externSeqStore, srcSize, zc->appliedParams.cParams.minMatch);
+ return ZSTDbss_noCompress; /* don't even attempt compression below a certain srcSize */
+ }
+ ZSTD_resetSeqStore(&(zc->seqStore));
+ /* required for optimal parser to read stats from dictionary */
+ ms->opt.symbolCosts = &zc->blockState.prevCBlock->entropy;
+ /* tell the optimal parser how we expect to compress literals */
+ ms->opt.literalCompressionMode = zc->appliedParams.literalCompressionMode;
+ /* a gap between an attached dict and the current window is not safe,
+ * they must remain adjacent,
+ * and when that stops being the case, the dict must be unset */
+ assert(ms->dictMatchState == NULL || ms->loadedDictEnd == ms->window.dictLimit);
+
+ /* limited update after a very long match */
+ { const BYTE* const base = ms->window.base;
+ const BYTE* const istart = (const BYTE*)src;
+ const U32 current = (U32)(istart-base);
+ if (sizeof(ptrdiff_t)==8) assert(istart - base < (ptrdiff_t)(U32)(-1)); /* ensure no overflow */
+ if (current > ms->nextToUpdate + 384)
+ ms->nextToUpdate = current - MIN(192, (U32)(current - ms->nextToUpdate - 384));
+ }
+
+ /* select and store sequences */
+ { ZSTD_dictMode_e const dictMode = ZSTD_matchState_dictMode(ms);
+ size_t lastLLSize;
+ { int i;
+ for (i = 0; i < ZSTD_REP_NUM; ++i)
+ zc->blockState.nextCBlock->rep[i] = zc->blockState.prevCBlock->rep[i];
+ }
+ if (zc->externSeqStore.pos < zc->externSeqStore.size) {
+ assert(!zc->appliedParams.ldmParams.enableLdm);
+ /* Updates ldmSeqStore.pos */
+ lastLLSize =
+ ZSTD_ldm_blockCompress(&zc->externSeqStore,
+ ms, &zc->seqStore,
+ zc->blockState.nextCBlock->rep,
+ src, srcSize);
+ assert(zc->externSeqStore.pos <= zc->externSeqStore.size);
+ } else if (zc->appliedParams.ldmParams.enableLdm) {
+ rawSeqStore_t ldmSeqStore = {NULL, 0, 0, 0};
+
+ ldmSeqStore.seq = zc->ldmSequences;
+ ldmSeqStore.capacity = zc->maxNbLdmSequences;
+ /* Updates ldmSeqStore.size */
+ FORWARD_IF_ERROR(ZSTD_ldm_generateSequences(&zc->ldmState, &ldmSeqStore,
+ &zc->appliedParams.ldmParams,
+ src, srcSize), "");
+ /* Updates ldmSeqStore.pos */
+ lastLLSize =
+ ZSTD_ldm_blockCompress(&ldmSeqStore,
+ ms, &zc->seqStore,
+ zc->blockState.nextCBlock->rep,
+ src, srcSize);
+ assert(ldmSeqStore.pos == ldmSeqStore.size);
+ } else { /* not long range mode */
+ ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, dictMode);
+ lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, src, srcSize);
+ }
+ { const BYTE* const lastLiterals = (const BYTE*)src + srcSize - lastLLSize;
+ ZSTD_storeLastLiterals(&zc->seqStore, lastLiterals, lastLLSize);
+ } }
+ return ZSTDbss_compress;
+}
+
+static void ZSTD_copyBlockSequences(ZSTD_CCtx* zc)
+{
+ const seqStore_t* seqStore = ZSTD_getSeqStore(zc);
+ const seqDef* seqs = seqStore->sequencesStart;
+ size_t seqsSize = seqStore->sequences - seqs;
+
+ ZSTD_Sequence* outSeqs = &zc->seqCollector.seqStart[zc->seqCollector.seqIndex];
+ size_t i; size_t position; int repIdx;
+
+ assert(zc->seqCollector.seqIndex + 1 < zc->seqCollector.maxSequences);
+ for (i = 0, position = 0; i < seqsSize; ++i) {
+ outSeqs[i].offset = seqs[i].offset;
+ outSeqs[i].litLength = seqs[i].litLength;
+ outSeqs[i].matchLength = seqs[i].matchLength + MINMATCH;
+
+ if (i == seqStore->longLengthPos) {
+ if (seqStore->longLengthID == 1) {
+ outSeqs[i].litLength += 0x10000;
+ } else if (seqStore->longLengthID == 2) {
+ outSeqs[i].matchLength += 0x10000;
+ }
+ }
+
+ if (outSeqs[i].offset <= ZSTD_REP_NUM) {
+ outSeqs[i].rep = outSeqs[i].offset;
+ repIdx = (unsigned int)i - outSeqs[i].offset;
+
+ if (outSeqs[i].litLength == 0) {
+ if (outSeqs[i].offset < 3) {
+ --repIdx;
+ } else {
+ repIdx = (unsigned int)i - 1;
+ }
+ ++outSeqs[i].rep;
+ }
+ assert(repIdx >= -3);
+ outSeqs[i].offset = repIdx >= 0 ? outSeqs[repIdx].offset : repStartValue[-repIdx - 1];
+ if (outSeqs[i].rep == 4) {
+ --outSeqs[i].offset;
+ }
+ } else {
+ outSeqs[i].offset -= ZSTD_REP_NUM;
+ }
+
+ position += outSeqs[i].litLength;
+ outSeqs[i].matchPos = (unsigned int)position;
+ position += outSeqs[i].matchLength;
+ }
+ zc->seqCollector.seqIndex += seqsSize;
+}
+
+size_t ZSTD_getSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs,
+ size_t outSeqsSize, const void* src, size_t srcSize)
+{
+ const size_t dstCapacity = ZSTD_compressBound(srcSize);
+ void* dst = ZSTD_malloc(dstCapacity, ZSTD_defaultCMem);
+ SeqCollector seqCollector;
+
+ RETURN_ERROR_IF(dst == NULL, memory_allocation, "NULL pointer!");
+
+ seqCollector.collectSequences = 1;
+ seqCollector.seqStart = outSeqs;
+ seqCollector.seqIndex = 0;
+ seqCollector.maxSequences = outSeqsSize;
+ zc->seqCollector = seqCollector;
+
+ ZSTD_compress2(zc, dst, dstCapacity, src, srcSize);
+ ZSTD_free(dst, ZSTD_defaultCMem);
+ return zc->seqCollector.seqIndex;
+}
+
+/* Returns true if the given block is a RLE block */
+static int ZSTD_isRLE(const BYTE *ip, size_t length) {
+ size_t i;
+ if (length < 2) return 1;
+ for (i = 1; i < length; ++i) {
+ if (ip[0] != ip[i]) return 0;
+ }
+ return 1;
+}
+
+/* Returns true if the given block may be RLE.
+ * This is just a heuristic based on the compressibility.
+ * It may return both false positives and false negatives.
+ */
+static int ZSTD_maybeRLE(seqStore_t const* seqStore)
+{
+ size_t const nbSeqs = (size_t)(seqStore->sequences - seqStore->sequencesStart);
+ size_t const nbLits = (size_t)(seqStore->lit - seqStore->litStart);
+
+ return nbSeqs < 4 && nbLits < 10;
+}
+
+static void ZSTD_confirmRepcodesAndEntropyTables(ZSTD_CCtx* zc)
+{
+ ZSTD_compressedBlockState_t* const tmp = zc->blockState.prevCBlock;
+ zc->blockState.prevCBlock = zc->blockState.nextCBlock;
+ zc->blockState.nextCBlock = tmp;
+}
+
+static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize, U32 frame)
+{
+ /* This the upper bound for the length of an rle block.
+ * This isn't the actual upper bound. Finding the real threshold
+ * needs further investigation.
+ */
+ const U32 rleMaxLength = 25;
+ size_t cSize;
+ const BYTE* ip = (const BYTE*)src;
+ BYTE* op = (BYTE*)dst;
+ DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)",
+ (unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit,
+ (unsigned)zc->blockState.matchState.nextToUpdate);
+
+ { const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize);
+ FORWARD_IF_ERROR(bss, "ZSTD_buildSeqStore failed");
+ if (bss == ZSTDbss_noCompress) { cSize = 0; goto out; }
+ }
+
+ if (zc->seqCollector.collectSequences) {
+ ZSTD_copyBlockSequences(zc);
+ return 0;
+ }
+
+ /* encode sequences and literals */
+ cSize = ZSTD_compressSequences(&zc->seqStore,
+ &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy,
+ &zc->appliedParams,
+ dst, dstCapacity,
+ srcSize,
+ zc->entropyWorkspace, HUF_WORKSPACE_SIZE /* statically allocated in resetCCtx */,
+ zc->bmi2);
+
+ if (frame &&
+ /* We don't want to emit our first block as a RLE even if it qualifies because
+ * doing so will cause the decoder (cli only) to throw a "should consume all input error."
+ * This is only an issue for zstd <= v1.4.3
+ */
+ !zc->isFirstBlock &&
+ cSize < rleMaxLength &&
+ ZSTD_isRLE(ip, srcSize))
+ {
+ cSize = 1;
+ op[0] = ip[0];
+ }
+
+out:
+ if (!ZSTD_isError(cSize) && cSize > 1) {
+ ZSTD_confirmRepcodesAndEntropyTables(zc);
+ }
+ /* We check that dictionaries have offset codes available for the first
+ * block. After the first block, the offcode table might not have large
+ * enough codes to represent the offsets in the data.
+ */
+ if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid)
+ zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check;
+
+ return cSize;
+}
+
+static size_t ZSTD_compressBlock_targetCBlockSize_body(ZSTD_CCtx* zc,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const size_t bss, U32 lastBlock)
+{
+ DEBUGLOG(6, "Attempting ZSTD_compressSuperBlock()");
+ if (bss == ZSTDbss_compress) {
+ if (/* We don't want to emit our first block as a RLE even if it qualifies because
+ * doing so will cause the decoder (cli only) to throw a "should consume all input error."
+ * This is only an issue for zstd <= v1.4.3
+ */
+ !zc->isFirstBlock &&
+ ZSTD_maybeRLE(&zc->seqStore) &&
+ ZSTD_isRLE((BYTE const*)src, srcSize))
+ {
+ return ZSTD_rleCompressBlock(dst, dstCapacity, *(BYTE const*)src, srcSize, lastBlock);
+ }
+ /* Attempt superblock compression.
+ *
+ * Note that compressed size of ZSTD_compressSuperBlock() is not bound by the
+ * standard ZSTD_compressBound(). This is a problem, because even if we have
+ * space now, taking an extra byte now could cause us to run out of space later
+ * and violate ZSTD_compressBound().
+ *
+ * Define blockBound(blockSize) = blockSize + ZSTD_blockHeaderSize.
+ *
+ * In order to respect ZSTD_compressBound() we must attempt to emit a raw
+ * uncompressed block in these cases:
+ * * cSize == 0: Return code for an uncompressed block.
+ * * cSize == dstSize_tooSmall: We may have expanded beyond blockBound(srcSize).
+ * ZSTD_noCompressBlock() will return dstSize_tooSmall if we are really out of
+ * output space.
+ * * cSize >= blockBound(srcSize): We have expanded the block too much so
+ * emit an uncompressed block.
+ */
+ {
+ size_t const cSize = ZSTD_compressSuperBlock(zc, dst, dstCapacity, src, srcSize, lastBlock);
+ if (cSize != ERROR(dstSize_tooSmall)) {
+ size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, zc->appliedParams.cParams.strategy);
+ FORWARD_IF_ERROR(cSize, "ZSTD_compressSuperBlock failed");
+ if (cSize != 0 && cSize < maxCSize + ZSTD_blockHeaderSize) {
+ ZSTD_confirmRepcodesAndEntropyTables(zc);
+ return cSize;
+ }
+ }
+ }
+ }
+
+ DEBUGLOG(6, "Resorting to ZSTD_noCompressBlock()");
+ /* Superblock compression failed, attempt to emit a single no compress block.
+ * The decoder will be able to stream this block since it is uncompressed.
+ */
+ return ZSTD_noCompressBlock(dst, dstCapacity, src, srcSize, lastBlock);
+}
+
+static size_t ZSTD_compressBlock_targetCBlockSize(ZSTD_CCtx* zc,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ U32 lastBlock)
+{
+ size_t cSize = 0;
+ const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize);
+ DEBUGLOG(5, "ZSTD_compressBlock_targetCBlockSize (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u, srcSize=%zu)",
+ (unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit, (unsigned)zc->blockState.matchState.nextToUpdate, srcSize);
+ FORWARD_IF_ERROR(bss, "ZSTD_buildSeqStore failed");
+
+ cSize = ZSTD_compressBlock_targetCBlockSize_body(zc, dst, dstCapacity, src, srcSize, bss, lastBlock);
+ FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_targetCBlockSize_body failed");
+
+ if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid)
+ zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check;
+
+ return cSize;
+}
+
+static void ZSTD_overflowCorrectIfNeeded(ZSTD_matchState_t* ms,
+ ZSTD_cwksp* ws,
+ ZSTD_CCtx_params const* params,
+ void const* ip,
+ void const* iend)
+{
+ if (ZSTD_window_needOverflowCorrection(ms->window, iend)) {
+ U32 const maxDist = (U32)1 << params->cParams.windowLog;
+ U32 const cycleLog = ZSTD_cycleLog(params->cParams.chainLog, params->cParams.strategy);
+ U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, maxDist, ip);
+ ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30);
+ ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30);
+ ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31);
+ ZSTD_cwksp_mark_tables_dirty(ws);
+ ZSTD_reduceIndex(ms, params, correction);
+ ZSTD_cwksp_mark_tables_clean(ws);
+ if (ms->nextToUpdate < correction) ms->nextToUpdate = 0;
+ else ms->nextToUpdate -= correction;
+ /* invalidate dictionaries on overflow correction */
+ ms->loadedDictEnd = 0;
+ ms->dictMatchState = NULL;
+ }
+}
+
+/*! ZSTD_compress_frameChunk() :
+* Compress a chunk of data into one or multiple blocks.
+* All blocks will be terminated, all input will be consumed.
+* Function will issue an error if there is not enough `dstCapacity` to hold the compressed content.
+* Frame is supposed already started (header already produced)
+* @return : compressed size, or an error code
+*/
+static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ U32 lastFrameChunk)
+{
+ size_t blockSize = cctx->blockSize;
+ size_t remaining = srcSize;
+ const BYTE* ip = (const BYTE*)src;
+ BYTE* const ostart = (BYTE*)dst;
+ BYTE* op = ostart;
+ U32 const maxDist = (U32)1 << cctx->appliedParams.cParams.windowLog;
+
+ assert(cctx->appliedParams.cParams.windowLog <= ZSTD_WINDOWLOG_MAX);
+
+ DEBUGLOG(5, "ZSTD_compress_frameChunk (blockSize=%u)", (unsigned)blockSize);
+ if (cctx->appliedParams.fParams.checksumFlag && srcSize)
+ XXH64_update(&cctx->xxhState, src, srcSize);
+
+ while (remaining) {
+ ZSTD_matchState_t* const ms = &cctx->blockState.matchState;
+ U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
+
+ RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE,
+ dstSize_tooSmall,
+ "not enough space to store compressed block");
+ if (remaining < blockSize) blockSize = remaining;
+
+ ZSTD_overflowCorrectIfNeeded(
+ ms, &cctx->workspace, &cctx->appliedParams, ip, ip + blockSize);
+ ZSTD_checkDictValidity(&ms->window, ip + blockSize, maxDist, &ms->loadedDictEnd, &ms->dictMatchState);
+
+ /* Ensure hash/chain table insertion resumes no sooner than lowlimit */
+ if (ms->nextToUpdate < ms->window.lowLimit) ms->nextToUpdate = ms->window.lowLimit;
+
+ { size_t cSize;
+ if (ZSTD_useTargetCBlockSize(&cctx->appliedParams)) {
+ cSize = ZSTD_compressBlock_targetCBlockSize(cctx, op, dstCapacity, ip, blockSize, lastBlock);
+ FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_targetCBlockSize failed");
+ assert(cSize > 0);
+ assert(cSize <= blockSize + ZSTD_blockHeaderSize);
+ } else {
+ cSize = ZSTD_compressBlock_internal(cctx,
+ op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize,
+ ip, blockSize, 1 /* frame */);
+ FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_internal failed");
+
+ if (cSize == 0) { /* block is not compressible */
+ cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock);
+ FORWARD_IF_ERROR(cSize, "ZSTD_noCompressBlock failed");
+ } else {
+ U32 const cBlockHeader = cSize == 1 ?
+ lastBlock + (((U32)bt_rle)<<1) + (U32)(blockSize << 3) :
+ lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
+ MEM_writeLE24(op, cBlockHeader);
+ cSize += ZSTD_blockHeaderSize;
+ }
+ }
+
+
+ ip += blockSize;
+ assert(remaining >= blockSize);
+ remaining -= blockSize;
+ op += cSize;
+ assert(dstCapacity >= cSize);
+ dstCapacity -= cSize;
+ cctx->isFirstBlock = 0;
+ DEBUGLOG(5, "ZSTD_compress_frameChunk: adding a block of size %u",
+ (unsigned)cSize);
+ } }
+
+ if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending;
+ return (size_t)(op-ostart);
+}
+
+
+static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
+ const ZSTD_CCtx_params* params, U64 pledgedSrcSize, U32 dictID)
+{ BYTE* const op = (BYTE*)dst;
+ U32 const dictIDSizeCodeLength = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */
+ U32 const dictIDSizeCode = params->fParams.noDictIDFlag ? 0 : dictIDSizeCodeLength; /* 0-3 */
+ U32 const checksumFlag = params->fParams.checksumFlag>0;
+ U32 const windowSize = (U32)1 << params->cParams.windowLog;
+ U32 const singleSegment = params->fParams.contentSizeFlag && (windowSize >= pledgedSrcSize);
+ BYTE const windowLogByte = (BYTE)((params->cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);
+ U32 const fcsCode = params->fParams.contentSizeFlag ?
+ (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : 0; /* 0-3 */
+ BYTE const frameHeaderDescriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) );
+ size_t pos=0;
+
+ assert(!(params->fParams.contentSizeFlag && pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN));
+ RETURN_ERROR_IF(dstCapacity < ZSTD_FRAMEHEADERSIZE_MAX, dstSize_tooSmall,
+ "dst buf is too small to fit worst-case frame header size.");
+ DEBUGLOG(4, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u",
+ !params->fParams.noDictIDFlag, (unsigned)dictID, (unsigned)dictIDSizeCode);
+
+ if (params->format == ZSTD_f_zstd1) {
+ MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
+ pos = 4;
+ }
+ op[pos++] = frameHeaderDescriptionByte;
+ if (!singleSegment) op[pos++] = windowLogByte;
+ switch(dictIDSizeCode)
+ {
+ default: assert(0); /* impossible */
+ case 0 : break;
+ case 1 : op[pos] = (BYTE)(dictID); pos++; break;
+ case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break;
+ case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break;
+ }
+ switch(fcsCode)
+ {
+ default: assert(0); /* impossible */
+ case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break;
+ case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break;
+ case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break;
+ case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break;
+ }
+ return pos;
+}
+
+/* ZSTD_writeLastEmptyBlock() :
+ * output an empty Block with end-of-frame mark to complete a frame
+ * @return : size of data written into `dst` (== ZSTD_blockHeaderSize (defined in zstd_internal.h))
+ * or an error code if `dstCapacity` is too small (<ZSTD_blockHeaderSize)
+ */
+size_t ZSTD_writeLastEmptyBlock(void* dst, size_t dstCapacity)
+{
+ RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize, dstSize_tooSmall,
+ "dst buf is too small to write frame trailer empty block.");
+ { U32 const cBlockHeader24 = 1 /*lastBlock*/ + (((U32)bt_raw)<<1); /* 0 size */
+ MEM_writeLE24(dst, cBlockHeader24);
+ return ZSTD_blockHeaderSize;
+ }
+}
+
+size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq)
+{
+ RETURN_ERROR_IF(cctx->stage != ZSTDcs_init, stage_wrong,
+ "wrong cctx stage");
+ RETURN_ERROR_IF(cctx->appliedParams.ldmParams.enableLdm,
+ parameter_unsupported,
+ "incompatible with ldm");
+ cctx->externSeqStore.seq = seq;
+ cctx->externSeqStore.size = nbSeq;
+ cctx->externSeqStore.capacity = nbSeq;
+ cctx->externSeqStore.pos = 0;
+ return 0;
+}
+
+
+static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ U32 frame, U32 lastFrameChunk)
+{
+ ZSTD_matchState_t* const ms = &cctx->blockState.matchState;
+ size_t fhSize = 0;
+
+ DEBUGLOG(5, "ZSTD_compressContinue_internal, stage: %u, srcSize: %u",
+ cctx->stage, (unsigned)srcSize);
+ RETURN_ERROR_IF(cctx->stage==ZSTDcs_created, stage_wrong,
+ "missing init (ZSTD_compressBegin)");
+
+ if (frame && (cctx->stage==ZSTDcs_init)) {
+ fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, &cctx->appliedParams,
+ cctx->pledgedSrcSizePlusOne-1, cctx->dictID);
+ FORWARD_IF_ERROR(fhSize, "ZSTD_writeFrameHeader failed");
+ assert(fhSize <= dstCapacity);
+ dstCapacity -= fhSize;
+ dst = (char*)dst + fhSize;
+ cctx->stage = ZSTDcs_ongoing;
+ }
+
+ if (!srcSize) return fhSize; /* do not generate an empty block if no input */
+
+ if (!ZSTD_window_update(&ms->window, src, srcSize)) {
+ ms->nextToUpdate = ms->window.dictLimit;
+ }
+ if (cctx->appliedParams.ldmParams.enableLdm) {
+ ZSTD_window_update(&cctx->ldmState.window, src, srcSize);
+ }
+
+ if (!frame) {
+ /* overflow check and correction for block mode */
+ ZSTD_overflowCorrectIfNeeded(
+ ms, &cctx->workspace, &cctx->appliedParams,
+ src, (BYTE const*)src + srcSize);
+ }
+
+ DEBUGLOG(5, "ZSTD_compressContinue_internal (blockSize=%u)", (unsigned)cctx->blockSize);
+ { size_t const cSize = frame ?
+ ZSTD_compress_frameChunk (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) :
+ ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize, 0 /* frame */);
+ FORWARD_IF_ERROR(cSize, "%s", frame ? "ZSTD_compress_frameChunk failed" : "ZSTD_compressBlock_internal failed");
+ cctx->consumedSrcSize += srcSize;
+ cctx->producedCSize += (cSize + fhSize);
+ assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0));
+ if (cctx->pledgedSrcSizePlusOne != 0) { /* control src size */
+ ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (unsigned long long)-1);
+ RETURN_ERROR_IF(
+ cctx->consumedSrcSize+1 > cctx->pledgedSrcSizePlusOne,
+ srcSize_wrong,
+ "error : pledgedSrcSize = %u, while realSrcSize >= %u",
+ (unsigned)cctx->pledgedSrcSizePlusOne-1,
+ (unsigned)cctx->consumedSrcSize);
+ }
+ return cSize + fhSize;
+ }
+}
+
+size_t ZSTD_compressContinue (ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize)
+{
+ DEBUGLOG(5, "ZSTD_compressContinue (srcSize=%u)", (unsigned)srcSize);
+ return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 0 /* last chunk */);
+}
+
+
+size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx)
+{
+ ZSTD_compressionParameters const cParams = cctx->appliedParams.cParams;
+ assert(!ZSTD_checkCParams(cParams));
+ return MIN (ZSTD_BLOCKSIZE_MAX, (U32)1 << cParams.windowLog);
+}
+
+size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+{
+ DEBUGLOG(5, "ZSTD_compressBlock: srcSize = %u", (unsigned)srcSize);
+ { size_t const blockSizeMax = ZSTD_getBlockSize(cctx);
+ RETURN_ERROR_IF(srcSize > blockSizeMax, srcSize_wrong, "input is larger than a block"); }
+
+ return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0 /* frame mode */, 0 /* last chunk */);
+}
+
+/*! ZSTD_loadDictionaryContent() :
+ * @return : 0, or an error code
+ */
+static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms,
+ ldmState_t* ls,
+ ZSTD_cwksp* ws,
+ ZSTD_CCtx_params const* params,
+ const void* src, size_t srcSize,
+ ZSTD_dictTableLoadMethod_e dtlm)
+{
+ const BYTE* ip = (const BYTE*) src;
+ const BYTE* const iend = ip + srcSize;
+
+ ZSTD_window_update(&ms->window, src, srcSize);
+ ms->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ms->window.base);
+
+ if (params->ldmParams.enableLdm && ls != NULL) {
+ ZSTD_window_update(&ls->window, src, srcSize);
+ ls->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ls->window.base);
+ }
+
+ /* Assert that we the ms params match the params we're being given */
+ ZSTD_assertEqualCParams(params->cParams, ms->cParams);
+
+ if (srcSize <= HASH_READ_SIZE) return 0;
+
+ while (iend - ip > HASH_READ_SIZE) {
+ size_t const remaining = (size_t)(iend - ip);
+ size_t const chunk = MIN(remaining, ZSTD_CHUNKSIZE_MAX);
+ const BYTE* const ichunk = ip + chunk;
+
+ ZSTD_overflowCorrectIfNeeded(ms, ws, params, ip, ichunk);
+
+ if (params->ldmParams.enableLdm && ls != NULL)
+ ZSTD_ldm_fillHashTable(ls, (const BYTE*)src, (const BYTE*)src + srcSize, &params->ldmParams);
+
+ switch(params->cParams.strategy)
+ {
+ case ZSTD_fast:
+ ZSTD_fillHashTable(ms, ichunk, dtlm);
+ break;
+ case ZSTD_dfast:
+ ZSTD_fillDoubleHashTable(ms, ichunk, dtlm);
+ break;
+
+ case ZSTD_greedy:
+ case ZSTD_lazy:
+ case ZSTD_lazy2:
+ if (chunk >= HASH_READ_SIZE)
+ ZSTD_insertAndFindFirstIndex(ms, ichunk-HASH_READ_SIZE);
+ break;
+
+ case ZSTD_btlazy2: /* we want the dictionary table fully sorted */
+ case ZSTD_btopt:
+ case ZSTD_btultra:
+ case ZSTD_btultra2:
+ if (chunk >= HASH_READ_SIZE)
+ ZSTD_updateTree(ms, ichunk-HASH_READ_SIZE, ichunk);
+ break;
+
+ default:
+ assert(0); /* not possible : not a valid strategy id */
+ }
+
+ ip = ichunk;
+ }
+
+ ms->nextToUpdate = (U32)(iend - ms->window.base);
+ return 0;
+}
+
+
+/* Dictionaries that assign zero probability to symbols that show up causes problems
+ when FSE encoding. Refuse dictionaries that assign zero probability to symbols
+ that we may encounter during compression.
+ NOTE: This behavior is not standard and could be improved in the future. */
+static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) {
+ U32 s;
+ RETURN_ERROR_IF(dictMaxSymbolValue < maxSymbolValue, dictionary_corrupted, "dict fse tables don't have all symbols");
+ for (s = 0; s <= maxSymbolValue; ++s) {
+ RETURN_ERROR_IF(normalizedCounter[s] == 0, dictionary_corrupted, "dict fse tables don't have all symbols");
+ }
+ return 0;
+}
+
+size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace,
+ short* offcodeNCount, unsigned* offcodeMaxValue,
+ const void* const dict, size_t dictSize)
+{
+ const BYTE* dictPtr = (const BYTE*)dict; /* skip magic num and dict ID */
+ const BYTE* const dictEnd = dictPtr + dictSize;
+ dictPtr += 8;
+ bs->entropy.huf.repeatMode = HUF_repeat_check;
+
+ { unsigned maxSymbolValue = 255;
+ unsigned hasZeroWeights = 1;
+ size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)bs->entropy.huf.CTable, &maxSymbolValue, dictPtr,
+ dictEnd-dictPtr, &hasZeroWeights);
+
+ /* We only set the loaded table as valid if it contains all non-zero
+ * weights. Otherwise, we set it to check */
+ if (!hasZeroWeights)
+ bs->entropy.huf.repeatMode = HUF_repeat_valid;
+
+ RETURN_ERROR_IF(HUF_isError(hufHeaderSize), dictionary_corrupted, "");
+ RETURN_ERROR_IF(maxSymbolValue < 255, dictionary_corrupted, "");
+ dictPtr += hufHeaderSize;
+ }
+
+ { unsigned offcodeLog;
+ size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
+ RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted, "");
+ RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted, "");
+ /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
+ /* fill all offset symbols to avoid garbage at end of table */
+ RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp(
+ bs->entropy.fse.offcodeCTable,
+ offcodeNCount, MaxOff, offcodeLog,
+ workspace, HUF_WORKSPACE_SIZE)),
+ dictionary_corrupted, "");
+ dictPtr += offcodeHeaderSize;
+ }
+
+ { short matchlengthNCount[MaxML+1];
+ unsigned matchlengthMaxValue = MaxML, matchlengthLog;
+ size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
+ RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted, "");
+ RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted, "");
+ /* Every match length code must have non-zero probability */
+ FORWARD_IF_ERROR( ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML), "");
+ RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp(
+ bs->entropy.fse.matchlengthCTable,
+ matchlengthNCount, matchlengthMaxValue, matchlengthLog,
+ workspace, HUF_WORKSPACE_SIZE)),
+ dictionary_corrupted, "");
+ dictPtr += matchlengthHeaderSize;
+ }
+
+ { short litlengthNCount[MaxLL+1];
+ unsigned litlengthMaxValue = MaxLL, litlengthLog;
+ size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
+ RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted, "");
+ RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted, "");
+ /* Every literal length code must have non-zero probability */
+ FORWARD_IF_ERROR( ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL), "");
+ RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp(
+ bs->entropy.fse.litlengthCTable,
+ litlengthNCount, litlengthMaxValue, litlengthLog,
+ workspace, HUF_WORKSPACE_SIZE)),
+ dictionary_corrupted, "");
+ dictPtr += litlengthHeaderSize;
+ }
+
+ RETURN_ERROR_IF(dictPtr+12 > dictEnd, dictionary_corrupted, "");
+ bs->rep[0] = MEM_readLE32(dictPtr+0);
+ bs->rep[1] = MEM_readLE32(dictPtr+4);
+ bs->rep[2] = MEM_readLE32(dictPtr+8);
+ dictPtr += 12;
+
+ return dictPtr - (const BYTE*)dict;
+}
+
+/* Dictionary format :
+ * See :
+ * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format
+ */
+/*! ZSTD_loadZstdDictionary() :
+ * @return : dictID, or an error code
+ * assumptions : magic number supposed already checked
+ * dictSize supposed >= 8
+ */
+static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs,
+ ZSTD_matchState_t* ms,
+ ZSTD_cwksp* ws,
+ ZSTD_CCtx_params const* params,
+ const void* dict, size_t dictSize,
+ ZSTD_dictTableLoadMethod_e dtlm,
+ void* workspace)
+{
+ const BYTE* dictPtr = (const BYTE*)dict;
+ const BYTE* const dictEnd = dictPtr + dictSize;
+ short offcodeNCount[MaxOff+1];
+ unsigned offcodeMaxValue = MaxOff;
+ size_t dictID;
+ size_t eSize;
+
+ ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog)));
+ assert(dictSize >= 8);
+ assert(MEM_readLE32(dictPtr) == ZSTD_MAGIC_DICTIONARY);
+
+ dictID = params->fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr + 4 /* skip magic number */ );
+ eSize = ZSTD_loadCEntropy(bs, workspace, offcodeNCount, &offcodeMaxValue, dict, dictSize);
+ FORWARD_IF_ERROR(eSize, "ZSTD_loadCEntropy failed");
+ dictPtr += eSize;
+
+ { size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
+ U32 offcodeMax = MaxOff;
+ if (dictContentSize <= ((U32)-1) - 128 KB) {
+ U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */
+ offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */
+ }
+ /* All offset values <= dictContentSize + 128 KB must be representable */
+ FORWARD_IF_ERROR(ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)), "");
+ /* All repCodes must be <= dictContentSize and != 0*/
+ { U32 u;
+ for (u=0; u<3; u++) {
+ RETURN_ERROR_IF(bs->rep[u] == 0, dictionary_corrupted, "");
+ RETURN_ERROR_IF(bs->rep[u] > dictContentSize, dictionary_corrupted, "");
+ } }
+
+ bs->entropy.fse.offcode_repeatMode = FSE_repeat_valid;
+ bs->entropy.fse.matchlength_repeatMode = FSE_repeat_valid;
+ bs->entropy.fse.litlength_repeatMode = FSE_repeat_valid;
+ FORWARD_IF_ERROR(ZSTD_loadDictionaryContent(
+ ms, NULL, ws, params, dictPtr, dictContentSize, dtlm), "");
+ return dictID;
+ }
+}
+
+/** ZSTD_compress_insertDictionary() :
+* @return : dictID, or an error code */
+static size_t
+ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs,
+ ZSTD_matchState_t* ms,
+ ldmState_t* ls,
+ ZSTD_cwksp* ws,
+ const ZSTD_CCtx_params* params,
+ const void* dict, size_t dictSize,
+ ZSTD_dictContentType_e dictContentType,
+ ZSTD_dictTableLoadMethod_e dtlm,
+ void* workspace)
+{
+ DEBUGLOG(4, "ZSTD_compress_insertDictionary (dictSize=%u)", (U32)dictSize);
+ if ((dict==NULL) || (dictSize<8)) {
+ RETURN_ERROR_IF(dictContentType == ZSTD_dct_fullDict, dictionary_wrong, "");
+ return 0;
+ }
+
+ ZSTD_reset_compressedBlockState(bs);
+
+ /* dict restricted modes */
+ if (dictContentType == ZSTD_dct_rawContent)
+ return ZSTD_loadDictionaryContent(ms, ls, ws, params, dict, dictSize, dtlm);
+
+ if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) {
+ if (dictContentType == ZSTD_dct_auto) {
+ DEBUGLOG(4, "raw content dictionary detected");
+ return ZSTD_loadDictionaryContent(
+ ms, ls, ws, params, dict, dictSize, dtlm);
+ }
+ RETURN_ERROR_IF(dictContentType == ZSTD_dct_fullDict, dictionary_wrong, "");
+ assert(0); /* impossible */
+ }
+
+ /* dict as full zstd dictionary */
+ return ZSTD_loadZstdDictionary(
+ bs, ms, ws, params, dict, dictSize, dtlm, workspace);
+}
+
+#define ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF (128 KB)
+#define ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER (6)
+
+/*! ZSTD_compressBegin_internal() :
+ * @return : 0, or an error code */
+static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
+ const void* dict, size_t dictSize,
+ ZSTD_dictContentType_e dictContentType,
+ ZSTD_dictTableLoadMethod_e dtlm,
+ const ZSTD_CDict* cdict,
+ const ZSTD_CCtx_params* params, U64 pledgedSrcSize,
+ ZSTD_buffered_policy_e zbuff)
+{
+ DEBUGLOG(4, "ZSTD_compressBegin_internal: wlog=%u", params->cParams.windowLog);
+ /* params are supposed to be fully validated at this point */
+ assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams)));
+ assert(!((dict) && (cdict))); /* either dict or cdict, not both */
+ if ( (cdict)
+ && (cdict->dictContentSize > 0)
+ && ( pledgedSrcSize < ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF
+ || pledgedSrcSize < cdict->dictContentSize * ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER
+ || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN
+ || cdict->compressionLevel == 0)
+ && (params->attachDictPref != ZSTD_dictForceLoad) ) {
+ return ZSTD_resetCCtx_usingCDict(cctx, cdict, params, pledgedSrcSize, zbuff);
+ }
+
+ FORWARD_IF_ERROR( ZSTD_resetCCtx_internal(cctx, *params, pledgedSrcSize,
+ ZSTDcrp_makeClean, zbuff) , "");
+ { size_t const dictID = cdict ?
+ ZSTD_compress_insertDictionary(
+ cctx->blockState.prevCBlock, &cctx->blockState.matchState,
+ &cctx->ldmState, &cctx->workspace, &cctx->appliedParams, cdict->dictContent,
+ cdict->dictContentSize, dictContentType, dtlm,
+ cctx->entropyWorkspace)
+ : ZSTD_compress_insertDictionary(
+ cctx->blockState.prevCBlock, &cctx->blockState.matchState,
+ &cctx->ldmState, &cctx->workspace, &cctx->appliedParams, dict, dictSize,
+ dictContentType, dtlm, cctx->entropyWorkspace);
+ FORWARD_IF_ERROR(dictID, "ZSTD_compress_insertDictionary failed");
+ assert(dictID <= UINT_MAX);
+ cctx->dictID = (U32)dictID;
+ }
+ return 0;
+}
+
+size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx,
+ const void* dict, size_t dictSize,
+ ZSTD_dictContentType_e dictContentType,
+ ZSTD_dictTableLoadMethod_e dtlm,
+ const ZSTD_CDict* cdict,
+ const ZSTD_CCtx_params* params,
+ unsigned long long pledgedSrcSize)
+{
+ DEBUGLOG(4, "ZSTD_compressBegin_advanced_internal: wlog=%u", params->cParams.windowLog);
+ /* compression parameters verification and optimization */
+ FORWARD_IF_ERROR( ZSTD_checkCParams(params->cParams) , "");
+ return ZSTD_compressBegin_internal(cctx,
+ dict, dictSize, dictContentType, dtlm,
+ cdict,
+ params, pledgedSrcSize,
+ ZSTDb_not_buffered);
+}
+
+/*! ZSTD_compressBegin_advanced() :
+* @return : 0, or an error code */
+size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
+ const void* dict, size_t dictSize,
+ ZSTD_parameters params, unsigned long long pledgedSrcSize)
+{
+ ZSTD_CCtx_params const cctxParams =
+ ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, &params);
+ return ZSTD_compressBegin_advanced_internal(cctx,
+ dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast,
+ NULL /*cdict*/,
+ &cctxParams, pledgedSrcSize);
+}
+
+size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
+{
+ ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize);
+ ZSTD_CCtx_params const cctxParams =
+ ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, &params);
+ DEBUGLOG(4, "ZSTD_compressBegin_usingDict (dictSize=%u)", (unsigned)dictSize);
+ return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL,
+ &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered);
+}
+
+size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel)
+{
+ return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel);
+}
+
+
+/*! ZSTD_writeEpilogue() :
+* Ends a frame.
+* @return : nb of bytes written into dst (or an error code) */
+static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
+{
+ BYTE* const ostart = (BYTE*)dst;
+ BYTE* op = ostart;
+ size_t fhSize = 0;
+
+ DEBUGLOG(4, "ZSTD_writeEpilogue");
+ RETURN_ERROR_IF(cctx->stage == ZSTDcs_created, stage_wrong, "init missing");
+
+ /* special case : empty frame */
+ if (cctx->stage == ZSTDcs_init) {
+ fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, &cctx->appliedParams, 0, 0);
+ FORWARD_IF_ERROR(fhSize, "ZSTD_writeFrameHeader failed");
+ dstCapacity -= fhSize;
+ op += fhSize;
+ cctx->stage = ZSTDcs_ongoing;
+ }
+
+ if (cctx->stage != ZSTDcs_ending) {
+ /* write one last empty block, make it the "last" block */
+ U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0;
+ RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "no room for epilogue");
+ MEM_writeLE32(op, cBlockHeader24);
+ op += ZSTD_blockHeaderSize;
+ dstCapacity -= ZSTD_blockHeaderSize;
+ }
+
+ if (cctx->appliedParams.fParams.checksumFlag) {
+ U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
+ RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "no room for checksum");
+ DEBUGLOG(4, "ZSTD_writeEpilogue: write checksum : %08X", (unsigned)checksum);
+ MEM_writeLE32(op, checksum);
+ op += 4;
+ }
+
+ cctx->stage = ZSTDcs_created; /* return to "created but no init" status */
+ return op-ostart;
+}
+
+size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize)
+{
+ size_t endResult;
+ size_t const cSize = ZSTD_compressContinue_internal(cctx,
+ dst, dstCapacity, src, srcSize,
+ 1 /* frame mode */, 1 /* last chunk */);
+ FORWARD_IF_ERROR(cSize, "ZSTD_compressContinue_internal failed");
+ endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize);
+ FORWARD_IF_ERROR(endResult, "ZSTD_writeEpilogue failed");
+ assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0));
+ if (cctx->pledgedSrcSizePlusOne != 0) { /* control src size */
+ ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (unsigned long long)-1);
+ DEBUGLOG(4, "end of frame : controlling src size");
+ RETURN_ERROR_IF(
+ cctx->pledgedSrcSizePlusOne != cctx->consumedSrcSize+1,
+ srcSize_wrong,
+ "error : pledgedSrcSize = %u, while realSrcSize = %u",
+ (unsigned)cctx->pledgedSrcSizePlusOne-1,
+ (unsigned)cctx->consumedSrcSize);
+ }
+ return cSize + endResult;
+}
+
+
+static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const void* dict,size_t dictSize,
+ const ZSTD_parameters* params)
+{
+ ZSTD_CCtx_params const cctxParams =
+ ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, params);
+ DEBUGLOG(4, "ZSTD_compress_internal");
+ return ZSTD_compress_advanced_internal(cctx,
+ dst, dstCapacity,
+ src, srcSize,
+ dict, dictSize,
+ &cctxParams);
+}
+
+size_t ZSTD_compress_advanced (ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const void* dict,size_t dictSize,
+ ZSTD_parameters params)
+{
+ DEBUGLOG(4, "ZSTD_compress_advanced");
+ FORWARD_IF_ERROR(ZSTD_checkCParams(params.cParams), "");
+ return ZSTD_compress_internal(cctx,
+ dst, dstCapacity,
+ src, srcSize,
+ dict, dictSize,
+ &params);
+}
+
+/* Internal */
+size_t ZSTD_compress_advanced_internal(
+ ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const void* dict,size_t dictSize,
+ const ZSTD_CCtx_params* params)
+{
+ DEBUGLOG(4, "ZSTD_compress_advanced_internal (srcSize:%u)", (unsigned)srcSize);
+ FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx,
+ dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL,
+ params, srcSize, ZSTDb_not_buffered) , "");
+ return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
+}
+
+size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const void* dict, size_t dictSize,
+ int compressionLevel)
+{
+ ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, srcSize, dict ? dictSize : 0);
+ ZSTD_CCtx_params cctxParams = ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, &params);
+ DEBUGLOG(4, "ZSTD_compress_usingDict (srcSize=%u)", (unsigned)srcSize);
+ assert(params.fParams.contentSizeFlag == 1);
+ return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, &cctxParams);
+}
+
+size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ int compressionLevel)
+{
+ DEBUGLOG(4, "ZSTD_compressCCtx (srcSize=%u)", (unsigned)srcSize);
+ assert(cctx != NULL);
+ return ZSTD_compress_usingDict(cctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
+}
+
+size_t ZSTD_compress(void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ int compressionLevel)
+{
+ size_t result;
+ ZSTD_CCtx ctxBody;
+ ZSTD_initCCtx(&ctxBody, ZSTD_defaultCMem);
+ result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
+ ZSTD_freeCCtxContent(&ctxBody); /* can't free ctxBody itself, as it's on stack; free only heap content */
+ return result;
+}
+
+
+/* ===== Dictionary API ===== */
+
+/*! ZSTD_estimateCDictSize_advanced() :
+ * Estimate amount of memory that will be needed to create a dictionary with following arguments */
+size_t ZSTD_estimateCDictSize_advanced(
+ size_t dictSize, ZSTD_compressionParameters cParams,
+ ZSTD_dictLoadMethod_e dictLoadMethod)
+{
+ DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (unsigned)sizeof(ZSTD_CDict));
+ return ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict))
+ + ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE)
+ + ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0)
+ + (dictLoadMethod == ZSTD_dlm_byRef ? 0
+ : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void *))));
+}
+
+size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel)
+{
+ ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize);
+ return ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy);
+}
+
+size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict)
+{
+ if (cdict==NULL) return 0; /* support sizeof on NULL */
+ DEBUGLOG(5, "sizeof(*cdict) : %u", (unsigned)sizeof(*cdict));
+ /* cdict may be in the workspace */
+ return (cdict->workspace.workspace == cdict ? 0 : sizeof(*cdict))
+ + ZSTD_cwksp_sizeof(&cdict->workspace);
+}
+
+static size_t ZSTD_initCDict_internal(
+ ZSTD_CDict* cdict,
+ const void* dictBuffer, size_t dictSize,
+ ZSTD_dictLoadMethod_e dictLoadMethod,
+ ZSTD_dictContentType_e dictContentType,
+ ZSTD_compressionParameters cParams)
+{
+ DEBUGLOG(3, "ZSTD_initCDict_internal (dictContentType:%u)", (unsigned)dictContentType);
+ assert(!ZSTD_checkCParams(cParams));
+ cdict->matchState.cParams = cParams;
+ if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) {
+ cdict->dictContent = dictBuffer;
+ } else {
+ void *internalBuffer = ZSTD_cwksp_reserve_object(&cdict->workspace, ZSTD_cwksp_align(dictSize, sizeof(void*)));
+ RETURN_ERROR_IF(!internalBuffer, memory_allocation, "NULL pointer!");
+ cdict->dictContent = internalBuffer;
+ memcpy(internalBuffer, dictBuffer, dictSize);
+ }
+ cdict->dictContentSize = dictSize;
+
+ cdict->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object(&cdict->workspace, HUF_WORKSPACE_SIZE);
+
+
+ /* Reset the state to no dictionary */
+ ZSTD_reset_compressedBlockState(&cdict->cBlockState);
+ FORWARD_IF_ERROR(ZSTD_reset_matchState(
+ &cdict->matchState,
+ &cdict->workspace,
+ &cParams,
+ ZSTDcrp_makeClean,
+ ZSTDirp_reset,
+ ZSTD_resetTarget_CDict), "");
+ /* (Maybe) load the dictionary
+ * Skips loading the dictionary if it is < 8 bytes.
+ */
+ { ZSTD_CCtx_params params;
+ memset(&params, 0, sizeof(params));
+ params.compressionLevel = ZSTD_CLEVEL_DEFAULT;
+ params.fParams.contentSizeFlag = 1;
+ params.cParams = cParams;
+ { size_t const dictID = ZSTD_compress_insertDictionary(
+ &cdict->cBlockState, &cdict->matchState, NULL, &cdict->workspace,
+ &params, cdict->dictContent, cdict->dictContentSize,
+ dictContentType, ZSTD_dtlm_full, cdict->entropyWorkspace);
+ FORWARD_IF_ERROR(dictID, "ZSTD_compress_insertDictionary failed");
+ assert(dictID <= (size_t)(U32)-1);
+ cdict->dictID = (U32)dictID;
+ }
+ }
+
+ return 0;
+}
+
+ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize,
+ ZSTD_dictLoadMethod_e dictLoadMethod,
+ ZSTD_dictContentType_e dictContentType,
+ ZSTD_compressionParameters cParams, ZSTD_customMem customMem)
+{
+ DEBUGLOG(3, "ZSTD_createCDict_advanced, mode %u", (unsigned)dictContentType);
+ if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
+
+ { size_t const workspaceSize =
+ ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict)) +
+ ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE) +
+ ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0) +
+ (dictLoadMethod == ZSTD_dlm_byRef ? 0
+ : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*))));
+ void* const workspace = ZSTD_malloc(workspaceSize, customMem);
+ ZSTD_cwksp ws;
+ ZSTD_CDict* cdict;
+
+ if (!workspace) {
+ ZSTD_free(workspace, customMem);
+ return NULL;
+ }
+
+ ZSTD_cwksp_init(&ws, workspace, workspaceSize);
+
+ cdict = (ZSTD_CDict*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CDict));
+ assert(cdict != NULL);
+ ZSTD_cwksp_move(&cdict->workspace, &ws);
+ cdict->customMem = customMem;
+ cdict->compressionLevel = 0; /* signals advanced API usage */
+
+ if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
+ dictBuffer, dictSize,
+ dictLoadMethod, dictContentType,
+ cParams) )) {
+ ZSTD_freeCDict(cdict);
+ return NULL;
+ }
+
+ return cdict;
+ }
+}
+
+ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)
+{
+ ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize);
+ ZSTD_CDict* cdict = ZSTD_createCDict_advanced(dict, dictSize,
+ ZSTD_dlm_byCopy, ZSTD_dct_auto,
+ cParams, ZSTD_defaultCMem);
+ if (cdict)
+ cdict->compressionLevel = compressionLevel == 0 ? ZSTD_CLEVEL_DEFAULT : compressionLevel;
+ return cdict;
+}
+
+ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel)
+{
+ ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize);
+ return ZSTD_createCDict_advanced(dict, dictSize,
+ ZSTD_dlm_byRef, ZSTD_dct_auto,
+ cParams, ZSTD_defaultCMem);
+}
+
+size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
+{
+ if (cdict==NULL) return 0; /* support free on NULL */
+ { ZSTD_customMem const cMem = cdict->customMem;
+ int cdictInWorkspace = ZSTD_cwksp_owns_buffer(&cdict->workspace, cdict);
+ ZSTD_cwksp_free(&cdict->workspace, cMem);
+ if (!cdictInWorkspace) {
+ ZSTD_free(cdict, cMem);
+ }
+ return 0;
+ }
+}
+
+/*! ZSTD_initStaticCDict_advanced() :
+ * Generate a digested dictionary in provided memory area.
+ * workspace: The memory area to emplace the dictionary into.
+ * Provided pointer must 8-bytes aligned.
+ * It must outlive dictionary usage.
+ * workspaceSize: Use ZSTD_estimateCDictSize()
+ * to determine how large workspace must be.
+ * cParams : use ZSTD_getCParams() to transform a compression level
+ * into its relevants cParams.
+ * @return : pointer to ZSTD_CDict*, or NULL if error (size too small)
+ * Note : there is no corresponding "free" function.
+ * Since workspace was allocated externally, it must be freed externally.
+ */
+const ZSTD_CDict* ZSTD_initStaticCDict(
+ void* workspace, size_t workspaceSize,
+ const void* dict, size_t dictSize,
+ ZSTD_dictLoadMethod_e dictLoadMethod,
+ ZSTD_dictContentType_e dictContentType,
+ ZSTD_compressionParameters cParams)
+{
+ size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0);
+ size_t const neededSize = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict))
+ + (dictLoadMethod == ZSTD_dlm_byRef ? 0
+ : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*))))
+ + ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE)
+ + matchStateSize;
+ ZSTD_CDict* cdict;
+
+ if ((size_t)workspace & 7) return NULL; /* 8-aligned */
+
+ {
+ ZSTD_cwksp ws;
+ ZSTD_cwksp_init(&ws, workspace, workspaceSize);
+ cdict = (ZSTD_CDict*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CDict));
+ if (cdict == NULL) return NULL;
+ ZSTD_cwksp_move(&cdict->workspace, &ws);
+ }
+
+ DEBUGLOG(4, "(workspaceSize < neededSize) : (%u < %u) => %u",
+ (unsigned)workspaceSize, (unsigned)neededSize, (unsigned)(workspaceSize < neededSize));
+ if (workspaceSize < neededSize) return NULL;
+
+ if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
+ dict, dictSize,
+ dictLoadMethod, dictContentType,
+ cParams) ))
+ return NULL;
+
+ return cdict;
+}
+
+ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict)
+{
+ assert(cdict != NULL);
+ return cdict->matchState.cParams;
+}
+
+/* ZSTD_compressBegin_usingCDict_advanced() :
+ * cdict must be != NULL */
+size_t ZSTD_compressBegin_usingCDict_advanced(
+ ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict,
+ ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize)
+{
+ DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_advanced");
+ RETURN_ERROR_IF(cdict==NULL, dictionary_wrong, "NULL pointer!");
+ { ZSTD_CCtx_params params = cctx->requestedParams;
+ params.cParams = ( pledgedSrcSize < ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF
+ || pledgedSrcSize < cdict->dictContentSize * ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER
+ || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN
+ || cdict->compressionLevel == 0 )
+ && (params.attachDictPref != ZSTD_dictForceLoad) ?
+ ZSTD_getCParamsFromCDict(cdict)
+ : ZSTD_getCParams(cdict->compressionLevel,
+ pledgedSrcSize,
+ cdict->dictContentSize);
+ /* Increase window log to fit the entire dictionary and source if the
+ * source size is known. Limit the increase to 19, which is the
+ * window log for compression level 1 with the largest source size.
+ */
+ if (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN) {
+ U32 const limitedSrcSize = (U32)MIN(pledgedSrcSize, 1U << 19);
+ U32 const limitedSrcLog = limitedSrcSize > 1 ? ZSTD_highbit32(limitedSrcSize - 1) + 1 : 1;
+ params.cParams.windowLog = MAX(params.cParams.windowLog, limitedSrcLog);
+ }
+ params.fParams = fParams;
+ return ZSTD_compressBegin_internal(cctx,
+ NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast,
+ cdict,
+ &params, pledgedSrcSize,
+ ZSTDb_not_buffered);
+ }
+}
+
+/* ZSTD_compressBegin_usingCDict() :
+ * pledgedSrcSize=0 means "unknown"
+ * if pledgedSrcSize>0, it will enable contentSizeFlag */
+size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
+{
+ ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
+ DEBUGLOG(4, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u", !fParams.noDictIDFlag);
+ return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN);
+}
+
+size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const ZSTD_CDict* cdict, ZSTD_frameParameters fParams)
+{
+ FORWARD_IF_ERROR(ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, srcSize), ""); /* will check if cdict != NULL */
+ return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
+}
+
+/*! ZSTD_compress_usingCDict() :
+ * Compression using a digested Dictionary.
+ * Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times.
+ * Note that compression parameters are decided at CDict creation time
+ * while frame parameters are hardcoded */
+size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const ZSTD_CDict* cdict)
+{
+ ZSTD_frameParameters const fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
+ return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, fParams);
+}
+
+
+
+/* ******************************************************************
+* Streaming
+********************************************************************/
+
+ZSTD_CStream* ZSTD_createCStream(void)
+{
+ DEBUGLOG(3, "ZSTD_createCStream");
+ return ZSTD_createCStream_advanced(ZSTD_defaultCMem);
+}
+
+ZSTD_CStream* ZSTD_initStaticCStream(void *workspace, size_t workspaceSize)
+{
+ return ZSTD_initStaticCCtx(workspace, workspaceSize);
+}
+
+ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem)
+{ /* CStream and CCtx are now same object */
+ return ZSTD_createCCtx_advanced(customMem);
+}
+
+size_t ZSTD_freeCStream(ZSTD_CStream* zcs)
+{
+ return ZSTD_freeCCtx(zcs); /* same object */
+}
+
+
+
+/*====== Initialization ======*/
+
+size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX; }
+
+size_t ZSTD_CStreamOutSize(void)
+{
+ return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ;
+}
+
+static size_t ZSTD_resetCStream_internal(ZSTD_CStream* cctx,
+ const void* const dict, size_t const dictSize, ZSTD_dictContentType_e const dictContentType,
+ const ZSTD_CDict* const cdict,
+ ZSTD_CCtx_params params, unsigned long long const pledgedSrcSize)
+{
+ DEBUGLOG(4, "ZSTD_resetCStream_internal");
+ /* Finalize the compression parameters */
+ params.cParams = ZSTD_getCParamsFromCCtxParams(&params, pledgedSrcSize, dictSize);
+ /* params are supposed to be fully validated at this point */
+ assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
+ assert(!((dict) && (cdict))); /* either dict or cdict, not both */
+
+ FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx,
+ dict, dictSize, dictContentType, ZSTD_dtlm_fast,
+ cdict,
+ &params, pledgedSrcSize,
+ ZSTDb_buffered) , "");
+
+ cctx->inToCompress = 0;
+ cctx->inBuffPos = 0;
+ cctx->inBuffTarget = cctx->blockSize
+ + (cctx->blockSize == pledgedSrcSize); /* for small input: avoid automatic flush on reaching end of block, since it would require to add a 3-bytes null block to end frame */
+ cctx->outBuffContentSize = cctx->outBuffFlushedSize = 0;
+ cctx->streamStage = zcss_load;
+ cctx->frameEnded = 0;
+ return 0; /* ready to go */
+}
+
+/* ZSTD_resetCStream():
+ * pledgedSrcSize == 0 means "unknown" */
+size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pss)
+{
+ /* temporary : 0 interpreted as "unknown" during transition period.
+ * Users willing to specify "unknown" **must** use ZSTD_CONTENTSIZE_UNKNOWN.
+ * 0 will be interpreted as "empty" in the future.
+ */
+ U64 const pledgedSrcSize = (pss==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss;
+ DEBUGLOG(4, "ZSTD_resetCStream: pledgedSrcSize = %u", (unsigned)pledgedSrcSize);
+ FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
+ FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , "");
+ return 0;
+}
+
+/*! ZSTD_initCStream_internal() :
+ * Note : for lib/compress only. Used by zstdmt_compress.c.
+ * Assumption 1 : params are valid
+ * Assumption 2 : either dict, or cdict, is defined, not both */
+size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
+ const void* dict, size_t dictSize, const ZSTD_CDict* cdict,
+ const ZSTD_CCtx_params* params,
+ unsigned long long pledgedSrcSize)
+{
+ DEBUGLOG(4, "ZSTD_initCStream_internal");
+ FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
+ FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , "");
+ assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams)));
+ zcs->requestedParams = *params;
+ assert(!((dict) && (cdict))); /* either dict or cdict, not both */
+ if (dict) {
+ FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) , "");
+ } else {
+ /* Dictionary is cleared if !cdict */
+ FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) , "");
+ }
+ return 0;
+}
+
+/* ZSTD_initCStream_usingCDict_advanced() :
+ * same as ZSTD_initCStream_usingCDict(), with control over frame parameters */
+size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs,
+ const ZSTD_CDict* cdict,
+ ZSTD_frameParameters fParams,
+ unsigned long long pledgedSrcSize)
+{
+ DEBUGLOG(4, "ZSTD_initCStream_usingCDict_advanced");
+ FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
+ FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , "");
+ zcs->requestedParams.fParams = fParams;
+ FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) , "");
+ return 0;
+}
+
+/* note : cdict must outlive compression session */
+size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict)
+{
+ DEBUGLOG(4, "ZSTD_initCStream_usingCDict");
+ FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
+ FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) , "");
+ return 0;
+}
+
+
+/* ZSTD_initCStream_advanced() :
+ * pledgedSrcSize must be exact.
+ * if srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN.
+ * dict is loaded with default parameters ZSTD_dct_auto and ZSTD_dlm_byCopy. */
+size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
+ const void* dict, size_t dictSize,
+ ZSTD_parameters params, unsigned long long pss)
+{
+ /* for compatibility with older programs relying on this behavior.
+ * Users should now specify ZSTD_CONTENTSIZE_UNKNOWN.
+ * This line will be removed in the future.
+ */
+ U64 const pledgedSrcSize = (pss==0 && params.fParams.contentSizeFlag==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss;
+ DEBUGLOG(4, "ZSTD_initCStream_advanced");
+ FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
+ FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , "");
+ FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) , "");
+ zcs->requestedParams = ZSTD_assignParamsToCCtxParams(&zcs->requestedParams, &params);
+ FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) , "");
+ return 0;
+}
+
+size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel)
+{
+ DEBUGLOG(4, "ZSTD_initCStream_usingDict");
+ FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
+ FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) , "");
+ FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) , "");
+ return 0;
+}
+
+size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pss)
+{
+ /* temporary : 0 interpreted as "unknown" during transition period.
+ * Users willing to specify "unknown" **must** use ZSTD_CONTENTSIZE_UNKNOWN.
+ * 0 will be interpreted as "empty" in the future.
+ */
+ U64 const pledgedSrcSize = (pss==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss;
+ DEBUGLOG(4, "ZSTD_initCStream_srcSize");
+ FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
+ FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, NULL) , "");
+ FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) , "");
+ FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , "");
+ return 0;
+}
+
+size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel)
+{
+ DEBUGLOG(4, "ZSTD_initCStream");
+ FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
+ FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, NULL) , "");
+ FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) , "");
+ return 0;
+}
+
+/*====== Compression ======*/
+
+static size_t ZSTD_nextInputSizeHint(const ZSTD_CCtx* cctx)
+{
+ size_t hintInSize = cctx->inBuffTarget - cctx->inBuffPos;
+ if (hintInSize==0) hintInSize = cctx->blockSize;
+ return hintInSize;
+}
+
+/** ZSTD_compressStream_generic():
+ * internal function for all *compressStream*() variants
+ * non-static, because can be called from zstdmt_compress.c
+ * @return : hint size for next input */
+static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
+ ZSTD_outBuffer* output,
+ ZSTD_inBuffer* input,
+ ZSTD_EndDirective const flushMode)
+{
+ const char* const istart = (const char*)input->src;
+ const char* const iend = input->size != 0 ? istart + input->size : istart;
+ const char* ip = input->pos != 0 ? istart + input->pos : istart;
+ char* const ostart = (char*)output->dst;
+ char* const oend = output->size != 0 ? ostart + output->size : ostart;
+ char* op = output->pos != 0 ? ostart + output->pos : ostart;
+ U32 someMoreWork = 1;
+
+ /* check expectations */
+ DEBUGLOG(5, "ZSTD_compressStream_generic, flush=%u", (unsigned)flushMode);
+ assert(zcs->inBuff != NULL);
+ assert(zcs->inBuffSize > 0);
+ assert(zcs->outBuff != NULL);
+ assert(zcs->outBuffSize > 0);
+ assert(output->pos <= output->size);
+ assert(input->pos <= input->size);
+
+ while (someMoreWork) {
+ switch(zcs->streamStage)
+ {
+ case zcss_init:
+ RETURN_ERROR(init_missing, "call ZSTD_initCStream() first!");
+
+ case zcss_load:
+ if ( (flushMode == ZSTD_e_end)
+ && ((size_t)(oend-op) >= ZSTD_compressBound(iend-ip)) /* enough dstCapacity */
+ && (zcs->inBuffPos == 0) ) {
+ /* shortcut to compression pass directly into output buffer */
+ size_t const cSize = ZSTD_compressEnd(zcs,
+ op, oend-op, ip, iend-ip);
+ DEBUGLOG(4, "ZSTD_compressEnd : cSize=%u", (unsigned)cSize);
+ FORWARD_IF_ERROR(cSize, "ZSTD_compressEnd failed");
+ ip = iend;
+ op += cSize;
+ zcs->frameEnded = 1;
+ ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
+ someMoreWork = 0; break;
+ }
+ /* complete loading into inBuffer */
+ { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
+ size_t const loaded = ZSTD_limitCopy(
+ zcs->inBuff + zcs->inBuffPos, toLoad,
+ ip, iend-ip);
+ zcs->inBuffPos += loaded;
+ if (loaded != 0)
+ ip += loaded;
+ if ( (flushMode == ZSTD_e_continue)
+ && (zcs->inBuffPos < zcs->inBuffTarget) ) {
+ /* not enough input to fill full block : stop here */
+ someMoreWork = 0; break;
+ }
+ if ( (flushMode == ZSTD_e_flush)
+ && (zcs->inBuffPos == zcs->inToCompress) ) {
+ /* empty */
+ someMoreWork = 0; break;
+ }
+ }
+ /* compress current block (note : this stage cannot be stopped in the middle) */
+ DEBUGLOG(5, "stream compression stage (flushMode==%u)", flushMode);
+ { void* cDst;
+ size_t cSize;
+ size_t const iSize = zcs->inBuffPos - zcs->inToCompress;
+ size_t oSize = oend-op;
+ unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend);
+ if (oSize >= ZSTD_compressBound(iSize))
+ cDst = op; /* compress into output buffer, to skip flush stage */
+ else
+ cDst = zcs->outBuff, oSize = zcs->outBuffSize;
+ cSize = lastBlock ?
+ ZSTD_compressEnd(zcs, cDst, oSize,
+ zcs->inBuff + zcs->inToCompress, iSize) :
+ ZSTD_compressContinue(zcs, cDst, oSize,
+ zcs->inBuff + zcs->inToCompress, iSize);
+ FORWARD_IF_ERROR(cSize, "%s", lastBlock ? "ZSTD_compressEnd failed" : "ZSTD_compressContinue failed");
+ zcs->frameEnded = lastBlock;
+ /* prepare next block */
+ zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize;
+ if (zcs->inBuffTarget > zcs->inBuffSize)
+ zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize;
+ DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u",
+ (unsigned)zcs->inBuffTarget, (unsigned)zcs->inBuffSize);
+ if (!lastBlock)
+ assert(zcs->inBuffTarget <= zcs->inBuffSize);
+ zcs->inToCompress = zcs->inBuffPos;
+ if (cDst == op) { /* no need to flush */
+ op += cSize;
+ if (zcs->frameEnded) {
+ DEBUGLOG(5, "Frame completed directly in outBuffer");
+ someMoreWork = 0;
+ ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
+ }
+ break;
+ }
+ zcs->outBuffContentSize = cSize;
+ zcs->outBuffFlushedSize = 0;
+ zcs->streamStage = zcss_flush; /* pass-through to flush stage */
+ }
+ /* fall-through */
+ case zcss_flush:
+ DEBUGLOG(5, "flush stage");
+ { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
+ size_t const flushed = ZSTD_limitCopy(op, (size_t)(oend-op),
+ zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
+ DEBUGLOG(5, "toFlush: %u into %u ==> flushed: %u",
+ (unsigned)toFlush, (unsigned)(oend-op), (unsigned)flushed);
+ if (flushed)
+ op += flushed;
+ zcs->outBuffFlushedSize += flushed;
+ if (toFlush!=flushed) {
+ /* flush not fully completed, presumably because dst is too small */
+ assert(op==oend);
+ someMoreWork = 0;
+ break;
+ }
+ zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
+ if (zcs->frameEnded) {
+ DEBUGLOG(5, "Frame completed on flush");
+ someMoreWork = 0;
+ ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
+ break;
+ }
+ zcs->streamStage = zcss_load;
+ break;
+ }
+
+ default: /* impossible */
+ assert(0);
+ }
+ }
+
+ input->pos = ip - istart;
+ output->pos = op - ostart;
+ if (zcs->frameEnded) return 0;
+ return ZSTD_nextInputSizeHint(zcs);
+}
+
+static size_t ZSTD_nextInputSizeHint_MTorST(const ZSTD_CCtx* cctx)
+{
+#ifdef ZSTD_MULTITHREAD
+ if (cctx->appliedParams.nbWorkers >= 1) {
+ assert(cctx->mtctx != NULL);
+ return ZSTDMT_nextInputSizeHint(cctx->mtctx);
+ }
+#endif
+ return ZSTD_nextInputSizeHint(cctx);
+
+}
+
+size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
+{
+ FORWARD_IF_ERROR( ZSTD_compressStream2(zcs, output, input, ZSTD_e_continue) , "");
+ return ZSTD_nextInputSizeHint_MTorST(zcs);
+}
+
+
+size_t ZSTD_compressStream2( ZSTD_CCtx* cctx,
+ ZSTD_outBuffer* output,
+ ZSTD_inBuffer* input,
+ ZSTD_EndDirective endOp)
+{
+ DEBUGLOG(5, "ZSTD_compressStream2, endOp=%u ", (unsigned)endOp);
+ /* check conditions */
+ RETURN_ERROR_IF(output->pos > output->size, GENERIC, "invalid buffer");
+ RETURN_ERROR_IF(input->pos > input->size, GENERIC, "invalid buffer");
+ assert(cctx!=NULL);
+
+ /* transparent initialization stage */
+ if (cctx->streamStage == zcss_init) {
+ ZSTD_CCtx_params params = cctx->requestedParams;
+ ZSTD_prefixDict const prefixDict = cctx->prefixDict;
+ FORWARD_IF_ERROR( ZSTD_initLocalDict(cctx) , ""); /* Init the local dict if present. */
+ memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* single usage */
+ assert(prefixDict.dict==NULL || cctx->cdict==NULL); /* only one can be set */
+ DEBUGLOG(4, "ZSTD_compressStream2 : transparent init stage");
+ if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = input->size + 1; /* auto-fix pledgedSrcSize */
+ params.cParams = ZSTD_getCParamsFromCCtxParams(
+ &cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/);
+
+
+#ifdef ZSTD_MULTITHREAD
+ if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN) {
+ params.nbWorkers = 0; /* do not invoke multi-threading when src size is too small */
+ }
+ if (params.nbWorkers > 0) {
+ /* mt context creation */
+ if (cctx->mtctx == NULL) {
+ DEBUGLOG(4, "ZSTD_compressStream2: creating new mtctx for nbWorkers=%u",
+ params.nbWorkers);
+ cctx->mtctx = ZSTDMT_createCCtx_advanced((U32)params.nbWorkers, cctx->customMem);
+ RETURN_ERROR_IF(cctx->mtctx == NULL, memory_allocation, "NULL pointer!");
+ }
+ /* mt compression */
+ DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbWorkers=%u", params.nbWorkers);
+ FORWARD_IF_ERROR( ZSTDMT_initCStream_internal(
+ cctx->mtctx,
+ prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType,
+ cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) , "");
+ cctx->streamStage = zcss_load;
+ cctx->appliedParams.nbWorkers = params.nbWorkers;
+ } else
+#endif
+ { FORWARD_IF_ERROR( ZSTD_resetCStream_internal(cctx,
+ prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType,
+ cctx->cdict,
+ params, cctx->pledgedSrcSizePlusOne-1) , "");
+ assert(cctx->streamStage == zcss_load);
+ assert(cctx->appliedParams.nbWorkers == 0);
+ } }
+ /* end of transparent initialization stage */
+
+ /* compression stage */
+#ifdef ZSTD_MULTITHREAD
+ if (cctx->appliedParams.nbWorkers > 0) {
+ int const forceMaxProgress = (endOp == ZSTD_e_flush || endOp == ZSTD_e_end);
+ size_t flushMin;
+ assert(forceMaxProgress || endOp == ZSTD_e_continue /* Protection for a new flush type */);
+ if (cctx->cParamsChanged) {
+ ZSTDMT_updateCParams_whileCompressing(cctx->mtctx, &cctx->requestedParams);
+ cctx->cParamsChanged = 0;
+ }
+ do {
+ flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp);
+ if ( ZSTD_isError(flushMin)
+ || (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */
+ ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only);
+ }
+ FORWARD_IF_ERROR(flushMin, "ZSTDMT_compressStream_generic failed");
+ } while (forceMaxProgress && flushMin != 0 && output->pos < output->size);
+ DEBUGLOG(5, "completed ZSTD_compressStream2 delegating to ZSTDMT_compressStream_generic");
+ /* Either we don't require maximum forward progress, we've finished the
+ * flush, or we are out of output space.
+ */
+ assert(!forceMaxProgress || flushMin == 0 || output->pos == output->size);
+ return flushMin;
+ }
+#endif
+ FORWARD_IF_ERROR( ZSTD_compressStream_generic(cctx, output, input, endOp) , "");
+ DEBUGLOG(5, "completed ZSTD_compressStream2");
+ return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */
+}
+
+size_t ZSTD_compressStream2_simpleArgs (
+ ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity, size_t* dstPos,
+ const void* src, size_t srcSize, size_t* srcPos,
+ ZSTD_EndDirective endOp)
+{
+ ZSTD_outBuffer output = { dst, dstCapacity, *dstPos };
+ ZSTD_inBuffer input = { src, srcSize, *srcPos };
+ /* ZSTD_compressStream2() will check validity of dstPos and srcPos */
+ size_t const cErr = ZSTD_compressStream2(cctx, &output, &input, endOp);
+ *dstPos = output.pos;
+ *srcPos = input.pos;
+ return cErr;
+}
+
+size_t ZSTD_compress2(ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize)
+{
+ DEBUGLOG(4, "ZSTD_compress2 (srcSize=%u)", (unsigned)srcSize);
+ ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only);
+ { size_t oPos = 0;
+ size_t iPos = 0;
+ size_t const result = ZSTD_compressStream2_simpleArgs(cctx,
+ dst, dstCapacity, &oPos,
+ src, srcSize, &iPos,
+ ZSTD_e_end);
+ FORWARD_IF_ERROR(result, "ZSTD_compressStream2_simpleArgs failed");
+ if (result != 0) { /* compression not completed, due to lack of output space */
+ assert(oPos == dstCapacity);
+ RETURN_ERROR(dstSize_tooSmall, "");
+ }
+ assert(iPos == srcSize); /* all input is expected consumed */
+ return oPos;
+ }
+}
+
+/*====== Finalize ======*/
+
+/*! ZSTD_flushStream() :
+ * @return : amount of data remaining to flush */
+size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
+{
+ ZSTD_inBuffer input = { NULL, 0, 0 };
+ return ZSTD_compressStream2(zcs, output, &input, ZSTD_e_flush);
+}
+
+
+size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
+{
+ ZSTD_inBuffer input = { NULL, 0, 0 };
+ size_t const remainingToFlush = ZSTD_compressStream2(zcs, output, &input, ZSTD_e_end);
+ FORWARD_IF_ERROR( remainingToFlush , "ZSTD_compressStream2 failed");
+ if (zcs->appliedParams.nbWorkers > 0) return remainingToFlush; /* minimal estimation */
+ /* single thread mode : attempt to calculate remaining to flush more precisely */
+ { size_t const lastBlockSize = zcs->frameEnded ? 0 : ZSTD_BLOCKHEADERSIZE;
+ size_t const checksumSize = (size_t)(zcs->frameEnded ? 0 : zcs->appliedParams.fParams.checksumFlag * 4);
+ size_t const toFlush = remainingToFlush + lastBlockSize + checksumSize;
+ DEBUGLOG(4, "ZSTD_endStream : remaining to flush : %u", (unsigned)toFlush);
+ return toFlush;
+ }
+}
+
+
+/*-===== Pre-defined compression levels =====-*/
+
+#define ZSTD_MAX_CLEVEL 22
+int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
+int ZSTD_minCLevel(void) { return (int)-ZSTD_TARGETLENGTH_MAX; }
+
+static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
+{ /* "default" - for any srcSize > 256 KB */
+ /* W, C, H, S, L, TL, strat */
+ { 19, 12, 13, 1, 6, 1, ZSTD_fast }, /* base for negative levels */
+ { 19, 13, 14, 1, 7, 0, ZSTD_fast }, /* level 1 */
+ { 20, 15, 16, 1, 6, 0, ZSTD_fast }, /* level 2 */
+ { 21, 16, 17, 1, 5, 0, ZSTD_dfast }, /* level 3 */
+ { 21, 18, 18, 1, 5, 0, ZSTD_dfast }, /* level 4 */
+ { 21, 18, 19, 2, 5, 2, ZSTD_greedy }, /* level 5 */
+ { 21, 19, 19, 3, 5, 4, ZSTD_greedy }, /* level 6 */
+ { 21, 19, 19, 3, 5, 8, ZSTD_lazy }, /* level 7 */
+ { 21, 19, 19, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */
+ { 21, 19, 20, 4, 5, 16, ZSTD_lazy2 }, /* level 9 */
+ { 22, 20, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */
+ { 22, 21, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */
+ { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
+ { 22, 21, 22, 5, 5, 32, ZSTD_btlazy2 }, /* level 13 */
+ { 22, 22, 23, 5, 5, 32, ZSTD_btlazy2 }, /* level 14 */
+ { 22, 23, 23, 6, 5, 32, ZSTD_btlazy2 }, /* level 15 */
+ { 22, 22, 22, 5, 5, 48, ZSTD_btopt }, /* level 16 */
+ { 23, 23, 22, 5, 4, 64, ZSTD_btopt }, /* level 17 */
+ { 23, 23, 22, 6, 3, 64, ZSTD_btultra }, /* level 18 */
+ { 23, 24, 22, 7, 3,256, ZSTD_btultra2}, /* level 19 */
+ { 25, 25, 23, 7, 3,256, ZSTD_btultra2}, /* level 20 */
+ { 26, 26, 24, 7, 3,512, ZSTD_btultra2}, /* level 21 */
+ { 27, 27, 25, 9, 3,999, ZSTD_btultra2}, /* level 22 */
+},
+{ /* for srcSize <= 256 KB */
+ /* W, C, H, S, L, T, strat */
+ { 18, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */
+ { 18, 13, 14, 1, 6, 0, ZSTD_fast }, /* level 1 */
+ { 18, 14, 14, 1, 5, 0, ZSTD_dfast }, /* level 2 */
+ { 18, 16, 16, 1, 4, 0, ZSTD_dfast }, /* level 3 */
+ { 18, 16, 17, 2, 5, 2, ZSTD_greedy }, /* level 4.*/
+ { 18, 18, 18, 3, 5, 2, ZSTD_greedy }, /* level 5.*/
+ { 18, 18, 19, 3, 5, 4, ZSTD_lazy }, /* level 6.*/
+ { 18, 18, 19, 4, 4, 4, ZSTD_lazy }, /* level 7 */
+ { 18, 18, 19, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
+ { 18, 18, 19, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
+ { 18, 18, 19, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
+ { 18, 18, 19, 5, 4, 12, ZSTD_btlazy2 }, /* level 11.*/
+ { 18, 19, 19, 7, 4, 12, ZSTD_btlazy2 }, /* level 12.*/
+ { 18, 18, 19, 4, 4, 16, ZSTD_btopt }, /* level 13 */
+ { 18, 18, 19, 4, 3, 32, ZSTD_btopt }, /* level 14.*/
+ { 18, 18, 19, 6, 3,128, ZSTD_btopt }, /* level 15.*/
+ { 18, 19, 19, 6, 3,128, ZSTD_btultra }, /* level 16.*/
+ { 18, 19, 19, 8, 3,256, ZSTD_btultra }, /* level 17.*/
+ { 18, 19, 19, 6, 3,128, ZSTD_btultra2}, /* level 18.*/
+ { 18, 19, 19, 8, 3,256, ZSTD_btultra2}, /* level 19.*/
+ { 18, 19, 19, 10, 3,512, ZSTD_btultra2}, /* level 20.*/
+ { 18, 19, 19, 12, 3,512, ZSTD_btultra2}, /* level 21.*/
+ { 18, 19, 19, 13, 3,999, ZSTD_btultra2}, /* level 22.*/
+},
+{ /* for srcSize <= 128 KB */
+ /* W, C, H, S, L, T, strat */
+ { 17, 12, 12, 1, 5, 1, ZSTD_fast }, /* base for negative levels */
+ { 17, 12, 13, 1, 6, 0, ZSTD_fast }, /* level 1 */
+ { 17, 13, 15, 1, 5, 0, ZSTD_fast }, /* level 2 */
+ { 17, 15, 16, 2, 5, 0, ZSTD_dfast }, /* level 3 */
+ { 17, 17, 17, 2, 4, 0, ZSTD_dfast }, /* level 4 */
+ { 17, 16, 17, 3, 4, 2, ZSTD_greedy }, /* level 5 */
+ { 17, 17, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */
+ { 17, 17, 17, 3, 4, 8, ZSTD_lazy2 }, /* level 7 */
+ { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
+ { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
+ { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
+ { 17, 17, 17, 5, 4, 8, ZSTD_btlazy2 }, /* level 11 */
+ { 17, 18, 17, 7, 4, 12, ZSTD_btlazy2 }, /* level 12 */
+ { 17, 18, 17, 3, 4, 12, ZSTD_btopt }, /* level 13.*/
+ { 17, 18, 17, 4, 3, 32, ZSTD_btopt }, /* level 14.*/
+ { 17, 18, 17, 6, 3,256, ZSTD_btopt }, /* level 15.*/
+ { 17, 18, 17, 6, 3,128, ZSTD_btultra }, /* level 16.*/
+ { 17, 18, 17, 8, 3,256, ZSTD_btultra }, /* level 17.*/
+ { 17, 18, 17, 10, 3,512, ZSTD_btultra }, /* level 18.*/
+ { 17, 18, 17, 5, 3,256, ZSTD_btultra2}, /* level 19.*/
+ { 17, 18, 17, 7, 3,512, ZSTD_btultra2}, /* level 20.*/
+ { 17, 18, 17, 9, 3,512, ZSTD_btultra2}, /* level 21.*/
+ { 17, 18, 17, 11, 3,999, ZSTD_btultra2}, /* level 22.*/
+},
+{ /* for srcSize <= 16 KB */
+ /* W, C, H, S, L, T, strat */
+ { 14, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */
+ { 14, 14, 15, 1, 5, 0, ZSTD_fast }, /* level 1 */
+ { 14, 14, 15, 1, 4, 0, ZSTD_fast }, /* level 2 */
+ { 14, 14, 15, 2, 4, 0, ZSTD_dfast }, /* level 3 */
+ { 14, 14, 14, 4, 4, 2, ZSTD_greedy }, /* level 4 */
+ { 14, 14, 14, 3, 4, 4, ZSTD_lazy }, /* level 5.*/
+ { 14, 14, 14, 4, 4, 8, ZSTD_lazy2 }, /* level 6 */
+ { 14, 14, 14, 6, 4, 8, ZSTD_lazy2 }, /* level 7 */
+ { 14, 14, 14, 8, 4, 8, ZSTD_lazy2 }, /* level 8.*/
+ { 14, 15, 14, 5, 4, 8, ZSTD_btlazy2 }, /* level 9.*/
+ { 14, 15, 14, 9, 4, 8, ZSTD_btlazy2 }, /* level 10.*/
+ { 14, 15, 14, 3, 4, 12, ZSTD_btopt }, /* level 11.*/
+ { 14, 15, 14, 4, 3, 24, ZSTD_btopt }, /* level 12.*/
+ { 14, 15, 14, 5, 3, 32, ZSTD_btultra }, /* level 13.*/
+ { 14, 15, 15, 6, 3, 64, ZSTD_btultra }, /* level 14.*/
+ { 14, 15, 15, 7, 3,256, ZSTD_btultra }, /* level 15.*/
+ { 14, 15, 15, 5, 3, 48, ZSTD_btultra2}, /* level 16.*/
+ { 14, 15, 15, 6, 3,128, ZSTD_btultra2}, /* level 17.*/
+ { 14, 15, 15, 7, 3,256, ZSTD_btultra2}, /* level 18.*/
+ { 14, 15, 15, 8, 3,256, ZSTD_btultra2}, /* level 19.*/
+ { 14, 15, 15, 8, 3,512, ZSTD_btultra2}, /* level 20.*/
+ { 14, 15, 15, 9, 3,512, ZSTD_btultra2}, /* level 21.*/
+ { 14, 15, 15, 10, 3,999, ZSTD_btultra2}, /* level 22.*/
+},
+};
+
+/*! ZSTD_getCParams_internal() :
+ * @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize.
+ * Note: srcSizeHint 0 means 0, use ZSTD_CONTENTSIZE_UNKNOWN for unknown.
+ * Use dictSize == 0 for unknown or unused. */
+static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize)
+{
+ int const unknown = srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN;
+ size_t const addedSize = unknown && dictSize > 0 ? 500 : 0;
+ U64 const rSize = unknown && dictSize == 0 ? ZSTD_CONTENTSIZE_UNKNOWN : srcSizeHint+dictSize+addedSize;
+ U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB);
+ int row = compressionLevel;
+ DEBUGLOG(5, "ZSTD_getCParams_internal (cLevel=%i)", compressionLevel);
+ if (compressionLevel == 0) row = ZSTD_CLEVEL_DEFAULT; /* 0 == default */
+ if (compressionLevel < 0) row = 0; /* entry 0 is baseline for fast mode */
+ if (compressionLevel > ZSTD_MAX_CLEVEL) row = ZSTD_MAX_CLEVEL;
+ { ZSTD_compressionParameters cp = ZSTD_defaultCParameters[tableID][row];
+ if (compressionLevel < 0) cp.targetLength = (unsigned)(-compressionLevel); /* acceleration factor */
+ /* refine parameters based on srcSize & dictSize */
+ return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize);
+ }
+}
+
+/*! ZSTD_getCParams() :
+ * @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize.
+ * Size values are optional, provide 0 if not known or unused */
+ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize)
+{
+ if (srcSizeHint == 0) srcSizeHint = ZSTD_CONTENTSIZE_UNKNOWN;
+ return ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize);
+}
+
+/*! ZSTD_getParams() :
+ * same idea as ZSTD_getCParams()
+ * @return a `ZSTD_parameters` structure (instead of `ZSTD_compressionParameters`).
+ * Fields of `ZSTD_frameParameters` are set to default values */
+static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) {
+ ZSTD_parameters params;
+ ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize);
+ DEBUGLOG(5, "ZSTD_getParams (cLevel=%i)", compressionLevel);
+ memset(&params, 0, sizeof(params));
+ params.cParams = cParams;
+ params.fParams.contentSizeFlag = 1;
+ return params;
+}
+
+/*! ZSTD_getParams() :
+ * same idea as ZSTD_getCParams()
+ * @return a `ZSTD_parameters` structure (instead of `ZSTD_compressionParameters`).
+ * Fields of `ZSTD_frameParameters` are set to default values */
+ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) {
+ if (srcSizeHint == 0) srcSizeHint = ZSTD_CONTENTSIZE_UNKNOWN;
+ return ZSTD_getParams_internal(compressionLevel, srcSizeHint, dictSize);
+}
diff --git a/sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress_internal.h b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress_internal.h
new file mode 100644
index 000000000000..db73f6ce21f2
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress_internal.h
@@ -0,0 +1,1125 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/* This header contains definitions
+ * that shall **only** be used by modules within lib/compress.
+ */
+
+#ifndef ZSTD_COMPRESS_H
+#define ZSTD_COMPRESS_H
+
+/*-*************************************
+* Dependencies
+***************************************/
+#include "../common/zstd_internal.h"
+#include "zstd_cwksp.h"
+#ifdef ZSTD_MULTITHREAD
+# include "zstdmt_compress.h"
+#endif
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+
+/*-*************************************
+* Constants
+***************************************/
+#define kSearchStrength 8
+#define HASH_READ_SIZE 8
+#define ZSTD_DUBT_UNSORTED_MARK 1 /* For btlazy2 strategy, index ZSTD_DUBT_UNSORTED_MARK==1 means "unsorted".
+ It could be confused for a real successor at index "1", if sorted as larger than its predecessor.
+ It's not a big deal though : candidate will just be sorted again.
+ Additionally, candidate position 1 will be lost.
+ But candidate 1 cannot hide a large tree of candidates, so it's a minimal loss.
+ The benefit is that ZSTD_DUBT_UNSORTED_MARK cannot be mishandled after table re-use with a different strategy.
+ This constant is required by ZSTD_compressBlock_btlazy2() and ZSTD_reduceTable_internal() */
+
+
+/*-*************************************
+* Context memory management
+***************************************/
+typedef enum { ZSTDcs_created=0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e;
+typedef enum { zcss_init=0, zcss_load, zcss_flush } ZSTD_cStreamStage;
+
+typedef struct ZSTD_prefixDict_s {
+ const void* dict;
+ size_t dictSize;
+ ZSTD_dictContentType_e dictContentType;
+} ZSTD_prefixDict;
+
+typedef struct {
+ void* dictBuffer;
+ void const* dict;
+ size_t dictSize;
+ ZSTD_dictContentType_e dictContentType;
+ ZSTD_CDict* cdict;
+} ZSTD_localDict;
+
+typedef struct {
+ U32 CTable[HUF_CTABLE_SIZE_U32(255)];
+ HUF_repeat repeatMode;
+} ZSTD_hufCTables_t;
+
+typedef struct {
+ FSE_CTable offcodeCTable[FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
+ FSE_CTable matchlengthCTable[FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
+ FSE_CTable litlengthCTable[FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
+ FSE_repeat offcode_repeatMode;
+ FSE_repeat matchlength_repeatMode;
+ FSE_repeat litlength_repeatMode;
+} ZSTD_fseCTables_t;
+
+typedef struct {
+ ZSTD_hufCTables_t huf;
+ ZSTD_fseCTables_t fse;
+} ZSTD_entropyCTables_t;
+
+typedef struct {
+ U32 off;
+ U32 len;
+} ZSTD_match_t;
+
+typedef struct {
+ int price;
+ U32 off;
+ U32 mlen;
+ U32 litlen;
+ U32 rep[ZSTD_REP_NUM];
+} ZSTD_optimal_t;
+
+typedef enum { zop_dynamic=0, zop_predef } ZSTD_OptPrice_e;
+
+typedef struct {
+ /* All tables are allocated inside cctx->workspace by ZSTD_resetCCtx_internal() */
+ unsigned* litFreq; /* table of literals statistics, of size 256 */
+ unsigned* litLengthFreq; /* table of litLength statistics, of size (MaxLL+1) */
+ unsigned* matchLengthFreq; /* table of matchLength statistics, of size (MaxML+1) */
+ unsigned* offCodeFreq; /* table of offCode statistics, of size (MaxOff+1) */
+ ZSTD_match_t* matchTable; /* list of found matches, of size ZSTD_OPT_NUM+1 */
+ ZSTD_optimal_t* priceTable; /* All positions tracked by optimal parser, of size ZSTD_OPT_NUM+1 */
+
+ U32 litSum; /* nb of literals */
+ U32 litLengthSum; /* nb of litLength codes */
+ U32 matchLengthSum; /* nb of matchLength codes */
+ U32 offCodeSum; /* nb of offset codes */
+ U32 litSumBasePrice; /* to compare to log2(litfreq) */
+ U32 litLengthSumBasePrice; /* to compare to log2(llfreq) */
+ U32 matchLengthSumBasePrice;/* to compare to log2(mlfreq) */
+ U32 offCodeSumBasePrice; /* to compare to log2(offreq) */
+ ZSTD_OptPrice_e priceType; /* prices can be determined dynamically, or follow a pre-defined cost structure */
+ const ZSTD_entropyCTables_t* symbolCosts; /* pre-calculated dictionary statistics */
+ ZSTD_literalCompressionMode_e literalCompressionMode;
+} optState_t;
+
+typedef struct {
+ ZSTD_entropyCTables_t entropy;
+ U32 rep[ZSTD_REP_NUM];
+} ZSTD_compressedBlockState_t;
+
+typedef struct {
+ BYTE const* nextSrc; /* next block here to continue on current prefix */
+ BYTE const* base; /* All regular indexes relative to this position */
+ BYTE const* dictBase; /* extDict indexes relative to this position */
+ U32 dictLimit; /* below that point, need extDict */
+ U32 lowLimit; /* below that point, no more valid data */
+} ZSTD_window_t;
+
+typedef struct ZSTD_matchState_t ZSTD_matchState_t;
+struct ZSTD_matchState_t {
+ ZSTD_window_t window; /* State for window round buffer management */
+ U32 loadedDictEnd; /* index of end of dictionary, within context's referential.
+ * When loadedDictEnd != 0, a dictionary is in use, and still valid.
+ * This relies on a mechanism to set loadedDictEnd=0 when dictionary is no longer within distance.
+ * Such mechanism is provided within ZSTD_window_enforceMaxDist() and ZSTD_checkDictValidity().
+ * When dict referential is copied into active context (i.e. not attached),
+ * loadedDictEnd == dictSize, since referential starts from zero.
+ */
+ U32 nextToUpdate; /* index from which to continue table update */
+ U32 hashLog3; /* dispatch table for matches of len==3 : larger == faster, more memory */
+ U32* hashTable;
+ U32* hashTable3;
+ U32* chainTable;
+ optState_t opt; /* optimal parser state */
+ const ZSTD_matchState_t* dictMatchState;
+ ZSTD_compressionParameters cParams;
+};
+
+typedef struct {
+ ZSTD_compressedBlockState_t* prevCBlock;
+ ZSTD_compressedBlockState_t* nextCBlock;
+ ZSTD_matchState_t matchState;
+} ZSTD_blockState_t;
+
+typedef struct {
+ U32 offset;
+ U32 checksum;
+} ldmEntry_t;
+
+typedef struct {
+ ZSTD_window_t window; /* State for the window round buffer management */
+ ldmEntry_t* hashTable;
+ U32 loadedDictEnd;
+ BYTE* bucketOffsets; /* Next position in bucket to insert entry */
+ U64 hashPower; /* Used to compute the rolling hash.
+ * Depends on ldmParams.minMatchLength */
+} ldmState_t;
+
+typedef struct {
+ U32 enableLdm; /* 1 if enable long distance matching */
+ U32 hashLog; /* Log size of hashTable */
+ U32 bucketSizeLog; /* Log bucket size for collision resolution, at most 8 */
+ U32 minMatchLength; /* Minimum match length */
+ U32 hashRateLog; /* Log number of entries to skip */
+ U32 windowLog; /* Window log for the LDM */
+} ldmParams_t;
+
+typedef struct {
+ U32 offset;
+ U32 litLength;
+ U32 matchLength;
+} rawSeq;
+
+typedef struct {
+ rawSeq* seq; /* The start of the sequences */
+ size_t pos; /* The position where reading stopped. <= size. */
+ size_t size; /* The number of sequences. <= capacity. */
+ size_t capacity; /* The capacity starting from `seq` pointer */
+} rawSeqStore_t;
+
+typedef struct {
+ int collectSequences;
+ ZSTD_Sequence* seqStart;
+ size_t seqIndex;
+ size_t maxSequences;
+} SeqCollector;
+
+struct ZSTD_CCtx_params_s {
+ ZSTD_format_e format;
+ ZSTD_compressionParameters cParams;
+ ZSTD_frameParameters fParams;
+
+ int compressionLevel;
+ int forceWindow; /* force back-references to respect limit of
+ * 1<<wLog, even for dictionary */
+ size_t targetCBlockSize; /* Tries to fit compressed block size to be around targetCBlockSize.
+ * No target when targetCBlockSize == 0.
+ * There is no guarantee on compressed block size */
+ int srcSizeHint; /* User's best guess of source size.
+ * Hint is not valid when srcSizeHint == 0.
+ * There is no guarantee that hint is close to actual source size */
+
+ ZSTD_dictAttachPref_e attachDictPref;
+ ZSTD_literalCompressionMode_e literalCompressionMode;
+
+ /* Multithreading: used to pass parameters to mtctx */
+ int nbWorkers;
+ size_t jobSize;
+ int overlapLog;
+ int rsyncable;
+
+ /* Long distance matching parameters */
+ ldmParams_t ldmParams;
+
+ /* Internal use, for createCCtxParams() and freeCCtxParams() only */
+ ZSTD_customMem customMem;
+}; /* typedef'd to ZSTD_CCtx_params within "zstd.h" */
+
+struct ZSTD_CCtx_s {
+ ZSTD_compressionStage_e stage;
+ int cParamsChanged; /* == 1 if cParams(except wlog) or compression level are changed in requestedParams. Triggers transmission of new params to ZSTDMT (if available) then reset to 0. */
+ int bmi2; /* == 1 if the CPU supports BMI2 and 0 otherwise. CPU support is determined dynamically once per context lifetime. */
+ ZSTD_CCtx_params requestedParams;
+ ZSTD_CCtx_params appliedParams;
+ U32 dictID;
+
+ ZSTD_cwksp workspace; /* manages buffer for dynamic allocations */
+ size_t blockSize;
+ unsigned long long pledgedSrcSizePlusOne; /* this way, 0 (default) == unknown */
+ unsigned long long consumedSrcSize;
+ unsigned long long producedCSize;
+ XXH64_state_t xxhState;
+ ZSTD_customMem customMem;
+ size_t staticSize;
+ SeqCollector seqCollector;
+ int isFirstBlock;
+ int initialized;
+
+ seqStore_t seqStore; /* sequences storage ptrs */
+ ldmState_t ldmState; /* long distance matching state */
+ rawSeq* ldmSequences; /* Storage for the ldm output sequences */
+ size_t maxNbLdmSequences;
+ rawSeqStore_t externSeqStore; /* Mutable reference to external sequences */
+ ZSTD_blockState_t blockState;
+ U32* entropyWorkspace; /* entropy workspace of HUF_WORKSPACE_SIZE bytes */
+
+ /* streaming */
+ char* inBuff;
+ size_t inBuffSize;
+ size_t inToCompress;
+ size_t inBuffPos;
+ size_t inBuffTarget;
+ char* outBuff;
+ size_t outBuffSize;
+ size_t outBuffContentSize;
+ size_t outBuffFlushedSize;
+ ZSTD_cStreamStage streamStage;
+ U32 frameEnded;
+
+ /* Dictionary */
+ ZSTD_localDict localDict;
+ const ZSTD_CDict* cdict;
+ ZSTD_prefixDict prefixDict; /* single-usage dictionary */
+
+ /* Multi-threading */
+#ifdef ZSTD_MULTITHREAD
+ ZSTDMT_CCtx* mtctx;
+#endif
+};
+
+typedef enum { ZSTD_dtlm_fast, ZSTD_dtlm_full } ZSTD_dictTableLoadMethod_e;
+
+typedef enum { ZSTD_noDict = 0, ZSTD_extDict = 1, ZSTD_dictMatchState = 2 } ZSTD_dictMode_e;
+
+
+typedef size_t (*ZSTD_blockCompressor) (
+ ZSTD_matchState_t* bs, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode);
+
+
+MEM_STATIC U32 ZSTD_LLcode(U32 litLength)
+{
+ static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 16, 17, 17, 18, 18, 19, 19,
+ 20, 20, 20, 20, 21, 21, 21, 21,
+ 22, 22, 22, 22, 22, 22, 22, 22,
+ 23, 23, 23, 23, 23, 23, 23, 23,
+ 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24 };
+ static const U32 LL_deltaCode = 19;
+ return (litLength > 63) ? ZSTD_highbit32(litLength) + LL_deltaCode : LL_Code[litLength];
+}
+
+/* ZSTD_MLcode() :
+ * note : mlBase = matchLength - MINMATCH;
+ * because it's the format it's stored in seqStore->sequences */
+MEM_STATIC U32 ZSTD_MLcode(U32 mlBase)
+{
+ static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
+ 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+ 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
+ static const U32 ML_deltaCode = 36;
+ return (mlBase > 127) ? ZSTD_highbit32(mlBase) + ML_deltaCode : ML_Code[mlBase];
+}
+
+typedef struct repcodes_s {
+ U32 rep[3];
+} repcodes_t;
+
+MEM_STATIC repcodes_t ZSTD_updateRep(U32 const rep[3], U32 const offset, U32 const ll0)
+{
+ repcodes_t newReps;
+ if (offset >= ZSTD_REP_NUM) { /* full offset */
+ newReps.rep[2] = rep[1];
+ newReps.rep[1] = rep[0];
+ newReps.rep[0] = offset - ZSTD_REP_MOVE;
+ } else { /* repcode */
+ U32 const repCode = offset + ll0;
+ if (repCode > 0) { /* note : if repCode==0, no change */
+ U32 const currentOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode];
+ newReps.rep[2] = (repCode >= 2) ? rep[1] : rep[2];
+ newReps.rep[1] = rep[0];
+ newReps.rep[0] = currentOffset;
+ } else { /* repCode == 0 */
+ memcpy(&newReps, rep, sizeof(newReps));
+ }
+ }
+ return newReps;
+}
+
+/* ZSTD_cParam_withinBounds:
+ * @return 1 if value is within cParam bounds,
+ * 0 otherwise */
+MEM_STATIC int ZSTD_cParam_withinBounds(ZSTD_cParameter cParam, int value)
+{
+ ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam);
+ if (ZSTD_isError(bounds.error)) return 0;
+ if (value < bounds.lowerBound) return 0;
+ if (value > bounds.upperBound) return 0;
+ return 1;
+}
+
+/* ZSTD_noCompressBlock() :
+ * Writes uncompressed block to dst buffer from given src.
+ * Returns the size of the block */
+MEM_STATIC size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize, U32 lastBlock)
+{
+ U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(srcSize << 3);
+ RETURN_ERROR_IF(srcSize + ZSTD_blockHeaderSize > dstCapacity,
+ dstSize_tooSmall, "dst buf too small for uncompressed block");
+ MEM_writeLE24(dst, cBlockHeader24);
+ memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize);
+ return ZSTD_blockHeaderSize + srcSize;
+}
+
+MEM_STATIC size_t ZSTD_rleCompressBlock (void* dst, size_t dstCapacity, BYTE src, size_t srcSize, U32 lastBlock)
+{
+ BYTE* const op = (BYTE*)dst;
+ U32 const cBlockHeader = lastBlock + (((U32)bt_rle)<<1) + (U32)(srcSize << 3);
+ RETURN_ERROR_IF(dstCapacity < 4, dstSize_tooSmall, "");
+ MEM_writeLE24(op, cBlockHeader);
+ op[3] = src;
+ return 4;
+}
+
+
+/* ZSTD_minGain() :
+ * minimum compression required
+ * to generate a compress block or a compressed literals section.
+ * note : use same formula for both situations */
+MEM_STATIC size_t ZSTD_minGain(size_t srcSize, ZSTD_strategy strat)
+{
+ U32 const minlog = (strat>=ZSTD_btultra) ? (U32)(strat) - 1 : 6;
+ ZSTD_STATIC_ASSERT(ZSTD_btultra == 8);
+ assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, strat));
+ return (srcSize >> minlog) + 2;
+}
+
+MEM_STATIC int ZSTD_disableLiteralsCompression(const ZSTD_CCtx_params* cctxParams)
+{
+ switch (cctxParams->literalCompressionMode) {
+ case ZSTD_lcm_huffman:
+ return 0;
+ case ZSTD_lcm_uncompressed:
+ return 1;
+ default:
+ assert(0 /* impossible: pre-validated */);
+ /* fall-through */
+ case ZSTD_lcm_auto:
+ return (cctxParams->cParams.strategy == ZSTD_fast) && (cctxParams->cParams.targetLength > 0);
+ }
+}
+
+/*! ZSTD_safecopyLiterals() :
+ * memcpy() function that won't read beyond more than WILDCOPY_OVERLENGTH bytes past ilimit_w.
+ * Only called when the sequence ends past ilimit_w, so it only needs to be optimized for single
+ * large copies.
+ */
+static void ZSTD_safecopyLiterals(BYTE* op, BYTE const* ip, BYTE const* const iend, BYTE const* ilimit_w) {
+ assert(iend > ilimit_w);
+ if (ip <= ilimit_w) {
+ ZSTD_wildcopy(op, ip, ilimit_w - ip, ZSTD_no_overlap);
+ op += ilimit_w - ip;
+ ip = ilimit_w;
+ }
+ while (ip < iend) *op++ = *ip++;
+}
+
+/*! ZSTD_storeSeq() :
+ * Store a sequence (litlen, litPtr, offCode and mlBase) into seqStore_t.
+ * `offCode` : distance to match + ZSTD_REP_MOVE (values <= ZSTD_REP_MOVE are repCodes).
+ * `mlBase` : matchLength - MINMATCH
+ * Allowed to overread literals up to litLimit.
+*/
+HINT_INLINE UNUSED_ATTR
+void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, const BYTE* litLimit, U32 offCode, size_t mlBase)
+{
+ BYTE const* const litLimit_w = litLimit - WILDCOPY_OVERLENGTH;
+ BYTE const* const litEnd = literals + litLength;
+#if defined(DEBUGLEVEL) && (DEBUGLEVEL >= 6)
+ static const BYTE* g_start = NULL;
+ if (g_start==NULL) g_start = (const BYTE*)literals; /* note : index only works for compression within a single segment */
+ { U32 const pos = (U32)((const BYTE*)literals - g_start);
+ DEBUGLOG(6, "Cpos%7u :%3u literals, match%4u bytes at offCode%7u",
+ pos, (U32)litLength, (U32)mlBase+MINMATCH, (U32)offCode);
+ }
+#endif
+ assert((size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart) < seqStorePtr->maxNbSeq);
+ /* copy Literals */
+ assert(seqStorePtr->maxNbLit <= 128 KB);
+ assert(seqStorePtr->lit + litLength <= seqStorePtr->litStart + seqStorePtr->maxNbLit);
+ assert(literals + litLength <= litLimit);
+ if (litEnd <= litLimit_w) {
+ /* Common case we can use wildcopy.
+ * First copy 16 bytes, because literals are likely short.
+ */
+ assert(WILDCOPY_OVERLENGTH >= 16);
+ ZSTD_copy16(seqStorePtr->lit, literals);
+ if (litLength > 16) {
+ ZSTD_wildcopy(seqStorePtr->lit+16, literals+16, (ptrdiff_t)litLength-16, ZSTD_no_overlap);
+ }
+ } else {
+ ZSTD_safecopyLiterals(seqStorePtr->lit, literals, litEnd, litLimit_w);
+ }
+ seqStorePtr->lit += litLength;
+
+ /* literal Length */
+ if (litLength>0xFFFF) {
+ assert(seqStorePtr->longLengthID == 0); /* there can only be a single long length */
+ seqStorePtr->longLengthID = 1;
+ seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
+ }
+ seqStorePtr->sequences[0].litLength = (U16)litLength;
+
+ /* match offset */
+ seqStorePtr->sequences[0].offset = offCode + 1;
+
+ /* match Length */
+ if (mlBase>0xFFFF) {
+ assert(seqStorePtr->longLengthID == 0); /* there can only be a single long length */
+ seqStorePtr->longLengthID = 2;
+ seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
+ }
+ seqStorePtr->sequences[0].matchLength = (U16)mlBase;
+
+ seqStorePtr->sequences++;
+}
+
+
+/*-*************************************
+* Match length counter
+***************************************/
+static unsigned ZSTD_NbCommonBytes (size_t val)
+{
+ if (MEM_isLittleEndian()) {
+ if (MEM_64bits()) {
+# if defined(_MSC_VER) && defined(_WIN64)
+ unsigned long r = 0;
+ return _BitScanForward64( &r, (U64)val ) ? (unsigned)(r >> 3) : 0;
+# elif defined(__GNUC__) && (__GNUC__ >= 4)
+ return (__builtin_ctzll((U64)val) >> 3);
+# else
+ static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2,
+ 0, 3, 1, 3, 1, 4, 2, 7,
+ 0, 2, 3, 6, 1, 5, 3, 5,
+ 1, 3, 4, 4, 2, 5, 6, 7,
+ 7, 0, 1, 2, 3, 3, 4, 6,
+ 2, 6, 5, 5, 3, 4, 5, 6,
+ 7, 1, 2, 4, 6, 4, 4, 5,
+ 7, 2, 6, 5, 7, 6, 7, 7 };
+ return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
+# endif
+ } else { /* 32 bits */
+# if defined(_MSC_VER)
+ unsigned long r=0;
+ return _BitScanForward( &r, (U32)val ) ? (unsigned)(r >> 3) : 0;
+# elif defined(__GNUC__) && (__GNUC__ >= 3)
+ return (__builtin_ctz((U32)val) >> 3);
+# else
+ static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0,
+ 3, 2, 2, 1, 3, 2, 0, 1,
+ 3, 3, 1, 2, 2, 2, 2, 0,
+ 3, 1, 2, 0, 1, 0, 1, 1 };
+ return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
+# endif
+ }
+ } else { /* Big Endian CPU */
+ if (MEM_64bits()) {
+# if defined(_MSC_VER) && defined(_WIN64)
+ unsigned long r = 0;
+ return _BitScanReverse64( &r, val ) ? (unsigned)(r >> 3) : 0;
+# elif defined(__GNUC__) && (__GNUC__ >= 4)
+ return (__builtin_clzll(val) >> 3);
+# else
+ unsigned r;
+ const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
+ if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
+ if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
+ r += (!val);
+ return r;
+# endif
+ } else { /* 32 bits */
+# if defined(_MSC_VER)
+ unsigned long r = 0;
+ return _BitScanReverse( &r, (unsigned long)val ) ? (unsigned)(r >> 3) : 0;
+# elif defined(__GNUC__) && (__GNUC__ >= 3)
+ return (__builtin_clz((U32)val) >> 3);
+# else
+ unsigned r;
+ if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
+ r += (!val);
+ return r;
+# endif
+ } }
+}
+
+
+MEM_STATIC size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit)
+{
+ const BYTE* const pStart = pIn;
+ const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1);
+
+ if (pIn < pInLoopLimit) {
+ { size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
+ if (diff) return ZSTD_NbCommonBytes(diff); }
+ pIn+=sizeof(size_t); pMatch+=sizeof(size_t);
+ while (pIn < pInLoopLimit) {
+ size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
+ if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
+ pIn += ZSTD_NbCommonBytes(diff);
+ return (size_t)(pIn - pStart);
+ } }
+ if (MEM_64bits() && (pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
+ if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
+ if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
+ return (size_t)(pIn - pStart);
+}
+
+/** ZSTD_count_2segments() :
+ * can count match length with `ip` & `match` in 2 different segments.
+ * convention : on reaching mEnd, match count continue starting from iStart
+ */
+MEM_STATIC size_t
+ZSTD_count_2segments(const BYTE* ip, const BYTE* match,
+ const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
+{
+ const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd);
+ size_t const matchLength = ZSTD_count(ip, match, vEnd);
+ if (match + matchLength != mEnd) return matchLength;
+ DEBUGLOG(7, "ZSTD_count_2segments: found a 2-parts match (current length==%zu)", matchLength);
+ DEBUGLOG(7, "distance from match beginning to end dictionary = %zi", mEnd - match);
+ DEBUGLOG(7, "distance from current pos to end buffer = %zi", iEnd - ip);
+ DEBUGLOG(7, "next byte : ip==%02X, istart==%02X", ip[matchLength], *iStart);
+ DEBUGLOG(7, "final match length = %zu", matchLength + ZSTD_count(ip+matchLength, iStart, iEnd));
+ return matchLength + ZSTD_count(ip+matchLength, iStart, iEnd);
+}
+
+
+/*-*************************************
+ * Hashes
+ ***************************************/
+static const U32 prime3bytes = 506832829U;
+static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
+MEM_STATIC size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_readLE32(ptr), h); } /* only in zstd_opt.h */
+
+static const U32 prime4bytes = 2654435761U;
+static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
+static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
+
+static const U64 prime5bytes = 889523592379ULL;
+static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
+static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
+
+static const U64 prime6bytes = 227718039650203ULL;
+static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
+static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
+
+static const U64 prime7bytes = 58295818150454627ULL;
+static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
+static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
+
+static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
+static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
+static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
+
+MEM_STATIC size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
+{
+ switch(mls)
+ {
+ default:
+ case 4: return ZSTD_hash4Ptr(p, hBits);
+ case 5: return ZSTD_hash5Ptr(p, hBits);
+ case 6: return ZSTD_hash6Ptr(p, hBits);
+ case 7: return ZSTD_hash7Ptr(p, hBits);
+ case 8: return ZSTD_hash8Ptr(p, hBits);
+ }
+}
+
+/** ZSTD_ipow() :
+ * Return base^exponent.
+ */
+static U64 ZSTD_ipow(U64 base, U64 exponent)
+{
+ U64 power = 1;
+ while (exponent) {
+ if (exponent & 1) power *= base;
+ exponent >>= 1;
+ base *= base;
+ }
+ return power;
+}
+
+#define ZSTD_ROLL_HASH_CHAR_OFFSET 10
+
+/** ZSTD_rollingHash_append() :
+ * Add the buffer to the hash value.
+ */
+static U64 ZSTD_rollingHash_append(U64 hash, void const* buf, size_t size)
+{
+ BYTE const* istart = (BYTE const*)buf;
+ size_t pos;
+ for (pos = 0; pos < size; ++pos) {
+ hash *= prime8bytes;
+ hash += istart[pos] + ZSTD_ROLL_HASH_CHAR_OFFSET;
+ }
+ return hash;
+}
+
+/** ZSTD_rollingHash_compute() :
+ * Compute the rolling hash value of the buffer.
+ */
+MEM_STATIC U64 ZSTD_rollingHash_compute(void const* buf, size_t size)
+{
+ return ZSTD_rollingHash_append(0, buf, size);
+}
+
+/** ZSTD_rollingHash_primePower() :
+ * Compute the primePower to be passed to ZSTD_rollingHash_rotate() for a hash
+ * over a window of length bytes.
+ */
+MEM_STATIC U64 ZSTD_rollingHash_primePower(U32 length)
+{
+ return ZSTD_ipow(prime8bytes, length - 1);
+}
+
+/** ZSTD_rollingHash_rotate() :
+ * Rotate the rolling hash by one byte.
+ */
+MEM_STATIC U64 ZSTD_rollingHash_rotate(U64 hash, BYTE toRemove, BYTE toAdd, U64 primePower)
+{
+ hash -= (toRemove + ZSTD_ROLL_HASH_CHAR_OFFSET) * primePower;
+ hash *= prime8bytes;
+ hash += toAdd + ZSTD_ROLL_HASH_CHAR_OFFSET;
+ return hash;
+}
+
+/*-*************************************
+* Round buffer management
+***************************************/
+#if (ZSTD_WINDOWLOG_MAX_64 > 31)
+# error "ZSTD_WINDOWLOG_MAX is too large : would overflow ZSTD_CURRENT_MAX"
+#endif
+/* Max current allowed */
+#define ZSTD_CURRENT_MAX ((3U << 29) + (1U << ZSTD_WINDOWLOG_MAX))
+/* Maximum chunk size before overflow correction needs to be called again */
+#define ZSTD_CHUNKSIZE_MAX \
+ ( ((U32)-1) /* Maximum ending current index */ \
+ - ZSTD_CURRENT_MAX) /* Maximum beginning lowLimit */
+
+/**
+ * ZSTD_window_clear():
+ * Clears the window containing the history by simply setting it to empty.
+ */
+MEM_STATIC void ZSTD_window_clear(ZSTD_window_t* window)
+{
+ size_t const endT = (size_t)(window->nextSrc - window->base);
+ U32 const end = (U32)endT;
+
+ window->lowLimit = end;
+ window->dictLimit = end;
+}
+
+/**
+ * ZSTD_window_hasExtDict():
+ * Returns non-zero if the window has a non-empty extDict.
+ */
+MEM_STATIC U32 ZSTD_window_hasExtDict(ZSTD_window_t const window)
+{
+ return window.lowLimit < window.dictLimit;
+}
+
+/**
+ * ZSTD_matchState_dictMode():
+ * Inspects the provided matchState and figures out what dictMode should be
+ * passed to the compressor.
+ */
+MEM_STATIC ZSTD_dictMode_e ZSTD_matchState_dictMode(const ZSTD_matchState_t *ms)
+{
+ return ZSTD_window_hasExtDict(ms->window) ?
+ ZSTD_extDict :
+ ms->dictMatchState != NULL ?
+ ZSTD_dictMatchState :
+ ZSTD_noDict;
+}
+
+/**
+ * ZSTD_window_needOverflowCorrection():
+ * Returns non-zero if the indices are getting too large and need overflow
+ * protection.
+ */
+MEM_STATIC U32 ZSTD_window_needOverflowCorrection(ZSTD_window_t const window,
+ void const* srcEnd)
+{
+ U32 const current = (U32)((BYTE const*)srcEnd - window.base);
+ return current > ZSTD_CURRENT_MAX;
+}
+
+/**
+ * ZSTD_window_correctOverflow():
+ * Reduces the indices to protect from index overflow.
+ * Returns the correction made to the indices, which must be applied to every
+ * stored index.
+ *
+ * The least significant cycleLog bits of the indices must remain the same,
+ * which may be 0. Every index up to maxDist in the past must be valid.
+ * NOTE: (maxDist & cycleMask) must be zero.
+ */
+MEM_STATIC U32 ZSTD_window_correctOverflow(ZSTD_window_t* window, U32 cycleLog,
+ U32 maxDist, void const* src)
+{
+ /* preemptive overflow correction:
+ * 1. correction is large enough:
+ * lowLimit > (3<<29) ==> current > 3<<29 + 1<<windowLog
+ * 1<<windowLog <= newCurrent < 1<<chainLog + 1<<windowLog
+ *
+ * current - newCurrent
+ * > (3<<29 + 1<<windowLog) - (1<<windowLog + 1<<chainLog)
+ * > (3<<29) - (1<<chainLog)
+ * > (3<<29) - (1<<30) (NOTE: chainLog <= 30)
+ * > 1<<29
+ *
+ * 2. (ip+ZSTD_CHUNKSIZE_MAX - cctx->base) doesn't overflow:
+ * After correction, current is less than (1<<chainLog + 1<<windowLog).
+ * In 64-bit mode we are safe, because we have 64-bit ptrdiff_t.
+ * In 32-bit mode we are safe, because (chainLog <= 29), so
+ * ip+ZSTD_CHUNKSIZE_MAX - cctx->base < 1<<32.
+ * 3. (cctx->lowLimit + 1<<windowLog) < 1<<32:
+ * windowLog <= 31 ==> 3<<29 + 1<<windowLog < 7<<29 < 1<<32.
+ */
+ U32 const cycleMask = (1U << cycleLog) - 1;
+ U32 const current = (U32)((BYTE const*)src - window->base);
+ U32 const currentCycle0 = current & cycleMask;
+ /* Exclude zero so that newCurrent - maxDist >= 1. */
+ U32 const currentCycle1 = currentCycle0 == 0 ? (1U << cycleLog) : currentCycle0;
+ U32 const newCurrent = currentCycle1 + maxDist;
+ U32 const correction = current - newCurrent;
+ assert((maxDist & cycleMask) == 0);
+ assert(current > newCurrent);
+ /* Loose bound, should be around 1<<29 (see above) */
+ assert(correction > 1<<28);
+
+ window->base += correction;
+ window->dictBase += correction;
+ if (window->lowLimit <= correction) window->lowLimit = 1;
+ else window->lowLimit -= correction;
+ if (window->dictLimit <= correction) window->dictLimit = 1;
+ else window->dictLimit -= correction;
+
+ /* Ensure we can still reference the full window. */
+ assert(newCurrent >= maxDist);
+ assert(newCurrent - maxDist >= 1);
+ /* Ensure that lowLimit and dictLimit didn't underflow. */
+ assert(window->lowLimit <= newCurrent);
+ assert(window->dictLimit <= newCurrent);
+
+ DEBUGLOG(4, "Correction of 0x%x bytes to lowLimit=0x%x", correction,
+ window->lowLimit);
+ return correction;
+}
+
+/**
+ * ZSTD_window_enforceMaxDist():
+ * Updates lowLimit so that:
+ * (srcEnd - base) - lowLimit == maxDist + loadedDictEnd
+ *
+ * It ensures index is valid as long as index >= lowLimit.
+ * This must be called before a block compression call.
+ *
+ * loadedDictEnd is only defined if a dictionary is in use for current compression.
+ * As the name implies, loadedDictEnd represents the index at end of dictionary.
+ * The value lies within context's referential, it can be directly compared to blockEndIdx.
+ *
+ * If loadedDictEndPtr is NULL, no dictionary is in use, and we use loadedDictEnd == 0.
+ * If loadedDictEndPtr is not NULL, we set it to zero after updating lowLimit.
+ * This is because dictionaries are allowed to be referenced fully
+ * as long as the last byte of the dictionary is in the window.
+ * Once input has progressed beyond window size, dictionary cannot be referenced anymore.
+ *
+ * In normal dict mode, the dictionary lies between lowLimit and dictLimit.
+ * In dictMatchState mode, lowLimit and dictLimit are the same,
+ * and the dictionary is below them.
+ * forceWindow and dictMatchState are therefore incompatible.
+ */
+MEM_STATIC void
+ZSTD_window_enforceMaxDist(ZSTD_window_t* window,
+ const void* blockEnd,
+ U32 maxDist,
+ U32* loadedDictEndPtr,
+ const ZSTD_matchState_t** dictMatchStatePtr)
+{
+ U32 const blockEndIdx = (U32)((BYTE const*)blockEnd - window->base);
+ U32 const loadedDictEnd = (loadedDictEndPtr != NULL) ? *loadedDictEndPtr : 0;
+ DEBUGLOG(5, "ZSTD_window_enforceMaxDist: blockEndIdx=%u, maxDist=%u, loadedDictEnd=%u",
+ (unsigned)blockEndIdx, (unsigned)maxDist, (unsigned)loadedDictEnd);
+
+ /* - When there is no dictionary : loadedDictEnd == 0.
+ In which case, the test (blockEndIdx > maxDist) is merely to avoid
+ overflowing next operation `newLowLimit = blockEndIdx - maxDist`.
+ - When there is a standard dictionary :
+ Index referential is copied from the dictionary,
+ which means it starts from 0.
+ In which case, loadedDictEnd == dictSize,
+ and it makes sense to compare `blockEndIdx > maxDist + dictSize`
+ since `blockEndIdx` also starts from zero.
+ - When there is an attached dictionary :
+ loadedDictEnd is expressed within the referential of the context,
+ so it can be directly compared against blockEndIdx.
+ */
+ if (blockEndIdx > maxDist + loadedDictEnd) {
+ U32 const newLowLimit = blockEndIdx - maxDist;
+ if (window->lowLimit < newLowLimit) window->lowLimit = newLowLimit;
+ if (window->dictLimit < window->lowLimit) {
+ DEBUGLOG(5, "Update dictLimit to match lowLimit, from %u to %u",
+ (unsigned)window->dictLimit, (unsigned)window->lowLimit);
+ window->dictLimit = window->lowLimit;
+ }
+ /* On reaching window size, dictionaries are invalidated */
+ if (loadedDictEndPtr) *loadedDictEndPtr = 0;
+ if (dictMatchStatePtr) *dictMatchStatePtr = NULL;
+ }
+}
+
+/* Similar to ZSTD_window_enforceMaxDist(),
+ * but only invalidates dictionary
+ * when input progresses beyond window size.
+ * assumption : loadedDictEndPtr and dictMatchStatePtr are valid (non NULL)
+ * loadedDictEnd uses same referential as window->base
+ * maxDist is the window size */
+MEM_STATIC void
+ZSTD_checkDictValidity(const ZSTD_window_t* window,
+ const void* blockEnd,
+ U32 maxDist,
+ U32* loadedDictEndPtr,
+ const ZSTD_matchState_t** dictMatchStatePtr)
+{
+ assert(loadedDictEndPtr != NULL);
+ assert(dictMatchStatePtr != NULL);
+ { U32 const blockEndIdx = (U32)((BYTE const*)blockEnd - window->base);
+ U32 const loadedDictEnd = *loadedDictEndPtr;
+ DEBUGLOG(5, "ZSTD_checkDictValidity: blockEndIdx=%u, maxDist=%u, loadedDictEnd=%u",
+ (unsigned)blockEndIdx, (unsigned)maxDist, (unsigned)loadedDictEnd);
+ assert(blockEndIdx >= loadedDictEnd);
+
+ if (blockEndIdx > loadedDictEnd + maxDist) {
+ /* On reaching window size, dictionaries are invalidated.
+ * For simplification, if window size is reached anywhere within next block,
+ * the dictionary is invalidated for the full block.
+ */
+ DEBUGLOG(6, "invalidating dictionary for current block (distance > windowSize)");
+ *loadedDictEndPtr = 0;
+ *dictMatchStatePtr = NULL;
+ } else {
+ if (*loadedDictEndPtr != 0) {
+ DEBUGLOG(6, "dictionary considered valid for current block");
+ } } }
+}
+
+MEM_STATIC void ZSTD_window_init(ZSTD_window_t* window) {
+ memset(window, 0, sizeof(*window));
+ window->base = (BYTE const*)"";
+ window->dictBase = (BYTE const*)"";
+ window->dictLimit = 1; /* start from 1, so that 1st position is valid */
+ window->lowLimit = 1; /* it ensures first and later CCtx usages compress the same */
+ window->nextSrc = window->base + 1; /* see issue #1241 */
+}
+
+/**
+ * ZSTD_window_update():
+ * Updates the window by appending [src, src + srcSize) to the window.
+ * If it is not contiguous, the current prefix becomes the extDict, and we
+ * forget about the extDict. Handles overlap of the prefix and extDict.
+ * Returns non-zero if the segment is contiguous.
+ */
+MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window,
+ void const* src, size_t srcSize)
+{
+ BYTE const* const ip = (BYTE const*)src;
+ U32 contiguous = 1;
+ DEBUGLOG(5, "ZSTD_window_update");
+ if (srcSize == 0)
+ return contiguous;
+ assert(window->base != NULL);
+ assert(window->dictBase != NULL);
+ /* Check if blocks follow each other */
+ if (src != window->nextSrc) {
+ /* not contiguous */
+ size_t const distanceFromBase = (size_t)(window->nextSrc - window->base);
+ DEBUGLOG(5, "Non contiguous blocks, new segment starts at %u", window->dictLimit);
+ window->lowLimit = window->dictLimit;
+ assert(distanceFromBase == (size_t)(U32)distanceFromBase); /* should never overflow */
+ window->dictLimit = (U32)distanceFromBase;
+ window->dictBase = window->base;
+ window->base = ip - distanceFromBase;
+ /* ms->nextToUpdate = window->dictLimit; */
+ if (window->dictLimit - window->lowLimit < HASH_READ_SIZE) window->lowLimit = window->dictLimit; /* too small extDict */
+ contiguous = 0;
+ }
+ window->nextSrc = ip + srcSize;
+ /* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */
+ if ( (ip+srcSize > window->dictBase + window->lowLimit)
+ & (ip < window->dictBase + window->dictLimit)) {
+ ptrdiff_t const highInputIdx = (ip + srcSize) - window->dictBase;
+ U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)window->dictLimit) ? window->dictLimit : (U32)highInputIdx;
+ window->lowLimit = lowLimitMax;
+ DEBUGLOG(5, "Overlapping extDict and input : new lowLimit = %u", window->lowLimit);
+ }
+ return contiguous;
+}
+
+/**
+ * Returns the lowest allowed match index. It may either be in the ext-dict or the prefix.
+ */
+MEM_STATIC U32 ZSTD_getLowestMatchIndex(const ZSTD_matchState_t* ms, U32 current, unsigned windowLog)
+{
+ U32 const maxDistance = 1U << windowLog;
+ U32 const lowestValid = ms->window.lowLimit;
+ U32 const withinWindow = (current - lowestValid > maxDistance) ? current - maxDistance : lowestValid;
+ U32 const isDictionary = (ms->loadedDictEnd != 0);
+ U32 const matchLowest = isDictionary ? lowestValid : withinWindow;
+ return matchLowest;
+}
+
+/**
+ * Returns the lowest allowed match index in the prefix.
+ */
+MEM_STATIC U32 ZSTD_getLowestPrefixIndex(const ZSTD_matchState_t* ms, U32 current, unsigned windowLog)
+{
+ U32 const maxDistance = 1U << windowLog;
+ U32 const lowestValid = ms->window.dictLimit;
+ U32 const withinWindow = (current - lowestValid > maxDistance) ? current - maxDistance : lowestValid;
+ U32 const isDictionary = (ms->loadedDictEnd != 0);
+ U32 const matchLowest = isDictionary ? lowestValid : withinWindow;
+ return matchLowest;
+}
+
+
+
+/* debug functions */
+#if (DEBUGLEVEL>=2)
+
+MEM_STATIC double ZSTD_fWeight(U32 rawStat)
+{
+ U32 const fp_accuracy = 8;
+ U32 const fp_multiplier = (1 << fp_accuracy);
+ U32 const newStat = rawStat + 1;
+ U32 const hb = ZSTD_highbit32(newStat);
+ U32 const BWeight = hb * fp_multiplier;
+ U32 const FWeight = (newStat << fp_accuracy) >> hb;
+ U32 const weight = BWeight + FWeight;
+ assert(hb + fp_accuracy < 31);
+ return (double)weight / fp_multiplier;
+}
+
+/* display a table content,
+ * listing each element, its frequency, and its predicted bit cost */
+MEM_STATIC void ZSTD_debugTable(const U32* table, U32 max)
+{
+ unsigned u, sum;
+ for (u=0, sum=0; u<=max; u++) sum += table[u];
+ DEBUGLOG(2, "total nb elts: %u", sum);
+ for (u=0; u<=max; u++) {
+ DEBUGLOG(2, "%2u: %5u (%.2f)",
+ u, table[u], ZSTD_fWeight(sum) - ZSTD_fWeight(table[u]) );
+ }
+}
+
+#endif
+
+
+#if defined (__cplusplus)
+}
+#endif
+
+/* ===============================================================
+ * Shared internal declarations
+ * These prototypes may be called from sources not in lib/compress
+ * =============================================================== */
+
+/* ZSTD_loadCEntropy() :
+ * dict : must point at beginning of a valid zstd dictionary.
+ * return : size of dictionary header (size of magic number + dict ID + entropy tables)
+ * assumptions : magic number supposed already checked
+ * and dictSize >= 8 */
+size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace,
+ short* offcodeNCount, unsigned* offcodeMaxValue,
+ const void* const dict, size_t dictSize);
+
+void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs);
+
+/* ==============================================================
+ * Private declarations
+ * These prototypes shall only be called from within lib/compress
+ * ============================================================== */
+
+/* ZSTD_getCParamsFromCCtxParams() :
+ * cParams are built depending on compressionLevel, src size hints,
+ * LDM and manually set compression parameters.
+ * Note: srcSizeHint == 0 means 0!
+ */
+ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams(
+ const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize);
+
+/*! ZSTD_initCStream_internal() :
+ * Private use only. Init streaming operation.
+ * expects params to be valid.
+ * must receive dict, or cdict, or none, but not both.
+ * @return : 0, or an error code */
+size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
+ const void* dict, size_t dictSize,
+ const ZSTD_CDict* cdict,
+ const ZSTD_CCtx_params* params, unsigned long long pledgedSrcSize);
+
+void ZSTD_resetSeqStore(seqStore_t* ssPtr);
+
+/*! ZSTD_getCParamsFromCDict() :
+ * as the name implies */
+ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict);
+
+/* ZSTD_compressBegin_advanced_internal() :
+ * Private use only. To be called from zstdmt_compress.c. */
+size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx,
+ const void* dict, size_t dictSize,
+ ZSTD_dictContentType_e dictContentType,
+ ZSTD_dictTableLoadMethod_e dtlm,
+ const ZSTD_CDict* cdict,
+ const ZSTD_CCtx_params* params,
+ unsigned long long pledgedSrcSize);
+
+/* ZSTD_compress_advanced_internal() :
+ * Private use only. To be called from zstdmt_compress.c. */
+size_t ZSTD_compress_advanced_internal(ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const void* dict,size_t dictSize,
+ const ZSTD_CCtx_params* params);
+
+
+/* ZSTD_writeLastEmptyBlock() :
+ * output an empty Block with end-of-frame mark to complete a frame
+ * @return : size of data written into `dst` (== ZSTD_blockHeaderSize (defined in zstd_internal.h))
+ * or an error code if `dstCapacity` is too small (<ZSTD_blockHeaderSize)
+ */
+size_t ZSTD_writeLastEmptyBlock(void* dst, size_t dstCapacity);
+
+
+/* ZSTD_referenceExternalSequences() :
+ * Must be called before starting a compression operation.
+ * seqs must parse a prefix of the source.
+ * This cannot be used when long range matching is enabled.
+ * Zstd will use these sequences, and pass the literals to a secondary block
+ * compressor.
+ * @return : An error code on failure.
+ * NOTE: seqs are not verified! Invalid sequences can cause out-of-bounds memory
+ * access and data corruption.
+ */
+size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq);
+
+/** ZSTD_cycleLog() :
+ * condition for correct operation : hashLog > 1 */
+U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat);
+
+#endif /* ZSTD_COMPRESS_H */
diff --git a/sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress_literals.c b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress_literals.c
new file mode 100644
index 000000000000..17e7168d8936
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress_literals.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+ /*-*************************************
+ * Dependencies
+ ***************************************/
+#include "zstd_compress_literals.h"
+
+size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+{
+ BYTE* const ostart = (BYTE* const)dst;
+ U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
+
+ RETURN_ERROR_IF(srcSize + flSize > dstCapacity, dstSize_tooSmall, "");
+
+ switch(flSize)
+ {
+ case 1: /* 2 - 1 - 5 */
+ ostart[0] = (BYTE)((U32)set_basic + (srcSize<<3));
+ break;
+ case 2: /* 2 - 2 - 12 */
+ MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4)));
+ break;
+ case 3: /* 2 - 2 - 20 */
+ MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4)));
+ break;
+ default: /* not necessary : flSize is {1,2,3} */
+ assert(0);
+ }
+
+ memcpy(ostart + flSize, src, srcSize);
+ DEBUGLOG(5, "Raw literals: %u -> %u", (U32)srcSize, (U32)(srcSize + flSize));
+ return srcSize + flSize;
+}
+
+size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+{
+ BYTE* const ostart = (BYTE* const)dst;
+ U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
+
+ (void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */
+
+ switch(flSize)
+ {
+ case 1: /* 2 - 1 - 5 */
+ ostart[0] = (BYTE)((U32)set_rle + (srcSize<<3));
+ break;
+ case 2: /* 2 - 2 - 12 */
+ MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4)));
+ break;
+ case 3: /* 2 - 2 - 20 */
+ MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4)));
+ break;
+ default: /* not necessary : flSize is {1,2,3} */
+ assert(0);
+ }
+
+ ostart[flSize] = *(const BYTE*)src;
+ DEBUGLOG(5, "RLE literals: %u -> %u", (U32)srcSize, (U32)flSize + 1);
+ return flSize+1;
+}
+
+size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf,
+ ZSTD_hufCTables_t* nextHuf,
+ ZSTD_strategy strategy, int disableLiteralCompression,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ void* entropyWorkspace, size_t entropyWorkspaceSize,
+ const int bmi2)
+{
+ size_t const minGain = ZSTD_minGain(srcSize, strategy);
+ size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
+ BYTE* const ostart = (BYTE*)dst;
+ U32 singleStream = srcSize < 256;
+ symbolEncodingType_e hType = set_compressed;
+ size_t cLitSize;
+
+ DEBUGLOG(5,"ZSTD_compressLiterals (disableLiteralCompression=%i srcSize=%u)",
+ disableLiteralCompression, (U32)srcSize);
+
+ /* Prepare nextEntropy assuming reusing the existing table */
+ memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
+
+ if (disableLiteralCompression)
+ return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
+
+ /* small ? don't even attempt compression (speed opt) */
+# define COMPRESS_LITERALS_SIZE_MIN 63
+ { size_t const minLitSize = (prevHuf->repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN;
+ if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
+ }
+
+ RETURN_ERROR_IF(dstCapacity < lhSize+1, dstSize_tooSmall, "not enough space for compression");
+ { HUF_repeat repeat = prevHuf->repeatMode;
+ int const preferRepeat = strategy < ZSTD_lazy ? srcSize <= 1024 : 0;
+ if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1;
+ cLitSize = singleStream ?
+ HUF_compress1X_repeat(
+ ostart+lhSize, dstCapacity-lhSize, src, srcSize,
+ HUF_SYMBOLVALUE_MAX, HUF_TABLELOG_DEFAULT, entropyWorkspace, entropyWorkspaceSize,
+ (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2) :
+ HUF_compress4X_repeat(
+ ostart+lhSize, dstCapacity-lhSize, src, srcSize,
+ HUF_SYMBOLVALUE_MAX, HUF_TABLELOG_DEFAULT, entropyWorkspace, entropyWorkspaceSize,
+ (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2);
+ if (repeat != HUF_repeat_none) {
+ /* reused the existing table */
+ DEBUGLOG(5, "Reusing previous huffman table");
+ hType = set_repeat;
+ }
+ }
+
+ if ((cLitSize==0) | (cLitSize >= srcSize - minGain) | ERR_isError(cLitSize)) {
+ memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
+ return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
+ }
+ if (cLitSize==1) {
+ memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
+ return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
+ }
+
+ if (hType == set_compressed) {
+ /* using a newly constructed table */
+ nextHuf->repeatMode = HUF_repeat_check;
+ }
+
+ /* Build header */
+ switch(lhSize)
+ {
+ case 3: /* 2 - 2 - 10 - 10 */
+ { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14);
+ MEM_writeLE24(ostart, lhc);
+ break;
+ }
+ case 4: /* 2 - 2 - 14 - 14 */
+ { U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18);
+ MEM_writeLE32(ostart, lhc);
+ break;
+ }
+ case 5: /* 2 - 2 - 18 - 18 */
+ { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22);
+ MEM_writeLE32(ostart, lhc);
+ ostart[4] = (BYTE)(cLitSize >> 10);
+ break;
+ }
+ default: /* not possible : lhSize is {3,4,5} */
+ assert(0);
+ }
+ DEBUGLOG(5, "Compressed literals: %u -> %u", (U32)srcSize, (U32)(lhSize+cLitSize));
+ return lhSize+cLitSize;
+}
diff --git a/sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress_literals.h b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress_literals.h
new file mode 100644
index 000000000000..8b0870574326
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress_literals.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_COMPRESS_LITERALS_H
+#define ZSTD_COMPRESS_LITERALS_H
+
+#include "zstd_compress_internal.h" /* ZSTD_hufCTables_t, ZSTD_minGain() */
+
+
+size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize);
+
+size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize);
+
+size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf,
+ ZSTD_hufCTables_t* nextHuf,
+ ZSTD_strategy strategy, int disableLiteralCompression,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ void* entropyWorkspace, size_t entropyWorkspaceSize,
+ const int bmi2);
+
+#endif /* ZSTD_COMPRESS_LITERALS_H */
diff --git a/sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress_sequences.c b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress_sequences.c
new file mode 100644
index 000000000000..f9f8097c839b
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress_sequences.c
@@ -0,0 +1,419 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+ /*-*************************************
+ * Dependencies
+ ***************************************/
+#include "zstd_compress_sequences.h"
+
+/**
+ * -log2(x / 256) lookup table for x in [0, 256).
+ * If x == 0: Return 0
+ * Else: Return floor(-log2(x / 256) * 256)
+ */
+static unsigned const kInverseProbabilityLog256[256] = {
+ 0, 2048, 1792, 1642, 1536, 1453, 1386, 1329, 1280, 1236, 1197, 1162,
+ 1130, 1100, 1073, 1047, 1024, 1001, 980, 960, 941, 923, 906, 889,
+ 874, 859, 844, 830, 817, 804, 791, 779, 768, 756, 745, 734,
+ 724, 714, 704, 694, 685, 676, 667, 658, 650, 642, 633, 626,
+ 618, 610, 603, 595, 588, 581, 574, 567, 561, 554, 548, 542,
+ 535, 529, 523, 517, 512, 506, 500, 495, 489, 484, 478, 473,
+ 468, 463, 458, 453, 448, 443, 438, 434, 429, 424, 420, 415,
+ 411, 407, 402, 398, 394, 390, 386, 382, 377, 373, 370, 366,
+ 362, 358, 354, 350, 347, 343, 339, 336, 332, 329, 325, 322,
+ 318, 315, 311, 308, 305, 302, 298, 295, 292, 289, 286, 282,
+ 279, 276, 273, 270, 267, 264, 261, 258, 256, 253, 250, 247,
+ 244, 241, 239, 236, 233, 230, 228, 225, 222, 220, 217, 215,
+ 212, 209, 207, 204, 202, 199, 197, 194, 192, 190, 187, 185,
+ 182, 180, 178, 175, 173, 171, 168, 166, 164, 162, 159, 157,
+ 155, 153, 151, 149, 146, 144, 142, 140, 138, 136, 134, 132,
+ 130, 128, 126, 123, 121, 119, 117, 115, 114, 112, 110, 108,
+ 106, 104, 102, 100, 98, 96, 94, 93, 91, 89, 87, 85,
+ 83, 82, 80, 78, 76, 74, 73, 71, 69, 67, 66, 64,
+ 62, 61, 59, 57, 55, 54, 52, 50, 49, 47, 46, 44,
+ 42, 41, 39, 37, 36, 34, 33, 31, 30, 28, 26, 25,
+ 23, 22, 20, 19, 17, 16, 14, 13, 11, 10, 8, 7,
+ 5, 4, 2, 1,
+};
+
+static unsigned ZSTD_getFSEMaxSymbolValue(FSE_CTable const* ctable) {
+ void const* ptr = ctable;
+ U16 const* u16ptr = (U16 const*)ptr;
+ U32 const maxSymbolValue = MEM_read16(u16ptr + 1);
+ return maxSymbolValue;
+}
+
+/**
+ * Returns the cost in bytes of encoding the normalized count header.
+ * Returns an error if any of the helper functions return an error.
+ */
+static size_t ZSTD_NCountCost(unsigned const* count, unsigned const max,
+ size_t const nbSeq, unsigned const FSELog)
+{
+ BYTE wksp[FSE_NCOUNTBOUND];
+ S16 norm[MaxSeq + 1];
+ const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max);
+ FORWARD_IF_ERROR(FSE_normalizeCount(norm, tableLog, count, nbSeq, max), "");
+ return FSE_writeNCount(wksp, sizeof(wksp), norm, max, tableLog);
+}
+
+/**
+ * Returns the cost in bits of encoding the distribution described by count
+ * using the entropy bound.
+ */
+static size_t ZSTD_entropyCost(unsigned const* count, unsigned const max, size_t const total)
+{
+ unsigned cost = 0;
+ unsigned s;
+ for (s = 0; s <= max; ++s) {
+ unsigned norm = (unsigned)((256 * count[s]) / total);
+ if (count[s] != 0 && norm == 0)
+ norm = 1;
+ assert(count[s] < total);
+ cost += count[s] * kInverseProbabilityLog256[norm];
+ }
+ return cost >> 8;
+}
+
+/**
+ * Returns the cost in bits of encoding the distribution in count using ctable.
+ * Returns an error if ctable cannot represent all the symbols in count.
+ */
+size_t ZSTD_fseBitCost(
+ FSE_CTable const* ctable,
+ unsigned const* count,
+ unsigned const max)
+{
+ unsigned const kAccuracyLog = 8;
+ size_t cost = 0;
+ unsigned s;
+ FSE_CState_t cstate;
+ FSE_initCState(&cstate, ctable);
+ if (ZSTD_getFSEMaxSymbolValue(ctable) < max) {
+ DEBUGLOG(5, "Repeat FSE_CTable has maxSymbolValue %u < %u",
+ ZSTD_getFSEMaxSymbolValue(ctable), max);
+ return ERROR(GENERIC);
+ }
+ for (s = 0; s <= max; ++s) {
+ unsigned const tableLog = cstate.stateLog;
+ unsigned const badCost = (tableLog + 1) << kAccuracyLog;
+ unsigned const bitCost = FSE_bitCost(cstate.symbolTT, tableLog, s, kAccuracyLog);
+ if (count[s] == 0)
+ continue;
+ if (bitCost >= badCost) {
+ DEBUGLOG(5, "Repeat FSE_CTable has Prob[%u] == 0", s);
+ return ERROR(GENERIC);
+ }
+ cost += (size_t)count[s] * bitCost;
+ }
+ return cost >> kAccuracyLog;
+}
+
+/**
+ * Returns the cost in bits of encoding the distribution in count using the
+ * table described by norm. The max symbol support by norm is assumed >= max.
+ * norm must be valid for every symbol with non-zero probability in count.
+ */
+size_t ZSTD_crossEntropyCost(short const* norm, unsigned accuracyLog,
+ unsigned const* count, unsigned const max)
+{
+ unsigned const shift = 8 - accuracyLog;
+ size_t cost = 0;
+ unsigned s;
+ assert(accuracyLog <= 8);
+ for (s = 0; s <= max; ++s) {
+ unsigned const normAcc = (norm[s] != -1) ? (unsigned)norm[s] : 1;
+ unsigned const norm256 = normAcc << shift;
+ assert(norm256 > 0);
+ assert(norm256 < 256);
+ cost += count[s] * kInverseProbabilityLog256[norm256];
+ }
+ return cost >> 8;
+}
+
+symbolEncodingType_e
+ZSTD_selectEncodingType(
+ FSE_repeat* repeatMode, unsigned const* count, unsigned const max,
+ size_t const mostFrequent, size_t nbSeq, unsigned const FSELog,
+ FSE_CTable const* prevCTable,
+ short const* defaultNorm, U32 defaultNormLog,
+ ZSTD_defaultPolicy_e const isDefaultAllowed,
+ ZSTD_strategy const strategy)
+{
+ ZSTD_STATIC_ASSERT(ZSTD_defaultDisallowed == 0 && ZSTD_defaultAllowed != 0);
+ if (mostFrequent == nbSeq) {
+ *repeatMode = FSE_repeat_none;
+ if (isDefaultAllowed && nbSeq <= 2) {
+ /* Prefer set_basic over set_rle when there are 2 or less symbols,
+ * since RLE uses 1 byte, but set_basic uses 5-6 bits per symbol.
+ * If basic encoding isn't possible, always choose RLE.
+ */
+ DEBUGLOG(5, "Selected set_basic");
+ return set_basic;
+ }
+ DEBUGLOG(5, "Selected set_rle");
+ return set_rle;
+ }
+ if (strategy < ZSTD_lazy) {
+ if (isDefaultAllowed) {
+ size_t const staticFse_nbSeq_max = 1000;
+ size_t const mult = 10 - strategy;
+ size_t const baseLog = 3;
+ size_t const dynamicFse_nbSeq_min = (((size_t)1 << defaultNormLog) * mult) >> baseLog; /* 28-36 for offset, 56-72 for lengths */
+ assert(defaultNormLog >= 5 && defaultNormLog <= 6); /* xx_DEFAULTNORMLOG */
+ assert(mult <= 9 && mult >= 7);
+ if ( (*repeatMode == FSE_repeat_valid)
+ && (nbSeq < staticFse_nbSeq_max) ) {
+ DEBUGLOG(5, "Selected set_repeat");
+ return set_repeat;
+ }
+ if ( (nbSeq < dynamicFse_nbSeq_min)
+ || (mostFrequent < (nbSeq >> (defaultNormLog-1))) ) {
+ DEBUGLOG(5, "Selected set_basic");
+ /* The format allows default tables to be repeated, but it isn't useful.
+ * When using simple heuristics to select encoding type, we don't want
+ * to confuse these tables with dictionaries. When running more careful
+ * analysis, we don't need to waste time checking both repeating tables
+ * and default tables.
+ */
+ *repeatMode = FSE_repeat_none;
+ return set_basic;
+ }
+ }
+ } else {
+ size_t const basicCost = isDefaultAllowed ? ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, count, max) : ERROR(GENERIC);
+ size_t const repeatCost = *repeatMode != FSE_repeat_none ? ZSTD_fseBitCost(prevCTable, count, max) : ERROR(GENERIC);
+ size_t const NCountCost = ZSTD_NCountCost(count, max, nbSeq, FSELog);
+ size_t const compressedCost = (NCountCost << 3) + ZSTD_entropyCost(count, max, nbSeq);
+
+ if (isDefaultAllowed) {
+ assert(!ZSTD_isError(basicCost));
+ assert(!(*repeatMode == FSE_repeat_valid && ZSTD_isError(repeatCost)));
+ }
+ assert(!ZSTD_isError(NCountCost));
+ assert(compressedCost < ERROR(maxCode));
+ DEBUGLOG(5, "Estimated bit costs: basic=%u\trepeat=%u\tcompressed=%u",
+ (unsigned)basicCost, (unsigned)repeatCost, (unsigned)compressedCost);
+ if (basicCost <= repeatCost && basicCost <= compressedCost) {
+ DEBUGLOG(5, "Selected set_basic");
+ assert(isDefaultAllowed);
+ *repeatMode = FSE_repeat_none;
+ return set_basic;
+ }
+ if (repeatCost <= compressedCost) {
+ DEBUGLOG(5, "Selected set_repeat");
+ assert(!ZSTD_isError(repeatCost));
+ return set_repeat;
+ }
+ assert(compressedCost < basicCost && compressedCost < repeatCost);
+ }
+ DEBUGLOG(5, "Selected set_compressed");
+ *repeatMode = FSE_repeat_check;
+ return set_compressed;
+}
+
+size_t
+ZSTD_buildCTable(void* dst, size_t dstCapacity,
+ FSE_CTable* nextCTable, U32 FSELog, symbolEncodingType_e type,
+ unsigned* count, U32 max,
+ const BYTE* codeTable, size_t nbSeq,
+ const S16* defaultNorm, U32 defaultNormLog, U32 defaultMax,
+ const FSE_CTable* prevCTable, size_t prevCTableSize,
+ void* entropyWorkspace, size_t entropyWorkspaceSize)
+{
+ BYTE* op = (BYTE*)dst;
+ const BYTE* const oend = op + dstCapacity;
+ DEBUGLOG(6, "ZSTD_buildCTable (dstCapacity=%u)", (unsigned)dstCapacity);
+
+ switch (type) {
+ case set_rle:
+ FORWARD_IF_ERROR(FSE_buildCTable_rle(nextCTable, (BYTE)max), "");
+ RETURN_ERROR_IF(dstCapacity==0, dstSize_tooSmall, "not enough space");
+ *op = codeTable[0];
+ return 1;
+ case set_repeat:
+ memcpy(nextCTable, prevCTable, prevCTableSize);
+ return 0;
+ case set_basic:
+ FORWARD_IF_ERROR(FSE_buildCTable_wksp(nextCTable, defaultNorm, defaultMax, defaultNormLog, entropyWorkspace, entropyWorkspaceSize), ""); /* note : could be pre-calculated */
+ return 0;
+ case set_compressed: {
+ S16 norm[MaxSeq + 1];
+ size_t nbSeq_1 = nbSeq;
+ const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max);
+ if (count[codeTable[nbSeq-1]] > 1) {
+ count[codeTable[nbSeq-1]]--;
+ nbSeq_1--;
+ }
+ assert(nbSeq_1 > 1);
+ FORWARD_IF_ERROR(FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max), "");
+ { size_t const NCountSize = FSE_writeNCount(op, oend - op, norm, max, tableLog); /* overflow protected */
+ FORWARD_IF_ERROR(NCountSize, "FSE_writeNCount failed");
+ FORWARD_IF_ERROR(FSE_buildCTable_wksp(nextCTable, norm, max, tableLog, entropyWorkspace, entropyWorkspaceSize), "");
+ return NCountSize;
+ }
+ }
+ default: assert(0); RETURN_ERROR(GENERIC, "impossible to reach");
+ }
+}
+
+FORCE_INLINE_TEMPLATE size_t
+ZSTD_encodeSequences_body(
+ void* dst, size_t dstCapacity,
+ FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
+ FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
+ FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
+ seqDef const* sequences, size_t nbSeq, int longOffsets)
+{
+ BIT_CStream_t blockStream;
+ FSE_CState_t stateMatchLength;
+ FSE_CState_t stateOffsetBits;
+ FSE_CState_t stateLitLength;
+
+ RETURN_ERROR_IF(
+ ERR_isError(BIT_initCStream(&blockStream, dst, dstCapacity)),
+ dstSize_tooSmall, "not enough space remaining");
+ DEBUGLOG(6, "available space for bitstream : %i (dstCapacity=%u)",
+ (int)(blockStream.endPtr - blockStream.startPtr),
+ (unsigned)dstCapacity);
+
+ /* first symbols */
+ FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
+ FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
+ FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
+ BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]);
+ if (MEM_32bits()) BIT_flushBits(&blockStream);
+ BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]);
+ if (MEM_32bits()) BIT_flushBits(&blockStream);
+ if (longOffsets) {
+ U32 const ofBits = ofCodeTable[nbSeq-1];
+ unsigned const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
+ if (extraBits) {
+ BIT_addBits(&blockStream, sequences[nbSeq-1].offset, extraBits);
+ BIT_flushBits(&blockStream);
+ }
+ BIT_addBits(&blockStream, sequences[nbSeq-1].offset >> extraBits,
+ ofBits - extraBits);
+ } else {
+ BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]);
+ }
+ BIT_flushBits(&blockStream);
+
+ { size_t n;
+ for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */
+ BYTE const llCode = llCodeTable[n];
+ BYTE const ofCode = ofCodeTable[n];
+ BYTE const mlCode = mlCodeTable[n];
+ U32 const llBits = LL_bits[llCode];
+ U32 const ofBits = ofCode;
+ U32 const mlBits = ML_bits[mlCode];
+ DEBUGLOG(6, "encoding: litlen:%2u - matchlen:%2u - offCode:%7u",
+ (unsigned)sequences[n].litLength,
+ (unsigned)sequences[n].matchLength + MINMATCH,
+ (unsigned)sequences[n].offset);
+ /* 32b*/ /* 64b*/
+ /* (7)*/ /* (7)*/
+ FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
+ FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
+ if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
+ FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
+ if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
+ BIT_flushBits(&blockStream); /* (7)*/
+ BIT_addBits(&blockStream, sequences[n].litLength, llBits);
+ if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
+ BIT_addBits(&blockStream, sequences[n].matchLength, mlBits);
+ if (MEM_32bits() || (ofBits+mlBits+llBits > 56)) BIT_flushBits(&blockStream);
+ if (longOffsets) {
+ unsigned const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
+ if (extraBits) {
+ BIT_addBits(&blockStream, sequences[n].offset, extraBits);
+ BIT_flushBits(&blockStream); /* (7)*/
+ }
+ BIT_addBits(&blockStream, sequences[n].offset >> extraBits,
+ ofBits - extraBits); /* 31 */
+ } else {
+ BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */
+ }
+ BIT_flushBits(&blockStream); /* (7)*/
+ DEBUGLOG(7, "remaining space : %i", (int)(blockStream.endPtr - blockStream.ptr));
+ } }
+
+ DEBUGLOG(6, "ZSTD_encodeSequences: flushing ML state with %u bits", stateMatchLength.stateLog);
+ FSE_flushCState(&blockStream, &stateMatchLength);
+ DEBUGLOG(6, "ZSTD_encodeSequences: flushing Off state with %u bits", stateOffsetBits.stateLog);
+ FSE_flushCState(&blockStream, &stateOffsetBits);
+ DEBUGLOG(6, "ZSTD_encodeSequences: flushing LL state with %u bits", stateLitLength.stateLog);
+ FSE_flushCState(&blockStream, &stateLitLength);
+
+ { size_t const streamSize = BIT_closeCStream(&blockStream);
+ RETURN_ERROR_IF(streamSize==0, dstSize_tooSmall, "not enough space");
+ return streamSize;
+ }
+}
+
+static size_t
+ZSTD_encodeSequences_default(
+ void* dst, size_t dstCapacity,
+ FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
+ FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
+ FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
+ seqDef const* sequences, size_t nbSeq, int longOffsets)
+{
+ return ZSTD_encodeSequences_body(dst, dstCapacity,
+ CTable_MatchLength, mlCodeTable,
+ CTable_OffsetBits, ofCodeTable,
+ CTable_LitLength, llCodeTable,
+ sequences, nbSeq, longOffsets);
+}
+
+
+#if DYNAMIC_BMI2
+
+static TARGET_ATTRIBUTE("bmi2") size_t
+ZSTD_encodeSequences_bmi2(
+ void* dst, size_t dstCapacity,
+ FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
+ FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
+ FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
+ seqDef const* sequences, size_t nbSeq, int longOffsets)
+{
+ return ZSTD_encodeSequences_body(dst, dstCapacity,
+ CTable_MatchLength, mlCodeTable,
+ CTable_OffsetBits, ofCodeTable,
+ CTable_LitLength, llCodeTable,
+ sequences, nbSeq, longOffsets);
+}
+
+#endif
+
+size_t ZSTD_encodeSequences(
+ void* dst, size_t dstCapacity,
+ FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
+ FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
+ FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
+ seqDef const* sequences, size_t nbSeq, int longOffsets, int bmi2)
+{
+ DEBUGLOG(5, "ZSTD_encodeSequences: dstCapacity = %u", (unsigned)dstCapacity);
+#if DYNAMIC_BMI2
+ if (bmi2) {
+ return ZSTD_encodeSequences_bmi2(dst, dstCapacity,
+ CTable_MatchLength, mlCodeTable,
+ CTable_OffsetBits, ofCodeTable,
+ CTable_LitLength, llCodeTable,
+ sequences, nbSeq, longOffsets);
+ }
+#endif
+ (void)bmi2;
+ return ZSTD_encodeSequences_default(dst, dstCapacity,
+ CTable_MatchLength, mlCodeTable,
+ CTable_OffsetBits, ofCodeTable,
+ CTable_LitLength, llCodeTable,
+ sequences, nbSeq, longOffsets);
+}
diff --git a/sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress_sequences.h b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress_sequences.h
new file mode 100644
index 000000000000..68c6f9a5acd8
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress_sequences.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_COMPRESS_SEQUENCES_H
+#define ZSTD_COMPRESS_SEQUENCES_H
+
+#include "../common/fse.h" /* FSE_repeat, FSE_CTable */
+#include "../common/zstd_internal.h" /* symbolEncodingType_e, ZSTD_strategy */
+
+typedef enum {
+ ZSTD_defaultDisallowed = 0,
+ ZSTD_defaultAllowed = 1
+} ZSTD_defaultPolicy_e;
+
+symbolEncodingType_e
+ZSTD_selectEncodingType(
+ FSE_repeat* repeatMode, unsigned const* count, unsigned const max,
+ size_t const mostFrequent, size_t nbSeq, unsigned const FSELog,
+ FSE_CTable const* prevCTable,
+ short const* defaultNorm, U32 defaultNormLog,
+ ZSTD_defaultPolicy_e const isDefaultAllowed,
+ ZSTD_strategy const strategy);
+
+size_t
+ZSTD_buildCTable(void* dst, size_t dstCapacity,
+ FSE_CTable* nextCTable, U32 FSELog, symbolEncodingType_e type,
+ unsigned* count, U32 max,
+ const BYTE* codeTable, size_t nbSeq,
+ const S16* defaultNorm, U32 defaultNormLog, U32 defaultMax,
+ const FSE_CTable* prevCTable, size_t prevCTableSize,
+ void* entropyWorkspace, size_t entropyWorkspaceSize);
+
+size_t ZSTD_encodeSequences(
+ void* dst, size_t dstCapacity,
+ FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
+ FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
+ FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
+ seqDef const* sequences, size_t nbSeq, int longOffsets, int bmi2);
+
+size_t ZSTD_fseBitCost(
+ FSE_CTable const* ctable,
+ unsigned const* count,
+ unsigned const max);
+
+size_t ZSTD_crossEntropyCost(short const* norm, unsigned accuracyLog,
+ unsigned const* count, unsigned const max);
+#endif /* ZSTD_COMPRESS_SEQUENCES_H */
diff --git a/sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress_superblock.c b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress_superblock.c
new file mode 100644
index 000000000000..b693866c0ac1
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress_superblock.c
@@ -0,0 +1,845 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+ /*-*************************************
+ * Dependencies
+ ***************************************/
+#include "zstd_compress_superblock.h"
+
+#include "../common/zstd_internal.h" /* ZSTD_getSequenceLength */
+#include "hist.h" /* HIST_countFast_wksp */
+#include "zstd_compress_internal.h"
+#include "zstd_compress_sequences.h"
+#include "zstd_compress_literals.h"
+
+/*-*************************************
+* Superblock entropy buffer structs
+***************************************/
+/** ZSTD_hufCTablesMetadata_t :
+ * Stores Literals Block Type for a super-block in hType, and
+ * huffman tree description in hufDesBuffer.
+ * hufDesSize refers to the size of huffman tree description in bytes.
+ * This metadata is populated in ZSTD_buildSuperBlockEntropy_literal() */
+typedef struct {
+ symbolEncodingType_e hType;
+ BYTE hufDesBuffer[500]; /* TODO give name to this value */
+ size_t hufDesSize;
+} ZSTD_hufCTablesMetadata_t;
+
+/** ZSTD_fseCTablesMetadata_t :
+ * Stores symbol compression modes for a super-block in {ll, ol, ml}Type, and
+ * fse tables in fseTablesBuffer.
+ * fseTablesSize refers to the size of fse tables in bytes.
+ * This metadata is populated in ZSTD_buildSuperBlockEntropy_sequences() */
+typedef struct {
+ symbolEncodingType_e llType;
+ symbolEncodingType_e ofType;
+ symbolEncodingType_e mlType;
+ BYTE fseTablesBuffer[500]; /* TODO give name to this value */
+ size_t fseTablesSize;
+ size_t lastCountSize; /* This is to account for bug in 1.3.4. More detail in ZSTD_compressSubBlock_sequences() */
+} ZSTD_fseCTablesMetadata_t;
+
+typedef struct {
+ ZSTD_hufCTablesMetadata_t hufMetadata;
+ ZSTD_fseCTablesMetadata_t fseMetadata;
+} ZSTD_entropyCTablesMetadata_t;
+
+
+/** ZSTD_buildSuperBlockEntropy_literal() :
+ * Builds entropy for the super-block literals.
+ * Stores literals block type (raw, rle, compressed, repeat) and
+ * huffman description table to hufMetadata.
+ * @return : size of huffman description table or error code */
+static size_t ZSTD_buildSuperBlockEntropy_literal(void* const src, size_t srcSize,
+ const ZSTD_hufCTables_t* prevHuf,
+ ZSTD_hufCTables_t* nextHuf,
+ ZSTD_hufCTablesMetadata_t* hufMetadata,
+ const int disableLiteralsCompression,
+ void* workspace, size_t wkspSize)
+{
+ BYTE* const wkspStart = (BYTE*)workspace;
+ BYTE* const wkspEnd = wkspStart + wkspSize;
+ BYTE* const countWkspStart = wkspStart;
+ unsigned* const countWksp = (unsigned*)workspace;
+ const size_t countWkspSize = (HUF_SYMBOLVALUE_MAX + 1) * sizeof(unsigned);
+ BYTE* const nodeWksp = countWkspStart + countWkspSize;
+ const size_t nodeWkspSize = wkspEnd-nodeWksp;
+ unsigned maxSymbolValue = 255;
+ unsigned huffLog = HUF_TABLELOG_DEFAULT;
+ HUF_repeat repeat = prevHuf->repeatMode;
+
+ DEBUGLOG(5, "ZSTD_buildSuperBlockEntropy_literal (srcSize=%zu)", srcSize);
+
+ /* Prepare nextEntropy assuming reusing the existing table */
+ memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
+
+ if (disableLiteralsCompression) {
+ DEBUGLOG(5, "set_basic - disabled");
+ hufMetadata->hType = set_basic;
+ return 0;
+ }
+
+ /* small ? don't even attempt compression (speed opt) */
+# define COMPRESS_LITERALS_SIZE_MIN 63
+ { size_t const minLitSize = (prevHuf->repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN;
+ if (srcSize <= minLitSize) {
+ DEBUGLOG(5, "set_basic - too small");
+ hufMetadata->hType = set_basic;
+ return 0;
+ }
+ }
+
+ /* Scan input and build symbol stats */
+ { size_t const largest = HIST_count_wksp (countWksp, &maxSymbolValue, (const BYTE*)src, srcSize, workspace, wkspSize);
+ FORWARD_IF_ERROR(largest, "HIST_count_wksp failed");
+ if (largest == srcSize) {
+ DEBUGLOG(5, "set_rle");
+ hufMetadata->hType = set_rle;
+ return 0;
+ }
+ if (largest <= (srcSize >> 7)+4) {
+ DEBUGLOG(5, "set_basic - no gain");
+ hufMetadata->hType = set_basic;
+ return 0;
+ }
+ }
+
+ /* Validate the previous Huffman table */
+ if (repeat == HUF_repeat_check && !HUF_validateCTable((HUF_CElt const*)prevHuf->CTable, countWksp, maxSymbolValue)) {
+ repeat = HUF_repeat_none;
+ }
+
+ /* Build Huffman Tree */
+ memset(nextHuf->CTable, 0, sizeof(nextHuf->CTable));
+ huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue);
+ { size_t const maxBits = HUF_buildCTable_wksp((HUF_CElt*)nextHuf->CTable, countWksp,
+ maxSymbolValue, huffLog,
+ nodeWksp, nodeWkspSize);
+ FORWARD_IF_ERROR(maxBits, "HUF_buildCTable_wksp");
+ huffLog = (U32)maxBits;
+ { /* Build and write the CTable */
+ size_t const newCSize = HUF_estimateCompressedSize(
+ (HUF_CElt*)nextHuf->CTable, countWksp, maxSymbolValue);
+ size_t const hSize = HUF_writeCTable(
+ hufMetadata->hufDesBuffer, sizeof(hufMetadata->hufDesBuffer),
+ (HUF_CElt*)nextHuf->CTable, maxSymbolValue, huffLog);
+ /* Check against repeating the previous CTable */
+ if (repeat != HUF_repeat_none) {
+ size_t const oldCSize = HUF_estimateCompressedSize(
+ (HUF_CElt const*)prevHuf->CTable, countWksp, maxSymbolValue);
+ if (oldCSize < srcSize && (oldCSize <= hSize + newCSize || hSize + 12 >= srcSize)) {
+ DEBUGLOG(5, "set_repeat - smaller");
+ memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
+ hufMetadata->hType = set_repeat;
+ return 0;
+ }
+ }
+ if (newCSize + hSize >= srcSize) {
+ DEBUGLOG(5, "set_basic - no gains");
+ memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
+ hufMetadata->hType = set_basic;
+ return 0;
+ }
+ DEBUGLOG(5, "set_compressed (hSize=%u)", (U32)hSize);
+ hufMetadata->hType = set_compressed;
+ nextHuf->repeatMode = HUF_repeat_check;
+ return hSize;
+ }
+ }
+}
+
+/** ZSTD_buildSuperBlockEntropy_sequences() :
+ * Builds entropy for the super-block sequences.
+ * Stores symbol compression modes and fse table to fseMetadata.
+ * @return : size of fse tables or error code */
+static size_t ZSTD_buildSuperBlockEntropy_sequences(seqStore_t* seqStorePtr,
+ const ZSTD_fseCTables_t* prevEntropy,
+ ZSTD_fseCTables_t* nextEntropy,
+ const ZSTD_CCtx_params* cctxParams,
+ ZSTD_fseCTablesMetadata_t* fseMetadata,
+ void* workspace, size_t wkspSize)
+{
+ BYTE* const wkspStart = (BYTE*)workspace;
+ BYTE* const wkspEnd = wkspStart + wkspSize;
+ BYTE* const countWkspStart = wkspStart;
+ unsigned* const countWksp = (unsigned*)workspace;
+ const size_t countWkspSize = (MaxSeq + 1) * sizeof(unsigned);
+ BYTE* const cTableWksp = countWkspStart + countWkspSize;
+ const size_t cTableWkspSize = wkspEnd-cTableWksp;
+ ZSTD_strategy const strategy = cctxParams->cParams.strategy;
+ FSE_CTable* CTable_LitLength = nextEntropy->litlengthCTable;
+ FSE_CTable* CTable_OffsetBits = nextEntropy->offcodeCTable;
+ FSE_CTable* CTable_MatchLength = nextEntropy->matchlengthCTable;
+ const BYTE* const ofCodeTable = seqStorePtr->ofCode;
+ const BYTE* const llCodeTable = seqStorePtr->llCode;
+ const BYTE* const mlCodeTable = seqStorePtr->mlCode;
+ size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
+ BYTE* const ostart = fseMetadata->fseTablesBuffer;
+ BYTE* const oend = ostart + sizeof(fseMetadata->fseTablesBuffer);
+ BYTE* op = ostart;
+
+ assert(cTableWkspSize >= (1 << MaxFSELog) * sizeof(FSE_FUNCTION_TYPE));
+ DEBUGLOG(5, "ZSTD_buildSuperBlockEntropy_sequences (nbSeq=%zu)", nbSeq);
+ memset(workspace, 0, wkspSize);
+
+ fseMetadata->lastCountSize = 0;
+ /* convert length/distances into codes */
+ ZSTD_seqToCodes(seqStorePtr);
+ /* build CTable for Literal Lengths */
+ { U32 LLtype;
+ unsigned max = MaxLL;
+ size_t const mostFrequent = HIST_countFast_wksp(countWksp, &max, llCodeTable, nbSeq, workspace, wkspSize); /* can't fail */
+ DEBUGLOG(5, "Building LL table");
+ nextEntropy->litlength_repeatMode = prevEntropy->litlength_repeatMode;
+ LLtype = ZSTD_selectEncodingType(&nextEntropy->litlength_repeatMode,
+ countWksp, max, mostFrequent, nbSeq,
+ LLFSELog, prevEntropy->litlengthCTable,
+ LL_defaultNorm, LL_defaultNormLog,
+ ZSTD_defaultAllowed, strategy);
+ assert(set_basic < set_compressed && set_rle < set_compressed);
+ assert(!(LLtype < set_compressed && nextEntropy->litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
+ { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype,
+ countWksp, max, llCodeTable, nbSeq, LL_defaultNorm, LL_defaultNormLog, MaxLL,
+ prevEntropy->litlengthCTable, sizeof(prevEntropy->litlengthCTable),
+ cTableWksp, cTableWkspSize);
+ FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for LitLens failed");
+ if (LLtype == set_compressed)
+ fseMetadata->lastCountSize = countSize;
+ op += countSize;
+ fseMetadata->llType = (symbolEncodingType_e) LLtype;
+ } }
+ /* build CTable for Offsets */
+ { U32 Offtype;
+ unsigned max = MaxOff;
+ size_t const mostFrequent = HIST_countFast_wksp(countWksp, &max, ofCodeTable, nbSeq, workspace, wkspSize); /* can't fail */
+ /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */
+ ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed;
+ DEBUGLOG(5, "Building OF table");
+ nextEntropy->offcode_repeatMode = prevEntropy->offcode_repeatMode;
+ Offtype = ZSTD_selectEncodingType(&nextEntropy->offcode_repeatMode,
+ countWksp, max, mostFrequent, nbSeq,
+ OffFSELog, prevEntropy->offcodeCTable,
+ OF_defaultNorm, OF_defaultNormLog,
+ defaultPolicy, strategy);
+ assert(!(Offtype < set_compressed && nextEntropy->offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */
+ { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype,
+ countWksp, max, ofCodeTable, nbSeq, OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
+ prevEntropy->offcodeCTable, sizeof(prevEntropy->offcodeCTable),
+ cTableWksp, cTableWkspSize);
+ FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for Offsets failed");
+ if (Offtype == set_compressed)
+ fseMetadata->lastCountSize = countSize;
+ op += countSize;
+ fseMetadata->ofType = (symbolEncodingType_e) Offtype;
+ } }
+ /* build CTable for MatchLengths */
+ { U32 MLtype;
+ unsigned max = MaxML;
+ size_t const mostFrequent = HIST_countFast_wksp(countWksp, &max, mlCodeTable, nbSeq, workspace, wkspSize); /* can't fail */
+ DEBUGLOG(5, "Building ML table (remaining space : %i)", (int)(oend-op));
+ nextEntropy->matchlength_repeatMode = prevEntropy->matchlength_repeatMode;
+ MLtype = ZSTD_selectEncodingType(&nextEntropy->matchlength_repeatMode,
+ countWksp, max, mostFrequent, nbSeq,
+ MLFSELog, prevEntropy->matchlengthCTable,
+ ML_defaultNorm, ML_defaultNormLog,
+ ZSTD_defaultAllowed, strategy);
+ assert(!(MLtype < set_compressed && nextEntropy->matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
+ { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype,
+ countWksp, max, mlCodeTable, nbSeq, ML_defaultNorm, ML_defaultNormLog, MaxML,
+ prevEntropy->matchlengthCTable, sizeof(prevEntropy->matchlengthCTable),
+ cTableWksp, cTableWkspSize);
+ FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for MatchLengths failed");
+ if (MLtype == set_compressed)
+ fseMetadata->lastCountSize = countSize;
+ op += countSize;
+ fseMetadata->mlType = (symbolEncodingType_e) MLtype;
+ } }
+ assert((size_t) (op-ostart) <= sizeof(fseMetadata->fseTablesBuffer));
+ return op-ostart;
+}
+
+
+/** ZSTD_buildSuperBlockEntropy() :
+ * Builds entropy for the super-block.
+ * @return : 0 on success or error code */
+static size_t
+ZSTD_buildSuperBlockEntropy(seqStore_t* seqStorePtr,
+ const ZSTD_entropyCTables_t* prevEntropy,
+ ZSTD_entropyCTables_t* nextEntropy,
+ const ZSTD_CCtx_params* cctxParams,
+ ZSTD_entropyCTablesMetadata_t* entropyMetadata,
+ void* workspace, size_t wkspSize)
+{
+ size_t const litSize = seqStorePtr->lit - seqStorePtr->litStart;
+ DEBUGLOG(5, "ZSTD_buildSuperBlockEntropy");
+ entropyMetadata->hufMetadata.hufDesSize =
+ ZSTD_buildSuperBlockEntropy_literal(seqStorePtr->litStart, litSize,
+ &prevEntropy->huf, &nextEntropy->huf,
+ &entropyMetadata->hufMetadata,
+ ZSTD_disableLiteralsCompression(cctxParams),
+ workspace, wkspSize);
+ FORWARD_IF_ERROR(entropyMetadata->hufMetadata.hufDesSize, "ZSTD_buildSuperBlockEntropy_literal failed");
+ entropyMetadata->fseMetadata.fseTablesSize =
+ ZSTD_buildSuperBlockEntropy_sequences(seqStorePtr,
+ &prevEntropy->fse, &nextEntropy->fse,
+ cctxParams,
+ &entropyMetadata->fseMetadata,
+ workspace, wkspSize);
+ FORWARD_IF_ERROR(entropyMetadata->fseMetadata.fseTablesSize, "ZSTD_buildSuperBlockEntropy_sequences failed");
+ return 0;
+}
+
+/** ZSTD_compressSubBlock_literal() :
+ * Compresses literals section for a sub-block.
+ * When we have to write the Huffman table we will sometimes choose a header
+ * size larger than necessary. This is because we have to pick the header size
+ * before we know the table size + compressed size, so we have a bound on the
+ * table size. If we guessed incorrectly, we fall back to uncompressed literals.
+ *
+ * We write the header when writeEntropy=1 and set entropyWrriten=1 when we succeeded
+ * in writing the header, otherwise it is set to 0.
+ *
+ * hufMetadata->hType has literals block type info.
+ * If it is set_basic, all sub-blocks literals section will be Raw_Literals_Block.
+ * If it is set_rle, all sub-blocks literals section will be RLE_Literals_Block.
+ * If it is set_compressed, first sub-block's literals section will be Compressed_Literals_Block
+ * If it is set_compressed, first sub-block's literals section will be Treeless_Literals_Block
+ * and the following sub-blocks' literals sections will be Treeless_Literals_Block.
+ * @return : compressed size of literals section of a sub-block
+ * Or 0 if it unable to compress.
+ * Or error code */
+static size_t ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable,
+ const ZSTD_hufCTablesMetadata_t* hufMetadata,
+ const BYTE* literals, size_t litSize,
+ void* dst, size_t dstSize,
+ const int bmi2, int writeEntropy, int* entropyWritten)
+{
+ size_t const header = writeEntropy ? 200 : 0;
+ size_t const lhSize = 3 + (litSize >= (1 KB - header)) + (litSize >= (16 KB - header));
+ BYTE* const ostart = (BYTE*)dst;
+ BYTE* const oend = ostart + dstSize;
+ BYTE* op = ostart + lhSize;
+ U32 const singleStream = lhSize == 3;
+ symbolEncodingType_e hType = writeEntropy ? hufMetadata->hType : set_repeat;
+ size_t cLitSize = 0;
+
+ (void)bmi2; /* TODO bmi2... */
+
+ DEBUGLOG(5, "ZSTD_compressSubBlock_literal (litSize=%zu, lhSize=%zu, writeEntropy=%d)", litSize, lhSize, writeEntropy);
+
+ *entropyWritten = 0;
+ if (litSize == 0 || hufMetadata->hType == set_basic) {
+ DEBUGLOG(5, "ZSTD_compressSubBlock_literal using raw literal");
+ return ZSTD_noCompressLiterals(dst, dstSize, literals, litSize);
+ } else if (hufMetadata->hType == set_rle) {
+ DEBUGLOG(5, "ZSTD_compressSubBlock_literal using rle literal");
+ return ZSTD_compressRleLiteralsBlock(dst, dstSize, literals, litSize);
+ }
+
+ assert(litSize > 0);
+ assert(hufMetadata->hType == set_compressed || hufMetadata->hType == set_repeat);
+
+ if (writeEntropy && hufMetadata->hType == set_compressed) {
+ memcpy(op, hufMetadata->hufDesBuffer, hufMetadata->hufDesSize);
+ op += hufMetadata->hufDesSize;
+ cLitSize += hufMetadata->hufDesSize;
+ DEBUGLOG(5, "ZSTD_compressSubBlock_literal (hSize=%zu)", hufMetadata->hufDesSize);
+ }
+
+ /* TODO bmi2 */
+ { const size_t cSize = singleStream ? HUF_compress1X_usingCTable(op, oend-op, literals, litSize, hufTable)
+ : HUF_compress4X_usingCTable(op, oend-op, literals, litSize, hufTable);
+ op += cSize;
+ cLitSize += cSize;
+ if (cSize == 0 || ERR_isError(cSize)) {
+ DEBUGLOG(5, "Failed to write entropy tables %s", ZSTD_getErrorName(cSize));
+ return 0;
+ }
+ /* If we expand and we aren't writing a header then emit uncompressed */
+ if (!writeEntropy && cLitSize >= litSize) {
+ DEBUGLOG(5, "ZSTD_compressSubBlock_literal using raw literal because uncompressible");
+ return ZSTD_noCompressLiterals(dst, dstSize, literals, litSize);
+ }
+ /* If we are writing headers then allow expansion that doesn't change our header size. */
+ if (lhSize < (size_t)(3 + (cLitSize >= 1 KB) + (cLitSize >= 16 KB))) {
+ assert(cLitSize > litSize);
+ DEBUGLOG(5, "Literals expanded beyond allowed header size");
+ return ZSTD_noCompressLiterals(dst, dstSize, literals, litSize);
+ }
+ DEBUGLOG(5, "ZSTD_compressSubBlock_literal (cSize=%zu)", cSize);
+ }
+
+ /* Build header */
+ switch(lhSize)
+ {
+ case 3: /* 2 - 2 - 10 - 10 */
+ { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<14);
+ MEM_writeLE24(ostart, lhc);
+ break;
+ }
+ case 4: /* 2 - 2 - 14 - 14 */
+ { U32 const lhc = hType + (2 << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<18);
+ MEM_writeLE32(ostart, lhc);
+ break;
+ }
+ case 5: /* 2 - 2 - 18 - 18 */
+ { U32 const lhc = hType + (3 << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<22);
+ MEM_writeLE32(ostart, lhc);
+ ostart[4] = (BYTE)(cLitSize >> 10);
+ break;
+ }
+ default: /* not possible : lhSize is {3,4,5} */
+ assert(0);
+ }
+ *entropyWritten = 1;
+ DEBUGLOG(5, "Compressed literals: %u -> %u", (U32)litSize, (U32)(op-ostart));
+ return op-ostart;
+}
+
+static size_t ZSTD_seqDecompressedSize(seqStore_t const* seqStore, const seqDef* sequences, size_t nbSeq, size_t litSize, int lastSequence) {
+ const seqDef* const sstart = sequences;
+ const seqDef* const send = sequences + nbSeq;
+ const seqDef* sp = sstart;
+ size_t matchLengthSum = 0;
+ size_t litLengthSum = 0;
+ while (send-sp > 0) {
+ ZSTD_sequenceLength const seqLen = ZSTD_getSequenceLength(seqStore, sp);
+ litLengthSum += seqLen.litLength;
+ matchLengthSum += seqLen.matchLength;
+ sp++;
+ }
+ assert(litLengthSum <= litSize);
+ if (!lastSequence) {
+ assert(litLengthSum == litSize);
+ }
+ return matchLengthSum + litSize;
+}
+
+/** ZSTD_compressSubBlock_sequences() :
+ * Compresses sequences section for a sub-block.
+ * fseMetadata->llType, fseMetadata->ofType, and fseMetadata->mlType have
+ * symbol compression modes for the super-block.
+ * The first successfully compressed block will have these in its header.
+ * We set entropyWritten=1 when we succeed in compressing the sequences.
+ * The following sub-blocks will always have repeat mode.
+ * @return : compressed size of sequences section of a sub-block
+ * Or 0 if it is unable to compress
+ * Or error code. */
+static size_t ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables,
+ const ZSTD_fseCTablesMetadata_t* fseMetadata,
+ const seqDef* sequences, size_t nbSeq,
+ const BYTE* llCode, const BYTE* mlCode, const BYTE* ofCode,
+ const ZSTD_CCtx_params* cctxParams,
+ void* dst, size_t dstCapacity,
+ const int bmi2, int writeEntropy, int* entropyWritten)
+{
+ const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN;
+ BYTE* const ostart = (BYTE*)dst;
+ BYTE* const oend = ostart + dstCapacity;
+ BYTE* op = ostart;
+ BYTE* seqHead;
+
+ DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (nbSeq=%zu, writeEntropy=%d, longOffsets=%d)", nbSeq, writeEntropy, longOffsets);
+
+ *entropyWritten = 0;
+ /* Sequences Header */
+ RETURN_ERROR_IF((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead*/,
+ dstSize_tooSmall, "");
+ if (nbSeq < 0x7F)
+ *op++ = (BYTE)nbSeq;
+ else if (nbSeq < LONGNBSEQ)
+ op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
+ else
+ op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
+ if (nbSeq==0) {
+ return op - ostart;
+ }
+
+ /* seqHead : flags for FSE encoding type */
+ seqHead = op++;
+
+ DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (seqHeadSize=%u)", (unsigned)(op-ostart));
+
+ if (writeEntropy) {
+ const U32 LLtype = fseMetadata->llType;
+ const U32 Offtype = fseMetadata->ofType;
+ const U32 MLtype = fseMetadata->mlType;
+ DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (fseTablesSize=%zu)", fseMetadata->fseTablesSize);
+ *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
+ memcpy(op, fseMetadata->fseTablesBuffer, fseMetadata->fseTablesSize);
+ op += fseMetadata->fseTablesSize;
+ } else {
+ const U32 repeat = set_repeat;
+ *seqHead = (BYTE)((repeat<<6) + (repeat<<4) + (repeat<<2));
+ }
+
+ { size_t const bitstreamSize = ZSTD_encodeSequences(
+ op, oend - op,
+ fseTables->matchlengthCTable, mlCode,
+ fseTables->offcodeCTable, ofCode,
+ fseTables->litlengthCTable, llCode,
+ sequences, nbSeq,
+ longOffsets, bmi2);
+ FORWARD_IF_ERROR(bitstreamSize, "ZSTD_encodeSequences failed");
+ op += bitstreamSize;
+ /* zstd versions <= 1.3.4 mistakenly report corruption when
+ * FSE_readNCount() receives a buffer < 4 bytes.
+ * Fixed by https://github.com/facebook/zstd/pull/1146.
+ * This can happen when the last set_compressed table present is 2
+ * bytes and the bitstream is only one byte.
+ * In this exceedingly rare case, we will simply emit an uncompressed
+ * block, since it isn't worth optimizing.
+ */
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ if (writeEntropy && fseMetadata->lastCountSize && fseMetadata->lastCountSize + bitstreamSize < 4) {
+ /* NCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */
+ assert(fseMetadata->lastCountSize + bitstreamSize == 3);
+ DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.3.4 by "
+ "emitting an uncompressed block.");
+ return 0;
+ }
+#endif
+ DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (bitstreamSize=%zu)", bitstreamSize);
+ }
+
+ /* zstd versions <= 1.4.0 mistakenly report error when
+ * sequences section body size is less than 3 bytes.
+ * Fixed by https://github.com/facebook/zstd/pull/1664.
+ * This can happen when the previous sequences section block is compressed
+ * with rle mode and the current block's sequences section is compressed
+ * with repeat mode where sequences section body size can be 1 byte.
+ */
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ if (op-seqHead < 4) {
+ DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.4.0 by emitting "
+ "an uncompressed block when sequences are < 4 bytes");
+ return 0;
+ }
+#endif
+
+ *entropyWritten = 1;
+ return op - ostart;
+}
+
+/** ZSTD_compressSubBlock() :
+ * Compresses a single sub-block.
+ * @return : compressed size of the sub-block
+ * Or 0 if it failed to compress. */
+static size_t ZSTD_compressSubBlock(const ZSTD_entropyCTables_t* entropy,
+ const ZSTD_entropyCTablesMetadata_t* entropyMetadata,
+ const seqDef* sequences, size_t nbSeq,
+ const BYTE* literals, size_t litSize,
+ const BYTE* llCode, const BYTE* mlCode, const BYTE* ofCode,
+ const ZSTD_CCtx_params* cctxParams,
+ void* dst, size_t dstCapacity,
+ const int bmi2,
+ int writeLitEntropy, int writeSeqEntropy,
+ int* litEntropyWritten, int* seqEntropyWritten,
+ U32 lastBlock)
+{
+ BYTE* const ostart = (BYTE*)dst;
+ BYTE* const oend = ostart + dstCapacity;
+ BYTE* op = ostart + ZSTD_blockHeaderSize;
+ DEBUGLOG(5, "ZSTD_compressSubBlock (litSize=%zu, nbSeq=%zu, writeLitEntropy=%d, writeSeqEntropy=%d, lastBlock=%d)",
+ litSize, nbSeq, writeLitEntropy, writeSeqEntropy, lastBlock);
+ { size_t cLitSize = ZSTD_compressSubBlock_literal((const HUF_CElt*)entropy->huf.CTable,
+ &entropyMetadata->hufMetadata, literals, litSize,
+ op, oend-op, bmi2, writeLitEntropy, litEntropyWritten);
+ FORWARD_IF_ERROR(cLitSize, "ZSTD_compressSubBlock_literal failed");
+ if (cLitSize == 0) return 0;
+ op += cLitSize;
+ }
+ { size_t cSeqSize = ZSTD_compressSubBlock_sequences(&entropy->fse,
+ &entropyMetadata->fseMetadata,
+ sequences, nbSeq,
+ llCode, mlCode, ofCode,
+ cctxParams,
+ op, oend-op,
+ bmi2, writeSeqEntropy, seqEntropyWritten);
+ FORWARD_IF_ERROR(cSeqSize, "ZSTD_compressSubBlock_sequences failed");
+ if (cSeqSize == 0) return 0;
+ op += cSeqSize;
+ }
+ /* Write block header */
+ { size_t cSize = (op-ostart)-ZSTD_blockHeaderSize;
+ U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
+ MEM_writeLE24(ostart, cBlockHeader24);
+ }
+ return op-ostart;
+}
+
+static size_t ZSTD_estimateSubBlockSize_literal(const BYTE* literals, size_t litSize,
+ const ZSTD_hufCTables_t* huf,
+ const ZSTD_hufCTablesMetadata_t* hufMetadata,
+ void* workspace, size_t wkspSize,
+ int writeEntropy)
+{
+ unsigned* const countWksp = (unsigned*)workspace;
+ unsigned maxSymbolValue = 255;
+ size_t literalSectionHeaderSize = 3; /* Use hard coded size of 3 bytes */
+
+ if (hufMetadata->hType == set_basic) return litSize;
+ else if (hufMetadata->hType == set_rle) return 1;
+ else if (hufMetadata->hType == set_compressed || hufMetadata->hType == set_repeat) {
+ size_t const largest = HIST_count_wksp (countWksp, &maxSymbolValue, (const BYTE*)literals, litSize, workspace, wkspSize);
+ if (ZSTD_isError(largest)) return litSize;
+ { size_t cLitSizeEstimate = HUF_estimateCompressedSize((const HUF_CElt*)huf->CTable, countWksp, maxSymbolValue);
+ if (writeEntropy) cLitSizeEstimate += hufMetadata->hufDesSize;
+ return cLitSizeEstimate + literalSectionHeaderSize;
+ } }
+ assert(0); /* impossible */
+ return 0;
+}
+
+static size_t ZSTD_estimateSubBlockSize_symbolType(symbolEncodingType_e type,
+ const BYTE* codeTable, unsigned maxCode,
+ size_t nbSeq, const FSE_CTable* fseCTable,
+ const U32* additionalBits,
+ short const* defaultNorm, U32 defaultNormLog,
+ void* workspace, size_t wkspSize)
+{
+ unsigned* const countWksp = (unsigned*)workspace;
+ const BYTE* ctp = codeTable;
+ const BYTE* const ctStart = ctp;
+ const BYTE* const ctEnd = ctStart + nbSeq;
+ size_t cSymbolTypeSizeEstimateInBits = 0;
+ unsigned max = maxCode;
+
+ HIST_countFast_wksp(countWksp, &max, codeTable, nbSeq, workspace, wkspSize); /* can't fail */
+ if (type == set_basic) {
+ cSymbolTypeSizeEstimateInBits = ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, countWksp, max);
+ } else if (type == set_rle) {
+ cSymbolTypeSizeEstimateInBits = 0;
+ } else if (type == set_compressed || type == set_repeat) {
+ cSymbolTypeSizeEstimateInBits = ZSTD_fseBitCost(fseCTable, countWksp, max);
+ }
+ if (ZSTD_isError(cSymbolTypeSizeEstimateInBits)) return nbSeq * 10;
+ while (ctp < ctEnd) {
+ if (additionalBits) cSymbolTypeSizeEstimateInBits += additionalBits[*ctp];
+ else cSymbolTypeSizeEstimateInBits += *ctp; /* for offset, offset code is also the number of additional bits */
+ ctp++;
+ }
+ return cSymbolTypeSizeEstimateInBits / 8;
+}
+
+static size_t ZSTD_estimateSubBlockSize_sequences(const BYTE* ofCodeTable,
+ const BYTE* llCodeTable,
+ const BYTE* mlCodeTable,
+ size_t nbSeq,
+ const ZSTD_fseCTables_t* fseTables,
+ const ZSTD_fseCTablesMetadata_t* fseMetadata,
+ void* workspace, size_t wkspSize,
+ int writeEntropy)
+{
+ size_t sequencesSectionHeaderSize = 3; /* Use hard coded size of 3 bytes */
+ size_t cSeqSizeEstimate = 0;
+ cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->ofType, ofCodeTable, MaxOff,
+ nbSeq, fseTables->offcodeCTable, NULL,
+ OF_defaultNorm, OF_defaultNormLog,
+ workspace, wkspSize);
+ cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->llType, llCodeTable, MaxLL,
+ nbSeq, fseTables->litlengthCTable, LL_bits,
+ LL_defaultNorm, LL_defaultNormLog,
+ workspace, wkspSize);
+ cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->mlType, mlCodeTable, MaxML,
+ nbSeq, fseTables->matchlengthCTable, ML_bits,
+ ML_defaultNorm, ML_defaultNormLog,
+ workspace, wkspSize);
+ if (writeEntropy) cSeqSizeEstimate += fseMetadata->fseTablesSize;
+ return cSeqSizeEstimate + sequencesSectionHeaderSize;
+}
+
+static size_t ZSTD_estimateSubBlockSize(const BYTE* literals, size_t litSize,
+ const BYTE* ofCodeTable,
+ const BYTE* llCodeTable,
+ const BYTE* mlCodeTable,
+ size_t nbSeq,
+ const ZSTD_entropyCTables_t* entropy,
+ const ZSTD_entropyCTablesMetadata_t* entropyMetadata,
+ void* workspace, size_t wkspSize,
+ int writeLitEntropy, int writeSeqEntropy) {
+ size_t cSizeEstimate = 0;
+ cSizeEstimate += ZSTD_estimateSubBlockSize_literal(literals, litSize,
+ &entropy->huf, &entropyMetadata->hufMetadata,
+ workspace, wkspSize, writeLitEntropy);
+ cSizeEstimate += ZSTD_estimateSubBlockSize_sequences(ofCodeTable, llCodeTable, mlCodeTable,
+ nbSeq, &entropy->fse, &entropyMetadata->fseMetadata,
+ workspace, wkspSize, writeSeqEntropy);
+ return cSizeEstimate + ZSTD_blockHeaderSize;
+}
+
+static int ZSTD_needSequenceEntropyTables(ZSTD_fseCTablesMetadata_t const* fseMetadata)
+{
+ if (fseMetadata->llType == set_compressed || fseMetadata->llType == set_rle)
+ return 1;
+ if (fseMetadata->mlType == set_compressed || fseMetadata->mlType == set_rle)
+ return 1;
+ if (fseMetadata->ofType == set_compressed || fseMetadata->ofType == set_rle)
+ return 1;
+ return 0;
+}
+
+/** ZSTD_compressSubBlock_multi() :
+ * Breaks super-block into multiple sub-blocks and compresses them.
+ * Entropy will be written to the first block.
+ * The following blocks will use repeat mode to compress.
+ * All sub-blocks are compressed blocks (no raw or rle blocks).
+ * @return : compressed size of the super block (which is multiple ZSTD blocks)
+ * Or 0 if it failed to compress. */
+static size_t ZSTD_compressSubBlock_multi(const seqStore_t* seqStorePtr,
+ const ZSTD_compressedBlockState_t* prevCBlock,
+ ZSTD_compressedBlockState_t* nextCBlock,
+ const ZSTD_entropyCTablesMetadata_t* entropyMetadata,
+ const ZSTD_CCtx_params* cctxParams,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const int bmi2, U32 lastBlock,
+ void* workspace, size_t wkspSize)
+{
+ const seqDef* const sstart = seqStorePtr->sequencesStart;
+ const seqDef* const send = seqStorePtr->sequences;
+ const seqDef* sp = sstart;
+ const BYTE* const lstart = seqStorePtr->litStart;
+ const BYTE* const lend = seqStorePtr->lit;
+ const BYTE* lp = lstart;
+ BYTE const* ip = (BYTE const*)src;
+ BYTE const* const iend = ip + srcSize;
+ BYTE* const ostart = (BYTE*)dst;
+ BYTE* const oend = ostart + dstCapacity;
+ BYTE* op = ostart;
+ const BYTE* llCodePtr = seqStorePtr->llCode;
+ const BYTE* mlCodePtr = seqStorePtr->mlCode;
+ const BYTE* ofCodePtr = seqStorePtr->ofCode;
+ size_t targetCBlockSize = cctxParams->targetCBlockSize;
+ size_t litSize, seqCount;
+ int writeLitEntropy = entropyMetadata->hufMetadata.hType == set_compressed;
+ int writeSeqEntropy = 1;
+ int lastSequence = 0;
+
+ DEBUGLOG(5, "ZSTD_compressSubBlock_multi (litSize=%u, nbSeq=%u)",
+ (unsigned)(lend-lp), (unsigned)(send-sstart));
+
+ litSize = 0;
+ seqCount = 0;
+ do {
+ size_t cBlockSizeEstimate = 0;
+ if (sstart == send) {
+ lastSequence = 1;
+ } else {
+ const seqDef* const sequence = sp + seqCount;
+ lastSequence = sequence == send - 1;
+ litSize += ZSTD_getSequenceLength(seqStorePtr, sequence).litLength;
+ seqCount++;
+ }
+ if (lastSequence) {
+ assert(lp <= lend);
+ assert(litSize <= (size_t)(lend - lp));
+ litSize = (size_t)(lend - lp);
+ }
+ /* I think there is an optimization opportunity here.
+ * Calling ZSTD_estimateSubBlockSize for every sequence can be wasteful
+ * since it recalculates estimate from scratch.
+ * For example, it would recount literal distribution and symbol codes everytime.
+ */
+ cBlockSizeEstimate = ZSTD_estimateSubBlockSize(lp, litSize, ofCodePtr, llCodePtr, mlCodePtr, seqCount,
+ &nextCBlock->entropy, entropyMetadata,
+ workspace, wkspSize, writeLitEntropy, writeSeqEntropy);
+ if (cBlockSizeEstimate > targetCBlockSize || lastSequence) {
+ int litEntropyWritten = 0;
+ int seqEntropyWritten = 0;
+ const size_t decompressedSize = ZSTD_seqDecompressedSize(seqStorePtr, sp, seqCount, litSize, lastSequence);
+ const size_t cSize = ZSTD_compressSubBlock(&nextCBlock->entropy, entropyMetadata,
+ sp, seqCount,
+ lp, litSize,
+ llCodePtr, mlCodePtr, ofCodePtr,
+ cctxParams,
+ op, oend-op,
+ bmi2, writeLitEntropy, writeSeqEntropy,
+ &litEntropyWritten, &seqEntropyWritten,
+ lastBlock && lastSequence);
+ FORWARD_IF_ERROR(cSize, "ZSTD_compressSubBlock failed");
+ if (cSize > 0 && cSize < decompressedSize) {
+ DEBUGLOG(5, "Committed the sub-block");
+ assert(ip + decompressedSize <= iend);
+ ip += decompressedSize;
+ sp += seqCount;
+ lp += litSize;
+ op += cSize;
+ llCodePtr += seqCount;
+ mlCodePtr += seqCount;
+ ofCodePtr += seqCount;
+ litSize = 0;
+ seqCount = 0;
+ /* Entropy only needs to be written once */
+ if (litEntropyWritten) {
+ writeLitEntropy = 0;
+ }
+ if (seqEntropyWritten) {
+ writeSeqEntropy = 0;
+ }
+ }
+ }
+ } while (!lastSequence);
+ if (writeLitEntropy) {
+ DEBUGLOG(5, "ZSTD_compressSubBlock_multi has literal entropy tables unwritten");
+ memcpy(&nextCBlock->entropy.huf, &prevCBlock->entropy.huf, sizeof(prevCBlock->entropy.huf));
+ }
+ if (writeSeqEntropy && ZSTD_needSequenceEntropyTables(&entropyMetadata->fseMetadata)) {
+ /* If we haven't written our entropy tables, then we've violated our contract and
+ * must emit an uncompressed block.
+ */
+ DEBUGLOG(5, "ZSTD_compressSubBlock_multi has sequence entropy tables unwritten");
+ return 0;
+ }
+ if (ip < iend) {
+ size_t const cSize = ZSTD_noCompressBlock(op, oend - op, ip, iend - ip, lastBlock);
+ DEBUGLOG(5, "ZSTD_compressSubBlock_multi last sub-block uncompressed, %zu bytes", (size_t)(iend - ip));
+ FORWARD_IF_ERROR(cSize, "ZSTD_noCompressBlock failed");
+ assert(cSize != 0);
+ op += cSize;
+ /* We have to regenerate the repcodes because we've skipped some sequences */
+ if (sp < send) {
+ seqDef const* seq;
+ repcodes_t rep;
+ memcpy(&rep, prevCBlock->rep, sizeof(rep));
+ for (seq = sstart; seq < sp; ++seq) {
+ rep = ZSTD_updateRep(rep.rep, seq->offset - 1, ZSTD_getSequenceLength(seqStorePtr, seq).litLength == 0);
+ }
+ memcpy(nextCBlock->rep, &rep, sizeof(rep));
+ }
+ }
+ DEBUGLOG(5, "ZSTD_compressSubBlock_multi compressed");
+ return op-ostart;
+}
+
+size_t ZSTD_compressSuperBlock(ZSTD_CCtx* zc,
+ void* dst, size_t dstCapacity,
+ void const* src, size_t srcSize,
+ unsigned lastBlock) {
+ ZSTD_entropyCTablesMetadata_t entropyMetadata;
+
+ FORWARD_IF_ERROR(ZSTD_buildSuperBlockEntropy(&zc->seqStore,
+ &zc->blockState.prevCBlock->entropy,
+ &zc->blockState.nextCBlock->entropy,
+ &zc->appliedParams,
+ &entropyMetadata,
+ zc->entropyWorkspace, HUF_WORKSPACE_SIZE /* statically allocated in resetCCtx */), "");
+
+ return ZSTD_compressSubBlock_multi(&zc->seqStore,
+ zc->blockState.prevCBlock,
+ zc->blockState.nextCBlock,
+ &entropyMetadata,
+ &zc->appliedParams,
+ dst, dstCapacity,
+ src, srcSize,
+ zc->bmi2, lastBlock,
+ zc->entropyWorkspace, HUF_WORKSPACE_SIZE /* statically allocated in resetCCtx */);
+}
diff --git a/sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress_superblock.h b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress_superblock.h
new file mode 100644
index 000000000000..07f4cb1dc646
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_compress_superblock.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_COMPRESS_ADVANCED_H
+#define ZSTD_COMPRESS_ADVANCED_H
+
+/*-*************************************
+* Dependencies
+***************************************/
+
+#include "../zstd.h" /* ZSTD_CCtx */
+
+/*-*************************************
+* Target Compressed Block Size
+***************************************/
+
+/* ZSTD_compressSuperBlock() :
+ * Used to compress a super block when targetCBlockSize is being used.
+ * The given block will be compressed into multiple sub blocks that are around targetCBlockSize. */
+size_t ZSTD_compressSuperBlock(ZSTD_CCtx* zc,
+ void* dst, size_t dstCapacity,
+ void const* src, size_t srcSize,
+ unsigned lastBlock);
+
+#endif /* ZSTD_COMPRESS_ADVANCED_H */
diff --git a/sys/contrib/openzfs/module/zstd/lib/compress/zstd_cwksp.h b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_cwksp.h
new file mode 100644
index 000000000000..a25c9263b7d7
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_cwksp.h
@@ -0,0 +1,525 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_CWKSP_H
+#define ZSTD_CWKSP_H
+
+/*-*************************************
+* Dependencies
+***************************************/
+#include "../common/zstd_internal.h"
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+/*-*************************************
+* Constants
+***************************************/
+
+/* Since the workspace is effectively its own little malloc implementation /
+ * arena, when we run under ASAN, we should similarly insert redzones between
+ * each internal element of the workspace, so ASAN will catch overruns that
+ * reach outside an object but that stay inside the workspace.
+ *
+ * This defines the size of that redzone.
+ */
+#ifndef ZSTD_CWKSP_ASAN_REDZONE_SIZE
+#define ZSTD_CWKSP_ASAN_REDZONE_SIZE 128
+#endif
+
+/*-*************************************
+* Structures
+***************************************/
+typedef enum {
+ ZSTD_cwksp_alloc_objects,
+ ZSTD_cwksp_alloc_buffers,
+ ZSTD_cwksp_alloc_aligned
+} ZSTD_cwksp_alloc_phase_e;
+
+/**
+ * Zstd fits all its internal datastructures into a single continuous buffer,
+ * so that it only needs to perform a single OS allocation (or so that a buffer
+ * can be provided to it and it can perform no allocations at all). This buffer
+ * is called the workspace.
+ *
+ * Several optimizations complicate that process of allocating memory ranges
+ * from this workspace for each internal datastructure:
+ *
+ * - These different internal datastructures have different setup requirements:
+ *
+ * - The static objects need to be cleared once and can then be trivially
+ * reused for each compression.
+ *
+ * - Various buffers don't need to be initialized at all--they are always
+ * written into before they're read.
+ *
+ * - The matchstate tables have a unique requirement that they don't need
+ * their memory to be totally cleared, but they do need the memory to have
+ * some bound, i.e., a guarantee that all values in the memory they've been
+ * allocated is less than some maximum value (which is the starting value
+ * for the indices that they will then use for compression). When this
+ * guarantee is provided to them, they can use the memory without any setup
+ * work. When it can't, they have to clear the area.
+ *
+ * - These buffers also have different alignment requirements.
+ *
+ * - We would like to reuse the objects in the workspace for multiple
+ * compressions without having to perform any expensive reallocation or
+ * reinitialization work.
+ *
+ * - We would like to be able to efficiently reuse the workspace across
+ * multiple compressions **even when the compression parameters change** and
+ * we need to resize some of the objects (where possible).
+ *
+ * To attempt to manage this buffer, given these constraints, the ZSTD_cwksp
+ * abstraction was created. It works as follows:
+ *
+ * Workspace Layout:
+ *
+ * [ ... workspace ... ]
+ * [objects][tables ... ->] free space [<- ... aligned][<- ... buffers]
+ *
+ * The various objects that live in the workspace are divided into the
+ * following categories, and are allocated separately:
+ *
+ * - Static objects: this is optionally the enclosing ZSTD_CCtx or ZSTD_CDict,
+ * so that literally everything fits in a single buffer. Note: if present,
+ * this must be the first object in the workspace, since ZSTD_free{CCtx,
+ * CDict}() rely on a pointer comparison to see whether one or two frees are
+ * required.
+ *
+ * - Fixed size objects: these are fixed-size, fixed-count objects that are
+ * nonetheless "dynamically" allocated in the workspace so that we can
+ * control how they're initialized separately from the broader ZSTD_CCtx.
+ * Examples:
+ * - Entropy Workspace
+ * - 2 x ZSTD_compressedBlockState_t
+ * - CDict dictionary contents
+ *
+ * - Tables: these are any of several different datastructures (hash tables,
+ * chain tables, binary trees) that all respect a common format: they are
+ * uint32_t arrays, all of whose values are between 0 and (nextSrc - base).
+ * Their sizes depend on the cparams.
+ *
+ * - Aligned: these buffers are used for various purposes that require 4 byte
+ * alignment, but don't require any initialization before they're used.
+ *
+ * - Buffers: these buffers are used for various purposes that don't require
+ * any alignment or initialization before they're used. This means they can
+ * be moved around at no cost for a new compression.
+ *
+ * Allocating Memory:
+ *
+ * The various types of objects must be allocated in order, so they can be
+ * correctly packed into the workspace buffer. That order is:
+ *
+ * 1. Objects
+ * 2. Buffers
+ * 3. Aligned
+ * 4. Tables
+ *
+ * Attempts to reserve objects of different types out of order will fail.
+ */
+typedef struct {
+ void* workspace;
+ void* workspaceEnd;
+
+ void* objectEnd;
+ void* tableEnd;
+ void* tableValidEnd;
+ void* allocStart;
+
+ int allocFailed;
+ int workspaceOversizedDuration;
+ ZSTD_cwksp_alloc_phase_e phase;
+} ZSTD_cwksp;
+
+/*-*************************************
+* Functions
+***************************************/
+
+MEM_STATIC size_t ZSTD_cwksp_available_space(ZSTD_cwksp* ws);
+
+MEM_STATIC void ZSTD_cwksp_assert_internal_consistency(ZSTD_cwksp* ws) {
+ (void)ws;
+ assert(ws->workspace <= ws->objectEnd);
+ assert(ws->objectEnd <= ws->tableEnd);
+ assert(ws->objectEnd <= ws->tableValidEnd);
+ assert(ws->tableEnd <= ws->allocStart);
+ assert(ws->tableValidEnd <= ws->allocStart);
+ assert(ws->allocStart <= ws->workspaceEnd);
+}
+
+/**
+ * Align must be a power of 2.
+ */
+MEM_STATIC size_t ZSTD_cwksp_align(size_t size, size_t const align) {
+ size_t const mask = align - 1;
+ assert((align & mask) == 0);
+ return (size + mask) & ~mask;
+}
+
+/**
+ * Use this to determine how much space in the workspace we will consume to
+ * allocate this object. (Normally it should be exactly the size of the object,
+ * but under special conditions, like ASAN, where we pad each object, it might
+ * be larger.)
+ *
+ * Since tables aren't currently redzoned, you don't need to call through this
+ * to figure out how much space you need for the matchState tables. Everything
+ * else is though.
+ */
+MEM_STATIC size_t ZSTD_cwksp_alloc_size(size_t size) {
+#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
+ return size + 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE;
+#else
+ return size;
+#endif
+}
+
+MEM_STATIC void ZSTD_cwksp_internal_advance_phase(
+ ZSTD_cwksp* ws, ZSTD_cwksp_alloc_phase_e phase) {
+ assert(phase >= ws->phase);
+ if (phase > ws->phase) {
+ if (ws->phase < ZSTD_cwksp_alloc_buffers &&
+ phase >= ZSTD_cwksp_alloc_buffers) {
+ ws->tableValidEnd = ws->objectEnd;
+ }
+ if (ws->phase < ZSTD_cwksp_alloc_aligned &&
+ phase >= ZSTD_cwksp_alloc_aligned) {
+ /* If unaligned allocations down from a too-large top have left us
+ * unaligned, we need to realign our alloc ptr. Technically, this
+ * can consume space that is unaccounted for in the neededSpace
+ * calculation. However, I believe this can only happen when the
+ * workspace is too large, and specifically when it is too large
+ * by a larger margin than the space that will be consumed. */
+ /* TODO: cleaner, compiler warning friendly way to do this??? */
+ ws->allocStart = (BYTE*)ws->allocStart - ((size_t)ws->allocStart & (sizeof(U32)-1));
+ if (ws->allocStart < ws->tableValidEnd) {
+ ws->tableValidEnd = ws->allocStart;
+ }
+ }
+ ws->phase = phase;
+ }
+}
+
+/**
+ * Returns whether this object/buffer/etc was allocated in this workspace.
+ */
+MEM_STATIC int ZSTD_cwksp_owns_buffer(const ZSTD_cwksp* ws, const void* ptr) {
+ return (ptr != NULL) && (ws->workspace <= ptr) && (ptr <= ws->workspaceEnd);
+}
+
+/**
+ * Internal function. Do not use directly.
+ */
+MEM_STATIC void* ZSTD_cwksp_reserve_internal(
+ ZSTD_cwksp* ws, size_t bytes, ZSTD_cwksp_alloc_phase_e phase) {
+ void* alloc;
+ void* bottom = ws->tableEnd;
+ ZSTD_cwksp_internal_advance_phase(ws, phase);
+ alloc = (BYTE *)ws->allocStart - bytes;
+
+#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
+ /* over-reserve space */
+ alloc = (BYTE *)alloc - 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE;
+#endif
+
+ DEBUGLOG(5, "cwksp: reserving %p %zd bytes, %zd bytes remaining",
+ alloc, bytes, ZSTD_cwksp_available_space(ws) - bytes);
+ ZSTD_cwksp_assert_internal_consistency(ws);
+ assert(alloc >= bottom);
+ if (alloc < bottom) {
+ DEBUGLOG(4, "cwksp: alloc failed!");
+ ws->allocFailed = 1;
+ return NULL;
+ }
+ if (alloc < ws->tableValidEnd) {
+ ws->tableValidEnd = alloc;
+ }
+ ws->allocStart = alloc;
+
+#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
+ /* Move alloc so there's ZSTD_CWKSP_ASAN_REDZONE_SIZE unused space on
+ * either size. */
+ alloc = (BYTE *)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE;
+ __asan_unpoison_memory_region(alloc, bytes);
+#endif
+
+ return alloc;
+}
+
+/**
+ * Reserves and returns unaligned memory.
+ */
+MEM_STATIC BYTE* ZSTD_cwksp_reserve_buffer(ZSTD_cwksp* ws, size_t bytes) {
+ return (BYTE*)ZSTD_cwksp_reserve_internal(ws, bytes, ZSTD_cwksp_alloc_buffers);
+}
+
+/**
+ * Reserves and returns memory sized on and aligned on sizeof(unsigned).
+ */
+MEM_STATIC void* ZSTD_cwksp_reserve_aligned(ZSTD_cwksp* ws, size_t bytes) {
+ assert((bytes & (sizeof(U32)-1)) == 0);
+ return ZSTD_cwksp_reserve_internal(ws, ZSTD_cwksp_align(bytes, sizeof(U32)), ZSTD_cwksp_alloc_aligned);
+}
+
+/**
+ * Aligned on sizeof(unsigned). These buffers have the special property that
+ * their values remain constrained, allowing us to re-use them without
+ * memset()-ing them.
+ */
+MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes) {
+ const ZSTD_cwksp_alloc_phase_e phase = ZSTD_cwksp_alloc_aligned;
+ void* alloc = ws->tableEnd;
+ void* end = (BYTE *)alloc + bytes;
+ void* top = ws->allocStart;
+
+ DEBUGLOG(5, "cwksp: reserving %p table %zd bytes, %zd bytes remaining",
+ alloc, bytes, ZSTD_cwksp_available_space(ws) - bytes);
+ assert((bytes & (sizeof(U32)-1)) == 0);
+ ZSTD_cwksp_internal_advance_phase(ws, phase);
+ ZSTD_cwksp_assert_internal_consistency(ws);
+ assert(end <= top);
+ if (end > top) {
+ DEBUGLOG(4, "cwksp: table alloc failed!");
+ ws->allocFailed = 1;
+ return NULL;
+ }
+ ws->tableEnd = end;
+
+#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
+ __asan_unpoison_memory_region(alloc, bytes);
+#endif
+
+ return alloc;
+}
+
+/**
+ * Aligned on sizeof(void*).
+ */
+MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) {
+ size_t roundedBytes = ZSTD_cwksp_align(bytes, sizeof(void*));
+ void* alloc = ws->objectEnd;
+ void* end = (BYTE*)alloc + roundedBytes;
+
+#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
+ /* over-reserve space */
+ end = (BYTE *)end + 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE;
+#endif
+
+ DEBUGLOG(5,
+ "cwksp: reserving %p object %zd bytes (rounded to %zd), %zd bytes remaining",
+ alloc, bytes, roundedBytes, ZSTD_cwksp_available_space(ws) - roundedBytes);
+ assert(((size_t)alloc & (sizeof(void*)-1)) == 0);
+ assert((bytes & (sizeof(void*)-1)) == 0);
+ ZSTD_cwksp_assert_internal_consistency(ws);
+ /* we must be in the first phase, no advance is possible */
+ if (ws->phase != ZSTD_cwksp_alloc_objects || end > ws->workspaceEnd) {
+ DEBUGLOG(4, "cwksp: object alloc failed!");
+ ws->allocFailed = 1;
+ return NULL;
+ }
+ ws->objectEnd = end;
+ ws->tableEnd = end;
+ ws->tableValidEnd = end;
+
+#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
+ /* Move alloc so there's ZSTD_CWKSP_ASAN_REDZONE_SIZE unused space on
+ * either size. */
+ alloc = (BYTE *)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE;
+ __asan_unpoison_memory_region(alloc, bytes);
+#endif
+
+ return alloc;
+}
+
+MEM_STATIC void ZSTD_cwksp_mark_tables_dirty(ZSTD_cwksp* ws) {
+ DEBUGLOG(4, "cwksp: ZSTD_cwksp_mark_tables_dirty");
+
+#if defined (MEMORY_SANITIZER) && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE)
+ /* To validate that the table re-use logic is sound, and that we don't
+ * access table space that we haven't cleaned, we re-"poison" the table
+ * space every time we mark it dirty. */
+ {
+ size_t size = (BYTE*)ws->tableValidEnd - (BYTE*)ws->objectEnd;
+ assert(__msan_test_shadow(ws->objectEnd, size) == -1);
+ __msan_poison(ws->objectEnd, size);
+ }
+#endif
+
+ assert(ws->tableValidEnd >= ws->objectEnd);
+ assert(ws->tableValidEnd <= ws->allocStart);
+ ws->tableValidEnd = ws->objectEnd;
+ ZSTD_cwksp_assert_internal_consistency(ws);
+}
+
+MEM_STATIC void ZSTD_cwksp_mark_tables_clean(ZSTD_cwksp* ws) {
+ DEBUGLOG(4, "cwksp: ZSTD_cwksp_mark_tables_clean");
+ assert(ws->tableValidEnd >= ws->objectEnd);
+ assert(ws->tableValidEnd <= ws->allocStart);
+ if (ws->tableValidEnd < ws->tableEnd) {
+ ws->tableValidEnd = ws->tableEnd;
+ }
+ ZSTD_cwksp_assert_internal_consistency(ws);
+}
+
+/**
+ * Zero the part of the allocated tables not already marked clean.
+ */
+MEM_STATIC void ZSTD_cwksp_clean_tables(ZSTD_cwksp* ws) {
+ DEBUGLOG(4, "cwksp: ZSTD_cwksp_clean_tables");
+ assert(ws->tableValidEnd >= ws->objectEnd);
+ assert(ws->tableValidEnd <= ws->allocStart);
+ if (ws->tableValidEnd < ws->tableEnd) {
+ memset(ws->tableValidEnd, 0, (BYTE*)ws->tableEnd - (BYTE*)ws->tableValidEnd);
+ }
+ ZSTD_cwksp_mark_tables_clean(ws);
+}
+
+/**
+ * Invalidates table allocations.
+ * All other allocations remain valid.
+ */
+MEM_STATIC void ZSTD_cwksp_clear_tables(ZSTD_cwksp* ws) {
+ DEBUGLOG(4, "cwksp: clearing tables!");
+
+#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
+ {
+ size_t size = (BYTE*)ws->tableValidEnd - (BYTE*)ws->objectEnd;
+ __asan_poison_memory_region(ws->objectEnd, size);
+ }
+#endif
+
+ ws->tableEnd = ws->objectEnd;
+ ZSTD_cwksp_assert_internal_consistency(ws);
+}
+
+/**
+ * Invalidates all buffer, aligned, and table allocations.
+ * Object allocations remain valid.
+ */
+MEM_STATIC void ZSTD_cwksp_clear(ZSTD_cwksp* ws) {
+ DEBUGLOG(4, "cwksp: clearing!");
+
+#if defined (MEMORY_SANITIZER) && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE)
+ /* To validate that the context re-use logic is sound, and that we don't
+ * access stuff that this compression hasn't initialized, we re-"poison"
+ * the workspace (or at least the non-static, non-table parts of it)
+ * every time we start a new compression. */
+ {
+ size_t size = (BYTE*)ws->workspaceEnd - (BYTE*)ws->tableValidEnd;
+ __msan_poison(ws->tableValidEnd, size);
+ }
+#endif
+
+#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
+ {
+ size_t size = (BYTE*)ws->workspaceEnd - (BYTE*)ws->objectEnd;
+ __asan_poison_memory_region(ws->objectEnd, size);
+ }
+#endif
+
+ ws->tableEnd = ws->objectEnd;
+ ws->allocStart = ws->workspaceEnd;
+ ws->allocFailed = 0;
+ if (ws->phase > ZSTD_cwksp_alloc_buffers) {
+ ws->phase = ZSTD_cwksp_alloc_buffers;
+ }
+ ZSTD_cwksp_assert_internal_consistency(ws);
+}
+
+/**
+ * The provided workspace takes ownership of the buffer [start, start+size).
+ * Any existing values in the workspace are ignored (the previously managed
+ * buffer, if present, must be separately freed).
+ */
+MEM_STATIC void ZSTD_cwksp_init(ZSTD_cwksp* ws, void* start, size_t size) {
+ DEBUGLOG(4, "cwksp: init'ing workspace with %zd bytes", size);
+ assert(((size_t)start & (sizeof(void*)-1)) == 0); /* ensure correct alignment */
+ ws->workspace = start;
+ ws->workspaceEnd = (BYTE*)start + size;
+ ws->objectEnd = ws->workspace;
+ ws->tableValidEnd = ws->objectEnd;
+ ws->phase = ZSTD_cwksp_alloc_objects;
+ ZSTD_cwksp_clear(ws);
+ ws->workspaceOversizedDuration = 0;
+ ZSTD_cwksp_assert_internal_consistency(ws);
+}
+
+MEM_STATIC size_t ZSTD_cwksp_create(ZSTD_cwksp* ws, size_t size, ZSTD_customMem customMem) {
+ void* workspace = ZSTD_malloc(size, customMem);
+ DEBUGLOG(4, "cwksp: creating new workspace with %zd bytes", size);
+ RETURN_ERROR_IF(workspace == NULL, memory_allocation, "NULL pointer!");
+ ZSTD_cwksp_init(ws, workspace, size);
+ return 0;
+}
+
+MEM_STATIC void ZSTD_cwksp_free(ZSTD_cwksp* ws, ZSTD_customMem customMem) {
+ void *ptr = ws->workspace;
+ DEBUGLOG(4, "cwksp: freeing workspace");
+ memset(ws, 0, sizeof(ZSTD_cwksp));
+ ZSTD_free(ptr, customMem);
+}
+
+/**
+ * Moves the management of a workspace from one cwksp to another. The src cwksp
+ * is left in an invalid state (src must be re-init()'ed before its used again).
+ */
+MEM_STATIC void ZSTD_cwksp_move(ZSTD_cwksp* dst, ZSTD_cwksp* src) {
+ *dst = *src;
+ memset(src, 0, sizeof(ZSTD_cwksp));
+}
+
+MEM_STATIC size_t ZSTD_cwksp_sizeof(const ZSTD_cwksp* ws) {
+ return (size_t)((BYTE*)ws->workspaceEnd - (BYTE*)ws->workspace);
+}
+
+MEM_STATIC int ZSTD_cwksp_reserve_failed(const ZSTD_cwksp* ws) {
+ return ws->allocFailed;
+}
+
+/*-*************************************
+* Functions Checking Free Space
+***************************************/
+
+MEM_STATIC size_t ZSTD_cwksp_available_space(ZSTD_cwksp* ws) {
+ return (size_t)((BYTE*)ws->allocStart - (BYTE*)ws->tableEnd);
+}
+
+MEM_STATIC int ZSTD_cwksp_check_available(ZSTD_cwksp* ws, size_t additionalNeededSpace) {
+ return ZSTD_cwksp_available_space(ws) >= additionalNeededSpace;
+}
+
+MEM_STATIC int ZSTD_cwksp_check_too_large(ZSTD_cwksp* ws, size_t additionalNeededSpace) {
+ return ZSTD_cwksp_check_available(
+ ws, additionalNeededSpace * ZSTD_WORKSPACETOOLARGE_FACTOR);
+}
+
+MEM_STATIC int ZSTD_cwksp_check_wasteful(ZSTD_cwksp* ws, size_t additionalNeededSpace) {
+ return ZSTD_cwksp_check_too_large(ws, additionalNeededSpace)
+ && ws->workspaceOversizedDuration > ZSTD_WORKSPACETOOLARGE_MAXDURATION;
+}
+
+MEM_STATIC void ZSTD_cwksp_bump_oversized_duration(
+ ZSTD_cwksp* ws, size_t additionalNeededSpace) {
+ if (ZSTD_cwksp_check_too_large(ws, additionalNeededSpace)) {
+ ws->workspaceOversizedDuration++;
+ } else {
+ ws->workspaceOversizedDuration = 0;
+ }
+}
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* ZSTD_CWKSP_H */
diff --git a/sys/contrib/openzfs/module/zstd/lib/compress/zstd_double_fast.c b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_double_fast.c
new file mode 100644
index 000000000000..27eed66cfedd
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_double_fast.c
@@ -0,0 +1,521 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#include "zstd_compress_internal.h"
+#include "zstd_double_fast.h"
+
+
+void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms,
+ void const* end, ZSTD_dictTableLoadMethod_e dtlm)
+{
+ const ZSTD_compressionParameters* const cParams = &ms->cParams;
+ U32* const hashLarge = ms->hashTable;
+ U32 const hBitsL = cParams->hashLog;
+ U32 const mls = cParams->minMatch;
+ U32* const hashSmall = ms->chainTable;
+ U32 const hBitsS = cParams->chainLog;
+ const BYTE* const base = ms->window.base;
+ const BYTE* ip = base + ms->nextToUpdate;
+ const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
+ const U32 fastHashFillStep = 3;
+
+ /* Always insert every fastHashFillStep position into the hash tables.
+ * Insert the other positions into the large hash table if their entry
+ * is empty.
+ */
+ for (; ip + fastHashFillStep - 1 <= iend; ip += fastHashFillStep) {
+ U32 const current = (U32)(ip - base);
+ U32 i;
+ for (i = 0; i < fastHashFillStep; ++i) {
+ size_t const smHash = ZSTD_hashPtr(ip + i, hBitsS, mls);
+ size_t const lgHash = ZSTD_hashPtr(ip + i, hBitsL, 8);
+ if (i == 0)
+ hashSmall[smHash] = current + i;
+ if (i == 0 || hashLarge[lgHash] == 0)
+ hashLarge[lgHash] = current + i;
+ /* Only load extra positions for ZSTD_dtlm_full */
+ if (dtlm == ZSTD_dtlm_fast)
+ break;
+ } }
+}
+
+
+FORCE_INLINE_TEMPLATE
+size_t ZSTD_compressBlock_doubleFast_generic(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize,
+ U32 const mls /* template */, ZSTD_dictMode_e const dictMode)
+{
+ ZSTD_compressionParameters const* cParams = &ms->cParams;
+ U32* const hashLong = ms->hashTable;
+ const U32 hBitsL = cParams->hashLog;
+ U32* const hashSmall = ms->chainTable;
+ const U32 hBitsS = cParams->chainLog;
+ const BYTE* const base = ms->window.base;
+ const BYTE* const istart = (const BYTE*)src;
+ const BYTE* ip = istart;
+ const BYTE* anchor = istart;
+ const U32 endIndex = (U32)((size_t)(istart - base) + srcSize);
+ /* presumes that, if there is a dictionary, it must be using Attach mode */
+ const U32 prefixLowestIndex = ZSTD_getLowestPrefixIndex(ms, endIndex, cParams->windowLog);
+ const BYTE* const prefixLowest = base + prefixLowestIndex;
+ const BYTE* const iend = istart + srcSize;
+ const BYTE* const ilimit = iend - HASH_READ_SIZE;
+ U32 offset_1=rep[0], offset_2=rep[1];
+ U32 offsetSaved = 0;
+
+ const ZSTD_matchState_t* const dms = ms->dictMatchState;
+ const ZSTD_compressionParameters* const dictCParams =
+ dictMode == ZSTD_dictMatchState ?
+ &dms->cParams : NULL;
+ const U32* const dictHashLong = dictMode == ZSTD_dictMatchState ?
+ dms->hashTable : NULL;
+ const U32* const dictHashSmall = dictMode == ZSTD_dictMatchState ?
+ dms->chainTable : NULL;
+ const U32 dictStartIndex = dictMode == ZSTD_dictMatchState ?
+ dms->window.dictLimit : 0;
+ const BYTE* const dictBase = dictMode == ZSTD_dictMatchState ?
+ dms->window.base : NULL;
+ const BYTE* const dictStart = dictMode == ZSTD_dictMatchState ?
+ dictBase + dictStartIndex : NULL;
+ const BYTE* const dictEnd = dictMode == ZSTD_dictMatchState ?
+ dms->window.nextSrc : NULL;
+ const U32 dictIndexDelta = dictMode == ZSTD_dictMatchState ?
+ prefixLowestIndex - (U32)(dictEnd - dictBase) :
+ 0;
+ const U32 dictHBitsL = dictMode == ZSTD_dictMatchState ?
+ dictCParams->hashLog : hBitsL;
+ const U32 dictHBitsS = dictMode == ZSTD_dictMatchState ?
+ dictCParams->chainLog : hBitsS;
+ const U32 dictAndPrefixLength = (U32)((ip - prefixLowest) + (dictEnd - dictStart));
+
+ DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_generic");
+
+ assert(dictMode == ZSTD_noDict || dictMode == ZSTD_dictMatchState);
+
+ /* if a dictionary is attached, it must be within window range */
+ if (dictMode == ZSTD_dictMatchState) {
+ assert(ms->window.dictLimit + (1U << cParams->windowLog) >= endIndex);
+ }
+
+ /* init */
+ ip += (dictAndPrefixLength == 0);
+ if (dictMode == ZSTD_noDict) {
+ U32 const current = (U32)(ip - base);
+ U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, current, cParams->windowLog);
+ U32 const maxRep = current - windowLow;
+ if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
+ if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
+ }
+ if (dictMode == ZSTD_dictMatchState) {
+ /* dictMatchState repCode checks don't currently handle repCode == 0
+ * disabling. */
+ assert(offset_1 <= dictAndPrefixLength);
+ assert(offset_2 <= dictAndPrefixLength);
+ }
+
+ /* Main Search Loop */
+ while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
+ size_t mLength;
+ U32 offset;
+ size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
+ size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
+ size_t const dictHL = ZSTD_hashPtr(ip, dictHBitsL, 8);
+ size_t const dictHS = ZSTD_hashPtr(ip, dictHBitsS, mls);
+ U32 const current = (U32)(ip-base);
+ U32 const matchIndexL = hashLong[h2];
+ U32 matchIndexS = hashSmall[h];
+ const BYTE* matchLong = base + matchIndexL;
+ const BYTE* match = base + matchIndexS;
+ const U32 repIndex = current + 1 - offset_1;
+ const BYTE* repMatch = (dictMode == ZSTD_dictMatchState
+ && repIndex < prefixLowestIndex) ?
+ dictBase + (repIndex - dictIndexDelta) :
+ base + repIndex;
+ hashLong[h2] = hashSmall[h] = current; /* update hash tables */
+
+ /* check dictMatchState repcode */
+ if (dictMode == ZSTD_dictMatchState
+ && ((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */)
+ && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
+ const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend;
+ mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4;
+ ip++;
+ ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, 0, mLength-MINMATCH);
+ goto _match_stored;
+ }
+
+ /* check noDict repcode */
+ if ( dictMode == ZSTD_noDict
+ && ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)))) {
+ mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
+ ip++;
+ ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, 0, mLength-MINMATCH);
+ goto _match_stored;
+ }
+
+ if (matchIndexL > prefixLowestIndex) {
+ /* check prefix long match */
+ if (MEM_read64(matchLong) == MEM_read64(ip)) {
+ mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
+ offset = (U32)(ip-matchLong);
+ while (((ip>anchor) & (matchLong>prefixLowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
+ goto _match_found;
+ }
+ } else if (dictMode == ZSTD_dictMatchState) {
+ /* check dictMatchState long match */
+ U32 const dictMatchIndexL = dictHashLong[dictHL];
+ const BYTE* dictMatchL = dictBase + dictMatchIndexL;
+ assert(dictMatchL < dictEnd);
+
+ if (dictMatchL > dictStart && MEM_read64(dictMatchL) == MEM_read64(ip)) {
+ mLength = ZSTD_count_2segments(ip+8, dictMatchL+8, iend, dictEnd, prefixLowest) + 8;
+ offset = (U32)(current - dictMatchIndexL - dictIndexDelta);
+ while (((ip>anchor) & (dictMatchL>dictStart)) && (ip[-1] == dictMatchL[-1])) { ip--; dictMatchL--; mLength++; } /* catch up */
+ goto _match_found;
+ } }
+
+ if (matchIndexS > prefixLowestIndex) {
+ /* check prefix short match */
+ if (MEM_read32(match) == MEM_read32(ip)) {
+ goto _search_next_long;
+ }
+ } else if (dictMode == ZSTD_dictMatchState) {
+ /* check dictMatchState short match */
+ U32 const dictMatchIndexS = dictHashSmall[dictHS];
+ match = dictBase + dictMatchIndexS;
+ matchIndexS = dictMatchIndexS + dictIndexDelta;
+
+ if (match > dictStart && MEM_read32(match) == MEM_read32(ip)) {
+ goto _search_next_long;
+ } }
+
+ ip += ((ip-anchor) >> kSearchStrength) + 1;
+#if defined(__aarch64__)
+ PREFETCH_L1(ip+256);
+#endif
+ continue;
+
+_search_next_long:
+
+ { size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
+ size_t const dictHLNext = ZSTD_hashPtr(ip+1, dictHBitsL, 8);
+ U32 const matchIndexL3 = hashLong[hl3];
+ const BYTE* matchL3 = base + matchIndexL3;
+ hashLong[hl3] = current + 1;
+
+ /* check prefix long +1 match */
+ if (matchIndexL3 > prefixLowestIndex) {
+ if (MEM_read64(matchL3) == MEM_read64(ip+1)) {
+ mLength = ZSTD_count(ip+9, matchL3+8, iend) + 8;
+ ip++;
+ offset = (U32)(ip-matchL3);
+ while (((ip>anchor) & (matchL3>prefixLowest)) && (ip[-1] == matchL3[-1])) { ip--; matchL3--; mLength++; } /* catch up */
+ goto _match_found;
+ }
+ } else if (dictMode == ZSTD_dictMatchState) {
+ /* check dict long +1 match */
+ U32 const dictMatchIndexL3 = dictHashLong[dictHLNext];
+ const BYTE* dictMatchL3 = dictBase + dictMatchIndexL3;
+ assert(dictMatchL3 < dictEnd);
+ if (dictMatchL3 > dictStart && MEM_read64(dictMatchL3) == MEM_read64(ip+1)) {
+ mLength = ZSTD_count_2segments(ip+1+8, dictMatchL3+8, iend, dictEnd, prefixLowest) + 8;
+ ip++;
+ offset = (U32)(current + 1 - dictMatchIndexL3 - dictIndexDelta);
+ while (((ip>anchor) & (dictMatchL3>dictStart)) && (ip[-1] == dictMatchL3[-1])) { ip--; dictMatchL3--; mLength++; } /* catch up */
+ goto _match_found;
+ } } }
+
+ /* if no long +1 match, explore the short match we found */
+ if (dictMode == ZSTD_dictMatchState && matchIndexS < prefixLowestIndex) {
+ mLength = ZSTD_count_2segments(ip+4, match+4, iend, dictEnd, prefixLowest) + 4;
+ offset = (U32)(current - matchIndexS);
+ while (((ip>anchor) & (match>dictStart)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
+ } else {
+ mLength = ZSTD_count(ip+4, match+4, iend) + 4;
+ offset = (U32)(ip - match);
+ while (((ip>anchor) & (match>prefixLowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
+ }
+
+ /* fall-through */
+
+_match_found:
+ offset_2 = offset_1;
+ offset_1 = offset;
+
+ ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
+
+_match_stored:
+ /* match found */
+ ip += mLength;
+ anchor = ip;
+
+ if (ip <= ilimit) {
+ /* Complementary insertion */
+ /* done after iLimit test, as candidates could be > iend-8 */
+ { U32 const indexToInsert = current+2;
+ hashLong[ZSTD_hashPtr(base+indexToInsert, hBitsL, 8)] = indexToInsert;
+ hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
+ hashSmall[ZSTD_hashPtr(base+indexToInsert, hBitsS, mls)] = indexToInsert;
+ hashSmall[ZSTD_hashPtr(ip-1, hBitsS, mls)] = (U32)(ip-1-base);
+ }
+
+ /* check immediate repcode */
+ if (dictMode == ZSTD_dictMatchState) {
+ while (ip <= ilimit) {
+ U32 const current2 = (U32)(ip-base);
+ U32 const repIndex2 = current2 - offset_2;
+ const BYTE* repMatch2 = dictMode == ZSTD_dictMatchState
+ && repIndex2 < prefixLowestIndex ?
+ dictBase + repIndex2 - dictIndexDelta :
+ base + repIndex2;
+ if ( ((U32)((prefixLowestIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */)
+ && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
+ const BYTE* const repEnd2 = repIndex2 < prefixLowestIndex ? dictEnd : iend;
+ size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixLowest) + 4;
+ U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
+ ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, repLength2-MINMATCH);
+ hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
+ hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
+ ip += repLength2;
+ anchor = ip;
+ continue;
+ }
+ break;
+ } }
+
+ if (dictMode == ZSTD_noDict) {
+ while ( (ip <= ilimit)
+ && ( (offset_2>0)
+ & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
+ /* store sequence */
+ size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
+ U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; /* swap offset_2 <=> offset_1 */
+ hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
+ hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
+ ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, rLength-MINMATCH);
+ ip += rLength;
+ anchor = ip;
+ continue; /* faster when present ... (?) */
+ } } }
+ } /* while (ip < ilimit) */
+
+ /* save reps for next block */
+ rep[0] = offset_1 ? offset_1 : offsetSaved;
+ rep[1] = offset_2 ? offset_2 : offsetSaved;
+
+ /* Return the last literals size */
+ return (size_t)(iend - anchor);
+}
+
+
+size_t ZSTD_compressBlock_doubleFast(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ const U32 mls = ms->cParams.minMatch;
+ switch(mls)
+ {
+ default: /* includes case 3 */
+ case 4 :
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 4, ZSTD_noDict);
+ case 5 :
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 5, ZSTD_noDict);
+ case 6 :
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 6, ZSTD_noDict);
+ case 7 :
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 7, ZSTD_noDict);
+ }
+}
+
+
+size_t ZSTD_compressBlock_doubleFast_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ const U32 mls = ms->cParams.minMatch;
+ switch(mls)
+ {
+ default: /* includes case 3 */
+ case 4 :
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 4, ZSTD_dictMatchState);
+ case 5 :
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 5, ZSTD_dictMatchState);
+ case 6 :
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 6, ZSTD_dictMatchState);
+ case 7 :
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 7, ZSTD_dictMatchState);
+ }
+}
+
+
+static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize,
+ U32 const mls /* template */)
+{
+ ZSTD_compressionParameters const* cParams = &ms->cParams;
+ U32* const hashLong = ms->hashTable;
+ U32 const hBitsL = cParams->hashLog;
+ U32* const hashSmall = ms->chainTable;
+ U32 const hBitsS = cParams->chainLog;
+ const BYTE* const istart = (const BYTE*)src;
+ const BYTE* ip = istart;
+ const BYTE* anchor = istart;
+ const BYTE* const iend = istart + srcSize;
+ const BYTE* const ilimit = iend - 8;
+ const BYTE* const base = ms->window.base;
+ const U32 endIndex = (U32)((size_t)(istart - base) + srcSize);
+ const U32 lowLimit = ZSTD_getLowestMatchIndex(ms, endIndex, cParams->windowLog);
+ const U32 dictStartIndex = lowLimit;
+ const U32 dictLimit = ms->window.dictLimit;
+ const U32 prefixStartIndex = (dictLimit > lowLimit) ? dictLimit : lowLimit;
+ const BYTE* const prefixStart = base + prefixStartIndex;
+ const BYTE* const dictBase = ms->window.dictBase;
+ const BYTE* const dictStart = dictBase + dictStartIndex;
+ const BYTE* const dictEnd = dictBase + prefixStartIndex;
+ U32 offset_1=rep[0], offset_2=rep[1];
+
+ DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_extDict_generic (srcSize=%zu)", srcSize);
+
+ /* if extDict is invalidated due to maxDistance, switch to "regular" variant */
+ if (prefixStartIndex == dictStartIndex)
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, mls, ZSTD_noDict);
+
+ /* Search Loop */
+ while (ip < ilimit) { /* < instead of <=, because (ip+1) */
+ const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
+ const U32 matchIndex = hashSmall[hSmall];
+ const BYTE* const matchBase = matchIndex < prefixStartIndex ? dictBase : base;
+ const BYTE* match = matchBase + matchIndex;
+
+ const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
+ const U32 matchLongIndex = hashLong[hLong];
+ const BYTE* const matchLongBase = matchLongIndex < prefixStartIndex ? dictBase : base;
+ const BYTE* matchLong = matchLongBase + matchLongIndex;
+
+ const U32 current = (U32)(ip-base);
+ const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
+ const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base;
+ const BYTE* const repMatch = repBase + repIndex;
+ size_t mLength;
+ hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */
+
+ if ((((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow : ensure repIndex doesn't overlap dict + prefix */
+ & (repIndex > dictStartIndex))
+ && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
+ const BYTE* repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
+ mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4;
+ ip++;
+ ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, 0, mLength-MINMATCH);
+ } else {
+ if ((matchLongIndex > dictStartIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
+ const BYTE* const matchEnd = matchLongIndex < prefixStartIndex ? dictEnd : iend;
+ const BYTE* const lowMatchPtr = matchLongIndex < prefixStartIndex ? dictStart : prefixStart;
+ U32 offset;
+ mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, prefixStart) + 8;
+ offset = current - matchLongIndex;
+ while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
+ offset_2 = offset_1;
+ offset_1 = offset;
+ ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
+
+ } else if ((matchIndex > dictStartIndex) && (MEM_read32(match) == MEM_read32(ip))) {
+ size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
+ U32 const matchIndex3 = hashLong[h3];
+ const BYTE* const match3Base = matchIndex3 < prefixStartIndex ? dictBase : base;
+ const BYTE* match3 = match3Base + matchIndex3;
+ U32 offset;
+ hashLong[h3] = current + 1;
+ if ( (matchIndex3 > dictStartIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
+ const BYTE* const matchEnd = matchIndex3 < prefixStartIndex ? dictEnd : iend;
+ const BYTE* const lowMatchPtr = matchIndex3 < prefixStartIndex ? dictStart : prefixStart;
+ mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, prefixStart) + 8;
+ ip++;
+ offset = current+1 - matchIndex3;
+ while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
+ } else {
+ const BYTE* const matchEnd = matchIndex < prefixStartIndex ? dictEnd : iend;
+ const BYTE* const lowMatchPtr = matchIndex < prefixStartIndex ? dictStart : prefixStart;
+ mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, prefixStart) + 4;
+ offset = current - matchIndex;
+ while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
+ }
+ offset_2 = offset_1;
+ offset_1 = offset;
+ ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
+
+ } else {
+ ip += ((ip-anchor) >> kSearchStrength) + 1;
+ continue;
+ } }
+
+ /* move to next sequence start */
+ ip += mLength;
+ anchor = ip;
+
+ if (ip <= ilimit) {
+ /* Complementary insertion */
+ /* done after iLimit test, as candidates could be > iend-8 */
+ { U32 const indexToInsert = current+2;
+ hashLong[ZSTD_hashPtr(base+indexToInsert, hBitsL, 8)] = indexToInsert;
+ hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
+ hashSmall[ZSTD_hashPtr(base+indexToInsert, hBitsS, mls)] = indexToInsert;
+ hashSmall[ZSTD_hashPtr(ip-1, hBitsS, mls)] = (U32)(ip-1-base);
+ }
+
+ /* check immediate repcode */
+ while (ip <= ilimit) {
+ U32 const current2 = (U32)(ip-base);
+ U32 const repIndex2 = current2 - offset_2;
+ const BYTE* repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2;
+ if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) /* intentional overflow : ensure repIndex2 doesn't overlap dict + prefix */
+ & (repIndex2 > dictStartIndex))
+ && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
+ const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend;
+ size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4;
+ U32 const tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
+ ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, repLength2-MINMATCH);
+ hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
+ hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
+ ip += repLength2;
+ anchor = ip;
+ continue;
+ }
+ break;
+ } } }
+
+ /* save reps for next block */
+ rep[0] = offset_1;
+ rep[1] = offset_2;
+
+ /* Return the last literals size */
+ return (size_t)(iend - anchor);
+}
+
+
+size_t ZSTD_compressBlock_doubleFast_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ U32 const mls = ms->cParams.minMatch;
+ switch(mls)
+ {
+ default: /* includes case 3 */
+ case 4 :
+ return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 4);
+ case 5 :
+ return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 5);
+ case 6 :
+ return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 6);
+ case 7 :
+ return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 7);
+ }
+}
diff --git a/sys/contrib/openzfs/module/zstd/lib/compress/zstd_double_fast.h b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_double_fast.h
new file mode 100644
index 000000000000..14d944d69bc1
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_double_fast.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_DOUBLE_FAST_H
+#define ZSTD_DOUBLE_FAST_H
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#include "../common/mem.h" /* U32 */
+#include "zstd_compress_internal.h" /* ZSTD_CCtx, size_t */
+
+void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms,
+ void const* end, ZSTD_dictTableLoadMethod_e dtlm);
+size_t ZSTD_compressBlock_doubleFast(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_doubleFast_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_doubleFast_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* ZSTD_DOUBLE_FAST_H */
diff --git a/sys/contrib/openzfs/module/zstd/lib/compress/zstd_fast.c b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_fast.c
new file mode 100644
index 000000000000..85a3a7a91e49
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_fast.c
@@ -0,0 +1,496 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#include "zstd_compress_internal.h" /* ZSTD_hashPtr, ZSTD_count, ZSTD_storeSeq */
+#include "zstd_fast.h"
+
+
+void ZSTD_fillHashTable(ZSTD_matchState_t* ms,
+ const void* const end,
+ ZSTD_dictTableLoadMethod_e dtlm)
+{
+ const ZSTD_compressionParameters* const cParams = &ms->cParams;
+ U32* const hashTable = ms->hashTable;
+ U32 const hBits = cParams->hashLog;
+ U32 const mls = cParams->minMatch;
+ const BYTE* const base = ms->window.base;
+ const BYTE* ip = base + ms->nextToUpdate;
+ const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
+ const U32 fastHashFillStep = 3;
+
+ /* Always insert every fastHashFillStep position into the hash table.
+ * Insert the other positions if their hash entry is empty.
+ */
+ for ( ; ip + fastHashFillStep < iend + 2; ip += fastHashFillStep) {
+ U32 const current = (U32)(ip - base);
+ size_t const hash0 = ZSTD_hashPtr(ip, hBits, mls);
+ hashTable[hash0] = current;
+ if (dtlm == ZSTD_dtlm_fast) continue;
+ /* Only load extra positions for ZSTD_dtlm_full */
+ { U32 p;
+ for (p = 1; p < fastHashFillStep; ++p) {
+ size_t const hash = ZSTD_hashPtr(ip + p, hBits, mls);
+ if (hashTable[hash] == 0) { /* not yet filled */
+ hashTable[hash] = current + p;
+ } } } }
+}
+
+
+FORCE_INLINE_TEMPLATE size_t
+ZSTD_compressBlock_fast_generic(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize,
+ U32 const mls)
+{
+ const ZSTD_compressionParameters* const cParams = &ms->cParams;
+ U32* const hashTable = ms->hashTable;
+ U32 const hlog = cParams->hashLog;
+ /* support stepSize of 0 */
+ size_t const stepSize = cParams->targetLength + !(cParams->targetLength) + 1;
+ const BYTE* const base = ms->window.base;
+ const BYTE* const istart = (const BYTE*)src;
+ /* We check ip0 (ip + 0) and ip1 (ip + 1) each loop */
+ const BYTE* ip0 = istart;
+ const BYTE* ip1;
+ const BYTE* anchor = istart;
+ const U32 endIndex = (U32)((size_t)(istart - base) + srcSize);
+ const U32 prefixStartIndex = ZSTD_getLowestPrefixIndex(ms, endIndex, cParams->windowLog);
+ const BYTE* const prefixStart = base + prefixStartIndex;
+ const BYTE* const iend = istart + srcSize;
+ const BYTE* const ilimit = iend - HASH_READ_SIZE;
+ U32 offset_1=rep[0], offset_2=rep[1];
+ U32 offsetSaved = 0;
+
+ /* init */
+ DEBUGLOG(5, "ZSTD_compressBlock_fast_generic");
+ ip0 += (ip0 == prefixStart);
+ ip1 = ip0 + 1;
+ { U32 const current = (U32)(ip0 - base);
+ U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, current, cParams->windowLog);
+ U32 const maxRep = current - windowLow;
+ if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
+ if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
+ }
+
+ /* Main Search Loop */
+#ifdef __INTEL_COMPILER
+ /* From intel 'The vector pragma indicates that the loop should be
+ * vectorized if it is legal to do so'. Can be used together with
+ * #pragma ivdep (but have opted to exclude that because intel
+ * warns against using it).*/
+ #pragma vector always
+#endif
+ while (ip1 < ilimit) { /* < instead of <=, because check at ip0+2 */
+ size_t mLength;
+ BYTE const* ip2 = ip0 + 2;
+ size_t const h0 = ZSTD_hashPtr(ip0, hlog, mls);
+ U32 const val0 = MEM_read32(ip0);
+ size_t const h1 = ZSTD_hashPtr(ip1, hlog, mls);
+ U32 const val1 = MEM_read32(ip1);
+ U32 const current0 = (U32)(ip0-base);
+ U32 const current1 = (U32)(ip1-base);
+ U32 const matchIndex0 = hashTable[h0];
+ U32 const matchIndex1 = hashTable[h1];
+ BYTE const* repMatch = ip2 - offset_1;
+ const BYTE* match0 = base + matchIndex0;
+ const BYTE* match1 = base + matchIndex1;
+ U32 offcode;
+
+#if defined(__aarch64__)
+ PREFETCH_L1(ip0+256);
+#endif
+
+ hashTable[h0] = current0; /* update hash table */
+ hashTable[h1] = current1; /* update hash table */
+
+ assert(ip0 + 1 == ip1);
+
+ if ((offset_1 > 0) & (MEM_read32(repMatch) == MEM_read32(ip2))) {
+ mLength = (ip2[-1] == repMatch[-1]) ? 1 : 0;
+ ip0 = ip2 - mLength;
+ match0 = repMatch - mLength;
+ mLength += 4;
+ offcode = 0;
+ goto _match;
+ }
+ if ((matchIndex0 > prefixStartIndex) && MEM_read32(match0) == val0) {
+ /* found a regular match */
+ goto _offset;
+ }
+ if ((matchIndex1 > prefixStartIndex) && MEM_read32(match1) == val1) {
+ /* found a regular match after one literal */
+ ip0 = ip1;
+ match0 = match1;
+ goto _offset;
+ }
+ { size_t const step = ((size_t)(ip0-anchor) >> (kSearchStrength - 1)) + stepSize;
+ assert(step >= 2);
+ ip0 += step;
+ ip1 += step;
+ continue;
+ }
+_offset: /* Requires: ip0, match0 */
+ /* Compute the offset code */
+ offset_2 = offset_1;
+ offset_1 = (U32)(ip0-match0);
+ offcode = offset_1 + ZSTD_REP_MOVE;
+ mLength = 4;
+ /* Count the backwards match length */
+ while (((ip0>anchor) & (match0>prefixStart))
+ && (ip0[-1] == match0[-1])) { ip0--; match0--; mLength++; } /* catch up */
+
+_match: /* Requires: ip0, match0, offcode */
+ /* Count the forward length */
+ mLength += ZSTD_count(ip0+mLength, match0+mLength, iend);
+ ZSTD_storeSeq(seqStore, (size_t)(ip0-anchor), anchor, iend, offcode, mLength-MINMATCH);
+ /* match found */
+ ip0 += mLength;
+ anchor = ip0;
+
+ if (ip0 <= ilimit) {
+ /* Fill Table */
+ assert(base+current0+2 > istart); /* check base overflow */
+ hashTable[ZSTD_hashPtr(base+current0+2, hlog, mls)] = current0+2; /* here because current+2 could be > iend-8 */
+ hashTable[ZSTD_hashPtr(ip0-2, hlog, mls)] = (U32)(ip0-2-base);
+
+ if (offset_2 > 0) { /* offset_2==0 means offset_2 is invalidated */
+ while ( (ip0 <= ilimit) && (MEM_read32(ip0) == MEM_read32(ip0 - offset_2)) ) {
+ /* store sequence */
+ size_t const rLength = ZSTD_count(ip0+4, ip0+4-offset_2, iend) + 4;
+ { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
+ hashTable[ZSTD_hashPtr(ip0, hlog, mls)] = (U32)(ip0-base);
+ ip0 += rLength;
+ ZSTD_storeSeq(seqStore, 0 /*litLen*/, anchor, iend, 0 /*offCode*/, rLength-MINMATCH);
+ anchor = ip0;
+ continue; /* faster when present (confirmed on gcc-8) ... (?) */
+ } } }
+ ip1 = ip0 + 1;
+ }
+
+ /* save reps for next block */
+ rep[0] = offset_1 ? offset_1 : offsetSaved;
+ rep[1] = offset_2 ? offset_2 : offsetSaved;
+
+ /* Return the last literals size */
+ return (size_t)(iend - anchor);
+}
+
+
+size_t ZSTD_compressBlock_fast(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ U32 const mls = ms->cParams.minMatch;
+ assert(ms->dictMatchState == NULL);
+ switch(mls)
+ {
+ default: /* includes case 3 */
+ case 4 :
+ return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 4);
+ case 5 :
+ return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 5);
+ case 6 :
+ return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 6);
+ case 7 :
+ return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 7);
+ }
+}
+
+FORCE_INLINE_TEMPLATE
+size_t ZSTD_compressBlock_fast_dictMatchState_generic(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize, U32 const mls)
+{
+ const ZSTD_compressionParameters* const cParams = &ms->cParams;
+ U32* const hashTable = ms->hashTable;
+ U32 const hlog = cParams->hashLog;
+ /* support stepSize of 0 */
+ U32 const stepSize = cParams->targetLength + !(cParams->targetLength);
+ const BYTE* const base = ms->window.base;
+ const BYTE* const istart = (const BYTE*)src;
+ const BYTE* ip = istart;
+ const BYTE* anchor = istart;
+ const U32 prefixStartIndex = ms->window.dictLimit;
+ const BYTE* const prefixStart = base + prefixStartIndex;
+ const BYTE* const iend = istart + srcSize;
+ const BYTE* const ilimit = iend - HASH_READ_SIZE;
+ U32 offset_1=rep[0], offset_2=rep[1];
+ U32 offsetSaved = 0;
+
+ const ZSTD_matchState_t* const dms = ms->dictMatchState;
+ const ZSTD_compressionParameters* const dictCParams = &dms->cParams ;
+ const U32* const dictHashTable = dms->hashTable;
+ const U32 dictStartIndex = dms->window.dictLimit;
+ const BYTE* const dictBase = dms->window.base;
+ const BYTE* const dictStart = dictBase + dictStartIndex;
+ const BYTE* const dictEnd = dms->window.nextSrc;
+ const U32 dictIndexDelta = prefixStartIndex - (U32)(dictEnd - dictBase);
+ const U32 dictAndPrefixLength = (U32)(ip - prefixStart + dictEnd - dictStart);
+ const U32 dictHLog = dictCParams->hashLog;
+
+ /* if a dictionary is still attached, it necessarily means that
+ * it is within window size. So we just check it. */
+ const U32 maxDistance = 1U << cParams->windowLog;
+ const U32 endIndex = (U32)((size_t)(ip - base) + srcSize);
+ assert(endIndex - prefixStartIndex <= maxDistance);
+ (void)maxDistance; (void)endIndex; /* these variables are not used when assert() is disabled */
+
+ /* ensure there will be no no underflow
+ * when translating a dict index into a local index */
+ assert(prefixStartIndex >= (U32)(dictEnd - dictBase));
+
+ /* init */
+ DEBUGLOG(5, "ZSTD_compressBlock_fast_dictMatchState_generic");
+ ip += (dictAndPrefixLength == 0);
+ /* dictMatchState repCode checks don't currently handle repCode == 0
+ * disabling. */
+ assert(offset_1 <= dictAndPrefixLength);
+ assert(offset_2 <= dictAndPrefixLength);
+
+ /* Main Search Loop */
+ while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
+ size_t mLength;
+ size_t const h = ZSTD_hashPtr(ip, hlog, mls);
+ U32 const current = (U32)(ip-base);
+ U32 const matchIndex = hashTable[h];
+ const BYTE* match = base + matchIndex;
+ const U32 repIndex = current + 1 - offset_1;
+ const BYTE* repMatch = (repIndex < prefixStartIndex) ?
+ dictBase + (repIndex - dictIndexDelta) :
+ base + repIndex;
+ hashTable[h] = current; /* update hash table */
+
+ if ( ((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow : ensure repIndex isn't overlapping dict + prefix */
+ && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
+ const BYTE* const repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
+ mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4;
+ ip++;
+ ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, 0, mLength-MINMATCH);
+ } else if ( (matchIndex <= prefixStartIndex) ) {
+ size_t const dictHash = ZSTD_hashPtr(ip, dictHLog, mls);
+ U32 const dictMatchIndex = dictHashTable[dictHash];
+ const BYTE* dictMatch = dictBase + dictMatchIndex;
+ if (dictMatchIndex <= dictStartIndex ||
+ MEM_read32(dictMatch) != MEM_read32(ip)) {
+ assert(stepSize >= 1);
+ ip += ((ip-anchor) >> kSearchStrength) + stepSize;
+ continue;
+ } else {
+ /* found a dict match */
+ U32 const offset = (U32)(current-dictMatchIndex-dictIndexDelta);
+ mLength = ZSTD_count_2segments(ip+4, dictMatch+4, iend, dictEnd, prefixStart) + 4;
+ while (((ip>anchor) & (dictMatch>dictStart))
+ && (ip[-1] == dictMatch[-1])) {
+ ip--; dictMatch--; mLength++;
+ } /* catch up */
+ offset_2 = offset_1;
+ offset_1 = offset;
+ ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
+ }
+ } else if (MEM_read32(match) != MEM_read32(ip)) {
+ /* it's not a match, and we're not going to check the dictionary */
+ assert(stepSize >= 1);
+ ip += ((ip-anchor) >> kSearchStrength) + stepSize;
+ continue;
+ } else {
+ /* found a regular match */
+ U32 const offset = (U32)(ip-match);
+ mLength = ZSTD_count(ip+4, match+4, iend) + 4;
+ while (((ip>anchor) & (match>prefixStart))
+ && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
+ offset_2 = offset_1;
+ offset_1 = offset;
+ ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
+ }
+
+ /* match found */
+ ip += mLength;
+ anchor = ip;
+
+ if (ip <= ilimit) {
+ /* Fill Table */
+ assert(base+current+2 > istart); /* check base overflow */
+ hashTable[ZSTD_hashPtr(base+current+2, hlog, mls)] = current+2; /* here because current+2 could be > iend-8 */
+ hashTable[ZSTD_hashPtr(ip-2, hlog, mls)] = (U32)(ip-2-base);
+
+ /* check immediate repcode */
+ while (ip <= ilimit) {
+ U32 const current2 = (U32)(ip-base);
+ U32 const repIndex2 = current2 - offset_2;
+ const BYTE* repMatch2 = repIndex2 < prefixStartIndex ?
+ dictBase - dictIndexDelta + repIndex2 :
+ base + repIndex2;
+ if ( ((U32)((prefixStartIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */)
+ && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
+ const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend;
+ size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4;
+ U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
+ ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, repLength2-MINMATCH);
+ hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2;
+ ip += repLength2;
+ anchor = ip;
+ continue;
+ }
+ break;
+ }
+ }
+ }
+
+ /* save reps for next block */
+ rep[0] = offset_1 ? offset_1 : offsetSaved;
+ rep[1] = offset_2 ? offset_2 : offsetSaved;
+
+ /* Return the last literals size */
+ return (size_t)(iend - anchor);
+}
+
+size_t ZSTD_compressBlock_fast_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ U32 const mls = ms->cParams.minMatch;
+ assert(ms->dictMatchState != NULL);
+ switch(mls)
+ {
+ default: /* includes case 3 */
+ case 4 :
+ return ZSTD_compressBlock_fast_dictMatchState_generic(ms, seqStore, rep, src, srcSize, 4);
+ case 5 :
+ return ZSTD_compressBlock_fast_dictMatchState_generic(ms, seqStore, rep, src, srcSize, 5);
+ case 6 :
+ return ZSTD_compressBlock_fast_dictMatchState_generic(ms, seqStore, rep, src, srcSize, 6);
+ case 7 :
+ return ZSTD_compressBlock_fast_dictMatchState_generic(ms, seqStore, rep, src, srcSize, 7);
+ }
+}
+
+
+static size_t ZSTD_compressBlock_fast_extDict_generic(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize, U32 const mls)
+{
+ const ZSTD_compressionParameters* const cParams = &ms->cParams;
+ U32* const hashTable = ms->hashTable;
+ U32 const hlog = cParams->hashLog;
+ /* support stepSize of 0 */
+ U32 const stepSize = cParams->targetLength + !(cParams->targetLength);
+ const BYTE* const base = ms->window.base;
+ const BYTE* const dictBase = ms->window.dictBase;
+ const BYTE* const istart = (const BYTE*)src;
+ const BYTE* ip = istart;
+ const BYTE* anchor = istart;
+ const U32 endIndex = (U32)((size_t)(istart - base) + srcSize);
+ const U32 lowLimit = ZSTD_getLowestMatchIndex(ms, endIndex, cParams->windowLog);
+ const U32 dictStartIndex = lowLimit;
+ const BYTE* const dictStart = dictBase + dictStartIndex;
+ const U32 dictLimit = ms->window.dictLimit;
+ const U32 prefixStartIndex = dictLimit < lowLimit ? lowLimit : dictLimit;
+ const BYTE* const prefixStart = base + prefixStartIndex;
+ const BYTE* const dictEnd = dictBase + prefixStartIndex;
+ const BYTE* const iend = istart + srcSize;
+ const BYTE* const ilimit = iend - 8;
+ U32 offset_1=rep[0], offset_2=rep[1];
+
+ DEBUGLOG(5, "ZSTD_compressBlock_fast_extDict_generic (offset_1=%u)", offset_1);
+
+ /* switch to "regular" variant if extDict is invalidated due to maxDistance */
+ if (prefixStartIndex == dictStartIndex)
+ return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, mls);
+
+ /* Search Loop */
+ while (ip < ilimit) { /* < instead of <=, because (ip+1) */
+ const size_t h = ZSTD_hashPtr(ip, hlog, mls);
+ const U32 matchIndex = hashTable[h];
+ const BYTE* const matchBase = matchIndex < prefixStartIndex ? dictBase : base;
+ const BYTE* match = matchBase + matchIndex;
+ const U32 current = (U32)(ip-base);
+ const U32 repIndex = current + 1 - offset_1;
+ const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base;
+ const BYTE* const repMatch = repBase + repIndex;
+ hashTable[h] = current; /* update hash table */
+ DEBUGLOG(7, "offset_1 = %u , current = %u", offset_1, current);
+ assert(offset_1 <= current +1); /* check repIndex */
+
+ if ( (((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > dictStartIndex))
+ && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
+ const BYTE* const repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
+ size_t const rLength = ZSTD_count_2segments(ip+1 +4, repMatch +4, iend, repMatchEnd, prefixStart) + 4;
+ ip++;
+ ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, 0, rLength-MINMATCH);
+ ip += rLength;
+ anchor = ip;
+ } else {
+ if ( (matchIndex < dictStartIndex) ||
+ (MEM_read32(match) != MEM_read32(ip)) ) {
+ assert(stepSize >= 1);
+ ip += ((ip-anchor) >> kSearchStrength) + stepSize;
+ continue;
+ }
+ { const BYTE* const matchEnd = matchIndex < prefixStartIndex ? dictEnd : iend;
+ const BYTE* const lowMatchPtr = matchIndex < prefixStartIndex ? dictStart : prefixStart;
+ U32 const offset = current - matchIndex;
+ size_t mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, prefixStart) + 4;
+ while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
+ offset_2 = offset_1; offset_1 = offset; /* update offset history */
+ ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
+ ip += mLength;
+ anchor = ip;
+ } }
+
+ if (ip <= ilimit) {
+ /* Fill Table */
+ hashTable[ZSTD_hashPtr(base+current+2, hlog, mls)] = current+2;
+ hashTable[ZSTD_hashPtr(ip-2, hlog, mls)] = (U32)(ip-2-base);
+ /* check immediate repcode */
+ while (ip <= ilimit) {
+ U32 const current2 = (U32)(ip-base);
+ U32 const repIndex2 = current2 - offset_2;
+ const BYTE* const repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2;
+ if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) & (repIndex2 > dictStartIndex)) /* intentional overflow */
+ && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
+ const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend;
+ size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4;
+ { U32 const tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; } /* swap offset_2 <=> offset_1 */
+ ZSTD_storeSeq(seqStore, 0 /*litlen*/, anchor, iend, 0 /*offcode*/, repLength2-MINMATCH);
+ hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2;
+ ip += repLength2;
+ anchor = ip;
+ continue;
+ }
+ break;
+ } } }
+
+ /* save reps for next block */
+ rep[0] = offset_1;
+ rep[1] = offset_2;
+
+ /* Return the last literals size */
+ return (size_t)(iend - anchor);
+}
+
+
+size_t ZSTD_compressBlock_fast_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ U32 const mls = ms->cParams.minMatch;
+ switch(mls)
+ {
+ default: /* includes case 3 */
+ case 4 :
+ return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 4);
+ case 5 :
+ return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 5);
+ case 6 :
+ return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 6);
+ case 7 :
+ return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 7);
+ }
+}
diff --git a/sys/contrib/openzfs/module/zstd/lib/compress/zstd_fast.h b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_fast.h
new file mode 100644
index 000000000000..cf6aaa8e6750
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_fast.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_FAST_H
+#define ZSTD_FAST_H
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#include "../common/mem.h" /* U32 */
+#include "zstd_compress_internal.h"
+
+void ZSTD_fillHashTable(ZSTD_matchState_t* ms,
+ void const* end, ZSTD_dictTableLoadMethod_e dtlm);
+size_t ZSTD_compressBlock_fast(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_fast_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_fast_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* ZSTD_FAST_H */
diff --git a/sys/contrib/openzfs/module/zstd/lib/compress/zstd_lazy.c b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_lazy.c
new file mode 100644
index 000000000000..4cf5c88b5325
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_lazy.c
@@ -0,0 +1,1138 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#include "zstd_compress_internal.h"
+#include "zstd_lazy.h"
+
+
+/*-*************************************
+* Binary Tree search
+***************************************/
+
+static void
+ZSTD_updateDUBT(ZSTD_matchState_t* ms,
+ const BYTE* ip, const BYTE* iend,
+ U32 mls)
+{
+ const ZSTD_compressionParameters* const cParams = &ms->cParams;
+ U32* const hashTable = ms->hashTable;
+ U32 const hashLog = cParams->hashLog;
+
+ U32* const bt = ms->chainTable;
+ U32 const btLog = cParams->chainLog - 1;
+ U32 const btMask = (1 << btLog) - 1;
+
+ const BYTE* const base = ms->window.base;
+ U32 const target = (U32)(ip - base);
+ U32 idx = ms->nextToUpdate;
+
+ if (idx != target)
+ DEBUGLOG(7, "ZSTD_updateDUBT, from %u to %u (dictLimit:%u)",
+ idx, target, ms->window.dictLimit);
+ assert(ip + 8 <= iend); /* condition for ZSTD_hashPtr */
+ (void)iend;
+
+ assert(idx >= ms->window.dictLimit); /* condition for valid base+idx */
+ for ( ; idx < target ; idx++) {
+ size_t const h = ZSTD_hashPtr(base + idx, hashLog, mls); /* assumption : ip + 8 <= iend */
+ U32 const matchIndex = hashTable[h];
+
+ U32* const nextCandidatePtr = bt + 2*(idx&btMask);
+ U32* const sortMarkPtr = nextCandidatePtr + 1;
+
+ DEBUGLOG(8, "ZSTD_updateDUBT: insert %u", idx);
+ hashTable[h] = idx; /* Update Hash Table */
+ *nextCandidatePtr = matchIndex; /* update BT like a chain */
+ *sortMarkPtr = ZSTD_DUBT_UNSORTED_MARK;
+ }
+ ms->nextToUpdate = target;
+}
+
+
+/** ZSTD_insertDUBT1() :
+ * sort one already inserted but unsorted position
+ * assumption : current >= btlow == (current - btmask)
+ * doesn't fail */
+static void
+ZSTD_insertDUBT1(ZSTD_matchState_t* ms,
+ U32 current, const BYTE* inputEnd,
+ U32 nbCompares, U32 btLow,
+ const ZSTD_dictMode_e dictMode)
+{
+ const ZSTD_compressionParameters* const cParams = &ms->cParams;
+ U32* const bt = ms->chainTable;
+ U32 const btLog = cParams->chainLog - 1;
+ U32 const btMask = (1 << btLog) - 1;
+ size_t commonLengthSmaller=0, commonLengthLarger=0;
+ const BYTE* const base = ms->window.base;
+ const BYTE* const dictBase = ms->window.dictBase;
+ const U32 dictLimit = ms->window.dictLimit;
+ const BYTE* const ip = (current>=dictLimit) ? base + current : dictBase + current;
+ const BYTE* const iend = (current>=dictLimit) ? inputEnd : dictBase + dictLimit;
+ const BYTE* const dictEnd = dictBase + dictLimit;
+ const BYTE* const prefixStart = base + dictLimit;
+ const BYTE* match;
+ U32* smallerPtr = bt + 2*(current&btMask);
+ U32* largerPtr = smallerPtr + 1;
+ U32 matchIndex = *smallerPtr; /* this candidate is unsorted : next sorted candidate is reached through *smallerPtr, while *largerPtr contains previous unsorted candidate (which is already saved and can be overwritten) */
+ U32 dummy32; /* to be nullified at the end */
+ U32 const windowValid = ms->window.lowLimit;
+ U32 const maxDistance = 1U << cParams->windowLog;
+ U32 const windowLow = (current - windowValid > maxDistance) ? current - maxDistance : windowValid;
+
+
+ DEBUGLOG(8, "ZSTD_insertDUBT1(%u) (dictLimit=%u, lowLimit=%u)",
+ current, dictLimit, windowLow);
+ assert(current >= btLow);
+ assert(ip < iend); /* condition for ZSTD_count */
+
+ while (nbCompares-- && (matchIndex > windowLow)) {
+ U32* const nextPtr = bt + 2*(matchIndex & btMask);
+ size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
+ assert(matchIndex < current);
+ /* note : all candidates are now supposed sorted,
+ * but it's still possible to have nextPtr[1] == ZSTD_DUBT_UNSORTED_MARK
+ * when a real index has the same value as ZSTD_DUBT_UNSORTED_MARK */
+
+ if ( (dictMode != ZSTD_extDict)
+ || (matchIndex+matchLength >= dictLimit) /* both in current segment*/
+ || (current < dictLimit) /* both in extDict */) {
+ const BYTE* const mBase = ( (dictMode != ZSTD_extDict)
+ || (matchIndex+matchLength >= dictLimit)) ?
+ base : dictBase;
+ assert( (matchIndex+matchLength >= dictLimit) /* might be wrong if extDict is incorrectly set to 0 */
+ || (current < dictLimit) );
+ match = mBase + matchIndex;
+ matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
+ } else {
+ match = dictBase + matchIndex;
+ matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
+ if (matchIndex+matchLength >= dictLimit)
+ match = base + matchIndex; /* preparation for next read of match[matchLength] */
+ }
+
+ DEBUGLOG(8, "ZSTD_insertDUBT1: comparing %u with %u : found %u common bytes ",
+ current, matchIndex, (U32)matchLength);
+
+ if (ip+matchLength == iend) { /* equal : no way to know if inf or sup */
+ break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt tree */
+ }
+
+ if (match[matchLength] < ip[matchLength]) { /* necessarily within buffer */
+ /* match is smaller than current */
+ *smallerPtr = matchIndex; /* update smaller idx */
+ commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
+ if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop searching */
+ DEBUGLOG(8, "ZSTD_insertDUBT1: %u (>btLow=%u) is smaller : next => %u",
+ matchIndex, btLow, nextPtr[1]);
+ smallerPtr = nextPtr+1; /* new "candidate" => larger than match, which was smaller than target */
+ matchIndex = nextPtr[1]; /* new matchIndex, larger than previous and closer to current */
+ } else {
+ /* match is larger than current */
+ *largerPtr = matchIndex;
+ commonLengthLarger = matchLength;
+ if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop searching */
+ DEBUGLOG(8, "ZSTD_insertDUBT1: %u (>btLow=%u) is larger => %u",
+ matchIndex, btLow, nextPtr[0]);
+ largerPtr = nextPtr;
+ matchIndex = nextPtr[0];
+ } }
+
+ *smallerPtr = *largerPtr = 0;
+}
+
+
+static size_t
+ZSTD_DUBT_findBetterDictMatch (
+ ZSTD_matchState_t* ms,
+ const BYTE* const ip, const BYTE* const iend,
+ size_t* offsetPtr,
+ size_t bestLength,
+ U32 nbCompares,
+ U32 const mls,
+ const ZSTD_dictMode_e dictMode)
+{
+ const ZSTD_matchState_t * const dms = ms->dictMatchState;
+ const ZSTD_compressionParameters* const dmsCParams = &dms->cParams;
+ const U32 * const dictHashTable = dms->hashTable;
+ U32 const hashLog = dmsCParams->hashLog;
+ size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
+ U32 dictMatchIndex = dictHashTable[h];
+
+ const BYTE* const base = ms->window.base;
+ const BYTE* const prefixStart = base + ms->window.dictLimit;
+ U32 const current = (U32)(ip-base);
+ const BYTE* const dictBase = dms->window.base;
+ const BYTE* const dictEnd = dms->window.nextSrc;
+ U32 const dictHighLimit = (U32)(dms->window.nextSrc - dms->window.base);
+ U32 const dictLowLimit = dms->window.lowLimit;
+ U32 const dictIndexDelta = ms->window.lowLimit - dictHighLimit;
+
+ U32* const dictBt = dms->chainTable;
+ U32 const btLog = dmsCParams->chainLog - 1;
+ U32 const btMask = (1 << btLog) - 1;
+ U32 const btLow = (btMask >= dictHighLimit - dictLowLimit) ? dictLowLimit : dictHighLimit - btMask;
+
+ size_t commonLengthSmaller=0, commonLengthLarger=0;
+
+ (void)dictMode;
+ assert(dictMode == ZSTD_dictMatchState);
+
+ while (nbCompares-- && (dictMatchIndex > dictLowLimit)) {
+ U32* const nextPtr = dictBt + 2*(dictMatchIndex & btMask);
+ size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
+ const BYTE* match = dictBase + dictMatchIndex;
+ matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
+ if (dictMatchIndex+matchLength >= dictHighLimit)
+ match = base + dictMatchIndex + dictIndexDelta; /* to prepare for next usage of match[matchLength] */
+
+ if (matchLength > bestLength) {
+ U32 matchIndex = dictMatchIndex + dictIndexDelta;
+ if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) ) {
+ DEBUGLOG(9, "ZSTD_DUBT_findBetterDictMatch(%u) : found better match length %u -> %u and offsetCode %u -> %u (dictMatchIndex %u, matchIndex %u)",
+ current, (U32)bestLength, (U32)matchLength, (U32)*offsetPtr, ZSTD_REP_MOVE + current - matchIndex, dictMatchIndex, matchIndex);
+ bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
+ }
+ if (ip+matchLength == iend) { /* reached end of input : ip[matchLength] is not valid, no way to know if it's larger or smaller than match */
+ break; /* drop, to guarantee consistency (miss a little bit of compression) */
+ }
+ }
+
+ if (match[matchLength] < ip[matchLength]) {
+ if (dictMatchIndex <= btLow) { break; } /* beyond tree size, stop the search */
+ commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
+ dictMatchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
+ } else {
+ /* match is larger than current */
+ if (dictMatchIndex <= btLow) { break; } /* beyond tree size, stop the search */
+ commonLengthLarger = matchLength;
+ dictMatchIndex = nextPtr[0];
+ }
+ }
+
+ if (bestLength >= MINMATCH) {
+ U32 const mIndex = current - ((U32)*offsetPtr - ZSTD_REP_MOVE); (void)mIndex;
+ DEBUGLOG(8, "ZSTD_DUBT_findBetterDictMatch(%u) : found match of length %u and offsetCode %u (pos %u)",
+ current, (U32)bestLength, (U32)*offsetPtr, mIndex);
+ }
+ return bestLength;
+
+}
+
+
+static size_t
+ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms,
+ const BYTE* const ip, const BYTE* const iend,
+ size_t* offsetPtr,
+ U32 const mls,
+ const ZSTD_dictMode_e dictMode)
+{
+ const ZSTD_compressionParameters* const cParams = &ms->cParams;
+ U32* const hashTable = ms->hashTable;
+ U32 const hashLog = cParams->hashLog;
+ size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
+ U32 matchIndex = hashTable[h];
+
+ const BYTE* const base = ms->window.base;
+ U32 const current = (U32)(ip-base);
+ U32 const windowLow = ZSTD_getLowestMatchIndex(ms, current, cParams->windowLog);
+
+ U32* const bt = ms->chainTable;
+ U32 const btLog = cParams->chainLog - 1;
+ U32 const btMask = (1 << btLog) - 1;
+ U32 const btLow = (btMask >= current) ? 0 : current - btMask;
+ U32 const unsortLimit = MAX(btLow, windowLow);
+
+ U32* nextCandidate = bt + 2*(matchIndex&btMask);
+ U32* unsortedMark = bt + 2*(matchIndex&btMask) + 1;
+ U32 nbCompares = 1U << cParams->searchLog;
+ U32 nbCandidates = nbCompares;
+ U32 previousCandidate = 0;
+
+ DEBUGLOG(7, "ZSTD_DUBT_findBestMatch (%u) ", current);
+ assert(ip <= iend-8); /* required for h calculation */
+
+ /* reach end of unsorted candidates list */
+ while ( (matchIndex > unsortLimit)
+ && (*unsortedMark == ZSTD_DUBT_UNSORTED_MARK)
+ && (nbCandidates > 1) ) {
+ DEBUGLOG(8, "ZSTD_DUBT_findBestMatch: candidate %u is unsorted",
+ matchIndex);
+ *unsortedMark = previousCandidate; /* the unsortedMark becomes a reversed chain, to move up back to original position */
+ previousCandidate = matchIndex;
+ matchIndex = *nextCandidate;
+ nextCandidate = bt + 2*(matchIndex&btMask);
+ unsortedMark = bt + 2*(matchIndex&btMask) + 1;
+ nbCandidates --;
+ }
+
+ /* nullify last candidate if it's still unsorted
+ * simplification, detrimental to compression ratio, beneficial for speed */
+ if ( (matchIndex > unsortLimit)
+ && (*unsortedMark==ZSTD_DUBT_UNSORTED_MARK) ) {
+ DEBUGLOG(7, "ZSTD_DUBT_findBestMatch: nullify last unsorted candidate %u",
+ matchIndex);
+ *nextCandidate = *unsortedMark = 0;
+ }
+
+ /* batch sort stacked candidates */
+ matchIndex = previousCandidate;
+ while (matchIndex) { /* will end on matchIndex == 0 */
+ U32* const nextCandidateIdxPtr = bt + 2*(matchIndex&btMask) + 1;
+ U32 const nextCandidateIdx = *nextCandidateIdxPtr;
+ ZSTD_insertDUBT1(ms, matchIndex, iend,
+ nbCandidates, unsortLimit, dictMode);
+ matchIndex = nextCandidateIdx;
+ nbCandidates++;
+ }
+
+ /* find longest match */
+ { size_t commonLengthSmaller = 0, commonLengthLarger = 0;
+ const BYTE* const dictBase = ms->window.dictBase;
+ const U32 dictLimit = ms->window.dictLimit;
+ const BYTE* const dictEnd = dictBase + dictLimit;
+ const BYTE* const prefixStart = base + dictLimit;
+ U32* smallerPtr = bt + 2*(current&btMask);
+ U32* largerPtr = bt + 2*(current&btMask) + 1;
+ U32 matchEndIdx = current + 8 + 1;
+ U32 dummy32; /* to be nullified at the end */
+ size_t bestLength = 0;
+
+ matchIndex = hashTable[h];
+ hashTable[h] = current; /* Update Hash Table */
+
+ while (nbCompares-- && (matchIndex > windowLow)) {
+ U32* const nextPtr = bt + 2*(matchIndex & btMask);
+ size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
+ const BYTE* match;
+
+ if ((dictMode != ZSTD_extDict) || (matchIndex+matchLength >= dictLimit)) {
+ match = base + matchIndex;
+ matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
+ } else {
+ match = dictBase + matchIndex;
+ matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
+ if (matchIndex+matchLength >= dictLimit)
+ match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
+ }
+
+ if (matchLength > bestLength) {
+ if (matchLength > matchEndIdx - matchIndex)
+ matchEndIdx = matchIndex + (U32)matchLength;
+ if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
+ bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
+ if (ip+matchLength == iend) { /* equal : no way to know if inf or sup */
+ if (dictMode == ZSTD_dictMatchState) {
+ nbCompares = 0; /* in addition to avoiding checking any
+ * further in this loop, make sure we
+ * skip checking in the dictionary. */
+ }
+ break; /* drop, to guarantee consistency (miss a little bit of compression) */
+ }
+ }
+
+ if (match[matchLength] < ip[matchLength]) {
+ /* match is smaller than current */
+ *smallerPtr = matchIndex; /* update smaller idx */
+ commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
+ if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
+ smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
+ matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
+ } else {
+ /* match is larger than current */
+ *largerPtr = matchIndex;
+ commonLengthLarger = matchLength;
+ if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
+ largerPtr = nextPtr;
+ matchIndex = nextPtr[0];
+ } }
+
+ *smallerPtr = *largerPtr = 0;
+
+ if (dictMode == ZSTD_dictMatchState && nbCompares) {
+ bestLength = ZSTD_DUBT_findBetterDictMatch(
+ ms, ip, iend,
+ offsetPtr, bestLength, nbCompares,
+ mls, dictMode);
+ }
+
+ assert(matchEndIdx > current+8); /* ensure nextToUpdate is increased */
+ ms->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */
+ if (bestLength >= MINMATCH) {
+ U32 const mIndex = current - ((U32)*offsetPtr - ZSTD_REP_MOVE); (void)mIndex;
+ DEBUGLOG(8, "ZSTD_DUBT_findBestMatch(%u) : found match of length %u and offsetCode %u (pos %u)",
+ current, (U32)bestLength, (U32)*offsetPtr, mIndex);
+ }
+ return bestLength;
+ }
+}
+
+
+/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
+FORCE_INLINE_TEMPLATE size_t
+ZSTD_BtFindBestMatch( ZSTD_matchState_t* ms,
+ const BYTE* const ip, const BYTE* const iLimit,
+ size_t* offsetPtr,
+ const U32 mls /* template */,
+ const ZSTD_dictMode_e dictMode)
+{
+ DEBUGLOG(7, "ZSTD_BtFindBestMatch");
+ if (ip < ms->window.base + ms->nextToUpdate) return 0; /* skipped area */
+ ZSTD_updateDUBT(ms, ip, iLimit, mls);
+ return ZSTD_DUBT_findBestMatch(ms, ip, iLimit, offsetPtr, mls, dictMode);
+}
+
+
+static size_t
+ZSTD_BtFindBestMatch_selectMLS ( ZSTD_matchState_t* ms,
+ const BYTE* ip, const BYTE* const iLimit,
+ size_t* offsetPtr)
+{
+ switch(ms->cParams.minMatch)
+ {
+ default : /* includes case 3 */
+ case 4 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 4, ZSTD_noDict);
+ case 5 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 5, ZSTD_noDict);
+ case 7 :
+ case 6 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 6, ZSTD_noDict);
+ }
+}
+
+
+static size_t ZSTD_BtFindBestMatch_dictMatchState_selectMLS (
+ ZSTD_matchState_t* ms,
+ const BYTE* ip, const BYTE* const iLimit,
+ size_t* offsetPtr)
+{
+ switch(ms->cParams.minMatch)
+ {
+ default : /* includes case 3 */
+ case 4 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 4, ZSTD_dictMatchState);
+ case 5 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 5, ZSTD_dictMatchState);
+ case 7 :
+ case 6 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 6, ZSTD_dictMatchState);
+ }
+}
+
+
+static size_t ZSTD_BtFindBestMatch_extDict_selectMLS (
+ ZSTD_matchState_t* ms,
+ const BYTE* ip, const BYTE* const iLimit,
+ size_t* offsetPtr)
+{
+ switch(ms->cParams.minMatch)
+ {
+ default : /* includes case 3 */
+ case 4 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 4, ZSTD_extDict);
+ case 5 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 5, ZSTD_extDict);
+ case 7 :
+ case 6 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 6, ZSTD_extDict);
+ }
+}
+
+
+
+/* *********************************
+* Hash Chain
+***********************************/
+#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & (mask)]
+
+/* Update chains up to ip (excluded)
+ Assumption : always within prefix (i.e. not within extDict) */
+static U32 ZSTD_insertAndFindFirstIndex_internal(
+ ZSTD_matchState_t* ms,
+ const ZSTD_compressionParameters* const cParams,
+ const BYTE* ip, U32 const mls)
+{
+ U32* const hashTable = ms->hashTable;
+ const U32 hashLog = cParams->hashLog;
+ U32* const chainTable = ms->chainTable;
+ const U32 chainMask = (1 << cParams->chainLog) - 1;
+ const BYTE* const base = ms->window.base;
+ const U32 target = (U32)(ip - base);
+ U32 idx = ms->nextToUpdate;
+
+ while(idx < target) { /* catch up */
+ size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
+ NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
+ hashTable[h] = idx;
+ idx++;
+ }
+
+ ms->nextToUpdate = target;
+ return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
+}
+
+U32 ZSTD_insertAndFindFirstIndex(ZSTD_matchState_t* ms, const BYTE* ip) {
+ const ZSTD_compressionParameters* const cParams = &ms->cParams;
+ return ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, ms->cParams.minMatch);
+}
+
+
+/* inlining is important to hardwire a hot branch (template emulation) */
+FORCE_INLINE_TEMPLATE
+size_t ZSTD_HcFindBestMatch_generic (
+ ZSTD_matchState_t* ms,
+ const BYTE* const ip, const BYTE* const iLimit,
+ size_t* offsetPtr,
+ const U32 mls, const ZSTD_dictMode_e dictMode)
+{
+ const ZSTD_compressionParameters* const cParams = &ms->cParams;
+ U32* const chainTable = ms->chainTable;
+ const U32 chainSize = (1 << cParams->chainLog);
+ const U32 chainMask = chainSize-1;
+ const BYTE* const base = ms->window.base;
+ const BYTE* const dictBase = ms->window.dictBase;
+ const U32 dictLimit = ms->window.dictLimit;
+ const BYTE* const prefixStart = base + dictLimit;
+ const BYTE* const dictEnd = dictBase + dictLimit;
+ const U32 current = (U32)(ip-base);
+ const U32 maxDistance = 1U << cParams->windowLog;
+ const U32 lowestValid = ms->window.lowLimit;
+ const U32 withinMaxDistance = (current - lowestValid > maxDistance) ? current - maxDistance : lowestValid;
+ const U32 isDictionary = (ms->loadedDictEnd != 0);
+ const U32 lowLimit = isDictionary ? lowestValid : withinMaxDistance;
+ const U32 minChain = current > chainSize ? current - chainSize : 0;
+ U32 nbAttempts = 1U << cParams->searchLog;
+ size_t ml=4-1;
+
+ /* HC4 match finder */
+ U32 matchIndex = ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, mls);
+
+ for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
+ size_t currentMl=0;
+ if ((dictMode != ZSTD_extDict) || matchIndex >= dictLimit) {
+ const BYTE* const match = base + matchIndex;
+ assert(matchIndex >= dictLimit); /* ensures this is true if dictMode != ZSTD_extDict */
+ if (match[ml] == ip[ml]) /* potentially better */
+ currentMl = ZSTD_count(ip, match, iLimit);
+ } else {
+ const BYTE* const match = dictBase + matchIndex;
+ assert(match+4 <= dictEnd);
+ if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
+ currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dictEnd, prefixStart) + 4;
+ }
+
+ /* save best solution */
+ if (currentMl > ml) {
+ ml = currentMl;
+ *offsetPtr = current - matchIndex + ZSTD_REP_MOVE;
+ if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */
+ }
+
+ if (matchIndex <= minChain) break;
+ matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
+ }
+
+ if (dictMode == ZSTD_dictMatchState) {
+ const ZSTD_matchState_t* const dms = ms->dictMatchState;
+ const U32* const dmsChainTable = dms->chainTable;
+ const U32 dmsChainSize = (1 << dms->cParams.chainLog);
+ const U32 dmsChainMask = dmsChainSize - 1;
+ const U32 dmsLowestIndex = dms->window.dictLimit;
+ const BYTE* const dmsBase = dms->window.base;
+ const BYTE* const dmsEnd = dms->window.nextSrc;
+ const U32 dmsSize = (U32)(dmsEnd - dmsBase);
+ const U32 dmsIndexDelta = dictLimit - dmsSize;
+ const U32 dmsMinChain = dmsSize > dmsChainSize ? dmsSize - dmsChainSize : 0;
+
+ matchIndex = dms->hashTable[ZSTD_hashPtr(ip, dms->cParams.hashLog, mls)];
+
+ for ( ; (matchIndex>dmsLowestIndex) & (nbAttempts>0) ; nbAttempts--) {
+ size_t currentMl=0;
+ const BYTE* const match = dmsBase + matchIndex;
+ assert(match+4 <= dmsEnd);
+ if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
+ currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dmsEnd, prefixStart) + 4;
+
+ /* save best solution */
+ if (currentMl > ml) {
+ ml = currentMl;
+ *offsetPtr = current - (matchIndex + dmsIndexDelta) + ZSTD_REP_MOVE;
+ if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */
+ }
+
+ if (matchIndex <= dmsMinChain) break;
+ matchIndex = dmsChainTable[matchIndex & dmsChainMask];
+ }
+ }
+
+ return ml;
+}
+
+
+FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_selectMLS (
+ ZSTD_matchState_t* ms,
+ const BYTE* ip, const BYTE* const iLimit,
+ size_t* offsetPtr)
+{
+ switch(ms->cParams.minMatch)
+ {
+ default : /* includes case 3 */
+ case 4 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 4, ZSTD_noDict);
+ case 5 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 5, ZSTD_noDict);
+ case 7 :
+ case 6 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 6, ZSTD_noDict);
+ }
+}
+
+
+static size_t ZSTD_HcFindBestMatch_dictMatchState_selectMLS (
+ ZSTD_matchState_t* ms,
+ const BYTE* ip, const BYTE* const iLimit,
+ size_t* offsetPtr)
+{
+ switch(ms->cParams.minMatch)
+ {
+ default : /* includes case 3 */
+ case 4 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 4, ZSTD_dictMatchState);
+ case 5 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 5, ZSTD_dictMatchState);
+ case 7 :
+ case 6 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 6, ZSTD_dictMatchState);
+ }
+}
+
+
+FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
+ ZSTD_matchState_t* ms,
+ const BYTE* ip, const BYTE* const iLimit,
+ size_t* offsetPtr)
+{
+ switch(ms->cParams.minMatch)
+ {
+ default : /* includes case 3 */
+ case 4 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 4, ZSTD_extDict);
+ case 5 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 5, ZSTD_extDict);
+ case 7 :
+ case 6 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 6, ZSTD_extDict);
+ }
+}
+
+
+/* *******************************
+* Common parser - lazy strategy
+*********************************/
+typedef enum { search_hashChain, search_binaryTree } searchMethod_e;
+
+FORCE_INLINE_TEMPLATE size_t
+ZSTD_compressBlock_lazy_generic(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore,
+ U32 rep[ZSTD_REP_NUM],
+ const void* src, size_t srcSize,
+ const searchMethod_e searchMethod, const U32 depth,
+ ZSTD_dictMode_e const dictMode)
+{
+ const BYTE* const istart = (const BYTE*)src;
+ const BYTE* ip = istart;
+ const BYTE* anchor = istart;
+ const BYTE* const iend = istart + srcSize;
+ const BYTE* const ilimit = iend - 8;
+ const BYTE* const base = ms->window.base;
+ const U32 prefixLowestIndex = ms->window.dictLimit;
+ const BYTE* const prefixLowest = base + prefixLowestIndex;
+
+ typedef size_t (*searchMax_f)(
+ ZSTD_matchState_t* ms,
+ const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr);
+ searchMax_f const searchMax = dictMode == ZSTD_dictMatchState ?
+ (searchMethod==search_binaryTree ? ZSTD_BtFindBestMatch_dictMatchState_selectMLS
+ : ZSTD_HcFindBestMatch_dictMatchState_selectMLS) :
+ (searchMethod==search_binaryTree ? ZSTD_BtFindBestMatch_selectMLS
+ : ZSTD_HcFindBestMatch_selectMLS);
+ U32 offset_1 = rep[0], offset_2 = rep[1], savedOffset=0;
+
+ const ZSTD_matchState_t* const dms = ms->dictMatchState;
+ const U32 dictLowestIndex = dictMode == ZSTD_dictMatchState ?
+ dms->window.dictLimit : 0;
+ const BYTE* const dictBase = dictMode == ZSTD_dictMatchState ?
+ dms->window.base : NULL;
+ const BYTE* const dictLowest = dictMode == ZSTD_dictMatchState ?
+ dictBase + dictLowestIndex : NULL;
+ const BYTE* const dictEnd = dictMode == ZSTD_dictMatchState ?
+ dms->window.nextSrc : NULL;
+ const U32 dictIndexDelta = dictMode == ZSTD_dictMatchState ?
+ prefixLowestIndex - (U32)(dictEnd - dictBase) :
+ 0;
+ const U32 dictAndPrefixLength = (U32)((ip - prefixLowest) + (dictEnd - dictLowest));
+
+ DEBUGLOG(5, "ZSTD_compressBlock_lazy_generic (dictMode=%u)", (U32)dictMode);
+
+ /* init */
+ ip += (dictAndPrefixLength == 0);
+ if (dictMode == ZSTD_noDict) {
+ U32 const current = (U32)(ip - base);
+ U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, current, ms->cParams.windowLog);
+ U32 const maxRep = current - windowLow;
+ if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
+ if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
+ }
+ if (dictMode == ZSTD_dictMatchState) {
+ /* dictMatchState repCode checks don't currently handle repCode == 0
+ * disabling. */
+ assert(offset_1 <= dictAndPrefixLength);
+ assert(offset_2 <= dictAndPrefixLength);
+ }
+
+ /* Match Loop */
+#if defined(__GNUC__) && defined(__x86_64__)
+ /* I've measured random a 5% speed loss on levels 5 & 6 (greedy) when the
+ * code alignment is perturbed. To fix the instability align the loop on 32-bytes.
+ */
+ __asm__(".p2align 5");
+#endif
+ while (ip < ilimit) {
+ size_t matchLength=0;
+ size_t offset=0;
+ const BYTE* start=ip+1;
+
+ /* check repCode */
+ if (dictMode == ZSTD_dictMatchState) {
+ const U32 repIndex = (U32)(ip - base) + 1 - offset_1;
+ const BYTE* repMatch = (dictMode == ZSTD_dictMatchState
+ && repIndex < prefixLowestIndex) ?
+ dictBase + (repIndex - dictIndexDelta) :
+ base + repIndex;
+ if (((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */)
+ && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
+ const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend;
+ matchLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4;
+ if (depth==0) goto _storeSequence;
+ }
+ }
+ if ( dictMode == ZSTD_noDict
+ && ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)))) {
+ matchLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
+ if (depth==0) goto _storeSequence;
+ }
+
+ /* first search (depth 0) */
+ { size_t offsetFound = 999999999;
+ size_t const ml2 = searchMax(ms, ip, iend, &offsetFound);
+ if (ml2 > matchLength)
+ matchLength = ml2, start = ip, offset=offsetFound;
+ }
+
+ if (matchLength < 4) {
+ ip += ((ip-anchor) >> kSearchStrength) + 1; /* jump faster over incompressible sections */
+ continue;
+ }
+
+ /* let's try to find a better solution */
+ if (depth>=1)
+ while (ip<ilimit) {
+ ip ++;
+ if ( (dictMode == ZSTD_noDict)
+ && (offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
+ size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
+ int const gain2 = (int)(mlRep * 3);
+ int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
+ if ((mlRep >= 4) && (gain2 > gain1))
+ matchLength = mlRep, offset = 0, start = ip;
+ }
+ if (dictMode == ZSTD_dictMatchState) {
+ const U32 repIndex = (U32)(ip - base) - offset_1;
+ const BYTE* repMatch = repIndex < prefixLowestIndex ?
+ dictBase + (repIndex - dictIndexDelta) :
+ base + repIndex;
+ if (((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */)
+ && (MEM_read32(repMatch) == MEM_read32(ip)) ) {
+ const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend;
+ size_t const mlRep = ZSTD_count_2segments(ip+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4;
+ int const gain2 = (int)(mlRep * 3);
+ int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
+ if ((mlRep >= 4) && (gain2 > gain1))
+ matchLength = mlRep, offset = 0, start = ip;
+ }
+ }
+ { size_t offset2=999999999;
+ size_t const ml2 = searchMax(ms, ip, iend, &offset2);
+ int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
+ int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
+ if ((ml2 >= 4) && (gain2 > gain1)) {
+ matchLength = ml2, offset = offset2, start = ip;
+ continue; /* search a better one */
+ } }
+
+ /* let's find an even better one */
+ if ((depth==2) && (ip<ilimit)) {
+ ip ++;
+ if ( (dictMode == ZSTD_noDict)
+ && (offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
+ size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
+ int const gain2 = (int)(mlRep * 4);
+ int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
+ if ((mlRep >= 4) && (gain2 > gain1))
+ matchLength = mlRep, offset = 0, start = ip;
+ }
+ if (dictMode == ZSTD_dictMatchState) {
+ const U32 repIndex = (U32)(ip - base) - offset_1;
+ const BYTE* repMatch = repIndex < prefixLowestIndex ?
+ dictBase + (repIndex - dictIndexDelta) :
+ base + repIndex;
+ if (((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */)
+ && (MEM_read32(repMatch) == MEM_read32(ip)) ) {
+ const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend;
+ size_t const mlRep = ZSTD_count_2segments(ip+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4;
+ int const gain2 = (int)(mlRep * 4);
+ int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
+ if ((mlRep >= 4) && (gain2 > gain1))
+ matchLength = mlRep, offset = 0, start = ip;
+ }
+ }
+ { size_t offset2=999999999;
+ size_t const ml2 = searchMax(ms, ip, iend, &offset2);
+ int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
+ int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
+ if ((ml2 >= 4) && (gain2 > gain1)) {
+ matchLength = ml2, offset = offset2, start = ip;
+ continue;
+ } } }
+ break; /* nothing found : store previous solution */
+ }
+
+ /* NOTE:
+ * start[-offset+ZSTD_REP_MOVE-1] is undefined behavior.
+ * (-offset+ZSTD_REP_MOVE-1) is unsigned, and is added to start, which
+ * overflows the pointer, which is undefined behavior.
+ */
+ /* catch up */
+ if (offset) {
+ if (dictMode == ZSTD_noDict) {
+ while ( ((start > anchor) & (start - (offset-ZSTD_REP_MOVE) > prefixLowest))
+ && (start[-1] == (start-(offset-ZSTD_REP_MOVE))[-1]) ) /* only search for offset within prefix */
+ { start--; matchLength++; }
+ }
+ if (dictMode == ZSTD_dictMatchState) {
+ U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
+ const BYTE* match = (matchIndex < prefixLowestIndex) ? dictBase + matchIndex - dictIndexDelta : base + matchIndex;
+ const BYTE* const mStart = (matchIndex < prefixLowestIndex) ? dictLowest : prefixLowest;
+ while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
+ }
+ offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
+ }
+ /* store sequence */
+_storeSequence:
+ { size_t const litLength = start - anchor;
+ ZSTD_storeSeq(seqStore, litLength, anchor, iend, (U32)offset, matchLength-MINMATCH);
+ anchor = ip = start + matchLength;
+ }
+
+ /* check immediate repcode */
+ if (dictMode == ZSTD_dictMatchState) {
+ while (ip <= ilimit) {
+ U32 const current2 = (U32)(ip-base);
+ U32 const repIndex = current2 - offset_2;
+ const BYTE* repMatch = dictMode == ZSTD_dictMatchState
+ && repIndex < prefixLowestIndex ?
+ dictBase - dictIndexDelta + repIndex :
+ base + repIndex;
+ if ( ((U32)((prefixLowestIndex-1) - (U32)repIndex) >= 3 /* intentional overflow */)
+ && (MEM_read32(repMatch) == MEM_read32(ip)) ) {
+ const BYTE* const repEnd2 = repIndex < prefixLowestIndex ? dictEnd : iend;
+ matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd2, prefixLowest) + 4;
+ offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset_2 <=> offset_1 */
+ ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, matchLength-MINMATCH);
+ ip += matchLength;
+ anchor = ip;
+ continue;
+ }
+ break;
+ }
+ }
+
+ if (dictMode == ZSTD_noDict) {
+ while ( ((ip <= ilimit) & (offset_2>0))
+ && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) {
+ /* store sequence */
+ matchLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
+ offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
+ ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, matchLength-MINMATCH);
+ ip += matchLength;
+ anchor = ip;
+ continue; /* faster when present ... (?) */
+ } } }
+
+ /* Save reps for next block */
+ rep[0] = offset_1 ? offset_1 : savedOffset;
+ rep[1] = offset_2 ? offset_2 : savedOffset;
+
+ /* Return the last literals size */
+ return (size_t)(iend - anchor);
+}
+
+
+size_t ZSTD_compressBlock_btlazy2(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_binaryTree, 2, ZSTD_noDict);
+}
+
+size_t ZSTD_compressBlock_lazy2(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 2, ZSTD_noDict);
+}
+
+size_t ZSTD_compressBlock_lazy(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 1, ZSTD_noDict);
+}
+
+size_t ZSTD_compressBlock_greedy(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 0, ZSTD_noDict);
+}
+
+size_t ZSTD_compressBlock_btlazy2_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_binaryTree, 2, ZSTD_dictMatchState);
+}
+
+size_t ZSTD_compressBlock_lazy2_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 2, ZSTD_dictMatchState);
+}
+
+size_t ZSTD_compressBlock_lazy_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 1, ZSTD_dictMatchState);
+}
+
+size_t ZSTD_compressBlock_greedy_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 0, ZSTD_dictMatchState);
+}
+
+
+FORCE_INLINE_TEMPLATE
+size_t ZSTD_compressBlock_lazy_extDict_generic(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore,
+ U32 rep[ZSTD_REP_NUM],
+ const void* src, size_t srcSize,
+ const searchMethod_e searchMethod, const U32 depth)
+{
+ const BYTE* const istart = (const BYTE*)src;
+ const BYTE* ip = istart;
+ const BYTE* anchor = istart;
+ const BYTE* const iend = istart + srcSize;
+ const BYTE* const ilimit = iend - 8;
+ const BYTE* const base = ms->window.base;
+ const U32 dictLimit = ms->window.dictLimit;
+ const BYTE* const prefixStart = base + dictLimit;
+ const BYTE* const dictBase = ms->window.dictBase;
+ const BYTE* const dictEnd = dictBase + dictLimit;
+ const BYTE* const dictStart = dictBase + ms->window.lowLimit;
+ const U32 windowLog = ms->cParams.windowLog;
+
+ typedef size_t (*searchMax_f)(
+ ZSTD_matchState_t* ms,
+ const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr);
+ searchMax_f searchMax = searchMethod==search_binaryTree ? ZSTD_BtFindBestMatch_extDict_selectMLS : ZSTD_HcFindBestMatch_extDict_selectMLS;
+
+ U32 offset_1 = rep[0], offset_2 = rep[1];
+
+ DEBUGLOG(5, "ZSTD_compressBlock_lazy_extDict_generic");
+
+ /* init */
+ ip += (ip == prefixStart);
+
+ /* Match Loop */
+#if defined(__GNUC__) && defined(__x86_64__)
+ /* I've measured random a 5% speed loss on levels 5 & 6 (greedy) when the
+ * code alignment is perturbed. To fix the instability align the loop on 32-bytes.
+ */
+ __asm__(".p2align 5");
+#endif
+ while (ip < ilimit) {
+ size_t matchLength=0;
+ size_t offset=0;
+ const BYTE* start=ip+1;
+ U32 current = (U32)(ip-base);
+
+ /* check repCode */
+ { const U32 windowLow = ZSTD_getLowestMatchIndex(ms, current+1, windowLog);
+ const U32 repIndex = (U32)(current+1 - offset_1);
+ const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
+ const BYTE* const repMatch = repBase + repIndex;
+ if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > windowLow)) /* intentional overflow */
+ if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
+ /* repcode detected we should take it */
+ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
+ matchLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repEnd, prefixStart) + 4;
+ if (depth==0) goto _storeSequence;
+ } }
+
+ /* first search (depth 0) */
+ { size_t offsetFound = 999999999;
+ size_t const ml2 = searchMax(ms, ip, iend, &offsetFound);
+ if (ml2 > matchLength)
+ matchLength = ml2, start = ip, offset=offsetFound;
+ }
+
+ if (matchLength < 4) {
+ ip += ((ip-anchor) >> kSearchStrength) + 1; /* jump faster over incompressible sections */
+ continue;
+ }
+
+ /* let's try to find a better solution */
+ if (depth>=1)
+ while (ip<ilimit) {
+ ip ++;
+ current++;
+ /* check repCode */
+ if (offset) {
+ const U32 windowLow = ZSTD_getLowestMatchIndex(ms, current, windowLog);
+ const U32 repIndex = (U32)(current - offset_1);
+ const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
+ const BYTE* const repMatch = repBase + repIndex;
+ if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > windowLow)) /* intentional overflow */
+ if (MEM_read32(ip) == MEM_read32(repMatch)) {
+ /* repcode detected */
+ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
+ size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
+ int const gain2 = (int)(repLength * 3);
+ int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
+ if ((repLength >= 4) && (gain2 > gain1))
+ matchLength = repLength, offset = 0, start = ip;
+ } }
+
+ /* search match, depth 1 */
+ { size_t offset2=999999999;
+ size_t const ml2 = searchMax(ms, ip, iend, &offset2);
+ int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
+ int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
+ if ((ml2 >= 4) && (gain2 > gain1)) {
+ matchLength = ml2, offset = offset2, start = ip;
+ continue; /* search a better one */
+ } }
+
+ /* let's find an even better one */
+ if ((depth==2) && (ip<ilimit)) {
+ ip ++;
+ current++;
+ /* check repCode */
+ if (offset) {
+ const U32 windowLow = ZSTD_getLowestMatchIndex(ms, current, windowLog);
+ const U32 repIndex = (U32)(current - offset_1);
+ const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
+ const BYTE* const repMatch = repBase + repIndex;
+ if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > windowLow)) /* intentional overflow */
+ if (MEM_read32(ip) == MEM_read32(repMatch)) {
+ /* repcode detected */
+ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
+ size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
+ int const gain2 = (int)(repLength * 4);
+ int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
+ if ((repLength >= 4) && (gain2 > gain1))
+ matchLength = repLength, offset = 0, start = ip;
+ } }
+
+ /* search match, depth 2 */
+ { size_t offset2=999999999;
+ size_t const ml2 = searchMax(ms, ip, iend, &offset2);
+ int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
+ int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
+ if ((ml2 >= 4) && (gain2 > gain1)) {
+ matchLength = ml2, offset = offset2, start = ip;
+ continue;
+ } } }
+ break; /* nothing found : store previous solution */
+ }
+
+ /* catch up */
+ if (offset) {
+ U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
+ const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
+ const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
+ while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
+ offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
+ }
+
+ /* store sequence */
+_storeSequence:
+ { size_t const litLength = start - anchor;
+ ZSTD_storeSeq(seqStore, litLength, anchor, iend, (U32)offset, matchLength-MINMATCH);
+ anchor = ip = start + matchLength;
+ }
+
+ /* check immediate repcode */
+ while (ip <= ilimit) {
+ const U32 repCurrent = (U32)(ip-base);
+ const U32 windowLow = ZSTD_getLowestMatchIndex(ms, repCurrent, windowLog);
+ const U32 repIndex = repCurrent - offset_2;
+ const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
+ const BYTE* const repMatch = repBase + repIndex;
+ if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > windowLow)) /* intentional overflow */
+ if (MEM_read32(ip) == MEM_read32(repMatch)) {
+ /* repcode detected we should take it */
+ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
+ matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
+ offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset history */
+ ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, matchLength-MINMATCH);
+ ip += matchLength;
+ anchor = ip;
+ continue; /* faster when present ... (?) */
+ }
+ break;
+ } }
+
+ /* Save reps for next block */
+ rep[0] = offset_1;
+ rep[1] = offset_2;
+
+ /* Return the last literals size */
+ return (size_t)(iend - anchor);
+}
+
+
+size_t ZSTD_compressBlock_greedy_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 0);
+}
+
+size_t ZSTD_compressBlock_lazy_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+
+{
+ return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 1);
+}
+
+size_t ZSTD_compressBlock_lazy2_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+
+{
+ return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 2);
+}
+
+size_t ZSTD_compressBlock_btlazy2_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+
+{
+ return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_binaryTree, 2);
+}
diff --git a/sys/contrib/openzfs/module/zstd/lib/compress/zstd_lazy.h b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_lazy.h
new file mode 100644
index 000000000000..581936f03bd4
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_lazy.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_LAZY_H
+#define ZSTD_LAZY_H
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#include "zstd_compress_internal.h"
+
+U32 ZSTD_insertAndFindFirstIndex(ZSTD_matchState_t* ms, const BYTE* ip);
+
+void ZSTD_preserveUnsortedMark (U32* const table, U32 const size, U32 const reducerValue); /*! used in ZSTD_reduceIndex(). preemptively increase value of ZSTD_DUBT_UNSORTED_MARK */
+
+size_t ZSTD_compressBlock_btlazy2(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy2(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_greedy(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+
+size_t ZSTD_compressBlock_btlazy2_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy2_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_greedy_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+
+size_t ZSTD_compressBlock_greedy_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy2_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_btlazy2_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* ZSTD_LAZY_H */
diff --git a/sys/contrib/openzfs/module/zstd/lib/compress/zstd_ldm.c b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_ldm.c
new file mode 100644
index 000000000000..8c479483581c
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_ldm.c
@@ -0,0 +1,619 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#include "zstd_ldm.h"
+
+#include "../common/debug.h"
+#include "zstd_fast.h" /* ZSTD_fillHashTable() */
+#include "zstd_double_fast.h" /* ZSTD_fillDoubleHashTable() */
+
+#define LDM_BUCKET_SIZE_LOG 3
+#define LDM_MIN_MATCH_LENGTH 64
+#define LDM_HASH_RLOG 7
+#define LDM_HASH_CHAR_OFFSET 10
+
+void ZSTD_ldm_adjustParameters(ldmParams_t* params,
+ ZSTD_compressionParameters const* cParams)
+{
+ params->windowLog = cParams->windowLog;
+ ZSTD_STATIC_ASSERT(LDM_BUCKET_SIZE_LOG <= ZSTD_LDM_BUCKETSIZELOG_MAX);
+ DEBUGLOG(4, "ZSTD_ldm_adjustParameters");
+ if (!params->bucketSizeLog) params->bucketSizeLog = LDM_BUCKET_SIZE_LOG;
+ if (!params->minMatchLength) params->minMatchLength = LDM_MIN_MATCH_LENGTH;
+ if (cParams->strategy >= ZSTD_btopt) {
+ /* Get out of the way of the optimal parser */
+ U32 const minMatch = MAX(cParams->targetLength, params->minMatchLength);
+ assert(minMatch >= ZSTD_LDM_MINMATCH_MIN);
+ assert(minMatch <= ZSTD_LDM_MINMATCH_MAX);
+ params->minMatchLength = minMatch;
+ }
+ if (params->hashLog == 0) {
+ params->hashLog = MAX(ZSTD_HASHLOG_MIN, params->windowLog - LDM_HASH_RLOG);
+ assert(params->hashLog <= ZSTD_HASHLOG_MAX);
+ }
+ if (params->hashRateLog == 0) {
+ params->hashRateLog = params->windowLog < params->hashLog
+ ? 0
+ : params->windowLog - params->hashLog;
+ }
+ params->bucketSizeLog = MIN(params->bucketSizeLog, params->hashLog);
+}
+
+size_t ZSTD_ldm_getTableSize(ldmParams_t params)
+{
+ size_t const ldmHSize = ((size_t)1) << params.hashLog;
+ size_t const ldmBucketSizeLog = MIN(params.bucketSizeLog, params.hashLog);
+ size_t const ldmBucketSize = ((size_t)1) << (params.hashLog - ldmBucketSizeLog);
+ size_t const totalSize = ZSTD_cwksp_alloc_size(ldmBucketSize)
+ + ZSTD_cwksp_alloc_size(ldmHSize * sizeof(ldmEntry_t));
+ return params.enableLdm ? totalSize : 0;
+}
+
+size_t ZSTD_ldm_getMaxNbSeq(ldmParams_t params, size_t maxChunkSize)
+{
+ return params.enableLdm ? (maxChunkSize / params.minMatchLength) : 0;
+}
+
+/** ZSTD_ldm_getSmallHash() :
+ * numBits should be <= 32
+ * If numBits==0, returns 0.
+ * @return : the most significant numBits of value. */
+static U32 ZSTD_ldm_getSmallHash(U64 value, U32 numBits)
+{
+ assert(numBits <= 32);
+ return numBits == 0 ? 0 : (U32)(value >> (64 - numBits));
+}
+
+/** ZSTD_ldm_getChecksum() :
+ * numBitsToDiscard should be <= 32
+ * @return : the next most significant 32 bits after numBitsToDiscard */
+static U32 ZSTD_ldm_getChecksum(U64 hash, U32 numBitsToDiscard)
+{
+ assert(numBitsToDiscard <= 32);
+ return (hash >> (64 - 32 - numBitsToDiscard)) & 0xFFFFFFFF;
+}
+
+/** ZSTD_ldm_getTag() ;
+ * Given the hash, returns the most significant numTagBits bits
+ * after (32 + hbits) bits.
+ *
+ * If there are not enough bits remaining, return the last
+ * numTagBits bits. */
+static U32 ZSTD_ldm_getTag(U64 hash, U32 hbits, U32 numTagBits)
+{
+ assert(numTagBits < 32 && hbits <= 32);
+ if (32 - hbits < numTagBits) {
+ return hash & (((U32)1 << numTagBits) - 1);
+ } else {
+ return (hash >> (32 - hbits - numTagBits)) & (((U32)1 << numTagBits) - 1);
+ }
+}
+
+/** ZSTD_ldm_getBucket() :
+ * Returns a pointer to the start of the bucket associated with hash. */
+static ldmEntry_t* ZSTD_ldm_getBucket(
+ ldmState_t* ldmState, size_t hash, ldmParams_t const ldmParams)
+{
+ return ldmState->hashTable + (hash << ldmParams.bucketSizeLog);
+}
+
+/** ZSTD_ldm_insertEntry() :
+ * Insert the entry with corresponding hash into the hash table */
+static void ZSTD_ldm_insertEntry(ldmState_t* ldmState,
+ size_t const hash, const ldmEntry_t entry,
+ ldmParams_t const ldmParams)
+{
+ BYTE* const bucketOffsets = ldmState->bucketOffsets;
+ *(ZSTD_ldm_getBucket(ldmState, hash, ldmParams) + bucketOffsets[hash]) = entry;
+ bucketOffsets[hash]++;
+ bucketOffsets[hash] &= ((U32)1 << ldmParams.bucketSizeLog) - 1;
+}
+
+/** ZSTD_ldm_makeEntryAndInsertByTag() :
+ *
+ * Gets the small hash, checksum, and tag from the rollingHash.
+ *
+ * If the tag matches (1 << ldmParams.hashRateLog)-1, then
+ * creates an ldmEntry from the offset, and inserts it into the hash table.
+ *
+ * hBits is the length of the small hash, which is the most significant hBits
+ * of rollingHash. The checksum is the next 32 most significant bits, followed
+ * by ldmParams.hashRateLog bits that make up the tag. */
+static void ZSTD_ldm_makeEntryAndInsertByTag(ldmState_t* ldmState,
+ U64 const rollingHash,
+ U32 const hBits,
+ U32 const offset,
+ ldmParams_t const ldmParams)
+{
+ U32 const tag = ZSTD_ldm_getTag(rollingHash, hBits, ldmParams.hashRateLog);
+ U32 const tagMask = ((U32)1 << ldmParams.hashRateLog) - 1;
+ if (tag == tagMask) {
+ U32 const hash = ZSTD_ldm_getSmallHash(rollingHash, hBits);
+ U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits);
+ ldmEntry_t entry;
+ entry.offset = offset;
+ entry.checksum = checksum;
+ ZSTD_ldm_insertEntry(ldmState, hash, entry, ldmParams);
+ }
+}
+
+/** ZSTD_ldm_countBackwardsMatch() :
+ * Returns the number of bytes that match backwards before pIn and pMatch.
+ *
+ * We count only bytes where pMatch >= pBase and pIn >= pAnchor. */
+static size_t ZSTD_ldm_countBackwardsMatch(
+ const BYTE* pIn, const BYTE* pAnchor,
+ const BYTE* pMatch, const BYTE* pBase)
+{
+ size_t matchLength = 0;
+ while (pIn > pAnchor && pMatch > pBase && pIn[-1] == pMatch[-1]) {
+ pIn--;
+ pMatch--;
+ matchLength++;
+ }
+ return matchLength;
+}
+
+/** ZSTD_ldm_fillFastTables() :
+ *
+ * Fills the relevant tables for the ZSTD_fast and ZSTD_dfast strategies.
+ * This is similar to ZSTD_loadDictionaryContent.
+ *
+ * The tables for the other strategies are filled within their
+ * block compressors. */
+static size_t ZSTD_ldm_fillFastTables(ZSTD_matchState_t* ms,
+ void const* end)
+{
+ const BYTE* const iend = (const BYTE*)end;
+
+ switch(ms->cParams.strategy)
+ {
+ case ZSTD_fast:
+ ZSTD_fillHashTable(ms, iend, ZSTD_dtlm_fast);
+ break;
+
+ case ZSTD_dfast:
+ ZSTD_fillDoubleHashTable(ms, iend, ZSTD_dtlm_fast);
+ break;
+
+ case ZSTD_greedy:
+ case ZSTD_lazy:
+ case ZSTD_lazy2:
+ case ZSTD_btlazy2:
+ case ZSTD_btopt:
+ case ZSTD_btultra:
+ case ZSTD_btultra2:
+ break;
+ default:
+ assert(0); /* not possible : not a valid strategy id */
+ }
+
+ return 0;
+}
+
+/** ZSTD_ldm_fillLdmHashTable() :
+ *
+ * Fills hashTable from (lastHashed + 1) to iend (non-inclusive).
+ * lastHash is the rolling hash that corresponds to lastHashed.
+ *
+ * Returns the rolling hash corresponding to position iend-1. */
+static U64 ZSTD_ldm_fillLdmHashTable(ldmState_t* state,
+ U64 lastHash, const BYTE* lastHashed,
+ const BYTE* iend, const BYTE* base,
+ U32 hBits, ldmParams_t const ldmParams)
+{
+ U64 rollingHash = lastHash;
+ const BYTE* cur = lastHashed + 1;
+
+ while (cur < iend) {
+ rollingHash = ZSTD_rollingHash_rotate(rollingHash, cur[-1],
+ cur[ldmParams.minMatchLength-1],
+ state->hashPower);
+ ZSTD_ldm_makeEntryAndInsertByTag(state,
+ rollingHash, hBits,
+ (U32)(cur - base), ldmParams);
+ ++cur;
+ }
+ return rollingHash;
+}
+
+void ZSTD_ldm_fillHashTable(
+ ldmState_t* state, const BYTE* ip,
+ const BYTE* iend, ldmParams_t const* params)
+{
+ DEBUGLOG(5, "ZSTD_ldm_fillHashTable");
+ if ((size_t)(iend - ip) >= params->minMatchLength) {
+ U64 startingHash = ZSTD_rollingHash_compute(ip, params->minMatchLength);
+ ZSTD_ldm_fillLdmHashTable(
+ state, startingHash, ip, iend - params->minMatchLength, state->window.base,
+ params->hashLog - params->bucketSizeLog,
+ *params);
+ }
+}
+
+
+/** ZSTD_ldm_limitTableUpdate() :
+ *
+ * Sets cctx->nextToUpdate to a position corresponding closer to anchor
+ * if it is far way
+ * (after a long match, only update tables a limited amount). */
+static void ZSTD_ldm_limitTableUpdate(ZSTD_matchState_t* ms, const BYTE* anchor)
+{
+ U32 const current = (U32)(anchor - ms->window.base);
+ if (current > ms->nextToUpdate + 1024) {
+ ms->nextToUpdate =
+ current - MIN(512, current - ms->nextToUpdate - 1024);
+ }
+}
+
+static size_t ZSTD_ldm_generateSequences_internal(
+ ldmState_t* ldmState, rawSeqStore_t* rawSeqStore,
+ ldmParams_t const* params, void const* src, size_t srcSize)
+{
+ /* LDM parameters */
+ int const extDict = ZSTD_window_hasExtDict(ldmState->window);
+ U32 const minMatchLength = params->minMatchLength;
+ U64 const hashPower = ldmState->hashPower;
+ U32 const hBits = params->hashLog - params->bucketSizeLog;
+ U32 const ldmBucketSize = 1U << params->bucketSizeLog;
+ U32 const hashRateLog = params->hashRateLog;
+ U32 const ldmTagMask = (1U << params->hashRateLog) - 1;
+ /* Prefix and extDict parameters */
+ U32 const dictLimit = ldmState->window.dictLimit;
+ U32 const lowestIndex = extDict ? ldmState->window.lowLimit : dictLimit;
+ BYTE const* const base = ldmState->window.base;
+ BYTE const* const dictBase = extDict ? ldmState->window.dictBase : NULL;
+ BYTE const* const dictStart = extDict ? dictBase + lowestIndex : NULL;
+ BYTE const* const dictEnd = extDict ? dictBase + dictLimit : NULL;
+ BYTE const* const lowPrefixPtr = base + dictLimit;
+ /* Input bounds */
+ BYTE const* const istart = (BYTE const*)src;
+ BYTE const* const iend = istart + srcSize;
+ BYTE const* const ilimit = iend - MAX(minMatchLength, HASH_READ_SIZE);
+ /* Input positions */
+ BYTE const* anchor = istart;
+ BYTE const* ip = istart;
+ /* Rolling hash */
+ BYTE const* lastHashed = NULL;
+ U64 rollingHash = 0;
+
+ while (ip <= ilimit) {
+ size_t mLength;
+ U32 const current = (U32)(ip - base);
+ size_t forwardMatchLength = 0, backwardMatchLength = 0;
+ ldmEntry_t* bestEntry = NULL;
+ if (ip != istart) {
+ rollingHash = ZSTD_rollingHash_rotate(rollingHash, lastHashed[0],
+ lastHashed[minMatchLength],
+ hashPower);
+ } else {
+ rollingHash = ZSTD_rollingHash_compute(ip, minMatchLength);
+ }
+ lastHashed = ip;
+
+ /* Do not insert and do not look for a match */
+ if (ZSTD_ldm_getTag(rollingHash, hBits, hashRateLog) != ldmTagMask) {
+ ip++;
+ continue;
+ }
+
+ /* Get the best entry and compute the match lengths */
+ {
+ ldmEntry_t* const bucket =
+ ZSTD_ldm_getBucket(ldmState,
+ ZSTD_ldm_getSmallHash(rollingHash, hBits),
+ *params);
+ ldmEntry_t* cur;
+ size_t bestMatchLength = 0;
+ U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits);
+
+ for (cur = bucket; cur < bucket + ldmBucketSize; ++cur) {
+ size_t curForwardMatchLength, curBackwardMatchLength,
+ curTotalMatchLength;
+ if (cur->checksum != checksum || cur->offset <= lowestIndex) {
+ continue;
+ }
+ if (extDict) {
+ BYTE const* const curMatchBase =
+ cur->offset < dictLimit ? dictBase : base;
+ BYTE const* const pMatch = curMatchBase + cur->offset;
+ BYTE const* const matchEnd =
+ cur->offset < dictLimit ? dictEnd : iend;
+ BYTE const* const lowMatchPtr =
+ cur->offset < dictLimit ? dictStart : lowPrefixPtr;
+
+ curForwardMatchLength = ZSTD_count_2segments(
+ ip, pMatch, iend,
+ matchEnd, lowPrefixPtr);
+ if (curForwardMatchLength < minMatchLength) {
+ continue;
+ }
+ curBackwardMatchLength =
+ ZSTD_ldm_countBackwardsMatch(ip, anchor, pMatch,
+ lowMatchPtr);
+ curTotalMatchLength = curForwardMatchLength +
+ curBackwardMatchLength;
+ } else { /* !extDict */
+ BYTE const* const pMatch = base + cur->offset;
+ curForwardMatchLength = ZSTD_count(ip, pMatch, iend);
+ if (curForwardMatchLength < minMatchLength) {
+ continue;
+ }
+ curBackwardMatchLength =
+ ZSTD_ldm_countBackwardsMatch(ip, anchor, pMatch,
+ lowPrefixPtr);
+ curTotalMatchLength = curForwardMatchLength +
+ curBackwardMatchLength;
+ }
+
+ if (curTotalMatchLength > bestMatchLength) {
+ bestMatchLength = curTotalMatchLength;
+ forwardMatchLength = curForwardMatchLength;
+ backwardMatchLength = curBackwardMatchLength;
+ bestEntry = cur;
+ }
+ }
+ }
+
+ /* No match found -- continue searching */
+ if (bestEntry == NULL) {
+ ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash,
+ hBits, current,
+ *params);
+ ip++;
+ continue;
+ }
+
+ /* Match found */
+ mLength = forwardMatchLength + backwardMatchLength;
+ ip -= backwardMatchLength;
+
+ {
+ /* Store the sequence:
+ * ip = current - backwardMatchLength
+ * The match is at (bestEntry->offset - backwardMatchLength)
+ */
+ U32 const matchIndex = bestEntry->offset;
+ U32 const offset = current - matchIndex;
+ rawSeq* const seq = rawSeqStore->seq + rawSeqStore->size;
+
+ /* Out of sequence storage */
+ if (rawSeqStore->size == rawSeqStore->capacity)
+ return ERROR(dstSize_tooSmall);
+ seq->litLength = (U32)(ip - anchor);
+ seq->matchLength = (U32)mLength;
+ seq->offset = offset;
+ rawSeqStore->size++;
+ }
+
+ /* Insert the current entry into the hash table */
+ ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits,
+ (U32)(lastHashed - base),
+ *params);
+
+ assert(ip + backwardMatchLength == lastHashed);
+
+ /* Fill the hash table from lastHashed+1 to ip+mLength*/
+ /* Heuristic: don't need to fill the entire table at end of block */
+ if (ip + mLength <= ilimit) {
+ rollingHash = ZSTD_ldm_fillLdmHashTable(
+ ldmState, rollingHash, lastHashed,
+ ip + mLength, base, hBits, *params);
+ lastHashed = ip + mLength - 1;
+ }
+ ip += mLength;
+ anchor = ip;
+ }
+ return iend - anchor;
+}
+
+/*! ZSTD_ldm_reduceTable() :
+ * reduce table indexes by `reducerValue` */
+static void ZSTD_ldm_reduceTable(ldmEntry_t* const table, U32 const size,
+ U32 const reducerValue)
+{
+ U32 u;
+ for (u = 0; u < size; u++) {
+ if (table[u].offset < reducerValue) table[u].offset = 0;
+ else table[u].offset -= reducerValue;
+ }
+}
+
+size_t ZSTD_ldm_generateSequences(
+ ldmState_t* ldmState, rawSeqStore_t* sequences,
+ ldmParams_t const* params, void const* src, size_t srcSize)
+{
+ U32 const maxDist = 1U << params->windowLog;
+ BYTE const* const istart = (BYTE const*)src;
+ BYTE const* const iend = istart + srcSize;
+ size_t const kMaxChunkSize = 1 << 20;
+ size_t const nbChunks = (srcSize / kMaxChunkSize) + ((srcSize % kMaxChunkSize) != 0);
+ size_t chunk;
+ size_t leftoverSize = 0;
+
+ assert(ZSTD_CHUNKSIZE_MAX >= kMaxChunkSize);
+ /* Check that ZSTD_window_update() has been called for this chunk prior
+ * to passing it to this function.
+ */
+ assert(ldmState->window.nextSrc >= (BYTE const*)src + srcSize);
+ /* The input could be very large (in zstdmt), so it must be broken up into
+ * chunks to enforce the maximum distance and handle overflow correction.
+ */
+ assert(sequences->pos <= sequences->size);
+ assert(sequences->size <= sequences->capacity);
+ for (chunk = 0; chunk < nbChunks && sequences->size < sequences->capacity; ++chunk) {
+ BYTE const* const chunkStart = istart + chunk * kMaxChunkSize;
+ size_t const remaining = (size_t)(iend - chunkStart);
+ BYTE const *const chunkEnd =
+ (remaining < kMaxChunkSize) ? iend : chunkStart + kMaxChunkSize;
+ size_t const chunkSize = chunkEnd - chunkStart;
+ size_t newLeftoverSize;
+ size_t const prevSize = sequences->size;
+
+ assert(chunkStart < iend);
+ /* 1. Perform overflow correction if necessary. */
+ if (ZSTD_window_needOverflowCorrection(ldmState->window, chunkEnd)) {
+ U32 const ldmHSize = 1U << params->hashLog;
+ U32 const correction = ZSTD_window_correctOverflow(
+ &ldmState->window, /* cycleLog */ 0, maxDist, chunkStart);
+ ZSTD_ldm_reduceTable(ldmState->hashTable, ldmHSize, correction);
+ /* invalidate dictionaries on overflow correction */
+ ldmState->loadedDictEnd = 0;
+ }
+ /* 2. We enforce the maximum offset allowed.
+ *
+ * kMaxChunkSize should be small enough that we don't lose too much of
+ * the window through early invalidation.
+ * TODO: * Test the chunk size.
+ * * Try invalidation after the sequence generation and test the
+ * the offset against maxDist directly.
+ *
+ * NOTE: Because of dictionaries + sequence splitting we MUST make sure
+ * that any offset used is valid at the END of the sequence, since it may
+ * be split into two sequences. This condition holds when using
+ * ZSTD_window_enforceMaxDist(), but if we move to checking offsets
+ * against maxDist directly, we'll have to carefully handle that case.
+ */
+ ZSTD_window_enforceMaxDist(&ldmState->window, chunkEnd, maxDist, &ldmState->loadedDictEnd, NULL);
+ /* 3. Generate the sequences for the chunk, and get newLeftoverSize. */
+ newLeftoverSize = ZSTD_ldm_generateSequences_internal(
+ ldmState, sequences, params, chunkStart, chunkSize);
+ if (ZSTD_isError(newLeftoverSize))
+ return newLeftoverSize;
+ /* 4. We add the leftover literals from previous iterations to the first
+ * newly generated sequence, or add the `newLeftoverSize` if none are
+ * generated.
+ */
+ /* Prepend the leftover literals from the last call */
+ if (prevSize < sequences->size) {
+ sequences->seq[prevSize].litLength += (U32)leftoverSize;
+ leftoverSize = newLeftoverSize;
+ } else {
+ assert(newLeftoverSize == chunkSize);
+ leftoverSize += chunkSize;
+ }
+ }
+ return 0;
+}
+
+void ZSTD_ldm_skipSequences(rawSeqStore_t* rawSeqStore, size_t srcSize, U32 const minMatch) {
+ while (srcSize > 0 && rawSeqStore->pos < rawSeqStore->size) {
+ rawSeq* seq = rawSeqStore->seq + rawSeqStore->pos;
+ if (srcSize <= seq->litLength) {
+ /* Skip past srcSize literals */
+ seq->litLength -= (U32)srcSize;
+ return;
+ }
+ srcSize -= seq->litLength;
+ seq->litLength = 0;
+ if (srcSize < seq->matchLength) {
+ /* Skip past the first srcSize of the match */
+ seq->matchLength -= (U32)srcSize;
+ if (seq->matchLength < minMatch) {
+ /* The match is too short, omit it */
+ if (rawSeqStore->pos + 1 < rawSeqStore->size) {
+ seq[1].litLength += seq[0].matchLength;
+ }
+ rawSeqStore->pos++;
+ }
+ return;
+ }
+ srcSize -= seq->matchLength;
+ seq->matchLength = 0;
+ rawSeqStore->pos++;
+ }
+}
+
+/**
+ * If the sequence length is longer than remaining then the sequence is split
+ * between this block and the next.
+ *
+ * Returns the current sequence to handle, or if the rest of the block should
+ * be literals, it returns a sequence with offset == 0.
+ */
+static rawSeq maybeSplitSequence(rawSeqStore_t* rawSeqStore,
+ U32 const remaining, U32 const minMatch)
+{
+ rawSeq sequence = rawSeqStore->seq[rawSeqStore->pos];
+ assert(sequence.offset > 0);
+ /* Likely: No partial sequence */
+ if (remaining >= sequence.litLength + sequence.matchLength) {
+ rawSeqStore->pos++;
+ return sequence;
+ }
+ /* Cut the sequence short (offset == 0 ==> rest is literals). */
+ if (remaining <= sequence.litLength) {
+ sequence.offset = 0;
+ } else if (remaining < sequence.litLength + sequence.matchLength) {
+ sequence.matchLength = remaining - sequence.litLength;
+ if (sequence.matchLength < minMatch) {
+ sequence.offset = 0;
+ }
+ }
+ /* Skip past `remaining` bytes for the future sequences. */
+ ZSTD_ldm_skipSequences(rawSeqStore, remaining, minMatch);
+ return sequence;
+}
+
+size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ const ZSTD_compressionParameters* const cParams = &ms->cParams;
+ unsigned const minMatch = cParams->minMatch;
+ ZSTD_blockCompressor const blockCompressor =
+ ZSTD_selectBlockCompressor(cParams->strategy, ZSTD_matchState_dictMode(ms));
+ /* Input bounds */
+ BYTE const* const istart = (BYTE const*)src;
+ BYTE const* const iend = istart + srcSize;
+ /* Input positions */
+ BYTE const* ip = istart;
+
+ DEBUGLOG(5, "ZSTD_ldm_blockCompress: srcSize=%zu", srcSize);
+ assert(rawSeqStore->pos <= rawSeqStore->size);
+ assert(rawSeqStore->size <= rawSeqStore->capacity);
+ /* Loop through each sequence and apply the block compressor to the lits */
+ while (rawSeqStore->pos < rawSeqStore->size && ip < iend) {
+ /* maybeSplitSequence updates rawSeqStore->pos */
+ rawSeq const sequence = maybeSplitSequence(rawSeqStore,
+ (U32)(iend - ip), minMatch);
+ int i;
+ /* End signal */
+ if (sequence.offset == 0)
+ break;
+
+ assert(ip + sequence.litLength + sequence.matchLength <= iend);
+
+ /* Fill tables for block compressor */
+ ZSTD_ldm_limitTableUpdate(ms, ip);
+ ZSTD_ldm_fillFastTables(ms, ip);
+ /* Run the block compressor */
+ DEBUGLOG(5, "pos %u : calling block compressor on segment of size %u", (unsigned)(ip-istart), sequence.litLength);
+ {
+ size_t const newLitLength =
+ blockCompressor(ms, seqStore, rep, ip, sequence.litLength);
+ ip += sequence.litLength;
+ /* Update the repcodes */
+ for (i = ZSTD_REP_NUM - 1; i > 0; i--)
+ rep[i] = rep[i-1];
+ rep[0] = sequence.offset;
+ /* Store the sequence */
+ ZSTD_storeSeq(seqStore, newLitLength, ip - newLitLength, iend,
+ sequence.offset + ZSTD_REP_MOVE,
+ sequence.matchLength - MINMATCH);
+ ip += sequence.matchLength;
+ }
+ }
+ /* Fill the tables for the block compressor */
+ ZSTD_ldm_limitTableUpdate(ms, ip);
+ ZSTD_ldm_fillFastTables(ms, ip);
+ /* Compress the last literals */
+ return blockCompressor(ms, seqStore, rep, ip, iend - ip);
+}
diff --git a/sys/contrib/openzfs/module/zstd/lib/compress/zstd_ldm.h b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_ldm.h
new file mode 100644
index 000000000000..229ea05a9e1e
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_ldm.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_LDM_H
+#define ZSTD_LDM_H
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#include "zstd_compress_internal.h" /* ldmParams_t, U32 */
+#include "../zstd.h" /* ZSTD_CCtx, size_t */
+
+/*-*************************************
+* Long distance matching
+***************************************/
+
+#define ZSTD_LDM_DEFAULT_WINDOW_LOG ZSTD_WINDOWLOG_LIMIT_DEFAULT
+
+void ZSTD_ldm_fillHashTable(
+ ldmState_t* state, const BYTE* ip,
+ const BYTE* iend, ldmParams_t const* params);
+
+/**
+ * ZSTD_ldm_generateSequences():
+ *
+ * Generates the sequences using the long distance match finder.
+ * Generates long range matching sequences in `sequences`, which parse a prefix
+ * of the source. `sequences` must be large enough to store every sequence,
+ * which can be checked with `ZSTD_ldm_getMaxNbSeq()`.
+ * @returns 0 or an error code.
+ *
+ * NOTE: The user must have called ZSTD_window_update() for all of the input
+ * they have, even if they pass it to ZSTD_ldm_generateSequences() in chunks.
+ * NOTE: This function returns an error if it runs out of space to store
+ * sequences.
+ */
+size_t ZSTD_ldm_generateSequences(
+ ldmState_t* ldms, rawSeqStore_t* sequences,
+ ldmParams_t const* params, void const* src, size_t srcSize);
+
+/**
+ * ZSTD_ldm_blockCompress():
+ *
+ * Compresses a block using the predefined sequences, along with a secondary
+ * block compressor. The literals section of every sequence is passed to the
+ * secondary block compressor, and those sequences are interspersed with the
+ * predefined sequences. Returns the length of the last literals.
+ * Updates `rawSeqStore.pos` to indicate how many sequences have been consumed.
+ * `rawSeqStore.seq` may also be updated to split the last sequence between two
+ * blocks.
+ * @return The length of the last literals.
+ *
+ * NOTE: The source must be at most the maximum block size, but the predefined
+ * sequences can be any size, and may be longer than the block. In the case that
+ * they are longer than the block, the last sequences may need to be split into
+ * two. We handle that case correctly, and update `rawSeqStore` appropriately.
+ * NOTE: This function does not return any errors.
+ */
+size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+
+/**
+ * ZSTD_ldm_skipSequences():
+ *
+ * Skip past `srcSize` bytes worth of sequences in `rawSeqStore`.
+ * Avoids emitting matches less than `minMatch` bytes.
+ * Must be called for data with is not passed to ZSTD_ldm_blockCompress().
+ */
+void ZSTD_ldm_skipSequences(rawSeqStore_t* rawSeqStore, size_t srcSize,
+ U32 const minMatch);
+
+
+/** ZSTD_ldm_getTableSize() :
+ * Estimate the space needed for long distance matching tables or 0 if LDM is
+ * disabled.
+ */
+size_t ZSTD_ldm_getTableSize(ldmParams_t params);
+
+/** ZSTD_ldm_getSeqSpace() :
+ * Return an upper bound on the number of sequences that can be produced by
+ * the long distance matcher, or 0 if LDM is disabled.
+ */
+size_t ZSTD_ldm_getMaxNbSeq(ldmParams_t params, size_t maxChunkSize);
+
+/** ZSTD_ldm_adjustParameters() :
+ * If the params->hashRateLog is not set, set it to its default value based on
+ * windowLog and params->hashLog.
+ *
+ * Ensures that params->bucketSizeLog is <= params->hashLog (setting it to
+ * params->hashLog if it is not).
+ *
+ * Ensures that the minMatchLength >= targetLength during optimal parsing.
+ */
+void ZSTD_ldm_adjustParameters(ldmParams_t* params,
+ ZSTD_compressionParameters const* cParams);
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* ZSTD_FAST_H */
diff --git a/sys/contrib/openzfs/module/zstd/lib/compress/zstd_opt.c b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_opt.c
new file mode 100644
index 000000000000..36fff050cf5a
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_opt.c
@@ -0,0 +1,1200 @@
+/*
+ * Copyright (c) 2016-2020, Przemyslaw Skibinski, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#include "zstd_compress_internal.h"
+#include "hist.h"
+#include "zstd_opt.h"
+
+
+#define ZSTD_LITFREQ_ADD 2 /* scaling factor for litFreq, so that frequencies adapt faster to new stats */
+#define ZSTD_FREQ_DIV 4 /* log factor when using previous stats to init next stats */
+#define ZSTD_MAX_PRICE (1<<30)
+
+#define ZSTD_PREDEF_THRESHOLD 1024 /* if srcSize < ZSTD_PREDEF_THRESHOLD, symbols' cost is assumed static, directly determined by pre-defined distributions */
+
+
+/*-*************************************
+* Price functions for optimal parser
+***************************************/
+
+#if 0 /* approximation at bit level */
+# define BITCOST_ACCURACY 0
+# define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY)
+# define WEIGHT(stat) ((void)opt, ZSTD_bitWeight(stat))
+#elif 0 /* fractional bit accuracy */
+# define BITCOST_ACCURACY 8
+# define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY)
+# define WEIGHT(stat,opt) ((void)opt, ZSTD_fracWeight(stat))
+#else /* opt==approx, ultra==accurate */
+# define BITCOST_ACCURACY 8
+# define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY)
+# define WEIGHT(stat,opt) (opt ? ZSTD_fracWeight(stat) : ZSTD_bitWeight(stat))
+#endif
+
+MEM_STATIC U32 ZSTD_bitWeight(U32 stat)
+{
+ return (ZSTD_highbit32(stat+1) * BITCOST_MULTIPLIER);
+}
+
+MEM_STATIC U32 ZSTD_fracWeight(U32 rawStat)
+{
+ U32 const stat = rawStat + 1;
+ U32 const hb = ZSTD_highbit32(stat);
+ U32 const BWeight = hb * BITCOST_MULTIPLIER;
+ U32 const FWeight = (stat << BITCOST_ACCURACY) >> hb;
+ U32 const weight = BWeight + FWeight;
+ assert(hb + BITCOST_ACCURACY < 31);
+ return weight;
+}
+
+#if (DEBUGLEVEL>=2)
+/* debugging function,
+ * @return price in bytes as fractional value
+ * for debug messages only */
+MEM_STATIC double ZSTD_fCost(U32 price)
+{
+ return (double)price / (BITCOST_MULTIPLIER*8);
+}
+#endif
+
+static int ZSTD_compressedLiterals(optState_t const* const optPtr)
+{
+ return optPtr->literalCompressionMode != ZSTD_lcm_uncompressed;
+}
+
+static void ZSTD_setBasePrices(optState_t* optPtr, int optLevel)
+{
+ if (ZSTD_compressedLiterals(optPtr))
+ optPtr->litSumBasePrice = WEIGHT(optPtr->litSum, optLevel);
+ optPtr->litLengthSumBasePrice = WEIGHT(optPtr->litLengthSum, optLevel);
+ optPtr->matchLengthSumBasePrice = WEIGHT(optPtr->matchLengthSum, optLevel);
+ optPtr->offCodeSumBasePrice = WEIGHT(optPtr->offCodeSum, optLevel);
+}
+
+
+/* ZSTD_downscaleStat() :
+ * reduce all elements in table by a factor 2^(ZSTD_FREQ_DIV+malus)
+ * return the resulting sum of elements */
+static U32 ZSTD_downscaleStat(unsigned* table, U32 lastEltIndex, int malus)
+{
+ U32 s, sum=0;
+ DEBUGLOG(5, "ZSTD_downscaleStat (nbElts=%u)", (unsigned)lastEltIndex+1);
+ assert(ZSTD_FREQ_DIV+malus > 0 && ZSTD_FREQ_DIV+malus < 31);
+ for (s=0; s<lastEltIndex+1; s++) {
+ table[s] = 1 + (table[s] >> (ZSTD_FREQ_DIV+malus));
+ sum += table[s];
+ }
+ return sum;
+}
+
+/* ZSTD_rescaleFreqs() :
+ * if first block (detected by optPtr->litLengthSum == 0) : init statistics
+ * take hints from dictionary if there is one
+ * or init from zero, using src for literals stats, or flat 1 for match symbols
+ * otherwise downscale existing stats, to be used as seed for next block.
+ */
+static void
+ZSTD_rescaleFreqs(optState_t* const optPtr,
+ const BYTE* const src, size_t const srcSize,
+ int const optLevel)
+{
+ int const compressedLiterals = ZSTD_compressedLiterals(optPtr);
+ DEBUGLOG(5, "ZSTD_rescaleFreqs (srcSize=%u)", (unsigned)srcSize);
+ optPtr->priceType = zop_dynamic;
+
+ if (optPtr->litLengthSum == 0) { /* first block : init */
+ if (srcSize <= ZSTD_PREDEF_THRESHOLD) { /* heuristic */
+ DEBUGLOG(5, "(srcSize <= ZSTD_PREDEF_THRESHOLD) => zop_predef");
+ optPtr->priceType = zop_predef;
+ }
+
+ assert(optPtr->symbolCosts != NULL);
+ if (optPtr->symbolCosts->huf.repeatMode == HUF_repeat_valid) {
+ /* huffman table presumed generated by dictionary */
+ optPtr->priceType = zop_dynamic;
+
+ if (compressedLiterals) {
+ unsigned lit;
+ assert(optPtr->litFreq != NULL);
+ optPtr->litSum = 0;
+ for (lit=0; lit<=MaxLit; lit++) {
+ U32 const scaleLog = 11; /* scale to 2K */
+ U32 const bitCost = HUF_getNbBits(optPtr->symbolCosts->huf.CTable, lit);
+ assert(bitCost <= scaleLog);
+ optPtr->litFreq[lit] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/;
+ optPtr->litSum += optPtr->litFreq[lit];
+ } }
+
+ { unsigned ll;
+ FSE_CState_t llstate;
+ FSE_initCState(&llstate, optPtr->symbolCosts->fse.litlengthCTable);
+ optPtr->litLengthSum = 0;
+ for (ll=0; ll<=MaxLL; ll++) {
+ U32 const scaleLog = 10; /* scale to 1K */
+ U32 const bitCost = FSE_getMaxNbBits(llstate.symbolTT, ll);
+ assert(bitCost < scaleLog);
+ optPtr->litLengthFreq[ll] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/;
+ optPtr->litLengthSum += optPtr->litLengthFreq[ll];
+ } }
+
+ { unsigned ml;
+ FSE_CState_t mlstate;
+ FSE_initCState(&mlstate, optPtr->symbolCosts->fse.matchlengthCTable);
+ optPtr->matchLengthSum = 0;
+ for (ml=0; ml<=MaxML; ml++) {
+ U32 const scaleLog = 10;
+ U32 const bitCost = FSE_getMaxNbBits(mlstate.symbolTT, ml);
+ assert(bitCost < scaleLog);
+ optPtr->matchLengthFreq[ml] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/;
+ optPtr->matchLengthSum += optPtr->matchLengthFreq[ml];
+ } }
+
+ { unsigned of;
+ FSE_CState_t ofstate;
+ FSE_initCState(&ofstate, optPtr->symbolCosts->fse.offcodeCTable);
+ optPtr->offCodeSum = 0;
+ for (of=0; of<=MaxOff; of++) {
+ U32 const scaleLog = 10;
+ U32 const bitCost = FSE_getMaxNbBits(ofstate.symbolTT, of);
+ assert(bitCost < scaleLog);
+ optPtr->offCodeFreq[of] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/;
+ optPtr->offCodeSum += optPtr->offCodeFreq[of];
+ } }
+
+ } else { /* not a dictionary */
+
+ assert(optPtr->litFreq != NULL);
+ if (compressedLiterals) {
+ unsigned lit = MaxLit;
+ HIST_count_simple(optPtr->litFreq, &lit, src, srcSize); /* use raw first block to init statistics */
+ optPtr->litSum = ZSTD_downscaleStat(optPtr->litFreq, MaxLit, 1);
+ }
+
+ { unsigned ll;
+ for (ll=0; ll<=MaxLL; ll++)
+ optPtr->litLengthFreq[ll] = 1;
+ }
+ optPtr->litLengthSum = MaxLL+1;
+
+ { unsigned ml;
+ for (ml=0; ml<=MaxML; ml++)
+ optPtr->matchLengthFreq[ml] = 1;
+ }
+ optPtr->matchLengthSum = MaxML+1;
+
+ { unsigned of;
+ for (of=0; of<=MaxOff; of++)
+ optPtr->offCodeFreq[of] = 1;
+ }
+ optPtr->offCodeSum = MaxOff+1;
+
+ }
+
+ } else { /* new block : re-use previous statistics, scaled down */
+
+ if (compressedLiterals)
+ optPtr->litSum = ZSTD_downscaleStat(optPtr->litFreq, MaxLit, 1);
+ optPtr->litLengthSum = ZSTD_downscaleStat(optPtr->litLengthFreq, MaxLL, 0);
+ optPtr->matchLengthSum = ZSTD_downscaleStat(optPtr->matchLengthFreq, MaxML, 0);
+ optPtr->offCodeSum = ZSTD_downscaleStat(optPtr->offCodeFreq, MaxOff, 0);
+ }
+
+ ZSTD_setBasePrices(optPtr, optLevel);
+}
+
+/* ZSTD_rawLiteralsCost() :
+ * price of literals (only) in specified segment (which length can be 0).
+ * does not include price of literalLength symbol */
+static U32 ZSTD_rawLiteralsCost(const BYTE* const literals, U32 const litLength,
+ const optState_t* const optPtr,
+ int optLevel)
+{
+ if (litLength == 0) return 0;
+
+ if (!ZSTD_compressedLiterals(optPtr))
+ return (litLength << 3) * BITCOST_MULTIPLIER; /* Uncompressed - 8 bytes per literal. */
+
+ if (optPtr->priceType == zop_predef)
+ return (litLength*6) * BITCOST_MULTIPLIER; /* 6 bit per literal - no statistic used */
+
+ /* dynamic statistics */
+ { U32 price = litLength * optPtr->litSumBasePrice;
+ U32 u;
+ for (u=0; u < litLength; u++) {
+ assert(WEIGHT(optPtr->litFreq[literals[u]], optLevel) <= optPtr->litSumBasePrice); /* literal cost should never be negative */
+ price -= WEIGHT(optPtr->litFreq[literals[u]], optLevel);
+ }
+ return price;
+ }
+}
+
+/* ZSTD_litLengthPrice() :
+ * cost of literalLength symbol */
+static U32 ZSTD_litLengthPrice(U32 const litLength, const optState_t* const optPtr, int optLevel)
+{
+ if (optPtr->priceType == zop_predef) return WEIGHT(litLength, optLevel);
+
+ /* dynamic statistics */
+ { U32 const llCode = ZSTD_LLcode(litLength);
+ return (LL_bits[llCode] * BITCOST_MULTIPLIER)
+ + optPtr->litLengthSumBasePrice
+ - WEIGHT(optPtr->litLengthFreq[llCode], optLevel);
+ }
+}
+
+/* ZSTD_getMatchPrice() :
+ * Provides the cost of the match part (offset + matchLength) of a sequence
+ * Must be combined with ZSTD_fullLiteralsCost() to get the full cost of a sequence.
+ * optLevel: when <2, favors small offset for decompression speed (improved cache efficiency) */
+FORCE_INLINE_TEMPLATE U32
+ZSTD_getMatchPrice(U32 const offset,
+ U32 const matchLength,
+ const optState_t* const optPtr,
+ int const optLevel)
+{
+ U32 price;
+ U32 const offCode = ZSTD_highbit32(offset+1);
+ U32 const mlBase = matchLength - MINMATCH;
+ assert(matchLength >= MINMATCH);
+
+ if (optPtr->priceType == zop_predef) /* fixed scheme, do not use statistics */
+ return WEIGHT(mlBase, optLevel) + ((16 + offCode) * BITCOST_MULTIPLIER);
+
+ /* dynamic statistics */
+ price = (offCode * BITCOST_MULTIPLIER) + (optPtr->offCodeSumBasePrice - WEIGHT(optPtr->offCodeFreq[offCode], optLevel));
+ if ((optLevel<2) /*static*/ && offCode >= 20)
+ price += (offCode-19)*2 * BITCOST_MULTIPLIER; /* handicap for long distance offsets, favor decompression speed */
+
+ /* match Length */
+ { U32 const mlCode = ZSTD_MLcode(mlBase);
+ price += (ML_bits[mlCode] * BITCOST_MULTIPLIER) + (optPtr->matchLengthSumBasePrice - WEIGHT(optPtr->matchLengthFreq[mlCode], optLevel));
+ }
+
+ price += BITCOST_MULTIPLIER / 5; /* heuristic : make matches a bit more costly to favor less sequences -> faster decompression speed */
+
+ DEBUGLOG(8, "ZSTD_getMatchPrice(ml:%u) = %u", matchLength, price);
+ return price;
+}
+
+/* ZSTD_updateStats() :
+ * assumption : literals + litLengtn <= iend */
+static void ZSTD_updateStats(optState_t* const optPtr,
+ U32 litLength, const BYTE* literals,
+ U32 offsetCode, U32 matchLength)
+{
+ /* literals */
+ if (ZSTD_compressedLiterals(optPtr)) {
+ U32 u;
+ for (u=0; u < litLength; u++)
+ optPtr->litFreq[literals[u]] += ZSTD_LITFREQ_ADD;
+ optPtr->litSum += litLength*ZSTD_LITFREQ_ADD;
+ }
+
+ /* literal Length */
+ { U32 const llCode = ZSTD_LLcode(litLength);
+ optPtr->litLengthFreq[llCode]++;
+ optPtr->litLengthSum++;
+ }
+
+ /* match offset code (0-2=>repCode; 3+=>offset+2) */
+ { U32 const offCode = ZSTD_highbit32(offsetCode+1);
+ assert(offCode <= MaxOff);
+ optPtr->offCodeFreq[offCode]++;
+ optPtr->offCodeSum++;
+ }
+
+ /* match Length */
+ { U32 const mlBase = matchLength - MINMATCH;
+ U32 const mlCode = ZSTD_MLcode(mlBase);
+ optPtr->matchLengthFreq[mlCode]++;
+ optPtr->matchLengthSum++;
+ }
+}
+
+
+/* ZSTD_readMINMATCH() :
+ * function safe only for comparisons
+ * assumption : memPtr must be at least 4 bytes before end of buffer */
+MEM_STATIC U32 ZSTD_readMINMATCH(const void* memPtr, U32 length)
+{
+ switch (length)
+ {
+ default :
+ case 4 : return MEM_read32(memPtr);
+ case 3 : if (MEM_isLittleEndian())
+ return MEM_read32(memPtr)<<8;
+ else
+ return MEM_read32(memPtr)>>8;
+ }
+}
+
+
+/* Update hashTable3 up to ip (excluded)
+ Assumption : always within prefix (i.e. not within extDict) */
+static U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_matchState_t* ms,
+ U32* nextToUpdate3,
+ const BYTE* const ip)
+{
+ U32* const hashTable3 = ms->hashTable3;
+ U32 const hashLog3 = ms->hashLog3;
+ const BYTE* const base = ms->window.base;
+ U32 idx = *nextToUpdate3;
+ U32 const target = (U32)(ip - base);
+ size_t const hash3 = ZSTD_hash3Ptr(ip, hashLog3);
+ assert(hashLog3 > 0);
+
+ while(idx < target) {
+ hashTable3[ZSTD_hash3Ptr(base+idx, hashLog3)] = idx;
+ idx++;
+ }
+
+ *nextToUpdate3 = target;
+ return hashTable3[hash3];
+}
+
+
+/*-*************************************
+* Binary Tree search
+***************************************/
+/** ZSTD_insertBt1() : add one or multiple positions to tree.
+ * ip : assumed <= iend-8 .
+ * @return : nb of positions added */
+static U32 ZSTD_insertBt1(
+ ZSTD_matchState_t* ms,
+ const BYTE* const ip, const BYTE* const iend,
+ U32 const mls, const int extDict)
+{
+ const ZSTD_compressionParameters* const cParams = &ms->cParams;
+ U32* const hashTable = ms->hashTable;
+ U32 const hashLog = cParams->hashLog;
+ size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
+ U32* const bt = ms->chainTable;
+ U32 const btLog = cParams->chainLog - 1;
+ U32 const btMask = (1 << btLog) - 1;
+ U32 matchIndex = hashTable[h];
+ size_t commonLengthSmaller=0, commonLengthLarger=0;
+ const BYTE* const base = ms->window.base;
+ const BYTE* const dictBase = ms->window.dictBase;
+ const U32 dictLimit = ms->window.dictLimit;
+ const BYTE* const dictEnd = dictBase + dictLimit;
+ const BYTE* const prefixStart = base + dictLimit;
+ const BYTE* match;
+ const U32 current = (U32)(ip-base);
+ const U32 btLow = btMask >= current ? 0 : current - btMask;
+ U32* smallerPtr = bt + 2*(current&btMask);
+ U32* largerPtr = smallerPtr + 1;
+ U32 dummy32; /* to be nullified at the end */
+ U32 const windowLow = ms->window.lowLimit;
+ U32 matchEndIdx = current+8+1;
+ size_t bestLength = 8;
+ U32 nbCompares = 1U << cParams->searchLog;
+#ifdef ZSTD_C_PREDICT
+ U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
+ U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
+ predictedSmall += (predictedSmall>0);
+ predictedLarge += (predictedLarge>0);
+#endif /* ZSTD_C_PREDICT */
+
+ DEBUGLOG(8, "ZSTD_insertBt1 (%u)", current);
+
+ assert(ip <= iend-8); /* required for h calculation */
+ hashTable[h] = current; /* Update Hash Table */
+
+ assert(windowLow > 0);
+ while (nbCompares-- && (matchIndex >= windowLow)) {
+ U32* const nextPtr = bt + 2*(matchIndex & btMask);
+ size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
+ assert(matchIndex < current);
+
+#ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */
+ const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
+ if (matchIndex == predictedSmall) {
+ /* no need to check length, result known */
+ *smallerPtr = matchIndex;
+ if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
+ smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
+ matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
+ predictedSmall = predictPtr[1] + (predictPtr[1]>0);
+ continue;
+ }
+ if (matchIndex == predictedLarge) {
+ *largerPtr = matchIndex;
+ if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
+ largerPtr = nextPtr;
+ matchIndex = nextPtr[0];
+ predictedLarge = predictPtr[0] + (predictPtr[0]>0);
+ continue;
+ }
+#endif
+
+ if (!extDict || (matchIndex+matchLength >= dictLimit)) {
+ assert(matchIndex+matchLength >= dictLimit); /* might be wrong if actually extDict */
+ match = base + matchIndex;
+ matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
+ } else {
+ match = dictBase + matchIndex;
+ matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
+ if (matchIndex+matchLength >= dictLimit)
+ match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
+ }
+
+ if (matchLength > bestLength) {
+ bestLength = matchLength;
+ if (matchLength > matchEndIdx - matchIndex)
+ matchEndIdx = matchIndex + (U32)matchLength;
+ }
+
+ if (ip+matchLength == iend) { /* equal : no way to know if inf or sup */
+ break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt tree */
+ }
+
+ if (match[matchLength] < ip[matchLength]) { /* necessarily within buffer */
+ /* match is smaller than current */
+ *smallerPtr = matchIndex; /* update smaller idx */
+ commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
+ if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop searching */
+ smallerPtr = nextPtr+1; /* new "candidate" => larger than match, which was smaller than target */
+ matchIndex = nextPtr[1]; /* new matchIndex, larger than previous and closer to current */
+ } else {
+ /* match is larger than current */
+ *largerPtr = matchIndex;
+ commonLengthLarger = matchLength;
+ if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop searching */
+ largerPtr = nextPtr;
+ matchIndex = nextPtr[0];
+ } }
+
+ *smallerPtr = *largerPtr = 0;
+ { U32 positions = 0;
+ if (bestLength > 384) positions = MIN(192, (U32)(bestLength - 384)); /* speed optimization */
+ assert(matchEndIdx > current + 8);
+ return MAX(positions, matchEndIdx - (current + 8));
+ }
+}
+
+FORCE_INLINE_TEMPLATE
+void ZSTD_updateTree_internal(
+ ZSTD_matchState_t* ms,
+ const BYTE* const ip, const BYTE* const iend,
+ const U32 mls, const ZSTD_dictMode_e dictMode)
+{
+ const BYTE* const base = ms->window.base;
+ U32 const target = (U32)(ip - base);
+ U32 idx = ms->nextToUpdate;
+ DEBUGLOG(6, "ZSTD_updateTree_internal, from %u to %u (dictMode:%u)",
+ idx, target, dictMode);
+
+ while(idx < target) {
+ U32 const forward = ZSTD_insertBt1(ms, base+idx, iend, mls, dictMode == ZSTD_extDict);
+ assert(idx < (U32)(idx + forward));
+ idx += forward;
+ }
+ assert((size_t)(ip - base) <= (size_t)(U32)(-1));
+ assert((size_t)(iend - base) <= (size_t)(U32)(-1));
+ ms->nextToUpdate = target;
+}
+
+void ZSTD_updateTree(ZSTD_matchState_t* ms, const BYTE* ip, const BYTE* iend) {
+ ZSTD_updateTree_internal(ms, ip, iend, ms->cParams.minMatch, ZSTD_noDict);
+}
+
+FORCE_INLINE_TEMPLATE
+U32 ZSTD_insertBtAndGetAllMatches (
+ ZSTD_match_t* matches, /* store result (found matches) in this table (presumed large enough) */
+ ZSTD_matchState_t* ms,
+ U32* nextToUpdate3,
+ const BYTE* const ip, const BYTE* const iLimit, const ZSTD_dictMode_e dictMode,
+ const U32 rep[ZSTD_REP_NUM],
+ U32 const ll0, /* tells if associated literal length is 0 or not. This value must be 0 or 1 */
+ const U32 lengthToBeat,
+ U32 const mls /* template */)
+{
+ const ZSTD_compressionParameters* const cParams = &ms->cParams;
+ U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1);
+ const BYTE* const base = ms->window.base;
+ U32 const current = (U32)(ip-base);
+ U32 const hashLog = cParams->hashLog;
+ U32 const minMatch = (mls==3) ? 3 : 4;
+ U32* const hashTable = ms->hashTable;
+ size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
+ U32 matchIndex = hashTable[h];
+ U32* const bt = ms->chainTable;
+ U32 const btLog = cParams->chainLog - 1;
+ U32 const btMask= (1U << btLog) - 1;
+ size_t commonLengthSmaller=0, commonLengthLarger=0;
+ const BYTE* const dictBase = ms->window.dictBase;
+ U32 const dictLimit = ms->window.dictLimit;
+ const BYTE* const dictEnd = dictBase + dictLimit;
+ const BYTE* const prefixStart = base + dictLimit;
+ U32 const btLow = (btMask >= current) ? 0 : current - btMask;
+ U32 const windowLow = ZSTD_getLowestMatchIndex(ms, current, cParams->windowLog);
+ U32 const matchLow = windowLow ? windowLow : 1;
+ U32* smallerPtr = bt + 2*(current&btMask);
+ U32* largerPtr = bt + 2*(current&btMask) + 1;
+ U32 matchEndIdx = current+8+1; /* farthest referenced position of any match => detects repetitive patterns */
+ U32 dummy32; /* to be nullified at the end */
+ U32 mnum = 0;
+ U32 nbCompares = 1U << cParams->searchLog;
+
+ const ZSTD_matchState_t* dms = dictMode == ZSTD_dictMatchState ? ms->dictMatchState : NULL;
+ const ZSTD_compressionParameters* const dmsCParams =
+ dictMode == ZSTD_dictMatchState ? &dms->cParams : NULL;
+ const BYTE* const dmsBase = dictMode == ZSTD_dictMatchState ? dms->window.base : NULL;
+ const BYTE* const dmsEnd = dictMode == ZSTD_dictMatchState ? dms->window.nextSrc : NULL;
+ U32 const dmsHighLimit = dictMode == ZSTD_dictMatchState ? (U32)(dmsEnd - dmsBase) : 0;
+ U32 const dmsLowLimit = dictMode == ZSTD_dictMatchState ? dms->window.lowLimit : 0;
+ U32 const dmsIndexDelta = dictMode == ZSTD_dictMatchState ? windowLow - dmsHighLimit : 0;
+ U32 const dmsHashLog = dictMode == ZSTD_dictMatchState ? dmsCParams->hashLog : hashLog;
+ U32 const dmsBtLog = dictMode == ZSTD_dictMatchState ? dmsCParams->chainLog - 1 : btLog;
+ U32 const dmsBtMask = dictMode == ZSTD_dictMatchState ? (1U << dmsBtLog) - 1 : 0;
+ U32 const dmsBtLow = dictMode == ZSTD_dictMatchState && dmsBtMask < dmsHighLimit - dmsLowLimit ? dmsHighLimit - dmsBtMask : dmsLowLimit;
+
+ size_t bestLength = lengthToBeat-1;
+ DEBUGLOG(8, "ZSTD_insertBtAndGetAllMatches: current=%u", current);
+
+ /* check repCode */
+ assert(ll0 <= 1); /* necessarily 1 or 0 */
+ { U32 const lastR = ZSTD_REP_NUM + ll0;
+ U32 repCode;
+ for (repCode = ll0; repCode < lastR; repCode++) {
+ U32 const repOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode];
+ U32 const repIndex = current - repOffset;
+ U32 repLen = 0;
+ assert(current >= dictLimit);
+ if (repOffset-1 /* intentional overflow, discards 0 and -1 */ < current-dictLimit) { /* equivalent to `current > repIndex >= dictLimit` */
+ /* We must validate the repcode offset because when we're using a dictionary the
+ * valid offset range shrinks when the dictionary goes out of bounds.
+ */
+ if ((repIndex >= windowLow) & (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(ip - repOffset, minMatch))) {
+ repLen = (U32)ZSTD_count(ip+minMatch, ip+minMatch-repOffset, iLimit) + minMatch;
+ }
+ } else { /* repIndex < dictLimit || repIndex >= current */
+ const BYTE* const repMatch = dictMode == ZSTD_dictMatchState ?
+ dmsBase + repIndex - dmsIndexDelta :
+ dictBase + repIndex;
+ assert(current >= windowLow);
+ if ( dictMode == ZSTD_extDict
+ && ( ((repOffset-1) /*intentional overflow*/ < current - windowLow) /* equivalent to `current > repIndex >= windowLow` */
+ & (((U32)((dictLimit-1) - repIndex) >= 3) ) /* intentional overflow : do not test positions overlapping 2 memory segments */)
+ && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) {
+ repLen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iLimit, dictEnd, prefixStart) + minMatch;
+ }
+ if (dictMode == ZSTD_dictMatchState
+ && ( ((repOffset-1) /*intentional overflow*/ < current - (dmsLowLimit + dmsIndexDelta)) /* equivalent to `current > repIndex >= dmsLowLimit` */
+ & ((U32)((dictLimit-1) - repIndex) >= 3) ) /* intentional overflow : do not test positions overlapping 2 memory segments */
+ && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) {
+ repLen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iLimit, dmsEnd, prefixStart) + minMatch;
+ } }
+ /* save longer solution */
+ if (repLen > bestLength) {
+ DEBUGLOG(8, "found repCode %u (ll0:%u, offset:%u) of length %u",
+ repCode, ll0, repOffset, repLen);
+ bestLength = repLen;
+ matches[mnum].off = repCode - ll0;
+ matches[mnum].len = (U32)repLen;
+ mnum++;
+ if ( (repLen > sufficient_len)
+ | (ip+repLen == iLimit) ) { /* best possible */
+ return mnum;
+ } } } }
+
+ /* HC3 match finder */
+ if ((mls == 3) /*static*/ && (bestLength < mls)) {
+ U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3(ms, nextToUpdate3, ip);
+ if ((matchIndex3 >= matchLow)
+ & (current - matchIndex3 < (1<<18)) /*heuristic : longer distance likely too expensive*/ ) {
+ size_t mlen;
+ if ((dictMode == ZSTD_noDict) /*static*/ || (dictMode == ZSTD_dictMatchState) /*static*/ || (matchIndex3 >= dictLimit)) {
+ const BYTE* const match = base + matchIndex3;
+ mlen = ZSTD_count(ip, match, iLimit);
+ } else {
+ const BYTE* const match = dictBase + matchIndex3;
+ mlen = ZSTD_count_2segments(ip, match, iLimit, dictEnd, prefixStart);
+ }
+
+ /* save best solution */
+ if (mlen >= mls /* == 3 > bestLength */) {
+ DEBUGLOG(8, "found small match with hlog3, of length %u",
+ (U32)mlen);
+ bestLength = mlen;
+ assert(current > matchIndex3);
+ assert(mnum==0); /* no prior solution */
+ matches[0].off = (current - matchIndex3) + ZSTD_REP_MOVE;
+ matches[0].len = (U32)mlen;
+ mnum = 1;
+ if ( (mlen > sufficient_len) |
+ (ip+mlen == iLimit) ) { /* best possible length */
+ ms->nextToUpdate = current+1; /* skip insertion */
+ return 1;
+ } } }
+ /* no dictMatchState lookup: dicts don't have a populated HC3 table */
+ }
+
+ hashTable[h] = current; /* Update Hash Table */
+
+ while (nbCompares-- && (matchIndex >= matchLow)) {
+ U32* const nextPtr = bt + 2*(matchIndex & btMask);
+ const BYTE* match;
+ size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
+ assert(current > matchIndex);
+
+ if ((dictMode == ZSTD_noDict) || (dictMode == ZSTD_dictMatchState) || (matchIndex+matchLength >= dictLimit)) {
+ assert(matchIndex+matchLength >= dictLimit); /* ensure the condition is correct when !extDict */
+ match = base + matchIndex;
+ if (matchIndex >= dictLimit) assert(memcmp(match, ip, matchLength) == 0); /* ensure early section of match is equal as expected */
+ matchLength += ZSTD_count(ip+matchLength, match+matchLength, iLimit);
+ } else {
+ match = dictBase + matchIndex;
+ assert(memcmp(match, ip, matchLength) == 0); /* ensure early section of match is equal as expected */
+ matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iLimit, dictEnd, prefixStart);
+ if (matchIndex+matchLength >= dictLimit)
+ match = base + matchIndex; /* prepare for match[matchLength] read */
+ }
+
+ if (matchLength > bestLength) {
+ DEBUGLOG(8, "found match of length %u at distance %u (offCode=%u)",
+ (U32)matchLength, current - matchIndex, current - matchIndex + ZSTD_REP_MOVE);
+ assert(matchEndIdx > matchIndex);
+ if (matchLength > matchEndIdx - matchIndex)
+ matchEndIdx = matchIndex + (U32)matchLength;
+ bestLength = matchLength;
+ matches[mnum].off = (current - matchIndex) + ZSTD_REP_MOVE;
+ matches[mnum].len = (U32)matchLength;
+ mnum++;
+ if ( (matchLength > ZSTD_OPT_NUM)
+ | (ip+matchLength == iLimit) /* equal : no way to know if inf or sup */) {
+ if (dictMode == ZSTD_dictMatchState) nbCompares = 0; /* break should also skip searching dms */
+ break; /* drop, to preserve bt consistency (miss a little bit of compression) */
+ }
+ }
+
+ if (match[matchLength] < ip[matchLength]) {
+ /* match smaller than current */
+ *smallerPtr = matchIndex; /* update smaller idx */
+ commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
+ if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
+ smallerPtr = nextPtr+1; /* new candidate => larger than match, which was smaller than current */
+ matchIndex = nextPtr[1]; /* new matchIndex, larger than previous, closer to current */
+ } else {
+ *largerPtr = matchIndex;
+ commonLengthLarger = matchLength;
+ if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
+ largerPtr = nextPtr;
+ matchIndex = nextPtr[0];
+ } }
+
+ *smallerPtr = *largerPtr = 0;
+
+ if (dictMode == ZSTD_dictMatchState && nbCompares) {
+ size_t const dmsH = ZSTD_hashPtr(ip, dmsHashLog, mls);
+ U32 dictMatchIndex = dms->hashTable[dmsH];
+ const U32* const dmsBt = dms->chainTable;
+ commonLengthSmaller = commonLengthLarger = 0;
+ while (nbCompares-- && (dictMatchIndex > dmsLowLimit)) {
+ const U32* const nextPtr = dmsBt + 2*(dictMatchIndex & dmsBtMask);
+ size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
+ const BYTE* match = dmsBase + dictMatchIndex;
+ matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iLimit, dmsEnd, prefixStart);
+ if (dictMatchIndex+matchLength >= dmsHighLimit)
+ match = base + dictMatchIndex + dmsIndexDelta; /* to prepare for next usage of match[matchLength] */
+
+ if (matchLength > bestLength) {
+ matchIndex = dictMatchIndex + dmsIndexDelta;
+ DEBUGLOG(8, "found dms match of length %u at distance %u (offCode=%u)",
+ (U32)matchLength, current - matchIndex, current - matchIndex + ZSTD_REP_MOVE);
+ if (matchLength > matchEndIdx - matchIndex)
+ matchEndIdx = matchIndex + (U32)matchLength;
+ bestLength = matchLength;
+ matches[mnum].off = (current - matchIndex) + ZSTD_REP_MOVE;
+ matches[mnum].len = (U32)matchLength;
+ mnum++;
+ if ( (matchLength > ZSTD_OPT_NUM)
+ | (ip+matchLength == iLimit) /* equal : no way to know if inf or sup */) {
+ break; /* drop, to guarantee consistency (miss a little bit of compression) */
+ }
+ }
+
+ if (dictMatchIndex <= dmsBtLow) { break; } /* beyond tree size, stop the search */
+ if (match[matchLength] < ip[matchLength]) {
+ commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
+ dictMatchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
+ } else {
+ /* match is larger than current */
+ commonLengthLarger = matchLength;
+ dictMatchIndex = nextPtr[0];
+ }
+ }
+ }
+
+ assert(matchEndIdx > current+8);
+ ms->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */
+ return mnum;
+}
+
+
+FORCE_INLINE_TEMPLATE U32 ZSTD_BtGetAllMatches (
+ ZSTD_match_t* matches, /* store result (match found, increasing size) in this table */
+ ZSTD_matchState_t* ms,
+ U32* nextToUpdate3,
+ const BYTE* ip, const BYTE* const iHighLimit, const ZSTD_dictMode_e dictMode,
+ const U32 rep[ZSTD_REP_NUM],
+ U32 const ll0,
+ U32 const lengthToBeat)
+{
+ const ZSTD_compressionParameters* const cParams = &ms->cParams;
+ U32 const matchLengthSearch = cParams->minMatch;
+ DEBUGLOG(8, "ZSTD_BtGetAllMatches");
+ if (ip < ms->window.base + ms->nextToUpdate) return 0; /* skipped area */
+ ZSTD_updateTree_internal(ms, ip, iHighLimit, matchLengthSearch, dictMode);
+ switch(matchLengthSearch)
+ {
+ case 3 : return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, 3);
+ default :
+ case 4 : return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, 4);
+ case 5 : return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, 5);
+ case 7 :
+ case 6 : return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, 6);
+ }
+}
+
+
+/*-*******************************
+* Optimal parser
+*********************************/
+
+
+static U32 ZSTD_totalLen(ZSTD_optimal_t sol)
+{
+ return sol.litlen + sol.mlen;
+}
+
+#if 0 /* debug */
+
+static void
+listStats(const U32* table, int lastEltID)
+{
+ int const nbElts = lastEltID + 1;
+ int enb;
+ for (enb=0; enb < nbElts; enb++) {
+ (void)table;
+ /* RAWLOG(2, "%3i:%3i, ", enb, table[enb]); */
+ RAWLOG(2, "%4i,", table[enb]);
+ }
+ RAWLOG(2, " \n");
+}
+
+#endif
+
+FORCE_INLINE_TEMPLATE size_t
+ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,
+ seqStore_t* seqStore,
+ U32 rep[ZSTD_REP_NUM],
+ const void* src, size_t srcSize,
+ const int optLevel,
+ const ZSTD_dictMode_e dictMode)
+{
+ optState_t* const optStatePtr = &ms->opt;
+ const BYTE* const istart = (const BYTE*)src;
+ const BYTE* ip = istart;
+ const BYTE* anchor = istart;
+ const BYTE* const iend = istart + srcSize;
+ const BYTE* const ilimit = iend - 8;
+ const BYTE* const base = ms->window.base;
+ const BYTE* const prefixStart = base + ms->window.dictLimit;
+ const ZSTD_compressionParameters* const cParams = &ms->cParams;
+
+ U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1);
+ U32 const minMatch = (cParams->minMatch == 3) ? 3 : 4;
+ U32 nextToUpdate3 = ms->nextToUpdate;
+
+ ZSTD_optimal_t* const opt = optStatePtr->priceTable;
+ ZSTD_match_t* const matches = optStatePtr->matchTable;
+ ZSTD_optimal_t lastSequence;
+
+ /* init */
+ DEBUGLOG(5, "ZSTD_compressBlock_opt_generic: current=%u, prefix=%u, nextToUpdate=%u",
+ (U32)(ip - base), ms->window.dictLimit, ms->nextToUpdate);
+ assert(optLevel <= 2);
+ ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize, optLevel);
+ ip += (ip==prefixStart);
+
+ /* Match Loop */
+ while (ip < ilimit) {
+ U32 cur, last_pos = 0;
+
+ /* find first match */
+ { U32 const litlen = (U32)(ip - anchor);
+ U32 const ll0 = !litlen;
+ U32 const nbMatches = ZSTD_BtGetAllMatches(matches, ms, &nextToUpdate3, ip, iend, dictMode, rep, ll0, minMatch);
+ if (!nbMatches) { ip++; continue; }
+
+ /* initialize opt[0] */
+ { U32 i ; for (i=0; i<ZSTD_REP_NUM; i++) opt[0].rep[i] = rep[i]; }
+ opt[0].mlen = 0; /* means is_a_literal */
+ opt[0].litlen = litlen;
+ /* We don't need to include the actual price of the literals because
+ * it is static for the duration of the forward pass, and is included
+ * in every price. We include the literal length to avoid negative
+ * prices when we subtract the previous literal length.
+ */
+ opt[0].price = ZSTD_litLengthPrice(litlen, optStatePtr, optLevel);
+
+ /* large match -> immediate encoding */
+ { U32 const maxML = matches[nbMatches-1].len;
+ U32 const maxOffset = matches[nbMatches-1].off;
+ DEBUGLOG(6, "found %u matches of maxLength=%u and maxOffCode=%u at cPos=%u => start new series",
+ nbMatches, maxML, maxOffset, (U32)(ip-prefixStart));
+
+ if (maxML > sufficient_len) {
+ lastSequence.litlen = litlen;
+ lastSequence.mlen = maxML;
+ lastSequence.off = maxOffset;
+ DEBUGLOG(6, "large match (%u>%u), immediate encoding",
+ maxML, sufficient_len);
+ cur = 0;
+ last_pos = ZSTD_totalLen(lastSequence);
+ goto _shortestPath;
+ } }
+
+ /* set prices for first matches starting position == 0 */
+ { U32 const literalsPrice = opt[0].price + ZSTD_litLengthPrice(0, optStatePtr, optLevel);
+ U32 pos;
+ U32 matchNb;
+ for (pos = 1; pos < minMatch; pos++) {
+ opt[pos].price = ZSTD_MAX_PRICE; /* mlen, litlen and price will be fixed during forward scanning */
+ }
+ for (matchNb = 0; matchNb < nbMatches; matchNb++) {
+ U32 const offset = matches[matchNb].off;
+ U32 const end = matches[matchNb].len;
+ for ( ; pos <= end ; pos++ ) {
+ U32 const matchPrice = ZSTD_getMatchPrice(offset, pos, optStatePtr, optLevel);
+ U32 const sequencePrice = literalsPrice + matchPrice;
+ DEBUGLOG(7, "rPos:%u => set initial price : %.2f",
+ pos, ZSTD_fCost(sequencePrice));
+ opt[pos].mlen = pos;
+ opt[pos].off = offset;
+ opt[pos].litlen = litlen;
+ opt[pos].price = sequencePrice;
+ } }
+ last_pos = pos-1;
+ }
+ }
+
+ /* check further positions */
+ for (cur = 1; cur <= last_pos; cur++) {
+ const BYTE* const inr = ip + cur;
+ assert(cur < ZSTD_OPT_NUM);
+ DEBUGLOG(7, "cPos:%zi==rPos:%u", inr-istart, cur)
+
+ /* Fix current position with one literal if cheaper */
+ { U32 const litlen = (opt[cur-1].mlen == 0) ? opt[cur-1].litlen + 1 : 1;
+ int const price = opt[cur-1].price
+ + ZSTD_rawLiteralsCost(ip+cur-1, 1, optStatePtr, optLevel)
+ + ZSTD_litLengthPrice(litlen, optStatePtr, optLevel)
+ - ZSTD_litLengthPrice(litlen-1, optStatePtr, optLevel);
+ assert(price < 1000000000); /* overflow check */
+ if (price <= opt[cur].price) {
+ DEBUGLOG(7, "cPos:%zi==rPos:%u : better price (%.2f<=%.2f) using literal (ll==%u) (hist:%u,%u,%u)",
+ inr-istart, cur, ZSTD_fCost(price), ZSTD_fCost(opt[cur].price), litlen,
+ opt[cur-1].rep[0], opt[cur-1].rep[1], opt[cur-1].rep[2]);
+ opt[cur].mlen = 0;
+ opt[cur].off = 0;
+ opt[cur].litlen = litlen;
+ opt[cur].price = price;
+ } else {
+ DEBUGLOG(7, "cPos:%zi==rPos:%u : literal would cost more (%.2f>%.2f) (hist:%u,%u,%u)",
+ inr-istart, cur, ZSTD_fCost(price), ZSTD_fCost(opt[cur].price),
+ opt[cur].rep[0], opt[cur].rep[1], opt[cur].rep[2]);
+ }
+ }
+
+ /* Set the repcodes of the current position. We must do it here
+ * because we rely on the repcodes of the 2nd to last sequence being
+ * correct to set the next chunks repcodes during the backward
+ * traversal.
+ */
+ ZSTD_STATIC_ASSERT(sizeof(opt[cur].rep) == sizeof(repcodes_t));
+ assert(cur >= opt[cur].mlen);
+ if (opt[cur].mlen != 0) {
+ U32 const prev = cur - opt[cur].mlen;
+ repcodes_t newReps = ZSTD_updateRep(opt[prev].rep, opt[cur].off, opt[cur].litlen==0);
+ memcpy(opt[cur].rep, &newReps, sizeof(repcodes_t));
+ } else {
+ memcpy(opt[cur].rep, opt[cur - 1].rep, sizeof(repcodes_t));
+ }
+
+ /* last match must start at a minimum distance of 8 from oend */
+ if (inr > ilimit) continue;
+
+ if (cur == last_pos) break;
+
+ if ( (optLevel==0) /*static_test*/
+ && (opt[cur+1].price <= opt[cur].price + (BITCOST_MULTIPLIER/2)) ) {
+ DEBUGLOG(7, "move to next rPos:%u : price is <=", cur+1);
+ continue; /* skip unpromising positions; about ~+6% speed, -0.01 ratio */
+ }
+
+ { U32 const ll0 = (opt[cur].mlen != 0);
+ U32 const litlen = (opt[cur].mlen == 0) ? opt[cur].litlen : 0;
+ U32 const previousPrice = opt[cur].price;
+ U32 const basePrice = previousPrice + ZSTD_litLengthPrice(0, optStatePtr, optLevel);
+ U32 const nbMatches = ZSTD_BtGetAllMatches(matches, ms, &nextToUpdate3, inr, iend, dictMode, opt[cur].rep, ll0, minMatch);
+ U32 matchNb;
+ if (!nbMatches) {
+ DEBUGLOG(7, "rPos:%u : no match found", cur);
+ continue;
+ }
+
+ { U32 const maxML = matches[nbMatches-1].len;
+ DEBUGLOG(7, "cPos:%zi==rPos:%u, found %u matches, of maxLength=%u",
+ inr-istart, cur, nbMatches, maxML);
+
+ if ( (maxML > sufficient_len)
+ || (cur + maxML >= ZSTD_OPT_NUM) ) {
+ lastSequence.mlen = maxML;
+ lastSequence.off = matches[nbMatches-1].off;
+ lastSequence.litlen = litlen;
+ cur -= (opt[cur].mlen==0) ? opt[cur].litlen : 0; /* last sequence is actually only literals, fix cur to last match - note : may underflow, in which case, it's first sequence, and it's okay */
+ last_pos = cur + ZSTD_totalLen(lastSequence);
+ if (cur > ZSTD_OPT_NUM) cur = 0; /* underflow => first match */
+ goto _shortestPath;
+ } }
+
+ /* set prices using matches found at position == cur */
+ for (matchNb = 0; matchNb < nbMatches; matchNb++) {
+ U32 const offset = matches[matchNb].off;
+ U32 const lastML = matches[matchNb].len;
+ U32 const startML = (matchNb>0) ? matches[matchNb-1].len+1 : minMatch;
+ U32 mlen;
+
+ DEBUGLOG(7, "testing match %u => offCode=%4u, mlen=%2u, llen=%2u",
+ matchNb, matches[matchNb].off, lastML, litlen);
+
+ for (mlen = lastML; mlen >= startML; mlen--) { /* scan downward */
+ U32 const pos = cur + mlen;
+ int const price = basePrice + ZSTD_getMatchPrice(offset, mlen, optStatePtr, optLevel);
+
+ if ((pos > last_pos) || (price < opt[pos].price)) {
+ DEBUGLOG(7, "rPos:%u (ml=%2u) => new better price (%.2f<%.2f)",
+ pos, mlen, ZSTD_fCost(price), ZSTD_fCost(opt[pos].price));
+ while (last_pos < pos) { opt[last_pos+1].price = ZSTD_MAX_PRICE; last_pos++; } /* fill empty positions */
+ opt[pos].mlen = mlen;
+ opt[pos].off = offset;
+ opt[pos].litlen = litlen;
+ opt[pos].price = price;
+ } else {
+ DEBUGLOG(7, "rPos:%u (ml=%2u) => new price is worse (%.2f>=%.2f)",
+ pos, mlen, ZSTD_fCost(price), ZSTD_fCost(opt[pos].price));
+ if (optLevel==0) break; /* early update abort; gets ~+10% speed for about -0.01 ratio loss */
+ }
+ } } }
+ } /* for (cur = 1; cur <= last_pos; cur++) */
+
+ lastSequence = opt[last_pos];
+ cur = last_pos > ZSTD_totalLen(lastSequence) ? last_pos - ZSTD_totalLen(lastSequence) : 0; /* single sequence, and it starts before `ip` */
+ assert(cur < ZSTD_OPT_NUM); /* control overflow*/
+
+_shortestPath: /* cur, last_pos, best_mlen, best_off have to be set */
+ assert(opt[0].mlen == 0);
+
+ /* Set the next chunk's repcodes based on the repcodes of the beginning
+ * of the last match, and the last sequence. This avoids us having to
+ * update them while traversing the sequences.
+ */
+ if (lastSequence.mlen != 0) {
+ repcodes_t reps = ZSTD_updateRep(opt[cur].rep, lastSequence.off, lastSequence.litlen==0);
+ memcpy(rep, &reps, sizeof(reps));
+ } else {
+ memcpy(rep, opt[cur].rep, sizeof(repcodes_t));
+ }
+
+ { U32 const storeEnd = cur + 1;
+ U32 storeStart = storeEnd;
+ U32 seqPos = cur;
+
+ DEBUGLOG(6, "start reverse traversal (last_pos:%u, cur:%u)",
+ last_pos, cur); (void)last_pos;
+ assert(storeEnd < ZSTD_OPT_NUM);
+ DEBUGLOG(6, "last sequence copied into pos=%u (llen=%u,mlen=%u,ofc=%u)",
+ storeEnd, lastSequence.litlen, lastSequence.mlen, lastSequence.off);
+ opt[storeEnd] = lastSequence;
+ while (seqPos > 0) {
+ U32 const backDist = ZSTD_totalLen(opt[seqPos]);
+ storeStart--;
+ DEBUGLOG(6, "sequence from rPos=%u copied into pos=%u (llen=%u,mlen=%u,ofc=%u)",
+ seqPos, storeStart, opt[seqPos].litlen, opt[seqPos].mlen, opt[seqPos].off);
+ opt[storeStart] = opt[seqPos];
+ seqPos = (seqPos > backDist) ? seqPos - backDist : 0;
+ }
+
+ /* save sequences */
+ DEBUGLOG(6, "sending selected sequences into seqStore")
+ { U32 storePos;
+ for (storePos=storeStart; storePos <= storeEnd; storePos++) {
+ U32 const llen = opt[storePos].litlen;
+ U32 const mlen = opt[storePos].mlen;
+ U32 const offCode = opt[storePos].off;
+ U32 const advance = llen + mlen;
+ DEBUGLOG(6, "considering seq starting at %zi, llen=%u, mlen=%u",
+ anchor - istart, (unsigned)llen, (unsigned)mlen);
+
+ if (mlen==0) { /* only literals => must be last "sequence", actually starting a new stream of sequences */
+ assert(storePos == storeEnd); /* must be last sequence */
+ ip = anchor + llen; /* last "sequence" is a bunch of literals => don't progress anchor */
+ continue; /* will finish */
+ }
+
+ assert(anchor + llen <= iend);
+ ZSTD_updateStats(optStatePtr, llen, anchor, offCode, mlen);
+ ZSTD_storeSeq(seqStore, llen, anchor, iend, offCode, mlen-MINMATCH);
+ anchor += advance;
+ ip = anchor;
+ } }
+ ZSTD_setBasePrices(optStatePtr, optLevel);
+ }
+ } /* while (ip < ilimit) */
+
+ /* Return the last literals size */
+ return (size_t)(iend - anchor);
+}
+
+
+size_t ZSTD_compressBlock_btopt(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ const void* src, size_t srcSize)
+{
+ DEBUGLOG(5, "ZSTD_compressBlock_btopt");
+ return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /*optLevel*/, ZSTD_noDict);
+}
+
+
+/* used in 2-pass strategy */
+static U32 ZSTD_upscaleStat(unsigned* table, U32 lastEltIndex, int bonus)
+{
+ U32 s, sum=0;
+ assert(ZSTD_FREQ_DIV+bonus >= 0);
+ for (s=0; s<lastEltIndex+1; s++) {
+ table[s] <<= ZSTD_FREQ_DIV+bonus;
+ table[s]--;
+ sum += table[s];
+ }
+ return sum;
+}
+
+/* used in 2-pass strategy */
+MEM_STATIC void ZSTD_upscaleStats(optState_t* optPtr)
+{
+ if (ZSTD_compressedLiterals(optPtr))
+ optPtr->litSum = ZSTD_upscaleStat(optPtr->litFreq, MaxLit, 0);
+ optPtr->litLengthSum = ZSTD_upscaleStat(optPtr->litLengthFreq, MaxLL, 0);
+ optPtr->matchLengthSum = ZSTD_upscaleStat(optPtr->matchLengthFreq, MaxML, 0);
+ optPtr->offCodeSum = ZSTD_upscaleStat(optPtr->offCodeFreq, MaxOff, 0);
+}
+
+/* ZSTD_initStats_ultra():
+ * make a first compression pass, just to seed stats with more accurate starting values.
+ * only works on first block, with no dictionary and no ldm.
+ * this function cannot error, hence its contract must be respected.
+ */
+static void
+ZSTD_initStats_ultra(ZSTD_matchState_t* ms,
+ seqStore_t* seqStore,
+ U32 rep[ZSTD_REP_NUM],
+ const void* src, size_t srcSize)
+{
+ U32 tmpRep[ZSTD_REP_NUM]; /* updated rep codes will sink here */
+ memcpy(tmpRep, rep, sizeof(tmpRep));
+
+ DEBUGLOG(4, "ZSTD_initStats_ultra (srcSize=%zu)", srcSize);
+ assert(ms->opt.litLengthSum == 0); /* first block */
+ assert(seqStore->sequences == seqStore->sequencesStart); /* no ldm */
+ assert(ms->window.dictLimit == ms->window.lowLimit); /* no dictionary */
+ assert(ms->window.dictLimit - ms->nextToUpdate <= 1); /* no prefix (note: intentional overflow, defined as 2-complement) */
+
+ ZSTD_compressBlock_opt_generic(ms, seqStore, tmpRep, src, srcSize, 2 /*optLevel*/, ZSTD_noDict); /* generate stats into ms->opt*/
+
+ /* invalidate first scan from history */
+ ZSTD_resetSeqStore(seqStore);
+ ms->window.base -= srcSize;
+ ms->window.dictLimit += (U32)srcSize;
+ ms->window.lowLimit = ms->window.dictLimit;
+ ms->nextToUpdate = ms->window.dictLimit;
+
+ /* re-inforce weight of collected statistics */
+ ZSTD_upscaleStats(&ms->opt);
+}
+
+size_t ZSTD_compressBlock_btultra(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ const void* src, size_t srcSize)
+{
+ DEBUGLOG(5, "ZSTD_compressBlock_btultra (srcSize=%zu)", srcSize);
+ return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_noDict);
+}
+
+size_t ZSTD_compressBlock_btultra2(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ const void* src, size_t srcSize)
+{
+ U32 const current = (U32)((const BYTE*)src - ms->window.base);
+ DEBUGLOG(5, "ZSTD_compressBlock_btultra2 (srcSize=%zu)", srcSize);
+
+ /* 2-pass strategy:
+ * this strategy makes a first pass over first block to collect statistics
+ * and seed next round's statistics with it.
+ * After 1st pass, function forgets everything, and starts a new block.
+ * Consequently, this can only work if no data has been previously loaded in tables,
+ * aka, no dictionary, no prefix, no ldm preprocessing.
+ * The compression ratio gain is generally small (~0.5% on first block),
+ * the cost is 2x cpu time on first block. */
+ assert(srcSize <= ZSTD_BLOCKSIZE_MAX);
+ if ( (ms->opt.litLengthSum==0) /* first block */
+ && (seqStore->sequences == seqStore->sequencesStart) /* no ldm */
+ && (ms->window.dictLimit == ms->window.lowLimit) /* no dictionary */
+ && (current == ms->window.dictLimit) /* start of frame, nothing already loaded nor skipped */
+ && (srcSize > ZSTD_PREDEF_THRESHOLD)
+ ) {
+ ZSTD_initStats_ultra(ms, seqStore, rep, src, srcSize);
+ }
+
+ return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_noDict);
+}
+
+size_t ZSTD_compressBlock_btopt_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ const void* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /*optLevel*/, ZSTD_dictMatchState);
+}
+
+size_t ZSTD_compressBlock_btultra_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ const void* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_dictMatchState);
+}
+
+size_t ZSTD_compressBlock_btopt_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ const void* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /*optLevel*/, ZSTD_extDict);
+}
+
+size_t ZSTD_compressBlock_btultra_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ const void* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_extDict);
+}
+
+/* note : no btultra2 variant for extDict nor dictMatchState,
+ * because btultra2 is not meant to work with dictionaries
+ * and is only specific for the first block (no prefix) */
diff --git a/sys/contrib/openzfs/module/zstd/lib/compress/zstd_opt.h b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_opt.h
new file mode 100644
index 000000000000..9aba8a9018c5
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/compress/zstd_opt.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_OPT_H
+#define ZSTD_OPT_H
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#include "zstd_compress_internal.h"
+
+/* used in ZSTD_loadDictionaryContent() */
+void ZSTD_updateTree(ZSTD_matchState_t* ms, const BYTE* ip, const BYTE* iend);
+
+size_t ZSTD_compressBlock_btopt(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_btultra(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_btultra2(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+
+
+size_t ZSTD_compressBlock_btopt_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_btultra_dictMatchState(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+
+size_t ZSTD_compressBlock_btopt_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_btultra_extDict(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+
+ /* note : no btultra2 variant for extDict nor dictMatchState,
+ * because btultra2 is not meant to work with dictionaries
+ * and is only specific for the first block (no prefix) */
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* ZSTD_OPT_H */
diff --git a/sys/contrib/openzfs/module/zstd/lib/decompress/huf_decompress.c b/sys/contrib/openzfs/module/zstd/lib/decompress/huf_decompress.c
new file mode 100644
index 000000000000..68293a13096a
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/decompress/huf_decompress.c
@@ -0,0 +1,1248 @@
+/* ******************************************************************
+ * huff0 huffman decoder,
+ * part of Finite State Entropy library
+ * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ *
+ * You can contact the author at :
+ * - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+****************************************************************** */
+
+/* **************************************************************
+* Dependencies
+****************************************************************/
+#include <string.h> /* memcpy, memset */
+#include "../common/compiler.h"
+#include "../common/bitstream.h" /* BIT_* */
+#include "../common/fse.h" /* to compress headers */
+#define HUF_STATIC_LINKING_ONLY
+#include "../common/huf.h"
+#include "../common/error_private.h"
+
+/* **************************************************************
+* Macros
+****************************************************************/
+
+/* These two optional macros force the use one way or another of the two
+ * Huffman decompression implementations. You can't force in both directions
+ * at the same time.
+ */
+#if defined(HUF_FORCE_DECOMPRESS_X1) && \
+ defined(HUF_FORCE_DECOMPRESS_X2)
+#error "Cannot force the use of the X1 and X2 decoders at the same time!"
+#endif
+
+
+/* **************************************************************
+* Error Management
+****************************************************************/
+#define HUF_isError ERR_isError
+
+
+/* **************************************************************
+* Byte alignment for workSpace management
+****************************************************************/
+#define HUF_ALIGN(x, a) HUF_ALIGN_MASK((x), (a) - 1)
+#define HUF_ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
+
+
+/* **************************************************************
+* BMI2 Variant Wrappers
+****************************************************************/
+#if DYNAMIC_BMI2
+
+#define HUF_DGEN(fn) \
+ \
+ static size_t fn##_default( \
+ void* dst, size_t dstSize, \
+ const void* cSrc, size_t cSrcSize, \
+ const HUF_DTable* DTable) \
+ { \
+ return fn##_body(dst, dstSize, cSrc, cSrcSize, DTable); \
+ } \
+ \
+ static TARGET_ATTRIBUTE("bmi2") size_t fn##_bmi2( \
+ void* dst, size_t dstSize, \
+ const void* cSrc, size_t cSrcSize, \
+ const HUF_DTable* DTable) \
+ { \
+ return fn##_body(dst, dstSize, cSrc, cSrcSize, DTable); \
+ } \
+ \
+ static size_t fn(void* dst, size_t dstSize, void const* cSrc, \
+ size_t cSrcSize, HUF_DTable const* DTable, int bmi2) \
+ { \
+ if (bmi2) { \
+ return fn##_bmi2(dst, dstSize, cSrc, cSrcSize, DTable); \
+ } \
+ return fn##_default(dst, dstSize, cSrc, cSrcSize, DTable); \
+ }
+
+#else
+
+#define HUF_DGEN(fn) \
+ static size_t fn(void* dst, size_t dstSize, void const* cSrc, \
+ size_t cSrcSize, HUF_DTable const* DTable, int bmi2) \
+ { \
+ (void)bmi2; \
+ return fn##_body(dst, dstSize, cSrc, cSrcSize, DTable); \
+ }
+
+#endif
+
+
+/*-***************************/
+/* generic DTableDesc */
+/*-***************************/
+typedef struct { BYTE maxTableLog; BYTE tableType; BYTE tableLog; BYTE reserved; } DTableDesc;
+
+static DTableDesc HUF_getDTableDesc(const HUF_DTable* table)
+{
+ DTableDesc dtd;
+ memcpy(&dtd, table, sizeof(dtd));
+ return dtd;
+}
+
+
+#ifndef HUF_FORCE_DECOMPRESS_X2
+
+/*-***************************/
+/* single-symbol decoding */
+/*-***************************/
+typedef struct { BYTE byte; BYTE nbBits; } HUF_DEltX1; /* single-symbol decoding */
+
+size_t HUF_readDTableX1_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize)
+{
+ U32 tableLog = 0;
+ U32 nbSymbols = 0;
+ size_t iSize;
+ void* const dtPtr = DTable + 1;
+ HUF_DEltX1* const dt = (HUF_DEltX1*)dtPtr;
+
+ U32* rankVal;
+ BYTE* huffWeight;
+ size_t spaceUsed32 = 0;
+
+ rankVal = (U32 *)workSpace + spaceUsed32;
+ spaceUsed32 += HUF_TABLELOG_ABSOLUTEMAX + 1;
+ huffWeight = (BYTE *)((U32 *)workSpace + spaceUsed32);
+ spaceUsed32 += HUF_ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2;
+
+ if ((spaceUsed32 << 2) > wkspSize) return ERROR(tableLog_tooLarge);
+
+ DEBUG_STATIC_ASSERT(sizeof(DTableDesc) == sizeof(HUF_DTable));
+ /* memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */
+
+ iSize = HUF_readStats(huffWeight, HUF_SYMBOLVALUE_MAX + 1, rankVal, &nbSymbols, &tableLog, src, srcSize);
+ if (HUF_isError(iSize)) return iSize;
+
+ /* Table header */
+ { DTableDesc dtd = HUF_getDTableDesc(DTable);
+ if (tableLog > (U32)(dtd.maxTableLog+1)) return ERROR(tableLog_tooLarge); /* DTable too small, Huffman tree cannot fit in */
+ dtd.tableType = 0;
+ dtd.tableLog = (BYTE)tableLog;
+ memcpy(DTable, &dtd, sizeof(dtd));
+ }
+
+ /* Calculate starting value for each rank */
+ { U32 n, nextRankStart = 0;
+ for (n=1; n<tableLog+1; n++) {
+ U32 const current = nextRankStart;
+ nextRankStart += (rankVal[n] << (n-1));
+ rankVal[n] = current;
+ } }
+
+ /* fill DTable */
+ { U32 n;
+ size_t const nEnd = nbSymbols;
+ for (n=0; n<nEnd; n++) {
+ size_t const w = huffWeight[n];
+ size_t const length = (1 << w) >> 1;
+ size_t const uStart = rankVal[w];
+ size_t const uEnd = uStart + length;
+ size_t u;
+ HUF_DEltX1 D;
+ D.byte = (BYTE)n;
+ D.nbBits = (BYTE)(tableLog + 1 - w);
+ rankVal[w] = (U32)uEnd;
+ if (length < 4) {
+ /* Use length in the loop bound so the compiler knows it is short. */
+ for (u = 0; u < length; ++u)
+ dt[uStart + u] = D;
+ } else {
+ /* Unroll the loop 4 times, we know it is a power of 2. */
+ for (u = uStart; u < uEnd; u += 4) {
+ dt[u + 0] = D;
+ dt[u + 1] = D;
+ dt[u + 2] = D;
+ dt[u + 3] = D;
+ } } } }
+ return iSize;
+}
+
+size_t HUF_readDTableX1(HUF_DTable* DTable, const void* src, size_t srcSize)
+{
+ U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+ return HUF_readDTableX1_wksp(DTable, src, srcSize,
+ workSpace, sizeof(workSpace));
+}
+
+FORCE_INLINE_TEMPLATE BYTE
+HUF_decodeSymbolX1(BIT_DStream_t* Dstream, const HUF_DEltX1* dt, const U32 dtLog)
+{
+ size_t const val = BIT_lookBitsFast(Dstream, dtLog); /* note : dtLog >= 1 */
+ BYTE const c = dt[val].byte;
+ BIT_skipBits(Dstream, dt[val].nbBits);
+ return c;
+}
+
+#define HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr) \
+ *ptr++ = HUF_decodeSymbolX1(DStreamPtr, dt, dtLog)
+
+#define HUF_DECODE_SYMBOLX1_1(ptr, DStreamPtr) \
+ if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \
+ HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr)
+
+#define HUF_DECODE_SYMBOLX1_2(ptr, DStreamPtr) \
+ if (MEM_64bits()) \
+ HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr)
+
+HINT_INLINE size_t
+HUF_decodeStreamX1(BYTE* p, BIT_DStream_t* const bitDPtr, BYTE* const pEnd, const HUF_DEltX1* const dt, const U32 dtLog)
+{
+ BYTE* const pStart = p;
+
+ /* up to 4 symbols at a time */
+ while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-3)) {
+ HUF_DECODE_SYMBOLX1_2(p, bitDPtr);
+ HUF_DECODE_SYMBOLX1_1(p, bitDPtr);
+ HUF_DECODE_SYMBOLX1_2(p, bitDPtr);
+ HUF_DECODE_SYMBOLX1_0(p, bitDPtr);
+ }
+
+ /* [0-3] symbols remaining */
+ if (MEM_32bits())
+ while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd))
+ HUF_DECODE_SYMBOLX1_0(p, bitDPtr);
+
+ /* no more data to retrieve from bitstream, no need to reload */
+ while (p < pEnd)
+ HUF_DECODE_SYMBOLX1_0(p, bitDPtr);
+
+ return pEnd-pStart;
+}
+
+FORCE_INLINE_TEMPLATE size_t
+HUF_decompress1X1_usingDTable_internal_body(
+ void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize,
+ const HUF_DTable* DTable)
+{
+ BYTE* op = (BYTE*)dst;
+ BYTE* const oend = op + dstSize;
+ const void* dtPtr = DTable + 1;
+ const HUF_DEltX1* const dt = (const HUF_DEltX1*)dtPtr;
+ BIT_DStream_t bitD;
+ DTableDesc const dtd = HUF_getDTableDesc(DTable);
+ U32 const dtLog = dtd.tableLog;
+
+ CHECK_F( BIT_initDStream(&bitD, cSrc, cSrcSize) );
+
+ HUF_decodeStreamX1(op, &bitD, oend, dt, dtLog);
+
+ if (!BIT_endOfDStream(&bitD)) return ERROR(corruption_detected);
+
+ return dstSize;
+}
+
+FORCE_INLINE_TEMPLATE size_t
+HUF_decompress4X1_usingDTable_internal_body(
+ void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize,
+ const HUF_DTable* DTable)
+{
+ /* Check */
+ if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */
+
+ { const BYTE* const istart = (const BYTE*) cSrc;
+ BYTE* const ostart = (BYTE*) dst;
+ BYTE* const oend = ostart + dstSize;
+ BYTE* const olimit = oend - 3;
+ const void* const dtPtr = DTable + 1;
+ const HUF_DEltX1* const dt = (const HUF_DEltX1*)dtPtr;
+
+ /* Init */
+ BIT_DStream_t bitD1;
+ BIT_DStream_t bitD2;
+ BIT_DStream_t bitD3;
+ BIT_DStream_t bitD4;
+ size_t const length1 = MEM_readLE16(istart);
+ size_t const length2 = MEM_readLE16(istart+2);
+ size_t const length3 = MEM_readLE16(istart+4);
+ size_t const length4 = cSrcSize - (length1 + length2 + length3 + 6);
+ const BYTE* const istart1 = istart + 6; /* jumpTable */
+ const BYTE* const istart2 = istart1 + length1;
+ const BYTE* const istart3 = istart2 + length2;
+ const BYTE* const istart4 = istart3 + length3;
+ const size_t segmentSize = (dstSize+3) / 4;
+ BYTE* const opStart2 = ostart + segmentSize;
+ BYTE* const opStart3 = opStart2 + segmentSize;
+ BYTE* const opStart4 = opStart3 + segmentSize;
+ BYTE* op1 = ostart;
+ BYTE* op2 = opStart2;
+ BYTE* op3 = opStart3;
+ BYTE* op4 = opStart4;
+ DTableDesc const dtd = HUF_getDTableDesc(DTable);
+ U32 const dtLog = dtd.tableLog;
+ U32 endSignal = 1;
+
+ if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */
+ CHECK_F( BIT_initDStream(&bitD1, istart1, length1) );
+ CHECK_F( BIT_initDStream(&bitD2, istart2, length2) );
+ CHECK_F( BIT_initDStream(&bitD3, istart3, length3) );
+ CHECK_F( BIT_initDStream(&bitD4, istart4, length4) );
+
+ /* up to 16 symbols per loop (4 symbols per stream) in 64-bit mode */
+ for ( ; (endSignal) & (op4 < olimit) ; ) {
+ HUF_DECODE_SYMBOLX1_2(op1, &bitD1);
+ HUF_DECODE_SYMBOLX1_2(op2, &bitD2);
+ HUF_DECODE_SYMBOLX1_2(op3, &bitD3);
+ HUF_DECODE_SYMBOLX1_2(op4, &bitD4);
+ HUF_DECODE_SYMBOLX1_1(op1, &bitD1);
+ HUF_DECODE_SYMBOLX1_1(op2, &bitD2);
+ HUF_DECODE_SYMBOLX1_1(op3, &bitD3);
+ HUF_DECODE_SYMBOLX1_1(op4, &bitD4);
+ HUF_DECODE_SYMBOLX1_2(op1, &bitD1);
+ HUF_DECODE_SYMBOLX1_2(op2, &bitD2);
+ HUF_DECODE_SYMBOLX1_2(op3, &bitD3);
+ HUF_DECODE_SYMBOLX1_2(op4, &bitD4);
+ HUF_DECODE_SYMBOLX1_0(op1, &bitD1);
+ HUF_DECODE_SYMBOLX1_0(op2, &bitD2);
+ HUF_DECODE_SYMBOLX1_0(op3, &bitD3);
+ HUF_DECODE_SYMBOLX1_0(op4, &bitD4);
+ endSignal &= BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished;
+ endSignal &= BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished;
+ endSignal &= BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished;
+ endSignal &= BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished;
+ }
+
+ /* check corruption */
+ /* note : should not be necessary : op# advance in lock step, and we control op4.
+ * but curiously, binary generated by gcc 7.2 & 7.3 with -mbmi2 runs faster when >=1 test is present */
+ if (op1 > opStart2) return ERROR(corruption_detected);
+ if (op2 > opStart3) return ERROR(corruption_detected);
+ if (op3 > opStart4) return ERROR(corruption_detected);
+ /* note : op4 supposed already verified within main loop */
+
+ /* finish bitStreams one by one */
+ HUF_decodeStreamX1(op1, &bitD1, opStart2, dt, dtLog);
+ HUF_decodeStreamX1(op2, &bitD2, opStart3, dt, dtLog);
+ HUF_decodeStreamX1(op3, &bitD3, opStart4, dt, dtLog);
+ HUF_decodeStreamX1(op4, &bitD4, oend, dt, dtLog);
+
+ /* check */
+ { U32 const endCheck = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4);
+ if (!endCheck) return ERROR(corruption_detected); }
+
+ /* decoded size */
+ return dstSize;
+ }
+}
+
+
+typedef size_t (*HUF_decompress_usingDTable_t)(void *dst, size_t dstSize,
+ const void *cSrc,
+ size_t cSrcSize,
+ const HUF_DTable *DTable);
+
+HUF_DGEN(HUF_decompress1X1_usingDTable_internal)
+HUF_DGEN(HUF_decompress4X1_usingDTable_internal)
+
+
+
+size_t HUF_decompress1X1_usingDTable(
+ void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize,
+ const HUF_DTable* DTable)
+{
+ DTableDesc dtd = HUF_getDTableDesc(DTable);
+ if (dtd.tableType != 0) return ERROR(GENERIC);
+ return HUF_decompress1X1_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
+}
+
+size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize,
+ void* workSpace, size_t wkspSize)
+{
+ const BYTE* ip = (const BYTE*) cSrc;
+
+ size_t const hSize = HUF_readDTableX1_wksp(DCtx, cSrc, cSrcSize, workSpace, wkspSize);
+ if (HUF_isError(hSize)) return hSize;
+ if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
+ ip += hSize; cSrcSize -= hSize;
+
+ return HUF_decompress1X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx, /* bmi2 */ 0);
+}
+
+
+size_t HUF_decompress1X1_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize)
+{
+ U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+ return HUF_decompress1X1_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize,
+ workSpace, sizeof(workSpace));
+}
+
+size_t HUF_decompress1X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+ HUF_CREATE_STATIC_DTABLEX1(DTable, HUF_TABLELOG_MAX);
+ return HUF_decompress1X1_DCtx (DTable, dst, dstSize, cSrc, cSrcSize);
+}
+
+size_t HUF_decompress4X1_usingDTable(
+ void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize,
+ const HUF_DTable* DTable)
+{
+ DTableDesc dtd = HUF_getDTableDesc(DTable);
+ if (dtd.tableType != 0) return ERROR(GENERIC);
+ return HUF_decompress4X1_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
+}
+
+static size_t HUF_decompress4X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize,
+ void* workSpace, size_t wkspSize, int bmi2)
+{
+ const BYTE* ip = (const BYTE*) cSrc;
+
+ size_t const hSize = HUF_readDTableX1_wksp (dctx, cSrc, cSrcSize,
+ workSpace, wkspSize);
+ if (HUF_isError(hSize)) return hSize;
+ if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
+ ip += hSize; cSrcSize -= hSize;
+
+ return HUF_decompress4X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2);
+}
+
+size_t HUF_decompress4X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize,
+ void* workSpace, size_t wkspSize)
+{
+ return HUF_decompress4X1_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, 0);
+}
+
+
+size_t HUF_decompress4X1_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+ U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+ return HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize,
+ workSpace, sizeof(workSpace));
+}
+size_t HUF_decompress4X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+ HUF_CREATE_STATIC_DTABLEX1(DTable, HUF_TABLELOG_MAX);
+ return HUF_decompress4X1_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);
+}
+
+#endif /* HUF_FORCE_DECOMPRESS_X2 */
+
+
+#ifndef HUF_FORCE_DECOMPRESS_X1
+
+/* *************************/
+/* double-symbols decoding */
+/* *************************/
+
+typedef struct { U16 sequence; BYTE nbBits; BYTE length; } HUF_DEltX2; /* double-symbols decoding */
+typedef struct { BYTE symbol; BYTE weight; } sortedSymbol_t;
+typedef U32 rankValCol_t[HUF_TABLELOG_MAX + 1];
+typedef rankValCol_t rankVal_t[HUF_TABLELOG_MAX];
+
+
+/* HUF_fillDTableX2Level2() :
+ * `rankValOrigin` must be a table of at least (HUF_TABLELOG_MAX + 1) U32 */
+static void HUF_fillDTableX2Level2(HUF_DEltX2* DTable, U32 sizeLog, const U32 consumed,
+ const U32* rankValOrigin, const int minWeight,
+ const sortedSymbol_t* sortedSymbols, const U32 sortedListSize,
+ U32 nbBitsBaseline, U16 baseSeq)
+{
+ HUF_DEltX2 DElt;
+ U32 rankVal[HUF_TABLELOG_MAX + 1];
+
+ /* get pre-calculated rankVal */
+ memcpy(rankVal, rankValOrigin, sizeof(rankVal));
+
+ /* fill skipped values */
+ if (minWeight>1) {
+ U32 i, skipSize = rankVal[minWeight];
+ MEM_writeLE16(&(DElt.sequence), baseSeq);
+ DElt.nbBits = (BYTE)(consumed);
+ DElt.length = 1;
+ for (i = 0; i < skipSize; i++)
+ DTable[i] = DElt;
+ }
+
+ /* fill DTable */
+ { U32 s; for (s=0; s<sortedListSize; s++) { /* note : sortedSymbols already skipped */
+ const U32 symbol = sortedSymbols[s].symbol;
+ const U32 weight = sortedSymbols[s].weight;
+ const U32 nbBits = nbBitsBaseline - weight;
+ const U32 length = 1 << (sizeLog-nbBits);
+ const U32 start = rankVal[weight];
+ U32 i = start;
+ const U32 end = start + length;
+
+ MEM_writeLE16(&(DElt.sequence), (U16)(baseSeq + (symbol << 8)));
+ DElt.nbBits = (BYTE)(nbBits + consumed);
+ DElt.length = 2;
+ do { DTable[i++] = DElt; } while (i<end); /* since length >= 1 */
+
+ rankVal[weight] += length;
+ } }
+}
+
+
+static void HUF_fillDTableX2(HUF_DEltX2* DTable, const U32 targetLog,
+ const sortedSymbol_t* sortedList, const U32 sortedListSize,
+ const U32* rankStart, rankVal_t rankValOrigin, const U32 maxWeight,
+ const U32 nbBitsBaseline)
+{
+ U32 rankVal[HUF_TABLELOG_MAX + 1];
+ const int scaleLog = nbBitsBaseline - targetLog; /* note : targetLog >= srcLog, hence scaleLog <= 1 */
+ const U32 minBits = nbBitsBaseline - maxWeight;
+ U32 s;
+
+ memcpy(rankVal, rankValOrigin, sizeof(rankVal));
+
+ /* fill DTable */
+ for (s=0; s<sortedListSize; s++) {
+ const U16 symbol = sortedList[s].symbol;
+ const U32 weight = sortedList[s].weight;
+ const U32 nbBits = nbBitsBaseline - weight;
+ const U32 start = rankVal[weight];
+ const U32 length = 1 << (targetLog-nbBits);
+
+ if (targetLog-nbBits >= minBits) { /* enough room for a second symbol */
+ U32 sortedRank;
+ int minWeight = nbBits + scaleLog;
+ if (minWeight < 1) minWeight = 1;
+ sortedRank = rankStart[minWeight];
+ HUF_fillDTableX2Level2(DTable+start, targetLog-nbBits, nbBits,
+ rankValOrigin[nbBits], minWeight,
+ sortedList+sortedRank, sortedListSize-sortedRank,
+ nbBitsBaseline, symbol);
+ } else {
+ HUF_DEltX2 DElt;
+ MEM_writeLE16(&(DElt.sequence), symbol);
+ DElt.nbBits = (BYTE)(nbBits);
+ DElt.length = 1;
+ { U32 const end = start + length;
+ U32 u;
+ for (u = start; u < end; u++) DTable[u] = DElt;
+ } }
+ rankVal[weight] += length;
+ }
+}
+
+size_t HUF_readDTableX2_wksp(HUF_DTable* DTable,
+ const void* src, size_t srcSize,
+ void* workSpace, size_t wkspSize)
+{
+ U32 tableLog, maxW, sizeOfSort, nbSymbols;
+ DTableDesc dtd = HUF_getDTableDesc(DTable);
+ U32 const maxTableLog = dtd.maxTableLog;
+ size_t iSize;
+ void* dtPtr = DTable+1; /* force compiler to avoid strict-aliasing */
+ HUF_DEltX2* const dt = (HUF_DEltX2*)dtPtr;
+ U32 *rankStart;
+
+ rankValCol_t* rankVal;
+ U32* rankStats;
+ U32* rankStart0;
+ sortedSymbol_t* sortedSymbol;
+ BYTE* weightList;
+ size_t spaceUsed32 = 0;
+
+ rankVal = (rankValCol_t *)((U32 *)workSpace + spaceUsed32);
+ spaceUsed32 += (sizeof(rankValCol_t) * HUF_TABLELOG_MAX) >> 2;
+ rankStats = (U32 *)workSpace + spaceUsed32;
+ spaceUsed32 += HUF_TABLELOG_MAX + 1;
+ rankStart0 = (U32 *)workSpace + spaceUsed32;
+ spaceUsed32 += HUF_TABLELOG_MAX + 2;
+ sortedSymbol = (sortedSymbol_t *)workSpace + (spaceUsed32 * sizeof(U32)) / sizeof(sortedSymbol_t);
+ spaceUsed32 += HUF_ALIGN(sizeof(sortedSymbol_t) * (HUF_SYMBOLVALUE_MAX + 1), sizeof(U32)) >> 2;
+ weightList = (BYTE *)((U32 *)workSpace + spaceUsed32);
+ spaceUsed32 += HUF_ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2;
+
+ if ((spaceUsed32 << 2) > wkspSize) return ERROR(tableLog_tooLarge);
+
+ rankStart = rankStart0 + 1;
+ memset(rankStats, 0, sizeof(U32) * (2 * HUF_TABLELOG_MAX + 2 + 1));
+
+ DEBUG_STATIC_ASSERT(sizeof(HUF_DEltX2) == sizeof(HUF_DTable)); /* if compiler fails here, assertion is wrong */
+ if (maxTableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge);
+ /* memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, even though some analyzer complain ... */
+
+ iSize = HUF_readStats(weightList, HUF_SYMBOLVALUE_MAX + 1, rankStats, &nbSymbols, &tableLog, src, srcSize);
+ if (HUF_isError(iSize)) return iSize;
+
+ /* check result */
+ if (tableLog > maxTableLog) return ERROR(tableLog_tooLarge); /* DTable can't fit code depth */
+
+ /* find maxWeight */
+ for (maxW = tableLog; rankStats[maxW]==0; maxW--) {} /* necessarily finds a solution before 0 */
+
+ /* Get start index of each weight */
+ { U32 w, nextRankStart = 0;
+ for (w=1; w<maxW+1; w++) {
+ U32 current = nextRankStart;
+ nextRankStart += rankStats[w];
+ rankStart[w] = current;
+ }
+ rankStart[0] = nextRankStart; /* put all 0w symbols at the end of sorted list*/
+ sizeOfSort = nextRankStart;
+ }
+
+ /* sort symbols by weight */
+ { U32 s;
+ for (s=0; s<nbSymbols; s++) {
+ U32 const w = weightList[s];
+ U32 const r = rankStart[w]++;
+ sortedSymbol[r].symbol = (BYTE)s;
+ sortedSymbol[r].weight = (BYTE)w;
+ }
+ rankStart[0] = 0; /* forget 0w symbols; this is beginning of weight(1) */
+ }
+
+ /* Build rankVal */
+ { U32* const rankVal0 = rankVal[0];
+ { int const rescale = (maxTableLog-tableLog) - 1; /* tableLog <= maxTableLog */
+ U32 nextRankVal = 0;
+ U32 w;
+ for (w=1; w<maxW+1; w++) {
+ U32 current = nextRankVal;
+ nextRankVal += rankStats[w] << (w+rescale);
+ rankVal0[w] = current;
+ } }
+ { U32 const minBits = tableLog+1 - maxW;
+ U32 consumed;
+ for (consumed = minBits; consumed < maxTableLog - minBits + 1; consumed++) {
+ U32* const rankValPtr = rankVal[consumed];
+ U32 w;
+ for (w = 1; w < maxW+1; w++) {
+ rankValPtr[w] = rankVal0[w] >> consumed;
+ } } } }
+
+ HUF_fillDTableX2(dt, maxTableLog,
+ sortedSymbol, sizeOfSort,
+ rankStart0, rankVal, maxW,
+ tableLog+1);
+
+ dtd.tableLog = (BYTE)maxTableLog;
+ dtd.tableType = 1;
+ memcpy(DTable, &dtd, sizeof(dtd));
+ return iSize;
+}
+
+size_t HUF_readDTableX2(HUF_DTable* DTable, const void* src, size_t srcSize)
+{
+ U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+ return HUF_readDTableX2_wksp(DTable, src, srcSize,
+ workSpace, sizeof(workSpace));
+}
+
+
+FORCE_INLINE_TEMPLATE U32
+HUF_decodeSymbolX2(void* op, BIT_DStream_t* DStream, const HUF_DEltX2* dt, const U32 dtLog)
+{
+ size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */
+ memcpy(op, dt+val, 2);
+ BIT_skipBits(DStream, dt[val].nbBits);
+ return dt[val].length;
+}
+
+FORCE_INLINE_TEMPLATE U32
+HUF_decodeLastSymbolX2(void* op, BIT_DStream_t* DStream, const HUF_DEltX2* dt, const U32 dtLog)
+{
+ size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */
+ memcpy(op, dt+val, 1);
+ if (dt[val].length==1) BIT_skipBits(DStream, dt[val].nbBits);
+ else {
+ if (DStream->bitsConsumed < (sizeof(DStream->bitContainer)*8)) {
+ BIT_skipBits(DStream, dt[val].nbBits);
+ if (DStream->bitsConsumed > (sizeof(DStream->bitContainer)*8))
+ /* ugly hack; works only because it's the last symbol. Note : can't easily extract nbBits from just this symbol */
+ DStream->bitsConsumed = (sizeof(DStream->bitContainer)*8);
+ } }
+ return 1;
+}
+
+#define HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr) \
+ ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog)
+
+#define HUF_DECODE_SYMBOLX2_1(ptr, DStreamPtr) \
+ if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \
+ ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog)
+
+#define HUF_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \
+ if (MEM_64bits()) \
+ ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog)
+
+HINT_INLINE size_t
+HUF_decodeStreamX2(BYTE* p, BIT_DStream_t* bitDPtr, BYTE* const pEnd,
+ const HUF_DEltX2* const dt, const U32 dtLog)
+{
+ BYTE* const pStart = p;
+
+ /* up to 8 symbols at a time */
+ while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-(sizeof(bitDPtr->bitContainer)-1))) {
+ HUF_DECODE_SYMBOLX2_2(p, bitDPtr);
+ HUF_DECODE_SYMBOLX2_1(p, bitDPtr);
+ HUF_DECODE_SYMBOLX2_2(p, bitDPtr);
+ HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
+ }
+
+ /* closer to end : up to 2 symbols at a time */
+ while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p <= pEnd-2))
+ HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
+
+ while (p <= pEnd-2)
+ HUF_DECODE_SYMBOLX2_0(p, bitDPtr); /* no need to reload : reached the end of DStream */
+
+ if (p < pEnd)
+ p += HUF_decodeLastSymbolX2(p, bitDPtr, dt, dtLog);
+
+ return p-pStart;
+}
+
+FORCE_INLINE_TEMPLATE size_t
+HUF_decompress1X2_usingDTable_internal_body(
+ void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize,
+ const HUF_DTable* DTable)
+{
+ BIT_DStream_t bitD;
+
+ /* Init */
+ CHECK_F( BIT_initDStream(&bitD, cSrc, cSrcSize) );
+
+ /* decode */
+ { BYTE* const ostart = (BYTE*) dst;
+ BYTE* const oend = ostart + dstSize;
+ const void* const dtPtr = DTable+1; /* force compiler to not use strict-aliasing */
+ const HUF_DEltX2* const dt = (const HUF_DEltX2*)dtPtr;
+ DTableDesc const dtd = HUF_getDTableDesc(DTable);
+ HUF_decodeStreamX2(ostart, &bitD, oend, dt, dtd.tableLog);
+ }
+
+ /* check */
+ if (!BIT_endOfDStream(&bitD)) return ERROR(corruption_detected);
+
+ /* decoded size */
+ return dstSize;
+}
+
+FORCE_INLINE_TEMPLATE size_t
+HUF_decompress4X2_usingDTable_internal_body(
+ void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize,
+ const HUF_DTable* DTable)
+{
+ if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */
+
+ { const BYTE* const istart = (const BYTE*) cSrc;
+ BYTE* const ostart = (BYTE*) dst;
+ BYTE* const oend = ostart + dstSize;
+ BYTE* const olimit = oend - (sizeof(size_t)-1);
+ const void* const dtPtr = DTable+1;
+ const HUF_DEltX2* const dt = (const HUF_DEltX2*)dtPtr;
+
+ /* Init */
+ BIT_DStream_t bitD1;
+ BIT_DStream_t bitD2;
+ BIT_DStream_t bitD3;
+ BIT_DStream_t bitD4;
+ size_t const length1 = MEM_readLE16(istart);
+ size_t const length2 = MEM_readLE16(istart+2);
+ size_t const length3 = MEM_readLE16(istart+4);
+ size_t const length4 = cSrcSize - (length1 + length2 + length3 + 6);
+ const BYTE* const istart1 = istart + 6; /* jumpTable */
+ const BYTE* const istart2 = istart1 + length1;
+ const BYTE* const istart3 = istart2 + length2;
+ const BYTE* const istart4 = istart3 + length3;
+ size_t const segmentSize = (dstSize+3) / 4;
+ BYTE* const opStart2 = ostart + segmentSize;
+ BYTE* const opStart3 = opStart2 + segmentSize;
+ BYTE* const opStart4 = opStart3 + segmentSize;
+ BYTE* op1 = ostart;
+ BYTE* op2 = opStart2;
+ BYTE* op3 = opStart3;
+ BYTE* op4 = opStart4;
+ U32 endSignal = 1;
+ DTableDesc const dtd = HUF_getDTableDesc(DTable);
+ U32 const dtLog = dtd.tableLog;
+
+ if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */
+ CHECK_F( BIT_initDStream(&bitD1, istart1, length1) );
+ CHECK_F( BIT_initDStream(&bitD2, istart2, length2) );
+ CHECK_F( BIT_initDStream(&bitD3, istart3, length3) );
+ CHECK_F( BIT_initDStream(&bitD4, istart4, length4) );
+
+ /* 16-32 symbols per loop (4-8 symbols per stream) */
+ for ( ; (endSignal) & (op4 < olimit); ) {
+#if defined(__clang__) && (defined(__x86_64__) || defined(__i386__))
+ HUF_DECODE_SYMBOLX2_2(op1, &bitD1);
+ HUF_DECODE_SYMBOLX2_1(op1, &bitD1);
+ HUF_DECODE_SYMBOLX2_2(op1, &bitD1);
+ HUF_DECODE_SYMBOLX2_0(op1, &bitD1);
+ HUF_DECODE_SYMBOLX2_2(op2, &bitD2);
+ HUF_DECODE_SYMBOLX2_1(op2, &bitD2);
+ HUF_DECODE_SYMBOLX2_2(op2, &bitD2);
+ HUF_DECODE_SYMBOLX2_0(op2, &bitD2);
+ endSignal &= BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished;
+ endSignal &= BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished;
+ HUF_DECODE_SYMBOLX2_2(op3, &bitD3);
+ HUF_DECODE_SYMBOLX2_1(op3, &bitD3);
+ HUF_DECODE_SYMBOLX2_2(op3, &bitD3);
+ HUF_DECODE_SYMBOLX2_0(op3, &bitD3);
+ HUF_DECODE_SYMBOLX2_2(op4, &bitD4);
+ HUF_DECODE_SYMBOLX2_1(op4, &bitD4);
+ HUF_DECODE_SYMBOLX2_2(op4, &bitD4);
+ HUF_DECODE_SYMBOLX2_0(op4, &bitD4);
+ endSignal &= BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished;
+ endSignal &= BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished;
+#else
+ HUF_DECODE_SYMBOLX2_2(op1, &bitD1);
+ HUF_DECODE_SYMBOLX2_2(op2, &bitD2);
+ HUF_DECODE_SYMBOLX2_2(op3, &bitD3);
+ HUF_DECODE_SYMBOLX2_2(op4, &bitD4);
+ HUF_DECODE_SYMBOLX2_1(op1, &bitD1);
+ HUF_DECODE_SYMBOLX2_1(op2, &bitD2);
+ HUF_DECODE_SYMBOLX2_1(op3, &bitD3);
+ HUF_DECODE_SYMBOLX2_1(op4, &bitD4);
+ HUF_DECODE_SYMBOLX2_2(op1, &bitD1);
+ HUF_DECODE_SYMBOLX2_2(op2, &bitD2);
+ HUF_DECODE_SYMBOLX2_2(op3, &bitD3);
+ HUF_DECODE_SYMBOLX2_2(op4, &bitD4);
+ HUF_DECODE_SYMBOLX2_0(op1, &bitD1);
+ HUF_DECODE_SYMBOLX2_0(op2, &bitD2);
+ HUF_DECODE_SYMBOLX2_0(op3, &bitD3);
+ HUF_DECODE_SYMBOLX2_0(op4, &bitD4);
+ endSignal = (U32)LIKELY(
+ (BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished)
+ & (BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished)
+ & (BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished)
+ & (BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished));
+#endif
+ }
+
+ /* check corruption */
+ if (op1 > opStart2) return ERROR(corruption_detected);
+ if (op2 > opStart3) return ERROR(corruption_detected);
+ if (op3 > opStart4) return ERROR(corruption_detected);
+ /* note : op4 already verified within main loop */
+
+ /* finish bitStreams one by one */
+ HUF_decodeStreamX2(op1, &bitD1, opStart2, dt, dtLog);
+ HUF_decodeStreamX2(op2, &bitD2, opStart3, dt, dtLog);
+ HUF_decodeStreamX2(op3, &bitD3, opStart4, dt, dtLog);
+ HUF_decodeStreamX2(op4, &bitD4, oend, dt, dtLog);
+
+ /* check */
+ { U32 const endCheck = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4);
+ if (!endCheck) return ERROR(corruption_detected); }
+
+ /* decoded size */
+ return dstSize;
+ }
+}
+
+HUF_DGEN(HUF_decompress1X2_usingDTable_internal)
+HUF_DGEN(HUF_decompress4X2_usingDTable_internal)
+
+size_t HUF_decompress1X2_usingDTable(
+ void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize,
+ const HUF_DTable* DTable)
+{
+ DTableDesc dtd = HUF_getDTableDesc(DTable);
+ if (dtd.tableType != 1) return ERROR(GENERIC);
+ return HUF_decompress1X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
+}
+
+size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize,
+ void* workSpace, size_t wkspSize)
+{
+ const BYTE* ip = (const BYTE*) cSrc;
+
+ size_t const hSize = HUF_readDTableX2_wksp(DCtx, cSrc, cSrcSize,
+ workSpace, wkspSize);
+ if (HUF_isError(hSize)) return hSize;
+ if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
+ ip += hSize; cSrcSize -= hSize;
+
+ return HUF_decompress1X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx, /* bmi2 */ 0);
+}
+
+
+size_t HUF_decompress1X2_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize)
+{
+ U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+ return HUF_decompress1X2_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize,
+ workSpace, sizeof(workSpace));
+}
+
+size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+ HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX);
+ return HUF_decompress1X2_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);
+}
+
+size_t HUF_decompress4X2_usingDTable(
+ void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize,
+ const HUF_DTable* DTable)
+{
+ DTableDesc dtd = HUF_getDTableDesc(DTable);
+ if (dtd.tableType != 1) return ERROR(GENERIC);
+ return HUF_decompress4X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
+}
+
+static size_t HUF_decompress4X2_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize,
+ void* workSpace, size_t wkspSize, int bmi2)
+{
+ const BYTE* ip = (const BYTE*) cSrc;
+
+ size_t hSize = HUF_readDTableX2_wksp(dctx, cSrc, cSrcSize,
+ workSpace, wkspSize);
+ if (HUF_isError(hSize)) return hSize;
+ if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
+ ip += hSize; cSrcSize -= hSize;
+
+ return HUF_decompress4X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2);
+}
+
+size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize,
+ void* workSpace, size_t wkspSize)
+{
+ return HUF_decompress4X2_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, /* bmi2 */ 0);
+}
+
+
+size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize)
+{
+ U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+ return HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize,
+ workSpace, sizeof(workSpace));
+}
+
+size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+ HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX);
+ return HUF_decompress4X2_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);
+}
+
+#endif /* HUF_FORCE_DECOMPRESS_X1 */
+
+
+/* ***********************************/
+/* Universal decompression selectors */
+/* ***********************************/
+
+size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize,
+ const void* cSrc, size_t cSrcSize,
+ const HUF_DTable* DTable)
+{
+ DTableDesc const dtd = HUF_getDTableDesc(DTable);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+ (void)dtd;
+ assert(dtd.tableType == 0);
+ return HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+ (void)dtd;
+ assert(dtd.tableType == 1);
+ return HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
+#else
+ return dtd.tableType ? HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0) :
+ HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
+#endif
+}
+
+size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize,
+ const void* cSrc, size_t cSrcSize,
+ const HUF_DTable* DTable)
+{
+ DTableDesc const dtd = HUF_getDTableDesc(DTable);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+ (void)dtd;
+ assert(dtd.tableType == 0);
+ return HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+ (void)dtd;
+ assert(dtd.tableType == 1);
+ return HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
+#else
+ return dtd.tableType ? HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0) :
+ HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
+#endif
+}
+
+
+#if !defined(HUF_FORCE_DECOMPRESS_X1) && !defined(HUF_FORCE_DECOMPRESS_X2)
+typedef struct { U32 tableTime; U32 decode256Time; } algo_time_t;
+static const algo_time_t algoTime[16 /* Quantization */][3 /* single, double, quad */] =
+{
+ /* single, double, quad */
+ {{0,0}, {1,1}, {2,2}}, /* Q==0 : impossible */
+ {{0,0}, {1,1}, {2,2}}, /* Q==1 : impossible */
+ {{ 38,130}, {1313, 74}, {2151, 38}}, /* Q == 2 : 12-18% */
+ {{ 448,128}, {1353, 74}, {2238, 41}}, /* Q == 3 : 18-25% */
+ {{ 556,128}, {1353, 74}, {2238, 47}}, /* Q == 4 : 25-32% */
+ {{ 714,128}, {1418, 74}, {2436, 53}}, /* Q == 5 : 32-38% */
+ {{ 883,128}, {1437, 74}, {2464, 61}}, /* Q == 6 : 38-44% */
+ {{ 897,128}, {1515, 75}, {2622, 68}}, /* Q == 7 : 44-50% */
+ {{ 926,128}, {1613, 75}, {2730, 75}}, /* Q == 8 : 50-56% */
+ {{ 947,128}, {1729, 77}, {3359, 77}}, /* Q == 9 : 56-62% */
+ {{1107,128}, {2083, 81}, {4006, 84}}, /* Q ==10 : 62-69% */
+ {{1177,128}, {2379, 87}, {4785, 88}}, /* Q ==11 : 69-75% */
+ {{1242,128}, {2415, 93}, {5155, 84}}, /* Q ==12 : 75-81% */
+ {{1349,128}, {2644,106}, {5260,106}}, /* Q ==13 : 81-87% */
+ {{1455,128}, {2422,124}, {4174,124}}, /* Q ==14 : 87-93% */
+ {{ 722,128}, {1891,145}, {1936,146}}, /* Q ==15 : 93-99% */
+};
+#endif
+
+/** HUF_selectDecoder() :
+ * Tells which decoder is likely to decode faster,
+ * based on a set of pre-computed metrics.
+ * @return : 0==HUF_decompress4X1, 1==HUF_decompress4X2 .
+ * Assumption : 0 < dstSize <= 128 KB */
+U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize)
+{
+ assert(dstSize > 0);
+ assert(dstSize <= 128*1024);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+ (void)dstSize;
+ (void)cSrcSize;
+ return 0;
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+ (void)dstSize;
+ (void)cSrcSize;
+ return 1;
+#else
+ /* decoder timing evaluation */
+ { U32 const Q = (cSrcSize >= dstSize) ? 15 : (U32)(cSrcSize * 16 / dstSize); /* Q < 16 */
+ U32 const D256 = (U32)(dstSize >> 8);
+ U32 const DTime0 = algoTime[Q][0].tableTime + (algoTime[Q][0].decode256Time * D256);
+ U32 DTime1 = algoTime[Q][1].tableTime + (algoTime[Q][1].decode256Time * D256);
+ DTime1 += DTime1 >> 3; /* advantage to algorithm using less memory, to reduce cache eviction */
+ return DTime1 < DTime0;
+ }
+#endif
+}
+
+
+typedef size_t (*decompressionAlgo)(void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);
+
+size_t HUF_decompress (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+#if !defined(HUF_FORCE_DECOMPRESS_X1) && !defined(HUF_FORCE_DECOMPRESS_X2)
+ static const decompressionAlgo decompress[2] = { HUF_decompress4X1, HUF_decompress4X2 };
+#endif
+
+ /* validation checks */
+ if (dstSize == 0) return ERROR(dstSize_tooSmall);
+ if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */
+ if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */
+ if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */
+
+ { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+ (void)algoNb;
+ assert(algoNb == 0);
+ return HUF_decompress4X1(dst, dstSize, cSrc, cSrcSize);
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+ (void)algoNb;
+ assert(algoNb == 1);
+ return HUF_decompress4X2(dst, dstSize, cSrc, cSrcSize);
+#else
+ return decompress[algoNb](dst, dstSize, cSrc, cSrcSize);
+#endif
+ }
+}
+
+size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+ /* validation checks */
+ if (dstSize == 0) return ERROR(dstSize_tooSmall);
+ if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */
+ if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */
+ if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */
+
+ { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+ (void)algoNb;
+ assert(algoNb == 0);
+ return HUF_decompress4X1_DCtx(dctx, dst, dstSize, cSrc, cSrcSize);
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+ (void)algoNb;
+ assert(algoNb == 1);
+ return HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize);
+#else
+ return algoNb ? HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) :
+ HUF_decompress4X1_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) ;
+#endif
+ }
+}
+
+size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+ U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+ return HUF_decompress4X_hufOnly_wksp(dctx, dst, dstSize, cSrc, cSrcSize,
+ workSpace, sizeof(workSpace));
+}
+
+
+size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst,
+ size_t dstSize, const void* cSrc,
+ size_t cSrcSize, void* workSpace,
+ size_t wkspSize)
+{
+ /* validation checks */
+ if (dstSize == 0) return ERROR(dstSize_tooSmall);
+ if (cSrcSize == 0) return ERROR(corruption_detected);
+
+ { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+ (void)algoNb;
+ assert(algoNb == 0);
+ return HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize);
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+ (void)algoNb;
+ assert(algoNb == 1);
+ return HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize);
+#else
+ return algoNb ? HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc,
+ cSrcSize, workSpace, wkspSize):
+ HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize);
+#endif
+ }
+}
+
+size_t HUF_decompress1X_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize,
+ void* workSpace, size_t wkspSize)
+{
+ /* validation checks */
+ if (dstSize == 0) return ERROR(dstSize_tooSmall);
+ if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */
+ if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */
+ if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */
+
+ { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+ (void)algoNb;
+ assert(algoNb == 0);
+ return HUF_decompress1X1_DCtx_wksp(dctx, dst, dstSize, cSrc,
+ cSrcSize, workSpace, wkspSize);
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+ (void)algoNb;
+ assert(algoNb == 1);
+ return HUF_decompress1X2_DCtx_wksp(dctx, dst, dstSize, cSrc,
+ cSrcSize, workSpace, wkspSize);
+#else
+ return algoNb ? HUF_decompress1X2_DCtx_wksp(dctx, dst, dstSize, cSrc,
+ cSrcSize, workSpace, wkspSize):
+ HUF_decompress1X1_DCtx_wksp(dctx, dst, dstSize, cSrc,
+ cSrcSize, workSpace, wkspSize);
+#endif
+ }
+}
+
+size_t HUF_decompress1X_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize,
+ const void* cSrc, size_t cSrcSize)
+{
+ U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+ return HUF_decompress1X_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize,
+ workSpace, sizeof(workSpace));
+}
+
+
+size_t HUF_decompress1X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2)
+{
+ DTableDesc const dtd = HUF_getDTableDesc(DTable);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+ (void)dtd;
+ assert(dtd.tableType == 0);
+ return HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2);
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+ (void)dtd;
+ assert(dtd.tableType == 1);
+ return HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2);
+#else
+ return dtd.tableType ? HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2) :
+ HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2);
+#endif
+}
+
+#ifndef HUF_FORCE_DECOMPRESS_X2
+size_t HUF_decompress1X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2)
+{
+ const BYTE* ip = (const BYTE*) cSrc;
+
+ size_t const hSize = HUF_readDTableX1_wksp(dctx, cSrc, cSrcSize, workSpace, wkspSize);
+ if (HUF_isError(hSize)) return hSize;
+ if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
+ ip += hSize; cSrcSize -= hSize;
+
+ return HUF_decompress1X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2);
+}
+#endif
+
+size_t HUF_decompress4X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2)
+{
+ DTableDesc const dtd = HUF_getDTableDesc(DTable);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+ (void)dtd;
+ assert(dtd.tableType == 0);
+ return HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2);
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+ (void)dtd;
+ assert(dtd.tableType == 1);
+ return HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2);
+#else
+ return dtd.tableType ? HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2) :
+ HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2);
+#endif
+}
+
+size_t HUF_decompress4X_hufOnly_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2)
+{
+ /* validation checks */
+ if (dstSize == 0) return ERROR(dstSize_tooSmall);
+ if (cSrcSize == 0) return ERROR(corruption_detected);
+
+ { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+ (void)algoNb;
+ assert(algoNb == 0);
+ return HUF_decompress4X1_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2);
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+ (void)algoNb;
+ assert(algoNb == 1);
+ return HUF_decompress4X2_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2);
+#else
+ return algoNb ? HUF_decompress4X2_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2) :
+ HUF_decompress4X1_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2);
+#endif
+ }
+}
diff --git a/sys/contrib/openzfs/module/zstd/lib/decompress/zstd_ddict.c b/sys/contrib/openzfs/module/zstd/lib/decompress/zstd_ddict.c
new file mode 100644
index 000000000000..c8cb8ecc9524
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/decompress/zstd_ddict.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/* zstd_ddict.c :
+ * concentrates all logic that needs to know the internals of ZSTD_DDict object */
+
+/*-*******************************************************
+* Dependencies
+*********************************************************/
+#include <string.h> /* memcpy, memmove, memset */
+#include "../common/cpu.h" /* bmi2 */
+#include "../common/mem.h" /* low level memory routines */
+#define FSE_STATIC_LINKING_ONLY
+#include "../common/fse.h"
+#define HUF_STATIC_LINKING_ONLY
+#include "../common/huf.h"
+#include "zstd_decompress_internal.h"
+#include "zstd_ddict.h"
+
+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
+# include "../legacy/zstd_legacy.h"
+#endif
+
+
+
+/*-*******************************************************
+* Types
+*********************************************************/
+struct ZSTD_DDict_s {
+ void* dictBuffer;
+ const void* dictContent;
+ size_t dictSize;
+ ZSTD_entropyDTables_t entropy;
+ U32 dictID;
+ U32 entropyPresent;
+ ZSTD_customMem cMem;
+}; /* typedef'd to ZSTD_DDict within "zstd.h" */
+
+const void* ZSTD_DDict_dictContent(const ZSTD_DDict* ddict)
+{
+ assert(ddict != NULL);
+ return ddict->dictContent;
+}
+
+size_t ZSTD_DDict_dictSize(const ZSTD_DDict* ddict)
+{
+ assert(ddict != NULL);
+ return ddict->dictSize;
+}
+
+void ZSTD_copyDDictParameters(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)
+{
+ DEBUGLOG(4, "ZSTD_copyDDictParameters");
+ assert(dctx != NULL);
+ assert(ddict != NULL);
+ dctx->dictID = ddict->dictID;
+ dctx->prefixStart = ddict->dictContent;
+ dctx->virtualStart = ddict->dictContent;
+ dctx->dictEnd = (const BYTE*)ddict->dictContent + ddict->dictSize;
+ dctx->previousDstEnd = dctx->dictEnd;
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ dctx->dictContentBeginForFuzzing = dctx->prefixStart;
+ dctx->dictContentEndForFuzzing = dctx->previousDstEnd;
+#endif
+ if (ddict->entropyPresent) {
+ dctx->litEntropy = 1;
+ dctx->fseEntropy = 1;
+ dctx->LLTptr = ddict->entropy.LLTable;
+ dctx->MLTptr = ddict->entropy.MLTable;
+ dctx->OFTptr = ddict->entropy.OFTable;
+ dctx->HUFptr = ddict->entropy.hufTable;
+ dctx->entropy.rep[0] = ddict->entropy.rep[0];
+ dctx->entropy.rep[1] = ddict->entropy.rep[1];
+ dctx->entropy.rep[2] = ddict->entropy.rep[2];
+ } else {
+ dctx->litEntropy = 0;
+ dctx->fseEntropy = 0;
+ }
+}
+
+
+static size_t
+ZSTD_loadEntropy_intoDDict(ZSTD_DDict* ddict,
+ ZSTD_dictContentType_e dictContentType)
+{
+ ddict->dictID = 0;
+ ddict->entropyPresent = 0;
+ if (dictContentType == ZSTD_dct_rawContent) return 0;
+
+ if (ddict->dictSize < 8) {
+ if (dictContentType == ZSTD_dct_fullDict)
+ return ERROR(dictionary_corrupted); /* only accept specified dictionaries */
+ return 0; /* pure content mode */
+ }
+ { U32 const magic = MEM_readLE32(ddict->dictContent);
+ if (magic != ZSTD_MAGIC_DICTIONARY) {
+ if (dictContentType == ZSTD_dct_fullDict)
+ return ERROR(dictionary_corrupted); /* only accept specified dictionaries */
+ return 0; /* pure content mode */
+ }
+ }
+ ddict->dictID = MEM_readLE32((const char*)ddict->dictContent + ZSTD_FRAMEIDSIZE);
+
+ /* load entropy tables */
+ RETURN_ERROR_IF(ZSTD_isError(ZSTD_loadDEntropy(
+ &ddict->entropy, ddict->dictContent, ddict->dictSize)),
+ dictionary_corrupted, "");
+ ddict->entropyPresent = 1;
+ return 0;
+}
+
+
+static size_t ZSTD_initDDict_internal(ZSTD_DDict* ddict,
+ const void* dict, size_t dictSize,
+ ZSTD_dictLoadMethod_e dictLoadMethod,
+ ZSTD_dictContentType_e dictContentType)
+{
+ if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dict) || (!dictSize)) {
+ ddict->dictBuffer = NULL;
+ ddict->dictContent = dict;
+ if (!dict) dictSize = 0;
+ } else {
+ void* const internalBuffer = ZSTD_malloc(dictSize, ddict->cMem);
+ ddict->dictBuffer = internalBuffer;
+ ddict->dictContent = internalBuffer;
+ if (!internalBuffer) return ERROR(memory_allocation);
+ memcpy(internalBuffer, dict, dictSize);
+ }
+ ddict->dictSize = dictSize;
+ ddict->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */
+
+ /* parse dictionary content */
+ FORWARD_IF_ERROR( ZSTD_loadEntropy_intoDDict(ddict, dictContentType) , "");
+
+ return 0;
+}
+
+ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize,
+ ZSTD_dictLoadMethod_e dictLoadMethod,
+ ZSTD_dictContentType_e dictContentType,
+ ZSTD_customMem customMem)
+{
+ if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
+
+ { ZSTD_DDict* const ddict = (ZSTD_DDict*) ZSTD_malloc(sizeof(ZSTD_DDict), customMem);
+ if (ddict == NULL) return NULL;
+ ddict->cMem = customMem;
+ { size_t const initResult = ZSTD_initDDict_internal(ddict,
+ dict, dictSize,
+ dictLoadMethod, dictContentType);
+ if (ZSTD_isError(initResult)) {
+ ZSTD_freeDDict(ddict);
+ return NULL;
+ } }
+ return ddict;
+ }
+}
+
+/*! ZSTD_createDDict() :
+* Create a digested dictionary, to start decompression without startup delay.
+* `dict` content is copied inside DDict.
+* Consequently, `dict` can be released after `ZSTD_DDict` creation */
+ZSTD_DDict* ZSTD_createDDict(const void* dict, size_t dictSize)
+{
+ ZSTD_customMem const allocator = { NULL, NULL, NULL };
+ return ZSTD_createDDict_advanced(dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto, allocator);
+}
+
+/*! ZSTD_createDDict_byReference() :
+ * Create a digested dictionary, to start decompression without startup delay.
+ * Dictionary content is simply referenced, it will be accessed during decompression.
+ * Warning : dictBuffer must outlive DDict (DDict must be freed before dictBuffer) */
+ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize)
+{
+ ZSTD_customMem const allocator = { NULL, NULL, NULL };
+ return ZSTD_createDDict_advanced(dictBuffer, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto, allocator);
+}
+
+
+const ZSTD_DDict* ZSTD_initStaticDDict(
+ void* sBuffer, size_t sBufferSize,
+ const void* dict, size_t dictSize,
+ ZSTD_dictLoadMethod_e dictLoadMethod,
+ ZSTD_dictContentType_e dictContentType)
+{
+ size_t const neededSpace = sizeof(ZSTD_DDict)
+ + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize);
+ ZSTD_DDict* const ddict = (ZSTD_DDict*)sBuffer;
+ assert(sBuffer != NULL);
+ assert(dict != NULL);
+ if ((size_t)sBuffer & 7) return NULL; /* 8-aligned */
+ if (sBufferSize < neededSpace) return NULL;
+ if (dictLoadMethod == ZSTD_dlm_byCopy) {
+ memcpy(ddict+1, dict, dictSize); /* local copy */
+ dict = ddict+1;
+ }
+ if (ZSTD_isError( ZSTD_initDDict_internal(ddict,
+ dict, dictSize,
+ ZSTD_dlm_byRef, dictContentType) ))
+ return NULL;
+ return ddict;
+}
+
+
+size_t ZSTD_freeDDict(ZSTD_DDict* ddict)
+{
+ if (ddict==NULL) return 0; /* support free on NULL */
+ { ZSTD_customMem const cMem = ddict->cMem;
+ ZSTD_free(ddict->dictBuffer, cMem);
+ ZSTD_free(ddict, cMem);
+ return 0;
+ }
+}
+
+/*! ZSTD_estimateDDictSize() :
+ * Estimate amount of memory that will be needed to create a dictionary for decompression.
+ * Note : dictionary created by reference using ZSTD_dlm_byRef are smaller */
+size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod)
+{
+ return sizeof(ZSTD_DDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize);
+}
+
+size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict)
+{
+ if (ddict==NULL) return 0; /* support sizeof on NULL */
+ return sizeof(*ddict) + (ddict->dictBuffer ? ddict->dictSize : 0) ;
+}
+
+/*! ZSTD_getDictID_fromDDict() :
+ * Provides the dictID of the dictionary loaded into `ddict`.
+ * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty.
+ * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */
+unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict)
+{
+ if (ddict==NULL) return 0;
+ return ZSTD_getDictID_fromDict(ddict->dictContent, ddict->dictSize);
+}
diff --git a/sys/contrib/openzfs/module/zstd/lib/decompress/zstd_ddict.h b/sys/contrib/openzfs/module/zstd/lib/decompress/zstd_ddict.h
new file mode 100644
index 000000000000..af307efd3d76
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/decompress/zstd_ddict.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+
+#ifndef ZSTD_DDICT_H
+#define ZSTD_DDICT_H
+
+/*-*******************************************************
+ * Dependencies
+ *********************************************************/
+#include <stddef.h> /* size_t */
+#include "../zstd.h" /* ZSTD_DDict, and several public functions */
+
+
+/*-*******************************************************
+ * Interface
+ *********************************************************/
+
+/* note: several prototypes are already published in `zstd.h` :
+ * ZSTD_createDDict()
+ * ZSTD_createDDict_byReference()
+ * ZSTD_createDDict_advanced()
+ * ZSTD_freeDDict()
+ * ZSTD_initStaticDDict()
+ * ZSTD_sizeof_DDict()
+ * ZSTD_estimateDDictSize()
+ * ZSTD_getDictID_fromDict()
+ */
+
+const void* ZSTD_DDict_dictContent(const ZSTD_DDict* ddict);
+size_t ZSTD_DDict_dictSize(const ZSTD_DDict* ddict);
+
+void ZSTD_copyDDictParameters(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict);
+
+
+
+#endif /* ZSTD_DDICT_H */
diff --git a/sys/contrib/openzfs/module/zstd/lib/decompress/zstd_decompress.c b/sys/contrib/openzfs/module/zstd/lib/decompress/zstd_decompress.c
new file mode 100644
index 000000000000..be5c7cfc3347
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/decompress/zstd_decompress.c
@@ -0,0 +1,1885 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+
+/* ***************************************************************
+* Tuning parameters
+*****************************************************************/
+/*!
+ * HEAPMODE :
+ * Select how default decompression function ZSTD_decompress() allocates its context,
+ * on stack (0), or into heap (1, default; requires malloc()).
+ * Note that functions with explicit context such as ZSTD_decompressDCtx() are unaffected.
+ */
+#ifndef ZSTD_HEAPMODE
+# define ZSTD_HEAPMODE 1
+#endif
+
+/*!
+* LEGACY_SUPPORT :
+* if set to 1+, ZSTD_decompress() can decode older formats (v0.1+)
+*/
+#ifndef ZSTD_LEGACY_SUPPORT
+# define ZSTD_LEGACY_SUPPORT 0
+#endif
+
+/*!
+ * MAXWINDOWSIZE_DEFAULT :
+ * maximum window size accepted by DStream __by default__.
+ * Frames requiring more memory will be rejected.
+ * It's possible to set a different limit using ZSTD_DCtx_setMaxWindowSize().
+ */
+#ifndef ZSTD_MAXWINDOWSIZE_DEFAULT
+# define ZSTD_MAXWINDOWSIZE_DEFAULT (((U32)1 << ZSTD_WINDOWLOG_LIMIT_DEFAULT) + 1)
+#endif
+
+/*!
+ * NO_FORWARD_PROGRESS_MAX :
+ * maximum allowed nb of calls to ZSTD_decompressStream()
+ * without any forward progress
+ * (defined as: no byte read from input, and no byte flushed to output)
+ * before triggering an error.
+ */
+#ifndef ZSTD_NO_FORWARD_PROGRESS_MAX
+# define ZSTD_NO_FORWARD_PROGRESS_MAX 16
+#endif
+
+
+/*-*******************************************************
+* Dependencies
+*********************************************************/
+#include <string.h> /* memcpy, memmove, memset */
+#include "../common/cpu.h" /* bmi2 */
+#include "../common/mem.h" /* low level memory routines */
+#define FSE_STATIC_LINKING_ONLY
+#include "../common/fse.h"
+#define HUF_STATIC_LINKING_ONLY
+#include "../common/huf.h"
+#include "../common/zstd_internal.h" /* blockProperties_t */
+#include "zstd_decompress_internal.h" /* ZSTD_DCtx */
+#include "zstd_ddict.h" /* ZSTD_DDictDictContent */
+#include "zstd_decompress_block.h" /* ZSTD_decompressBlock_internal */
+
+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
+# include "../legacy/zstd_legacy.h"
+#endif
+
+
+/*-*************************************************************
+* Context management
+***************************************************************/
+size_t ZSTD_sizeof_DCtx (const ZSTD_DCtx* dctx)
+{
+ if (dctx==NULL) return 0; /* support sizeof NULL */
+ return sizeof(*dctx)
+ + ZSTD_sizeof_DDict(dctx->ddictLocal)
+ + dctx->inBuffSize + dctx->outBuffSize;
+}
+
+size_t ZSTD_estimateDCtxSize(void) { return sizeof(ZSTD_DCtx); }
+
+
+static size_t ZSTD_startingInputLength(ZSTD_format_e format)
+{
+ size_t const startingInputLength = ZSTD_FRAMEHEADERSIZE_PREFIX(format);
+ /* only supports formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless */
+ assert( (format == ZSTD_f_zstd1) || (format == ZSTD_f_zstd1_magicless) );
+ return startingInputLength;
+}
+
+static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx)
+{
+ dctx->format = ZSTD_f_zstd1; /* ZSTD_decompressBegin() invokes ZSTD_startingInputLength() with argument dctx->format */
+ dctx->staticSize = 0;
+ dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT;
+ dctx->ddict = NULL;
+ dctx->ddictLocal = NULL;
+ dctx->dictEnd = NULL;
+ dctx->ddictIsCold = 0;
+ dctx->dictUses = ZSTD_dont_use;
+ dctx->inBuff = NULL;
+ dctx->inBuffSize = 0;
+ dctx->outBuffSize = 0;
+ dctx->streamStage = zdss_init;
+ dctx->legacyContext = NULL;
+ dctx->previousLegacyVersion = 0;
+ dctx->noForwardProgress = 0;
+ dctx->oversizedDuration = 0;
+ dctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
+ dctx->outBufferMode = ZSTD_obm_buffered;
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ dctx->dictContentEndForFuzzing = NULL;
+#endif
+}
+
+ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize)
+{
+ ZSTD_DCtx* const dctx = (ZSTD_DCtx*) workspace;
+
+ if ((size_t)workspace & 7) return NULL; /* 8-aligned */
+ if (workspaceSize < sizeof(ZSTD_DCtx)) return NULL; /* minimum size */
+
+ ZSTD_initDCtx_internal(dctx);
+ dctx->staticSize = workspaceSize;
+ dctx->inBuff = (char*)(dctx+1);
+ return dctx;
+}
+
+ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem)
+{
+ if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
+
+ { ZSTD_DCtx* const dctx = (ZSTD_DCtx*)ZSTD_malloc(sizeof(*dctx), customMem);
+ if (!dctx) return NULL;
+ dctx->customMem = customMem;
+ ZSTD_initDCtx_internal(dctx);
+ return dctx;
+ }
+}
+
+ZSTD_DCtx* ZSTD_createDCtx(void)
+{
+ DEBUGLOG(3, "ZSTD_createDCtx");
+ return ZSTD_createDCtx_advanced(ZSTD_defaultCMem);
+}
+
+static void ZSTD_clearDict(ZSTD_DCtx* dctx)
+{
+ ZSTD_freeDDict(dctx->ddictLocal);
+ dctx->ddictLocal = NULL;
+ dctx->ddict = NULL;
+ dctx->dictUses = ZSTD_dont_use;
+}
+
+size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx)
+{
+ if (dctx==NULL) return 0; /* support free on NULL */
+ RETURN_ERROR_IF(dctx->staticSize, memory_allocation, "not compatible with static DCtx");
+ { ZSTD_customMem const cMem = dctx->customMem;
+ ZSTD_clearDict(dctx);
+ ZSTD_free(dctx->inBuff, cMem);
+ dctx->inBuff = NULL;
+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
+ if (dctx->legacyContext)
+ ZSTD_freeLegacyStreamContext(dctx->legacyContext, dctx->previousLegacyVersion);
+#endif
+ ZSTD_free(dctx, cMem);
+ return 0;
+ }
+}
+
+/* no longer useful */
+void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx)
+{
+ size_t const toCopy = (size_t)((char*)(&dstDCtx->inBuff) - (char*)dstDCtx);
+ memcpy(dstDCtx, srcDCtx, toCopy); /* no need to copy workspace */
+}
+
+
+/*-*************************************************************
+ * Frame header decoding
+ ***************************************************************/
+
+/*! ZSTD_isFrame() :
+ * Tells if the content of `buffer` starts with a valid Frame Identifier.
+ * Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0.
+ * Note 2 : Legacy Frame Identifiers are considered valid only if Legacy Support is enabled.
+ * Note 3 : Skippable Frame Identifiers are considered valid. */
+unsigned ZSTD_isFrame(const void* buffer, size_t size)
+{
+ if (size < ZSTD_FRAMEIDSIZE) return 0;
+ { U32 const magic = MEM_readLE32(buffer);
+ if (magic == ZSTD_MAGICNUMBER) return 1;
+ if ((magic & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) return 1;
+ }
+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
+ if (ZSTD_isLegacy(buffer, size)) return 1;
+#endif
+ return 0;
+}
+
+/** ZSTD_frameHeaderSize_internal() :
+ * srcSize must be large enough to reach header size fields.
+ * note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless.
+ * @return : size of the Frame Header
+ * or an error code, which can be tested with ZSTD_isError() */
+static size_t ZSTD_frameHeaderSize_internal(const void* src, size_t srcSize, ZSTD_format_e format)
+{
+ size_t const minInputSize = ZSTD_startingInputLength(format);
+ RETURN_ERROR_IF(srcSize < minInputSize, srcSize_wrong, "");
+
+ { BYTE const fhd = ((const BYTE*)src)[minInputSize-1];
+ U32 const dictID= fhd & 3;
+ U32 const singleSegment = (fhd >> 5) & 1;
+ U32 const fcsId = fhd >> 6;
+ return minInputSize + !singleSegment
+ + ZSTD_did_fieldSize[dictID] + ZSTD_fcs_fieldSize[fcsId]
+ + (singleSegment && !fcsId);
+ }
+}
+
+/** ZSTD_frameHeaderSize() :
+ * srcSize must be >= ZSTD_frameHeaderSize_prefix.
+ * @return : size of the Frame Header,
+ * or an error code (if srcSize is too small) */
+size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize)
+{
+ return ZSTD_frameHeaderSize_internal(src, srcSize, ZSTD_f_zstd1);
+}
+
+
+/** ZSTD_getFrameHeader_advanced() :
+ * decode Frame Header, or require larger `srcSize`.
+ * note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless
+ * @return : 0, `zfhPtr` is correctly filled,
+ * >0, `srcSize` is too small, value is wanted `srcSize` amount,
+ * or an error code, which can be tested using ZSTD_isError() */
+size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format)
+{
+ const BYTE* ip = (const BYTE*)src;
+ size_t const minInputSize = ZSTD_startingInputLength(format);
+
+ memset(zfhPtr, 0, sizeof(*zfhPtr)); /* not strictly necessary, but static analyzer do not understand that zfhPtr is only going to be read only if return value is zero, since they are 2 different signals */
+ if (srcSize < minInputSize) return minInputSize;
+ RETURN_ERROR_IF(src==NULL, GENERIC, "invalid parameter");
+
+ if ( (format != ZSTD_f_zstd1_magicless)
+ && (MEM_readLE32(src) != ZSTD_MAGICNUMBER) ) {
+ if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
+ /* skippable frame */
+ if (srcSize < ZSTD_SKIPPABLEHEADERSIZE)
+ return ZSTD_SKIPPABLEHEADERSIZE; /* magic number + frame length */
+ memset(zfhPtr, 0, sizeof(*zfhPtr));
+ zfhPtr->frameContentSize = MEM_readLE32((const char *)src + ZSTD_FRAMEIDSIZE);
+ zfhPtr->frameType = ZSTD_skippableFrame;
+ return 0;
+ }
+ RETURN_ERROR(prefix_unknown, "");
+ }
+
+ /* ensure there is enough `srcSize` to fully read/decode frame header */
+ { size_t const fhsize = ZSTD_frameHeaderSize_internal(src, srcSize, format);
+ if (srcSize < fhsize) return fhsize;
+ zfhPtr->headerSize = (U32)fhsize;
+ }
+
+ { BYTE const fhdByte = ip[minInputSize-1];
+ size_t pos = minInputSize;
+ U32 const dictIDSizeCode = fhdByte&3;
+ U32 const checksumFlag = (fhdByte>>2)&1;
+ U32 const singleSegment = (fhdByte>>5)&1;
+ U32 const fcsID = fhdByte>>6;
+ U64 windowSize = 0;
+ U32 dictID = 0;
+ U64 frameContentSize = ZSTD_CONTENTSIZE_UNKNOWN;
+ RETURN_ERROR_IF((fhdByte & 0x08) != 0, frameParameter_unsupported,
+ "reserved bits, must be zero");
+
+ if (!singleSegment) {
+ BYTE const wlByte = ip[pos++];
+ U32 const windowLog = (wlByte >> 3) + ZSTD_WINDOWLOG_ABSOLUTEMIN;
+ RETURN_ERROR_IF(windowLog > ZSTD_WINDOWLOG_MAX, frameParameter_windowTooLarge, "");
+ windowSize = (1ULL << windowLog);
+ windowSize += (windowSize >> 3) * (wlByte&7);
+ }
+ switch(dictIDSizeCode)
+ {
+ default: assert(0); /* impossible */
+ case 0 : break;
+ case 1 : dictID = ip[pos]; pos++; break;
+ case 2 : dictID = MEM_readLE16(ip+pos); pos+=2; break;
+ case 3 : dictID = MEM_readLE32(ip+pos); pos+=4; break;
+ }
+ switch(fcsID)
+ {
+ default: assert(0); /* impossible */
+ case 0 : if (singleSegment) frameContentSize = ip[pos]; break;
+ case 1 : frameContentSize = MEM_readLE16(ip+pos)+256; break;
+ case 2 : frameContentSize = MEM_readLE32(ip+pos); break;
+ case 3 : frameContentSize = MEM_readLE64(ip+pos); break;
+ }
+ if (singleSegment) windowSize = frameContentSize;
+
+ zfhPtr->frameType = ZSTD_frame;
+ zfhPtr->frameContentSize = frameContentSize;
+ zfhPtr->windowSize = windowSize;
+ zfhPtr->blockSizeMax = (unsigned) MIN(windowSize, ZSTD_BLOCKSIZE_MAX);
+ zfhPtr->dictID = dictID;
+ zfhPtr->checksumFlag = checksumFlag;
+ }
+ return 0;
+}
+
+/** ZSTD_getFrameHeader() :
+ * decode Frame Header, or require larger `srcSize`.
+ * note : this function does not consume input, it only reads it.
+ * @return : 0, `zfhPtr` is correctly filled,
+ * >0, `srcSize` is too small, value is wanted `srcSize` amount,
+ * or an error code, which can be tested using ZSTD_isError() */
+size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize)
+{
+ return ZSTD_getFrameHeader_advanced(zfhPtr, src, srcSize, ZSTD_f_zstd1);
+}
+
+
+/** ZSTD_getFrameContentSize() :
+ * compatible with legacy mode
+ * @return : decompressed size of the single frame pointed to be `src` if known, otherwise
+ * - ZSTD_CONTENTSIZE_UNKNOWN if the size cannot be determined
+ * - ZSTD_CONTENTSIZE_ERROR if an error occurred (e.g. invalid magic number, srcSize too small) */
+unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize)
+{
+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
+ if (ZSTD_isLegacy(src, srcSize)) {
+ unsigned long long const ret = ZSTD_getDecompressedSize_legacy(src, srcSize);
+ return ret == 0 ? ZSTD_CONTENTSIZE_UNKNOWN : ret;
+ }
+#endif
+ { ZSTD_frameHeader zfh;
+ if (ZSTD_getFrameHeader(&zfh, src, srcSize) != 0)
+ return ZSTD_CONTENTSIZE_ERROR;
+ if (zfh.frameType == ZSTD_skippableFrame) {
+ return 0;
+ } else {
+ return zfh.frameContentSize;
+ } }
+}
+
+static size_t readSkippableFrameSize(void const* src, size_t srcSize)
+{
+ size_t const skippableHeaderSize = ZSTD_SKIPPABLEHEADERSIZE;
+ U32 sizeU32;
+
+ RETURN_ERROR_IF(srcSize < ZSTD_SKIPPABLEHEADERSIZE, srcSize_wrong, "");
+
+ sizeU32 = MEM_readLE32((BYTE const*)src + ZSTD_FRAMEIDSIZE);
+ RETURN_ERROR_IF((U32)(sizeU32 + ZSTD_SKIPPABLEHEADERSIZE) < sizeU32,
+ frameParameter_unsupported, "");
+ {
+ size_t const skippableSize = skippableHeaderSize + sizeU32;
+ RETURN_ERROR_IF(skippableSize > srcSize, srcSize_wrong, "");
+ return skippableSize;
+ }
+}
+
+/** ZSTD_findDecompressedSize() :
+ * compatible with legacy mode
+ * `srcSize` must be the exact length of some number of ZSTD compressed and/or
+ * skippable frames
+ * @return : decompressed size of the frames contained */
+unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
+{
+ unsigned long long totalDstSize = 0;
+
+ while (srcSize >= ZSTD_startingInputLength(ZSTD_f_zstd1)) {
+ U32 const magicNumber = MEM_readLE32(src);
+
+ if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
+ size_t const skippableSize = readSkippableFrameSize(src, srcSize);
+ if (ZSTD_isError(skippableSize)) {
+ return ZSTD_CONTENTSIZE_ERROR;
+ }
+ assert(skippableSize <= srcSize);
+
+ src = (const BYTE *)src + skippableSize;
+ srcSize -= skippableSize;
+ continue;
+ }
+
+ { unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize);
+ if (ret >= ZSTD_CONTENTSIZE_ERROR) return ret;
+
+ /* check for overflow */
+ if (totalDstSize + ret < totalDstSize) return ZSTD_CONTENTSIZE_ERROR;
+ totalDstSize += ret;
+ }
+ { size_t const frameSrcSize = ZSTD_findFrameCompressedSize(src, srcSize);
+ if (ZSTD_isError(frameSrcSize)) {
+ return ZSTD_CONTENTSIZE_ERROR;
+ }
+
+ src = (const BYTE *)src + frameSrcSize;
+ srcSize -= frameSrcSize;
+ }
+ } /* while (srcSize >= ZSTD_frameHeaderSize_prefix) */
+
+ if (srcSize) return ZSTD_CONTENTSIZE_ERROR;
+
+ return totalDstSize;
+}
+
+/** ZSTD_getDecompressedSize() :
+ * compatible with legacy mode
+ * @return : decompressed size if known, 0 otherwise
+ note : 0 can mean any of the following :
+ - frame content is empty
+ - decompressed size field is not present in frame header
+ - frame header unknown / not supported
+ - frame header not complete (`srcSize` too small) */
+unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize)
+{
+ unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize);
+ ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_ERROR < ZSTD_CONTENTSIZE_UNKNOWN);
+ return (ret >= ZSTD_CONTENTSIZE_ERROR) ? 0 : ret;
+}
+
+
+/** ZSTD_decodeFrameHeader() :
+ * `headerSize` must be the size provided by ZSTD_frameHeaderSize().
+ * @return : 0 if success, or an error code, which can be tested using ZSTD_isError() */
+static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t headerSize)
+{
+ size_t const result = ZSTD_getFrameHeader_advanced(&(dctx->fParams), src, headerSize, dctx->format);
+ if (ZSTD_isError(result)) return result; /* invalid header */
+ RETURN_ERROR_IF(result>0, srcSize_wrong, "headerSize too small");
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ /* Skip the dictID check in fuzzing mode, because it makes the search
+ * harder.
+ */
+ RETURN_ERROR_IF(dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID),
+ dictionary_wrong, "");
+#endif
+ if (dctx->fParams.checksumFlag) XXH64_reset(&dctx->xxhState, 0);
+ return 0;
+}
+
+static ZSTD_frameSizeInfo ZSTD_errorFrameSizeInfo(size_t ret)
+{
+ ZSTD_frameSizeInfo frameSizeInfo;
+ frameSizeInfo.compressedSize = ret;
+ frameSizeInfo.decompressedBound = ZSTD_CONTENTSIZE_ERROR;
+ return frameSizeInfo;
+}
+
+static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize)
+{
+ ZSTD_frameSizeInfo frameSizeInfo;
+ memset(&frameSizeInfo, 0, sizeof(ZSTD_frameSizeInfo));
+
+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
+ if (ZSTD_isLegacy(src, srcSize))
+ return ZSTD_findFrameSizeInfoLegacy(src, srcSize);
+#endif
+
+ if ((srcSize >= ZSTD_SKIPPABLEHEADERSIZE)
+ && (MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
+ frameSizeInfo.compressedSize = readSkippableFrameSize(src, srcSize);
+ assert(ZSTD_isError(frameSizeInfo.compressedSize) ||
+ frameSizeInfo.compressedSize <= srcSize);
+ return frameSizeInfo;
+ } else {
+ const BYTE* ip = (const BYTE*)src;
+ const BYTE* const ipstart = ip;
+ size_t remainingSize = srcSize;
+ size_t nbBlocks = 0;
+ ZSTD_frameHeader zfh;
+
+ /* Extract Frame Header */
+ { size_t const ret = ZSTD_getFrameHeader(&zfh, src, srcSize);
+ if (ZSTD_isError(ret))
+ return ZSTD_errorFrameSizeInfo(ret);
+ if (ret > 0)
+ return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong));
+ }
+
+ ip += zfh.headerSize;
+ remainingSize -= zfh.headerSize;
+
+ /* Iterate over each block */
+ while (1) {
+ blockProperties_t blockProperties;
+ size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSize, &blockProperties);
+ if (ZSTD_isError(cBlockSize))
+ return ZSTD_errorFrameSizeInfo(cBlockSize);
+
+ if (ZSTD_blockHeaderSize + cBlockSize > remainingSize)
+ return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong));
+
+ ip += ZSTD_blockHeaderSize + cBlockSize;
+ remainingSize -= ZSTD_blockHeaderSize + cBlockSize;
+ nbBlocks++;
+
+ if (blockProperties.lastBlock) break;
+ }
+
+ /* Final frame content checksum */
+ if (zfh.checksumFlag) {
+ if (remainingSize < 4)
+ return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong));
+ ip += 4;
+ }
+
+ frameSizeInfo.compressedSize = ip - ipstart;
+ frameSizeInfo.decompressedBound = (zfh.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN)
+ ? zfh.frameContentSize
+ : nbBlocks * zfh.blockSizeMax;
+ return frameSizeInfo;
+ }
+}
+
+/** ZSTD_findFrameCompressedSize() :
+ * compatible with legacy mode
+ * `src` must point to the start of a ZSTD frame, ZSTD legacy frame, or skippable frame
+ * `srcSize` must be at least as large as the frame contained
+ * @return : the compressed size of the frame starting at `src` */
+size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize)
+{
+ ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize);
+ return frameSizeInfo.compressedSize;
+}
+
+/** ZSTD_decompressBound() :
+ * compatible with legacy mode
+ * `src` must point to the start of a ZSTD frame or a skippeable frame
+ * `srcSize` must be at least as large as the frame contained
+ * @return : the maximum decompressed size of the compressed source
+ */
+unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize)
+{
+ unsigned long long bound = 0;
+ /* Iterate over each frame */
+ while (srcSize > 0) {
+ ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize);
+ size_t const compressedSize = frameSizeInfo.compressedSize;
+ unsigned long long const decompressedBound = frameSizeInfo.decompressedBound;
+ if (ZSTD_isError(compressedSize) || decompressedBound == ZSTD_CONTENTSIZE_ERROR)
+ return ZSTD_CONTENTSIZE_ERROR;
+ assert(srcSize >= compressedSize);
+ src = (const BYTE*)src + compressedSize;
+ srcSize -= compressedSize;
+ bound += decompressedBound;
+ }
+ return bound;
+}
+
+
+/*-*************************************************************
+ * Frame decoding
+ ***************************************************************/
+
+/** ZSTD_insertBlock() :
+ * insert `src` block into `dctx` history. Useful to track uncompressed blocks. */
+size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize)
+{
+ DEBUGLOG(5, "ZSTD_insertBlock: %u bytes", (unsigned)blockSize);
+ ZSTD_checkContinuity(dctx, blockStart);
+ dctx->previousDstEnd = (const char*)blockStart + blockSize;
+ return blockSize;
+}
+
+
+static size_t ZSTD_copyRawBlock(void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize)
+{
+ DEBUGLOG(5, "ZSTD_copyRawBlock");
+ if (dst == NULL) {
+ if (srcSize == 0) return 0;
+ RETURN_ERROR(dstBuffer_null, "");
+ }
+ RETURN_ERROR_IF(srcSize > dstCapacity, dstSize_tooSmall, "");
+ memcpy(dst, src, srcSize);
+ return srcSize;
+}
+
+static size_t ZSTD_setRleBlock(void* dst, size_t dstCapacity,
+ BYTE b,
+ size_t regenSize)
+{
+ if (dst == NULL) {
+ if (regenSize == 0) return 0;
+ RETURN_ERROR(dstBuffer_null, "");
+ }
+ RETURN_ERROR_IF(regenSize > dstCapacity, dstSize_tooSmall, "");
+ memset(dst, b, regenSize);
+ return regenSize;
+}
+
+
+/*! ZSTD_decompressFrame() :
+ * @dctx must be properly initialized
+ * will update *srcPtr and *srcSizePtr,
+ * to make *srcPtr progress by one frame. */
+static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
+ void* dst, size_t dstCapacity,
+ const void** srcPtr, size_t *srcSizePtr)
+{
+ const BYTE* ip = (const BYTE*)(*srcPtr);
+ BYTE* const ostart = (BYTE* const)dst;
+ BYTE* const oend = dstCapacity != 0 ? ostart + dstCapacity : ostart;
+ BYTE* op = ostart;
+ size_t remainingSrcSize = *srcSizePtr;
+
+ DEBUGLOG(4, "ZSTD_decompressFrame (srcSize:%i)", (int)*srcSizePtr);
+
+ /* check */
+ RETURN_ERROR_IF(
+ remainingSrcSize < ZSTD_FRAMEHEADERSIZE_MIN(dctx->format)+ZSTD_blockHeaderSize,
+ srcSize_wrong, "");
+
+ /* Frame Header */
+ { size_t const frameHeaderSize = ZSTD_frameHeaderSize_internal(
+ ip, ZSTD_FRAMEHEADERSIZE_PREFIX(dctx->format), dctx->format);
+ if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize;
+ RETURN_ERROR_IF(remainingSrcSize < frameHeaderSize+ZSTD_blockHeaderSize,
+ srcSize_wrong, "");
+ FORWARD_IF_ERROR( ZSTD_decodeFrameHeader(dctx, ip, frameHeaderSize) , "");
+ ip += frameHeaderSize; remainingSrcSize -= frameHeaderSize;
+ }
+
+ /* Loop on each block */
+ while (1) {
+ size_t decodedSize;
+ blockProperties_t blockProperties;
+ size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSrcSize, &blockProperties);
+ if (ZSTD_isError(cBlockSize)) return cBlockSize;
+
+ ip += ZSTD_blockHeaderSize;
+ remainingSrcSize -= ZSTD_blockHeaderSize;
+ RETURN_ERROR_IF(cBlockSize > remainingSrcSize, srcSize_wrong, "");
+
+ switch(blockProperties.blockType)
+ {
+ case bt_compressed:
+ decodedSize = ZSTD_decompressBlock_internal(dctx, op, oend-op, ip, cBlockSize, /* frame */ 1);
+ break;
+ case bt_raw :
+ decodedSize = ZSTD_copyRawBlock(op, oend-op, ip, cBlockSize);
+ break;
+ case bt_rle :
+ decodedSize = ZSTD_setRleBlock(op, oend-op, *ip, blockProperties.origSize);
+ break;
+ case bt_reserved :
+ default:
+ RETURN_ERROR(corruption_detected, "invalid block type");
+ }
+
+ if (ZSTD_isError(decodedSize)) return decodedSize;
+ if (dctx->fParams.checksumFlag)
+ XXH64_update(&dctx->xxhState, op, decodedSize);
+ if (decodedSize != 0)
+ op += decodedSize;
+ assert(ip != NULL);
+ ip += cBlockSize;
+ remainingSrcSize -= cBlockSize;
+ if (blockProperties.lastBlock) break;
+ }
+
+ if (dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN) {
+ RETURN_ERROR_IF((U64)(op-ostart) != dctx->fParams.frameContentSize,
+ corruption_detected, "");
+ }
+ if (dctx->fParams.checksumFlag) { /* Frame content checksum verification */
+ U32 const checkCalc = (U32)XXH64_digest(&dctx->xxhState);
+ U32 checkRead;
+ RETURN_ERROR_IF(remainingSrcSize<4, checksum_wrong, "");
+ checkRead = MEM_readLE32(ip);
+ RETURN_ERROR_IF(checkRead != checkCalc, checksum_wrong, "");
+ ip += 4;
+ remainingSrcSize -= 4;
+ }
+
+ /* Allow caller to get size read */
+ *srcPtr = ip;
+ *srcSizePtr = remainingSrcSize;
+ return op-ostart;
+}
+
+static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const void* dict, size_t dictSize,
+ const ZSTD_DDict* ddict)
+{
+ void* const dststart = dst;
+ int moreThan1Frame = 0;
+
+ DEBUGLOG(5, "ZSTD_decompressMultiFrame");
+ assert(dict==NULL || ddict==NULL); /* either dict or ddict set, not both */
+
+ if (ddict) {
+ dict = ZSTD_DDict_dictContent(ddict);
+ dictSize = ZSTD_DDict_dictSize(ddict);
+ }
+
+ while (srcSize >= ZSTD_startingInputLength(dctx->format)) {
+
+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
+ if (ZSTD_isLegacy(src, srcSize)) {
+ size_t decodedSize;
+ size_t const frameSize = ZSTD_findFrameCompressedSizeLegacy(src, srcSize);
+ if (ZSTD_isError(frameSize)) return frameSize;
+ RETURN_ERROR_IF(dctx->staticSize, memory_allocation,
+ "legacy support is not compatible with static dctx");
+
+ decodedSize = ZSTD_decompressLegacy(dst, dstCapacity, src, frameSize, dict, dictSize);
+ if (ZSTD_isError(decodedSize)) return decodedSize;
+
+ assert(decodedSize <=- dstCapacity);
+ dst = (BYTE*)dst + decodedSize;
+ dstCapacity -= decodedSize;
+
+ src = (const BYTE*)src + frameSize;
+ srcSize -= frameSize;
+
+ continue;
+ }
+#endif
+
+ { U32 const magicNumber = MEM_readLE32(src);
+ DEBUGLOG(4, "reading magic number %08X (expecting %08X)",
+ (unsigned)magicNumber, ZSTD_MAGICNUMBER);
+ if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
+ size_t const skippableSize = readSkippableFrameSize(src, srcSize);
+ FORWARD_IF_ERROR(skippableSize, "readSkippableFrameSize failed");
+ assert(skippableSize <= srcSize);
+
+ src = (const BYTE *)src + skippableSize;
+ srcSize -= skippableSize;
+ continue;
+ } }
+
+ if (ddict) {
+ /* we were called from ZSTD_decompress_usingDDict */
+ FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(dctx, ddict), "");
+ } else {
+ /* this will initialize correctly with no dict if dict == NULL, so
+ * use this in all cases but ddict */
+ FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDict(dctx, dict, dictSize), "");
+ }
+ ZSTD_checkContinuity(dctx, dst);
+
+ { const size_t res = ZSTD_decompressFrame(dctx, dst, dstCapacity,
+ &src, &srcSize);
+ RETURN_ERROR_IF(
+ (ZSTD_getErrorCode(res) == ZSTD_error_prefix_unknown)
+ && (moreThan1Frame==1),
+ srcSize_wrong,
+ "at least one frame successfully completed, but following "
+ "bytes are garbage: it's more likely to be a srcSize error, "
+ "specifying more bytes than compressed size of frame(s). This "
+ "error message replaces ERROR(prefix_unknown), which would be "
+ "confusing, as the first header is actually correct. Note that "
+ "one could be unlucky, it might be a corruption error instead, "
+ "happening right at the place where we expect zstd magic "
+ "bytes. But this is _much_ less likely than a srcSize field "
+ "error.");
+ if (ZSTD_isError(res)) return res;
+ assert(res <= dstCapacity);
+ if (res != 0)
+ dst = (BYTE*)dst + res;
+ dstCapacity -= res;
+ }
+ moreThan1Frame = 1;
+ } /* while (srcSize >= ZSTD_frameHeaderSize_prefix) */
+
+ RETURN_ERROR_IF(srcSize, srcSize_wrong, "input not entirely consumed");
+
+ return (BYTE*)dst - (BYTE*)dststart;
+}
+
+size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const void* dict, size_t dictSize)
+{
+ return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, srcSize, dict, dictSize, NULL);
+}
+
+
+static ZSTD_DDict const* ZSTD_getDDict(ZSTD_DCtx* dctx)
+{
+ switch (dctx->dictUses) {
+ default:
+ assert(0 /* Impossible */);
+ /* fall-through */
+ case ZSTD_dont_use:
+ ZSTD_clearDict(dctx);
+ return NULL;
+ case ZSTD_use_indefinitely:
+ return dctx->ddict;
+ case ZSTD_use_once:
+ dctx->dictUses = ZSTD_dont_use;
+ return dctx->ddict;
+ }
+}
+
+size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+{
+ return ZSTD_decompress_usingDDict(dctx, dst, dstCapacity, src, srcSize, ZSTD_getDDict(dctx));
+}
+
+
+size_t ZSTD_decompress(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+{
+#if defined(ZSTD_HEAPMODE) && (ZSTD_HEAPMODE>=1)
+ size_t regenSize;
+ ZSTD_DCtx* const dctx = ZSTD_createDCtx();
+ RETURN_ERROR_IF(dctx==NULL, memory_allocation, "NULL pointer!");
+ regenSize = ZSTD_decompressDCtx(dctx, dst, dstCapacity, src, srcSize);
+ ZSTD_freeDCtx(dctx);
+ return regenSize;
+#else /* stack mode */
+ ZSTD_DCtx dctx;
+ ZSTD_initDCtx_internal(&dctx);
+ return ZSTD_decompressDCtx(&dctx, dst, dstCapacity, src, srcSize);
+#endif
+}
+
+
+/*-**************************************
+* Advanced Streaming Decompression API
+* Bufferless and synchronous
+****************************************/
+size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx) { return dctx->expected; }
+
+/**
+ * Similar to ZSTD_nextSrcSizeToDecompress(), but when when a block input can be streamed,
+ * we allow taking a partial block as the input. Currently only raw uncompressed blocks can
+ * be streamed.
+ *
+ * For blocks that can be streamed, this allows us to reduce the latency until we produce
+ * output, and avoid copying the input.
+ *
+ * @param inputSize - The total amount of input that the caller currently has.
+ */
+static size_t ZSTD_nextSrcSizeToDecompressWithInputSize(ZSTD_DCtx* dctx, size_t inputSize) {
+ if (!(dctx->stage == ZSTDds_decompressBlock || dctx->stage == ZSTDds_decompressLastBlock))
+ return dctx->expected;
+ if (dctx->bType != bt_raw)
+ return dctx->expected;
+ return MIN(MAX(inputSize, 1), dctx->expected);
+}
+
+ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx) {
+ switch(dctx->stage)
+ {
+ default: /* should not happen */
+ assert(0);
+ case ZSTDds_getFrameHeaderSize:
+ case ZSTDds_decodeFrameHeader:
+ return ZSTDnit_frameHeader;
+ case ZSTDds_decodeBlockHeader:
+ return ZSTDnit_blockHeader;
+ case ZSTDds_decompressBlock:
+ return ZSTDnit_block;
+ case ZSTDds_decompressLastBlock:
+ return ZSTDnit_lastBlock;
+ case ZSTDds_checkChecksum:
+ return ZSTDnit_checksum;
+ case ZSTDds_decodeSkippableHeader:
+ case ZSTDds_skipFrame:
+ return ZSTDnit_skippableFrame;
+ }
+}
+
+static int ZSTD_isSkipFrame(ZSTD_DCtx* dctx) { return dctx->stage == ZSTDds_skipFrame; }
+
+/** ZSTD_decompressContinue() :
+ * srcSize : must be the exact nb of bytes expected (see ZSTD_nextSrcSizeToDecompress())
+ * @return : nb of bytes generated into `dst` (necessarily <= `dstCapacity)
+ * or an error code, which can be tested using ZSTD_isError() */
+size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+{
+ DEBUGLOG(5, "ZSTD_decompressContinue (srcSize:%u)", (unsigned)srcSize);
+ /* Sanity check */
+ RETURN_ERROR_IF(srcSize != ZSTD_nextSrcSizeToDecompressWithInputSize(dctx, srcSize), srcSize_wrong, "not allowed");
+ if (dstCapacity) ZSTD_checkContinuity(dctx, dst);
+
+ switch (dctx->stage)
+ {
+ case ZSTDds_getFrameHeaderSize :
+ assert(src != NULL);
+ if (dctx->format == ZSTD_f_zstd1) { /* allows header */
+ assert(srcSize >= ZSTD_FRAMEIDSIZE); /* to read skippable magic number */
+ if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */
+ memcpy(dctx->headerBuffer, src, srcSize);
+ dctx->expected = ZSTD_SKIPPABLEHEADERSIZE - srcSize; /* remaining to load to get full skippable frame header */
+ dctx->stage = ZSTDds_decodeSkippableHeader;
+ return 0;
+ } }
+ dctx->headerSize = ZSTD_frameHeaderSize_internal(src, srcSize, dctx->format);
+ if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize;
+ memcpy(dctx->headerBuffer, src, srcSize);
+ dctx->expected = dctx->headerSize - srcSize;
+ dctx->stage = ZSTDds_decodeFrameHeader;
+ return 0;
+
+ case ZSTDds_decodeFrameHeader:
+ assert(src != NULL);
+ memcpy(dctx->headerBuffer + (dctx->headerSize - srcSize), src, srcSize);
+ FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize), "");
+ dctx->expected = ZSTD_blockHeaderSize;
+ dctx->stage = ZSTDds_decodeBlockHeader;
+ return 0;
+
+ case ZSTDds_decodeBlockHeader:
+ { blockProperties_t bp;
+ size_t const cBlockSize = ZSTD_getcBlockSize(src, ZSTD_blockHeaderSize, &bp);
+ if (ZSTD_isError(cBlockSize)) return cBlockSize;
+ RETURN_ERROR_IF(cBlockSize > dctx->fParams.blockSizeMax, corruption_detected, "Block Size Exceeds Maximum");
+ dctx->expected = cBlockSize;
+ dctx->bType = bp.blockType;
+ dctx->rleSize = bp.origSize;
+ if (cBlockSize) {
+ dctx->stage = bp.lastBlock ? ZSTDds_decompressLastBlock : ZSTDds_decompressBlock;
+ return 0;
+ }
+ /* empty block */
+ if (bp.lastBlock) {
+ if (dctx->fParams.checksumFlag) {
+ dctx->expected = 4;
+ dctx->stage = ZSTDds_checkChecksum;
+ } else {
+ dctx->expected = 0; /* end of frame */
+ dctx->stage = ZSTDds_getFrameHeaderSize;
+ }
+ } else {
+ dctx->expected = ZSTD_blockHeaderSize; /* jump to next header */
+ dctx->stage = ZSTDds_decodeBlockHeader;
+ }
+ return 0;
+ }
+
+ case ZSTDds_decompressLastBlock:
+ case ZSTDds_decompressBlock:
+ DEBUGLOG(5, "ZSTD_decompressContinue: case ZSTDds_decompressBlock");
+ { size_t rSize;
+ switch(dctx->bType)
+ {
+ case bt_compressed:
+ DEBUGLOG(5, "ZSTD_decompressContinue: case bt_compressed");
+ rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 1);
+ dctx->expected = 0; /* Streaming not supported */
+ break;
+ case bt_raw :
+ assert(srcSize <= dctx->expected);
+ rSize = ZSTD_copyRawBlock(dst, dstCapacity, src, srcSize);
+ FORWARD_IF_ERROR(rSize, "ZSTD_copyRawBlock failed");
+ assert(rSize == srcSize);
+ dctx->expected -= rSize;
+ break;
+ case bt_rle :
+ rSize = ZSTD_setRleBlock(dst, dstCapacity, *(const BYTE*)src, dctx->rleSize);
+ dctx->expected = 0; /* Streaming not supported */
+ break;
+ case bt_reserved : /* should never happen */
+ default:
+ RETURN_ERROR(corruption_detected, "invalid block type");
+ }
+ FORWARD_IF_ERROR(rSize, "");
+ RETURN_ERROR_IF(rSize > dctx->fParams.blockSizeMax, corruption_detected, "Decompressed Block Size Exceeds Maximum");
+ DEBUGLOG(5, "ZSTD_decompressContinue: decoded size from block : %u", (unsigned)rSize);
+ dctx->decodedSize += rSize;
+ if (dctx->fParams.checksumFlag) XXH64_update(&dctx->xxhState, dst, rSize);
+ dctx->previousDstEnd = (char*)dst + rSize;
+
+ /* Stay on the same stage until we are finished streaming the block. */
+ if (dctx->expected > 0) {
+ return rSize;
+ }
+
+ if (dctx->stage == ZSTDds_decompressLastBlock) { /* end of frame */
+ DEBUGLOG(4, "ZSTD_decompressContinue: decoded size from frame : %u", (unsigned)dctx->decodedSize);
+ RETURN_ERROR_IF(
+ dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN
+ && dctx->decodedSize != dctx->fParams.frameContentSize,
+ corruption_detected, "");
+ if (dctx->fParams.checksumFlag) { /* another round for frame checksum */
+ dctx->expected = 4;
+ dctx->stage = ZSTDds_checkChecksum;
+ } else {
+ dctx->expected = 0; /* ends here */
+ dctx->stage = ZSTDds_getFrameHeaderSize;
+ }
+ } else {
+ dctx->stage = ZSTDds_decodeBlockHeader;
+ dctx->expected = ZSTD_blockHeaderSize;
+ }
+ return rSize;
+ }
+
+ case ZSTDds_checkChecksum:
+ assert(srcSize == 4); /* guaranteed by dctx->expected */
+ { U32 const h32 = (U32)XXH64_digest(&dctx->xxhState);
+ U32 const check32 = MEM_readLE32(src);
+ DEBUGLOG(4, "ZSTD_decompressContinue: checksum : calculated %08X :: %08X read", (unsigned)h32, (unsigned)check32);
+ RETURN_ERROR_IF(check32 != h32, checksum_wrong, "");
+ dctx->expected = 0;
+ dctx->stage = ZSTDds_getFrameHeaderSize;
+ return 0;
+ }
+
+ case ZSTDds_decodeSkippableHeader:
+ assert(src != NULL);
+ assert(srcSize <= ZSTD_SKIPPABLEHEADERSIZE);
+ memcpy(dctx->headerBuffer + (ZSTD_SKIPPABLEHEADERSIZE - srcSize), src, srcSize); /* complete skippable header */
+ dctx->expected = MEM_readLE32(dctx->headerBuffer + ZSTD_FRAMEIDSIZE); /* note : dctx->expected can grow seriously large, beyond local buffer size */
+ dctx->stage = ZSTDds_skipFrame;
+ return 0;
+
+ case ZSTDds_skipFrame:
+ dctx->expected = 0;
+ dctx->stage = ZSTDds_getFrameHeaderSize;
+ return 0;
+
+ default:
+ assert(0); /* impossible */
+ RETURN_ERROR(GENERIC, "impossible to reach"); /* some compiler require default to do something */
+ }
+}
+
+
+static size_t ZSTD_refDictContent(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
+{
+ dctx->dictEnd = dctx->previousDstEnd;
+ dctx->virtualStart = (const char*)dict - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart));
+ dctx->prefixStart = dict;
+ dctx->previousDstEnd = (const char*)dict + dictSize;
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ dctx->dictContentBeginForFuzzing = dctx->prefixStart;
+ dctx->dictContentEndForFuzzing = dctx->previousDstEnd;
+#endif
+ return 0;
+}
+
+/*! ZSTD_loadDEntropy() :
+ * dict : must point at beginning of a valid zstd dictionary.
+ * @return : size of entropy tables read */
+size_t
+ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy,
+ const void* const dict, size_t const dictSize)
+{
+ const BYTE* dictPtr = (const BYTE*)dict;
+ const BYTE* const dictEnd = dictPtr + dictSize;
+
+ RETURN_ERROR_IF(dictSize <= 8, dictionary_corrupted, "dict is too small");
+ assert(MEM_readLE32(dict) == ZSTD_MAGIC_DICTIONARY); /* dict must be valid */
+ dictPtr += 8; /* skip header = magic + dictID */
+
+ ZSTD_STATIC_ASSERT(offsetof(ZSTD_entropyDTables_t, OFTable) == offsetof(ZSTD_entropyDTables_t, LLTable) + sizeof(entropy->LLTable));
+ ZSTD_STATIC_ASSERT(offsetof(ZSTD_entropyDTables_t, MLTable) == offsetof(ZSTD_entropyDTables_t, OFTable) + sizeof(entropy->OFTable));
+ ZSTD_STATIC_ASSERT(sizeof(entropy->LLTable) + sizeof(entropy->OFTable) + sizeof(entropy->MLTable) >= HUF_DECOMPRESS_WORKSPACE_SIZE);
+ { void* const workspace = &entropy->LLTable; /* use fse tables as temporary workspace; implies fse tables are grouped together */
+ size_t const workspaceSize = sizeof(entropy->LLTable) + sizeof(entropy->OFTable) + sizeof(entropy->MLTable);
+#ifdef HUF_FORCE_DECOMPRESS_X1
+ /* in minimal huffman, we always use X1 variants */
+ size_t const hSize = HUF_readDTableX1_wksp(entropy->hufTable,
+ dictPtr, dictEnd - dictPtr,
+ workspace, workspaceSize);
+#else
+ size_t const hSize = HUF_readDTableX2_wksp(entropy->hufTable,
+ dictPtr, dictEnd - dictPtr,
+ workspace, workspaceSize);
+#endif
+ RETURN_ERROR_IF(HUF_isError(hSize), dictionary_corrupted, "");
+ dictPtr += hSize;
+ }
+
+ { short offcodeNCount[MaxOff+1];
+ unsigned offcodeMaxValue = MaxOff, offcodeLog;
+ size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
+ RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted, "");
+ RETURN_ERROR_IF(offcodeMaxValue > MaxOff, dictionary_corrupted, "");
+ RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted, "");
+ ZSTD_buildFSETable( entropy->OFTable,
+ offcodeNCount, offcodeMaxValue,
+ OF_base, OF_bits,
+ offcodeLog);
+ dictPtr += offcodeHeaderSize;
+ }
+
+ { short matchlengthNCount[MaxML+1];
+ unsigned matchlengthMaxValue = MaxML, matchlengthLog;
+ size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
+ RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted, "");
+ RETURN_ERROR_IF(matchlengthMaxValue > MaxML, dictionary_corrupted, "");
+ RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted, "");
+ ZSTD_buildFSETable( entropy->MLTable,
+ matchlengthNCount, matchlengthMaxValue,
+ ML_base, ML_bits,
+ matchlengthLog);
+ dictPtr += matchlengthHeaderSize;
+ }
+
+ { short litlengthNCount[MaxLL+1];
+ unsigned litlengthMaxValue = MaxLL, litlengthLog;
+ size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
+ RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted, "");
+ RETURN_ERROR_IF(litlengthMaxValue > MaxLL, dictionary_corrupted, "");
+ RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted, "");
+ ZSTD_buildFSETable( entropy->LLTable,
+ litlengthNCount, litlengthMaxValue,
+ LL_base, LL_bits,
+ litlengthLog);
+ dictPtr += litlengthHeaderSize;
+ }
+
+ RETURN_ERROR_IF(dictPtr+12 > dictEnd, dictionary_corrupted, "");
+ { int i;
+ size_t const dictContentSize = (size_t)(dictEnd - (dictPtr+12));
+ for (i=0; i<3; i++) {
+ U32 const rep = MEM_readLE32(dictPtr); dictPtr += 4;
+ RETURN_ERROR_IF(rep==0 || rep > dictContentSize,
+ dictionary_corrupted, "");
+ entropy->rep[i] = rep;
+ } }
+
+ return dictPtr - (const BYTE*)dict;
+}
+
+static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
+{
+ if (dictSize < 8) return ZSTD_refDictContent(dctx, dict, dictSize);
+ { U32 const magic = MEM_readLE32(dict);
+ if (magic != ZSTD_MAGIC_DICTIONARY) {
+ return ZSTD_refDictContent(dctx, dict, dictSize); /* pure content mode */
+ } }
+ dctx->dictID = MEM_readLE32((const char*)dict + ZSTD_FRAMEIDSIZE);
+
+ /* load entropy tables */
+ { size_t const eSize = ZSTD_loadDEntropy(&dctx->entropy, dict, dictSize);
+ RETURN_ERROR_IF(ZSTD_isError(eSize), dictionary_corrupted, "");
+ dict = (const char*)dict + eSize;
+ dictSize -= eSize;
+ }
+ dctx->litEntropy = dctx->fseEntropy = 1;
+
+ /* reference dictionary content */
+ return ZSTD_refDictContent(dctx, dict, dictSize);
+}
+
+size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx)
+{
+ assert(dctx != NULL);
+ dctx->expected = ZSTD_startingInputLength(dctx->format); /* dctx->format must be properly set */
+ dctx->stage = ZSTDds_getFrameHeaderSize;
+ dctx->decodedSize = 0;
+ dctx->previousDstEnd = NULL;
+ dctx->prefixStart = NULL;
+ dctx->virtualStart = NULL;
+ dctx->dictEnd = NULL;
+ dctx->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */
+ dctx->litEntropy = dctx->fseEntropy = 0;
+ dctx->dictID = 0;
+ dctx->bType = bt_reserved;
+ ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue));
+ memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */
+ dctx->LLTptr = dctx->entropy.LLTable;
+ dctx->MLTptr = dctx->entropy.MLTable;
+ dctx->OFTptr = dctx->entropy.OFTable;
+ dctx->HUFptr = dctx->entropy.hufTable;
+ return 0;
+}
+
+size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
+{
+ FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) , "");
+ if (dict && dictSize)
+ RETURN_ERROR_IF(
+ ZSTD_isError(ZSTD_decompress_insertDictionary(dctx, dict, dictSize)),
+ dictionary_corrupted, "");
+ return 0;
+}
+
+
+/* ====== ZSTD_DDict ====== */
+
+size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)
+{
+ DEBUGLOG(4, "ZSTD_decompressBegin_usingDDict");
+ assert(dctx != NULL);
+ if (ddict) {
+ const char* const dictStart = (const char*)ZSTD_DDict_dictContent(ddict);
+ size_t const dictSize = ZSTD_DDict_dictSize(ddict);
+ const void* const dictEnd = dictStart + dictSize;
+ dctx->ddictIsCold = (dctx->dictEnd != dictEnd);
+ DEBUGLOG(4, "DDict is %s",
+ dctx->ddictIsCold ? "~cold~" : "hot!");
+ }
+ FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) , "");
+ if (ddict) { /* NULL ddict is equivalent to no dictionary */
+ ZSTD_copyDDictParameters(dctx, ddict);
+ }
+ return 0;
+}
+
+/*! ZSTD_getDictID_fromDict() :
+ * Provides the dictID stored within dictionary.
+ * if @return == 0, the dictionary is not conformant with Zstandard specification.
+ * It can still be loaded, but as a content-only dictionary. */
+unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize)
+{
+ if (dictSize < 8) return 0;
+ if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) return 0;
+ return MEM_readLE32((const char*)dict + ZSTD_FRAMEIDSIZE);
+}
+
+/*! ZSTD_getDictID_fromFrame() :
+ * Provides the dictID required to decompress frame stored within `src`.
+ * If @return == 0, the dictID could not be decoded.
+ * This could for one of the following reasons :
+ * - The frame does not require a dictionary (most common case).
+ * - The frame was built with dictID intentionally removed.
+ * Needed dictionary is a hidden information.
+ * Note : this use case also happens when using a non-conformant dictionary.
+ * - `srcSize` is too small, and as a result, frame header could not be decoded.
+ * Note : possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`.
+ * - This is not a Zstandard frame.
+ * When identifying the exact failure cause, it's possible to use
+ * ZSTD_getFrameHeader(), which will provide a more precise error code. */
+unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize)
+{
+ ZSTD_frameHeader zfp = { 0, 0, 0, ZSTD_frame, 0, 0, 0 };
+ size_t const hError = ZSTD_getFrameHeader(&zfp, src, srcSize);
+ if (ZSTD_isError(hError)) return 0;
+ return zfp.dictID;
+}
+
+
+/*! ZSTD_decompress_usingDDict() :
+* Decompression using a pre-digested Dictionary
+* Use dictionary without significant overhead. */
+size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const ZSTD_DDict* ddict)
+{
+ /* pass content and size in case legacy frames are encountered */
+ return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, srcSize,
+ NULL, 0,
+ ddict);
+}
+
+
+/*=====================================
+* Streaming decompression
+*====================================*/
+
+ZSTD_DStream* ZSTD_createDStream(void)
+{
+ DEBUGLOG(3, "ZSTD_createDStream");
+ return ZSTD_createDStream_advanced(ZSTD_defaultCMem);
+}
+
+ZSTD_DStream* ZSTD_initStaticDStream(void *workspace, size_t workspaceSize)
+{
+ return ZSTD_initStaticDCtx(workspace, workspaceSize);
+}
+
+ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem)
+{
+ return ZSTD_createDCtx_advanced(customMem);
+}
+
+size_t ZSTD_freeDStream(ZSTD_DStream* zds)
+{
+ return ZSTD_freeDCtx(zds);
+}
+
+
+/* *** Initialization *** */
+
+size_t ZSTD_DStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize; }
+size_t ZSTD_DStreamOutSize(void) { return ZSTD_BLOCKSIZE_MAX; }
+
+size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx,
+ const void* dict, size_t dictSize,
+ ZSTD_dictLoadMethod_e dictLoadMethod,
+ ZSTD_dictContentType_e dictContentType)
+{
+ RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");
+ ZSTD_clearDict(dctx);
+ if (dict && dictSize != 0) {
+ dctx->ddictLocal = ZSTD_createDDict_advanced(dict, dictSize, dictLoadMethod, dictContentType, dctx->customMem);
+ RETURN_ERROR_IF(dctx->ddictLocal == NULL, memory_allocation, "NULL pointer!");
+ dctx->ddict = dctx->ddictLocal;
+ dctx->dictUses = ZSTD_use_indefinitely;
+ }
+ return 0;
+}
+
+size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
+{
+ return ZSTD_DCtx_loadDictionary_advanced(dctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto);
+}
+
+size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
+{
+ return ZSTD_DCtx_loadDictionary_advanced(dctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto);
+}
+
+size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType)
+{
+ FORWARD_IF_ERROR(ZSTD_DCtx_loadDictionary_advanced(dctx, prefix, prefixSize, ZSTD_dlm_byRef, dictContentType), "");
+ dctx->dictUses = ZSTD_use_once;
+ return 0;
+}
+
+size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize)
+{
+ return ZSTD_DCtx_refPrefix_advanced(dctx, prefix, prefixSize, ZSTD_dct_rawContent);
+}
+
+
+/* ZSTD_initDStream_usingDict() :
+ * return : expected size, aka ZSTD_startingInputLength().
+ * this function cannot fail */
+size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize)
+{
+ DEBUGLOG(4, "ZSTD_initDStream_usingDict");
+ FORWARD_IF_ERROR( ZSTD_DCtx_reset(zds, ZSTD_reset_session_only) , "");
+ FORWARD_IF_ERROR( ZSTD_DCtx_loadDictionary(zds, dict, dictSize) , "");
+ return ZSTD_startingInputLength(zds->format);
+}
+
+/* note : this variant can't fail */
+size_t ZSTD_initDStream(ZSTD_DStream* zds)
+{
+ DEBUGLOG(4, "ZSTD_initDStream");
+ return ZSTD_initDStream_usingDDict(zds, NULL);
+}
+
+/* ZSTD_initDStream_usingDDict() :
+ * ddict will just be referenced, and must outlive decompression session
+ * this function cannot fail */
+size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* dctx, const ZSTD_DDict* ddict)
+{
+ FORWARD_IF_ERROR( ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only) , "");
+ FORWARD_IF_ERROR( ZSTD_DCtx_refDDict(dctx, ddict) , "");
+ return ZSTD_startingInputLength(dctx->format);
+}
+
+/* ZSTD_resetDStream() :
+ * return : expected size, aka ZSTD_startingInputLength().
+ * this function cannot fail */
+size_t ZSTD_resetDStream(ZSTD_DStream* dctx)
+{
+ FORWARD_IF_ERROR(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only), "");
+ return ZSTD_startingInputLength(dctx->format);
+}
+
+
+size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)
+{
+ RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");
+ ZSTD_clearDict(dctx);
+ if (ddict) {
+ dctx->ddict = ddict;
+ dctx->dictUses = ZSTD_use_indefinitely;
+ }
+ return 0;
+}
+
+/* ZSTD_DCtx_setMaxWindowSize() :
+ * note : no direct equivalence in ZSTD_DCtx_setParameter,
+ * since this version sets windowSize, and the other sets windowLog */
+size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize)
+{
+ ZSTD_bounds const bounds = ZSTD_dParam_getBounds(ZSTD_d_windowLogMax);
+ size_t const min = (size_t)1 << bounds.lowerBound;
+ size_t const max = (size_t)1 << bounds.upperBound;
+ RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");
+ RETURN_ERROR_IF(maxWindowSize < min, parameter_outOfBound, "");
+ RETURN_ERROR_IF(maxWindowSize > max, parameter_outOfBound, "");
+ dctx->maxWindowSize = maxWindowSize;
+ return 0;
+}
+
+size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format)
+{
+ return ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, format);
+}
+
+ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam)
+{
+ ZSTD_bounds bounds = { 0, 0, 0 };
+ switch(dParam) {
+ case ZSTD_d_windowLogMax:
+ bounds.lowerBound = ZSTD_WINDOWLOG_ABSOLUTEMIN;
+ bounds.upperBound = ZSTD_WINDOWLOG_MAX;
+ return bounds;
+ case ZSTD_d_format:
+ bounds.lowerBound = (int)ZSTD_f_zstd1;
+ bounds.upperBound = (int)ZSTD_f_zstd1_magicless;
+ ZSTD_STATIC_ASSERT(ZSTD_f_zstd1 < ZSTD_f_zstd1_magicless);
+ return bounds;
+ case ZSTD_d_stableOutBuffer:
+ bounds.lowerBound = (int)ZSTD_obm_buffered;
+ bounds.upperBound = (int)ZSTD_obm_stable;
+ return bounds;
+ default:;
+ }
+ bounds.error = ERROR(parameter_unsupported);
+ return bounds;
+}
+
+/* ZSTD_dParam_withinBounds:
+ * @return 1 if value is within dParam bounds,
+ * 0 otherwise */
+static int ZSTD_dParam_withinBounds(ZSTD_dParameter dParam, int value)
+{
+ ZSTD_bounds const bounds = ZSTD_dParam_getBounds(dParam);
+ if (ZSTD_isError(bounds.error)) return 0;
+ if (value < bounds.lowerBound) return 0;
+ if (value > bounds.upperBound) return 0;
+ return 1;
+}
+
+#define CHECK_DBOUNDS(p,v) { \
+ RETURN_ERROR_IF(!ZSTD_dParam_withinBounds(p, v), parameter_outOfBound, ""); \
+}
+
+size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter dParam, int value)
+{
+ RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");
+ switch(dParam) {
+ case ZSTD_d_windowLogMax:
+ if (value == 0) value = ZSTD_WINDOWLOG_LIMIT_DEFAULT;
+ CHECK_DBOUNDS(ZSTD_d_windowLogMax, value);
+ dctx->maxWindowSize = ((size_t)1) << value;
+ return 0;
+ case ZSTD_d_format:
+ CHECK_DBOUNDS(ZSTD_d_format, value);
+ dctx->format = (ZSTD_format_e)value;
+ return 0;
+ case ZSTD_d_stableOutBuffer:
+ CHECK_DBOUNDS(ZSTD_d_stableOutBuffer, value);
+ dctx->outBufferMode = (ZSTD_outBufferMode_e)value;
+ return 0;
+ default:;
+ }
+ RETURN_ERROR(parameter_unsupported, "");
+}
+
+size_t ZSTD_DCtx_reset(ZSTD_DCtx* dctx, ZSTD_ResetDirective reset)
+{
+ if ( (reset == ZSTD_reset_session_only)
+ || (reset == ZSTD_reset_session_and_parameters) ) {
+ dctx->streamStage = zdss_init;
+ dctx->noForwardProgress = 0;
+ }
+ if ( (reset == ZSTD_reset_parameters)
+ || (reset == ZSTD_reset_session_and_parameters) ) {
+ RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");
+ ZSTD_clearDict(dctx);
+ dctx->format = ZSTD_f_zstd1;
+ dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT;
+ }
+ return 0;
+}
+
+
+size_t ZSTD_sizeof_DStream(const ZSTD_DStream* dctx)
+{
+ return ZSTD_sizeof_DCtx(dctx);
+}
+
+size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize)
+{
+ size_t const blockSize = (size_t) MIN(windowSize, ZSTD_BLOCKSIZE_MAX);
+ unsigned long long const neededRBSize = windowSize + blockSize + (WILDCOPY_OVERLENGTH * 2);
+ unsigned long long const neededSize = MIN(frameContentSize, neededRBSize);
+ size_t const minRBSize = (size_t) neededSize;
+ RETURN_ERROR_IF((unsigned long long)minRBSize != neededSize,
+ frameParameter_windowTooLarge, "");
+ return minRBSize;
+}
+
+size_t ZSTD_estimateDStreamSize(size_t windowSize)
+{
+ size_t const blockSize = MIN(windowSize, ZSTD_BLOCKSIZE_MAX);
+ size_t const inBuffSize = blockSize; /* no block can be larger */
+ size_t const outBuffSize = ZSTD_decodingBufferSize_min(windowSize, ZSTD_CONTENTSIZE_UNKNOWN);
+ return ZSTD_estimateDCtxSize() + inBuffSize + outBuffSize;
+}
+
+size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize)
+{
+ U32 const windowSizeMax = 1U << ZSTD_WINDOWLOG_MAX; /* note : should be user-selectable, but requires an additional parameter (or a dctx) */
+ ZSTD_frameHeader zfh;
+ size_t const err = ZSTD_getFrameHeader(&zfh, src, srcSize);
+ if (ZSTD_isError(err)) return err;
+ RETURN_ERROR_IF(err>0, srcSize_wrong, "");
+ RETURN_ERROR_IF(zfh.windowSize > windowSizeMax,
+ frameParameter_windowTooLarge, "");
+ return ZSTD_estimateDStreamSize((size_t)zfh.windowSize);
+}
+
+
+/* ***** Decompression ***** */
+
+static int ZSTD_DCtx_isOverflow(ZSTD_DStream* zds, size_t const neededInBuffSize, size_t const neededOutBuffSize)
+{
+ return (zds->inBuffSize + zds->outBuffSize) >= (neededInBuffSize + neededOutBuffSize) * ZSTD_WORKSPACETOOLARGE_FACTOR;
+}
+
+static void ZSTD_DCtx_updateOversizedDuration(ZSTD_DStream* zds, size_t const neededInBuffSize, size_t const neededOutBuffSize)
+{
+ if (ZSTD_DCtx_isOverflow(zds, neededInBuffSize, neededOutBuffSize))
+ zds->oversizedDuration++;
+ else
+ zds->oversizedDuration = 0;
+}
+
+static int ZSTD_DCtx_isOversizedTooLong(ZSTD_DStream* zds)
+{
+ return zds->oversizedDuration >= ZSTD_WORKSPACETOOLARGE_MAXDURATION;
+}
+
+/* Checks that the output buffer hasn't changed if ZSTD_obm_stable is used. */
+static size_t ZSTD_checkOutBuffer(ZSTD_DStream const* zds, ZSTD_outBuffer const* output)
+{
+ ZSTD_outBuffer const expect = zds->expectedOutBuffer;
+ /* No requirement when ZSTD_obm_stable is not enabled. */
+ if (zds->outBufferMode != ZSTD_obm_stable)
+ return 0;
+ /* Any buffer is allowed in zdss_init, this must be the same for every other call until
+ * the context is reset.
+ */
+ if (zds->streamStage == zdss_init)
+ return 0;
+ /* The buffer must match our expectation exactly. */
+ if (expect.dst == output->dst && expect.pos == output->pos && expect.size == output->size)
+ return 0;
+ RETURN_ERROR(dstBuffer_wrong, "ZSTD_obm_stable enabled but output differs!");
+}
+
+/* Calls ZSTD_decompressContinue() with the right parameters for ZSTD_decompressStream()
+ * and updates the stage and the output buffer state. This call is extracted so it can be
+ * used both when reading directly from the ZSTD_inBuffer, and in buffered input mode.
+ * NOTE: You must break after calling this function since the streamStage is modified.
+ */
+static size_t ZSTD_decompressContinueStream(
+ ZSTD_DStream* zds, char** op, char* oend,
+ void const* src, size_t srcSize) {
+ int const isSkipFrame = ZSTD_isSkipFrame(zds);
+ if (zds->outBufferMode == ZSTD_obm_buffered) {
+ size_t const dstSize = isSkipFrame ? 0 : zds->outBuffSize - zds->outStart;
+ size_t const decodedSize = ZSTD_decompressContinue(zds,
+ zds->outBuff + zds->outStart, dstSize, src, srcSize);
+ FORWARD_IF_ERROR(decodedSize, "");
+ if (!decodedSize && !isSkipFrame) {
+ zds->streamStage = zdss_read;
+ } else {
+ zds->outEnd = zds->outStart + decodedSize;
+ zds->streamStage = zdss_flush;
+ }
+ } else {
+ /* Write directly into the output buffer */
+ size_t const dstSize = isSkipFrame ? 0 : oend - *op;
+ size_t const decodedSize = ZSTD_decompressContinue(zds, *op, dstSize, src, srcSize);
+ FORWARD_IF_ERROR(decodedSize, "");
+ *op += decodedSize;
+ /* Flushing is not needed. */
+ zds->streamStage = zdss_read;
+ assert(*op <= oend);
+ assert(zds->outBufferMode == ZSTD_obm_stable);
+ }
+ return 0;
+}
+
+size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
+{
+ const char* const src = (const char*)input->src;
+ const char* const istart = input->pos != 0 ? src + input->pos : src;
+ const char* const iend = input->size != 0 ? src + input->size : src;
+ const char* ip = istart;
+ char* const dst = (char*)output->dst;
+ char* const ostart = output->pos != 0 ? dst + output->pos : dst;
+ char* const oend = output->size != 0 ? dst + output->size : dst;
+ char* op = ostart;
+ U32 someMoreWork = 1;
+
+ DEBUGLOG(5, "ZSTD_decompressStream");
+ RETURN_ERROR_IF(
+ input->pos > input->size,
+ srcSize_wrong,
+ "forbidden. in: pos: %u vs size: %u",
+ (U32)input->pos, (U32)input->size);
+ RETURN_ERROR_IF(
+ output->pos > output->size,
+ dstSize_tooSmall,
+ "forbidden. out: pos: %u vs size: %u",
+ (U32)output->pos, (U32)output->size);
+ DEBUGLOG(5, "input size : %u", (U32)(input->size - input->pos));
+ FORWARD_IF_ERROR(ZSTD_checkOutBuffer(zds, output), "");
+
+ while (someMoreWork) {
+ switch(zds->streamStage)
+ {
+ case zdss_init :
+ DEBUGLOG(5, "stage zdss_init => transparent reset ");
+ zds->streamStage = zdss_loadHeader;
+ zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0;
+ zds->legacyVersion = 0;
+ zds->hostageByte = 0;
+ zds->expectedOutBuffer = *output;
+ /* fall-through */
+
+ case zdss_loadHeader :
+ DEBUGLOG(5, "stage zdss_loadHeader (srcSize : %u)", (U32)(iend - ip));
+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
+ if (zds->legacyVersion) {
+ RETURN_ERROR_IF(zds->staticSize, memory_allocation,
+ "legacy support is incompatible with static dctx");
+ { size_t const hint = ZSTD_decompressLegacyStream(zds->legacyContext, zds->legacyVersion, output, input);
+ if (hint==0) zds->streamStage = zdss_init;
+ return hint;
+ } }
+#endif
+ { size_t const hSize = ZSTD_getFrameHeader_advanced(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format);
+ DEBUGLOG(5, "header size : %u", (U32)hSize);
+ if (ZSTD_isError(hSize)) {
+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
+ U32 const legacyVersion = ZSTD_isLegacy(istart, iend-istart);
+ if (legacyVersion) {
+ ZSTD_DDict const* const ddict = ZSTD_getDDict(zds);
+ const void* const dict = ddict ? ZSTD_DDict_dictContent(ddict) : NULL;
+ size_t const dictSize = ddict ? ZSTD_DDict_dictSize(ddict) : 0;
+ DEBUGLOG(5, "ZSTD_decompressStream: detected legacy version v0.%u", legacyVersion);
+ RETURN_ERROR_IF(zds->staticSize, memory_allocation,
+ "legacy support is incompatible with static dctx");
+ FORWARD_IF_ERROR(ZSTD_initLegacyStream(&zds->legacyContext,
+ zds->previousLegacyVersion, legacyVersion,
+ dict, dictSize), "");
+ zds->legacyVersion = zds->previousLegacyVersion = legacyVersion;
+ { size_t const hint = ZSTD_decompressLegacyStream(zds->legacyContext, legacyVersion, output, input);
+ if (hint==0) zds->streamStage = zdss_init; /* or stay in stage zdss_loadHeader */
+ return hint;
+ } }
+#endif
+ return hSize; /* error */
+ }
+ if (hSize != 0) { /* need more input */
+ size_t const toLoad = hSize - zds->lhSize; /* if hSize!=0, hSize > zds->lhSize */
+ size_t const remainingInput = (size_t)(iend-ip);
+ assert(iend >= ip);
+ if (toLoad > remainingInput) { /* not enough input to load full header */
+ if (remainingInput > 0) {
+ memcpy(zds->headerBuffer + zds->lhSize, ip, remainingInput);
+ zds->lhSize += remainingInput;
+ }
+ input->pos = input->size;
+ return (MAX((size_t)ZSTD_FRAMEHEADERSIZE_MIN(zds->format), hSize) - zds->lhSize) + ZSTD_blockHeaderSize; /* remaining header bytes + next block header */
+ }
+ assert(ip != NULL);
+ memcpy(zds->headerBuffer + zds->lhSize, ip, toLoad); zds->lhSize = hSize; ip += toLoad;
+ break;
+ } }
+
+ /* check for single-pass mode opportunity */
+ if (zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN
+ && zds->fParams.frameType != ZSTD_skippableFrame
+ && (U64)(size_t)(oend-op) >= zds->fParams.frameContentSize) {
+ size_t const cSize = ZSTD_findFrameCompressedSize(istart, iend-istart);
+ if (cSize <= (size_t)(iend-istart)) {
+ /* shortcut : using single-pass mode */
+ size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, oend-op, istart, cSize, ZSTD_getDDict(zds));
+ if (ZSTD_isError(decompressedSize)) return decompressedSize;
+ DEBUGLOG(4, "shortcut to single-pass ZSTD_decompress_usingDDict()")
+ ip = istart + cSize;
+ op += decompressedSize;
+ zds->expected = 0;
+ zds->streamStage = zdss_init;
+ someMoreWork = 0;
+ break;
+ } }
+
+ /* Check output buffer is large enough for ZSTD_odm_stable. */
+ if (zds->outBufferMode == ZSTD_obm_stable
+ && zds->fParams.frameType != ZSTD_skippableFrame
+ && zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN
+ && (U64)(size_t)(oend-op) < zds->fParams.frameContentSize) {
+ RETURN_ERROR(dstSize_tooSmall, "ZSTD_obm_stable passed but ZSTD_outBuffer is too small");
+ }
+
+ /* Consume header (see ZSTDds_decodeFrameHeader) */
+ DEBUGLOG(4, "Consume header");
+ FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(zds, ZSTD_getDDict(zds)), "");
+
+ if ((MEM_readLE32(zds->headerBuffer) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */
+ zds->expected = MEM_readLE32(zds->headerBuffer + ZSTD_FRAMEIDSIZE);
+ zds->stage = ZSTDds_skipFrame;
+ } else {
+ FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(zds, zds->headerBuffer, zds->lhSize), "");
+ zds->expected = ZSTD_blockHeaderSize;
+ zds->stage = ZSTDds_decodeBlockHeader;
+ }
+
+ /* control buffer memory usage */
+ DEBUGLOG(4, "Control max memory usage (%u KB <= max %u KB)",
+ (U32)(zds->fParams.windowSize >>10),
+ (U32)(zds->maxWindowSize >> 10) );
+ zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN);
+ RETURN_ERROR_IF(zds->fParams.windowSize > zds->maxWindowSize,
+ frameParameter_windowTooLarge, "");
+
+ /* Adapt buffer sizes to frame header instructions */
+ { size_t const neededInBuffSize = MAX(zds->fParams.blockSizeMax, 4 /* frame checksum */);
+ size_t const neededOutBuffSize = zds->outBufferMode == ZSTD_obm_buffered
+ ? ZSTD_decodingBufferSize_min(zds->fParams.windowSize, zds->fParams.frameContentSize)
+ : 0;
+
+ ZSTD_DCtx_updateOversizedDuration(zds, neededInBuffSize, neededOutBuffSize);
+
+ { int const tooSmall = (zds->inBuffSize < neededInBuffSize) || (zds->outBuffSize < neededOutBuffSize);
+ int const tooLarge = ZSTD_DCtx_isOversizedTooLong(zds);
+
+ if (tooSmall || tooLarge) {
+ size_t const bufferSize = neededInBuffSize + neededOutBuffSize;
+ DEBUGLOG(4, "inBuff : from %u to %u",
+ (U32)zds->inBuffSize, (U32)neededInBuffSize);
+ DEBUGLOG(4, "outBuff : from %u to %u",
+ (U32)zds->outBuffSize, (U32)neededOutBuffSize);
+ if (zds->staticSize) { /* static DCtx */
+ DEBUGLOG(4, "staticSize : %u", (U32)zds->staticSize);
+ assert(zds->staticSize >= sizeof(ZSTD_DCtx)); /* controlled at init */
+ RETURN_ERROR_IF(
+ bufferSize > zds->staticSize - sizeof(ZSTD_DCtx),
+ memory_allocation, "");
+ } else {
+ ZSTD_free(zds->inBuff, zds->customMem);
+ zds->inBuffSize = 0;
+ zds->outBuffSize = 0;
+ zds->inBuff = (char*)ZSTD_malloc(bufferSize, zds->customMem);
+ RETURN_ERROR_IF(zds->inBuff == NULL, memory_allocation, "");
+ }
+ zds->inBuffSize = neededInBuffSize;
+ zds->outBuff = zds->inBuff + zds->inBuffSize;
+ zds->outBuffSize = neededOutBuffSize;
+ } } }
+ zds->streamStage = zdss_read;
+ /* fall-through */
+
+ case zdss_read:
+ DEBUGLOG(5, "stage zdss_read");
+ { size_t const neededInSize = ZSTD_nextSrcSizeToDecompressWithInputSize(zds, iend - ip);
+ DEBUGLOG(5, "neededInSize = %u", (U32)neededInSize);
+ if (neededInSize==0) { /* end of frame */
+ zds->streamStage = zdss_init;
+ someMoreWork = 0;
+ break;
+ }
+ if ((size_t)(iend-ip) >= neededInSize) { /* decode directly from src */
+ FORWARD_IF_ERROR(ZSTD_decompressContinueStream(zds, &op, oend, ip, neededInSize), "");
+ ip += neededInSize;
+ /* Function modifies the stage so we must break */
+ break;
+ } }
+ if (ip==iend) { someMoreWork = 0; break; } /* no more input */
+ zds->streamStage = zdss_load;
+ /* fall-through */
+
+ case zdss_load:
+ { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds);
+ size_t const toLoad = neededInSize - zds->inPos;
+ int const isSkipFrame = ZSTD_isSkipFrame(zds);
+ size_t loadedSize;
+ /* At this point we shouldn't be decompressing a block that we can stream. */
+ assert(neededInSize == ZSTD_nextSrcSizeToDecompressWithInputSize(zds, iend - ip));
+ if (isSkipFrame) {
+ loadedSize = MIN(toLoad, (size_t)(iend-ip));
+ } else {
+ RETURN_ERROR_IF(toLoad > zds->inBuffSize - zds->inPos,
+ corruption_detected,
+ "should never happen");
+ loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, iend-ip);
+ }
+ ip += loadedSize;
+ zds->inPos += loadedSize;
+ if (loadedSize < toLoad) { someMoreWork = 0; break; } /* not enough input, wait for more */
+
+ /* decode loaded input */
+ zds->inPos = 0; /* input is consumed */
+ FORWARD_IF_ERROR(ZSTD_decompressContinueStream(zds, &op, oend, zds->inBuff, neededInSize), "");
+ /* Function modifies the stage so we must break */
+ break;
+ }
+ case zdss_flush:
+ { size_t const toFlushSize = zds->outEnd - zds->outStart;
+ size_t const flushedSize = ZSTD_limitCopy(op, oend-op, zds->outBuff + zds->outStart, toFlushSize);
+ op += flushedSize;
+ zds->outStart += flushedSize;
+ if (flushedSize == toFlushSize) { /* flush completed */
+ zds->streamStage = zdss_read;
+ if ( (zds->outBuffSize < zds->fParams.frameContentSize)
+ && (zds->outStart + zds->fParams.blockSizeMax > zds->outBuffSize) ) {
+ DEBUGLOG(5, "restart filling outBuff from beginning (left:%i, needed:%u)",
+ (int)(zds->outBuffSize - zds->outStart),
+ (U32)zds->fParams.blockSizeMax);
+ zds->outStart = zds->outEnd = 0;
+ }
+ break;
+ } }
+ /* cannot complete flush */
+ someMoreWork = 0;
+ break;
+
+ default:
+ assert(0); /* impossible */
+ RETURN_ERROR(GENERIC, "impossible to reach"); /* some compiler require default to do something */
+ } }
+
+ /* result */
+ input->pos = (size_t)(ip - (const char*)(input->src));
+ output->pos = (size_t)(op - (char*)(output->dst));
+
+ /* Update the expected output buffer for ZSTD_obm_stable. */
+ zds->expectedOutBuffer = *output;
+
+ if ((ip==istart) && (op==ostart)) { /* no forward progress */
+ zds->noForwardProgress ++;
+ if (zds->noForwardProgress >= ZSTD_NO_FORWARD_PROGRESS_MAX) {
+ RETURN_ERROR_IF(op==oend, dstSize_tooSmall, "");
+ RETURN_ERROR_IF(ip==iend, srcSize_wrong, "");
+ assert(0);
+ }
+ } else {
+ zds->noForwardProgress = 0;
+ }
+ { size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zds);
+ if (!nextSrcSizeHint) { /* frame fully decoded */
+ if (zds->outEnd == zds->outStart) { /* output fully flushed */
+ if (zds->hostageByte) {
+ if (input->pos >= input->size) {
+ /* can't release hostage (not present) */
+ zds->streamStage = zdss_read;
+ return 1;
+ }
+ input->pos++; /* release hostage */
+ } /* zds->hostageByte */
+ return 0;
+ } /* zds->outEnd == zds->outStart */
+ if (!zds->hostageByte) { /* output not fully flushed; keep last byte as hostage; will be released when all output is flushed */
+ input->pos--; /* note : pos > 0, otherwise, impossible to finish reading last block */
+ zds->hostageByte=1;
+ }
+ return 1;
+ } /* nextSrcSizeHint==0 */
+ nextSrcSizeHint += ZSTD_blockHeaderSize * (ZSTD_nextInputType(zds) == ZSTDnit_block); /* preload header of next block */
+ assert(zds->inPos <= nextSrcSizeHint);
+ nextSrcSizeHint -= zds->inPos; /* part already loaded*/
+ return nextSrcSizeHint;
+ }
+}
+
+size_t ZSTD_decompressStream_simpleArgs (
+ ZSTD_DCtx* dctx,
+ void* dst, size_t dstCapacity, size_t* dstPos,
+ const void* src, size_t srcSize, size_t* srcPos)
+{
+ ZSTD_outBuffer output = { dst, dstCapacity, *dstPos };
+ ZSTD_inBuffer input = { src, srcSize, *srcPos };
+ /* ZSTD_compress_generic() will check validity of dstPos and srcPos */
+ size_t const cErr = ZSTD_decompressStream(dctx, &output, &input);
+ *dstPos = output.pos;
+ *srcPos = input.pos;
+ return cErr;
+}
diff --git a/sys/contrib/openzfs/module/zstd/lib/decompress/zstd_decompress_block.c b/sys/contrib/openzfs/module/zstd/lib/decompress/zstd_decompress_block.c
new file mode 100644
index 000000000000..ad3b3d8dbd0a
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/decompress/zstd_decompress_block.c
@@ -0,0 +1,1432 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/* zstd_decompress_block :
+ * this module takes care of decompressing _compressed_ block */
+
+/*-*******************************************************
+* Dependencies
+*********************************************************/
+#include <string.h> /* memcpy, memmove, memset */
+#include "../common/compiler.h" /* prefetch */
+#include "../common/cpu.h" /* bmi2 */
+#include "../common/mem.h" /* low level memory routines */
+#define FSE_STATIC_LINKING_ONLY
+#include "../common/fse.h"
+#define HUF_STATIC_LINKING_ONLY
+#include "../common/huf.h"
+#include "../common/zstd_internal.h"
+#include "zstd_decompress_internal.h" /* ZSTD_DCtx */
+#include "zstd_ddict.h" /* ZSTD_DDictDictContent */
+#include "zstd_decompress_block.h"
+
+/*_*******************************************************
+* Macros
+**********************************************************/
+
+/* These two optional macros force the use one way or another of the two
+ * ZSTD_decompressSequences implementations. You can't force in both directions
+ * at the same time.
+ */
+#if defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \
+ defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG)
+#error "Cannot force the use of the short and the long ZSTD_decompressSequences variants!"
+#endif
+
+
+/*_*******************************************************
+* Memory operations
+**********************************************************/
+static void ZSTD_copy4(void* dst, const void* src) { memcpy(dst, src, 4); }
+
+
+/*-*************************************************************
+ * Block decoding
+ ***************************************************************/
+
+/*! ZSTD_getcBlockSize() :
+ * Provides the size of compressed block from block header `src` */
+size_t ZSTD_getcBlockSize(const void* src, size_t srcSize,
+ blockProperties_t* bpPtr)
+{
+ RETURN_ERROR_IF(srcSize < ZSTD_blockHeaderSize, srcSize_wrong, "");
+
+ { U32 const cBlockHeader = MEM_readLE24(src);
+ U32 const cSize = cBlockHeader >> 3;
+ bpPtr->lastBlock = cBlockHeader & 1;
+ bpPtr->blockType = (blockType_e)((cBlockHeader >> 1) & 3);
+ bpPtr->origSize = cSize; /* only useful for RLE */
+ if (bpPtr->blockType == bt_rle) return 1;
+ RETURN_ERROR_IF(bpPtr->blockType == bt_reserved, corruption_detected, "");
+ return cSize;
+ }
+}
+
+
+/* Hidden declaration for fullbench */
+size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
+ const void* src, size_t srcSize);
+/*! ZSTD_decodeLiteralsBlock() :
+ * @return : nb of bytes read from src (< srcSize )
+ * note : symbol not declared but exposed for fullbench */
+size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
+ const void* src, size_t srcSize) /* note : srcSize < BLOCKSIZE */
+{
+ DEBUGLOG(5, "ZSTD_decodeLiteralsBlock");
+ RETURN_ERROR_IF(srcSize < MIN_CBLOCK_SIZE, corruption_detected, "");
+
+ { const BYTE* const istart = (const BYTE*) src;
+ symbolEncodingType_e const litEncType = (symbolEncodingType_e)(istart[0] & 3);
+
+ switch(litEncType)
+ {
+ case set_repeat:
+ DEBUGLOG(5, "set_repeat flag : re-using stats from previous compressed literals block");
+ RETURN_ERROR_IF(dctx->litEntropy==0, dictionary_corrupted, "");
+ /* fall-through */
+
+ case set_compressed:
+ RETURN_ERROR_IF(srcSize < 5, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 3; here we need up to 5 for case 3");
+ { size_t lhSize, litSize, litCSize;
+ U32 singleStream=0;
+ U32 const lhlCode = (istart[0] >> 2) & 3;
+ U32 const lhc = MEM_readLE32(istart);
+ size_t hufSuccess;
+ switch(lhlCode)
+ {
+ case 0: case 1: default: /* note : default is impossible, since lhlCode into [0..3] */
+ /* 2 - 2 - 10 - 10 */
+ singleStream = !lhlCode;
+ lhSize = 3;
+ litSize = (lhc >> 4) & 0x3FF;
+ litCSize = (lhc >> 14) & 0x3FF;
+ break;
+ case 2:
+ /* 2 - 2 - 14 - 14 */
+ lhSize = 4;
+ litSize = (lhc >> 4) & 0x3FFF;
+ litCSize = lhc >> 18;
+ break;
+ case 3:
+ /* 2 - 2 - 18 - 18 */
+ lhSize = 5;
+ litSize = (lhc >> 4) & 0x3FFFF;
+ litCSize = (lhc >> 22) + ((size_t)istart[4] << 10);
+ break;
+ }
+ RETURN_ERROR_IF(litSize > ZSTD_BLOCKSIZE_MAX, corruption_detected, "");
+ RETURN_ERROR_IF(litCSize + lhSize > srcSize, corruption_detected, "");
+
+ /* prefetch huffman table if cold */
+ if (dctx->ddictIsCold && (litSize > 768 /* heuristic */)) {
+ PREFETCH_AREA(dctx->HUFptr, sizeof(dctx->entropy.hufTable));
+ }
+
+ if (litEncType==set_repeat) {
+ if (singleStream) {
+ hufSuccess = HUF_decompress1X_usingDTable_bmi2(
+ dctx->litBuffer, litSize, istart+lhSize, litCSize,
+ dctx->HUFptr, dctx->bmi2);
+ } else {
+ hufSuccess = HUF_decompress4X_usingDTable_bmi2(
+ dctx->litBuffer, litSize, istart+lhSize, litCSize,
+ dctx->HUFptr, dctx->bmi2);
+ }
+ } else {
+ if (singleStream) {
+#if defined(HUF_FORCE_DECOMPRESS_X2)
+ hufSuccess = HUF_decompress1X_DCtx_wksp(
+ dctx->entropy.hufTable, dctx->litBuffer, litSize,
+ istart+lhSize, litCSize, dctx->workspace,
+ sizeof(dctx->workspace));
+#else
+ hufSuccess = HUF_decompress1X1_DCtx_wksp_bmi2(
+ dctx->entropy.hufTable, dctx->litBuffer, litSize,
+ istart+lhSize, litCSize, dctx->workspace,
+ sizeof(dctx->workspace), dctx->bmi2);
+#endif
+ } else {
+ hufSuccess = HUF_decompress4X_hufOnly_wksp_bmi2(
+ dctx->entropy.hufTable, dctx->litBuffer, litSize,
+ istart+lhSize, litCSize, dctx->workspace,
+ sizeof(dctx->workspace), dctx->bmi2);
+ }
+ }
+
+ RETURN_ERROR_IF(HUF_isError(hufSuccess), corruption_detected, "");
+
+ dctx->litPtr = dctx->litBuffer;
+ dctx->litSize = litSize;
+ dctx->litEntropy = 1;
+ if (litEncType==set_compressed) dctx->HUFptr = dctx->entropy.hufTable;
+ memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH);
+ return litCSize + lhSize;
+ }
+
+ case set_basic:
+ { size_t litSize, lhSize;
+ U32 const lhlCode = ((istart[0]) >> 2) & 3;
+ switch(lhlCode)
+ {
+ case 0: case 2: default: /* note : default is impossible, since lhlCode into [0..3] */
+ lhSize = 1;
+ litSize = istart[0] >> 3;
+ break;
+ case 1:
+ lhSize = 2;
+ litSize = MEM_readLE16(istart) >> 4;
+ break;
+ case 3:
+ lhSize = 3;
+ litSize = MEM_readLE24(istart) >> 4;
+ break;
+ }
+
+ if (lhSize+litSize+WILDCOPY_OVERLENGTH > srcSize) { /* risk reading beyond src buffer with wildcopy */
+ RETURN_ERROR_IF(litSize+lhSize > srcSize, corruption_detected, "");
+ memcpy(dctx->litBuffer, istart+lhSize, litSize);
+ dctx->litPtr = dctx->litBuffer;
+ dctx->litSize = litSize;
+ memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH);
+ return lhSize+litSize;
+ }
+ /* direct reference into compressed stream */
+ dctx->litPtr = istart+lhSize;
+ dctx->litSize = litSize;
+ return lhSize+litSize;
+ }
+
+ case set_rle:
+ { U32 const lhlCode = ((istart[0]) >> 2) & 3;
+ size_t litSize, lhSize;
+ switch(lhlCode)
+ {
+ case 0: case 2: default: /* note : default is impossible, since lhlCode into [0..3] */
+ lhSize = 1;
+ litSize = istart[0] >> 3;
+ break;
+ case 1:
+ lhSize = 2;
+ litSize = MEM_readLE16(istart) >> 4;
+ break;
+ case 3:
+ lhSize = 3;
+ litSize = MEM_readLE24(istart) >> 4;
+ RETURN_ERROR_IF(srcSize<4, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 3; here we need lhSize+1 = 4");
+ break;
+ }
+ RETURN_ERROR_IF(litSize > ZSTD_BLOCKSIZE_MAX, corruption_detected, "");
+ memset(dctx->litBuffer, istart[lhSize], litSize + WILDCOPY_OVERLENGTH);
+ dctx->litPtr = dctx->litBuffer;
+ dctx->litSize = litSize;
+ return lhSize+1;
+ }
+ default:
+ RETURN_ERROR(corruption_detected, "impossible");
+ }
+ }
+}
+
+/* Default FSE distribution tables.
+ * These are pre-calculated FSE decoding tables using default distributions as defined in specification :
+ * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#default-distributions
+ * They were generated programmatically with following method :
+ * - start from default distributions, present in /lib/common/zstd_internal.h
+ * - generate tables normally, using ZSTD_buildFSETable()
+ * - printout the content of tables
+ * - pretify output, report below, test with fuzzer to ensure it's correct */
+
+/* Default FSE distribution table for Literal Lengths */
+static const ZSTD_seqSymbol LL_defaultDTable[(1<<LL_DEFAULTNORMLOG)+1] = {
+ { 1, 1, 1, LL_DEFAULTNORMLOG}, /* header : fastMode, tableLog */
+ /* nextState, nbAddBits, nbBits, baseVal */
+ { 0, 0, 4, 0}, { 16, 0, 4, 0},
+ { 32, 0, 5, 1}, { 0, 0, 5, 3},
+ { 0, 0, 5, 4}, { 0, 0, 5, 6},
+ { 0, 0, 5, 7}, { 0, 0, 5, 9},
+ { 0, 0, 5, 10}, { 0, 0, 5, 12},
+ { 0, 0, 6, 14}, { 0, 1, 5, 16},
+ { 0, 1, 5, 20}, { 0, 1, 5, 22},
+ { 0, 2, 5, 28}, { 0, 3, 5, 32},
+ { 0, 4, 5, 48}, { 32, 6, 5, 64},
+ { 0, 7, 5, 128}, { 0, 8, 6, 256},
+ { 0, 10, 6, 1024}, { 0, 12, 6, 4096},
+ { 32, 0, 4, 0}, { 0, 0, 4, 1},
+ { 0, 0, 5, 2}, { 32, 0, 5, 4},
+ { 0, 0, 5, 5}, { 32, 0, 5, 7},
+ { 0, 0, 5, 8}, { 32, 0, 5, 10},
+ { 0, 0, 5, 11}, { 0, 0, 6, 13},
+ { 32, 1, 5, 16}, { 0, 1, 5, 18},
+ { 32, 1, 5, 22}, { 0, 2, 5, 24},
+ { 32, 3, 5, 32}, { 0, 3, 5, 40},
+ { 0, 6, 4, 64}, { 16, 6, 4, 64},
+ { 32, 7, 5, 128}, { 0, 9, 6, 512},
+ { 0, 11, 6, 2048}, { 48, 0, 4, 0},
+ { 16, 0, 4, 1}, { 32, 0, 5, 2},
+ { 32, 0, 5, 3}, { 32, 0, 5, 5},
+ { 32, 0, 5, 6}, { 32, 0, 5, 8},
+ { 32, 0, 5, 9}, { 32, 0, 5, 11},
+ { 32, 0, 5, 12}, { 0, 0, 6, 15},
+ { 32, 1, 5, 18}, { 32, 1, 5, 20},
+ { 32, 2, 5, 24}, { 32, 2, 5, 28},
+ { 32, 3, 5, 40}, { 32, 4, 5, 48},
+ { 0, 16, 6,65536}, { 0, 15, 6,32768},
+ { 0, 14, 6,16384}, { 0, 13, 6, 8192},
+}; /* LL_defaultDTable */
+
+/* Default FSE distribution table for Offset Codes */
+static const ZSTD_seqSymbol OF_defaultDTable[(1<<OF_DEFAULTNORMLOG)+1] = {
+ { 1, 1, 1, OF_DEFAULTNORMLOG}, /* header : fastMode, tableLog */
+ /* nextState, nbAddBits, nbBits, baseVal */
+ { 0, 0, 5, 0}, { 0, 6, 4, 61},
+ { 0, 9, 5, 509}, { 0, 15, 5,32765},
+ { 0, 21, 5,2097149}, { 0, 3, 5, 5},
+ { 0, 7, 4, 125}, { 0, 12, 5, 4093},
+ { 0, 18, 5,262141}, { 0, 23, 5,8388605},
+ { 0, 5, 5, 29}, { 0, 8, 4, 253},
+ { 0, 14, 5,16381}, { 0, 20, 5,1048573},
+ { 0, 2, 5, 1}, { 16, 7, 4, 125},
+ { 0, 11, 5, 2045}, { 0, 17, 5,131069},
+ { 0, 22, 5,4194301}, { 0, 4, 5, 13},
+ { 16, 8, 4, 253}, { 0, 13, 5, 8189},
+ { 0, 19, 5,524285}, { 0, 1, 5, 1},
+ { 16, 6, 4, 61}, { 0, 10, 5, 1021},
+ { 0, 16, 5,65533}, { 0, 28, 5,268435453},
+ { 0, 27, 5,134217725}, { 0, 26, 5,67108861},
+ { 0, 25, 5,33554429}, { 0, 24, 5,16777213},
+}; /* OF_defaultDTable */
+
+
+/* Default FSE distribution table for Match Lengths */
+static const ZSTD_seqSymbol ML_defaultDTable[(1<<ML_DEFAULTNORMLOG)+1] = {
+ { 1, 1, 1, ML_DEFAULTNORMLOG}, /* header : fastMode, tableLog */
+ /* nextState, nbAddBits, nbBits, baseVal */
+ { 0, 0, 6, 3}, { 0, 0, 4, 4},
+ { 32, 0, 5, 5}, { 0, 0, 5, 6},
+ { 0, 0, 5, 8}, { 0, 0, 5, 9},
+ { 0, 0, 5, 11}, { 0, 0, 6, 13},
+ { 0, 0, 6, 16}, { 0, 0, 6, 19},
+ { 0, 0, 6, 22}, { 0, 0, 6, 25},
+ { 0, 0, 6, 28}, { 0, 0, 6, 31},
+ { 0, 0, 6, 34}, { 0, 1, 6, 37},
+ { 0, 1, 6, 41}, { 0, 2, 6, 47},
+ { 0, 3, 6, 59}, { 0, 4, 6, 83},
+ { 0, 7, 6, 131}, { 0, 9, 6, 515},
+ { 16, 0, 4, 4}, { 0, 0, 4, 5},
+ { 32, 0, 5, 6}, { 0, 0, 5, 7},
+ { 32, 0, 5, 9}, { 0, 0, 5, 10},
+ { 0, 0, 6, 12}, { 0, 0, 6, 15},
+ { 0, 0, 6, 18}, { 0, 0, 6, 21},
+ { 0, 0, 6, 24}, { 0, 0, 6, 27},
+ { 0, 0, 6, 30}, { 0, 0, 6, 33},
+ { 0, 1, 6, 35}, { 0, 1, 6, 39},
+ { 0, 2, 6, 43}, { 0, 3, 6, 51},
+ { 0, 4, 6, 67}, { 0, 5, 6, 99},
+ { 0, 8, 6, 259}, { 32, 0, 4, 4},
+ { 48, 0, 4, 4}, { 16, 0, 4, 5},
+ { 32, 0, 5, 7}, { 32, 0, 5, 8},
+ { 32, 0, 5, 10}, { 32, 0, 5, 11},
+ { 0, 0, 6, 14}, { 0, 0, 6, 17},
+ { 0, 0, 6, 20}, { 0, 0, 6, 23},
+ { 0, 0, 6, 26}, { 0, 0, 6, 29},
+ { 0, 0, 6, 32}, { 0, 16, 6,65539},
+ { 0, 15, 6,32771}, { 0, 14, 6,16387},
+ { 0, 13, 6, 8195}, { 0, 12, 6, 4099},
+ { 0, 11, 6, 2051}, { 0, 10, 6, 1027},
+}; /* ML_defaultDTable */
+
+
+static void ZSTD_buildSeqTable_rle(ZSTD_seqSymbol* dt, U32 baseValue, U32 nbAddBits)
+{
+ void* ptr = dt;
+ ZSTD_seqSymbol_header* const DTableH = (ZSTD_seqSymbol_header*)ptr;
+ ZSTD_seqSymbol* const cell = dt + 1;
+
+ DTableH->tableLog = 0;
+ DTableH->fastMode = 0;
+
+ cell->nbBits = 0;
+ cell->nextState = 0;
+ assert(nbAddBits < 255);
+ cell->nbAdditionalBits = (BYTE)nbAddBits;
+ cell->baseValue = baseValue;
+}
+
+
+/* ZSTD_buildFSETable() :
+ * generate FSE decoding table for one symbol (ll, ml or off)
+ * cannot fail if input is valid =>
+ * all inputs are presumed validated at this stage */
+void
+ZSTD_buildFSETable(ZSTD_seqSymbol* dt,
+ const short* normalizedCounter, unsigned maxSymbolValue,
+ const U32* baseValue, const U32* nbAdditionalBits,
+ unsigned tableLog)
+{
+ ZSTD_seqSymbol* const tableDecode = dt+1;
+ U16 symbolNext[MaxSeq+1];
+
+ U32 const maxSV1 = maxSymbolValue + 1;
+ U32 const tableSize = 1 << tableLog;
+ U32 highThreshold = tableSize-1;
+
+ /* Sanity Checks */
+ assert(maxSymbolValue <= MaxSeq);
+ assert(tableLog <= MaxFSELog);
+
+ /* Init, lay down lowprob symbols */
+ { ZSTD_seqSymbol_header DTableH;
+ DTableH.tableLog = tableLog;
+ DTableH.fastMode = 1;
+ { S16 const largeLimit= (S16)(1 << (tableLog-1));
+ U32 s;
+ for (s=0; s<maxSV1; s++) {
+ if (normalizedCounter[s]==-1) {
+ tableDecode[highThreshold--].baseValue = s;
+ symbolNext[s] = 1;
+ } else {
+ if (normalizedCounter[s] >= largeLimit) DTableH.fastMode=0;
+ assert(normalizedCounter[s]>=0);
+ symbolNext[s] = (U16)normalizedCounter[s];
+ } } }
+ memcpy(dt, &DTableH, sizeof(DTableH));
+ }
+
+ /* Spread symbols */
+ { U32 const tableMask = tableSize-1;
+ U32 const step = FSE_TABLESTEP(tableSize);
+ U32 s, position = 0;
+ for (s=0; s<maxSV1; s++) {
+ int i;
+ for (i=0; i<normalizedCounter[s]; i++) {
+ tableDecode[position].baseValue = s;
+ position = (position + step) & tableMask;
+ while (position > highThreshold) position = (position + step) & tableMask; /* lowprob area */
+ } }
+ assert(position == 0); /* position must reach all cells once, otherwise normalizedCounter is incorrect */
+ }
+
+ /* Build Decoding table */
+ { U32 u;
+ for (u=0; u<tableSize; u++) {
+ U32 const symbol = tableDecode[u].baseValue;
+ U32 const nextState = symbolNext[symbol]++;
+ tableDecode[u].nbBits = (BYTE) (tableLog - BIT_highbit32(nextState) );
+ tableDecode[u].nextState = (U16) ( (nextState << tableDecode[u].nbBits) - tableSize);
+ assert(nbAdditionalBits[symbol] < 255);
+ tableDecode[u].nbAdditionalBits = (BYTE)nbAdditionalBits[symbol];
+ tableDecode[u].baseValue = baseValue[symbol];
+ } }
+}
+
+
+/*! ZSTD_buildSeqTable() :
+ * @return : nb bytes read from src,
+ * or an error code if it fails */
+static size_t ZSTD_buildSeqTable(ZSTD_seqSymbol* DTableSpace, const ZSTD_seqSymbol** DTablePtr,
+ symbolEncodingType_e type, unsigned max, U32 maxLog,
+ const void* src, size_t srcSize,
+ const U32* baseValue, const U32* nbAdditionalBits,
+ const ZSTD_seqSymbol* defaultTable, U32 flagRepeatTable,
+ int ddictIsCold, int nbSeq)
+{
+ switch(type)
+ {
+ case set_rle :
+ RETURN_ERROR_IF(!srcSize, srcSize_wrong, "");
+ RETURN_ERROR_IF((*(const BYTE*)src) > max, corruption_detected, "");
+ { U32 const symbol = *(const BYTE*)src;
+ U32 const baseline = baseValue[symbol];
+ U32 const nbBits = nbAdditionalBits[symbol];
+ ZSTD_buildSeqTable_rle(DTableSpace, baseline, nbBits);
+ }
+ *DTablePtr = DTableSpace;
+ return 1;
+ case set_basic :
+ *DTablePtr = defaultTable;
+ return 0;
+ case set_repeat:
+ RETURN_ERROR_IF(!flagRepeatTable, corruption_detected, "");
+ /* prefetch FSE table if used */
+ if (ddictIsCold && (nbSeq > 24 /* heuristic */)) {
+ const void* const pStart = *DTablePtr;
+ size_t const pSize = sizeof(ZSTD_seqSymbol) * (SEQSYMBOL_TABLE_SIZE(maxLog));
+ PREFETCH_AREA(pStart, pSize);
+ }
+ return 0;
+ case set_compressed :
+ { unsigned tableLog;
+ S16 norm[MaxSeq+1];
+ size_t const headerSize = FSE_readNCount(norm, &max, &tableLog, src, srcSize);
+ RETURN_ERROR_IF(FSE_isError(headerSize), corruption_detected, "");
+ RETURN_ERROR_IF(tableLog > maxLog, corruption_detected, "");
+ ZSTD_buildFSETable(DTableSpace, norm, max, baseValue, nbAdditionalBits, tableLog);
+ *DTablePtr = DTableSpace;
+ return headerSize;
+ }
+ default :
+ assert(0);
+ RETURN_ERROR(GENERIC, "impossible");
+ }
+}
+
+size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr,
+ const void* src, size_t srcSize)
+{
+ const BYTE* const istart = (const BYTE* const)src;
+ const BYTE* const iend = istart + srcSize;
+ const BYTE* ip = istart;
+ int nbSeq;
+ DEBUGLOG(5, "ZSTD_decodeSeqHeaders");
+
+ /* check */
+ RETURN_ERROR_IF(srcSize < MIN_SEQUENCES_SIZE, srcSize_wrong, "");
+
+ /* SeqHead */
+ nbSeq = *ip++;
+ if (!nbSeq) {
+ *nbSeqPtr=0;
+ RETURN_ERROR_IF(srcSize != 1, srcSize_wrong, "");
+ return 1;
+ }
+ if (nbSeq > 0x7F) {
+ if (nbSeq == 0xFF) {
+ RETURN_ERROR_IF(ip+2 > iend, srcSize_wrong, "");
+ nbSeq = MEM_readLE16(ip) + LONGNBSEQ, ip+=2;
+ } else {
+ RETURN_ERROR_IF(ip >= iend, srcSize_wrong, "");
+ nbSeq = ((nbSeq-0x80)<<8) + *ip++;
+ }
+ }
+ *nbSeqPtr = nbSeq;
+
+ /* FSE table descriptors */
+ RETURN_ERROR_IF(ip+1 > iend, srcSize_wrong, ""); /* minimum possible size: 1 byte for symbol encoding types */
+ { symbolEncodingType_e const LLtype = (symbolEncodingType_e)(*ip >> 6);
+ symbolEncodingType_e const OFtype = (symbolEncodingType_e)((*ip >> 4) & 3);
+ symbolEncodingType_e const MLtype = (symbolEncodingType_e)((*ip >> 2) & 3);
+ ip++;
+
+ /* Build DTables */
+ { size_t const llhSize = ZSTD_buildSeqTable(dctx->entropy.LLTable, &dctx->LLTptr,
+ LLtype, MaxLL, LLFSELog,
+ ip, iend-ip,
+ LL_base, LL_bits,
+ LL_defaultDTable, dctx->fseEntropy,
+ dctx->ddictIsCold, nbSeq);
+ RETURN_ERROR_IF(ZSTD_isError(llhSize), corruption_detected, "ZSTD_buildSeqTable failed");
+ ip += llhSize;
+ }
+
+ { size_t const ofhSize = ZSTD_buildSeqTable(dctx->entropy.OFTable, &dctx->OFTptr,
+ OFtype, MaxOff, OffFSELog,
+ ip, iend-ip,
+ OF_base, OF_bits,
+ OF_defaultDTable, dctx->fseEntropy,
+ dctx->ddictIsCold, nbSeq);
+ RETURN_ERROR_IF(ZSTD_isError(ofhSize), corruption_detected, "ZSTD_buildSeqTable failed");
+ ip += ofhSize;
+ }
+
+ { size_t const mlhSize = ZSTD_buildSeqTable(dctx->entropy.MLTable, &dctx->MLTptr,
+ MLtype, MaxML, MLFSELog,
+ ip, iend-ip,
+ ML_base, ML_bits,
+ ML_defaultDTable, dctx->fseEntropy,
+ dctx->ddictIsCold, nbSeq);
+ RETURN_ERROR_IF(ZSTD_isError(mlhSize), corruption_detected, "ZSTD_buildSeqTable failed");
+ ip += mlhSize;
+ }
+ }
+
+ return ip-istart;
+}
+
+
+typedef struct {
+ size_t litLength;
+ size_t matchLength;
+ size_t offset;
+ const BYTE* match;
+} seq_t;
+
+typedef struct {
+ size_t state;
+ const ZSTD_seqSymbol* table;
+} ZSTD_fseState;
+
+typedef struct {
+ BIT_DStream_t DStream;
+ ZSTD_fseState stateLL;
+ ZSTD_fseState stateOffb;
+ ZSTD_fseState stateML;
+ size_t prevOffset[ZSTD_REP_NUM];
+ const BYTE* prefixStart;
+ const BYTE* dictEnd;
+ size_t pos;
+} seqState_t;
+
+/*! ZSTD_overlapCopy8() :
+ * Copies 8 bytes from ip to op and updates op and ip where ip <= op.
+ * If the offset is < 8 then the offset is spread to at least 8 bytes.
+ *
+ * Precondition: *ip <= *op
+ * Postcondition: *op - *op >= 8
+ */
+HINT_INLINE void ZSTD_overlapCopy8(BYTE** op, BYTE const** ip, size_t offset) {
+ assert(*ip <= *op);
+ if (offset < 8) {
+ /* close range match, overlap */
+ static const U32 dec32table[] = { 0, 1, 2, 1, 4, 4, 4, 4 }; /* added */
+ static const int dec64table[] = { 8, 8, 8, 7, 8, 9,10,11 }; /* subtracted */
+ int const sub2 = dec64table[offset];
+ (*op)[0] = (*ip)[0];
+ (*op)[1] = (*ip)[1];
+ (*op)[2] = (*ip)[2];
+ (*op)[3] = (*ip)[3];
+ *ip += dec32table[offset];
+ ZSTD_copy4(*op+4, *ip);
+ *ip -= sub2;
+ } else {
+ ZSTD_copy8(*op, *ip);
+ }
+ *ip += 8;
+ *op += 8;
+ assert(*op - *ip >= 8);
+}
+
+/*! ZSTD_safecopy() :
+ * Specialized version of memcpy() that is allowed to READ up to WILDCOPY_OVERLENGTH past the input buffer
+ * and write up to 16 bytes past oend_w (op >= oend_w is allowed).
+ * This function is only called in the uncommon case where the sequence is near the end of the block. It
+ * should be fast for a single long sequence, but can be slow for several short sequences.
+ *
+ * @param ovtype controls the overlap detection
+ * - ZSTD_no_overlap: The source and destination are guaranteed to be at least WILDCOPY_VECLEN bytes apart.
+ * - ZSTD_overlap_src_before_dst: The src and dst may overlap and may be any distance apart.
+ * The src buffer must be before the dst buffer.
+ */
+static void ZSTD_safecopy(BYTE* op, BYTE* const oend_w, BYTE const* ip, ptrdiff_t length, ZSTD_overlap_e ovtype) {
+ ptrdiff_t const diff = op - ip;
+ BYTE* const oend = op + length;
+
+ assert((ovtype == ZSTD_no_overlap && (diff <= -8 || diff >= 8 || op >= oend_w)) ||
+ (ovtype == ZSTD_overlap_src_before_dst && diff >= 0));
+
+ if (length < 8) {
+ /* Handle short lengths. */
+ while (op < oend) *op++ = *ip++;
+ return;
+ }
+ if (ovtype == ZSTD_overlap_src_before_dst) {
+ /* Copy 8 bytes and ensure the offset >= 8 when there can be overlap. */
+ assert(length >= 8);
+ ZSTD_overlapCopy8(&op, &ip, diff);
+ assert(op - ip >= 8);
+ assert(op <= oend);
+ }
+
+ if (oend <= oend_w) {
+ /* No risk of overwrite. */
+ ZSTD_wildcopy(op, ip, length, ovtype);
+ return;
+ }
+ if (op <= oend_w) {
+ /* Wildcopy until we get close to the end. */
+ assert(oend > oend_w);
+ ZSTD_wildcopy(op, ip, oend_w - op, ovtype);
+ ip += oend_w - op;
+ op = oend_w;
+ }
+ /* Handle the leftovers. */
+ while (op < oend) *op++ = *ip++;
+}
+
+/* ZSTD_execSequenceEnd():
+ * This version handles cases that are near the end of the output buffer. It requires
+ * more careful checks to make sure there is no overflow. By separating out these hard
+ * and unlikely cases, we can speed up the common cases.
+ *
+ * NOTE: This function needs to be fast for a single long sequence, but doesn't need
+ * to be optimized for many small sequences, since those fall into ZSTD_execSequence().
+ */
+FORCE_NOINLINE
+size_t ZSTD_execSequenceEnd(BYTE* op,
+ BYTE* const oend, seq_t sequence,
+ const BYTE** litPtr, const BYTE* const litLimit,
+ const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd)
+{
+ BYTE* const oLitEnd = op + sequence.litLength;
+ size_t const sequenceLength = sequence.litLength + sequence.matchLength;
+ const BYTE* const iLitEnd = *litPtr + sequence.litLength;
+ const BYTE* match = oLitEnd - sequence.offset;
+ BYTE* const oend_w = oend - WILDCOPY_OVERLENGTH;
+
+ /* bounds checks : careful of address space overflow in 32-bit mode */
+ RETURN_ERROR_IF(sequenceLength > (size_t)(oend - op), dstSize_tooSmall, "last match must fit within dstBuffer");
+ RETURN_ERROR_IF(sequence.litLength > (size_t)(litLimit - *litPtr), corruption_detected, "try to read beyond literal buffer");
+ assert(op < op + sequenceLength);
+ assert(oLitEnd < op + sequenceLength);
+
+ /* copy literals */
+ ZSTD_safecopy(op, oend_w, *litPtr, sequence.litLength, ZSTD_no_overlap);
+ op = oLitEnd;
+ *litPtr = iLitEnd;
+
+ /* copy Match */
+ if (sequence.offset > (size_t)(oLitEnd - prefixStart)) {
+ /* offset beyond prefix */
+ RETURN_ERROR_IF(sequence.offset > (size_t)(oLitEnd - virtualStart), corruption_detected, "");
+ match = dictEnd - (prefixStart-match);
+ if (match + sequence.matchLength <= dictEnd) {
+ memmove(oLitEnd, match, sequence.matchLength);
+ return sequenceLength;
+ }
+ /* span extDict & currentPrefixSegment */
+ { size_t const length1 = dictEnd - match;
+ memmove(oLitEnd, match, length1);
+ op = oLitEnd + length1;
+ sequence.matchLength -= length1;
+ match = prefixStart;
+ } }
+ ZSTD_safecopy(op, oend_w, match, sequence.matchLength, ZSTD_overlap_src_before_dst);
+ return sequenceLength;
+}
+
+HINT_INLINE
+size_t ZSTD_execSequence(BYTE* op,
+ BYTE* const oend, seq_t sequence,
+ const BYTE** litPtr, const BYTE* const litLimit,
+ const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd)
+{
+ BYTE* const oLitEnd = op + sequence.litLength;
+ size_t const sequenceLength = sequence.litLength + sequence.matchLength;
+ BYTE* const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */
+ BYTE* const oend_w = oend - WILDCOPY_OVERLENGTH; /* risk : address space underflow on oend=NULL */
+ const BYTE* const iLitEnd = *litPtr + sequence.litLength;
+ const BYTE* match = oLitEnd - sequence.offset;
+
+ assert(op != NULL /* Precondition */);
+ assert(oend_w < oend /* No underflow */);
+ /* Handle edge cases in a slow path:
+ * - Read beyond end of literals
+ * - Match end is within WILDCOPY_OVERLIMIT of oend
+ * - 32-bit mode and the match length overflows
+ */
+ if (UNLIKELY(
+ iLitEnd > litLimit ||
+ oMatchEnd > oend_w ||
+ (MEM_32bits() && (size_t)(oend - op) < sequenceLength + WILDCOPY_OVERLENGTH)))
+ return ZSTD_execSequenceEnd(op, oend, sequence, litPtr, litLimit, prefixStart, virtualStart, dictEnd);
+
+ /* Assumptions (everything else goes into ZSTD_execSequenceEnd()) */
+ assert(op <= oLitEnd /* No overflow */);
+ assert(oLitEnd < oMatchEnd /* Non-zero match & no overflow */);
+ assert(oMatchEnd <= oend /* No underflow */);
+ assert(iLitEnd <= litLimit /* Literal length is in bounds */);
+ assert(oLitEnd <= oend_w /* Can wildcopy literals */);
+ assert(oMatchEnd <= oend_w /* Can wildcopy matches */);
+
+ /* Copy Literals:
+ * Split out litLength <= 16 since it is nearly always true. +1.6% on gcc-9.
+ * We likely don't need the full 32-byte wildcopy.
+ */
+ assert(WILDCOPY_OVERLENGTH >= 16);
+ ZSTD_copy16(op, (*litPtr));
+ if (UNLIKELY(sequence.litLength > 16)) {
+ ZSTD_wildcopy(op+16, (*litPtr)+16, sequence.litLength-16, ZSTD_no_overlap);
+ }
+ op = oLitEnd;
+ *litPtr = iLitEnd; /* update for next sequence */
+
+ /* Copy Match */
+ if (sequence.offset > (size_t)(oLitEnd - prefixStart)) {
+ /* offset beyond prefix -> go into extDict */
+ RETURN_ERROR_IF(UNLIKELY(sequence.offset > (size_t)(oLitEnd - virtualStart)), corruption_detected, "");
+ match = dictEnd + (match - prefixStart);
+ if (match + sequence.matchLength <= dictEnd) {
+ memmove(oLitEnd, match, sequence.matchLength);
+ return sequenceLength;
+ }
+ /* span extDict & currentPrefixSegment */
+ { size_t const length1 = dictEnd - match;
+ memmove(oLitEnd, match, length1);
+ op = oLitEnd + length1;
+ sequence.matchLength -= length1;
+ match = prefixStart;
+ } }
+ /* Match within prefix of 1 or more bytes */
+ assert(op <= oMatchEnd);
+ assert(oMatchEnd <= oend_w);
+ assert(match >= prefixStart);
+ assert(sequence.matchLength >= 1);
+
+ /* Nearly all offsets are >= WILDCOPY_VECLEN bytes, which means we can use wildcopy
+ * without overlap checking.
+ */
+ if (LIKELY(sequence.offset >= WILDCOPY_VECLEN)) {
+ /* We bet on a full wildcopy for matches, since we expect matches to be
+ * longer than literals (in general). In silesia, ~10% of matches are longer
+ * than 16 bytes.
+ */
+ ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength, ZSTD_no_overlap);
+ return sequenceLength;
+ }
+ assert(sequence.offset < WILDCOPY_VECLEN);
+
+ /* Copy 8 bytes and spread the offset to be >= 8. */
+ ZSTD_overlapCopy8(&op, &match, sequence.offset);
+
+ /* If the match length is > 8 bytes, then continue with the wildcopy. */
+ if (sequence.matchLength > 8) {
+ assert(op < oMatchEnd);
+ ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength-8, ZSTD_overlap_src_before_dst);
+ }
+ return sequenceLength;
+}
+
+static void
+ZSTD_initFseState(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, const ZSTD_seqSymbol* dt)
+{
+ const void* ptr = dt;
+ const ZSTD_seqSymbol_header* const DTableH = (const ZSTD_seqSymbol_header*)ptr;
+ DStatePtr->state = BIT_readBits(bitD, DTableH->tableLog);
+ DEBUGLOG(6, "ZSTD_initFseState : val=%u using %u bits",
+ (U32)DStatePtr->state, DTableH->tableLog);
+ BIT_reloadDStream(bitD);
+ DStatePtr->table = dt + 1;
+}
+
+FORCE_INLINE_TEMPLATE void
+ZSTD_updateFseState(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD)
+{
+ ZSTD_seqSymbol const DInfo = DStatePtr->table[DStatePtr->state];
+ U32 const nbBits = DInfo.nbBits;
+ size_t const lowBits = BIT_readBits(bitD, nbBits);
+ DStatePtr->state = DInfo.nextState + lowBits;
+}
+
+FORCE_INLINE_TEMPLATE void
+ZSTD_updateFseStateWithDInfo(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, ZSTD_seqSymbol const DInfo)
+{
+ U32 const nbBits = DInfo.nbBits;
+ size_t const lowBits = BIT_readBits(bitD, nbBits);
+ DStatePtr->state = DInfo.nextState + lowBits;
+}
+
+/* We need to add at most (ZSTD_WINDOWLOG_MAX_32 - 1) bits to read the maximum
+ * offset bits. But we can only read at most (STREAM_ACCUMULATOR_MIN_32 - 1)
+ * bits before reloading. This value is the maximum number of bytes we read
+ * after reloading when we are decoding long offsets.
+ */
+#define LONG_OFFSETS_MAX_EXTRA_BITS_32 \
+ (ZSTD_WINDOWLOG_MAX_32 > STREAM_ACCUMULATOR_MIN_32 \
+ ? ZSTD_WINDOWLOG_MAX_32 - STREAM_ACCUMULATOR_MIN_32 \
+ : 0)
+
+typedef enum { ZSTD_lo_isRegularOffset, ZSTD_lo_isLongOffset=1 } ZSTD_longOffset_e;
+typedef enum { ZSTD_p_noPrefetch=0, ZSTD_p_prefetch=1 } ZSTD_prefetch_e;
+
+FORCE_INLINE_TEMPLATE seq_t
+ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets, const ZSTD_prefetch_e prefetch)
+{
+ seq_t seq;
+ ZSTD_seqSymbol const llDInfo = seqState->stateLL.table[seqState->stateLL.state];
+ ZSTD_seqSymbol const mlDInfo = seqState->stateML.table[seqState->stateML.state];
+ ZSTD_seqSymbol const ofDInfo = seqState->stateOffb.table[seqState->stateOffb.state];
+ U32 const llBase = llDInfo.baseValue;
+ U32 const mlBase = mlDInfo.baseValue;
+ U32 const ofBase = ofDInfo.baseValue;
+ BYTE const llBits = llDInfo.nbAdditionalBits;
+ BYTE const mlBits = mlDInfo.nbAdditionalBits;
+ BYTE const ofBits = ofDInfo.nbAdditionalBits;
+ BYTE const totalBits = llBits+mlBits+ofBits;
+
+ /* sequence */
+ { size_t offset;
+ if (ofBits > 1) {
+ ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1);
+ ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5);
+ assert(ofBits <= MaxOff);
+ if (MEM_32bits() && longOffsets && (ofBits >= STREAM_ACCUMULATOR_MIN_32)) {
+ U32 const extraBits = ofBits - MIN(ofBits, 32 - seqState->DStream.bitsConsumed);
+ offset = ofBase + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits);
+ BIT_reloadDStream(&seqState->DStream);
+ if (extraBits) offset += BIT_readBitsFast(&seqState->DStream, extraBits);
+ assert(extraBits <= LONG_OFFSETS_MAX_EXTRA_BITS_32); /* to avoid another reload */
+ } else {
+ offset = ofBase + BIT_readBitsFast(&seqState->DStream, ofBits/*>0*/); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */
+ if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream);
+ }
+ seqState->prevOffset[2] = seqState->prevOffset[1];
+ seqState->prevOffset[1] = seqState->prevOffset[0];
+ seqState->prevOffset[0] = offset;
+ } else {
+ U32 const ll0 = (llBase == 0);
+ if (LIKELY((ofBits == 0))) {
+ if (LIKELY(!ll0))
+ offset = seqState->prevOffset[0];
+ else {
+ offset = seqState->prevOffset[1];
+ seqState->prevOffset[1] = seqState->prevOffset[0];
+ seqState->prevOffset[0] = offset;
+ }
+ } else {
+ offset = ofBase + ll0 + BIT_readBitsFast(&seqState->DStream, 1);
+ { size_t temp = (offset==3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset];
+ temp += !temp; /* 0 is not valid; input is corrupted; force offset to 1 */
+ if (offset != 1) seqState->prevOffset[2] = seqState->prevOffset[1];
+ seqState->prevOffset[1] = seqState->prevOffset[0];
+ seqState->prevOffset[0] = offset = temp;
+ } } }
+ seq.offset = offset;
+ }
+
+ seq.matchLength = mlBase;
+ if (mlBits > 0)
+ seq.matchLength += BIT_readBitsFast(&seqState->DStream, mlBits/*>0*/);
+
+ if (MEM_32bits() && (mlBits+llBits >= STREAM_ACCUMULATOR_MIN_32-LONG_OFFSETS_MAX_EXTRA_BITS_32))
+ BIT_reloadDStream(&seqState->DStream);
+ if (MEM_64bits() && UNLIKELY(totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog)))
+ BIT_reloadDStream(&seqState->DStream);
+ /* Ensure there are enough bits to read the rest of data in 64-bit mode. */
+ ZSTD_STATIC_ASSERT(16+LLFSELog+MLFSELog+OffFSELog < STREAM_ACCUMULATOR_MIN_64);
+
+ seq.litLength = llBase;
+ if (llBits > 0)
+ seq.litLength += BIT_readBitsFast(&seqState->DStream, llBits/*>0*/);
+
+ if (MEM_32bits())
+ BIT_reloadDStream(&seqState->DStream);
+
+ DEBUGLOG(6, "seq: litL=%u, matchL=%u, offset=%u",
+ (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset);
+
+ if (prefetch == ZSTD_p_prefetch) {
+ size_t const pos = seqState->pos + seq.litLength;
+ const BYTE* const matchBase = (seq.offset > pos) ? seqState->dictEnd : seqState->prefixStart;
+ seq.match = matchBase + pos - seq.offset; /* note : this operation can overflow when seq.offset is really too large, which can only happen when input is corrupted.
+ * No consequence though : no memory access will occur, offset is only used for prefetching */
+ seqState->pos = pos + seq.matchLength;
+ }
+
+ /* ANS state update
+ * gcc-9.0.0 does 2.5% worse with ZSTD_updateFseStateWithDInfo().
+ * clang-9.2.0 does 7% worse with ZSTD_updateFseState().
+ * Naturally it seems like ZSTD_updateFseStateWithDInfo() should be the
+ * better option, so it is the default for other compilers. But, if you
+ * measure that it is worse, please put up a pull request.
+ */
+ {
+#if defined(__GNUC__) && !defined(__clang__)
+ const int kUseUpdateFseState = 1;
+#else
+ const int kUseUpdateFseState = 0;
+#endif
+ if (kUseUpdateFseState) {
+ ZSTD_updateFseState(&seqState->stateLL, &seqState->DStream); /* <= 9 bits */
+ ZSTD_updateFseState(&seqState->stateML, &seqState->DStream); /* <= 9 bits */
+ if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */
+ ZSTD_updateFseState(&seqState->stateOffb, &seqState->DStream); /* <= 8 bits */
+ } else {
+ ZSTD_updateFseStateWithDInfo(&seqState->stateLL, &seqState->DStream, llDInfo); /* <= 9 bits */
+ ZSTD_updateFseStateWithDInfo(&seqState->stateML, &seqState->DStream, mlDInfo); /* <= 9 bits */
+ if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */
+ ZSTD_updateFseStateWithDInfo(&seqState->stateOffb, &seqState->DStream, ofDInfo); /* <= 8 bits */
+ }
+ }
+
+ return seq;
+}
+
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+static int ZSTD_dictionaryIsActive(ZSTD_DCtx const* dctx, BYTE const* prefixStart, BYTE const* oLitEnd)
+{
+ size_t const windowSize = dctx->fParams.windowSize;
+ /* No dictionary used. */
+ if (dctx->dictContentEndForFuzzing == NULL) return 0;
+ /* Dictionary is our prefix. */
+ if (prefixStart == dctx->dictContentBeginForFuzzing) return 1;
+ /* Dictionary is not our ext-dict. */
+ if (dctx->dictEnd != dctx->dictContentEndForFuzzing) return 0;
+ /* Dictionary is not within our window size. */
+ if ((size_t)(oLitEnd - prefixStart) >= windowSize) return 0;
+ /* Dictionary is active. */
+ return 1;
+}
+
+MEM_STATIC void ZSTD_assertValidSequence(
+ ZSTD_DCtx const* dctx,
+ BYTE const* op, BYTE const* oend,
+ seq_t const seq,
+ BYTE const* prefixStart, BYTE const* virtualStart)
+{
+ size_t const windowSize = dctx->fParams.windowSize;
+ size_t const sequenceSize = seq.litLength + seq.matchLength;
+ BYTE const* const oLitEnd = op + seq.litLength;
+ DEBUGLOG(6, "Checking sequence: litL=%u matchL=%u offset=%u",
+ (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset);
+ assert(op <= oend);
+ assert((size_t)(oend - op) >= sequenceSize);
+ assert(sequenceSize <= ZSTD_BLOCKSIZE_MAX);
+ if (ZSTD_dictionaryIsActive(dctx, prefixStart, oLitEnd)) {
+ size_t const dictSize = (size_t)((char const*)dctx->dictContentEndForFuzzing - (char const*)dctx->dictContentBeginForFuzzing);
+ /* Offset must be within the dictionary. */
+ assert(seq.offset <= (size_t)(oLitEnd - virtualStart));
+ assert(seq.offset <= windowSize + dictSize);
+ } else {
+ /* Offset must be within our window. */
+ assert(seq.offset <= windowSize);
+ }
+}
+#endif
+
+#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG
+FORCE_INLINE_TEMPLATE size_t
+DONT_VECTORIZE
+ZSTD_decompressSequences_body( ZSTD_DCtx* dctx,
+ void* dst, size_t maxDstSize,
+ const void* seqStart, size_t seqSize, int nbSeq,
+ const ZSTD_longOffset_e isLongOffset,
+ const int frame)
+{
+ const BYTE* ip = (const BYTE*)seqStart;
+ const BYTE* const iend = ip + seqSize;
+ BYTE* const ostart = (BYTE* const)dst;
+ BYTE* const oend = ostart + maxDstSize;
+ BYTE* op = ostart;
+ const BYTE* litPtr = dctx->litPtr;
+ const BYTE* const litEnd = litPtr + dctx->litSize;
+ const BYTE* const prefixStart = (const BYTE*) (dctx->prefixStart);
+ const BYTE* const vBase = (const BYTE*) (dctx->virtualStart);
+ const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd);
+ DEBUGLOG(5, "ZSTD_decompressSequences_body");
+ (void)frame;
+
+ /* Regen sequences */
+ if (nbSeq) {
+ seqState_t seqState;
+ size_t error = 0;
+ dctx->fseEntropy = 1;
+ { U32 i; for (i=0; i<ZSTD_REP_NUM; i++) seqState.prevOffset[i] = dctx->entropy.rep[i]; }
+ RETURN_ERROR_IF(
+ ERR_isError(BIT_initDStream(&seqState.DStream, ip, iend-ip)),
+ corruption_detected, "");
+ ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr);
+ ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr);
+ ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr);
+ assert(dst != NULL);
+
+ ZSTD_STATIC_ASSERT(
+ BIT_DStream_unfinished < BIT_DStream_completed &&
+ BIT_DStream_endOfBuffer < BIT_DStream_completed &&
+ BIT_DStream_completed < BIT_DStream_overflow);
+
+#if defined(__GNUC__) && defined(__x86_64__)
+ /* Align the decompression loop to 32 + 16 bytes.
+ *
+ * zstd compiled with gcc-9 on an Intel i9-9900k shows 10% decompression
+ * speed swings based on the alignment of the decompression loop. This
+ * performance swing is caused by parts of the decompression loop falling
+ * out of the DSB. The entire decompression loop should fit in the DSB,
+ * when it can't we get much worse performance. You can measure if you've
+ * hit the good case or the bad case with this perf command for some
+ * compressed file test.zst:
+ *
+ * perf stat -e cycles -e instructions -e idq.all_dsb_cycles_any_uops \
+ * -e idq.all_mite_cycles_any_uops -- ./zstd -tq test.zst
+ *
+ * If you see most cycles served out of the MITE you've hit the bad case.
+ * If you see most cycles served out of the DSB you've hit the good case.
+ * If it is pretty even then you may be in an okay case.
+ *
+ * I've been able to reproduce this issue on the following CPUs:
+ * - Kabylake: Macbook Pro (15-inch, 2019) 2.4 GHz Intel Core i9
+ * Use Instruments->Counters to get DSB/MITE cycles.
+ * I never got performance swings, but I was able to
+ * go from the good case of mostly DSB to half of the
+ * cycles served from MITE.
+ * - Coffeelake: Intel i9-9900k
+ *
+ * I haven't been able to reproduce the instability or DSB misses on any
+ * of the following CPUS:
+ * - Haswell
+ * - Broadwell: Intel(R) Xeon(R) CPU E5-2680 v4 @ 2.40GH
+ * - Skylake
+ *
+ * If you are seeing performance stability this script can help test.
+ * It tests on 4 commits in zstd where I saw performance change.
+ *
+ * https://gist.github.com/terrelln/9889fc06a423fd5ca6e99351564473f4
+ */
+ __asm__(".p2align 5");
+ __asm__("nop");
+ __asm__(".p2align 4");
+#endif
+ for ( ; ; ) {
+ seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset, ZSTD_p_noPrefetch);
+ size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litEnd, prefixStart, vBase, dictEnd);
+#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE)
+ assert(!ZSTD_isError(oneSeqSize));
+ if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase);
+#endif
+ DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize);
+ BIT_reloadDStream(&(seqState.DStream));
+ /* gcc and clang both don't like early returns in this loop.
+ * gcc doesn't like early breaks either.
+ * Instead save an error and report it at the end.
+ * When there is an error, don't increment op, so we don't
+ * overwrite.
+ */
+ if (UNLIKELY(ZSTD_isError(oneSeqSize))) error = oneSeqSize;
+ else op += oneSeqSize;
+ if (UNLIKELY(!--nbSeq)) break;
+ }
+
+ /* check if reached exact end */
+ DEBUGLOG(5, "ZSTD_decompressSequences_body: after decode loop, remaining nbSeq : %i", nbSeq);
+ if (ZSTD_isError(error)) return error;
+ RETURN_ERROR_IF(nbSeq, corruption_detected, "");
+ RETURN_ERROR_IF(BIT_reloadDStream(&seqState.DStream) < BIT_DStream_completed, corruption_detected, "");
+ /* save reps for next block */
+ { U32 i; for (i=0; i<ZSTD_REP_NUM; i++) dctx->entropy.rep[i] = (U32)(seqState.prevOffset[i]); }
+ }
+
+ /* last literal segment */
+ { size_t const lastLLSize = litEnd - litPtr;
+ RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, "");
+ if (op != NULL) {
+ memcpy(op, litPtr, lastLLSize);
+ op += lastLLSize;
+ }
+ }
+
+ return op-ostart;
+}
+
+static size_t
+ZSTD_decompressSequences_default(ZSTD_DCtx* dctx,
+ void* dst, size_t maxDstSize,
+ const void* seqStart, size_t seqSize, int nbSeq,
+ const ZSTD_longOffset_e isLongOffset,
+ const int frame)
+{
+ return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
+}
+#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */
+
+#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT
+FORCE_INLINE_TEMPLATE size_t
+ZSTD_decompressSequencesLong_body(
+ ZSTD_DCtx* dctx,
+ void* dst, size_t maxDstSize,
+ const void* seqStart, size_t seqSize, int nbSeq,
+ const ZSTD_longOffset_e isLongOffset,
+ const int frame)
+{
+ const BYTE* ip = (const BYTE*)seqStart;
+ const BYTE* const iend = ip + seqSize;
+ BYTE* const ostart = (BYTE* const)dst;
+ BYTE* const oend = ostart + maxDstSize;
+ BYTE* op = ostart;
+ const BYTE* litPtr = dctx->litPtr;
+ const BYTE* const litEnd = litPtr + dctx->litSize;
+ const BYTE* const prefixStart = (const BYTE*) (dctx->prefixStart);
+ const BYTE* const dictStart = (const BYTE*) (dctx->virtualStart);
+ const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd);
+ (void)frame;
+
+ /* Regen sequences */
+ if (nbSeq) {
+#define STORED_SEQS 4
+#define STORED_SEQS_MASK (STORED_SEQS-1)
+#define ADVANCED_SEQS 4
+ seq_t sequences[STORED_SEQS];
+ int const seqAdvance = MIN(nbSeq, ADVANCED_SEQS);
+ seqState_t seqState;
+ int seqNb;
+ dctx->fseEntropy = 1;
+ { int i; for (i=0; i<ZSTD_REP_NUM; i++) seqState.prevOffset[i] = dctx->entropy.rep[i]; }
+ seqState.prefixStart = prefixStart;
+ seqState.pos = (size_t)(op-prefixStart);
+ seqState.dictEnd = dictEnd;
+ assert(dst != NULL);
+ assert(iend >= ip);
+ RETURN_ERROR_IF(
+ ERR_isError(BIT_initDStream(&seqState.DStream, ip, iend-ip)),
+ corruption_detected, "");
+ ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr);
+ ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr);
+ ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr);
+
+ /* prepare in advance */
+ for (seqNb=0; (BIT_reloadDStream(&seqState.DStream) <= BIT_DStream_completed) && (seqNb<seqAdvance); seqNb++) {
+ sequences[seqNb] = ZSTD_decodeSequence(&seqState, isLongOffset, ZSTD_p_prefetch);
+ PREFETCH_L1(sequences[seqNb].match); PREFETCH_L1(sequences[seqNb].match + sequences[seqNb].matchLength - 1); /* note : it's safe to invoke PREFETCH() on any memory address, including invalid ones */
+ }
+ RETURN_ERROR_IF(seqNb<seqAdvance, corruption_detected, "");
+
+ /* decode and decompress */
+ for ( ; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && (seqNb<nbSeq) ; seqNb++) {
+ seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset, ZSTD_p_prefetch);
+ size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequences[(seqNb-ADVANCED_SEQS) & STORED_SEQS_MASK], &litPtr, litEnd, prefixStart, dictStart, dictEnd);
+#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE)
+ assert(!ZSTD_isError(oneSeqSize));
+ if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[(seqNb-ADVANCED_SEQS) & STORED_SEQS_MASK], prefixStart, dictStart);
+#endif
+ if (ZSTD_isError(oneSeqSize)) return oneSeqSize;
+ PREFETCH_L1(sequence.match); PREFETCH_L1(sequence.match + sequence.matchLength - 1); /* note : it's safe to invoke PREFETCH() on any memory address, including invalid ones */
+ sequences[seqNb & STORED_SEQS_MASK] = sequence;
+ op += oneSeqSize;
+ }
+ RETURN_ERROR_IF(seqNb<nbSeq, corruption_detected, "");
+
+ /* finish queue */
+ seqNb -= seqAdvance;
+ for ( ; seqNb<nbSeq ; seqNb++) {
+ size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequences[seqNb&STORED_SEQS_MASK], &litPtr, litEnd, prefixStart, dictStart, dictEnd);
+#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE)
+ assert(!ZSTD_isError(oneSeqSize));
+ if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[seqNb&STORED_SEQS_MASK], prefixStart, dictStart);
+#endif
+ if (ZSTD_isError(oneSeqSize)) return oneSeqSize;
+ op += oneSeqSize;
+ }
+
+ /* save reps for next block */
+ { U32 i; for (i=0; i<ZSTD_REP_NUM; i++) dctx->entropy.rep[i] = (U32)(seqState.prevOffset[i]); }
+ }
+
+ /* last literal segment */
+ { size_t const lastLLSize = litEnd - litPtr;
+ RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, "");
+ if (op != NULL) {
+ memcpy(op, litPtr, lastLLSize);
+ op += lastLLSize;
+ }
+ }
+
+ return op-ostart;
+}
+
+static size_t
+ZSTD_decompressSequencesLong_default(ZSTD_DCtx* dctx,
+ void* dst, size_t maxDstSize,
+ const void* seqStart, size_t seqSize, int nbSeq,
+ const ZSTD_longOffset_e isLongOffset,
+ const int frame)
+{
+ return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
+}
+#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */
+
+
+
+#if DYNAMIC_BMI2
+
+#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG
+static TARGET_ATTRIBUTE("bmi2") size_t
+DONT_VECTORIZE
+ZSTD_decompressSequences_bmi2(ZSTD_DCtx* dctx,
+ void* dst, size_t maxDstSize,
+ const void* seqStart, size_t seqSize, int nbSeq,
+ const ZSTD_longOffset_e isLongOffset,
+ const int frame)
+{
+ return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
+}
+#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */
+
+#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT
+static TARGET_ATTRIBUTE("bmi2") size_t
+ZSTD_decompressSequencesLong_bmi2(ZSTD_DCtx* dctx,
+ void* dst, size_t maxDstSize,
+ const void* seqStart, size_t seqSize, int nbSeq,
+ const ZSTD_longOffset_e isLongOffset,
+ const int frame)
+{
+ return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
+}
+#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */
+
+#endif /* DYNAMIC_BMI2 */
+
+typedef size_t (*ZSTD_decompressSequences_t)(
+ ZSTD_DCtx* dctx,
+ void* dst, size_t maxDstSize,
+ const void* seqStart, size_t seqSize, int nbSeq,
+ const ZSTD_longOffset_e isLongOffset,
+ const int frame);
+
+#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG
+static size_t
+ZSTD_decompressSequences(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize,
+ const void* seqStart, size_t seqSize, int nbSeq,
+ const ZSTD_longOffset_e isLongOffset,
+ const int frame)
+{
+ DEBUGLOG(5, "ZSTD_decompressSequences");
+#if DYNAMIC_BMI2
+ if (dctx->bmi2) {
+ return ZSTD_decompressSequences_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
+ }
+#endif
+ return ZSTD_decompressSequences_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
+}
+#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */
+
+
+#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT
+/* ZSTD_decompressSequencesLong() :
+ * decompression function triggered when a minimum share of offsets is considered "long",
+ * aka out of cache.
+ * note : "long" definition seems overloaded here, sometimes meaning "wider than bitstream register", and sometimes meaning "farther than memory cache distance".
+ * This function will try to mitigate main memory latency through the use of prefetching */
+static size_t
+ZSTD_decompressSequencesLong(ZSTD_DCtx* dctx,
+ void* dst, size_t maxDstSize,
+ const void* seqStart, size_t seqSize, int nbSeq,
+ const ZSTD_longOffset_e isLongOffset,
+ const int frame)
+{
+ DEBUGLOG(5, "ZSTD_decompressSequencesLong");
+#if DYNAMIC_BMI2
+ if (dctx->bmi2) {
+ return ZSTD_decompressSequencesLong_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
+ }
+#endif
+ return ZSTD_decompressSequencesLong_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
+}
+#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */
+
+
+
+#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \
+ !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG)
+/* ZSTD_getLongOffsetsShare() :
+ * condition : offTable must be valid
+ * @return : "share" of long offsets (arbitrarily defined as > (1<<23))
+ * compared to maximum possible of (1<<OffFSELog) */
+static unsigned
+ZSTD_getLongOffsetsShare(const ZSTD_seqSymbol* offTable)
+{
+ const void* ptr = offTable;
+ U32 const tableLog = ((const ZSTD_seqSymbol_header*)ptr)[0].tableLog;
+ const ZSTD_seqSymbol* table = offTable + 1;
+ U32 const max = 1 << tableLog;
+ U32 u, total = 0;
+ DEBUGLOG(5, "ZSTD_getLongOffsetsShare: (tableLog=%u)", tableLog);
+
+ assert(max <= (1 << OffFSELog)); /* max not too large */
+ for (u=0; u<max; u++) {
+ if (table[u].nbAdditionalBits > 22) total += 1;
+ }
+
+ assert(tableLog <= OffFSELog);
+ total <<= (OffFSELog - tableLog); /* scale to OffFSELog */
+
+ return total;
+}
+#endif
+
+size_t
+ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize, const int frame)
+{ /* blockType == blockCompressed */
+ const BYTE* ip = (const BYTE*)src;
+ /* isLongOffset must be true if there are long offsets.
+ * Offsets are long if they are larger than 2^STREAM_ACCUMULATOR_MIN.
+ * We don't expect that to be the case in 64-bit mode.
+ * In block mode, window size is not known, so we have to be conservative.
+ * (note: but it could be evaluated from current-lowLimit)
+ */
+ ZSTD_longOffset_e const isLongOffset = (ZSTD_longOffset_e)(MEM_32bits() && (!frame || (dctx->fParams.windowSize > (1ULL << STREAM_ACCUMULATOR_MIN))));
+ DEBUGLOG(5, "ZSTD_decompressBlock_internal (size : %u)", (U32)srcSize);
+
+ RETURN_ERROR_IF(srcSize >= ZSTD_BLOCKSIZE_MAX, srcSize_wrong, "");
+
+ /* Decode literals section */
+ { size_t const litCSize = ZSTD_decodeLiteralsBlock(dctx, src, srcSize);
+ DEBUGLOG(5, "ZSTD_decodeLiteralsBlock : %u", (U32)litCSize);
+ if (ZSTD_isError(litCSize)) return litCSize;
+ ip += litCSize;
+ srcSize -= litCSize;
+ }
+
+ /* Build Decoding Tables */
+ {
+ /* These macros control at build-time which decompressor implementation
+ * we use. If neither is defined, we do some inspection and dispatch at
+ * runtime.
+ */
+#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \
+ !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG)
+ int usePrefetchDecoder = dctx->ddictIsCold;
+#endif
+ int nbSeq;
+ size_t const seqHSize = ZSTD_decodeSeqHeaders(dctx, &nbSeq, ip, srcSize);
+ if (ZSTD_isError(seqHSize)) return seqHSize;
+ ip += seqHSize;
+ srcSize -= seqHSize;
+
+ RETURN_ERROR_IF(dst == NULL && nbSeq > 0, dstSize_tooSmall, "NULL not handled");
+
+#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \
+ !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG)
+ if ( !usePrefetchDecoder
+ && (!frame || (dctx->fParams.windowSize > (1<<24)))
+ && (nbSeq>ADVANCED_SEQS) ) { /* could probably use a larger nbSeq limit */
+ U32 const shareLongOffsets = ZSTD_getLongOffsetsShare(dctx->OFTptr);
+ U32 const minShare = MEM_64bits() ? 7 : 20; /* heuristic values, correspond to 2.73% and 7.81% */
+ usePrefetchDecoder = (shareLongOffsets >= minShare);
+ }
+#endif
+
+ dctx->ddictIsCold = 0;
+
+#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \
+ !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG)
+ if (usePrefetchDecoder)
+#endif
+#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT
+ return ZSTD_decompressSequencesLong(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset, frame);
+#endif
+
+#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG
+ /* else */
+ return ZSTD_decompressSequences(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset, frame);
+#endif
+ }
+}
+
+
+void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst)
+{
+ if (dst != dctx->previousDstEnd) { /* not contiguous */
+ dctx->dictEnd = dctx->previousDstEnd;
+ dctx->virtualStart = (const char*)dst - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart));
+ dctx->prefixStart = dst;
+ dctx->previousDstEnd = dst;
+ }
+}
+
+
+size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize)
+{
+ size_t dSize;
+ ZSTD_checkContinuity(dctx, dst);
+ dSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 0);
+ dctx->previousDstEnd = (char*)dst + dSize;
+ return dSize;
+}
diff --git a/sys/contrib/openzfs/module/zstd/lib/decompress/zstd_decompress_block.h b/sys/contrib/openzfs/module/zstd/lib/decompress/zstd_decompress_block.h
new file mode 100644
index 000000000000..bf39b7350cf9
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/decompress/zstd_decompress_block.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+
+#ifndef ZSTD_DEC_BLOCK_H
+#define ZSTD_DEC_BLOCK_H
+
+/*-*******************************************************
+ * Dependencies
+ *********************************************************/
+#include <stddef.h> /* size_t */
+#include "../zstd.h" /* DCtx, and some public functions */
+#include "../common/zstd_internal.h" /* blockProperties_t, and some public functions */
+#include "zstd_decompress_internal.h" /* ZSTD_seqSymbol */
+
+
+/* === Prototypes === */
+
+/* note: prototypes already published within `zstd.h` :
+ * ZSTD_decompressBlock()
+ */
+
+/* note: prototypes already published within `zstd_internal.h` :
+ * ZSTD_getcBlockSize()
+ * ZSTD_decodeSeqHeaders()
+ */
+
+
+/* ZSTD_decompressBlock_internal() :
+ * decompress block, starting at `src`,
+ * into destination buffer `dst`.
+ * @return : decompressed block size,
+ * or an error code (which can be tested using ZSTD_isError())
+ */
+size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize, const int frame);
+
+/* ZSTD_buildFSETable() :
+ * generate FSE decoding table for one symbol (ll, ml or off)
+ * this function must be called with valid parameters only
+ * (dt is large enough, normalizedCounter distribution total is a power of 2, max is within range, etc.)
+ * in which case it cannot fail.
+ * Internal use only.
+ */
+void ZSTD_buildFSETable(ZSTD_seqSymbol* dt,
+ const short* normalizedCounter, unsigned maxSymbolValue,
+ const U32* baseValue, const U32* nbAdditionalBits,
+ unsigned tableLog);
+
+
+#endif /* ZSTD_DEC_BLOCK_H */
diff --git a/sys/contrib/openzfs/module/zstd/lib/decompress/zstd_decompress_internal.h b/sys/contrib/openzfs/module/zstd/lib/decompress/zstd_decompress_internal.h
new file mode 100644
index 000000000000..9ad96c554885
--- /dev/null
+++ b/sys/contrib/openzfs/module/zstd/lib/decompress/zstd_decompress_internal.h
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+
+/* zstd_decompress_internal:
+ * objects and definitions shared within lib/decompress modules */
+
+ #ifndef ZSTD_DECOMPRESS_INTERNAL_H
+ #define ZSTD_DECOMPRESS_INTERNAL_H
+
+
+/*-*******************************************************
+ * Dependencies
+ *********************************************************/
+#include "../common/mem.h" /* BYTE, U16, U32 */
+#include "../common/zstd_internal.h" /* ZSTD_seqSymbol */
+
+
+
+/*-*******************************************************
+ * Constants
+ *********************************************************/
+static const U32 LL_base[MaxLL+1] = {
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 18, 20, 22, 24, 28, 32, 40,
+ 48, 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000,
+ 0x2000, 0x4000, 0x8000, 0x10000 };
+
+static const U32 OF_base[MaxOff+1] = {
+ 0, 1, 1, 5, 0xD, 0x1D, 0x3D, 0x7D,
+ 0xFD, 0x1FD, 0x3FD, 0x7FD, 0xFFD, 0x1FFD, 0x3FFD, 0x7FFD,
+ 0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD, 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD,
+ 0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD, 0x1FFFFFFD, 0x3FFFFFFD, 0x7FFFFFFD };
+
+static const U32 OF_bits[MaxOff+1] = {
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31 };
+
+static const U32 ML_base[MaxML+1] = {
+ 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 26,
+ 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 37, 39, 41, 43, 47, 51, 59,
+ 67, 83, 99, 0x83, 0x103, 0x203, 0x403, 0x803,
+ 0x1003, 0x2003, 0x4003, 0x8003, 0x10003 };
+
+
+/*-*******************************************************
+ * Decompression types
+ *********************************************************/
+ typedef struct {
+ U32 fastMode;
+ U32 tableLog;
+ } ZSTD_seqSymbol_header;
+
+ typedef struct {
+ U16 nextState;
+ BYTE nbAdditionalBits;
+ BYTE nbBits;
+ U32 baseValue;
+ } ZSTD_seqSymbol;
+
+ #define SEQSYMBOL_TABLE_SIZE(log) (1 + (1 << (log)))
+
+typedef struct {
+ ZSTD_seqSymbol LLTable[SEQSYMBOL_TABLE_SIZE(LLFSELog)]; /* Note : Space reserved for FSE Tables */
+ ZSTD_seqSymbol OFTable[SEQSYMBOL_TABLE_SIZE(OffFSELog)]; /* is also used as temporary workspace while building hufTable during DDict creation */
+ ZSTD_seqSymbol MLTable[SEQSYMBOL_TABLE_SIZE(MLFSELog)]; /* and therefore must be at least HUF_DECOMPRESS_WORKSPACE_SIZE large */
+ HUF_DTable hufTable[HUF_DTABLE_SIZE(HufLog)]; /* can accommodate HUF_decompress4X */
+ U32 rep[ZSTD_REP_NUM];
+} ZSTD_entropyDTables_t;
+
+typedef enum { ZSTDds_getFrameHeaderSize, ZSTDds_decodeFrameHeader,
+ ZSTDds_decodeBlockHeader, ZSTDds_decompressBlock,
+ ZSTDds_decompressLastBlock, ZSTDds_checkChecksum,
+ ZSTDds_decodeSkippableHeader, ZSTDds_skipFrame } ZSTD_dStage;
+
+typedef enum { zdss_init=0, zdss_loadHeader,
+ zdss_read, zdss_load, zdss_flush } ZSTD_dStreamStage;
+
+typedef enum {
+ ZSTD_use_indefinitely = -1, /* Use the dictionary indefinitely */
+ ZSTD_dont_use = 0, /* Do not use the dictionary (if one exists free it) */
+ ZSTD_use_once = 1 /* Use the dictionary once and set to ZSTD_dont_use */
+} ZSTD_dictUses_e;
+
+typedef enum {
+ ZSTD_obm_buffered = 0, /* Buffer the output */
+ ZSTD_obm_stable = 1 /* ZSTD_outBuffer is stable */
+} ZSTD_outBufferMode_e;
+
+struct ZSTD_DCtx_s
+{
+ const ZSTD_seqSymbol* LLTptr;
+ const ZSTD_seqSymbol* MLTptr;
+ const ZSTD_seqSymbol* OFTptr;
+ const HUF_DTable* HUFptr;
+ ZSTD_entropyDTables_t entropy;
+ U32 workspace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; /* space needed when building huffman tables */
+ const void* previousDstEnd; /* detect continuity */
+ const void* prefixStart; /* start of current segment */
+ const void* virtualStart; /* virtual start of previous segment if it was just before current one */
+ const void* dictEnd; /* end of previous segment */
+ size_t expected;
+ ZSTD_frameHeader fParams;
+ U64 decodedSize;
+ blockType_e bType; /* used in ZSTD_decompressContinue(), store blockType between block header decoding and block decompression stages */
+ ZSTD_dStage stage;
+ U32 litEntropy;
+ U32 fseEntropy;
+ XXH64_state_t xxhState;
+ size_t headerSize;
+ ZSTD_format_e format;
+ const BYTE* litPtr;
+ ZSTD_customMem customMem;
+ size_t litSize;
+ size_t rleSize;
+ size_t staticSize;
+ int bmi2; /* == 1 if the CPU supports BMI2 and 0 otherwise. CPU support is determined dynamically once per context lifetime. */
+
+ /* dictionary */
+ ZSTD_DDict* ddictLocal;
+ const ZSTD_DDict* ddict; /* set by ZSTD_initDStream_usingDDict(), or ZSTD_DCtx_refDDict() */
+ U32 dictID;
+ int ddictIsCold; /* if == 1 : dictionary is "new" for working context, and presumed "cold" (not in cpu cache) */
+ ZSTD_dictUses_e dictUses;
+
+ /* streaming */
+ ZSTD_dStreamStage streamStage;
+ char* inBuff;
+ size_t inBuffSize;
+ size_t inPos;
+ size_t maxWindowSize;
+ char* outBuff;
+ size_t outBuffSize;
+ size_t outStart;
+ size_t outEnd;
+ size_t lhSize;
+ void* legacyContext;
+ U32 previousLegacyVersion;
+ U32 legacyVersion;
+ U32 hostageByte;
+ int noForwardProgress;
+ ZSTD_outBufferMode_e outBufferMode;
+ ZSTD_outBuffer expectedOutBuffer;
+
+ /* workspace */
+ BYTE litBuffer[ZSTD_BLOCKSIZE_MAX + WILDCOPY_OVERLENGTH];
+ BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX];
+
+ size_t oversizedDuration;
+
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ void const* dictContentBeginForFuzzing;
+ void const* dictContentEndForFuzzing;
+#endif
+}; /* typedef'd to ZSTD_DCtx within "zstd.h" */
+
+
+/*-*******************************************************
+ * Shared internal functions
+ *********************************************************/
+
+/*! ZSTD_loadDEntropy() :
+ * dict : must point at beginning of a valid zstd dictionary.
+ * @return : size of dictionary header (size of magic number + dict ID + entropy tables) */
+size_t ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy,
+ const void* const dict, size_t const dictSize);
+
+/*! ZSTD_checkContinuity() :
+ * check if next `dst` follows previous position, where decompression ended.
+ * If yes, do nothing (continue on current segment).
+ * If not, classify previous segment as "external dictionary", and start a new segment.
+ * This function cannot fail. */
+void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst);
+
+
+#endif /* ZSTD_DECOMPRESS_INTERNAL_H */
diff --git a/sys/contrib/openzfs/module/zstd/lib/zstd.c b/sys/contrib/openzfs/module/zstd/lib/zstd.c
deleted file mode 100644
index 2766e5b74f55..000000000000
--- a/sys/contrib/openzfs/module/zstd/lib/zstd.c
+++ /dev/null
@@ -1,27824 +0,0 @@
-/*
- * BSD 3-Clause Clear License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * 3. Neither the name of the copyright holder nor the names of its
- * contributors may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. All rights reserved.
- * Copyright (c) 2019-2020, Michael Niewöhner. All rights reserved.
- */
-
-#define MEM_MODULE
-#define XXH_NAMESPACE ZSTD_
-#define XXH_PRIVATE_API
-#define XXH_INLINE_ALL
-#define ZSTD_LEGACY_SUPPORT 0
-#define ZSTD_LIB_DICTBUILDER 0
-#define ZSTD_LIB_DEPRECATED 0
-#define ZSTD_NOBENCH
-
-/**** start inlining common/debug.c ****/
-/* ******************************************************************
- * debug
- * Part of FSE library
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
- *
- * You can contact the author at :
- * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
-****************************************************************** */
-
-
-/*
- * This module only hosts one global variable
- * which can be used to dynamically influence the verbosity of traces,
- * such as DEBUGLOG and RAWLOG
- */
-
-/**** start inlining debug.h ****/
-/* ******************************************************************
- * debug
- * Part of FSE library
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
- *
- * You can contact the author at :
- * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
-****************************************************************** */
-
-
-/*
- * The purpose of this header is to enable debug functions.
- * They regroup assert(), DEBUGLOG() and RAWLOG() for run-time,
- * and DEBUG_STATIC_ASSERT() for compile-time.
- *
- * By default, DEBUGLEVEL==0, which means run-time debug is disabled.
- *
- * Level 1 enables assert() only.
- * Starting level 2, traces can be generated and pushed to stderr.
- * The higher the level, the more verbose the traces.
- *
- * It's possible to dynamically adjust level using variable g_debug_level,
- * which is only declared if DEBUGLEVEL>=2,
- * and is a global variable, not multi-thread protected (use with care)
- */
-
-#ifndef DEBUG_H_12987983217
-#define DEBUG_H_12987983217
-
-#if defined (__cplusplus)
-extern "C" {
-#endif
-
-
-/* static assert is triggered at compile time, leaving no runtime artefact.
- * static assert only works with compile-time constants.
- * Also, this variant can only be used inside a function. */
-#define DEBUG_STATIC_ASSERT(c) (void)sizeof(char[(c) ? 1 : -1])
-
-
-/* DEBUGLEVEL is expected to be defined externally,
- * typically through compiler command line.
- * Value must be a number. */
-#ifndef DEBUGLEVEL
-# define DEBUGLEVEL 0
-#endif
-
-
-/* DEBUGFILE can be defined externally,
- * typically through compiler command line.
- * note : currently useless.
- * Value must be stderr or stdout */
-#ifndef DEBUGFILE
-# define DEBUGFILE stderr
-#endif
-
-
-/* recommended values for DEBUGLEVEL :
- * 0 : release mode, no debug, all run-time checks disabled
- * 1 : enables assert() only, no display
- * 2 : reserved, for currently active debug path
- * 3 : events once per object lifetime (CCtx, CDict, etc.)
- * 4 : events once per frame
- * 5 : events once per block
- * 6 : events once per sequence (verbose)
- * 7+: events at every position (*very* verbose)
- *
- * It's generally inconvenient to output traces > 5.
- * In which case, it's possible to selectively trigger high verbosity levels
- * by modifying g_debug_level.
- */
-
-#if (DEBUGLEVEL>=1)
-# include <assert.h>
-#else
-# ifndef assert /* assert may be already defined, due to prior #include <assert.h> */
-# define assert(condition) ((void)0) /* disable assert (default) */
-# endif
-#endif
-
-#if (DEBUGLEVEL>=2)
-# include <stdio.h>
-extern int g_debuglevel; /* the variable is only declared,
- it actually lives in debug.c,
- and is shared by the whole process.
- It's not thread-safe.
- It's useful when enabling very verbose levels
- on selective conditions (such as position in src) */
-
-# define RAWLOG(l, ...) { \
- if (l<=g_debuglevel) { \
- fprintf(stderr, __VA_ARGS__); \
- } }
-# define DEBUGLOG(l, ...) { \
- if (l<=g_debuglevel) { \
- fprintf(stderr, __FILE__ ": " __VA_ARGS__); \
- fprintf(stderr, " \n"); \
- } }
-#else
-# define RAWLOG(l, ...) {} /* disabled */
-# define DEBUGLOG(l, ...) {} /* disabled */
-#endif
-
-
-#if defined (__cplusplus)
-}
-#endif
-
-#endif /* DEBUG_H_12987983217 */
-/**** ended inlining debug.h ****/
-
-int g_debuglevel = DEBUGLEVEL;
-/**** ended inlining common/debug.c ****/
-/**** start inlining common/entropy_common.c ****/
-/* ******************************************************************
- * Common functions of New Generation Entropy library
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- *
- * You can contact the author at :
- * - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
- * - Public forum : https://groups.google.com/forum/#!forum/lz4c
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
-****************************************************************** */
-
-/* *************************************
-* Dependencies
-***************************************/
-/**** start inlining mem.h ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-#ifndef MEM_H_MODULE
-#define MEM_H_MODULE
-
-#if defined (__cplusplus)
-extern "C" {
-#endif
-
-/*-****************************************
-* Dependencies
-******************************************/
-#include <stddef.h> /* size_t, ptrdiff_t */
-#include <string.h> /* memcpy */
-
-
-/*-****************************************
-* Compiler specifics
-******************************************/
-#if defined(_MSC_VER) /* Visual Studio */
-# include <stdlib.h> /* _byteswap_ulong */
-# include <intrin.h> /* _byteswap_* */
-#endif
-#if defined(__GNUC__)
-# define MEM_STATIC static __inline __attribute__((unused))
-#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
-# define MEM_STATIC static inline
-#elif defined(_MSC_VER)
-# define MEM_STATIC static __inline
-#else
-# define MEM_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */
-#endif
-
-#ifndef __has_builtin
-# define __has_builtin(x) 0 /* compat. with non-clang compilers */
-#endif
-
-/* code only tested on 32 and 64 bits systems */
-#define MEM_STATIC_ASSERT(c) { enum { MEM_static_assert = 1/(int)(!!(c)) }; }
-MEM_STATIC void MEM_check(void) { MEM_STATIC_ASSERT((sizeof(size_t)==4) || (sizeof(size_t)==8)); }
-
-/* detects whether we are being compiled under msan */
-#if defined (__has_feature)
-# if __has_feature(memory_sanitizer)
-# define MEMORY_SANITIZER 1
-# endif
-#endif
-
-#if defined (MEMORY_SANITIZER)
-/* Not all platforms that support msan provide sanitizers/msan_interface.h.
- * We therefore declare the functions we need ourselves, rather than trying to
- * include the header file... */
-
-#include <stdint.h> /* intptr_t */
-
-/* Make memory region fully initialized (without changing its contents). */
-void __msan_unpoison(const volatile void *a, size_t size);
-
-/* Make memory region fully uninitialized (without changing its contents).
- This is a legacy interface that does not update origin information. Use
- __msan_allocated_memory() instead. */
-void __msan_poison(const volatile void *a, size_t size);
-
-/* Returns the offset of the first (at least partially) poisoned byte in the
- memory range, or -1 if the whole range is good. */
-intptr_t __msan_test_shadow(const volatile void *x, size_t size);
-#endif
-
-/* detects whether we are being compiled under asan */
-#if defined (__has_feature)
-# if __has_feature(address_sanitizer)
-# define ADDRESS_SANITIZER 1
-# endif
-#elif defined(__SANITIZE_ADDRESS__)
-# define ADDRESS_SANITIZER 1
-#endif
-
-#if defined (ADDRESS_SANITIZER)
-/* Not all platforms that support asan provide sanitizers/asan_interface.h.
- * We therefore declare the functions we need ourselves, rather than trying to
- * include the header file... */
-
-/**
- * Marks a memory region (<c>[addr, addr+size)</c>) as unaddressable.
- *
- * This memory must be previously allocated by your program. Instrumented
- * code is forbidden from accessing addresses in this region until it is
- * unpoisoned. This function is not guaranteed to poison the entire region -
- * it could poison only a subregion of <c>[addr, addr+size)</c> due to ASan
- * alignment restrictions.
- *
- * \note This function is not thread-safe because no two threads can poison or
- * unpoison memory in the same memory region simultaneously.
- *
- * \param addr Start of memory region.
- * \param size Size of memory region. */
-void __asan_poison_memory_region(void const volatile *addr, size_t size);
-
-/**
- * Marks a memory region (<c>[addr, addr+size)</c>) as addressable.
- *
- * This memory must be previously allocated by your program. Accessing
- * addresses in this region is allowed until this region is poisoned again.
- * This function could unpoison a super-region of <c>[addr, addr+size)</c> due
- * to ASan alignment restrictions.
- *
- * \note This function is not thread-safe because no two threads can
- * poison or unpoison memory in the same memory region simultaneously.
- *
- * \param addr Start of memory region.
- * \param size Size of memory region. */
-void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
-#endif
-
-
-/*-**************************************************************
-* Basic Types
-*****************************************************************/
-#if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
-# include <stdint.h>
- typedef uint8_t BYTE;
- typedef uint16_t U16;
- typedef int16_t S16;
- typedef uint32_t U32;
- typedef int32_t S32;
- typedef uint64_t U64;
- typedef int64_t S64;
-#else
-# include <limits.h>
-#if CHAR_BIT != 8
-# error "this implementation requires char to be exactly 8-bit type"
-#endif
- typedef unsigned char BYTE;
-#if USHRT_MAX != 65535
-# error "this implementation requires short to be exactly 16-bit type"
-#endif
- typedef unsigned short U16;
- typedef signed short S16;
-#if UINT_MAX != 4294967295
-# error "this implementation requires int to be exactly 32-bit type"
-#endif
- typedef unsigned int U32;
- typedef signed int S32;
-/* note : there are no limits defined for long long type in C90.
- * limits exist in C99, however, in such case, <stdint.h> is preferred */
- typedef unsigned long long U64;
- typedef signed long long S64;
-#endif
-
-
-/*-**************************************************************
-* Memory I/O
-*****************************************************************/
-/* MEM_FORCE_MEMORY_ACCESS :
- * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.
- * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.
- * The below switch allow to select different access method for improved performance.
- * Method 0 (default) : use `memcpy()`. Safe and portable.
- * Method 1 : `__packed` statement. It depends on compiler extension (i.e., not portable).
- * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.
- * Method 2 : direct access. This method is portable but violate C standard.
- * It can generate buggy code on targets depending on alignment.
- * In some circumstances, it's the only known way to get the most performance (i.e. GCC + ARMv6)
- * See http://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details.
- * Prefer these methods in priority order (0 > 1 > 2)
- */
-#ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */
-# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) )
-# define MEM_FORCE_MEMORY_ACCESS 2
-# elif defined(__INTEL_COMPILER) || defined(__GNUC__) || defined(__ICCARM__)
-# define MEM_FORCE_MEMORY_ACCESS 1
-# endif
-#endif
-
-MEM_STATIC unsigned MEM_32bits(void) { return sizeof(size_t)==4; }
-MEM_STATIC unsigned MEM_64bits(void) { return sizeof(size_t)==8; }
-
-MEM_STATIC unsigned MEM_isLittleEndian(void)
-{
- const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */
- return one.c[0];
-}
-
-#if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2)
-
-/* violates C standard, by lying on structure alignment.
-Only use if no other choice to achieve best performance on target platform */
-MEM_STATIC U16 MEM_read16(const void* memPtr) { return *(const U16*) memPtr; }
-MEM_STATIC U32 MEM_read32(const void* memPtr) { return *(const U32*) memPtr; }
-MEM_STATIC U64 MEM_read64(const void* memPtr) { return *(const U64*) memPtr; }
-MEM_STATIC size_t MEM_readST(const void* memPtr) { return *(const size_t*) memPtr; }
-
-MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; }
-MEM_STATIC void MEM_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; }
-MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(U64*)memPtr = value; }
-
-#elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1)
-
-/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
-/* currently only defined for gcc and icc */
-#if defined(_MSC_VER) || (defined(__INTEL_COMPILER) && defined(WIN32))
- __pragma( pack(push, 1) )
- typedef struct { U16 v; } unalign16;
- typedef struct { U32 v; } unalign32;
- typedef struct { U64 v; } unalign64;
- typedef struct { size_t v; } unalignArch;
- __pragma( pack(pop) )
-#else
- typedef struct { U16 v; } __attribute__((packed)) unalign16;
- typedef struct { U32 v; } __attribute__((packed)) unalign32;
- typedef struct { U64 v; } __attribute__((packed)) unalign64;
- typedef struct { size_t v; } __attribute__((packed)) unalignArch;
-#endif
-
-MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign16*)ptr)->v; }
-MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign32*)ptr)->v; }
-MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign64*)ptr)->v; }
-MEM_STATIC size_t MEM_readST(const void* ptr) { return ((const unalignArch*)ptr)->v; }
-
-MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign16*)memPtr)->v = value; }
-MEM_STATIC void MEM_write32(void* memPtr, U32 value) { ((unalign32*)memPtr)->v = value; }
-MEM_STATIC void MEM_write64(void* memPtr, U64 value) { ((unalign64*)memPtr)->v = value; }
-
-#else
-
-/* default method, safe and standard.
- can sometimes prove slower */
-
-MEM_STATIC U16 MEM_read16(const void* memPtr)
-{
- U16 val; memcpy(&val, memPtr, sizeof(val)); return val;
-}
-
-MEM_STATIC U32 MEM_read32(const void* memPtr)
-{
- U32 val; memcpy(&val, memPtr, sizeof(val)); return val;
-}
-
-MEM_STATIC U64 MEM_read64(const void* memPtr)
-{
- U64 val; memcpy(&val, memPtr, sizeof(val)); return val;
-}
-
-MEM_STATIC size_t MEM_readST(const void* memPtr)
-{
- size_t val; memcpy(&val, memPtr, sizeof(val)); return val;
-}
-
-MEM_STATIC void MEM_write16(void* memPtr, U16 value)
-{
- memcpy(memPtr, &value, sizeof(value));
-}
-
-MEM_STATIC void MEM_write32(void* memPtr, U32 value)
-{
- memcpy(memPtr, &value, sizeof(value));
-}
-
-MEM_STATIC void MEM_write64(void* memPtr, U64 value)
-{
- memcpy(memPtr, &value, sizeof(value));
-}
-
-#endif /* MEM_FORCE_MEMORY_ACCESS */
-
-MEM_STATIC U32 MEM_swap32(U32 in)
-{
-#if defined(_MSC_VER) /* Visual Studio */
- return _byteswap_ulong(in);
-#elif (defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) \
- || (defined(__clang__) && __has_builtin(__builtin_bswap32))
- return __builtin_bswap32(in);
-#else
- return ((in << 24) & 0xff000000 ) |
- ((in << 8) & 0x00ff0000 ) |
- ((in >> 8) & 0x0000ff00 ) |
- ((in >> 24) & 0x000000ff );
-#endif
-}
-
-MEM_STATIC U64 MEM_swap64(U64 in)
-{
-#if defined(_MSC_VER) /* Visual Studio */
- return _byteswap_uint64(in);
-#elif (defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) \
- || (defined(__clang__) && __has_builtin(__builtin_bswap64))
- return __builtin_bswap64(in);
-#else
- return ((in << 56) & 0xff00000000000000ULL) |
- ((in << 40) & 0x00ff000000000000ULL) |
- ((in << 24) & 0x0000ff0000000000ULL) |
- ((in << 8) & 0x000000ff00000000ULL) |
- ((in >> 8) & 0x00000000ff000000ULL) |
- ((in >> 24) & 0x0000000000ff0000ULL) |
- ((in >> 40) & 0x000000000000ff00ULL) |
- ((in >> 56) & 0x00000000000000ffULL);
-#endif
-}
-
-MEM_STATIC size_t MEM_swapST(size_t in)
-{
- if (MEM_32bits())
- return (size_t)MEM_swap32((U32)in);
- else
- return (size_t)MEM_swap64((U64)in);
-}
-
-/*=== Little endian r/w ===*/
-
-MEM_STATIC U16 MEM_readLE16(const void* memPtr)
-{
- if (MEM_isLittleEndian())
- return MEM_read16(memPtr);
- else {
- const BYTE* p = (const BYTE*)memPtr;
- return (U16)(p[0] + (p[1]<<8));
- }
-}
-
-MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val)
-{
- if (MEM_isLittleEndian()) {
- MEM_write16(memPtr, val);
- } else {
- BYTE* p = (BYTE*)memPtr;
- p[0] = (BYTE)val;
- p[1] = (BYTE)(val>>8);
- }
-}
-
-MEM_STATIC U32 MEM_readLE24(const void* memPtr)
-{
- return MEM_readLE16(memPtr) + (((const BYTE*)memPtr)[2] << 16);
-}
-
-MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val)
-{
- MEM_writeLE16(memPtr, (U16)val);
- ((BYTE*)memPtr)[2] = (BYTE)(val>>16);
-}
-
-MEM_STATIC U32 MEM_readLE32(const void* memPtr)
-{
- if (MEM_isLittleEndian())
- return MEM_read32(memPtr);
- else
- return MEM_swap32(MEM_read32(memPtr));
-}
-
-MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32)
-{
- if (MEM_isLittleEndian())
- MEM_write32(memPtr, val32);
- else
- MEM_write32(memPtr, MEM_swap32(val32));
-}
-
-MEM_STATIC U64 MEM_readLE64(const void* memPtr)
-{
- if (MEM_isLittleEndian())
- return MEM_read64(memPtr);
- else
- return MEM_swap64(MEM_read64(memPtr));
-}
-
-MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64)
-{
- if (MEM_isLittleEndian())
- MEM_write64(memPtr, val64);
- else
- MEM_write64(memPtr, MEM_swap64(val64));
-}
-
-MEM_STATIC size_t MEM_readLEST(const void* memPtr)
-{
- if (MEM_32bits())
- return (size_t)MEM_readLE32(memPtr);
- else
- return (size_t)MEM_readLE64(memPtr);
-}
-
-MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val)
-{
- if (MEM_32bits())
- MEM_writeLE32(memPtr, (U32)val);
- else
- MEM_writeLE64(memPtr, (U64)val);
-}
-
-/*=== Big endian r/w ===*/
-
-MEM_STATIC U32 MEM_readBE32(const void* memPtr)
-{
- if (MEM_isLittleEndian())
- return MEM_swap32(MEM_read32(memPtr));
- else
- return MEM_read32(memPtr);
-}
-
-MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32)
-{
- if (MEM_isLittleEndian())
- MEM_write32(memPtr, MEM_swap32(val32));
- else
- MEM_write32(memPtr, val32);
-}
-
-MEM_STATIC U64 MEM_readBE64(const void* memPtr)
-{
- if (MEM_isLittleEndian())
- return MEM_swap64(MEM_read64(memPtr));
- else
- return MEM_read64(memPtr);
-}
-
-MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64)
-{
- if (MEM_isLittleEndian())
- MEM_write64(memPtr, MEM_swap64(val64));
- else
- MEM_write64(memPtr, val64);
-}
-
-MEM_STATIC size_t MEM_readBEST(const void* memPtr)
-{
- if (MEM_32bits())
- return (size_t)MEM_readBE32(memPtr);
- else
- return (size_t)MEM_readBE64(memPtr);
-}
-
-MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val)
-{
- if (MEM_32bits())
- MEM_writeBE32(memPtr, (U32)val);
- else
- MEM_writeBE64(memPtr, (U64)val);
-}
-
-
-#if defined (__cplusplus)
-}
-#endif
-
-#endif /* MEM_H_MODULE */
-/**** ended inlining mem.h ****/
-/**** start inlining error_private.h ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-/* Note : this module is expected to remain private, do not expose it */
-
-#ifndef ERROR_H_MODULE
-#define ERROR_H_MODULE
-
-#if defined (__cplusplus)
-extern "C" {
-#endif
-
-
-/* ****************************************
-* Dependencies
-******************************************/
-#include <stddef.h> /* size_t */
-/**** start inlining zstd_errors.h ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-#ifndef ZSTD_ERRORS_H_398273423
-#define ZSTD_ERRORS_H_398273423
-
-#if defined (__cplusplus)
-extern "C" {
-#endif
-
-/*===== dependency =====*/
-#include <stddef.h> /* size_t */
-
-
-/* ===== ZSTDERRORLIB_API : control library symbols visibility ===== */
-#ifndef ZSTDERRORLIB_VISIBILITY
-# if defined(__GNUC__) && (__GNUC__ >= 4)
-# define ZSTDERRORLIB_VISIBILITY __attribute__ ((visibility ("default")))
-# else
-# define ZSTDERRORLIB_VISIBILITY
-# endif
-#endif
-#if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1)
-# define ZSTDERRORLIB_API __declspec(dllexport) ZSTDERRORLIB_VISIBILITY
-#elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1)
-# define ZSTDERRORLIB_API __declspec(dllimport) ZSTDERRORLIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/
-#else
-# define ZSTDERRORLIB_API ZSTDERRORLIB_VISIBILITY
-#endif
-
-/*-*********************************************
- * Error codes list
- *-*********************************************
- * Error codes _values_ are pinned down since v1.3.1 only.
- * Therefore, don't rely on values if you may link to any version < v1.3.1.
- *
- * Only values < 100 are considered stable.
- *
- * note 1 : this API shall be used with static linking only.
- * dynamic linking is not yet officially supported.
- * note 2 : Prefer relying on the enum than on its value whenever possible
- * This is the only supported way to use the error list < v1.3.1
- * note 3 : ZSTD_isError() is always correct, whatever the library version.
- **********************************************/
-typedef enum {
- ZSTD_error_no_error = 0,
- ZSTD_error_GENERIC = 1,
- ZSTD_error_prefix_unknown = 10,
- ZSTD_error_version_unsupported = 12,
- ZSTD_error_frameParameter_unsupported = 14,
- ZSTD_error_frameParameter_windowTooLarge = 16,
- ZSTD_error_corruption_detected = 20,
- ZSTD_error_checksum_wrong = 22,
- ZSTD_error_dictionary_corrupted = 30,
- ZSTD_error_dictionary_wrong = 32,
- ZSTD_error_dictionaryCreation_failed = 34,
- ZSTD_error_parameter_unsupported = 40,
- ZSTD_error_parameter_outOfBound = 42,
- ZSTD_error_tableLog_tooLarge = 44,
- ZSTD_error_maxSymbolValue_tooLarge = 46,
- ZSTD_error_maxSymbolValue_tooSmall = 48,
- ZSTD_error_stage_wrong = 60,
- ZSTD_error_init_missing = 62,
- ZSTD_error_memory_allocation = 64,
- ZSTD_error_workSpace_tooSmall= 66,
- ZSTD_error_dstSize_tooSmall = 70,
- ZSTD_error_srcSize_wrong = 72,
- ZSTD_error_dstBuffer_null = 74,
- /* following error codes are __NOT STABLE__, they can be removed or changed in future versions */
- ZSTD_error_frameIndex_tooLarge = 100,
- ZSTD_error_seekableIO = 102,
- ZSTD_error_dstBuffer_wrong = 104,
- ZSTD_error_maxCode = 120 /* never EVER use this value directly, it can change in future versions! Use ZSTD_isError() instead */
-} ZSTD_ErrorCode;
-
-/*! ZSTD_getErrorCode() :
- convert a `size_t` function result into a `ZSTD_ErrorCode` enum type,
- which can be used to compare with enum list published above */
-ZSTDERRORLIB_API ZSTD_ErrorCode ZSTD_getErrorCode(size_t functionResult);
-ZSTDERRORLIB_API const char* ZSTD_getErrorString(ZSTD_ErrorCode code); /**< Same as ZSTD_getErrorName, but using a `ZSTD_ErrorCode` enum argument */
-
-
-#if defined (__cplusplus)
-}
-#endif
-
-#endif /* ZSTD_ERRORS_H_398273423 */
-/**** ended inlining zstd_errors.h ****/
-
-
-/* ****************************************
-* Compiler-specific
-******************************************/
-#if defined(__GNUC__)
-# define ERR_STATIC static __attribute__((unused))
-#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
-# define ERR_STATIC static inline
-#elif defined(_MSC_VER)
-# define ERR_STATIC static __inline
-#else
-# define ERR_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */
-#endif
-
-
-/*-****************************************
-* Customization (error_public.h)
-******************************************/
-typedef ZSTD_ErrorCode ERR_enum;
-#define PREFIX(name) ZSTD_error_##name
-
-
-/*-****************************************
-* Error codes handling
-******************************************/
-#undef ERROR /* already defined on Visual Studio */
-#define ERROR(name) ZSTD_ERROR(name)
-#define ZSTD_ERROR(name) ((size_t)-PREFIX(name))
-
-ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); }
-
-ERR_STATIC ERR_enum ERR_getErrorCode(size_t code) { if (!ERR_isError(code)) return (ERR_enum)0; return (ERR_enum) (0-code); }
-
-/* check and forward error code */
-#define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return e
-#define CHECK_F(f) { CHECK_V_F(_var_err__, f); }
-
-
-/*-****************************************
-* Error Strings
-******************************************/
-
-const char* ERR_getErrorString(ERR_enum code); /* error_private.c */
-
-ERR_STATIC const char* ERR_getErrorName(size_t code)
-{
- return ERR_getErrorString(ERR_getErrorCode(code));
-}
-
-#if defined (__cplusplus)
-}
-#endif
-
-#endif /* ERROR_H_MODULE */
-/**** ended inlining error_private.h ****/
-#define FSE_STATIC_LINKING_ONLY /* FSE_MIN_TABLELOG */
-/**** start inlining fse.h ****/
-/* ******************************************************************
- * FSE : Finite State Entropy codec
- * Public Prototypes declaration
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
- *
- * You can contact the author at :
- * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
-****************************************************************** */
-
-#if defined (__cplusplus)
-extern "C" {
-#endif
-
-#ifndef FSE_H
-#define FSE_H
-
-
-/*-*****************************************
-* Dependencies
-******************************************/
-#include <stddef.h> /* size_t, ptrdiff_t */
-
-
-/*-*****************************************
-* FSE_PUBLIC_API : control library symbols visibility
-******************************************/
-#if defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) && defined(__GNUC__) && (__GNUC__ >= 4)
-# define FSE_PUBLIC_API __attribute__ ((visibility ("default")))
-#elif defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) /* Visual expected */
-# define FSE_PUBLIC_API __declspec(dllexport)
-#elif defined(FSE_DLL_IMPORT) && (FSE_DLL_IMPORT==1)
-# define FSE_PUBLIC_API __declspec(dllimport) /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/
-#else
-# define FSE_PUBLIC_API
-#endif
-
-/*------ Version ------*/
-#define FSE_VERSION_MAJOR 0
-#define FSE_VERSION_MINOR 9
-#define FSE_VERSION_RELEASE 0
-
-#define FSE_LIB_VERSION FSE_VERSION_MAJOR.FSE_VERSION_MINOR.FSE_VERSION_RELEASE
-#define FSE_QUOTE(str) #str
-#define FSE_EXPAND_AND_QUOTE(str) FSE_QUOTE(str)
-#define FSE_VERSION_STRING FSE_EXPAND_AND_QUOTE(FSE_LIB_VERSION)
-
-#define FSE_VERSION_NUMBER (FSE_VERSION_MAJOR *100*100 + FSE_VERSION_MINOR *100 + FSE_VERSION_RELEASE)
-FSE_PUBLIC_API unsigned FSE_versionNumber(void); /**< library version number; to be used when checking dll version */
-
-
-/*-****************************************
-* FSE simple functions
-******************************************/
-/*! FSE_compress() :
- Compress content of buffer 'src', of size 'srcSize', into destination buffer 'dst'.
- 'dst' buffer must be already allocated. Compression runs faster is dstCapacity >= FSE_compressBound(srcSize).
- @return : size of compressed data (<= dstCapacity).
- Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!!
- if return == 1, srcData is a single byte symbol * srcSize times. Use RLE compression instead.
- if FSE_isError(return), compression failed (more details using FSE_getErrorName())
-*/
-FSE_PUBLIC_API size_t FSE_compress(void* dst, size_t dstCapacity,
- const void* src, size_t srcSize);
-
-/*! FSE_decompress():
- Decompress FSE data from buffer 'cSrc', of size 'cSrcSize',
- into already allocated destination buffer 'dst', of size 'dstCapacity'.
- @return : size of regenerated data (<= maxDstSize),
- or an error code, which can be tested using FSE_isError() .
-
- ** Important ** : FSE_decompress() does not decompress non-compressible nor RLE data !!!
- Why ? : making this distinction requires a header.
- Header management is intentionally delegated to the user layer, which can better manage special cases.
-*/
-FSE_PUBLIC_API size_t FSE_decompress(void* dst, size_t dstCapacity,
- const void* cSrc, size_t cSrcSize);
-
-
-/*-*****************************************
-* Tool functions
-******************************************/
-FSE_PUBLIC_API size_t FSE_compressBound(size_t size); /* maximum compressed size */
-
-/* Error Management */
-FSE_PUBLIC_API unsigned FSE_isError(size_t code); /* tells if a return value is an error code */
-FSE_PUBLIC_API const char* FSE_getErrorName(size_t code); /* provides error code string (useful for debugging) */
-
-
-/*-*****************************************
-* FSE advanced functions
-******************************************/
-/*! FSE_compress2() :
- Same as FSE_compress(), but allows the selection of 'maxSymbolValue' and 'tableLog'
- Both parameters can be defined as '0' to mean : use default value
- @return : size of compressed data
- Special values : if return == 0, srcData is not compressible => Nothing is stored within cSrc !!!
- if return == 1, srcData is a single byte symbol * srcSize times. Use RLE compression.
- if FSE_isError(return), it's an error code.
-*/
-FSE_PUBLIC_API size_t FSE_compress2 (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog);
-
-
-/*-*****************************************
-* FSE detailed API
-******************************************/
-/*!
-FSE_compress() does the following:
-1. count symbol occurrence from source[] into table count[] (see hist.h)
-2. normalize counters so that sum(count[]) == Power_of_2 (2^tableLog)
-3. save normalized counters to memory buffer using writeNCount()
-4. build encoding table 'CTable' from normalized counters
-5. encode the data stream using encoding table 'CTable'
-
-FSE_decompress() does the following:
-1. read normalized counters with readNCount()
-2. build decoding table 'DTable' from normalized counters
-3. decode the data stream using decoding table 'DTable'
-
-The following API allows targeting specific sub-functions for advanced tasks.
-For example, it's possible to compress several blocks using the same 'CTable',
-or to save and provide normalized distribution using external method.
-*/
-
-/* *** COMPRESSION *** */
-
-/*! FSE_optimalTableLog():
- dynamically downsize 'tableLog' when conditions are met.
- It saves CPU time, by using smaller tables, while preserving or even improving compression ratio.
- @return : recommended tableLog (necessarily <= 'maxTableLog') */
-FSE_PUBLIC_API unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue);
-
-/*! FSE_normalizeCount():
- normalize counts so that sum(count[]) == Power_of_2 (2^tableLog)
- 'normalizedCounter' is a table of short, of minimum size (maxSymbolValue+1).
- @return : tableLog,
- or an errorCode, which can be tested using FSE_isError() */
-FSE_PUBLIC_API size_t FSE_normalizeCount(short* normalizedCounter, unsigned tableLog,
- const unsigned* count, size_t srcSize, unsigned maxSymbolValue);
-
-/*! FSE_NCountWriteBound():
- Provides the maximum possible size of an FSE normalized table, given 'maxSymbolValue' and 'tableLog'.
- Typically useful for allocation purpose. */
-FSE_PUBLIC_API size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog);
-
-/*! FSE_writeNCount():
- Compactly save 'normalizedCounter' into 'buffer'.
- @return : size of the compressed table,
- or an errorCode, which can be tested using FSE_isError(). */
-FSE_PUBLIC_API size_t FSE_writeNCount (void* buffer, size_t bufferSize,
- const short* normalizedCounter,
- unsigned maxSymbolValue, unsigned tableLog);
-
-/*! Constructor and Destructor of FSE_CTable.
- Note that FSE_CTable size depends on 'tableLog' and 'maxSymbolValue' */
-typedef unsigned FSE_CTable; /* don't allocate that. It's only meant to be more restrictive than void* */
-FSE_PUBLIC_API FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog);
-FSE_PUBLIC_API void FSE_freeCTable (FSE_CTable* ct);
-
-/*! FSE_buildCTable():
- Builds `ct`, which must be already allocated, using FSE_createCTable().
- @return : 0, or an errorCode, which can be tested using FSE_isError() */
-FSE_PUBLIC_API size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog);
-
-/*! FSE_compress_usingCTable():
- Compress `src` using `ct` into `dst` which must be already allocated.
- @return : size of compressed data (<= `dstCapacity`),
- or 0 if compressed data could not fit into `dst`,
- or an errorCode, which can be tested using FSE_isError() */
-FSE_PUBLIC_API size_t FSE_compress_usingCTable (void* dst, size_t dstCapacity, const void* src, size_t srcSize, const FSE_CTable* ct);
-
-/*!
-Tutorial :
-----------
-The first step is to count all symbols. FSE_count() does this job very fast.
-Result will be saved into 'count', a table of unsigned int, which must be already allocated, and have 'maxSymbolValuePtr[0]+1' cells.
-'src' is a table of bytes of size 'srcSize'. All values within 'src' MUST be <= maxSymbolValuePtr[0]
-maxSymbolValuePtr[0] will be updated, with its real value (necessarily <= original value)
-FSE_count() will return the number of occurrence of the most frequent symbol.
-This can be used to know if there is a single symbol within 'src', and to quickly evaluate its compressibility.
-If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError()).
-
-The next step is to normalize the frequencies.
-FSE_normalizeCount() will ensure that sum of frequencies is == 2 ^'tableLog'.
-It also guarantees a minimum of 1 to any Symbol with frequency >= 1.
-You can use 'tableLog'==0 to mean "use default tableLog value".
-If you are unsure of which tableLog value to use, you can ask FSE_optimalTableLog(),
-which will provide the optimal valid tableLog given sourceSize, maxSymbolValue, and a user-defined maximum (0 means "default").
-
-The result of FSE_normalizeCount() will be saved into a table,
-called 'normalizedCounter', which is a table of signed short.
-'normalizedCounter' must be already allocated, and have at least 'maxSymbolValue+1' cells.
-The return value is tableLog if everything proceeded as expected.
-It is 0 if there is a single symbol within distribution.
-If there is an error (ex: invalid tableLog value), the function will return an ErrorCode (which can be tested using FSE_isError()).
-
-'normalizedCounter' can be saved in a compact manner to a memory area using FSE_writeNCount().
-'buffer' must be already allocated.
-For guaranteed success, buffer size must be at least FSE_headerBound().
-The result of the function is the number of bytes written into 'buffer'.
-If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError(); ex : buffer size too small).
-
-'normalizedCounter' can then be used to create the compression table 'CTable'.
-The space required by 'CTable' must be already allocated, using FSE_createCTable().
-You can then use FSE_buildCTable() to fill 'CTable'.
-If there is an error, both functions will return an ErrorCode (which can be tested using FSE_isError()).
-
-'CTable' can then be used to compress 'src', with FSE_compress_usingCTable().
-Similar to FSE_count(), the convention is that 'src' is assumed to be a table of char of size 'srcSize'
-The function returns the size of compressed data (without header), necessarily <= `dstCapacity`.
-If it returns '0', compressed data could not fit into 'dst'.
-If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError()).
-*/
-
-
-/* *** DECOMPRESSION *** */
-
-/*! FSE_readNCount():
- Read compactly saved 'normalizedCounter' from 'rBuffer'.
- @return : size read from 'rBuffer',
- or an errorCode, which can be tested using FSE_isError().
- maxSymbolValuePtr[0] and tableLogPtr[0] will also be updated with their respective values */
-FSE_PUBLIC_API size_t FSE_readNCount (short* normalizedCounter,
- unsigned* maxSymbolValuePtr, unsigned* tableLogPtr,
- const void* rBuffer, size_t rBuffSize);
-
-/*! Constructor and Destructor of FSE_DTable.
- Note that its size depends on 'tableLog' */
-typedef unsigned FSE_DTable; /* don't allocate that. It's just a way to be more restrictive than void* */
-FSE_PUBLIC_API FSE_DTable* FSE_createDTable(unsigned tableLog);
-FSE_PUBLIC_API void FSE_freeDTable(FSE_DTable* dt);
-
-/*! FSE_buildDTable():
- Builds 'dt', which must be already allocated, using FSE_createDTable().
- return : 0, or an errorCode, which can be tested using FSE_isError() */
-FSE_PUBLIC_API size_t FSE_buildDTable (FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog);
-
-/*! FSE_decompress_usingDTable():
- Decompress compressed source `cSrc` of size `cSrcSize` using `dt`
- into `dst` which must be already allocated.
- @return : size of regenerated data (necessarily <= `dstCapacity`),
- or an errorCode, which can be tested using FSE_isError() */
-FSE_PUBLIC_API size_t FSE_decompress_usingDTable(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, const FSE_DTable* dt);
-
-/*!
-Tutorial :
-----------
-(Note : these functions only decompress FSE-compressed blocks.
- If block is uncompressed, use memcpy() instead
- If block is a single repeated byte, use memset() instead )
-
-The first step is to obtain the normalized frequencies of symbols.
-This can be performed by FSE_readNCount() if it was saved using FSE_writeNCount().
-'normalizedCounter' must be already allocated, and have at least 'maxSymbolValuePtr[0]+1' cells of signed short.
-In practice, that means it's necessary to know 'maxSymbolValue' beforehand,
-or size the table to handle worst case situations (typically 256).
-FSE_readNCount() will provide 'tableLog' and 'maxSymbolValue'.
-The result of FSE_readNCount() is the number of bytes read from 'rBuffer'.
-Note that 'rBufferSize' must be at least 4 bytes, even if useful information is less than that.
-If there is an error, the function will return an error code, which can be tested using FSE_isError().
-
-The next step is to build the decompression tables 'FSE_DTable' from 'normalizedCounter'.
-This is performed by the function FSE_buildDTable().
-The space required by 'FSE_DTable' must be already allocated using FSE_createDTable().
-If there is an error, the function will return an error code, which can be tested using FSE_isError().
-
-`FSE_DTable` can then be used to decompress `cSrc`, with FSE_decompress_usingDTable().
-`cSrcSize` must be strictly correct, otherwise decompression will fail.
-FSE_decompress_usingDTable() result will tell how many bytes were regenerated (<=`dstCapacity`).
-If there is an error, the function will return an error code, which can be tested using FSE_isError(). (ex: dst buffer too small)
-*/
-
-#endif /* FSE_H */
-
-#if defined(FSE_STATIC_LINKING_ONLY) && !defined(FSE_H_FSE_STATIC_LINKING_ONLY)
-#define FSE_H_FSE_STATIC_LINKING_ONLY
-
-/* *** Dependency *** */
-/**** start inlining bitstream.h ****/
-/* ******************************************************************
- * bitstream
- * Part of FSE library
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
- *
- * You can contact the author at :
- * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
-****************************************************************** */
-#ifndef BITSTREAM_H_MODULE
-#define BITSTREAM_H_MODULE
-
-#if defined (__cplusplus)
-extern "C" {
-#endif
-
-/*
-* This API consists of small unitary functions, which must be inlined for best performance.
-* Since link-time-optimization is not available for all compilers,
-* these functions are defined into a .h to be included.
-*/
-
-/*-****************************************
-* Dependencies
-******************************************/
-/**** skipping file: mem.h ****/
-/**** start inlining compiler.h ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-#ifndef ZSTD_COMPILER_H
-#define ZSTD_COMPILER_H
-
-/*-*******************************************************
-* Compiler specifics
-*********************************************************/
-/* force inlining */
-
-#if !defined(ZSTD_NO_INLINE)
-#if (defined(__GNUC__) && !defined(__STRICT_ANSI__)) || defined(__cplusplus) || defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
-# define INLINE_KEYWORD inline
-#else
-# define INLINE_KEYWORD
-#endif
-
-#if defined(__GNUC__) || defined(__ICCARM__)
-# define FORCE_INLINE_ATTR __attribute__((always_inline))
-#elif defined(_MSC_VER)
-# define FORCE_INLINE_ATTR __forceinline
-#else
-# define FORCE_INLINE_ATTR
-#endif
-
-#else
-
-#define INLINE_KEYWORD
-#define FORCE_INLINE_ATTR
-
-#endif
-
-/**
- * FORCE_INLINE_TEMPLATE is used to define C "templates", which take constant
- * parameters. They must be inlined for the compiler to eliminate the constant
- * branches.
- */
-#define FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR
-/**
- * HINT_INLINE is used to help the compiler generate better code. It is *not*
- * used for "templates", so it can be tweaked based on the compilers
- * performance.
- *
- * gcc-4.8 and gcc-4.9 have been shown to benefit from leaving off the
- * always_inline attribute.
- *
- * clang up to 5.0.0 (trunk) benefit tremendously from the always_inline
- * attribute.
- */
-#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8 && __GNUC__ < 5
-# define HINT_INLINE static INLINE_KEYWORD
-#else
-# define HINT_INLINE static INLINE_KEYWORD FORCE_INLINE_ATTR
-#endif
-
-/* UNUSED_ATTR tells the compiler it is okay if the function is unused. */
-#if defined(__GNUC__)
-# define UNUSED_ATTR __attribute__((unused))
-#else
-# define UNUSED_ATTR
-#endif
-
-/* force no inlining */
-#ifdef _MSC_VER
-# define FORCE_NOINLINE static __declspec(noinline)
-#else
-# if defined(__GNUC__) || defined(__ICCARM__)
-# define FORCE_NOINLINE static __attribute__((__noinline__))
-# else
-# define FORCE_NOINLINE static
-# endif
-#endif
-
-/* target attribute */
-#ifndef __has_attribute
- #define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
-#endif
-#if defined(__GNUC__) || defined(__ICCARM__)
-# define TARGET_ATTRIBUTE(target) __attribute__((__target__(target)))
-#else
-# define TARGET_ATTRIBUTE(target)
-#endif
-
-/* Enable runtime BMI2 dispatch based on the CPU.
- * Enabled for clang & gcc >=4.8 on x86 when BMI2 isn't enabled by default.
- */
-#ifndef DYNAMIC_BMI2
- #if ((defined(__clang__) && __has_attribute(__target__)) \
- || (defined(__GNUC__) \
- && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))) \
- && (defined(__x86_64__) || defined(_M_X86)) \
- && !defined(__BMI2__)
- # define DYNAMIC_BMI2 1
- #else
- # define DYNAMIC_BMI2 0
- #endif
-#endif
-
-/* prefetch
- * can be disabled, by declaring NO_PREFETCH build macro */
-#if defined(NO_PREFETCH)
-# define PREFETCH_L1(ptr) (void)(ptr) /* disabled */
-# define PREFETCH_L2(ptr) (void)(ptr) /* disabled */
-#else
-# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) /* _mm_prefetch() is not defined outside of x86/x64 */
-# include <mmintrin.h> /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */
-# define PREFETCH_L1(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0)
-# define PREFETCH_L2(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T1)
-# elif defined(__aarch64__)
-# define PREFETCH_L1(ptr) __asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr)))
-# define PREFETCH_L2(ptr) __asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr)))
-# elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) )
-# define PREFETCH_L1(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */)
-# define PREFETCH_L2(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 2 /* locality */)
-# else
-# define PREFETCH_L1(ptr) (void)(ptr) /* disabled */
-# define PREFETCH_L2(ptr) (void)(ptr) /* disabled */
-# endif
-#endif /* NO_PREFETCH */
-
-#define CACHELINE_SIZE 64
-
-#define PREFETCH_AREA(p, s) { \
- const char* const _ptr = (const char*)(p); \
- size_t const _size = (size_t)(s); \
- size_t _pos; \
- for (_pos=0; _pos<_size; _pos+=CACHELINE_SIZE) { \
- PREFETCH_L2(_ptr + _pos); \
- } \
-}
-
-/* vectorization
- * older GCC (pre gcc-4.3 picked as the cutoff) uses a different syntax */
-#if !defined(__INTEL_COMPILER) && !defined(__clang__) && defined(__GNUC__)
-# if (__GNUC__ == 4 && __GNUC_MINOR__ > 3) || (__GNUC__ >= 5)
-# define DONT_VECTORIZE __attribute__((optimize("no-tree-vectorize")))
-# else
-# define DONT_VECTORIZE _Pragma("GCC optimize(\"no-tree-vectorize\")")
-# endif
-#else
-# define DONT_VECTORIZE
-#endif
-
-/* Tell the compiler that a branch is likely or unlikely.
- * Only use these macros if it causes the compiler to generate better code.
- * If you can remove a LIKELY/UNLIKELY annotation without speed changes in gcc
- * and clang, please do.
- */
-#if defined(__GNUC__)
-#define LIKELY(x) (__builtin_expect((x), 1))
-#define UNLIKELY(x) (__builtin_expect((x), 0))
-#else
-#define LIKELY(x) (x)
-#define UNLIKELY(x) (x)
-#endif
-
-/* disable warnings */
-#ifdef _MSC_VER /* Visual Studio */
-# include <intrin.h> /* For Visual 2005 */
-# pragma warning(disable : 4100) /* disable: C4100: unreferenced formal parameter */
-# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
-# pragma warning(disable : 4204) /* disable: C4204: non-constant aggregate initializer */
-# pragma warning(disable : 4214) /* disable: C4214: non-int bitfields */
-# pragma warning(disable : 4324) /* disable: C4324: padded structure */
-#endif
-
-#endif /* ZSTD_COMPILER_H */
-/**** ended inlining compiler.h ****/
-/**** skipping file: debug.h ****/
-/**** skipping file: error_private.h ****/
-
-
-/*=========================================
-* Target specific
-=========================================*/
-#if defined(__BMI__) && defined(__GNUC__)
-# include <immintrin.h> /* support for bextr (experimental) */
-#elif defined(__ICCARM__)
-# include <intrinsics.h>
-#endif
-
-#define STREAM_ACCUMULATOR_MIN_32 25
-#define STREAM_ACCUMULATOR_MIN_64 57
-#define STREAM_ACCUMULATOR_MIN ((U32)(MEM_32bits() ? STREAM_ACCUMULATOR_MIN_32 : STREAM_ACCUMULATOR_MIN_64))
-
-
-/*-******************************************
-* bitStream encoding API (write forward)
-********************************************/
-/* bitStream can mix input from multiple sources.
- * A critical property of these streams is that they encode and decode in **reverse** direction.
- * So the first bit sequence you add will be the last to be read, like a LIFO stack.
- */
-typedef struct {
- size_t bitContainer;
- unsigned bitPos;
- char* startPtr;
- char* ptr;
- char* endPtr;
-} BIT_CStream_t;
-
-MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, void* dstBuffer, size_t dstCapacity);
-MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits);
-MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC);
-MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC);
-
-/* Start with initCStream, providing the size of buffer to write into.
-* bitStream will never write outside of this buffer.
-* `dstCapacity` must be >= sizeof(bitD->bitContainer), otherwise @return will be an error code.
-*
-* bits are first added to a local register.
-* Local register is size_t, hence 64-bits on 64-bits systems, or 32-bits on 32-bits systems.
-* Writing data into memory is an explicit operation, performed by the flushBits function.
-* Hence keep track how many bits are potentially stored into local register to avoid register overflow.
-* After a flushBits, a maximum of 7 bits might still be stored into local register.
-*
-* Avoid storing elements of more than 24 bits if you want compatibility with 32-bits bitstream readers.
-*
-* Last operation is to close the bitStream.
-* The function returns the final size of CStream in bytes.
-* If data couldn't fit into `dstBuffer`, it will return a 0 ( == not storable)
-*/
-
-
-/*-********************************************
-* bitStream decoding API (read backward)
-**********************************************/
-typedef struct {
- size_t bitContainer;
- unsigned bitsConsumed;
- const char* ptr;
- const char* start;
- const char* limitPtr;
-} BIT_DStream_t;
-
-typedef enum { BIT_DStream_unfinished = 0,
- BIT_DStream_endOfBuffer = 1,
- BIT_DStream_completed = 2,
- BIT_DStream_overflow = 3 } BIT_DStream_status; /* result of BIT_reloadDStream() */
- /* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */
-
-MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize);
-MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits);
-MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD);
-MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD);
-
-
-/* Start by invoking BIT_initDStream().
-* A chunk of the bitStream is then stored into a local register.
-* Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
-* You can then retrieve bitFields stored into the local register, **in reverse order**.
-* Local register is explicitly reloaded from memory by the BIT_reloadDStream() method.
-* A reload guarantee a minimum of ((8*sizeof(bitD->bitContainer))-7) bits when its result is BIT_DStream_unfinished.
-* Otherwise, it can be less than that, so proceed accordingly.
-* Checking if DStream has reached its end can be performed with BIT_endOfDStream().
-*/
-
-
-/*-****************************************
-* unsafe API
-******************************************/
-MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, size_t value, unsigned nbBits);
-/* faster, but works only if value is "clean", meaning all high bits above nbBits are 0 */
-
-MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC);
-/* unsafe version; does not check buffer overflow */
-
-MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits);
-/* faster, but works only if nbBits >= 1 */
-
-
-
-/*-**************************************************************
-* Internal functions
-****************************************************************/
-MEM_STATIC unsigned BIT_highbit32 (U32 val)
-{
- assert(val != 0);
- {
-# if defined(_MSC_VER) /* Visual */
- unsigned long r=0;
- return _BitScanReverse ( &r, val ) ? (unsigned)r : 0;
-# elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */
- return __builtin_clz (val) ^ 31;
-# elif defined(__ICCARM__) /* IAR Intrinsic */
- return 31 - __CLZ(val);
-# else /* Software version */
- static const unsigned DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29,
- 11, 14, 16, 18, 22, 25, 3, 30,
- 8, 12, 20, 28, 15, 17, 24, 7,
- 19, 27, 23, 6, 26, 5, 4, 31 };
- U32 v = val;
- v |= v >> 1;
- v |= v >> 2;
- v |= v >> 4;
- v |= v >> 8;
- v |= v >> 16;
- return DeBruijnClz[ (U32) (v * 0x07C4ACDDU) >> 27];
-# endif
- }
-}
-
-/*===== Local Constants =====*/
-static const unsigned BIT_mask[] = {
- 0, 1, 3, 7, 0xF, 0x1F,
- 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF,
- 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0x1FFFF,
- 0x3FFFF, 0x7FFFF, 0xFFFFF, 0x1FFFFF, 0x3FFFFF, 0x7FFFFF,
- 0xFFFFFF, 0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF, 0x1FFFFFFF,
- 0x3FFFFFFF, 0x7FFFFFFF}; /* up to 31 bits */
-#define BIT_MASK_SIZE (sizeof(BIT_mask) / sizeof(BIT_mask[0]))
-
-/*-**************************************************************
-* bitStream encoding
-****************************************************************/
-/*! BIT_initCStream() :
- * `dstCapacity` must be > sizeof(size_t)
- * @return : 0 if success,
- * otherwise an error code (can be tested using ERR_isError()) */
-MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC,
- void* startPtr, size_t dstCapacity)
-{
- bitC->bitContainer = 0;
- bitC->bitPos = 0;
- bitC->startPtr = (char*)startPtr;
- bitC->ptr = bitC->startPtr;
- bitC->endPtr = bitC->startPtr + dstCapacity - sizeof(bitC->bitContainer);
- if (dstCapacity <= sizeof(bitC->bitContainer)) return ERROR(dstSize_tooSmall);
- return 0;
-}
-
-/*! BIT_addBits() :
- * can add up to 31 bits into `bitC`.
- * Note : does not check for register overflow ! */
-MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC,
- size_t value, unsigned nbBits)
-{
- MEM_STATIC_ASSERT(BIT_MASK_SIZE == 32);
- assert(nbBits < BIT_MASK_SIZE);
- assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8);
- bitC->bitContainer |= (value & BIT_mask[nbBits]) << bitC->bitPos;
- bitC->bitPos += nbBits;
-}
-
-/*! BIT_addBitsFast() :
- * works only if `value` is _clean_,
- * meaning all high bits above nbBits are 0 */
-MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC,
- size_t value, unsigned nbBits)
-{
- assert((value>>nbBits) == 0);
- assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8);
- bitC->bitContainer |= value << bitC->bitPos;
- bitC->bitPos += nbBits;
-}
-
-/*! BIT_flushBitsFast() :
- * assumption : bitContainer has not overflowed
- * unsafe version; does not check buffer overflow */
-MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC)
-{
- size_t const nbBytes = bitC->bitPos >> 3;
- assert(bitC->bitPos < sizeof(bitC->bitContainer) * 8);
- assert(bitC->ptr <= bitC->endPtr);
- MEM_writeLEST(bitC->ptr, bitC->bitContainer);
- bitC->ptr += nbBytes;
- bitC->bitPos &= 7;
- bitC->bitContainer >>= nbBytes*8;
-}
-
-/*! BIT_flushBits() :
- * assumption : bitContainer has not overflowed
- * safe version; check for buffer overflow, and prevents it.
- * note : does not signal buffer overflow.
- * overflow will be revealed later on using BIT_closeCStream() */
-MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC)
-{
- size_t const nbBytes = bitC->bitPos >> 3;
- assert(bitC->bitPos < sizeof(bitC->bitContainer) * 8);
- assert(bitC->ptr <= bitC->endPtr);
- MEM_writeLEST(bitC->ptr, bitC->bitContainer);
- bitC->ptr += nbBytes;
- if (bitC->ptr > bitC->endPtr) bitC->ptr = bitC->endPtr;
- bitC->bitPos &= 7;
- bitC->bitContainer >>= nbBytes*8;
-}
-
-/*! BIT_closeCStream() :
- * @return : size of CStream, in bytes,
- * or 0 if it could not fit into dstBuffer */
-MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC)
-{
- BIT_addBitsFast(bitC, 1, 1); /* endMark */
- BIT_flushBits(bitC);
- if (bitC->ptr >= bitC->endPtr) return 0; /* overflow detected */
- return (bitC->ptr - bitC->startPtr) + (bitC->bitPos > 0);
-}
-
-
-/*-********************************************************
-* bitStream decoding
-**********************************************************/
-/*! BIT_initDStream() :
- * Initialize a BIT_DStream_t.
- * `bitD` : a pointer to an already allocated BIT_DStream_t structure.
- * `srcSize` must be the *exact* size of the bitStream, in bytes.
- * @return : size of stream (== srcSize), or an errorCode if a problem is detected
- */
-MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize)
-{
- if (srcSize < 1) { memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); }
-
- bitD->start = (const char*)srcBuffer;
- bitD->limitPtr = bitD->start + sizeof(bitD->bitContainer);
-
- if (srcSize >= sizeof(bitD->bitContainer)) { /* normal case */
- bitD->ptr = (const char*)srcBuffer + srcSize - sizeof(bitD->bitContainer);
- bitD->bitContainer = MEM_readLEST(bitD->ptr);
- { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];
- bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; /* ensures bitsConsumed is always set */
- if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ }
- } else {
- bitD->ptr = bitD->start;
- bitD->bitContainer = *(const BYTE*)(bitD->start);
- switch(srcSize)
- {
- case 7: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16);
- /* fall-through */
-
- case 6: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24);
- /* fall-through */
-
- case 5: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32);
- /* fall-through */
-
- case 4: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[3]) << 24;
- /* fall-through */
-
- case 3: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[2]) << 16;
- /* fall-through */
-
- case 2: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[1]) << 8;
- /* fall-through */
-
- default: break;
- }
- { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];
- bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0;
- if (lastByte == 0) return ERROR(corruption_detected); /* endMark not present */
- }
- bitD->bitsConsumed += (U32)(sizeof(bitD->bitContainer) - srcSize)*8;
- }
-
- return srcSize;
-}
-
-MEM_STATIC size_t BIT_getUpperBits(size_t bitContainer, U32 const start)
-{
- return bitContainer >> start;
-}
-
-MEM_STATIC size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits)
-{
- U32 const regMask = sizeof(bitContainer)*8 - 1;
- /* if start > regMask, bitstream is corrupted, and result is undefined */
- assert(nbBits < BIT_MASK_SIZE);
- return (bitContainer >> (start & regMask)) & BIT_mask[nbBits];
-}
-
-MEM_STATIC size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits)
-{
- assert(nbBits < BIT_MASK_SIZE);
- return bitContainer & BIT_mask[nbBits];
-}
-
-/*! BIT_lookBits() :
- * Provides next n bits from local register.
- * local register is not modified.
- * On 32-bits, maxNbBits==24.
- * On 64-bits, maxNbBits==56.
- * @return : value extracted */
-MEM_STATIC size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits)
-{
- /* arbitrate between double-shift and shift+mask */
-#if 1
- /* if bitD->bitsConsumed + nbBits > sizeof(bitD->bitContainer)*8,
- * bitstream is likely corrupted, and result is undefined */
- return BIT_getMiddleBits(bitD->bitContainer, (sizeof(bitD->bitContainer)*8) - bitD->bitsConsumed - nbBits, nbBits);
-#else
- /* this code path is slower on my os-x laptop */
- U32 const regMask = sizeof(bitD->bitContainer)*8 - 1;
- return ((bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> 1) >> ((regMask-nbBits) & regMask);
-#endif
-}
-
-/*! BIT_lookBitsFast() :
- * unsafe version; only works if nbBits >= 1 */
-MEM_STATIC size_t BIT_lookBitsFast(const BIT_DStream_t* bitD, U32 nbBits)
-{
- U32 const regMask = sizeof(bitD->bitContainer)*8 - 1;
- assert(nbBits >= 1);
- return (bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> (((regMask+1)-nbBits) & regMask);
-}
-
-MEM_STATIC void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits)
-{
- bitD->bitsConsumed += nbBits;
-}
-
-/*! BIT_readBits() :
- * Read (consume) next n bits from local register and update.
- * Pay attention to not read more than nbBits contained into local register.
- * @return : extracted value. */
-MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits)
-{
- size_t const value = BIT_lookBits(bitD, nbBits);
- BIT_skipBits(bitD, nbBits);
- return value;
-}
-
-/*! BIT_readBitsFast() :
- * unsafe version; only works only if nbBits >= 1 */
-MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits)
-{
- size_t const value = BIT_lookBitsFast(bitD, nbBits);
- assert(nbBits >= 1);
- BIT_skipBits(bitD, nbBits);
- return value;
-}
-
-/*! BIT_reloadDStreamFast() :
- * Similar to BIT_reloadDStream(), but with two differences:
- * 1. bitsConsumed <= sizeof(bitD->bitContainer)*8 must hold!
- * 2. Returns BIT_DStream_overflow when bitD->ptr < bitD->limitPtr, at this
- * point you must use BIT_reloadDStream() to reload.
- */
-MEM_STATIC BIT_DStream_status BIT_reloadDStreamFast(BIT_DStream_t* bitD)
-{
- if (UNLIKELY(bitD->ptr < bitD->limitPtr))
- return BIT_DStream_overflow;
- assert(bitD->bitsConsumed <= sizeof(bitD->bitContainer)*8);
- bitD->ptr -= bitD->bitsConsumed >> 3;
- bitD->bitsConsumed &= 7;
- bitD->bitContainer = MEM_readLEST(bitD->ptr);
- return BIT_DStream_unfinished;
-}
-
-/*! BIT_reloadDStream() :
- * Refill `bitD` from buffer previously set in BIT_initDStream() .
- * This function is safe, it guarantees it will not read beyond src buffer.
- * @return : status of `BIT_DStream_t` internal register.
- * when status == BIT_DStream_unfinished, internal register is filled with at least 25 or 57 bits */
-MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD)
-{
- if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* overflow detected, like end of stream */
- return BIT_DStream_overflow;
-
- if (bitD->ptr >= bitD->limitPtr) {
- return BIT_reloadDStreamFast(bitD);
- }
- if (bitD->ptr == bitD->start) {
- if (bitD->bitsConsumed < sizeof(bitD->bitContainer)*8) return BIT_DStream_endOfBuffer;
- return BIT_DStream_completed;
- }
- /* start < ptr < limitPtr */
- { U32 nbBytes = bitD->bitsConsumed >> 3;
- BIT_DStream_status result = BIT_DStream_unfinished;
- if (bitD->ptr - nbBytes < bitD->start) {
- nbBytes = (U32)(bitD->ptr - bitD->start); /* ptr > start */
- result = BIT_DStream_endOfBuffer;
- }
- bitD->ptr -= nbBytes;
- bitD->bitsConsumed -= nbBytes*8;
- bitD->bitContainer = MEM_readLEST(bitD->ptr); /* reminder : srcSize > sizeof(bitD->bitContainer), otherwise bitD->ptr == bitD->start */
- return result;
- }
-}
-
-/*! BIT_endOfDStream() :
- * @return : 1 if DStream has _exactly_ reached its end (all bits consumed).
- */
-MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* DStream)
-{
- return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == sizeof(DStream->bitContainer)*8));
-}
-
-#if defined (__cplusplus)
-}
-#endif
-
-#endif /* BITSTREAM_H_MODULE */
-/**** ended inlining bitstream.h ****/
-
-
-/* *****************************************
-* Static allocation
-*******************************************/
-/* FSE buffer bounds */
-#define FSE_NCOUNTBOUND 512
-#define FSE_BLOCKBOUND(size) (size + (size>>7) + 4 /* fse states */ + sizeof(size_t) /* bitContainer */)
-#define FSE_COMPRESSBOUND(size) (FSE_NCOUNTBOUND + FSE_BLOCKBOUND(size)) /* Macro version, useful for static allocation */
-
-/* It is possible to statically allocate FSE CTable/DTable as a table of FSE_CTable/FSE_DTable using below macros */
-#define FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) (1 + (1<<(maxTableLog-1)) + ((maxSymbolValue+1)*2))
-#define FSE_DTABLE_SIZE_U32(maxTableLog) (1 + (1<<maxTableLog))
-
-/* or use the size to malloc() space directly. Pay attention to alignment restrictions though */
-#define FSE_CTABLE_SIZE(maxTableLog, maxSymbolValue) (FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) * sizeof(FSE_CTable))
-#define FSE_DTABLE_SIZE(maxTableLog) (FSE_DTABLE_SIZE_U32(maxTableLog) * sizeof(FSE_DTable))
-
-
-/* *****************************************
- * FSE advanced API
- ***************************************** */
-
-unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus);
-/**< same as FSE_optimalTableLog(), which used `minus==2` */
-
-/* FSE_compress_wksp() :
- * Same as FSE_compress2(), but using an externally allocated scratch buffer (`workSpace`).
- * FSE_WKSP_SIZE_U32() provides the minimum size required for `workSpace` as a table of FSE_CTable.
- */
-#define FSE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) ( FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) + ((maxTableLog > 12) ? (1 << (maxTableLog - 2)) : 1024) )
-size_t FSE_compress_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize);
-
-size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits);
-/**< build a fake FSE_CTable, designed for a flat distribution, where each symbol uses nbBits */
-
-size_t FSE_buildCTable_rle (FSE_CTable* ct, unsigned char symbolValue);
-/**< build a fake FSE_CTable, designed to compress always the same symbolValue */
-
-/* FSE_buildCTable_wksp() :
- * Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`).
- * `wkspSize` must be >= `(1<<tableLog)`.
- */
-size_t FSE_buildCTable_wksp(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize);
-
-size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits);
-/**< build a fake FSE_DTable, designed to read a flat distribution where each symbol uses nbBits */
-
-size_t FSE_buildDTable_rle (FSE_DTable* dt, unsigned char symbolValue);
-/**< build a fake FSE_DTable, designed to always generate the same symbolValue */
-
-size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, FSE_DTable* workSpace, unsigned maxLog);
-/**< same as FSE_decompress(), using an externally allocated `workSpace` produced with `FSE_DTABLE_SIZE_U32(maxLog)` */
-
-typedef enum {
- FSE_repeat_none, /**< Cannot use the previous table */
- FSE_repeat_check, /**< Can use the previous table but it must be checked */
- FSE_repeat_valid /**< Can use the previous table and it is assumed to be valid */
- } FSE_repeat;
-
-/* *****************************************
-* FSE symbol compression API
-*******************************************/
-/*!
- This API consists of small unitary functions, which highly benefit from being inlined.
- Hence their body are included in next section.
-*/
-typedef struct {
- ptrdiff_t value;
- const void* stateTable;
- const void* symbolTT;
- unsigned stateLog;
-} FSE_CState_t;
-
-static void FSE_initCState(FSE_CState_t* CStatePtr, const FSE_CTable* ct);
-
-static void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* CStatePtr, unsigned symbol);
-
-static void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* CStatePtr);
-
-/**<
-These functions are inner components of FSE_compress_usingCTable().
-They allow the creation of custom streams, mixing multiple tables and bit sources.
-
-A key property to keep in mind is that encoding and decoding are done **in reverse direction**.
-So the first symbol you will encode is the last you will decode, like a LIFO stack.
-
-You will need a few variables to track your CStream. They are :
-
-FSE_CTable ct; // Provided by FSE_buildCTable()
-BIT_CStream_t bitStream; // bitStream tracking structure
-FSE_CState_t state; // State tracking structure (can have several)
-
-
-The first thing to do is to init bitStream and state.
- size_t errorCode = BIT_initCStream(&bitStream, dstBuffer, maxDstSize);
- FSE_initCState(&state, ct);
-
-Note that BIT_initCStream() can produce an error code, so its result should be tested, using FSE_isError();
-You can then encode your input data, byte after byte.
-FSE_encodeSymbol() outputs a maximum of 'tableLog' bits at a time.
-Remember decoding will be done in reverse direction.
- FSE_encodeByte(&bitStream, &state, symbol);
-
-At any time, you can also add any bit sequence.
-Note : maximum allowed nbBits is 25, for compatibility with 32-bits decoders
- BIT_addBits(&bitStream, bitField, nbBits);
-
-The above methods don't commit data to memory, they just store it into local register, for speed.
-Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
-Writing data to memory is a manual operation, performed by the flushBits function.
- BIT_flushBits(&bitStream);
-
-Your last FSE encoding operation shall be to flush your last state value(s).
- FSE_flushState(&bitStream, &state);
-
-Finally, you must close the bitStream.
-The function returns the size of CStream in bytes.
-If data couldn't fit into dstBuffer, it will return a 0 ( == not compressible)
-If there is an error, it returns an errorCode (which can be tested using FSE_isError()).
- size_t size = BIT_closeCStream(&bitStream);
-*/
-
-
-/* *****************************************
-* FSE symbol decompression API
-*******************************************/
-typedef struct {
- size_t state;
- const void* table; /* precise table may vary, depending on U16 */
-} FSE_DState_t;
-
-
-static void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt);
-
-static unsigned char FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD);
-
-static unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr);
-
-/**<
-Let's now decompose FSE_decompress_usingDTable() into its unitary components.
-You will decode FSE-encoded symbols from the bitStream,
-and also any other bitFields you put in, **in reverse order**.
-
-You will need a few variables to track your bitStream. They are :
-
-BIT_DStream_t DStream; // Stream context
-FSE_DState_t DState; // State context. Multiple ones are possible
-FSE_DTable* DTablePtr; // Decoding table, provided by FSE_buildDTable()
-
-The first thing to do is to init the bitStream.
- errorCode = BIT_initDStream(&DStream, srcBuffer, srcSize);
-
-You should then retrieve your initial state(s)
-(in reverse flushing order if you have several ones) :
- errorCode = FSE_initDState(&DState, &DStream, DTablePtr);
-
-You can then decode your data, symbol after symbol.
-For information the maximum number of bits read by FSE_decodeSymbol() is 'tableLog'.
-Keep in mind that symbols are decoded in reverse order, like a LIFO stack (last in, first out).
- unsigned char symbol = FSE_decodeSymbol(&DState, &DStream);
-
-You can retrieve any bitfield you eventually stored into the bitStream (in reverse order)
-Note : maximum allowed nbBits is 25, for 32-bits compatibility
- size_t bitField = BIT_readBits(&DStream, nbBits);
-
-All above operations only read from local register (which size depends on size_t).
-Refueling the register from memory is manually performed by the reload method.
- endSignal = FSE_reloadDStream(&DStream);
-
-BIT_reloadDStream() result tells if there is still some more data to read from DStream.
-BIT_DStream_unfinished : there is still some data left into the DStream.
-BIT_DStream_endOfBuffer : Dstream reached end of buffer. Its container may no longer be completely filled.
-BIT_DStream_completed : Dstream reached its exact end, corresponding in general to decompression completed.
-BIT_DStream_tooFar : Dstream went too far. Decompression result is corrupted.
-
-When reaching end of buffer (BIT_DStream_endOfBuffer), progress slowly, notably if you decode multiple symbols per loop,
-to properly detect the exact end of stream.
-After each decoded symbol, check if DStream is fully consumed using this simple test :
- BIT_reloadDStream(&DStream) >= BIT_DStream_completed
-
-When it's done, verify decompression is fully completed, by checking both DStream and the relevant states.
-Checking if DStream has reached its end is performed by :
- BIT_endOfDStream(&DStream);
-Check also the states. There might be some symbols left there, if some high probability ones (>50%) are possible.
- FSE_endOfDState(&DState);
-*/
-
-
-/* *****************************************
-* FSE unsafe API
-*******************************************/
-static unsigned char FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD);
-/* faster, but works only if nbBits is always >= 1 (otherwise, result will be corrupted) */
-
-
-/* *****************************************
-* Implementation of inlined functions
-*******************************************/
-typedef struct {
- int deltaFindState;
- U32 deltaNbBits;
-} FSE_symbolCompressionTransform; /* total 8 bytes */
-
-MEM_STATIC void FSE_initCState(FSE_CState_t* statePtr, const FSE_CTable* ct)
-{
- const void* ptr = ct;
- const U16* u16ptr = (const U16*) ptr;
- const U32 tableLog = MEM_read16(ptr);
- statePtr->value = (ptrdiff_t)1<<tableLog;
- statePtr->stateTable = u16ptr+2;
- statePtr->symbolTT = ct + 1 + (tableLog ? (1<<(tableLog-1)) : 1);
- statePtr->stateLog = tableLog;
-}
-
-
-/*! FSE_initCState2() :
-* Same as FSE_initCState(), but the first symbol to include (which will be the last to be read)
-* uses the smallest state value possible, saving the cost of this symbol */
-MEM_STATIC void FSE_initCState2(FSE_CState_t* statePtr, const FSE_CTable* ct, U32 symbol)
-{
- FSE_initCState(statePtr, ct);
- { const FSE_symbolCompressionTransform symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol];
- const U16* stateTable = (const U16*)(statePtr->stateTable);
- U32 nbBitsOut = (U32)((symbolTT.deltaNbBits + (1<<15)) >> 16);
- statePtr->value = (nbBitsOut << 16) - symbolTT.deltaNbBits;
- statePtr->value = stateTable[(statePtr->value >> nbBitsOut) + symbolTT.deltaFindState];
- }
-}
-
-MEM_STATIC void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* statePtr, unsigned symbol)
-{
- FSE_symbolCompressionTransform const symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol];
- const U16* const stateTable = (const U16*)(statePtr->stateTable);
- U32 const nbBitsOut = (U32)((statePtr->value + symbolTT.deltaNbBits) >> 16);
- BIT_addBits(bitC, statePtr->value, nbBitsOut);
- statePtr->value = stateTable[ (statePtr->value >> nbBitsOut) + symbolTT.deltaFindState];
-}
-
-MEM_STATIC void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* statePtr)
-{
- BIT_addBits(bitC, statePtr->value, statePtr->stateLog);
- BIT_flushBits(bitC);
-}
-
-
-/* FSE_getMaxNbBits() :
- * Approximate maximum cost of a symbol, in bits.
- * Fractional get rounded up (i.e : a symbol with a normalized frequency of 3 gives the same result as a frequency of 2)
- * note 1 : assume symbolValue is valid (<= maxSymbolValue)
- * note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */
-MEM_STATIC U32 FSE_getMaxNbBits(const void* symbolTTPtr, U32 symbolValue)
-{
- const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr;
- return (symbolTT[symbolValue].deltaNbBits + ((1<<16)-1)) >> 16;
-}
-
-/* FSE_bitCost() :
- * Approximate symbol cost, as fractional value, using fixed-point format (accuracyLog fractional bits)
- * note 1 : assume symbolValue is valid (<= maxSymbolValue)
- * note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */
-MEM_STATIC U32 FSE_bitCost(const void* symbolTTPtr, U32 tableLog, U32 symbolValue, U32 accuracyLog)
-{
- const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr;
- U32 const minNbBits = symbolTT[symbolValue].deltaNbBits >> 16;
- U32 const threshold = (minNbBits+1) << 16;
- assert(tableLog < 16);
- assert(accuracyLog < 31-tableLog); /* ensure enough room for renormalization double shift */
- { U32 const tableSize = 1 << tableLog;
- U32 const deltaFromThreshold = threshold - (symbolTT[symbolValue].deltaNbBits + tableSize);
- U32 const normalizedDeltaFromThreshold = (deltaFromThreshold << accuracyLog) >> tableLog; /* linear interpolation (very approximate) */
- U32 const bitMultiplier = 1 << accuracyLog;
- assert(symbolTT[symbolValue].deltaNbBits + tableSize <= threshold);
- assert(normalizedDeltaFromThreshold <= bitMultiplier);
- return (minNbBits+1)*bitMultiplier - normalizedDeltaFromThreshold;
- }
-}
-
-
-/* ====== Decompression ====== */
-
-typedef struct {
- U16 tableLog;
- U16 fastMode;
-} FSE_DTableHeader; /* sizeof U32 */
-
-typedef struct
-{
- unsigned short newState;
- unsigned char symbol;
- unsigned char nbBits;
-} FSE_decode_t; /* size == U32 */
-
-MEM_STATIC void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt)
-{
- const void* ptr = dt;
- const FSE_DTableHeader* const DTableH = (const FSE_DTableHeader*)ptr;
- DStatePtr->state = BIT_readBits(bitD, DTableH->tableLog);
- BIT_reloadDStream(bitD);
- DStatePtr->table = dt + 1;
-}
-
-MEM_STATIC BYTE FSE_peekSymbol(const FSE_DState_t* DStatePtr)
-{
- FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
- return DInfo.symbol;
-}
-
-MEM_STATIC void FSE_updateState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
-{
- FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
- U32 const nbBits = DInfo.nbBits;
- size_t const lowBits = BIT_readBits(bitD, nbBits);
- DStatePtr->state = DInfo.newState + lowBits;
-}
-
-MEM_STATIC BYTE FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
-{
- FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
- U32 const nbBits = DInfo.nbBits;
- BYTE const symbol = DInfo.symbol;
- size_t const lowBits = BIT_readBits(bitD, nbBits);
-
- DStatePtr->state = DInfo.newState + lowBits;
- return symbol;
-}
-
-/*! FSE_decodeSymbolFast() :
- unsafe, only works if no symbol has a probability > 50% */
-MEM_STATIC BYTE FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
-{
- FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
- U32 const nbBits = DInfo.nbBits;
- BYTE const symbol = DInfo.symbol;
- size_t const lowBits = BIT_readBitsFast(bitD, nbBits);
-
- DStatePtr->state = DInfo.newState + lowBits;
- return symbol;
-}
-
-MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr)
-{
- return DStatePtr->state == 0;
-}
-
-
-
-#ifndef FSE_COMMONDEFS_ONLY
-
-/* **************************************************************
-* Tuning parameters
-****************************************************************/
-/*!MEMORY_USAGE :
-* Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
-* Increasing memory usage improves compression ratio
-* Reduced memory usage can improve speed, due to cache effect
-* Recommended max value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */
-#ifndef FSE_MAX_MEMORY_USAGE
-# define FSE_MAX_MEMORY_USAGE 14
-#endif
-#ifndef FSE_DEFAULT_MEMORY_USAGE
-# define FSE_DEFAULT_MEMORY_USAGE 13
-#endif
-
-/*!FSE_MAX_SYMBOL_VALUE :
-* Maximum symbol value authorized.
-* Required for proper stack allocation */
-#ifndef FSE_MAX_SYMBOL_VALUE
-# define FSE_MAX_SYMBOL_VALUE 255
-#endif
-
-/* **************************************************************
-* template functions type & suffix
-****************************************************************/
-#define FSE_FUNCTION_TYPE BYTE
-#define FSE_FUNCTION_EXTENSION
-#define FSE_DECODE_TYPE FSE_decode_t
-
-
-#endif /* !FSE_COMMONDEFS_ONLY */
-
-
-/* ***************************************************************
-* Constants
-*****************************************************************/
-#define FSE_MAX_TABLELOG (FSE_MAX_MEMORY_USAGE-2)
-#define FSE_MAX_TABLESIZE (1U<<FSE_MAX_TABLELOG)
-#define FSE_MAXTABLESIZE_MASK (FSE_MAX_TABLESIZE-1)
-#define FSE_DEFAULT_TABLELOG (FSE_DEFAULT_MEMORY_USAGE-2)
-#define FSE_MIN_TABLELOG 5
-
-#define FSE_TABLELOG_ABSOLUTE_MAX 15
-#if FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX
-# error "FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX is not supported"
-#endif
-
-#define FSE_TABLESTEP(tableSize) ((tableSize>>1) + (tableSize>>3) + 3)
-
-
-#endif /* FSE_STATIC_LINKING_ONLY */
-
-
-#if defined (__cplusplus)
-}
-#endif
-/**** ended inlining fse.h ****/
-#define HUF_STATIC_LINKING_ONLY /* HUF_TABLELOG_ABSOLUTEMAX */
-/**** start inlining huf.h ****/
-/* ******************************************************************
- * huff0 huffman codec,
- * part of Finite State Entropy library
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
- *
- * You can contact the author at :
- * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
-****************************************************************** */
-
-#if defined (__cplusplus)
-extern "C" {
-#endif
-
-#ifndef HUF_H_298734234
-#define HUF_H_298734234
-
-/* *** Dependencies *** */
-#include <stddef.h> /* size_t */
-
-
-/* *** library symbols visibility *** */
-/* Note : when linking with -fvisibility=hidden on gcc, or by default on Visual,
- * HUF symbols remain "private" (internal symbols for library only).
- * Set macro FSE_DLL_EXPORT to 1 if you want HUF symbols visible on DLL interface */
-#if defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) && defined(__GNUC__) && (__GNUC__ >= 4)
-# define HUF_PUBLIC_API __attribute__ ((visibility ("default")))
-#elif defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) /* Visual expected */
-# define HUF_PUBLIC_API __declspec(dllexport)
-#elif defined(FSE_DLL_IMPORT) && (FSE_DLL_IMPORT==1)
-# define HUF_PUBLIC_API __declspec(dllimport) /* not required, just to generate faster code (saves a function pointer load from IAT and an indirect jump) */
-#else
-# define HUF_PUBLIC_API
-#endif
-
-
-/* ========================== */
-/* *** simple functions *** */
-/* ========================== */
-
-/** HUF_compress() :
- * Compress content from buffer 'src', of size 'srcSize', into buffer 'dst'.
- * 'dst' buffer must be already allocated.
- * Compression runs faster if `dstCapacity` >= HUF_compressBound(srcSize).
- * `srcSize` must be <= `HUF_BLOCKSIZE_MAX` == 128 KB.
- * @return : size of compressed data (<= `dstCapacity`).
- * Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!!
- * if HUF_isError(return), compression failed (more details using HUF_getErrorName())
- */
-HUF_PUBLIC_API size_t HUF_compress(void* dst, size_t dstCapacity,
- const void* src, size_t srcSize);
-
-/** HUF_decompress() :
- * Decompress HUF data from buffer 'cSrc', of size 'cSrcSize',
- * into already allocated buffer 'dst', of minimum size 'dstSize'.
- * `originalSize` : **must** be the ***exact*** size of original (uncompressed) data.
- * Note : in contrast with FSE, HUF_decompress can regenerate
- * RLE (cSrcSize==1) and uncompressed (cSrcSize==dstSize) data,
- * because it knows size to regenerate (originalSize).
- * @return : size of regenerated data (== originalSize),
- * or an error code, which can be tested using HUF_isError()
- */
-HUF_PUBLIC_API size_t HUF_decompress(void* dst, size_t originalSize,
- const void* cSrc, size_t cSrcSize);
-
-
-/* *** Tool functions *** */
-#define HUF_BLOCKSIZE_MAX (128 * 1024) /**< maximum input size for a single block compressed with HUF_compress */
-HUF_PUBLIC_API size_t HUF_compressBound(size_t size); /**< maximum compressed size (worst case) */
-
-/* Error Management */
-HUF_PUBLIC_API unsigned HUF_isError(size_t code); /**< tells if a return value is an error code */
-HUF_PUBLIC_API const char* HUF_getErrorName(size_t code); /**< provides error code string (useful for debugging) */
-
-
-/* *** Advanced function *** */
-
-/** HUF_compress2() :
- * Same as HUF_compress(), but offers control over `maxSymbolValue` and `tableLog`.
- * `maxSymbolValue` must be <= HUF_SYMBOLVALUE_MAX .
- * `tableLog` must be `<= HUF_TABLELOG_MAX` . */
-HUF_PUBLIC_API size_t HUF_compress2 (void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- unsigned maxSymbolValue, unsigned tableLog);
-
-/** HUF_compress4X_wksp() :
- * Same as HUF_compress2(), but uses externally allocated `workSpace`.
- * `workspace` must have minimum alignment of 4, and be at least as large as HUF_WORKSPACE_SIZE */
-#define HUF_WORKSPACE_SIZE ((6 << 10) + 256)
-#define HUF_WORKSPACE_SIZE_U32 (HUF_WORKSPACE_SIZE / sizeof(U32))
-HUF_PUBLIC_API size_t HUF_compress4X_wksp (void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- unsigned maxSymbolValue, unsigned tableLog,
- void* workSpace, size_t wkspSize);
-
-#endif /* HUF_H_298734234 */
-
-/* ******************************************************************
- * WARNING !!
- * The following section contains advanced and experimental definitions
- * which shall never be used in the context of a dynamic library,
- * because they are not guaranteed to remain stable in the future.
- * Only consider them in association with static linking.
- * *****************************************************************/
-#if defined(HUF_STATIC_LINKING_ONLY) && !defined(HUF_H_HUF_STATIC_LINKING_ONLY)
-#define HUF_H_HUF_STATIC_LINKING_ONLY
-
-/* *** Dependencies *** */
-/**** skipping file: mem.h ****/
-
-
-/* *** Constants *** */
-#define HUF_TABLELOG_MAX 12 /* max runtime value of tableLog (due to static allocation); can be modified up to HUF_ABSOLUTEMAX_TABLELOG */
-#define HUF_TABLELOG_DEFAULT 11 /* default tableLog value when none specified */
-#define HUF_SYMBOLVALUE_MAX 255
-
-#define HUF_TABLELOG_ABSOLUTEMAX 15 /* absolute limit of HUF_MAX_TABLELOG. Beyond that value, code does not work */
-#if (HUF_TABLELOG_MAX > HUF_TABLELOG_ABSOLUTEMAX)
-# error "HUF_TABLELOG_MAX is too large !"
-#endif
-
-
-/* ****************************************
-* Static allocation
-******************************************/
-/* HUF buffer bounds */
-#define HUF_CTABLEBOUND 129
-#define HUF_BLOCKBOUND(size) (size + (size>>8) + 8) /* only true when incompressible is pre-filtered with fast heuristic */
-#define HUF_COMPRESSBOUND(size) (HUF_CTABLEBOUND + HUF_BLOCKBOUND(size)) /* Macro version, useful for static allocation */
-
-/* static allocation of HUF's Compression Table */
-#define HUF_CTABLE_SIZE_U32(maxSymbolValue) ((maxSymbolValue)+1) /* Use tables of U32, for proper alignment */
-#define HUF_CTABLE_SIZE(maxSymbolValue) (HUF_CTABLE_SIZE_U32(maxSymbolValue) * sizeof(U32))
-#define HUF_CREATE_STATIC_CTABLE(name, maxSymbolValue) \
- U32 name##hb[HUF_CTABLE_SIZE_U32(maxSymbolValue)]; \
- void* name##hv = &(name##hb); \
- HUF_CElt* name = (HUF_CElt*)(name##hv) /* no final ; */
-
-/* static allocation of HUF's DTable */
-typedef U32 HUF_DTable;
-#define HUF_DTABLE_SIZE(maxTableLog) (1 + (1<<(maxTableLog)))
-#define HUF_CREATE_STATIC_DTABLEX1(DTable, maxTableLog) \
- HUF_DTable DTable[HUF_DTABLE_SIZE((maxTableLog)-1)] = { ((U32)((maxTableLog)-1) * 0x01000001) }
-#define HUF_CREATE_STATIC_DTABLEX2(DTable, maxTableLog) \
- HUF_DTable DTable[HUF_DTABLE_SIZE(maxTableLog)] = { ((U32)(maxTableLog) * 0x01000001) }
-
-
-/* ****************************************
-* Advanced decompression functions
-******************************************/
-size_t HUF_decompress4X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */
-#ifndef HUF_FORCE_DECOMPRESS_X1
-size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */
-#endif
-
-size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< decodes RLE and uncompressed */
-size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< considers RLE and uncompressed as errors */
-size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< considers RLE and uncompressed as errors */
-size_t HUF_decompress4X1_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */
-size_t HUF_decompress4X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< single-symbol decoder */
-#ifndef HUF_FORCE_DECOMPRESS_X1
-size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */
-size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< double-symbols decoder */
-#endif
-
-
-/* ****************************************
- * HUF detailed API
- * ****************************************/
-
-/*! HUF_compress() does the following:
- * 1. count symbol occurrence from source[] into table count[] using FSE_count() (exposed within "fse.h")
- * 2. (optional) refine tableLog using HUF_optimalTableLog()
- * 3. build Huffman table from count using HUF_buildCTable()
- * 4. save Huffman table to memory buffer using HUF_writeCTable()
- * 5. encode the data stream using HUF_compress4X_usingCTable()
- *
- * The following API allows targeting specific sub-functions for advanced tasks.
- * For example, it's possible to compress several blocks using the same 'CTable',
- * or to save and regenerate 'CTable' using external methods.
- */
-unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue);
-typedef struct HUF_CElt_s HUF_CElt; /* incomplete type */
-size_t HUF_buildCTable (HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue, unsigned maxNbBits); /* @return : maxNbBits; CTable and count can overlap. In which case, CTable will overwrite count content */
-size_t HUF_writeCTable (void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog);
-size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable);
-size_t HUF_estimateCompressedSize(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue);
-int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue);
-
-typedef enum {
- HUF_repeat_none, /**< Cannot use the previous table */
- HUF_repeat_check, /**< Can use the previous table but it must be checked. Note : The previous table must have been constructed by HUF_compress{1, 4}X_repeat */
- HUF_repeat_valid /**< Can use the previous table and it is assumed to be valid */
- } HUF_repeat;
-/** HUF_compress4X_repeat() :
- * Same as HUF_compress4X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none.
- * If it uses hufTable it does not modify hufTable or repeat.
- * If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used.
- * If preferRepeat then the old table will always be used if valid. */
-size_t HUF_compress4X_repeat(void* dst, size_t dstSize,
- const void* src, size_t srcSize,
- unsigned maxSymbolValue, unsigned tableLog,
- void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */
- HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2);
-
-/** HUF_buildCTable_wksp() :
- * Same as HUF_buildCTable(), but using externally allocated scratch buffer.
- * `workSpace` must be aligned on 4-bytes boundaries, and its size must be >= HUF_CTABLE_WORKSPACE_SIZE.
- */
-#define HUF_CTABLE_WORKSPACE_SIZE_U32 (2*HUF_SYMBOLVALUE_MAX +1 +1)
-#define HUF_CTABLE_WORKSPACE_SIZE (HUF_CTABLE_WORKSPACE_SIZE_U32 * sizeof(unsigned))
-size_t HUF_buildCTable_wksp (HUF_CElt* tree,
- const unsigned* count, U32 maxSymbolValue, U32 maxNbBits,
- void* workSpace, size_t wkspSize);
-
-/*! HUF_readStats() :
- * Read compact Huffman tree, saved by HUF_writeCTable().
- * `huffWeight` is destination buffer.
- * @return : size read from `src` , or an error Code .
- * Note : Needed by HUF_readCTable() and HUF_readDTableXn() . */
-size_t HUF_readStats(BYTE* huffWeight, size_t hwSize,
- U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr,
- const void* src, size_t srcSize);
-
-/** HUF_readCTable() :
- * Loading a CTable saved with HUF_writeCTable() */
-size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned *hasZeroWeights);
-
-/** HUF_getNbBits() :
- * Read nbBits from CTable symbolTable, for symbol `symbolValue` presumed <= HUF_SYMBOLVALUE_MAX
- * Note 1 : is not inlined, as HUF_CElt definition is private
- * Note 2 : const void* used, so that it can provide a statically allocated table as argument (which uses type U32) */
-U32 HUF_getNbBits(const void* symbolTable, U32 symbolValue);
-
-/*
- * HUF_decompress() does the following:
- * 1. select the decompression algorithm (X1, X2) based on pre-computed heuristics
- * 2. build Huffman table from save, using HUF_readDTableX?()
- * 3. decode 1 or 4 segments in parallel using HUF_decompress?X?_usingDTable()
- */
-
-/** HUF_selectDecoder() :
- * Tells which decoder is likely to decode faster,
- * based on a set of pre-computed metrics.
- * @return : 0==HUF_decompress4X1, 1==HUF_decompress4X2 .
- * Assumption : 0 < dstSize <= 128 KB */
-U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize);
-
-/**
- * The minimum workspace size for the `workSpace` used in
- * HUF_readDTableX1_wksp() and HUF_readDTableX2_wksp().
- *
- * The space used depends on HUF_TABLELOG_MAX, ranging from ~1500 bytes when
- * HUF_TABLE_LOG_MAX=12 to ~1850 bytes when HUF_TABLE_LOG_MAX=15.
- * Buffer overflow errors may potentially occur if code modifications result in
- * a required workspace size greater than that specified in the following
- * macro.
- */
-#define HUF_DECOMPRESS_WORKSPACE_SIZE (2 << 10)
-#define HUF_DECOMPRESS_WORKSPACE_SIZE_U32 (HUF_DECOMPRESS_WORKSPACE_SIZE / sizeof(U32))
-
-#ifndef HUF_FORCE_DECOMPRESS_X2
-size_t HUF_readDTableX1 (HUF_DTable* DTable, const void* src, size_t srcSize);
-size_t HUF_readDTableX1_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize);
-#endif
-#ifndef HUF_FORCE_DECOMPRESS_X1
-size_t HUF_readDTableX2 (HUF_DTable* DTable, const void* src, size_t srcSize);
-size_t HUF_readDTableX2_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize);
-#endif
-
-size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
-#ifndef HUF_FORCE_DECOMPRESS_X2
-size_t HUF_decompress4X1_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
-#endif
-#ifndef HUF_FORCE_DECOMPRESS_X1
-size_t HUF_decompress4X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
-#endif
-
-
-/* ====================== */
-/* single stream variants */
-/* ====================== */
-
-size_t HUF_compress1X (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog);
-size_t HUF_compress1X_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); /**< `workSpace` must be a table of at least HUF_WORKSPACE_SIZE_U32 unsigned */
-size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable);
-/** HUF_compress1X_repeat() :
- * Same as HUF_compress1X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none.
- * If it uses hufTable it does not modify hufTable or repeat.
- * If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used.
- * If preferRepeat then the old table will always be used if valid. */
-size_t HUF_compress1X_repeat(void* dst, size_t dstSize,
- const void* src, size_t srcSize,
- unsigned maxSymbolValue, unsigned tableLog,
- void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */
- HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2);
-
-size_t HUF_decompress1X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* single-symbol decoder */
-#ifndef HUF_FORCE_DECOMPRESS_X1
-size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* double-symbol decoder */
-#endif
-
-size_t HUF_decompress1X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);
-size_t HUF_decompress1X_DCtx_wksp (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize);
-#ifndef HUF_FORCE_DECOMPRESS_X2
-size_t HUF_decompress1X1_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */
-size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< single-symbol decoder */
-#endif
-#ifndef HUF_FORCE_DECOMPRESS_X1
-size_t HUF_decompress1X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */
-size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< double-symbols decoder */
-#endif
-
-size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); /**< automatic selection of sing or double symbol decoder, based on DTable */
-#ifndef HUF_FORCE_DECOMPRESS_X2
-size_t HUF_decompress1X1_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
-#endif
-#ifndef HUF_FORCE_DECOMPRESS_X1
-size_t HUF_decompress1X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
-#endif
-
-/* BMI2 variants.
- * If the CPU has BMI2 support, pass bmi2=1, otherwise pass bmi2=0.
- */
-size_t HUF_decompress1X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2);
-#ifndef HUF_FORCE_DECOMPRESS_X2
-size_t HUF_decompress1X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2);
-#endif
-size_t HUF_decompress4X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2);
-size_t HUF_decompress4X_hufOnly_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2);
-
-#endif /* HUF_STATIC_LINKING_ONLY */
-
-#if defined (__cplusplus)
-}
-#endif
-/**** ended inlining huf.h ****/
-
-
-/*=== Version ===*/
-unsigned FSE_versionNumber(void) { return FSE_VERSION_NUMBER; }
-
-
-/*=== Error Management ===*/
-unsigned FSE_isError(size_t code) { return ERR_isError(code); }
-const char* FSE_getErrorName(size_t code) { return ERR_getErrorName(code); }
-
-unsigned HUF_isError(size_t code) { return ERR_isError(code); }
-const char* HUF_getErrorName(size_t code) { return ERR_getErrorName(code); }
-
-
-/*-**************************************************************
-* FSE NCount encoding-decoding
-****************************************************************/
-size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
- const void* headerBuffer, size_t hbSize)
-{
- const BYTE* const istart = (const BYTE*) headerBuffer;
- const BYTE* const iend = istart + hbSize;
- const BYTE* ip = istart;
- int nbBits;
- int remaining;
- int threshold;
- U32 bitStream;
- int bitCount;
- unsigned charnum = 0;
- int previous0 = 0;
-
- if (hbSize < 4) {
- /* This function only works when hbSize >= 4 */
- char buffer[4];
- memset(buffer, 0, sizeof(buffer));
- memcpy(buffer, headerBuffer, hbSize);
- { size_t const countSize = FSE_readNCount(normalizedCounter, maxSVPtr, tableLogPtr,
- buffer, sizeof(buffer));
- if (FSE_isError(countSize)) return countSize;
- if (countSize > hbSize) return ERROR(corruption_detected);
- return countSize;
- } }
- assert(hbSize >= 4);
-
- /* init */
- memset(normalizedCounter, 0, (*maxSVPtr+1) * sizeof(normalizedCounter[0])); /* all symbols not present in NCount have a frequency of 0 */
- bitStream = MEM_readLE32(ip);
- nbBits = (bitStream & 0xF) + FSE_MIN_TABLELOG; /* extract tableLog */
- if (nbBits > FSE_TABLELOG_ABSOLUTE_MAX) return ERROR(tableLog_tooLarge);
- bitStream >>= 4;
- bitCount = 4;
- *tableLogPtr = nbBits;
- remaining = (1<<nbBits)+1;
- threshold = 1<<nbBits;
- nbBits++;
-
- while ((remaining>1) & (charnum<=*maxSVPtr)) {
- if (previous0) {
- unsigned n0 = charnum;
- while ((bitStream & 0xFFFF) == 0xFFFF) {
- n0 += 24;
- if (ip < iend-5) {
- ip += 2;
- bitStream = MEM_readLE32(ip) >> bitCount;
- } else {
- bitStream >>= 16;
- bitCount += 16;
- } }
- while ((bitStream & 3) == 3) {
- n0 += 3;
- bitStream >>= 2;
- bitCount += 2;
- }
- n0 += bitStream & 3;
- bitCount += 2;
- if (n0 > *maxSVPtr) return ERROR(maxSymbolValue_tooSmall);
- while (charnum < n0) normalizedCounter[charnum++] = 0;
- if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
- assert((bitCount >> 3) <= 3); /* For first condition to work */
- ip += bitCount>>3;
- bitCount &= 7;
- bitStream = MEM_readLE32(ip) >> bitCount;
- } else {
- bitStream >>= 2;
- } }
- { int const max = (2*threshold-1) - remaining;
- int count;
-
- if ((bitStream & (threshold-1)) < (U32)max) {
- count = bitStream & (threshold-1);
- bitCount += nbBits-1;
- } else {
- count = bitStream & (2*threshold-1);
- if (count >= threshold) count -= max;
- bitCount += nbBits;
- }
-
- count--; /* extra accuracy */
- remaining -= count < 0 ? -count : count; /* -1 means +1 */
- normalizedCounter[charnum++] = (short)count;
- previous0 = !count;
- while (remaining < threshold) {
- nbBits--;
- threshold >>= 1;
- }
-
- if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
- ip += bitCount>>3;
- bitCount &= 7;
- } else {
- bitCount -= (int)(8 * (iend - 4 - ip));
- ip = iend - 4;
- }
- bitStream = MEM_readLE32(ip) >> (bitCount & 31);
- } } /* while ((remaining>1) & (charnum<=*maxSVPtr)) */
- if (remaining != 1) return ERROR(corruption_detected);
- if (bitCount > 32) return ERROR(corruption_detected);
- *maxSVPtr = charnum-1;
-
- ip += (bitCount+7)>>3;
- return ip-istart;
-}
-
-
-/*! HUF_readStats() :
- Read compact Huffman tree, saved by HUF_writeCTable().
- `huffWeight` is destination buffer.
- `rankStats` is assumed to be a table of at least HUF_TABLELOG_MAX U32.
- @return : size read from `src` , or an error Code .
- Note : Needed by HUF_readCTable() and HUF_readDTableX?() .
-*/
-size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats,
- U32* nbSymbolsPtr, U32* tableLogPtr,
- const void* src, size_t srcSize)
-{
- U32 weightTotal;
- const BYTE* ip = (const BYTE*) src;
- size_t iSize;
- size_t oSize;
-
- if (!srcSize) return ERROR(srcSize_wrong);
- iSize = ip[0];
- /* memset(huffWeight, 0, hwSize); *//* is not necessary, even though some analyzer complain ... */
-
- if (iSize >= 128) { /* special header */
- oSize = iSize - 127;
- iSize = ((oSize+1)/2);
- if (iSize+1 > srcSize) return ERROR(srcSize_wrong);
- if (oSize >= hwSize) return ERROR(corruption_detected);
- ip += 1;
- { U32 n;
- for (n=0; n<oSize; n+=2) {
- huffWeight[n] = ip[n/2] >> 4;
- huffWeight[n+1] = ip[n/2] & 15;
- } } }
- else { /* header compressed with FSE (normal case) */
- FSE_DTable fseWorkspace[FSE_DTABLE_SIZE_U32(6)]; /* 6 is max possible tableLog for HUF header (maybe even 5, to be tested) */
- if (iSize+1 > srcSize) return ERROR(srcSize_wrong);
- oSize = FSE_decompress_wksp(huffWeight, hwSize-1, ip+1, iSize, fseWorkspace, 6); /* max (hwSize-1) values decoded, as last one is implied */
- if (FSE_isError(oSize)) return oSize;
- }
-
- /* collect weight stats */
- memset(rankStats, 0, (HUF_TABLELOG_MAX + 1) * sizeof(U32));
- weightTotal = 0;
- { U32 n; for (n=0; n<oSize; n++) {
- if (huffWeight[n] >= HUF_TABLELOG_MAX) return ERROR(corruption_detected);
- rankStats[huffWeight[n]]++;
- weightTotal += (1 << huffWeight[n]) >> 1;
- } }
- if (weightTotal == 0) return ERROR(corruption_detected);
-
- /* get last non-null symbol weight (implied, total must be 2^n) */
- { U32 const tableLog = BIT_highbit32(weightTotal) + 1;
- if (tableLog > HUF_TABLELOG_MAX) return ERROR(corruption_detected);
- *tableLogPtr = tableLog;
- /* determine last weight */
- { U32 const total = 1 << tableLog;
- U32 const rest = total - weightTotal;
- U32 const verif = 1 << BIT_highbit32(rest);
- U32 const lastWeight = BIT_highbit32(rest) + 1;
- if (verif != rest) return ERROR(corruption_detected); /* last value must be a clean power of 2 */
- huffWeight[oSize] = (BYTE)lastWeight;
- rankStats[lastWeight]++;
- } }
-
- /* check tree construction validity */
- if ((rankStats[1] < 2) || (rankStats[1] & 1)) return ERROR(corruption_detected); /* by construction : at least 2 elts of rank 1, must be even */
-
- /* results */
- *nbSymbolsPtr = (U32)(oSize+1);
- return iSize+1;
-}
-/**** ended inlining common/entropy_common.c ****/
-/**** start inlining common/error_private.c ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-/* The purpose of this file is to have a single list of error strings embedded in binary */
-
-/**** skipping file: error_private.h ****/
-
-const char* ERR_getErrorString(ERR_enum code)
-{
-#ifdef ZSTD_STRIP_ERROR_STRINGS
- (void)code;
- return "Error strings stripped";
-#else
- static const char* const notErrorCode = "Unspecified error code";
- switch( code )
- {
- case PREFIX(no_error): return "No error detected";
- case PREFIX(GENERIC): return "Error (generic)";
- case PREFIX(prefix_unknown): return "Unknown frame descriptor";
- case PREFIX(version_unsupported): return "Version not supported";
- case PREFIX(frameParameter_unsupported): return "Unsupported frame parameter";
- case PREFIX(frameParameter_windowTooLarge): return "Frame requires too much memory for decoding";
- case PREFIX(corruption_detected): return "Corrupted block detected";
- case PREFIX(checksum_wrong): return "Restored data doesn't match checksum";
- case PREFIX(parameter_unsupported): return "Unsupported parameter";
- case PREFIX(parameter_outOfBound): return "Parameter is out of bound";
- case PREFIX(init_missing): return "Context should be init first";
- case PREFIX(memory_allocation): return "Allocation error : not enough memory";
- case PREFIX(workSpace_tooSmall): return "workSpace buffer is not large enough";
- case PREFIX(stage_wrong): return "Operation not authorized at current processing stage";
- case PREFIX(tableLog_tooLarge): return "tableLog requires too much memory : unsupported";
- case PREFIX(maxSymbolValue_tooLarge): return "Unsupported max Symbol Value : too large";
- case PREFIX(maxSymbolValue_tooSmall): return "Specified maxSymbolValue is too small";
- case PREFIX(dictionary_corrupted): return "Dictionary is corrupted";
- case PREFIX(dictionary_wrong): return "Dictionary mismatch";
- case PREFIX(dictionaryCreation_failed): return "Cannot create Dictionary from provided samples";
- case PREFIX(dstSize_tooSmall): return "Destination buffer is too small";
- case PREFIX(srcSize_wrong): return "Src size is incorrect";
- case PREFIX(dstBuffer_null): return "Operation on NULL destination buffer";
- /* following error codes are not stable and may be removed or changed in a future version */
- case PREFIX(frameIndex_tooLarge): return "Frame index is too large";
- case PREFIX(seekableIO): return "An I/O error occurred when reading/seeking";
- case PREFIX(dstBuffer_wrong): return "Destination buffer is wrong";
- case PREFIX(maxCode):
- default: return notErrorCode;
- }
-#endif
-}
-/**** ended inlining common/error_private.c ****/
-/**** start inlining common/fse_decompress.c ****/
-/* ******************************************************************
- * FSE : Finite State Entropy decoder
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
- *
- * You can contact the author at :
- * - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
- * - Public forum : https://groups.google.com/forum/#!forum/lz4c
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
-****************************************************************** */
-
-
-/* **************************************************************
-* Includes
-****************************************************************/
-#include <stdlib.h> /* malloc, free, qsort */
-#include <string.h> /* memcpy, memset */
-/**** skipping file: bitstream.h ****/
-/**** skipping file: compiler.h ****/
-#define FSE_STATIC_LINKING_ONLY
-/**** skipping file: fse.h ****/
-/**** skipping file: error_private.h ****/
-
-
-/* **************************************************************
-* Error Management
-****************************************************************/
-#define FSE_isError ERR_isError
-#define FSE_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) /* use only *after* variable declarations */
-
-
-/* **************************************************************
-* Templates
-****************************************************************/
-/*
- designed to be included
- for type-specific functions (template emulation in C)
- Objective is to write these functions only once, for improved maintenance
-*/
-
-/* safety checks */
-#ifndef FSE_FUNCTION_EXTENSION
-# error "FSE_FUNCTION_EXTENSION must be defined"
-#endif
-#ifndef FSE_FUNCTION_TYPE
-# error "FSE_FUNCTION_TYPE must be defined"
-#endif
-
-/* Function names */
-#define FSE_CAT(X,Y) X##Y
-#define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y)
-#define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y)
-
-
-/* Function templates */
-FSE_DTable* FSE_createDTable (unsigned tableLog)
-{
- if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX;
- return (FSE_DTable*)malloc( FSE_DTABLE_SIZE_U32(tableLog) * sizeof (U32) );
-}
-
-void FSE_freeDTable (FSE_DTable* dt)
-{
- free(dt);
-}
-
-size_t FSE_buildDTable(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)
-{
- void* const tdPtr = dt+1; /* because *dt is unsigned, 32-bits aligned on 32-bits */
- FSE_DECODE_TYPE* const tableDecode = (FSE_DECODE_TYPE*) (tdPtr);
- U16 symbolNext[FSE_MAX_SYMBOL_VALUE+1];
-
- U32 const maxSV1 = maxSymbolValue + 1;
- U32 const tableSize = 1 << tableLog;
- U32 highThreshold = tableSize-1;
-
- /* Sanity Checks */
- if (maxSymbolValue > FSE_MAX_SYMBOL_VALUE) return ERROR(maxSymbolValue_tooLarge);
- if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge);
-
- /* Init, lay down lowprob symbols */
- { FSE_DTableHeader DTableH;
- DTableH.tableLog = (U16)tableLog;
- DTableH.fastMode = 1;
- { S16 const largeLimit= (S16)(1 << (tableLog-1));
- U32 s;
- for (s=0; s<maxSV1; s++) {
- if (normalizedCounter[s]==-1) {
- tableDecode[highThreshold--].symbol = (FSE_FUNCTION_TYPE)s;
- symbolNext[s] = 1;
- } else {
- if (normalizedCounter[s] >= largeLimit) DTableH.fastMode=0;
- symbolNext[s] = normalizedCounter[s];
- } } }
- memcpy(dt, &DTableH, sizeof(DTableH));
- }
-
- /* Spread symbols */
- { U32 const tableMask = tableSize-1;
- U32 const step = FSE_TABLESTEP(tableSize);
- U32 s, position = 0;
- for (s=0; s<maxSV1; s++) {
- int i;
- for (i=0; i<normalizedCounter[s]; i++) {
- tableDecode[position].symbol = (FSE_FUNCTION_TYPE)s;
- position = (position + step) & tableMask;
- while (position > highThreshold) position = (position + step) & tableMask; /* lowprob area */
- } }
- if (position!=0) return ERROR(GENERIC); /* position must reach all cells once, otherwise normalizedCounter is incorrect */
- }
-
- /* Build Decoding table */
- { U32 u;
- for (u=0; u<tableSize; u++) {
- FSE_FUNCTION_TYPE const symbol = (FSE_FUNCTION_TYPE)(tableDecode[u].symbol);
- U32 const nextState = symbolNext[symbol]++;
- tableDecode[u].nbBits = (BYTE) (tableLog - BIT_highbit32(nextState) );
- tableDecode[u].newState = (U16) ( (nextState << tableDecode[u].nbBits) - tableSize);
- } }
-
- return 0;
-}
-
-
-#ifndef FSE_COMMONDEFS_ONLY
-
-/*-*******************************************************
-* Decompression (Byte symbols)
-*********************************************************/
-size_t FSE_buildDTable_rle (FSE_DTable* dt, BYTE symbolValue)
-{
- void* ptr = dt;
- FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr;
- void* dPtr = dt + 1;
- FSE_decode_t* const cell = (FSE_decode_t*)dPtr;
-
- DTableH->tableLog = 0;
- DTableH->fastMode = 0;
-
- cell->newState = 0;
- cell->symbol = symbolValue;
- cell->nbBits = 0;
-
- return 0;
-}
-
-
-size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits)
-{
- void* ptr = dt;
- FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr;
- void* dPtr = dt + 1;
- FSE_decode_t* const dinfo = (FSE_decode_t*)dPtr;
- const unsigned tableSize = 1 << nbBits;
- const unsigned tableMask = tableSize - 1;
- const unsigned maxSV1 = tableMask+1;
- unsigned s;
-
- /* Sanity checks */
- if (nbBits < 1) return ERROR(GENERIC); /* min size */
-
- /* Build Decoding Table */
- DTableH->tableLog = (U16)nbBits;
- DTableH->fastMode = 1;
- for (s=0; s<maxSV1; s++) {
- dinfo[s].newState = 0;
- dinfo[s].symbol = (BYTE)s;
- dinfo[s].nbBits = (BYTE)nbBits;
- }
-
- return 0;
-}
-
-FORCE_INLINE_TEMPLATE size_t FSE_decompress_usingDTable_generic(
- void* dst, size_t maxDstSize,
- const void* cSrc, size_t cSrcSize,
- const FSE_DTable* dt, const unsigned fast)
-{
- BYTE* const ostart = (BYTE*) dst;
- BYTE* op = ostart;
- BYTE* const omax = op + maxDstSize;
- BYTE* const olimit = omax-3;
-
- BIT_DStream_t bitD;
- FSE_DState_t state1;
- FSE_DState_t state2;
-
- /* Init */
- CHECK_F(BIT_initDStream(&bitD, cSrc, cSrcSize));
-
- FSE_initDState(&state1, &bitD, dt);
- FSE_initDState(&state2, &bitD, dt);
-
-#define FSE_GETSYMBOL(statePtr) fast ? FSE_decodeSymbolFast(statePtr, &bitD) : FSE_decodeSymbol(statePtr, &bitD)
-
- /* 4 symbols per loop */
- for ( ; (BIT_reloadDStream(&bitD)==BIT_DStream_unfinished) & (op<olimit) ; op+=4) {
- op[0] = FSE_GETSYMBOL(&state1);
-
- if (FSE_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */
- BIT_reloadDStream(&bitD);
-
- op[1] = FSE_GETSYMBOL(&state2);
-
- if (FSE_MAX_TABLELOG*4+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */
- { if (BIT_reloadDStream(&bitD) > BIT_DStream_unfinished) { op+=2; break; } }
-
- op[2] = FSE_GETSYMBOL(&state1);
-
- if (FSE_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */
- BIT_reloadDStream(&bitD);
-
- op[3] = FSE_GETSYMBOL(&state2);
- }
-
- /* tail */
- /* note : BIT_reloadDStream(&bitD) >= FSE_DStream_partiallyFilled; Ends at exactly BIT_DStream_completed */
- while (1) {
- if (op>(omax-2)) return ERROR(dstSize_tooSmall);
- *op++ = FSE_GETSYMBOL(&state1);
- if (BIT_reloadDStream(&bitD)==BIT_DStream_overflow) {
- *op++ = FSE_GETSYMBOL(&state2);
- break;
- }
-
- if (op>(omax-2)) return ERROR(dstSize_tooSmall);
- *op++ = FSE_GETSYMBOL(&state2);
- if (BIT_reloadDStream(&bitD)==BIT_DStream_overflow) {
- *op++ = FSE_GETSYMBOL(&state1);
- break;
- } }
-
- return op-ostart;
-}
-
-
-size_t FSE_decompress_usingDTable(void* dst, size_t originalSize,
- const void* cSrc, size_t cSrcSize,
- const FSE_DTable* dt)
-{
- const void* ptr = dt;
- const FSE_DTableHeader* DTableH = (const FSE_DTableHeader*)ptr;
- const U32 fastMode = DTableH->fastMode;
-
- /* select fast mode (static) */
- if (fastMode) return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 1);
- return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 0);
-}
-
-
-size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, FSE_DTable* workSpace, unsigned maxLog)
-{
- const BYTE* const istart = (const BYTE*)cSrc;
- const BYTE* ip = istart;
- short counting[FSE_MAX_SYMBOL_VALUE+1];
- unsigned tableLog;
- unsigned maxSymbolValue = FSE_MAX_SYMBOL_VALUE;
-
- /* normal FSE decoding mode */
- size_t const NCountLength = FSE_readNCount (counting, &maxSymbolValue, &tableLog, istart, cSrcSize);
- if (FSE_isError(NCountLength)) return NCountLength;
- /* if (NCountLength >= cSrcSize) return ERROR(srcSize_wrong); */ /* too small input size; supposed to be already checked in NCountLength, only remaining case : NCountLength==cSrcSize */
- if (tableLog > maxLog) return ERROR(tableLog_tooLarge);
- ip += NCountLength;
- cSrcSize -= NCountLength;
-
- CHECK_F( FSE_buildDTable (workSpace, counting, maxSymbolValue, tableLog) );
-
- return FSE_decompress_usingDTable (dst, dstCapacity, ip, cSrcSize, workSpace); /* always return, even if it is an error code */
-}
-
-
-typedef FSE_DTable DTable_max_t[FSE_DTABLE_SIZE_U32(FSE_MAX_TABLELOG)];
-
-size_t FSE_decompress(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize)
-{
- DTable_max_t dt; /* Static analyzer seems unable to understand this table will be properly initialized later */
- return FSE_decompress_wksp(dst, dstCapacity, cSrc, cSrcSize, dt, FSE_MAX_TABLELOG);
-}
-
-
-
-#endif /* FSE_COMMONDEFS_ONLY */
-/**** ended inlining common/fse_decompress.c ****/
-/**** start inlining common/pool.c ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-
-/* ====== Dependencies ======= */
-#include <stddef.h> /* size_t */
-/**** skipping file: debug.h ****/
-/**** start inlining zstd_internal.h ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-#ifndef ZSTD_CCOMMON_H_MODULE
-#define ZSTD_CCOMMON_H_MODULE
-
-/* this module contains definitions which must be identical
- * across compression, decompression and dictBuilder.
- * It also contains a few functions useful to at least 2 of them
- * and which benefit from being inlined */
-
-/*-*************************************
-* Dependencies
-***************************************/
-#if !defined(ZSTD_NO_INTRINSICS) && defined(__ARM_NEON)
-#include <arm_neon.h>
-#endif
-/**** skipping file: compiler.h ****/
-/**** skipping file: mem.h ****/
-/**** skipping file: debug.h ****/
-/**** skipping file: error_private.h ****/
-#define ZSTD_STATIC_LINKING_ONLY
-/**** start inlining ../zstd.h ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-#if defined (__cplusplus)
-extern "C" {
-#endif
-
-#ifndef ZSTD_H_235446
-#define ZSTD_H_235446
-
-/* ====== Dependency ======*/
-#include <limits.h> /* INT_MAX */
-#include <stddef.h> /* size_t */
-
-
-/* ===== ZSTDLIB_API : control library symbols visibility ===== */
-#ifndef ZSTDLIB_VISIBILITY
-# if defined(__GNUC__) && (__GNUC__ >= 4)
-# define ZSTDLIB_VISIBILITY __attribute__ ((visibility ("default")))
-# else
-# define ZSTDLIB_VISIBILITY
-# endif
-#endif
-#if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1)
-# define ZSTDLIB_API __declspec(dllexport) ZSTDLIB_VISIBILITY
-#elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1)
-# define ZSTDLIB_API __declspec(dllimport) ZSTDLIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/
-#else
-# define ZSTDLIB_API ZSTDLIB_VISIBILITY
-#endif
-
-
-/*******************************************************************************
- Introduction
-
- zstd, short for Zstandard, is a fast lossless compression algorithm, targeting
- real-time compression scenarios at zlib-level and better compression ratios.
- The zstd compression library provides in-memory compression and decompression
- functions.
-
- The library supports regular compression levels from 1 up to ZSTD_maxCLevel(),
- which is currently 22. Levels >= 20, labeled `--ultra`, should be used with
- caution, as they require more memory. The library also offers negative
- compression levels, which extend the range of speed vs. ratio preferences.
- The lower the level, the faster the speed (at the cost of compression).
-
- Compression can be done in:
- - a single step (described as Simple API)
- - a single step, reusing a context (described as Explicit context)
- - unbounded multiple steps (described as Streaming compression)
-
- The compression ratio achievable on small data can be highly improved using
- a dictionary. Dictionary compression can be performed in:
- - a single step (described as Simple dictionary API)
- - a single step, reusing a dictionary (described as Bulk-processing
- dictionary API)
-
- Advanced experimental functions can be accessed using
- `#define ZSTD_STATIC_LINKING_ONLY` before including zstd.h.
-
- Advanced experimental APIs should never be used with a dynamically-linked
- library. They are not "stable"; their definitions or signatures may change in
- the future. Only static linking is allowed.
-*******************************************************************************/
-
-/*------ Version ------*/
-#define ZSTD_VERSION_MAJOR 1
-#define ZSTD_VERSION_MINOR 4
-#define ZSTD_VERSION_RELEASE 5
-
-#define ZSTD_VERSION_NUMBER (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE)
-ZSTDLIB_API unsigned ZSTD_versionNumber(void); /**< to check runtime library version */
-
-#define ZSTD_LIB_VERSION ZSTD_VERSION_MAJOR.ZSTD_VERSION_MINOR.ZSTD_VERSION_RELEASE
-#define ZSTD_QUOTE(str) #str
-#define ZSTD_EXPAND_AND_QUOTE(str) ZSTD_QUOTE(str)
-#define ZSTD_VERSION_STRING ZSTD_EXPAND_AND_QUOTE(ZSTD_LIB_VERSION)
-ZSTDLIB_API const char* ZSTD_versionString(void); /* requires v1.3.0+ */
-
-/* *************************************
- * Default constant
- ***************************************/
-#ifndef ZSTD_CLEVEL_DEFAULT
-# define ZSTD_CLEVEL_DEFAULT 3
-#endif
-
-/* *************************************
- * Constants
- ***************************************/
-
-/* All magic numbers are supposed read/written to/from files/memory using little-endian convention */
-#define ZSTD_MAGICNUMBER 0xFD2FB528 /* valid since v0.8.0 */
-#define ZSTD_MAGIC_DICTIONARY 0xEC30A437 /* valid since v0.7.0 */
-#define ZSTD_MAGIC_SKIPPABLE_START 0x184D2A50 /* all 16 values, from 0x184D2A50 to 0x184D2A5F, signal the beginning of a skippable frame */
-#define ZSTD_MAGIC_SKIPPABLE_MASK 0xFFFFFFF0
-
-#define ZSTD_BLOCKSIZELOG_MAX 17
-#define ZSTD_BLOCKSIZE_MAX (1<<ZSTD_BLOCKSIZELOG_MAX)
-
-
-
-/***************************************
-* Simple API
-***************************************/
-/*! ZSTD_compress() :
- * Compresses `src` content as a single zstd compressed frame into already allocated `dst`.
- * Hint : compression runs faster if `dstCapacity` >= `ZSTD_compressBound(srcSize)`.
- * @return : compressed size written into `dst` (<= `dstCapacity),
- * or an error code if it fails (which can be tested using ZSTD_isError()). */
-ZSTDLIB_API size_t ZSTD_compress( void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- int compressionLevel);
-
-/*! ZSTD_decompress() :
- * `compressedSize` : must be the _exact_ size of some number of compressed and/or skippable frames.
- * `dstCapacity` is an upper bound of originalSize to regenerate.
- * If user cannot imply a maximum upper bound, it's better to use streaming mode to decompress data.
- * @return : the number of bytes decompressed into `dst` (<= `dstCapacity`),
- * or an errorCode if it fails (which can be tested using ZSTD_isError()). */
-ZSTDLIB_API size_t ZSTD_decompress( void* dst, size_t dstCapacity,
- const void* src, size_t compressedSize);
-
-/*! ZSTD_getFrameContentSize() : requires v1.3.0+
- * `src` should point to the start of a ZSTD encoded frame.
- * `srcSize` must be at least as large as the frame header.
- * hint : any size >= `ZSTD_frameHeaderSize_max` is large enough.
- * @return : - decompressed size of `src` frame content, if known
- * - ZSTD_CONTENTSIZE_UNKNOWN if the size cannot be determined
- * - ZSTD_CONTENTSIZE_ERROR if an error occurred (e.g. invalid magic number, srcSize too small)
- * note 1 : a 0 return value means the frame is valid but "empty".
- * note 2 : decompressed size is an optional field, it may not be present, typically in streaming mode.
- * When `return==ZSTD_CONTENTSIZE_UNKNOWN`, data to decompress could be any size.
- * In which case, it's necessary to use streaming mode to decompress data.
- * Optionally, application can rely on some implicit limit,
- * as ZSTD_decompress() only needs an upper bound of decompressed size.
- * (For example, data could be necessarily cut into blocks <= 16 KB).
- * note 3 : decompressed size is always present when compression is completed using single-pass functions,
- * such as ZSTD_compress(), ZSTD_compressCCtx() ZSTD_compress_usingDict() or ZSTD_compress_usingCDict().
- * note 4 : decompressed size can be very large (64-bits value),
- * potentially larger than what local system can handle as a single memory segment.
- * In which case, it's necessary to use streaming mode to decompress data.
- * note 5 : If source is untrusted, decompressed size could be wrong or intentionally modified.
- * Always ensure return value fits within application's authorized limits.
- * Each application can set its own limits.
- * note 6 : This function replaces ZSTD_getDecompressedSize() */
-#define ZSTD_CONTENTSIZE_UNKNOWN (0ULL - 1)
-#define ZSTD_CONTENTSIZE_ERROR (0ULL - 2)
-ZSTDLIB_API unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize);
-
-/*! ZSTD_getDecompressedSize() :
- * NOTE: This function is now obsolete, in favor of ZSTD_getFrameContentSize().
- * Both functions work the same way, but ZSTD_getDecompressedSize() blends
- * "empty", "unknown" and "error" results to the same return value (0),
- * while ZSTD_getFrameContentSize() gives them separate return values.
- * @return : decompressed size of `src` frame content _if known and not empty_, 0 otherwise. */
-ZSTDLIB_API unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize);
-
-/*! ZSTD_findFrameCompressedSize() :
- * `src` should point to the start of a ZSTD frame or skippable frame.
- * `srcSize` must be >= first frame size
- * @return : the compressed size of the first frame starting at `src`,
- * suitable to pass as `srcSize` to `ZSTD_decompress` or similar,
- * or an error code if input is invalid */
-ZSTDLIB_API size_t ZSTD_findFrameCompressedSize(const void* src, size_t srcSize);
-
-
-/*====== Helper functions ======*/
-#define ZSTD_COMPRESSBOUND(srcSize) ((srcSize) + ((srcSize)>>8) + (((srcSize) < (128<<10)) ? (((128<<10) - (srcSize)) >> 11) /* margin, from 64 to 0 */ : 0)) /* this formula ensures that bound(A) + bound(B) <= bound(A+B) as long as A and B >= 128 KB */
-ZSTDLIB_API size_t ZSTD_compressBound(size_t srcSize); /*!< maximum compressed size in worst case single-pass scenario */
-ZSTDLIB_API unsigned ZSTD_isError(size_t code); /*!< tells if a `size_t` function result is an error code */
-ZSTDLIB_API const char* ZSTD_getErrorName(size_t code); /*!< provides readable string from an error code */
-ZSTDLIB_API int ZSTD_minCLevel(void); /*!< minimum negative compression level allowed */
-ZSTDLIB_API int ZSTD_maxCLevel(void); /*!< maximum compression level available */
-
-
-/***************************************
-* Explicit context
-***************************************/
-/*= Compression context
- * When compressing many times,
- * it is recommended to allocate a context just once,
- * and re-use it for each successive compression operation.
- * This will make workload friendlier for system's memory.
- * Note : re-using context is just a speed / resource optimization.
- * It doesn't change the compression ratio, which remains identical.
- * Note 2 : In multi-threaded environments,
- * use one different context per thread for parallel execution.
- */
-typedef struct ZSTD_CCtx_s ZSTD_CCtx;
-ZSTDLIB_API ZSTD_CCtx* ZSTD_createCCtx(void);
-ZSTDLIB_API size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx);
-
-/*! ZSTD_compressCCtx() :
- * Same as ZSTD_compress(), using an explicit ZSTD_CCtx.
- * Important : in order to behave similarly to `ZSTD_compress()`,
- * this function compresses at requested compression level,
- * __ignoring any other parameter__ .
- * If any advanced parameter was set using the advanced API,
- * they will all be reset. Only `compressionLevel` remains.
- */
-ZSTDLIB_API size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- int compressionLevel);
-
-/*= Decompression context
- * When decompressing many times,
- * it is recommended to allocate a context only once,
- * and re-use it for each successive compression operation.
- * This will make workload friendlier for system's memory.
- * Use one context per thread for parallel execution. */
-typedef struct ZSTD_DCtx_s ZSTD_DCtx;
-ZSTDLIB_API ZSTD_DCtx* ZSTD_createDCtx(void);
-ZSTDLIB_API size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx);
-
-/*! ZSTD_decompressDCtx() :
- * Same as ZSTD_decompress(),
- * requires an allocated ZSTD_DCtx.
- * Compatible with sticky parameters.
- */
-ZSTDLIB_API size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize);
-
-
-/***************************************
-* Advanced compression API
-***************************************/
-
-/* API design :
- * Parameters are pushed one by one into an existing context,
- * using ZSTD_CCtx_set*() functions.
- * Pushed parameters are sticky : they are valid for next compressed frame, and any subsequent frame.
- * "sticky" parameters are applicable to `ZSTD_compress2()` and `ZSTD_compressStream*()` !
- * __They do not apply to "simple" one-shot variants such as ZSTD_compressCCtx()__ .
- *
- * It's possible to reset all parameters to "default" using ZSTD_CCtx_reset().
- *
- * This API supercedes all other "advanced" API entry points in the experimental section.
- * In the future, we expect to remove from experimental API entry points which are redundant with this API.
- */
-
-
-/* Compression strategies, listed from fastest to strongest */
-typedef enum { ZSTD_fast=1,
- ZSTD_dfast=2,
- ZSTD_greedy=3,
- ZSTD_lazy=4,
- ZSTD_lazy2=5,
- ZSTD_btlazy2=6,
- ZSTD_btopt=7,
- ZSTD_btultra=8,
- ZSTD_btultra2=9
- /* note : new strategies _might_ be added in the future.
- Only the order (from fast to strong) is guaranteed */
-} ZSTD_strategy;
-
-
-typedef enum {
-
- /* compression parameters
- * Note: When compressing with a ZSTD_CDict these parameters are superseded
- * by the parameters used to construct the ZSTD_CDict.
- * See ZSTD_CCtx_refCDict() for more info (superseded-by-cdict). */
- ZSTD_c_compressionLevel=100, /* Set compression parameters according to pre-defined cLevel table.
- * Note that exact compression parameters are dynamically determined,
- * depending on both compression level and srcSize (when known).
- * Default level is ZSTD_CLEVEL_DEFAULT==3.
- * Special: value 0 means default, which is controlled by ZSTD_CLEVEL_DEFAULT.
- * Note 1 : it's possible to pass a negative compression level.
- * Note 2 : setting a level does not automatically set all other compression parameters
- * to default. Setting this will however eventually dynamically impact the compression
- * parameters which have not been manually set. The manually set
- * ones will 'stick'. */
- /* Advanced compression parameters :
- * It's possible to pin down compression parameters to some specific values.
- * In which case, these values are no longer dynamically selected by the compressor */
- ZSTD_c_windowLog=101, /* Maximum allowed back-reference distance, expressed as power of 2.
- * This will set a memory budget for streaming decompression,
- * with larger values requiring more memory
- * and typically compressing more.
- * Must be clamped between ZSTD_WINDOWLOG_MIN and ZSTD_WINDOWLOG_MAX.
- * Special: value 0 means "use default windowLog".
- * Note: Using a windowLog greater than ZSTD_WINDOWLOG_LIMIT_DEFAULT
- * requires explicitly allowing such size at streaming decompression stage. */
- ZSTD_c_hashLog=102, /* Size of the initial probe table, as a power of 2.
- * Resulting memory usage is (1 << (hashLog+2)).
- * Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX.
- * Larger tables improve compression ratio of strategies <= dFast,
- * and improve speed of strategies > dFast.
- * Special: value 0 means "use default hashLog". */
- ZSTD_c_chainLog=103, /* Size of the multi-probe search table, as a power of 2.
- * Resulting memory usage is (1 << (chainLog+2)).
- * Must be clamped between ZSTD_CHAINLOG_MIN and ZSTD_CHAINLOG_MAX.
- * Larger tables result in better and slower compression.
- * This parameter is useless for "fast" strategy.
- * It's still useful when using "dfast" strategy,
- * in which case it defines a secondary probe table.
- * Special: value 0 means "use default chainLog". */
- ZSTD_c_searchLog=104, /* Number of search attempts, as a power of 2.
- * More attempts result in better and slower compression.
- * This parameter is useless for "fast" and "dFast" strategies.
- * Special: value 0 means "use default searchLog". */
- ZSTD_c_minMatch=105, /* Minimum size of searched matches.
- * Note that Zstandard can still find matches of smaller size,
- * it just tweaks its search algorithm to look for this size and larger.
- * Larger values increase compression and decompression speed, but decrease ratio.
- * Must be clamped between ZSTD_MINMATCH_MIN and ZSTD_MINMATCH_MAX.
- * Note that currently, for all strategies < btopt, effective minimum is 4.
- * , for all strategies > fast, effective maximum is 6.
- * Special: value 0 means "use default minMatchLength". */
- ZSTD_c_targetLength=106, /* Impact of this field depends on strategy.
- * For strategies btopt, btultra & btultra2:
- * Length of Match considered "good enough" to stop search.
- * Larger values make compression stronger, and slower.
- * For strategy fast:
- * Distance between match sampling.
- * Larger values make compression faster, and weaker.
- * Special: value 0 means "use default targetLength". */
- ZSTD_c_strategy=107, /* See ZSTD_strategy enum definition.
- * The higher the value of selected strategy, the more complex it is,
- * resulting in stronger and slower compression.
- * Special: value 0 means "use default strategy". */
-
- /* LDM mode parameters */
- ZSTD_c_enableLongDistanceMatching=160, /* Enable long distance matching.
- * This parameter is designed to improve compression ratio
- * for large inputs, by finding large matches at long distance.
- * It increases memory usage and window size.
- * Note: enabling this parameter increases default ZSTD_c_windowLog to 128 MB
- * except when expressly set to a different value. */
- ZSTD_c_ldmHashLog=161, /* Size of the table for long distance matching, as a power of 2.
- * Larger values increase memory usage and compression ratio,
- * but decrease compression speed.
- * Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX
- * default: windowlog - 7.
- * Special: value 0 means "automatically determine hashlog". */
- ZSTD_c_ldmMinMatch=162, /* Minimum match size for long distance matcher.
- * Larger/too small values usually decrease compression ratio.
- * Must be clamped between ZSTD_LDM_MINMATCH_MIN and ZSTD_LDM_MINMATCH_MAX.
- * Special: value 0 means "use default value" (default: 64). */
- ZSTD_c_ldmBucketSizeLog=163, /* Log size of each bucket in the LDM hash table for collision resolution.
- * Larger values improve collision resolution but decrease compression speed.
- * The maximum value is ZSTD_LDM_BUCKETSIZELOG_MAX.
- * Special: value 0 means "use default value" (default: 3). */
- ZSTD_c_ldmHashRateLog=164, /* Frequency of inserting/looking up entries into the LDM hash table.
- * Must be clamped between 0 and (ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN).
- * Default is MAX(0, (windowLog - ldmHashLog)), optimizing hash table usage.
- * Larger values improve compression speed.
- * Deviating far from default value will likely result in a compression ratio decrease.
- * Special: value 0 means "automatically determine hashRateLog". */
-
- /* frame parameters */
- ZSTD_c_contentSizeFlag=200, /* Content size will be written into frame header _whenever known_ (default:1)
- * Content size must be known at the beginning of compression.
- * This is automatically the case when using ZSTD_compress2(),
- * For streaming scenarios, content size must be provided with ZSTD_CCtx_setPledgedSrcSize() */
- ZSTD_c_checksumFlag=201, /* A 32-bits checksum of content is written at end of frame (default:0) */
- ZSTD_c_dictIDFlag=202, /* When applicable, dictionary's ID is written into frame header (default:1) */
-
- /* multi-threading parameters */
- /* These parameters are only useful if multi-threading is enabled (compiled with build macro ZSTD_MULTITHREAD).
- * They return an error otherwise. */
- ZSTD_c_nbWorkers=400, /* Select how many threads will be spawned to compress in parallel.
- * When nbWorkers >= 1, triggers asynchronous mode when used with ZSTD_compressStream*() :
- * ZSTD_compressStream*() consumes input and flush output if possible, but immediately gives back control to caller,
- * while compression work is performed in parallel, within worker threads.
- * (note : a strong exception to this rule is when first invocation of ZSTD_compressStream2() sets ZSTD_e_end :
- * in which case, ZSTD_compressStream2() delegates to ZSTD_compress2(), which is always a blocking call).
- * More workers improve speed, but also increase memory usage.
- * Default value is `0`, aka "single-threaded mode" : no worker is spawned, compression is performed inside Caller's thread, all invocations are blocking */
- ZSTD_c_jobSize=401, /* Size of a compression job. This value is enforced only when nbWorkers >= 1.
- * Each compression job is completed in parallel, so this value can indirectly impact the nb of active threads.
- * 0 means default, which is dynamically determined based on compression parameters.
- * Job size must be a minimum of overlap size, or 1 MB, whichever is largest.
- * The minimum size is automatically and transparently enforced. */
- ZSTD_c_overlapLog=402, /* Control the overlap size, as a fraction of window size.
- * The overlap size is an amount of data reloaded from previous job at the beginning of a new job.
- * It helps preserve compression ratio, while each job is compressed in parallel.
- * This value is enforced only when nbWorkers >= 1.
- * Larger values increase compression ratio, but decrease speed.
- * Possible values range from 0 to 9 :
- * - 0 means "default" : value will be determined by the library, depending on strategy
- * - 1 means "no overlap"
- * - 9 means "full overlap", using a full window size.
- * Each intermediate rank increases/decreases load size by a factor 2 :
- * 9: full window; 8: w/2; 7: w/4; 6: w/8; 5:w/16; 4: w/32; 3:w/64; 2:w/128; 1:no overlap; 0:default
- * default value varies between 6 and 9, depending on strategy */
-
- /* note : additional experimental parameters are also available
- * within the experimental section of the API.
- * At the time of this writing, they include :
- * ZSTD_c_rsyncable
- * ZSTD_c_format
- * ZSTD_c_forceMaxWindow
- * ZSTD_c_forceAttachDict
- * ZSTD_c_literalCompressionMode
- * ZSTD_c_targetCBlockSize
- * ZSTD_c_srcSizeHint
- * Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them.
- * note : never ever use experimentalParam? names directly;
- * also, the enums values themselves are unstable and can still change.
- */
- ZSTD_c_experimentalParam1=500,
- ZSTD_c_experimentalParam2=10,
- ZSTD_c_experimentalParam3=1000,
- ZSTD_c_experimentalParam4=1001,
- ZSTD_c_experimentalParam5=1002,
- ZSTD_c_experimentalParam6=1003,
- ZSTD_c_experimentalParam7=1004
-} ZSTD_cParameter;
-
-typedef struct {
- size_t error;
- int lowerBound;
- int upperBound;
-} ZSTD_bounds;
-
-/*! ZSTD_cParam_getBounds() :
- * All parameters must belong to an interval with lower and upper bounds,
- * otherwise they will either trigger an error or be automatically clamped.
- * @return : a structure, ZSTD_bounds, which contains
- * - an error status field, which must be tested using ZSTD_isError()
- * - lower and upper bounds, both inclusive
- */
-ZSTDLIB_API ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter cParam);
-
-/*! ZSTD_CCtx_setParameter() :
- * Set one compression parameter, selected by enum ZSTD_cParameter.
- * All parameters have valid bounds. Bounds can be queried using ZSTD_cParam_getBounds().
- * Providing a value beyond bound will either clamp it, or trigger an error (depending on parameter).
- * Setting a parameter is generally only possible during frame initialization (before starting compression).
- * Exception : when using multi-threading mode (nbWorkers >= 1),
- * the following parameters can be updated _during_ compression (within same frame):
- * => compressionLevel, hashLog, chainLog, searchLog, minMatch, targetLength and strategy.
- * new parameters will be active for next job only (after a flush()).
- * @return : an error code (which can be tested using ZSTD_isError()).
- */
-ZSTDLIB_API size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value);
-
-/*! ZSTD_CCtx_setPledgedSrcSize() :
- * Total input data size to be compressed as a single frame.
- * Value will be written in frame header, unless if explicitly forbidden using ZSTD_c_contentSizeFlag.
- * This value will also be controlled at end of frame, and trigger an error if not respected.
- * @result : 0, or an error code (which can be tested with ZSTD_isError()).
- * Note 1 : pledgedSrcSize==0 actually means zero, aka an empty frame.
- * In order to mean "unknown content size", pass constant ZSTD_CONTENTSIZE_UNKNOWN.
- * ZSTD_CONTENTSIZE_UNKNOWN is default value for any new frame.
- * Note 2 : pledgedSrcSize is only valid once, for the next frame.
- * It's discarded at the end of the frame, and replaced by ZSTD_CONTENTSIZE_UNKNOWN.
- * Note 3 : Whenever all input data is provided and consumed in a single round,
- * for example with ZSTD_compress2(),
- * or invoking immediately ZSTD_compressStream2(,,,ZSTD_e_end),
- * this value is automatically overridden by srcSize instead.
- */
-ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize);
-
-typedef enum {
- ZSTD_reset_session_only = 1,
- ZSTD_reset_parameters = 2,
- ZSTD_reset_session_and_parameters = 3
-} ZSTD_ResetDirective;
-
-/*! ZSTD_CCtx_reset() :
- * There are 2 different things that can be reset, independently or jointly :
- * - The session : will stop compressing current frame, and make CCtx ready to start a new one.
- * Useful after an error, or to interrupt any ongoing compression.
- * Any internal data not yet flushed is cancelled.
- * Compression parameters and dictionary remain unchanged.
- * They will be used to compress next frame.
- * Resetting session never fails.
- * - The parameters : changes all parameters back to "default".
- * This removes any reference to any dictionary too.
- * Parameters can only be changed between 2 sessions (i.e. no compression is currently ongoing)
- * otherwise the reset fails, and function returns an error value (which can be tested using ZSTD_isError())
- * - Both : similar to resetting the session, followed by resetting parameters.
- */
-ZSTDLIB_API size_t ZSTD_CCtx_reset(ZSTD_CCtx* cctx, ZSTD_ResetDirective reset);
-
-/*! ZSTD_compress2() :
- * Behave the same as ZSTD_compressCCtx(), but compression parameters are set using the advanced API.
- * ZSTD_compress2() always starts a new frame.
- * Should cctx hold data from a previously unfinished frame, everything about it is forgotten.
- * - Compression parameters are pushed into CCtx before starting compression, using ZSTD_CCtx_set*()
- * - The function is always blocking, returns when compression is completed.
- * Hint : compression runs faster if `dstCapacity` >= `ZSTD_compressBound(srcSize)`.
- * @return : compressed size written into `dst` (<= `dstCapacity),
- * or an error code if it fails (which can be tested using ZSTD_isError()).
- */
-ZSTDLIB_API size_t ZSTD_compress2( ZSTD_CCtx* cctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize);
-
-
-/***************************************
-* Advanced decompression API
-***************************************/
-
-/* The advanced API pushes parameters one by one into an existing DCtx context.
- * Parameters are sticky, and remain valid for all following frames
- * using the same DCtx context.
- * It's possible to reset parameters to default values using ZSTD_DCtx_reset().
- * Note : This API is compatible with existing ZSTD_decompressDCtx() and ZSTD_decompressStream().
- * Therefore, no new decompression function is necessary.
- */
-
-typedef enum {
-
- ZSTD_d_windowLogMax=100, /* Select a size limit (in power of 2) beyond which
- * the streaming API will refuse to allocate memory buffer
- * in order to protect the host from unreasonable memory requirements.
- * This parameter is only useful in streaming mode, since no internal buffer is allocated in single-pass mode.
- * By default, a decompression context accepts window sizes <= (1 << ZSTD_WINDOWLOG_LIMIT_DEFAULT).
- * Special: value 0 means "use default maximum windowLog". */
-
- /* note : additional experimental parameters are also available
- * within the experimental section of the API.
- * At the time of this writing, they include :
- * ZSTD_d_format
- * ZSTD_d_stableOutBuffer
- * Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them.
- * note : never ever use experimentalParam? names directly
- */
- ZSTD_d_experimentalParam1=1000,
- ZSTD_d_experimentalParam2=1001
-
-} ZSTD_dParameter;
-
-/*! ZSTD_dParam_getBounds() :
- * All parameters must belong to an interval with lower and upper bounds,
- * otherwise they will either trigger an error or be automatically clamped.
- * @return : a structure, ZSTD_bounds, which contains
- * - an error status field, which must be tested using ZSTD_isError()
- * - both lower and upper bounds, inclusive
- */
-ZSTDLIB_API ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam);
-
-/*! ZSTD_DCtx_setParameter() :
- * Set one compression parameter, selected by enum ZSTD_dParameter.
- * All parameters have valid bounds. Bounds can be queried using ZSTD_dParam_getBounds().
- * Providing a value beyond bound will either clamp it, or trigger an error (depending on parameter).
- * Setting a parameter is only possible during frame initialization (before starting decompression).
- * @return : 0, or an error code (which can be tested using ZSTD_isError()).
- */
-ZSTDLIB_API size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param, int value);
-
-/*! ZSTD_DCtx_reset() :
- * Return a DCtx to clean state.
- * Session and parameters can be reset jointly or separately.
- * Parameters can only be reset when no active frame is being decompressed.
- * @return : 0, or an error code, which can be tested with ZSTD_isError()
- */
-ZSTDLIB_API size_t ZSTD_DCtx_reset(ZSTD_DCtx* dctx, ZSTD_ResetDirective reset);
-
-
-/****************************
-* Streaming
-****************************/
-
-typedef struct ZSTD_inBuffer_s {
- const void* src; /**< start of input buffer */
- size_t size; /**< size of input buffer */
- size_t pos; /**< position where reading stopped. Will be updated. Necessarily 0 <= pos <= size */
-} ZSTD_inBuffer;
-
-typedef struct ZSTD_outBuffer_s {
- void* dst; /**< start of output buffer */
- size_t size; /**< size of output buffer */
- size_t pos; /**< position where writing stopped. Will be updated. Necessarily 0 <= pos <= size */
-} ZSTD_outBuffer;
-
-
-
-/*-***********************************************************************
-* Streaming compression - HowTo
-*
-* A ZSTD_CStream object is required to track streaming operation.
-* Use ZSTD_createCStream() and ZSTD_freeCStream() to create/release resources.
-* ZSTD_CStream objects can be reused multiple times on consecutive compression operations.
-* It is recommended to re-use ZSTD_CStream since it will play nicer with system's memory, by re-using already allocated memory.
-*
-* For parallel execution, use one separate ZSTD_CStream per thread.
-*
-* note : since v1.3.0, ZSTD_CStream and ZSTD_CCtx are the same thing.
-*
-* Parameters are sticky : when starting a new compression on the same context,
-* it will re-use the same sticky parameters as previous compression session.
-* When in doubt, it's recommended to fully initialize the context before usage.
-* Use ZSTD_CCtx_reset() to reset the context and ZSTD_CCtx_setParameter(),
-* ZSTD_CCtx_setPledgedSrcSize(), or ZSTD_CCtx_loadDictionary() and friends to
-* set more specific parameters, the pledged source size, or load a dictionary.
-*
-* Use ZSTD_compressStream2() with ZSTD_e_continue as many times as necessary to
-* consume input stream. The function will automatically update both `pos`
-* fields within `input` and `output`.
-* Note that the function may not consume the entire input, for example, because
-* the output buffer is already full, in which case `input.pos < input.size`.
-* The caller must check if input has been entirely consumed.
-* If not, the caller must make some room to receive more compressed data,
-* and then present again remaining input data.
-* note: ZSTD_e_continue is guaranteed to make some forward progress when called,
-* but doesn't guarantee maximal forward progress. This is especially relevant
-* when compressing with multiple threads. The call won't block if it can
-* consume some input, but if it can't it will wait for some, but not all,
-* output to be flushed.
-* @return : provides a minimum amount of data remaining to be flushed from internal buffers
-* or an error code, which can be tested using ZSTD_isError().
-*
-* At any moment, it's possible to flush whatever data might remain stuck within internal buffer,
-* using ZSTD_compressStream2() with ZSTD_e_flush. `output->pos` will be updated.
-* Note that, if `output->size` is too small, a single invocation with ZSTD_e_flush might not be enough (return code > 0).
-* In which case, make some room to receive more compressed data, and call again ZSTD_compressStream2() with ZSTD_e_flush.
-* You must continue calling ZSTD_compressStream2() with ZSTD_e_flush until it returns 0, at which point you can change the
-* operation.
-* note: ZSTD_e_flush will flush as much output as possible, meaning when compressing with multiple threads, it will
-* block until the flush is complete or the output buffer is full.
-* @return : 0 if internal buffers are entirely flushed,
-* >0 if some data still present within internal buffer (the value is minimal estimation of remaining size),
-* or an error code, which can be tested using ZSTD_isError().
-*
-* Calling ZSTD_compressStream2() with ZSTD_e_end instructs to finish a frame.
-* It will perform a flush and write frame epilogue.
-* The epilogue is required for decoders to consider a frame completed.
-* flush operation is the same, and follows same rules as calling ZSTD_compressStream2() with ZSTD_e_flush.
-* You must continue calling ZSTD_compressStream2() with ZSTD_e_end until it returns 0, at which point you are free to
-* start a new frame.
-* note: ZSTD_e_end will flush as much output as possible, meaning when compressing with multiple threads, it will
-* block until the flush is complete or the output buffer is full.
-* @return : 0 if frame fully completed and fully flushed,
-* >0 if some data still present within internal buffer (the value is minimal estimation of remaining size),
-* or an error code, which can be tested using ZSTD_isError().
-*
-* *******************************************************************/
-
-typedef ZSTD_CCtx ZSTD_CStream; /**< CCtx and CStream are now effectively same object (>= v1.3.0) */
- /* Continue to distinguish them for compatibility with older versions <= v1.2.0 */
-/*===== ZSTD_CStream management functions =====*/
-ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream(void);
-ZSTDLIB_API size_t ZSTD_freeCStream(ZSTD_CStream* zcs);
-
-/*===== Streaming compression functions =====*/
-typedef enum {
- ZSTD_e_continue=0, /* collect more data, encoder decides when to output compressed result, for optimal compression ratio */
- ZSTD_e_flush=1, /* flush any data provided so far,
- * it creates (at least) one new block, that can be decoded immediately on reception;
- * frame will continue: any future data can still reference previously compressed data, improving compression.
- * note : multithreaded compression will block to flush as much output as possible. */
- ZSTD_e_end=2 /* flush any remaining data _and_ close current frame.
- * note that frame is only closed after compressed data is fully flushed (return value == 0).
- * After that point, any additional data starts a new frame.
- * note : each frame is independent (does not reference any content from previous frame).
- : note : multithreaded compression will block to flush as much output as possible. */
-} ZSTD_EndDirective;
-
-/*! ZSTD_compressStream2() :
- * Behaves about the same as ZSTD_compressStream, with additional control on end directive.
- * - Compression parameters are pushed into CCtx before starting compression, using ZSTD_CCtx_set*()
- * - Compression parameters cannot be changed once compression is started (save a list of exceptions in multi-threading mode)
- * - output->pos must be <= dstCapacity, input->pos must be <= srcSize
- * - output->pos and input->pos will be updated. They are guaranteed to remain below their respective limit.
- * - When nbWorkers==0 (default), function is blocking : it completes its job before returning to caller.
- * - When nbWorkers>=1, function is non-blocking : it just acquires a copy of input, and distributes jobs to internal worker threads, flush whatever is available,
- * and then immediately returns, just indicating that there is some data remaining to be flushed.
- * The function nonetheless guarantees forward progress : it will return only after it reads or write at least 1+ byte.
- * - Exception : if the first call requests a ZSTD_e_end directive and provides enough dstCapacity, the function delegates to ZSTD_compress2() which is always blocking.
- * - @return provides a minimum amount of data remaining to be flushed from internal buffers
- * or an error code, which can be tested using ZSTD_isError().
- * if @return != 0, flush is not fully completed, there is still some data left within internal buffers.
- * This is useful for ZSTD_e_flush, since in this case more flushes are necessary to empty all buffers.
- * For ZSTD_e_end, @return == 0 when internal buffers are fully flushed and frame is completed.
- * - after a ZSTD_e_end directive, if internal buffer is not fully flushed (@return != 0),
- * only ZSTD_e_end or ZSTD_e_flush operations are allowed.
- * Before starting a new compression job, or changing compression parameters,
- * it is required to fully flush internal buffers.
- */
-ZSTDLIB_API size_t ZSTD_compressStream2( ZSTD_CCtx* cctx,
- ZSTD_outBuffer* output,
- ZSTD_inBuffer* input,
- ZSTD_EndDirective endOp);
-
-
-/* These buffer sizes are softly recommended.
- * They are not required : ZSTD_compressStream*() happily accepts any buffer size, for both input and output.
- * Respecting the recommended size just makes it a bit easier for ZSTD_compressStream*(),
- * reducing the amount of memory shuffling and buffering, resulting in minor performance savings.
- *
- * However, note that these recommendations are from the perspective of a C caller program.
- * If the streaming interface is invoked from some other language,
- * especially managed ones such as Java or Go, through a foreign function interface such as jni or cgo,
- * a major performance rule is to reduce crossing such interface to an absolute minimum.
- * It's not rare that performance ends being spent more into the interface, rather than compression itself.
- * In which cases, prefer using large buffers, as large as practical,
- * for both input and output, to reduce the nb of roundtrips.
- */
-ZSTDLIB_API size_t ZSTD_CStreamInSize(void); /**< recommended size for input buffer */
-ZSTDLIB_API size_t ZSTD_CStreamOutSize(void); /**< recommended size for output buffer. Guarantee to successfully flush at least one complete compressed block. */
-
-
-/* *****************************************************************************
- * This following is a legacy streaming API.
- * It can be replaced by ZSTD_CCtx_reset() and ZSTD_compressStream2().
- * It is redundant, but remains fully supported.
- * Advanced parameters and dictionary compression can only be used through the
- * new API.
- ******************************************************************************/
-
-/*!
- * Equivalent to:
- *
- * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
- * ZSTD_CCtx_refCDict(zcs, NULL); // clear the dictionary (if any)
- * ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel);
- */
-ZSTDLIB_API size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel);
-/*!
- * Alternative for ZSTD_compressStream2(zcs, output, input, ZSTD_e_continue).
- * NOTE: The return value is different. ZSTD_compressStream() returns a hint for
- * the next read size (if non-zero and not an error). ZSTD_compressStream2()
- * returns the minimum nb of bytes left to flush (if non-zero and not an error).
- */
-ZSTDLIB_API size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input);
-/*! Equivalent to ZSTD_compressStream2(zcs, output, &emptyInput, ZSTD_e_flush). */
-ZSTDLIB_API size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output);
-/*! Equivalent to ZSTD_compressStream2(zcs, output, &emptyInput, ZSTD_e_end). */
-ZSTDLIB_API size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output);
-
-
-/*-***************************************************************************
-* Streaming decompression - HowTo
-*
-* A ZSTD_DStream object is required to track streaming operations.
-* Use ZSTD_createDStream() and ZSTD_freeDStream() to create/release resources.
-* ZSTD_DStream objects can be re-used multiple times.
-*
-* Use ZSTD_initDStream() to start a new decompression operation.
-* @return : recommended first input size
-* Alternatively, use advanced API to set specific properties.
-*
-* Use ZSTD_decompressStream() repetitively to consume your input.
-* The function will update both `pos` fields.
-* If `input.pos < input.size`, some input has not been consumed.
-* It's up to the caller to present again remaining data.
-* The function tries to flush all data decoded immediately, respecting output buffer size.
-* If `output.pos < output.size`, decoder has flushed everything it could.
-* But if `output.pos == output.size`, there might be some data left within internal buffers.,
-* In which case, call ZSTD_decompressStream() again to flush whatever remains in the buffer.
-* Note : with no additional input provided, amount of data flushed is necessarily <= ZSTD_BLOCKSIZE_MAX.
-* @return : 0 when a frame is completely decoded and fully flushed,
-* or an error code, which can be tested using ZSTD_isError(),
-* or any other value > 0, which means there is still some decoding or flushing to do to complete current frame :
-* the return value is a suggested next input size (just a hint for better latency)
-* that will never request more than the remaining frame size.
-* *******************************************************************************/
-
-typedef ZSTD_DCtx ZSTD_DStream; /**< DCtx and DStream are now effectively same object (>= v1.3.0) */
- /* For compatibility with versions <= v1.2.0, prefer differentiating them. */
-/*===== ZSTD_DStream management functions =====*/
-ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream(void);
-ZSTDLIB_API size_t ZSTD_freeDStream(ZSTD_DStream* zds);
-
-/*===== Streaming decompression functions =====*/
-
-/* This function is redundant with the advanced API and equivalent to:
- *
- * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only);
- * ZSTD_DCtx_refDDict(zds, NULL);
- */
-ZSTDLIB_API size_t ZSTD_initDStream(ZSTD_DStream* zds);
-
-ZSTDLIB_API size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inBuffer* input);
-
-ZSTDLIB_API size_t ZSTD_DStreamInSize(void); /*!< recommended size for input buffer */
-ZSTDLIB_API size_t ZSTD_DStreamOutSize(void); /*!< recommended size for output buffer. Guarantee to successfully flush at least one complete block in all circumstances. */
-
-
-/**************************
-* Simple dictionary API
-***************************/
-/*! ZSTD_compress_usingDict() :
- * Compression at an explicit compression level using a Dictionary.
- * A dictionary can be any arbitrary data segment (also called a prefix),
- * or a buffer with specified information (see dictBuilder/zdict.h).
- * Note : This function loads the dictionary, resulting in significant startup delay.
- * It's intended for a dictionary used only once.
- * Note 2 : When `dict == NULL || dictSize < 8` no dictionary is used. */
-ZSTDLIB_API size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- const void* dict,size_t dictSize,
- int compressionLevel);
-
-/*! ZSTD_decompress_usingDict() :
- * Decompression using a known Dictionary.
- * Dictionary must be identical to the one used during compression.
- * Note : This function loads the dictionary, resulting in significant startup delay.
- * It's intended for a dictionary used only once.
- * Note : When `dict == NULL || dictSize < 8` no dictionary is used. */
-ZSTDLIB_API size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- const void* dict,size_t dictSize);
-
-
-/***********************************
- * Bulk processing dictionary API
- **********************************/
-typedef struct ZSTD_CDict_s ZSTD_CDict;
-
-/*! ZSTD_createCDict() :
- * When compressing multiple messages or blocks using the same dictionary,
- * it's recommended to digest the dictionary only once, since it's a costly operation.
- * ZSTD_createCDict() will create a state from digesting a dictionary.
- * The resulting state can be used for future compression operations with very limited startup cost.
- * ZSTD_CDict can be created once and shared by multiple threads concurrently, since its usage is read-only.
- * @dictBuffer can be released after ZSTD_CDict creation, because its content is copied within CDict.
- * Note 1 : Consider experimental function `ZSTD_createCDict_byReference()` if you prefer to not duplicate @dictBuffer content.
- * Note 2 : A ZSTD_CDict can be created from an empty @dictBuffer,
- * in which case the only thing that it transports is the @compressionLevel.
- * This can be useful in a pipeline featuring ZSTD_compress_usingCDict() exclusively,
- * expecting a ZSTD_CDict parameter with any data, including those without a known dictionary. */
-ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict(const void* dictBuffer, size_t dictSize,
- int compressionLevel);
-
-/*! ZSTD_freeCDict() :
- * Function frees memory allocated by ZSTD_createCDict(). */
-ZSTDLIB_API size_t ZSTD_freeCDict(ZSTD_CDict* CDict);
-
-/*! ZSTD_compress_usingCDict() :
- * Compression using a digested Dictionary.
- * Recommended when same dictionary is used multiple times.
- * Note : compression level is _decided at dictionary creation time_,
- * and frame parameters are hardcoded (dictID=yes, contentSize=yes, checksum=no) */
-ZSTDLIB_API size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- const ZSTD_CDict* cdict);
-
-
-typedef struct ZSTD_DDict_s ZSTD_DDict;
-
-/*! ZSTD_createDDict() :
- * Create a digested dictionary, ready to start decompression operation without startup delay.
- * dictBuffer can be released after DDict creation, as its content is copied inside DDict. */
-ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict(const void* dictBuffer, size_t dictSize);
-
-/*! ZSTD_freeDDict() :
- * Function frees memory allocated with ZSTD_createDDict() */
-ZSTDLIB_API size_t ZSTD_freeDDict(ZSTD_DDict* ddict);
-
-/*! ZSTD_decompress_usingDDict() :
- * Decompression using a digested Dictionary.
- * Recommended when same dictionary is used multiple times. */
-ZSTDLIB_API size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- const ZSTD_DDict* ddict);
-
-
-/********************************
- * Dictionary helper functions
- *******************************/
-
-/*! ZSTD_getDictID_fromDict() :
- * Provides the dictID stored within dictionary.
- * if @return == 0, the dictionary is not conformant with Zstandard specification.
- * It can still be loaded, but as a content-only dictionary. */
-ZSTDLIB_API unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize);
-
-/*! ZSTD_getDictID_fromDDict() :
- * Provides the dictID of the dictionary loaded into `ddict`.
- * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty.
- * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */
-ZSTDLIB_API unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict);
-
-/*! ZSTD_getDictID_fromFrame() :
- * Provides the dictID required to decompressed the frame stored within `src`.
- * If @return == 0, the dictID could not be decoded.
- * This could for one of the following reasons :
- * - The frame does not require a dictionary to be decoded (most common case).
- * - The frame was built with dictID intentionally removed. Whatever dictionary is necessary is a hidden information.
- * Note : this use case also happens when using a non-conformant dictionary.
- * - `srcSize` is too small, and as a result, the frame header could not be decoded (only possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`).
- * - This is not a Zstandard frame.
- * When identifying the exact failure cause, it's possible to use ZSTD_getFrameHeader(), which will provide a more precise error code. */
-ZSTDLIB_API unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize);
-
-
-/*******************************************************************************
- * Advanced dictionary and prefix API
- *
- * This API allows dictionaries to be used with ZSTD_compress2(),
- * ZSTD_compressStream2(), and ZSTD_decompress(). Dictionaries are sticky, and
- * only reset with the context is reset with ZSTD_reset_parameters or
- * ZSTD_reset_session_and_parameters. Prefixes are single-use.
- ******************************************************************************/
-
-
-/*! ZSTD_CCtx_loadDictionary() :
- * Create an internal CDict from `dict` buffer.
- * Decompression will have to use same dictionary.
- * @result : 0, or an error code (which can be tested with ZSTD_isError()).
- * Special: Loading a NULL (or 0-size) dictionary invalidates previous dictionary,
- * meaning "return to no-dictionary mode".
- * Note 1 : Dictionary is sticky, it will be used for all future compressed frames.
- * To return to "no-dictionary" situation, load a NULL dictionary (or reset parameters).
- * Note 2 : Loading a dictionary involves building tables.
- * It's also a CPU consuming operation, with non-negligible impact on latency.
- * Tables are dependent on compression parameters, and for this reason,
- * compression parameters can no longer be changed after loading a dictionary.
- * Note 3 :`dict` content will be copied internally.
- * Use experimental ZSTD_CCtx_loadDictionary_byReference() to reference content instead.
- * In such a case, dictionary buffer must outlive its users.
- * Note 4 : Use ZSTD_CCtx_loadDictionary_advanced()
- * to precisely select how dictionary content must be interpreted. */
-ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize);
-
-/*! ZSTD_CCtx_refCDict() :
- * Reference a prepared dictionary, to be used for all next compressed frames.
- * Note that compression parameters are enforced from within CDict,
- * and supersede any compression parameter previously set within CCtx.
- * The parameters ignored are labled as "superseded-by-cdict" in the ZSTD_cParameter enum docs.
- * The ignored parameters will be used again if the CCtx is returned to no-dictionary mode.
- * The dictionary will remain valid for future compressed frames using same CCtx.
- * @result : 0, or an error code (which can be tested with ZSTD_isError()).
- * Special : Referencing a NULL CDict means "return to no-dictionary mode".
- * Note 1 : Currently, only one dictionary can be managed.
- * Referencing a new dictionary effectively "discards" any previous one.
- * Note 2 : CDict is just referenced, its lifetime must outlive its usage within CCtx. */
-ZSTDLIB_API size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict);
-
-/*! ZSTD_CCtx_refPrefix() :
- * Reference a prefix (single-usage dictionary) for next compressed frame.
- * A prefix is **only used once**. Tables are discarded at end of frame (ZSTD_e_end).
- * Decompression will need same prefix to properly regenerate data.
- * Compressing with a prefix is similar in outcome as performing a diff and compressing it,
- * but performs much faster, especially during decompression (compression speed is tunable with compression level).
- * @result : 0, or an error code (which can be tested with ZSTD_isError()).
- * Special: Adding any prefix (including NULL) invalidates any previous prefix or dictionary
- * Note 1 : Prefix buffer is referenced. It **must** outlive compression.
- * Its content must remain unmodified during compression.
- * Note 2 : If the intention is to diff some large src data blob with some prior version of itself,
- * ensure that the window size is large enough to contain the entire source.
- * See ZSTD_c_windowLog.
- * Note 3 : Referencing a prefix involves building tables, which are dependent on compression parameters.
- * It's a CPU consuming operation, with non-negligible impact on latency.
- * If there is a need to use the same prefix multiple times, consider loadDictionary instead.
- * Note 4 : By default, the prefix is interpreted as raw content (ZSTD_dct_rawContent).
- * Use experimental ZSTD_CCtx_refPrefix_advanced() to alter dictionary interpretation. */
-ZSTDLIB_API size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx,
- const void* prefix, size_t prefixSize);
-
-/*! ZSTD_DCtx_loadDictionary() :
- * Create an internal DDict from dict buffer,
- * to be used to decompress next frames.
- * The dictionary remains valid for all future frames, until explicitly invalidated.
- * @result : 0, or an error code (which can be tested with ZSTD_isError()).
- * Special : Adding a NULL (or 0-size) dictionary invalidates any previous dictionary,
- * meaning "return to no-dictionary mode".
- * Note 1 : Loading a dictionary involves building tables,
- * which has a non-negligible impact on CPU usage and latency.
- * It's recommended to "load once, use many times", to amortize the cost
- * Note 2 :`dict` content will be copied internally, so `dict` can be released after loading.
- * Use ZSTD_DCtx_loadDictionary_byReference() to reference dictionary content instead.
- * Note 3 : Use ZSTD_DCtx_loadDictionary_advanced() to take control of
- * how dictionary content is loaded and interpreted.
- */
-ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);
-
-/*! ZSTD_DCtx_refDDict() :
- * Reference a prepared dictionary, to be used to decompress next frames.
- * The dictionary remains active for decompression of future frames using same DCtx.
- * @result : 0, or an error code (which can be tested with ZSTD_isError()).
- * Note 1 : Currently, only one dictionary can be managed.
- * Referencing a new dictionary effectively "discards" any previous one.
- * Special: referencing a NULL DDict means "return to no-dictionary mode".
- * Note 2 : DDict is just referenced, its lifetime must outlive its usage from DCtx.
- */
-ZSTDLIB_API size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict);
-
-/*! ZSTD_DCtx_refPrefix() :
- * Reference a prefix (single-usage dictionary) to decompress next frame.
- * This is the reverse operation of ZSTD_CCtx_refPrefix(),
- * and must use the same prefix as the one used during compression.
- * Prefix is **only used once**. Reference is discarded at end of frame.
- * End of frame is reached when ZSTD_decompressStream() returns 0.
- * @result : 0, or an error code (which can be tested with ZSTD_isError()).
- * Note 1 : Adding any prefix (including NULL) invalidates any previously set prefix or dictionary
- * Note 2 : Prefix buffer is referenced. It **must** outlive decompression.
- * Prefix buffer must remain unmodified up to the end of frame,
- * reached when ZSTD_decompressStream() returns 0.
- * Note 3 : By default, the prefix is treated as raw content (ZSTD_dct_rawContent).
- * Use ZSTD_CCtx_refPrefix_advanced() to alter dictMode (Experimental section)
- * Note 4 : Referencing a raw content prefix has almost no cpu nor memory cost.
- * A full dictionary is more costly, as it requires building tables.
- */
-ZSTDLIB_API size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx,
- const void* prefix, size_t prefixSize);
-
-/* === Memory management === */
-
-/*! ZSTD_sizeof_*() :
- * These functions give the _current_ memory usage of selected object.
- * Note that object memory usage can evolve (increase or decrease) over time. */
-ZSTDLIB_API size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx);
-ZSTDLIB_API size_t ZSTD_sizeof_DCtx(const ZSTD_DCtx* dctx);
-ZSTDLIB_API size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs);
-ZSTDLIB_API size_t ZSTD_sizeof_DStream(const ZSTD_DStream* zds);
-ZSTDLIB_API size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict);
-ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict);
-
-#endif /* ZSTD_H_235446 */
-
-
-/* **************************************************************************************
- * ADVANCED AND EXPERIMENTAL FUNCTIONS
- ****************************************************************************************
- * The definitions in the following section are considered experimental.
- * They are provided for advanced scenarios.
- * They should never be used with a dynamic library, as prototypes may change in the future.
- * Use them only in association with static linking.
- * ***************************************************************************************/
-
-#if defined(ZSTD_STATIC_LINKING_ONLY) && !defined(ZSTD_H_ZSTD_STATIC_LINKING_ONLY)
-#define ZSTD_H_ZSTD_STATIC_LINKING_ONLY
-
-/****************************************************************************************
- * experimental API (static linking only)
- ****************************************************************************************
- * The following symbols and constants
- * are not planned to join "stable API" status in the near future.
- * They can still change in future versions.
- * Some of them are planned to remain in the static_only section indefinitely.
- * Some of them might be removed in the future (especially when redundant with existing stable functions)
- * ***************************************************************************************/
-
-#define ZSTD_FRAMEHEADERSIZE_PREFIX(format) ((format) == ZSTD_f_zstd1 ? 5 : 1) /* minimum input size required to query frame header size */
-#define ZSTD_FRAMEHEADERSIZE_MIN(format) ((format) == ZSTD_f_zstd1 ? 6 : 2)
-#define ZSTD_FRAMEHEADERSIZE_MAX 18 /* can be useful for static allocation */
-#define ZSTD_SKIPPABLEHEADERSIZE 8
-
-/* compression parameter bounds */
-#define ZSTD_WINDOWLOG_MAX_32 30
-#define ZSTD_WINDOWLOG_MAX_64 31
-#define ZSTD_WINDOWLOG_MAX ((int)(sizeof(size_t) == 4 ? ZSTD_WINDOWLOG_MAX_32 : ZSTD_WINDOWLOG_MAX_64))
-#define ZSTD_WINDOWLOG_MIN 10
-#define ZSTD_HASHLOG_MAX ((ZSTD_WINDOWLOG_MAX < 30) ? ZSTD_WINDOWLOG_MAX : 30)
-#define ZSTD_HASHLOG_MIN 6
-#define ZSTD_CHAINLOG_MAX_32 29
-#define ZSTD_CHAINLOG_MAX_64 30
-#define ZSTD_CHAINLOG_MAX ((int)(sizeof(size_t) == 4 ? ZSTD_CHAINLOG_MAX_32 : ZSTD_CHAINLOG_MAX_64))
-#define ZSTD_CHAINLOG_MIN ZSTD_HASHLOG_MIN
-#define ZSTD_SEARCHLOG_MAX (ZSTD_WINDOWLOG_MAX-1)
-#define ZSTD_SEARCHLOG_MIN 1
-#define ZSTD_MINMATCH_MAX 7 /* only for ZSTD_fast, other strategies are limited to 6 */
-#define ZSTD_MINMATCH_MIN 3 /* only for ZSTD_btopt+, faster strategies are limited to 4 */
-#define ZSTD_TARGETLENGTH_MAX ZSTD_BLOCKSIZE_MAX
-#define ZSTD_TARGETLENGTH_MIN 0 /* note : comparing this constant to an unsigned results in a tautological test */
-#define ZSTD_STRATEGY_MIN ZSTD_fast
-#define ZSTD_STRATEGY_MAX ZSTD_btultra2
-
-
-#define ZSTD_OVERLAPLOG_MIN 0
-#define ZSTD_OVERLAPLOG_MAX 9
-
-#define ZSTD_WINDOWLOG_LIMIT_DEFAULT 27 /* by default, the streaming decoder will refuse any frame
- * requiring larger than (1<<ZSTD_WINDOWLOG_LIMIT_DEFAULT) window size,
- * to preserve host's memory from unreasonable requirements.
- * This limit can be overridden using ZSTD_DCtx_setParameter(,ZSTD_d_windowLogMax,).
- * The limit does not apply for one-pass decoders (such as ZSTD_decompress()), since no additional memory is allocated */
-
-
-/* LDM parameter bounds */
-#define ZSTD_LDM_HASHLOG_MIN ZSTD_HASHLOG_MIN
-#define ZSTD_LDM_HASHLOG_MAX ZSTD_HASHLOG_MAX
-#define ZSTD_LDM_MINMATCH_MIN 4
-#define ZSTD_LDM_MINMATCH_MAX 4096
-#define ZSTD_LDM_BUCKETSIZELOG_MIN 1
-#define ZSTD_LDM_BUCKETSIZELOG_MAX 8
-#define ZSTD_LDM_HASHRATELOG_MIN 0
-#define ZSTD_LDM_HASHRATELOG_MAX (ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN)
-
-/* Advanced parameter bounds */
-#define ZSTD_TARGETCBLOCKSIZE_MIN 64
-#define ZSTD_TARGETCBLOCKSIZE_MAX ZSTD_BLOCKSIZE_MAX
-#define ZSTD_SRCSIZEHINT_MIN 0
-#define ZSTD_SRCSIZEHINT_MAX INT_MAX
-
-/* internal */
-#define ZSTD_HASHLOG3_MAX 17
-
-
-/* --- Advanced types --- */
-
-typedef struct ZSTD_CCtx_params_s ZSTD_CCtx_params;
-
-typedef struct {
- unsigned int matchPos; /* Match pos in dst */
- /* If seqDef.offset > 3, then this is seqDef.offset - 3
- * If seqDef.offset < 3, then this is the corresponding repeat offset
- * But if seqDef.offset < 3 and litLength == 0, this is the
- * repeat offset before the corresponding repeat offset
- * And if seqDef.offset == 3 and litLength == 0, this is the
- * most recent repeat offset - 1
- */
- unsigned int offset;
- unsigned int litLength; /* Literal length */
- unsigned int matchLength; /* Match length */
- /* 0 when seq not rep and seqDef.offset otherwise
- * when litLength == 0 this will be <= 4, otherwise <= 3 like normal
- */
- unsigned int rep;
-} ZSTD_Sequence;
-
-typedef struct {
- unsigned windowLog; /**< largest match distance : larger == more compression, more memory needed during decompression */
- unsigned chainLog; /**< fully searched segment : larger == more compression, slower, more memory (useless for fast) */
- unsigned hashLog; /**< dispatch table : larger == faster, more memory */
- unsigned searchLog; /**< nb of searches : larger == more compression, slower */
- unsigned minMatch; /**< match length searched : larger == faster decompression, sometimes less compression */
- unsigned targetLength; /**< acceptable match size for optimal parser (only) : larger == more compression, slower */
- ZSTD_strategy strategy; /**< see ZSTD_strategy definition above */
-} ZSTD_compressionParameters;
-
-typedef struct {
- int contentSizeFlag; /**< 1: content size will be in frame header (when known) */
- int checksumFlag; /**< 1: generate a 32-bits checksum using XXH64 algorithm at end of frame, for error detection */
- int noDictIDFlag; /**< 1: no dictID will be saved into frame header (dictID is only useful for dictionary compression) */
-} ZSTD_frameParameters;
-
-typedef struct {
- ZSTD_compressionParameters cParams;
- ZSTD_frameParameters fParams;
-} ZSTD_parameters;
-
-typedef enum {
- ZSTD_dct_auto = 0, /* dictionary is "full" when starting with ZSTD_MAGIC_DICTIONARY, otherwise it is "rawContent" */
- ZSTD_dct_rawContent = 1, /* ensures dictionary is always loaded as rawContent, even if it starts with ZSTD_MAGIC_DICTIONARY */
- ZSTD_dct_fullDict = 2 /* refuses to load a dictionary if it does not respect Zstandard's specification, starting with ZSTD_MAGIC_DICTIONARY */
-} ZSTD_dictContentType_e;
-
-typedef enum {
- ZSTD_dlm_byCopy = 0, /**< Copy dictionary content internally */
- ZSTD_dlm_byRef = 1 /**< Reference dictionary content -- the dictionary buffer must outlive its users. */
-} ZSTD_dictLoadMethod_e;
-
-typedef enum {
- ZSTD_f_zstd1 = 0, /* zstd frame format, specified in zstd_compression_format.md (default) */
- ZSTD_f_zstd1_magicless = 1 /* Variant of zstd frame format, without initial 4-bytes magic number.
- * Useful to save 4 bytes per generated frame.
- * Decoder cannot recognise automatically this format, requiring this instruction. */
-} ZSTD_format_e;
-
-typedef enum {
- /* Note: this enum and the behavior it controls are effectively internal
- * implementation details of the compressor. They are expected to continue
- * to evolve and should be considered only in the context of extremely
- * advanced performance tuning.
- *
- * Zstd currently supports the use of a CDict in three ways:
- *
- * - The contents of the CDict can be copied into the working context. This
- * means that the compression can search both the dictionary and input
- * while operating on a single set of internal tables. This makes
- * the compression faster per-byte of input. However, the initial copy of
- * the CDict's tables incurs a fixed cost at the beginning of the
- * compression. For small compressions (< 8 KB), that copy can dominate
- * the cost of the compression.
- *
- * - The CDict's tables can be used in-place. In this model, compression is
- * slower per input byte, because the compressor has to search two sets of
- * tables. However, this model incurs no start-up cost (as long as the
- * working context's tables can be reused). For small inputs, this can be
- * faster than copying the CDict's tables.
- *
- * - The CDict's tables are not used at all, and instead we use the working
- * context alone to reload the dictionary and use params based on the source
- * size. See ZSTD_compress_insertDictionary() and ZSTD_compress_usingDict().
- * This method is effective when the dictionary sizes are very small relative
- * to the input size, and the input size is fairly large to begin with.
- *
- * Zstd has a simple internal heuristic that selects which strategy to use
- * at the beginning of a compression. However, if experimentation shows that
- * Zstd is making poor choices, it is possible to override that choice with
- * this enum.
- */
- ZSTD_dictDefaultAttach = 0, /* Use the default heuristic. */
- ZSTD_dictForceAttach = 1, /* Never copy the dictionary. */
- ZSTD_dictForceCopy = 2, /* Always copy the dictionary. */
- ZSTD_dictForceLoad = 3 /* Always reload the dictionary */
-} ZSTD_dictAttachPref_e;
-
-typedef enum {
- ZSTD_lcm_auto = 0, /**< Automatically determine the compression mode based on the compression level.
- * Negative compression levels will be uncompressed, and positive compression
- * levels will be compressed. */
- ZSTD_lcm_huffman = 1, /**< Always attempt Huffman compression. Uncompressed literals will still be
- * emitted if Huffman compression is not profitable. */
- ZSTD_lcm_uncompressed = 2 /**< Always emit uncompressed literals. */
-} ZSTD_literalCompressionMode_e;
-
-
-/***************************************
-* Frame size functions
-***************************************/
-
-/*! ZSTD_findDecompressedSize() :
- * `src` should point to the start of a series of ZSTD encoded and/or skippable frames
- * `srcSize` must be the _exact_ size of this series
- * (i.e. there should be a frame boundary at `src + srcSize`)
- * @return : - decompressed size of all data in all successive frames
- * - if the decompressed size cannot be determined: ZSTD_CONTENTSIZE_UNKNOWN
- * - if an error occurred: ZSTD_CONTENTSIZE_ERROR
- *
- * note 1 : decompressed size is an optional field, that may not be present, especially in streaming mode.
- * When `return==ZSTD_CONTENTSIZE_UNKNOWN`, data to decompress could be any size.
- * In which case, it's necessary to use streaming mode to decompress data.
- * note 2 : decompressed size is always present when compression is done with ZSTD_compress()
- * note 3 : decompressed size can be very large (64-bits value),
- * potentially larger than what local system can handle as a single memory segment.
- * In which case, it's necessary to use streaming mode to decompress data.
- * note 4 : If source is untrusted, decompressed size could be wrong or intentionally modified.
- * Always ensure result fits within application's authorized limits.
- * Each application can set its own limits.
- * note 5 : ZSTD_findDecompressedSize handles multiple frames, and so it must traverse the input to
- * read each contained frame header. This is fast as most of the data is skipped,
- * however it does mean that all frame data must be present and valid. */
-ZSTDLIB_API unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize);
-
-/*! ZSTD_decompressBound() :
- * `src` should point to the start of a series of ZSTD encoded and/or skippable frames
- * `srcSize` must be the _exact_ size of this series
- * (i.e. there should be a frame boundary at `src + srcSize`)
- * @return : - upper-bound for the decompressed size of all data in all successive frames
- * - if an error occured: ZSTD_CONTENTSIZE_ERROR
- *
- * note 1 : an error can occur if `src` contains an invalid or incorrectly formatted frame.
- * note 2 : the upper-bound is exact when the decompressed size field is available in every ZSTD encoded frame of `src`.
- * in this case, `ZSTD_findDecompressedSize` and `ZSTD_decompressBound` return the same value.
- * note 3 : when the decompressed size field isn't available, the upper-bound for that frame is calculated by:
- * upper-bound = # blocks * min(128 KB, Window_Size)
- */
-ZSTDLIB_API unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize);
-
-/*! ZSTD_frameHeaderSize() :
- * srcSize must be >= ZSTD_FRAMEHEADERSIZE_PREFIX.
- * @return : size of the Frame Header,
- * or an error code (if srcSize is too small) */
-ZSTDLIB_API size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize);
-
-/*! ZSTD_getSequences() :
- * Extract sequences from the sequence store
- * zc can be used to insert custom compression params.
- * This function invokes ZSTD_compress2
- * @return : number of sequences extracted
- */
-ZSTDLIB_API size_t ZSTD_getSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs,
- size_t outSeqsSize, const void* src, size_t srcSize);
-
-
-/***************************************
-* Memory management
-***************************************/
-
-/*! ZSTD_estimate*() :
- * These functions make it possible to estimate memory usage
- * of a future {D,C}Ctx, before its creation.
- *
- * ZSTD_estimateCCtxSize() will provide a memory budget large enough
- * for any compression level up to selected one.
- * Note : Unlike ZSTD_estimateCStreamSize*(), this estimate
- * does not include space for a window buffer.
- * Therefore, the estimation is only guaranteed for single-shot compressions, not streaming.
- * The estimate will assume the input may be arbitrarily large,
- * which is the worst case.
- *
- * When srcSize can be bound by a known and rather "small" value,
- * this fact can be used to provide a tighter estimation
- * because the CCtx compression context will need less memory.
- * This tighter estimation can be provided by more advanced functions
- * ZSTD_estimateCCtxSize_usingCParams(), which can be used in tandem with ZSTD_getCParams(),
- * and ZSTD_estimateCCtxSize_usingCCtxParams(), which can be used in tandem with ZSTD_CCtxParams_setParameter().
- * Both can be used to estimate memory using custom compression parameters and arbitrary srcSize limits.
- *
- * Note 2 : only single-threaded compression is supported.
- * ZSTD_estimateCCtxSize_usingCCtxParams() will return an error code if ZSTD_c_nbWorkers is >= 1.
- */
-ZSTDLIB_API size_t ZSTD_estimateCCtxSize(int compressionLevel);
-ZSTDLIB_API size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams);
-ZSTDLIB_API size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params);
-ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void);
-
-/*! ZSTD_estimateCStreamSize() :
- * ZSTD_estimateCStreamSize() will provide a budget large enough for any compression level up to selected one.
- * It will also consider src size to be arbitrarily "large", which is worst case.
- * If srcSize is known to always be small, ZSTD_estimateCStreamSize_usingCParams() can provide a tighter estimation.
- * ZSTD_estimateCStreamSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
- * ZSTD_estimateCStreamSize_usingCCtxParams() can be used in tandem with ZSTD_CCtxParams_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_c_nbWorkers is >= 1.
- * Note : CStream size estimation is only correct for single-threaded compression.
- * ZSTD_DStream memory budget depends on window Size.
- * This information can be passed manually, using ZSTD_estimateDStreamSize,
- * or deducted from a valid frame Header, using ZSTD_estimateDStreamSize_fromFrame();
- * Note : if streaming is init with function ZSTD_init?Stream_usingDict(),
- * an internal ?Dict will be created, which additional size is not estimated here.
- * In this case, get total size by adding ZSTD_estimate?DictSize */
-ZSTDLIB_API size_t ZSTD_estimateCStreamSize(int compressionLevel);
-ZSTDLIB_API size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams);
-ZSTDLIB_API size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params);
-ZSTDLIB_API size_t ZSTD_estimateDStreamSize(size_t windowSize);
-ZSTDLIB_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize);
-
-/*! ZSTD_estimate?DictSize() :
- * ZSTD_estimateCDictSize() will bet that src size is relatively "small", and content is copied, like ZSTD_createCDict().
- * ZSTD_estimateCDictSize_advanced() makes it possible to control compression parameters precisely, like ZSTD_createCDict_advanced().
- * Note : dictionaries created by reference (`ZSTD_dlm_byRef`) are logically smaller.
- */
-ZSTDLIB_API size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel);
-ZSTDLIB_API size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, ZSTD_dictLoadMethod_e dictLoadMethod);
-ZSTDLIB_API size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod);
-
-/*! ZSTD_initStatic*() :
- * Initialize an object using a pre-allocated fixed-size buffer.
- * workspace: The memory area to emplace the object into.
- * Provided pointer *must be 8-bytes aligned*.
- * Buffer must outlive object.
- * workspaceSize: Use ZSTD_estimate*Size() to determine
- * how large workspace must be to support target scenario.
- * @return : pointer to object (same address as workspace, just different type),
- * or NULL if error (size too small, incorrect alignment, etc.)
- * Note : zstd will never resize nor malloc() when using a static buffer.
- * If the object requires more memory than available,
- * zstd will just error out (typically ZSTD_error_memory_allocation).
- * Note 2 : there is no corresponding "free" function.
- * Since workspace is allocated externally, it must be freed externally too.
- * Note 3 : cParams : use ZSTD_getCParams() to convert a compression level
- * into its associated cParams.
- * Limitation 1 : currently not compatible with internal dictionary creation, triggered by
- * ZSTD_CCtx_loadDictionary(), ZSTD_initCStream_usingDict() or ZSTD_initDStream_usingDict().
- * Limitation 2 : static cctx currently not compatible with multi-threading.
- * Limitation 3 : static dctx is incompatible with legacy support.
- */
-ZSTDLIB_API ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize);
-ZSTDLIB_API ZSTD_CStream* ZSTD_initStaticCStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticCCtx() */
-
-ZSTDLIB_API ZSTD_DCtx* ZSTD_initStaticDCtx(void* workspace, size_t workspaceSize);
-ZSTDLIB_API ZSTD_DStream* ZSTD_initStaticDStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticDCtx() */
-
-ZSTDLIB_API const ZSTD_CDict* ZSTD_initStaticCDict(
- void* workspace, size_t workspaceSize,
- const void* dict, size_t dictSize,
- ZSTD_dictLoadMethod_e dictLoadMethod,
- ZSTD_dictContentType_e dictContentType,
- ZSTD_compressionParameters cParams);
-
-ZSTDLIB_API const ZSTD_DDict* ZSTD_initStaticDDict(
- void* workspace, size_t workspaceSize,
- const void* dict, size_t dictSize,
- ZSTD_dictLoadMethod_e dictLoadMethod,
- ZSTD_dictContentType_e dictContentType);
-
-
-/*! Custom memory allocation :
- * These prototypes make it possible to pass your own allocation/free functions.
- * ZSTD_customMem is provided at creation time, using ZSTD_create*_advanced() variants listed below.
- * All allocation/free operations will be completed using these custom variants instead of regular <stdlib.h> ones.
- */
-typedef void* (*ZSTD_allocFunction) (void* opaque, size_t size);
-typedef void (*ZSTD_freeFunction) (void* opaque, void* address);
-typedef struct { ZSTD_allocFunction customAlloc; ZSTD_freeFunction customFree; void* opaque; } ZSTD_customMem;
-static ZSTD_customMem const ZSTD_defaultCMem = { NULL, NULL, NULL }; /**< this constant defers to stdlib's functions */
-
-ZSTDLIB_API ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem);
-ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem);
-ZSTDLIB_API ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem);
-ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem);
-
-ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize,
- ZSTD_dictLoadMethod_e dictLoadMethod,
- ZSTD_dictContentType_e dictContentType,
- ZSTD_compressionParameters cParams,
- ZSTD_customMem customMem);
-
-ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize,
- ZSTD_dictLoadMethod_e dictLoadMethod,
- ZSTD_dictContentType_e dictContentType,
- ZSTD_customMem customMem);
-
-
-
-/***************************************
-* Advanced compression functions
-***************************************/
-
-/*! ZSTD_createCDict_byReference() :
- * Create a digested dictionary for compression
- * Dictionary content is just referenced, not duplicated.
- * As a consequence, `dictBuffer` **must** outlive CDict,
- * and its content must remain unmodified throughout the lifetime of CDict.
- * note: equivalent to ZSTD_createCDict_advanced(), with dictLoadMethod==ZSTD_dlm_byRef */
-ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_byReference(const void* dictBuffer, size_t dictSize, int compressionLevel);
-
-/*! ZSTD_getCParams() :
- * @return ZSTD_compressionParameters structure for a selected compression level and estimated srcSize.
- * `estimatedSrcSize` value is optional, select 0 if not known */
-ZSTDLIB_API ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize);
-
-/*! ZSTD_getParams() :
- * same as ZSTD_getCParams(), but @return a full `ZSTD_parameters` object instead of sub-component `ZSTD_compressionParameters`.
- * All fields of `ZSTD_frameParameters` are set to default : contentSize=1, checksum=0, noDictID=0 */
-ZSTDLIB_API ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize);
-
-/*! ZSTD_checkCParams() :
- * Ensure param values remain within authorized range.
- * @return 0 on success, or an error code (can be checked with ZSTD_isError()) */
-ZSTDLIB_API size_t ZSTD_checkCParams(ZSTD_compressionParameters params);
-
-/*! ZSTD_adjustCParams() :
- * optimize params for a given `srcSize` and `dictSize`.
- * `srcSize` can be unknown, in which case use ZSTD_CONTENTSIZE_UNKNOWN.
- * `dictSize` must be `0` when there is no dictionary.
- * cPar can be invalid : all parameters will be clamped within valid range in the @return struct.
- * This function never fails (wide contract) */
-ZSTDLIB_API ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize);
-
-/*! ZSTD_compress_advanced() :
- * Note : this function is now DEPRECATED.
- * It can be replaced by ZSTD_compress2(), in combination with ZSTD_CCtx_setParameter() and other parameter setters.
- * This prototype will be marked as deprecated and generate compilation warning on reaching v1.5.x */
-ZSTDLIB_API size_t ZSTD_compress_advanced(ZSTD_CCtx* cctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- const void* dict,size_t dictSize,
- ZSTD_parameters params);
-
-/*! ZSTD_compress_usingCDict_advanced() :
- * Note : this function is now REDUNDANT.
- * It can be replaced by ZSTD_compress2(), in combination with ZSTD_CCtx_loadDictionary() and other parameter setters.
- * This prototype will be marked as deprecated and generate compilation warning in some future version */
-ZSTDLIB_API size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- const ZSTD_CDict* cdict,
- ZSTD_frameParameters fParams);
-
-
-/*! ZSTD_CCtx_loadDictionary_byReference() :
- * Same as ZSTD_CCtx_loadDictionary(), but dictionary content is referenced, instead of being copied into CCtx.
- * It saves some memory, but also requires that `dict` outlives its usage within `cctx` */
-ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference(ZSTD_CCtx* cctx, const void* dict, size_t dictSize);
-
-/*! ZSTD_CCtx_loadDictionary_advanced() :
- * Same as ZSTD_CCtx_loadDictionary(), but gives finer control over
- * how to load the dictionary (by copy ? by reference ?)
- * and how to interpret it (automatic ? force raw mode ? full mode only ?) */
-ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType);
-
-/*! ZSTD_CCtx_refPrefix_advanced() :
- * Same as ZSTD_CCtx_refPrefix(), but gives finer control over
- * how to interpret prefix content (automatic ? force raw mode (default) ? full mode only ?) */
-ZSTDLIB_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType);
-
-/* === experimental parameters === */
-/* these parameters can be used with ZSTD_setParameter()
- * they are not guaranteed to remain supported in the future */
-
- /* Enables rsyncable mode,
- * which makes compressed files more rsync friendly
- * by adding periodic synchronization points to the compressed data.
- * The target average block size is ZSTD_c_jobSize / 2.
- * It's possible to modify the job size to increase or decrease
- * the granularity of the synchronization point.
- * Once the jobSize is smaller than the window size,
- * it will result in compression ratio degradation.
- * NOTE 1: rsyncable mode only works when multithreading is enabled.
- * NOTE 2: rsyncable performs poorly in combination with long range mode,
- * since it will decrease the effectiveness of synchronization points,
- * though mileage may vary.
- * NOTE 3: Rsyncable mode limits maximum compression speed to ~400 MB/s.
- * If the selected compression level is already running significantly slower,
- * the overall speed won't be significantly impacted.
- */
- #define ZSTD_c_rsyncable ZSTD_c_experimentalParam1
-
-/* Select a compression format.
- * The value must be of type ZSTD_format_e.
- * See ZSTD_format_e enum definition for details */
-#define ZSTD_c_format ZSTD_c_experimentalParam2
-
-/* Force back-reference distances to remain < windowSize,
- * even when referencing into Dictionary content (default:0) */
-#define ZSTD_c_forceMaxWindow ZSTD_c_experimentalParam3
-
-/* Controls whether the contents of a CDict
- * are used in place, or copied into the working context.
- * Accepts values from the ZSTD_dictAttachPref_e enum.
- * See the comments on that enum for an explanation of the feature. */
-#define ZSTD_c_forceAttachDict ZSTD_c_experimentalParam4
-
-/* Controls how the literals are compressed (default is auto).
- * The value must be of type ZSTD_literalCompressionMode_e.
- * See ZSTD_literalCompressionMode_t enum definition for details.
- */
-#define ZSTD_c_literalCompressionMode ZSTD_c_experimentalParam5
-
-/* Tries to fit compressed block size to be around targetCBlockSize.
- * No target when targetCBlockSize == 0.
- * There is no guarantee on compressed block size (default:0) */
-#define ZSTD_c_targetCBlockSize ZSTD_c_experimentalParam6
-
-/* User's best guess of source size.
- * Hint is not valid when srcSizeHint == 0.
- * There is no guarantee that hint is close to actual source size,
- * but compression ratio may regress significantly if guess considerably underestimates */
-#define ZSTD_c_srcSizeHint ZSTD_c_experimentalParam7
-
-/*! ZSTD_CCtx_getParameter() :
- * Get the requested compression parameter value, selected by enum ZSTD_cParameter,
- * and store it into int* value.
- * @return : 0, or an error code (which can be tested with ZSTD_isError()).
- */
-ZSTDLIB_API size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value);
-
-
-/*! ZSTD_CCtx_params :
- * Quick howto :
- * - ZSTD_createCCtxParams() : Create a ZSTD_CCtx_params structure
- * - ZSTD_CCtxParams_setParameter() : Push parameters one by one into
- * an existing ZSTD_CCtx_params structure.
- * This is similar to
- * ZSTD_CCtx_setParameter().
- * - ZSTD_CCtx_setParametersUsingCCtxParams() : Apply parameters to
- * an existing CCtx.
- * These parameters will be applied to
- * all subsequent frames.
- * - ZSTD_compressStream2() : Do compression using the CCtx.
- * - ZSTD_freeCCtxParams() : Free the memory.
- *
- * This can be used with ZSTD_estimateCCtxSize_advanced_usingCCtxParams()
- * for static allocation of CCtx for single-threaded compression.
- */
-ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void);
-ZSTDLIB_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params);
-
-/*! ZSTD_CCtxParams_reset() :
- * Reset params to default values.
- */
-ZSTDLIB_API size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params);
-
-/*! ZSTD_CCtxParams_init() :
- * Initializes the compression parameters of cctxParams according to
- * compression level. All other parameters are reset to their default values.
- */
-ZSTDLIB_API size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel);
-
-/*! ZSTD_CCtxParams_init_advanced() :
- * Initializes the compression and frame parameters of cctxParams according to
- * params. All other parameters are reset to their default values.
- */
-ZSTDLIB_API size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params);
-
-/*! ZSTD_CCtxParams_setParameter() :
- * Similar to ZSTD_CCtx_setParameter.
- * Set one compression parameter, selected by enum ZSTD_cParameter.
- * Parameters must be applied to a ZSTD_CCtx using ZSTD_CCtx_setParametersUsingCCtxParams().
- * @result : 0, or an error code (which can be tested with ZSTD_isError()).
- */
-ZSTDLIB_API size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, int value);
-
-/*! ZSTD_CCtxParams_getParameter() :
- * Similar to ZSTD_CCtx_getParameter.
- * Get the requested value of one compression parameter, selected by enum ZSTD_cParameter.
- * @result : 0, or an error code (which can be tested with ZSTD_isError()).
- */
-ZSTDLIB_API size_t ZSTD_CCtxParams_getParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, int* value);
-
-/*! ZSTD_CCtx_setParametersUsingCCtxParams() :
- * Apply a set of ZSTD_CCtx_params to the compression context.
- * This can be done even after compression is started,
- * if nbWorkers==0, this will have no impact until a new compression is started.
- * if nbWorkers>=1, new parameters will be picked up at next job,
- * with a few restrictions (windowLog, pledgedSrcSize, nbWorkers, jobSize, and overlapLog are not updated).
- */
-ZSTDLIB_API size_t ZSTD_CCtx_setParametersUsingCCtxParams(
- ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params);
-
-/*! ZSTD_compressStream2_simpleArgs() :
- * Same as ZSTD_compressStream2(),
- * but using only integral types as arguments.
- * This variant might be helpful for binders from dynamic languages
- * which have troubles handling structures containing memory pointers.
- */
-ZSTDLIB_API size_t ZSTD_compressStream2_simpleArgs (
- ZSTD_CCtx* cctx,
- void* dst, size_t dstCapacity, size_t* dstPos,
- const void* src, size_t srcSize, size_t* srcPos,
- ZSTD_EndDirective endOp);
-
-
-/***************************************
-* Advanced decompression functions
-***************************************/
-
-/*! ZSTD_isFrame() :
- * Tells if the content of `buffer` starts with a valid Frame Identifier.
- * Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0.
- * Note 2 : Legacy Frame Identifiers are considered valid only if Legacy Support is enabled.
- * Note 3 : Skippable Frame Identifiers are considered valid. */
-ZSTDLIB_API unsigned ZSTD_isFrame(const void* buffer, size_t size);
-
-/*! ZSTD_createDDict_byReference() :
- * Create a digested dictionary, ready to start decompression operation without startup delay.
- * Dictionary content is referenced, and therefore stays in dictBuffer.
- * It is important that dictBuffer outlives DDict,
- * it must remain read accessible throughout the lifetime of DDict */
-ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize);
-
-/*! ZSTD_DCtx_loadDictionary_byReference() :
- * Same as ZSTD_DCtx_loadDictionary(),
- * but references `dict` content instead of copying it into `dctx`.
- * This saves memory if `dict` remains around.,
- * However, it's imperative that `dict` remains accessible (and unmodified) while being used, so it must outlive decompression. */
-ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);
-
-/*! ZSTD_DCtx_loadDictionary_advanced() :
- * Same as ZSTD_DCtx_loadDictionary(),
- * but gives direct control over
- * how to load the dictionary (by copy ? by reference ?)
- * and how to interpret it (automatic ? force raw mode ? full mode only ?). */
-ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType);
-
-/*! ZSTD_DCtx_refPrefix_advanced() :
- * Same as ZSTD_DCtx_refPrefix(), but gives finer control over
- * how to interpret prefix content (automatic ? force raw mode (default) ? full mode only ?) */
-ZSTDLIB_API size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType);
-
-/*! ZSTD_DCtx_setMaxWindowSize() :
- * Refuses allocating internal buffers for frames requiring a window size larger than provided limit.
- * This protects a decoder context from reserving too much memory for itself (potential attack scenario).
- * This parameter is only useful in streaming mode, since no internal buffer is allocated in single-pass mode.
- * By default, a decompression context accepts all window sizes <= (1 << ZSTD_WINDOWLOG_LIMIT_DEFAULT)
- * @return : 0, or an error code (which can be tested using ZSTD_isError()).
- */
-ZSTDLIB_API size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize);
-
-/* ZSTD_d_format
- * experimental parameter,
- * allowing selection between ZSTD_format_e input compression formats
- */
-#define ZSTD_d_format ZSTD_d_experimentalParam1
-/* ZSTD_d_stableOutBuffer
- * Experimental parameter.
- * Default is 0 == disabled. Set to 1 to enable.
- *
- * Tells the decompressor that the ZSTD_outBuffer will ALWAYS be the same
- * between calls, except for the modifications that zstd makes to pos (the
- * caller must not modify pos). This is checked by the decompressor, and
- * decompression will fail if it ever changes. Therefore the ZSTD_outBuffer
- * MUST be large enough to fit the entire decompressed frame. This will be
- * checked when the frame content size is known. The data in the ZSTD_outBuffer
- * in the range [dst, dst + pos) MUST not be modified during decompression
- * or you will get data corruption.
- *
- * When this flags is enabled zstd won't allocate an output buffer, because
- * it can write directly to the ZSTD_outBuffer, but it will still allocate
- * an input buffer large enough to fit any compressed block. This will also
- * avoid the memcpy() from the internal output buffer to the ZSTD_outBuffer.
- * If you need to avoid the input buffer allocation use the buffer-less
- * streaming API.
- *
- * NOTE: So long as the ZSTD_outBuffer always points to valid memory, using
- * this flag is ALWAYS memory safe, and will never access out-of-bounds
- * memory. However, decompression WILL fail if you violate the preconditions.
- *
- * WARNING: The data in the ZSTD_outBuffer in the range [dst, dst + pos) MUST
- * not be modified during decompression or you will get data corruption. This
- * is because zstd needs to reference data in the ZSTD_outBuffer to regenerate
- * matches. Normally zstd maintains its own buffer for this purpose, but passing
- * this flag tells zstd to use the user provided buffer.
- */
-#define ZSTD_d_stableOutBuffer ZSTD_d_experimentalParam2
-
-/*! ZSTD_DCtx_setFormat() :
- * Instruct the decoder context about what kind of data to decode next.
- * This instruction is mandatory to decode data without a fully-formed header,
- * such ZSTD_f_zstd1_magicless for example.
- * @return : 0, or an error code (which can be tested using ZSTD_isError()). */
-ZSTDLIB_API size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format);
-
-/*! ZSTD_decompressStream_simpleArgs() :
- * Same as ZSTD_decompressStream(),
- * but using only integral types as arguments.
- * This can be helpful for binders from dynamic languages
- * which have troubles handling structures containing memory pointers.
- */
-ZSTDLIB_API size_t ZSTD_decompressStream_simpleArgs (
- ZSTD_DCtx* dctx,
- void* dst, size_t dstCapacity, size_t* dstPos,
- const void* src, size_t srcSize, size_t* srcPos);
-
-
-/********************************************************************
-* Advanced streaming functions
-* Warning : most of these functions are now redundant with the Advanced API.
-* Once Advanced API reaches "stable" status,
-* redundant functions will be deprecated, and then at some point removed.
-********************************************************************/
-
-/*===== Advanced Streaming compression functions =====*/
-/**! ZSTD_initCStream_srcSize() :
- * This function is deprecated, and equivalent to:
- * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
- * ZSTD_CCtx_refCDict(zcs, NULL); // clear the dictionary (if any)
- * ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel);
- * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize);
- *
- * pledgedSrcSize must be correct. If it is not known at init time, use
- * ZSTD_CONTENTSIZE_UNKNOWN. Note that, for compatibility with older programs,
- * "0" also disables frame content size field. It may be enabled in the future.
- * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x
- */
-ZSTDLIB_API size_t
-ZSTD_initCStream_srcSize(ZSTD_CStream* zcs,
- int compressionLevel,
- unsigned long long pledgedSrcSize);
-
-/**! ZSTD_initCStream_usingDict() :
- * This function is deprecated, and is equivalent to:
- * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
- * ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel);
- * ZSTD_CCtx_loadDictionary(zcs, dict, dictSize);
- *
- * Creates of an internal CDict (incompatible with static CCtx), except if
- * dict == NULL or dictSize < 8, in which case no dict is used.
- * Note: dict is loaded with ZSTD_dct_auto (treated as a full zstd dictionary if
- * it begins with ZSTD_MAGIC_DICTIONARY, else as raw content) and ZSTD_dlm_byCopy.
- * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x
- */
-ZSTDLIB_API size_t
-ZSTD_initCStream_usingDict(ZSTD_CStream* zcs,
- const void* dict, size_t dictSize,
- int compressionLevel);
-
-/**! ZSTD_initCStream_advanced() :
- * This function is deprecated, and is approximately equivalent to:
- * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
- * // Pseudocode: Set each zstd parameter and leave the rest as-is.
- * for ((param, value) : params) {
- * ZSTD_CCtx_setParameter(zcs, param, value);
- * }
- * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize);
- * ZSTD_CCtx_loadDictionary(zcs, dict, dictSize);
- *
- * dict is loaded with ZSTD_dct_auto and ZSTD_dlm_byCopy.
- * pledgedSrcSize must be correct.
- * If srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN.
- * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x
- */
-ZSTDLIB_API size_t
-ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
- const void* dict, size_t dictSize,
- ZSTD_parameters params,
- unsigned long long pledgedSrcSize);
-
-/**! ZSTD_initCStream_usingCDict() :
- * This function is deprecated, and equivalent to:
- * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
- * ZSTD_CCtx_refCDict(zcs, cdict);
- *
- * note : cdict will just be referenced, and must outlive compression session
- * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x
- */
-ZSTDLIB_API size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict);
-
-/**! ZSTD_initCStream_usingCDict_advanced() :
- * This function is DEPRECATED, and is approximately equivalent to:
- * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
- * // Pseudocode: Set each zstd frame parameter and leave the rest as-is.
- * for ((fParam, value) : fParams) {
- * ZSTD_CCtx_setParameter(zcs, fParam, value);
- * }
- * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize);
- * ZSTD_CCtx_refCDict(zcs, cdict);
- *
- * same as ZSTD_initCStream_usingCDict(), with control over frame parameters.
- * pledgedSrcSize must be correct. If srcSize is not known at init time, use
- * value ZSTD_CONTENTSIZE_UNKNOWN.
- * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x
- */
-ZSTDLIB_API size_t
-ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs,
- const ZSTD_CDict* cdict,
- ZSTD_frameParameters fParams,
- unsigned long long pledgedSrcSize);
-
-/*! ZSTD_resetCStream() :
- * This function is deprecated, and is equivalent to:
- * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
- * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize);
- *
- * start a new frame, using same parameters from previous frame.
- * This is typically useful to skip dictionary loading stage, since it will re-use it in-place.
- * Note that zcs must be init at least once before using ZSTD_resetCStream().
- * If pledgedSrcSize is not known at reset time, use macro ZSTD_CONTENTSIZE_UNKNOWN.
- * If pledgedSrcSize > 0, its value must be correct, as it will be written in header, and controlled at the end.
- * For the time being, pledgedSrcSize==0 is interpreted as "srcSize unknown" for compatibility with older programs,
- * but it will change to mean "empty" in future version, so use macro ZSTD_CONTENTSIZE_UNKNOWN instead.
- * @return : 0, or an error code (which can be tested using ZSTD_isError())
- * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x
- */
-ZSTDLIB_API size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize);
-
-
-typedef struct {
- unsigned long long ingested; /* nb input bytes read and buffered */
- unsigned long long consumed; /* nb input bytes actually compressed */
- unsigned long long produced; /* nb of compressed bytes generated and buffered */
- unsigned long long flushed; /* nb of compressed bytes flushed : not provided; can be tracked from caller side */
- unsigned currentJobID; /* MT only : latest started job nb */
- unsigned nbActiveWorkers; /* MT only : nb of workers actively compressing at probe time */
-} ZSTD_frameProgression;
-
-/* ZSTD_getFrameProgression() :
- * tells how much data has been ingested (read from input)
- * consumed (input actually compressed) and produced (output) for current frame.
- * Note : (ingested - consumed) is amount of input data buffered internally, not yet compressed.
- * Aggregates progression inside active worker threads.
- */
-ZSTDLIB_API ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx);
-
-/*! ZSTD_toFlushNow() :
- * Tell how many bytes are ready to be flushed immediately.
- * Useful for multithreading scenarios (nbWorkers >= 1).
- * Probe the oldest active job, defined as oldest job not yet entirely flushed,
- * and check its output buffer.
- * @return : amount of data stored in oldest job and ready to be flushed immediately.
- * if @return == 0, it means either :
- * + there is no active job (could be checked with ZSTD_frameProgression()), or
- * + oldest job is still actively compressing data,
- * but everything it has produced has also been flushed so far,
- * therefore flush speed is limited by production speed of oldest job
- * irrespective of the speed of concurrent (and newer) jobs.
- */
-ZSTDLIB_API size_t ZSTD_toFlushNow(ZSTD_CCtx* cctx);
-
-
-/*===== Advanced Streaming decompression functions =====*/
-/**
- * This function is deprecated, and is equivalent to:
- *
- * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only);
- * ZSTD_DCtx_loadDictionary(zds, dict, dictSize);
- *
- * note: no dictionary will be used if dict == NULL or dictSize < 8
- * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x
- */
-ZSTDLIB_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize);
-
-/**
- * This function is deprecated, and is equivalent to:
- *
- * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only);
- * ZSTD_DCtx_refDDict(zds, ddict);
- *
- * note : ddict is referenced, it must outlive decompression session
- * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x
- */
-ZSTDLIB_API size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict);
-
-/**
- * This function is deprecated, and is equivalent to:
- *
- * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only);
- *
- * re-use decompression parameters from previous init; saves dictionary loading
- * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x
- */
-ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds);
-
-
-/*********************************************************************
-* Buffer-less and synchronous inner streaming functions
-*
-* This is an advanced API, giving full control over buffer management, for users which need direct control over memory.
-* But it's also a complex one, with several restrictions, documented below.
-* Prefer normal streaming API for an easier experience.
-********************************************************************* */
-
-/**
- Buffer-less streaming compression (synchronous mode)
-
- A ZSTD_CCtx object is required to track streaming operations.
- Use ZSTD_createCCtx() / ZSTD_freeCCtx() to manage resource.
- ZSTD_CCtx object can be re-used multiple times within successive compression operations.
-
- Start by initializing a context.
- Use ZSTD_compressBegin(), or ZSTD_compressBegin_usingDict() for dictionary compression,
- or ZSTD_compressBegin_advanced(), for finer parameter control.
- It's also possible to duplicate a reference context which has already been initialized, using ZSTD_copyCCtx()
-
- Then, consume your input using ZSTD_compressContinue().
- There are some important considerations to keep in mind when using this advanced function :
- - ZSTD_compressContinue() has no internal buffer. It uses externally provided buffers only.
- - Interface is synchronous : input is consumed entirely and produces 1+ compressed blocks.
- - Caller must ensure there is enough space in `dst` to store compressed data under worst case scenario.
- Worst case evaluation is provided by ZSTD_compressBound().
- ZSTD_compressContinue() doesn't guarantee recover after a failed compression.
- - ZSTD_compressContinue() presumes prior input ***is still accessible and unmodified*** (up to maximum distance size, see WindowLog).
- It remembers all previous contiguous blocks, plus one separated memory segment (which can itself consists of multiple contiguous blocks)
- - ZSTD_compressContinue() detects that prior input has been overwritten when `src` buffer overlaps.
- In which case, it will "discard" the relevant memory section from its history.
-
- Finish a frame with ZSTD_compressEnd(), which will write the last block(s) and optional checksum.
- It's possible to use srcSize==0, in which case, it will write a final empty block to end the frame.
- Without last block mark, frames are considered unfinished (hence corrupted) by compliant decoders.
-
- `ZSTD_CCtx` object can be re-used (ZSTD_compressBegin()) to compress again.
-*/
-
-/*===== Buffer-less streaming compression functions =====*/
-ZSTDLIB_API size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel);
-ZSTDLIB_API size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel);
-ZSTDLIB_API size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize : If srcSize is not known at init time, use ZSTD_CONTENTSIZE_UNKNOWN */
-ZSTDLIB_API size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); /**< note: fails if cdict==NULL */
-ZSTDLIB_API size_t ZSTD_compressBegin_usingCDict_advanced(ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize); /* compression parameters are already set within cdict. pledgedSrcSize must be correct. If srcSize is not known, use macro ZSTD_CONTENTSIZE_UNKNOWN */
-ZSTDLIB_API size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, unsigned long long pledgedSrcSize); /**< note: if pledgedSrcSize is not known, use ZSTD_CONTENTSIZE_UNKNOWN */
-
-ZSTDLIB_API size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
-ZSTDLIB_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
-
-
-/*-
- Buffer-less streaming decompression (synchronous mode)
-
- A ZSTD_DCtx object is required to track streaming operations.
- Use ZSTD_createDCtx() / ZSTD_freeDCtx() to manage it.
- A ZSTD_DCtx object can be re-used multiple times.
-
- First typical operation is to retrieve frame parameters, using ZSTD_getFrameHeader().
- Frame header is extracted from the beginning of compressed frame, so providing only the frame's beginning is enough.
- Data fragment must be large enough to ensure successful decoding.
- `ZSTD_frameHeaderSize_max` bytes is guaranteed to always be large enough.
- @result : 0 : successful decoding, the `ZSTD_frameHeader` structure is correctly filled.
- >0 : `srcSize` is too small, please provide at least @result bytes on next attempt.
- errorCode, which can be tested using ZSTD_isError().
-
- It fills a ZSTD_frameHeader structure with important information to correctly decode the frame,
- such as the dictionary ID, content size, or maximum back-reference distance (`windowSize`).
- Note that these values could be wrong, either because of data corruption, or because a 3rd party deliberately spoofs false information.
- As a consequence, check that values remain within valid application range.
- For example, do not allocate memory blindly, check that `windowSize` is within expectation.
- Each application can set its own limits, depending on local restrictions.
- For extended interoperability, it is recommended to support `windowSize` of at least 8 MB.
-
- ZSTD_decompressContinue() needs previous data blocks during decompression, up to `windowSize` bytes.
- ZSTD_decompressContinue() is very sensitive to contiguity,
- if 2 blocks don't follow each other, make sure that either the compressor breaks contiguity at the same place,
- or that previous contiguous segment is large enough to properly handle maximum back-reference distance.
- There are multiple ways to guarantee this condition.
-
- The most memory efficient way is to use a round buffer of sufficient size.
- Sufficient size is determined by invoking ZSTD_decodingBufferSize_min(),
- which can @return an error code if required value is too large for current system (in 32-bits mode).
- In a round buffer methodology, ZSTD_decompressContinue() decompresses each block next to previous one,
- up to the moment there is not enough room left in the buffer to guarantee decoding another full block,
- which maximum size is provided in `ZSTD_frameHeader` structure, field `blockSizeMax`.
- At which point, decoding can resume from the beginning of the buffer.
- Note that already decoded data stored in the buffer should be flushed before being overwritten.
-
- There are alternatives possible, for example using two or more buffers of size `windowSize` each, though they consume more memory.
-
- Finally, if you control the compression process, you can also ignore all buffer size rules,
- as long as the encoder and decoder progress in "lock-step",
- aka use exactly the same buffer sizes, break contiguity at the same place, etc.
-
- Once buffers are setup, start decompression, with ZSTD_decompressBegin().
- If decompression requires a dictionary, use ZSTD_decompressBegin_usingDict() or ZSTD_decompressBegin_usingDDict().
-
- Then use ZSTD_nextSrcSizeToDecompress() and ZSTD_decompressContinue() alternatively.
- ZSTD_nextSrcSizeToDecompress() tells how many bytes to provide as 'srcSize' to ZSTD_decompressContinue().
- ZSTD_decompressContinue() requires this _exact_ amount of bytes, or it will fail.
-
- @result of ZSTD_decompressContinue() is the number of bytes regenerated within 'dst' (necessarily <= dstCapacity).
- It can be zero : it just means ZSTD_decompressContinue() has decoded some metadata item.
- It can also be an error code, which can be tested with ZSTD_isError().
-
- A frame is fully decoded when ZSTD_nextSrcSizeToDecompress() returns zero.
- Context can then be reset to start a new decompression.
-
- Note : it's possible to know if next input to present is a header or a block, using ZSTD_nextInputType().
- This information is not required to properly decode a frame.
-
- == Special case : skippable frames ==
-
- Skippable frames allow integration of user-defined data into a flow of concatenated frames.
- Skippable frames will be ignored (skipped) by decompressor.
- The format of skippable frames is as follows :
- a) Skippable frame ID - 4 Bytes, Little endian format, any value from 0x184D2A50 to 0x184D2A5F
- b) Frame Size - 4 Bytes, Little endian format, unsigned 32-bits
- c) Frame Content - any content (User Data) of length equal to Frame Size
- For skippable frames ZSTD_getFrameHeader() returns zfhPtr->frameType==ZSTD_skippableFrame.
- For skippable frames ZSTD_decompressContinue() always returns 0 : it only skips the content.
-*/
-
-/*===== Buffer-less streaming decompression functions =====*/
-typedef enum { ZSTD_frame, ZSTD_skippableFrame } ZSTD_frameType_e;
-typedef struct {
- unsigned long long frameContentSize; /* if == ZSTD_CONTENTSIZE_UNKNOWN, it means this field is not available. 0 means "empty" */
- unsigned long long windowSize; /* can be very large, up to <= frameContentSize */
- unsigned blockSizeMax;
- ZSTD_frameType_e frameType; /* if == ZSTD_skippableFrame, frameContentSize is the size of skippable content */
- unsigned headerSize;
- unsigned dictID;
- unsigned checksumFlag;
-} ZSTD_frameHeader;
-
-/*! ZSTD_getFrameHeader() :
- * decode Frame Header, or requires larger `srcSize`.
- * @return : 0, `zfhPtr` is correctly filled,
- * >0, `srcSize` is too small, value is wanted `srcSize` amount,
- * or an error code, which can be tested using ZSTD_isError() */
-ZSTDLIB_API size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize); /**< doesn't consume input */
-/*! ZSTD_getFrameHeader_advanced() :
- * same as ZSTD_getFrameHeader(),
- * with added capability to select a format (like ZSTD_f_zstd1_magicless) */
-ZSTDLIB_API size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format);
-ZSTDLIB_API size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize); /**< when frame content size is not known, pass in frameContentSize == ZSTD_CONTENTSIZE_UNKNOWN */
-
-ZSTDLIB_API size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx);
-ZSTDLIB_API size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);
-ZSTDLIB_API size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict);
-
-ZSTDLIB_API size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx);
-ZSTDLIB_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
-
-/* misc */
-ZSTDLIB_API void ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx);
-typedef enum { ZSTDnit_frameHeader, ZSTDnit_blockHeader, ZSTDnit_block, ZSTDnit_lastBlock, ZSTDnit_checksum, ZSTDnit_skippableFrame } ZSTD_nextInputType_e;
-ZSTDLIB_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx);
-
-
-
-
-/* ============================ */
-/** Block level API */
-/* ============================ */
-
-/*!
- Block functions produce and decode raw zstd blocks, without frame metadata.
- Frame metadata cost is typically ~12 bytes, which can be non-negligible for very small blocks (< 100 bytes).
- But users will have to take in charge needed metadata to regenerate data, such as compressed and content sizes.
-
- A few rules to respect :
- - Compressing and decompressing require a context structure
- + Use ZSTD_createCCtx() and ZSTD_createDCtx()
- - It is necessary to init context before starting
- + compression : any ZSTD_compressBegin*() variant, including with dictionary
- + decompression : any ZSTD_decompressBegin*() variant, including with dictionary
- + copyCCtx() and copyDCtx() can be used too
- - Block size is limited, it must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX == 128 KB
- + If input is larger than a block size, it's necessary to split input data into multiple blocks
- + For inputs larger than a single block, consider using regular ZSTD_compress() instead.
- Frame metadata is not that costly, and quickly becomes negligible as source size grows larger than a block.
- - When a block is considered not compressible enough, ZSTD_compressBlock() result will be 0 (zero) !
- ===> In which case, nothing is produced into `dst` !
- + User __must__ test for such outcome and deal directly with uncompressed data
- + A block cannot be declared incompressible if ZSTD_compressBlock() return value was != 0.
- Doing so would mess up with statistics history, leading to potential data corruption.
- + ZSTD_decompressBlock() _doesn't accept uncompressed data as input_ !!
- + In case of multiple successive blocks, should some of them be uncompressed,
- decoder must be informed of their existence in order to follow proper history.
- Use ZSTD_insertBlock() for such a case.
-*/
-
-/*===== Raw zstd block functions =====*/
-ZSTDLIB_API size_t ZSTD_getBlockSize (const ZSTD_CCtx* cctx);
-ZSTDLIB_API size_t ZSTD_compressBlock (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
-ZSTDLIB_API size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
-ZSTDLIB_API size_t ZSTD_insertBlock (ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize); /**< insert uncompressed block into `dctx` history. Useful for multi-blocks decompression. */
-
-
-#endif /* ZSTD_H_ZSTD_STATIC_LINKING_ONLY */
-
-#if defined (__cplusplus)
-}
-#endif
-/**** ended inlining ../zstd.h ****/
-#define FSE_STATIC_LINKING_ONLY
-/**** skipping file: fse.h ****/
-#define HUF_STATIC_LINKING_ONLY
-/**** skipping file: huf.h ****/
-#ifndef XXH_STATIC_LINKING_ONLY
-# define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */
-#endif
-/**** start inlining xxhash.h ****/
-/*
- * xxHash - Extremely Fast Hash algorithm
- * Header File
- * Copyright (c) 2012-2020, Yann Collet, Facebook, Inc.
- *
- * You can contact the author at :
- * - xxHash source repository : https://github.com/Cyan4973/xxHash
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
-*/
-
-/* Notice extracted from xxHash homepage :
-
-xxHash is an extremely fast Hash algorithm, running at RAM speed limits.
-It also successfully passes all tests from the SMHasher suite.
-
-Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz)
-
-Name Speed Q.Score Author
-xxHash 5.4 GB/s 10
-CrapWow 3.2 GB/s 2 Andrew
-MumurHash 3a 2.7 GB/s 10 Austin Appleby
-SpookyHash 2.0 GB/s 10 Bob Jenkins
-SBox 1.4 GB/s 9 Bret Mulvey
-Lookup3 1.2 GB/s 9 Bob Jenkins
-SuperFastHash 1.2 GB/s 1 Paul Hsieh
-CityHash64 1.05 GB/s 10 Pike & Alakuijala
-FNV 0.55 GB/s 5 Fowler, Noll, Vo
-CRC32 0.43 GB/s 9
-MD5-32 0.33 GB/s 10 Ronald L. Rivest
-SHA1-32 0.28 GB/s 10
-
-Q.Score is a measure of quality of the hash function.
-It depends on successfully passing SMHasher test set.
-10 is a perfect score.
-
-A 64-bits version, named XXH64, is available since r35.
-It offers much better speed, but for 64-bits applications only.
-Name Speed on 64 bits Speed on 32 bits
-XXH64 13.8 GB/s 1.9 GB/s
-XXH32 6.8 GB/s 6.0 GB/s
-*/
-
-#if defined (__cplusplus)
-extern "C" {
-#endif
-
-#ifndef XXHASH_H_5627135585666179
-#define XXHASH_H_5627135585666179 1
-
-
-/* ****************************
-* Definitions
-******************************/
-#include <stddef.h> /* size_t */
-typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode;
-
-
-/* ****************************
-* API modifier
-******************************/
-/** XXH_PRIVATE_API
-* This is useful if you want to include xxhash functions in `static` mode
-* in order to inline them, and remove their symbol from the public list.
-* Methodology :
-* #define XXH_PRIVATE_API
-* #include "xxhash.h"
-* `xxhash.c` is automatically included.
-* It's not useful to compile and link it as a separate module anymore.
-*/
-#ifdef XXH_PRIVATE_API
-# ifndef XXH_STATIC_LINKING_ONLY
-# define XXH_STATIC_LINKING_ONLY
-# endif
-# if defined(__GNUC__)
-# define XXH_PUBLIC_API static __inline __attribute__((unused))
-# elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
-# define XXH_PUBLIC_API static inline
-# elif defined(_MSC_VER)
-# define XXH_PUBLIC_API static __inline
-# else
-# define XXH_PUBLIC_API static /* this version may generate warnings for unused static functions; disable the relevant warning */
-# endif
-#else
-# define XXH_PUBLIC_API /* do nothing */
-#endif /* XXH_PRIVATE_API */
-
-/*!XXH_NAMESPACE, aka Namespace Emulation :
-
-If you want to include _and expose_ xxHash functions from within your own library,
-but also want to avoid symbol collisions with another library which also includes xxHash,
-
-you can use XXH_NAMESPACE, to automatically prefix any public symbol from xxhash library
-with the value of XXH_NAMESPACE (so avoid to keep it NULL and avoid numeric values).
-
-Note that no change is required within the calling program as long as it includes `xxhash.h` :
-regular symbol name will be automatically translated by this header.
-*/
-#ifdef XXH_NAMESPACE
-# define XXH_CAT(A,B) A##B
-# define XXH_NAME2(A,B) XXH_CAT(A,B)
-# define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32)
-# define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64)
-# define XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber)
-# define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState)
-# define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState)
-# define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState)
-# define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState)
-# define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset)
-# define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset)
-# define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update)
-# define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update)
-# define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest)
-# define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest)
-# define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState)
-# define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState)
-# define XXH32_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash)
-# define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash)
-# define XXH32_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical)
-# define XXH64_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH64_hashFromCanonical)
-#endif
-
-
-/* *************************************
-* Version
-***************************************/
-#define XXH_VERSION_MAJOR 0
-#define XXH_VERSION_MINOR 6
-#define XXH_VERSION_RELEASE 2
-#define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE)
-XXH_PUBLIC_API unsigned XXH_versionNumber (void);
-
-
-/* ****************************
-* Simple Hash Functions
-******************************/
-typedef unsigned int XXH32_hash_t;
-typedef unsigned long long XXH64_hash_t;
-
-XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, unsigned int seed);
-XXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t length, unsigned long long seed);
-
-/*!
-XXH32() :
- Calculate the 32-bits hash of sequence "length" bytes stored at memory address "input".
- The memory between input & input+length must be valid (allocated and read-accessible).
- "seed" can be used to alter the result predictably.
- Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s
-XXH64() :
- Calculate the 64-bits hash of sequence of length "len" stored at memory address "input".
- "seed" can be used to alter the result predictably.
- This function runs 2x faster on 64-bits systems, but slower on 32-bits systems (see benchmark).
-*/
-
-
-/* ****************************
-* Streaming Hash Functions
-******************************/
-typedef struct XXH32_state_s XXH32_state_t; /* incomplete type */
-typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */
-
-/*! State allocation, compatible with dynamic libraries */
-
-XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void);
-XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr);
-
-XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void);
-XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr);
-
-
-/* hash streaming */
-
-XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, unsigned int seed);
-XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length);
-XXH_PUBLIC_API XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr);
-
-XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, unsigned long long seed);
-XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length);
-XXH_PUBLIC_API XXH64_hash_t XXH64_digest (const XXH64_state_t* statePtr);
-
-/*
-These functions generate the xxHash of an input provided in multiple segments.
-Note that, for small input, they are slower than single-call functions, due to state management.
-For small input, prefer `XXH32()` and `XXH64()` .
-
-XXH state must first be allocated, using XXH*_createState() .
-
-Start a new hash by initializing state with a seed, using XXH*_reset().
-
-Then, feed the hash state by calling XXH*_update() as many times as necessary.
-Obviously, input must be allocated and read accessible.
-The function returns an error code, with 0 meaning OK, and any other value meaning there is an error.
-
-Finally, a hash value can be produced anytime, by using XXH*_digest().
-This function returns the nn-bits hash as an int or long long.
-
-It's still possible to continue inserting input into the hash state after a digest,
-and generate some new hashes later on, by calling again XXH*_digest().
-
-When done, free XXH state space if it was allocated dynamically.
-*/
-
-
-/* **************************
-* Utils
-****************************/
-#if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) /* ! C99 */
-# define restrict /* disable restrict */
-#endif
-
-XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* restrict dst_state, const XXH32_state_t* restrict src_state);
-XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* restrict dst_state, const XXH64_state_t* restrict src_state);
-
-
-/* **************************
-* Canonical representation
-****************************/
-/* Default result type for XXH functions are primitive unsigned 32 and 64 bits.
-* The canonical representation uses human-readable write convention, aka big-endian (large digits first).
-* These functions allow transformation of hash result into and from its canonical format.
-* This way, hash values can be written into a file / memory, and remain comparable on different systems and programs.
-*/
-typedef struct { unsigned char digest[4]; } XXH32_canonical_t;
-typedef struct { unsigned char digest[8]; } XXH64_canonical_t;
-
-XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash);
-XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash);
-
-XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src);
-XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src);
-
-#endif /* XXHASH_H_5627135585666179 */
-
-
-
-/* ================================================================================================
- This section contains definitions which are not guaranteed to remain stable.
- They may change in future versions, becoming incompatible with a different version of the library.
- They shall only be used with static linking.
- Never use these definitions in association with dynamic linking !
-=================================================================================================== */
-#if defined(XXH_STATIC_LINKING_ONLY) && !defined(XXH_STATIC_H_3543687687345)
-#define XXH_STATIC_H_3543687687345
-
-/* These definitions are only meant to allow allocation of XXH state
- statically, on stack, or in a struct for example.
- Do not use members directly. */
-
- struct XXH32_state_s {
- unsigned total_len_32;
- unsigned large_len;
- unsigned v1;
- unsigned v2;
- unsigned v3;
- unsigned v4;
- unsigned mem32[4]; /* buffer defined as U32 for alignment */
- unsigned memsize;
- unsigned reserved; /* never read nor write, will be removed in a future version */
- }; /* typedef'd to XXH32_state_t */
-
- struct XXH64_state_s {
- unsigned long long total_len;
- unsigned long long v1;
- unsigned long long v2;
- unsigned long long v3;
- unsigned long long v4;
- unsigned long long mem64[4]; /* buffer defined as U64 for alignment */
- unsigned memsize;
- unsigned reserved[2]; /* never read nor write, will be removed in a future version */
- }; /* typedef'd to XXH64_state_t */
-
-
-# ifdef XXH_PRIVATE_API
-/**** start inlining xxhash.c ****/
-/*
- * xxHash - Fast Hash algorithm
- * Copyright (c) 2012-2020, Yann Collet, Facebook, Inc.
- *
- * You can contact the author at :
- * - xxHash homepage: http://www.xxhash.com
- * - xxHash source repository : https://github.com/Cyan4973/xxHash
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
-*/
-
-
-/* *************************************
-* Tuning parameters
-***************************************/
-/*!XXH_FORCE_MEMORY_ACCESS :
- * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.
- * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.
- * The below switch allow to select different access method for improved performance.
- * Method 0 (default) : use `memcpy()`. Safe and portable.
- * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable).
- * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.
- * Method 2 : direct access. This method doesn't depend on compiler but violate C standard.
- * It can generate buggy code on targets which do not support unaligned memory accesses.
- * But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6)
- * See http://stackoverflow.com/a/32095106/646947 for details.
- * Prefer these methods in priority order (0 > 1 > 2)
- */
-#ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */
-# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) )
-# define XXH_FORCE_MEMORY_ACCESS 2
-# elif (defined(__INTEL_COMPILER) && !defined(WIN32)) || \
- (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) )) || \
- defined(__ICCARM__)
-# define XXH_FORCE_MEMORY_ACCESS 1
-# endif
-#endif
-
-/*!XXH_ACCEPT_NULL_INPUT_POINTER :
- * If the input pointer is a null pointer, xxHash default behavior is to trigger a memory access error, since it is a bad pointer.
- * When this option is enabled, xxHash output for null input pointers will be the same as a null-length input.
- * By default, this option is disabled. To enable it, uncomment below define :
- */
-/* #define XXH_ACCEPT_NULL_INPUT_POINTER 1 */
-
-/*!XXH_FORCE_NATIVE_FORMAT :
- * By default, xxHash library provides endian-independent Hash values, based on little-endian convention.
- * Results are therefore identical for little-endian and big-endian CPU.
- * This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format.
- * Should endian-independence be of no importance for your application, you may set the #define below to 1,
- * to improve speed for Big-endian CPU.
- * This option has no impact on Little_Endian CPU.
- */
-#ifndef XXH_FORCE_NATIVE_FORMAT /* can be defined externally */
-# define XXH_FORCE_NATIVE_FORMAT 0
-#endif
-
-/*!XXH_FORCE_ALIGN_CHECK :
- * This is a minor performance trick, only useful with lots of very small keys.
- * It means : check for aligned/unaligned input.
- * The check costs one initial branch per hash; set to 0 when the input data
- * is guaranteed to be aligned.
- */
-#ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */
-# if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)
-# define XXH_FORCE_ALIGN_CHECK 0
-# else
-# define XXH_FORCE_ALIGN_CHECK 1
-# endif
-#endif
-
-
-/* *************************************
-* Includes & Memory related functions
-***************************************/
-/* Modify the local functions below should you wish to use some other memory routines */
-/* for malloc(), free() */
-#include <stdlib.h>
-#include <stddef.h> /* size_t */
-static void* XXH_malloc(size_t s) { return malloc(s); }
-static void XXH_free (void* p) { free(p); }
-/* for memcpy() */
-#include <string.h>
-static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcpy(dest,src,size); }
-
-#ifndef XXH_STATIC_LINKING_ONLY
-# define XXH_STATIC_LINKING_ONLY
-#endif
-/**** skipping file: xxhash.h ****/
-
-
-/* *************************************
-* Compiler Specific Options
-***************************************/
-#if (defined(__GNUC__) && !defined(__STRICT_ANSI__)) || defined(__cplusplus) || defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
-# define INLINE_KEYWORD inline
-#else
-# define INLINE_KEYWORD
-#endif
-
-#if defined(__GNUC__) || defined(__ICCARM__)
-# define FORCE_INLINE_ATTR __attribute__((always_inline))
-#elif defined(_MSC_VER)
-# define FORCE_INLINE_ATTR __forceinline
-#else
-# define FORCE_INLINE_ATTR
-#endif
-
-#define FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR
-
-
-#ifdef _MSC_VER
-# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
-#endif
-
-
-/* *************************************
-* Basic Types
-***************************************/
-#ifndef MEM_MODULE
-# define MEM_MODULE
-# if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
-# include <stdint.h>
- typedef uint8_t BYTE;
- typedef uint16_t U16;
- typedef uint32_t U32;
- typedef int32_t S32;
- typedef uint64_t U64;
-# else
- typedef unsigned char BYTE;
- typedef unsigned short U16;
- typedef unsigned int U32;
- typedef signed int S32;
- typedef unsigned long long U64; /* if your compiler doesn't support unsigned long long, replace by another 64-bit type here. Note that xxhash.h will also need to be updated. */
-# endif
-#endif
-
-
-#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2))
-
-/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */
-static U32 XXH_read32(const void* memPtr) { return *(const U32*) memPtr; }
-static U64 XXH_read64(const void* memPtr) { return *(const U64*) memPtr; }
-
-#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))
-
-/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
-/* currently only defined for gcc and icc */
-typedef union { U32 u32; U64 u64; } __attribute__((packed)) unalign;
-
-static U32 XXH_read32(const void* ptr) { return ((const unalign*)ptr)->u32; }
-static U64 XXH_read64(const void* ptr) { return ((const unalign*)ptr)->u64; }
-
-#else
-
-/* portable and safe solution. Generally efficient.
- * see : http://stackoverflow.com/a/32095106/646947
- */
-
-static U32 XXH_read32(const void* memPtr)
-{
- U32 val;
- memcpy(&val, memPtr, sizeof(val));
- return val;
-}
-
-static U64 XXH_read64(const void* memPtr)
-{
- U64 val;
- memcpy(&val, memPtr, sizeof(val));
- return val;
-}
-
-#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */
-
-
-/* ****************************************
-* Compiler-specific Functions and Macros
-******************************************/
-#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
-
-/* Note : although _rotl exists for minGW (GCC under windows), performance seems poor */
-#if defined(_MSC_VER)
-# define XXH_rotl32(x,r) _rotl(x,r)
-# define XXH_rotl64(x,r) _rotl64(x,r)
-#else
-#if defined(__ICCARM__)
-# include <intrinsics.h>
-# define XXH_rotl32(x,r) __ROR(x,(32 - r))
-#else
-# define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r)))
-#endif
-# define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r)))
-#endif
-
-#if defined(_MSC_VER) /* Visual Studio */
-# define XXH_swap32 _byteswap_ulong
-# define XXH_swap64 _byteswap_uint64
-#elif GCC_VERSION >= 403
-# define XXH_swap32 __builtin_bswap32
-# define XXH_swap64 __builtin_bswap64
-#else
-static U32 XXH_swap32 (U32 x)
-{
- return ((x << 24) & 0xff000000 ) |
- ((x << 8) & 0x00ff0000 ) |
- ((x >> 8) & 0x0000ff00 ) |
- ((x >> 24) & 0x000000ff );
-}
-static U64 XXH_swap64 (U64 x)
-{
- return ((x << 56) & 0xff00000000000000ULL) |
- ((x << 40) & 0x00ff000000000000ULL) |
- ((x << 24) & 0x0000ff0000000000ULL) |
- ((x << 8) & 0x000000ff00000000ULL) |
- ((x >> 8) & 0x00000000ff000000ULL) |
- ((x >> 24) & 0x0000000000ff0000ULL) |
- ((x >> 40) & 0x000000000000ff00ULL) |
- ((x >> 56) & 0x00000000000000ffULL);
-}
-#endif
-
-
-/* *************************************
-* Architecture Macros
-***************************************/
-typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess;
-
-/* XXH_CPU_LITTLE_ENDIAN can be defined externally, for example on the compiler command line */
-#ifndef XXH_CPU_LITTLE_ENDIAN
- static const int g_one = 1;
-# define XXH_CPU_LITTLE_ENDIAN (*(const char*)(&g_one))
-#endif
-
-
-/* ***************************
-* Memory reads
-*****************************/
-typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment;
-
-FORCE_INLINE_TEMPLATE U32 XXH_readLE32_align(const void* ptr, XXH_endianess endian, XXH_alignment align)
-{
- if (align==XXH_unaligned)
- return endian==XXH_littleEndian ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr));
- else
- return endian==XXH_littleEndian ? *(const U32*)ptr : XXH_swap32(*(const U32*)ptr);
-}
-
-FORCE_INLINE_TEMPLATE U32 XXH_readLE32(const void* ptr, XXH_endianess endian)
-{
- return XXH_readLE32_align(ptr, endian, XXH_unaligned);
-}
-
-static U32 XXH_readBE32(const void* ptr)
-{
- return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr);
-}
-
-FORCE_INLINE_TEMPLATE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align)
-{
- if (align==XXH_unaligned)
- return endian==XXH_littleEndian ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr));
- else
- return endian==XXH_littleEndian ? *(const U64*)ptr : XXH_swap64(*(const U64*)ptr);
-}
-
-FORCE_INLINE_TEMPLATE U64 XXH_readLE64(const void* ptr, XXH_endianess endian)
-{
- return XXH_readLE64_align(ptr, endian, XXH_unaligned);
-}
-
-static U64 XXH_readBE64(const void* ptr)
-{
- return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr);
-}
-
-
-/* *************************************
-* Macros
-***************************************/
-#define XXH_STATIC_ASSERT(c) { enum { XXH_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */
-
-
-/* *************************************
-* Constants
-***************************************/
-static const U32 PRIME32_1 = 2654435761U;
-static const U32 PRIME32_2 = 2246822519U;
-static const U32 PRIME32_3 = 3266489917U;
-static const U32 PRIME32_4 = 668265263U;
-static const U32 PRIME32_5 = 374761393U;
-
-static const U64 PRIME64_1 = 11400714785074694791ULL;
-static const U64 PRIME64_2 = 14029467366897019727ULL;
-static const U64 PRIME64_3 = 1609587929392839161ULL;
-static const U64 PRIME64_4 = 9650029242287828579ULL;
-static const U64 PRIME64_5 = 2870177450012600261ULL;
-
-XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; }
-
-
-/* **************************
-* Utils
-****************************/
-XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* restrict dstState, const XXH32_state_t* restrict srcState)
-{
- memcpy(dstState, srcState, sizeof(*dstState));
-}
-
-XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* restrict dstState, const XXH64_state_t* restrict srcState)
-{
- memcpy(dstState, srcState, sizeof(*dstState));
-}
-
-
-/* ***************************
-* Simple Hash Functions
-*****************************/
-
-static U32 XXH32_round(U32 seed, U32 input)
-{
- seed += input * PRIME32_2;
- seed = XXH_rotl32(seed, 13);
- seed *= PRIME32_1;
- return seed;
-}
-
-FORCE_INLINE_TEMPLATE U32 XXH32_endian_align(const void* input, size_t len, U32 seed, XXH_endianess endian, XXH_alignment align)
-{
- const BYTE* p = (const BYTE*)input;
- const BYTE* bEnd = p + len;
- U32 h32;
-#define XXH_get32bits(p) XXH_readLE32_align(p, endian, align)
-
-#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
- if (p==NULL) {
- len=0;
- bEnd=p=(const BYTE*)(size_t)16;
- }
-#endif
-
- if (len>=16) {
- const BYTE* const limit = bEnd - 16;
- U32 v1 = seed + PRIME32_1 + PRIME32_2;
- U32 v2 = seed + PRIME32_2;
- U32 v3 = seed + 0;
- U32 v4 = seed - PRIME32_1;
-
- do {
- v1 = XXH32_round(v1, XXH_get32bits(p)); p+=4;
- v2 = XXH32_round(v2, XXH_get32bits(p)); p+=4;
- v3 = XXH32_round(v3, XXH_get32bits(p)); p+=4;
- v4 = XXH32_round(v4, XXH_get32bits(p)); p+=4;
- } while (p<=limit);
-
- h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18);
- } else {
- h32 = seed + PRIME32_5;
- }
-
- h32 += (U32) len;
-
- while (p+4<=bEnd) {
- h32 += XXH_get32bits(p) * PRIME32_3;
- h32 = XXH_rotl32(h32, 17) * PRIME32_4 ;
- p+=4;
- }
-
- while (p<bEnd) {
- h32 += (*p) * PRIME32_5;
- h32 = XXH_rotl32(h32, 11) * PRIME32_1 ;
- p++;
- }
-
- h32 ^= h32 >> 15;
- h32 *= PRIME32_2;
- h32 ^= h32 >> 13;
- h32 *= PRIME32_3;
- h32 ^= h32 >> 16;
-
- return h32;
-}
-
-
-XXH_PUBLIC_API unsigned int XXH32 (const void* input, size_t len, unsigned int seed)
-{
-#if 0
- /* Simple version, good for code maintenance, but unfortunately slow for small inputs */
- XXH32_CREATESTATE_STATIC(state);
- XXH32_reset(state, seed);
- XXH32_update(state, input, len);
- return XXH32_digest(state);
-#else
- XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
-
- if (XXH_FORCE_ALIGN_CHECK) {
- if ((((size_t)input) & 3) == 0) { /* Input is 4-bytes aligned, leverage the speed benefit */
- if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
- return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
- else
- return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
- } }
-
- if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
- return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
- else
- return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
-#endif
-}
-
-
-static U64 XXH64_round(U64 acc, U64 input)
-{
- acc += input * PRIME64_2;
- acc = XXH_rotl64(acc, 31);
- acc *= PRIME64_1;
- return acc;
-}
-
-static U64 XXH64_mergeRound(U64 acc, U64 val)
-{
- val = XXH64_round(0, val);
- acc ^= val;
- acc = acc * PRIME64_1 + PRIME64_4;
- return acc;
-}
-
-FORCE_INLINE_TEMPLATE U64 XXH64_endian_align(const void* input, size_t len, U64 seed, XXH_endianess endian, XXH_alignment align)
-{
- const BYTE* p = (const BYTE*)input;
- const BYTE* const bEnd = p + len;
- U64 h64;
-#define XXH_get64bits(p) XXH_readLE64_align(p, endian, align)
-
-#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
- if (p==NULL) {
- len=0;
- bEnd=p=(const BYTE*)(size_t)32;
- }
-#endif
-
- if (len>=32) {
- const BYTE* const limit = bEnd - 32;
- U64 v1 = seed + PRIME64_1 + PRIME64_2;
- U64 v2 = seed + PRIME64_2;
- U64 v3 = seed + 0;
- U64 v4 = seed - PRIME64_1;
-
- do {
- v1 = XXH64_round(v1, XXH_get64bits(p)); p+=8;
- v2 = XXH64_round(v2, XXH_get64bits(p)); p+=8;
- v3 = XXH64_round(v3, XXH_get64bits(p)); p+=8;
- v4 = XXH64_round(v4, XXH_get64bits(p)); p+=8;
- } while (p<=limit);
-
- h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
- h64 = XXH64_mergeRound(h64, v1);
- h64 = XXH64_mergeRound(h64, v2);
- h64 = XXH64_mergeRound(h64, v3);
- h64 = XXH64_mergeRound(h64, v4);
-
- } else {
- h64 = seed + PRIME64_5;
- }
-
- h64 += (U64) len;
-
- while (p+8<=bEnd) {
- U64 const k1 = XXH64_round(0, XXH_get64bits(p));
- h64 ^= k1;
- h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4;
- p+=8;
- }
-
- if (p+4<=bEnd) {
- h64 ^= (U64)(XXH_get32bits(p)) * PRIME64_1;
- h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
- p+=4;
- }
-
- while (p<bEnd) {
- h64 ^= (*p) * PRIME64_5;
- h64 = XXH_rotl64(h64, 11) * PRIME64_1;
- p++;
- }
-
- h64 ^= h64 >> 33;
- h64 *= PRIME64_2;
- h64 ^= h64 >> 29;
- h64 *= PRIME64_3;
- h64 ^= h64 >> 32;
-
- return h64;
-}
-
-
-XXH_PUBLIC_API unsigned long long XXH64 (const void* input, size_t len, unsigned long long seed)
-{
-#if 0
- /* Simple version, good for code maintenance, but unfortunately slow for small inputs */
- XXH64_CREATESTATE_STATIC(state);
- XXH64_reset(state, seed);
- XXH64_update(state, input, len);
- return XXH64_digest(state);
-#else
- XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
-
- if (XXH_FORCE_ALIGN_CHECK) {
- if ((((size_t)input) & 7)==0) { /* Input is aligned, let's leverage the speed advantage */
- if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
- return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
- else
- return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
- } }
-
- if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
- return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
- else
- return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
-#endif
-}
-
-
-/* **************************************************
-* Advanced Hash Functions
-****************************************************/
-
-XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void)
-{
- return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t));
-}
-XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr)
-{
- XXH_free(statePtr);
- return XXH_OK;
-}
-
-XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void)
-{
- return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t));
-}
-XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr)
-{
- XXH_free(statePtr);
- return XXH_OK;
-}
-
-
-/*** Hash feed ***/
-
-XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, unsigned int seed)
-{
- XXH32_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */
- memset(&state, 0, sizeof(state)-4); /* do not write into reserved, for future removal */
- state.v1 = seed + PRIME32_1 + PRIME32_2;
- state.v2 = seed + PRIME32_2;
- state.v3 = seed + 0;
- state.v4 = seed - PRIME32_1;
- memcpy(statePtr, &state, sizeof(state));
- return XXH_OK;
-}
-
-
-XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, unsigned long long seed)
-{
- XXH64_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */
- memset(&state, 0, sizeof(state)-8); /* do not write into reserved, for future removal */
- state.v1 = seed + PRIME64_1 + PRIME64_2;
- state.v2 = seed + PRIME64_2;
- state.v3 = seed + 0;
- state.v4 = seed - PRIME64_1;
- memcpy(statePtr, &state, sizeof(state));
- return XXH_OK;
-}
-
-
-FORCE_INLINE_TEMPLATE XXH_errorcode XXH32_update_endian (XXH32_state_t* state, const void* input, size_t len, XXH_endianess endian)
-{
- const BYTE* p = (const BYTE*)input;
- const BYTE* const bEnd = p + len;
-
-#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
- if (input==NULL) return XXH_ERROR;
-#endif
-
- state->total_len_32 += (unsigned)len;
- state->large_len |= (len>=16) | (state->total_len_32>=16);
-
- if (state->memsize + len < 16) { /* fill in tmp buffer */
- XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, len);
- state->memsize += (unsigned)len;
- return XXH_OK;
- }
-
- if (state->memsize) { /* some data left from previous update */
- XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, 16-state->memsize);
- { const U32* p32 = state->mem32;
- state->v1 = XXH32_round(state->v1, XXH_readLE32(p32, endian)); p32++;
- state->v2 = XXH32_round(state->v2, XXH_readLE32(p32, endian)); p32++;
- state->v3 = XXH32_round(state->v3, XXH_readLE32(p32, endian)); p32++;
- state->v4 = XXH32_round(state->v4, XXH_readLE32(p32, endian)); p32++;
- }
- p += 16-state->memsize;
- state->memsize = 0;
- }
-
- if (p <= bEnd-16) {
- const BYTE* const limit = bEnd - 16;
- U32 v1 = state->v1;
- U32 v2 = state->v2;
- U32 v3 = state->v3;
- U32 v4 = state->v4;
-
- do {
- v1 = XXH32_round(v1, XXH_readLE32(p, endian)); p+=4;
- v2 = XXH32_round(v2, XXH_readLE32(p, endian)); p+=4;
- v3 = XXH32_round(v3, XXH_readLE32(p, endian)); p+=4;
- v4 = XXH32_round(v4, XXH_readLE32(p, endian)); p+=4;
- } while (p<=limit);
-
- state->v1 = v1;
- state->v2 = v2;
- state->v3 = v3;
- state->v4 = v4;
- }
-
- if (p < bEnd) {
- XXH_memcpy(state->mem32, p, (size_t)(bEnd-p));
- state->memsize = (unsigned)(bEnd-p);
- }
-
- return XXH_OK;
-}
-
-XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* state_in, const void* input, size_t len)
-{
- XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
-
- if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
- return XXH32_update_endian(state_in, input, len, XXH_littleEndian);
- else
- return XXH32_update_endian(state_in, input, len, XXH_bigEndian);
-}
-
-
-
-FORCE_INLINE_TEMPLATE U32 XXH32_digest_endian (const XXH32_state_t* state, XXH_endianess endian)
-{
- const BYTE * p = (const BYTE*)state->mem32;
- const BYTE* const bEnd = (const BYTE*)(state->mem32) + state->memsize;
- U32 h32;
-
- if (state->large_len) {
- h32 = XXH_rotl32(state->v1, 1) + XXH_rotl32(state->v2, 7) + XXH_rotl32(state->v3, 12) + XXH_rotl32(state->v4, 18);
- } else {
- h32 = state->v3 /* == seed */ + PRIME32_5;
- }
-
- h32 += state->total_len_32;
-
- while (p+4<=bEnd) {
- h32 += XXH_readLE32(p, endian) * PRIME32_3;
- h32 = XXH_rotl32(h32, 17) * PRIME32_4;
- p+=4;
- }
-
- while (p<bEnd) {
- h32 += (*p) * PRIME32_5;
- h32 = XXH_rotl32(h32, 11) * PRIME32_1;
- p++;
- }
-
- h32 ^= h32 >> 15;
- h32 *= PRIME32_2;
- h32 ^= h32 >> 13;
- h32 *= PRIME32_3;
- h32 ^= h32 >> 16;
-
- return h32;
-}
-
-
-XXH_PUBLIC_API unsigned int XXH32_digest (const XXH32_state_t* state_in)
-{
- XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
-
- if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
- return XXH32_digest_endian(state_in, XXH_littleEndian);
- else
- return XXH32_digest_endian(state_in, XXH_bigEndian);
-}
-
-
-
-/* **** XXH64 **** */
-
-FORCE_INLINE_TEMPLATE XXH_errorcode XXH64_update_endian (XXH64_state_t* state, const void* input, size_t len, XXH_endianess endian)
-{
- const BYTE* p = (const BYTE*)input;
- const BYTE* const bEnd = p + len;
-
-#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
- if (input==NULL) return XXH_ERROR;
-#endif
-
- state->total_len += len;
-
- if (state->memsize + len < 32) { /* fill in tmp buffer */
- if (input != NULL) {
- XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, len);
- }
- state->memsize += (U32)len;
- return XXH_OK;
- }
-
- if (state->memsize) { /* tmp buffer is full */
- XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, 32-state->memsize);
- state->v1 = XXH64_round(state->v1, XXH_readLE64(state->mem64+0, endian));
- state->v2 = XXH64_round(state->v2, XXH_readLE64(state->mem64+1, endian));
- state->v3 = XXH64_round(state->v3, XXH_readLE64(state->mem64+2, endian));
- state->v4 = XXH64_round(state->v4, XXH_readLE64(state->mem64+3, endian));
- p += 32-state->memsize;
- state->memsize = 0;
- }
-
- if (p+32 <= bEnd) {
- const BYTE* const limit = bEnd - 32;
- U64 v1 = state->v1;
- U64 v2 = state->v2;
- U64 v3 = state->v3;
- U64 v4 = state->v4;
-
- do {
- v1 = XXH64_round(v1, XXH_readLE64(p, endian)); p+=8;
- v2 = XXH64_round(v2, XXH_readLE64(p, endian)); p+=8;
- v3 = XXH64_round(v3, XXH_readLE64(p, endian)); p+=8;
- v4 = XXH64_round(v4, XXH_readLE64(p, endian)); p+=8;
- } while (p<=limit);
-
- state->v1 = v1;
- state->v2 = v2;
- state->v3 = v3;
- state->v4 = v4;
- }
-
- if (p < bEnd) {
- XXH_memcpy(state->mem64, p, (size_t)(bEnd-p));
- state->memsize = (unsigned)(bEnd-p);
- }
-
- return XXH_OK;
-}
-
-XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* state_in, const void* input, size_t len)
-{
- XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
-
- if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
- return XXH64_update_endian(state_in, input, len, XXH_littleEndian);
- else
- return XXH64_update_endian(state_in, input, len, XXH_bigEndian);
-}
-
-
-
-FORCE_INLINE_TEMPLATE U64 XXH64_digest_endian (const XXH64_state_t* state, XXH_endianess endian)
-{
- const BYTE * p = (const BYTE*)state->mem64;
- const BYTE* const bEnd = (const BYTE*)state->mem64 + state->memsize;
- U64 h64;
-
- if (state->total_len >= 32) {
- U64 const v1 = state->v1;
- U64 const v2 = state->v2;
- U64 const v3 = state->v3;
- U64 const v4 = state->v4;
-
- h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
- h64 = XXH64_mergeRound(h64, v1);
- h64 = XXH64_mergeRound(h64, v2);
- h64 = XXH64_mergeRound(h64, v3);
- h64 = XXH64_mergeRound(h64, v4);
- } else {
- h64 = state->v3 + PRIME64_5;
- }
-
- h64 += (U64) state->total_len;
-
- while (p+8<=bEnd) {
- U64 const k1 = XXH64_round(0, XXH_readLE64(p, endian));
- h64 ^= k1;
- h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4;
- p+=8;
- }
-
- if (p+4<=bEnd) {
- h64 ^= (U64)(XXH_readLE32(p, endian)) * PRIME64_1;
- h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
- p+=4;
- }
-
- while (p<bEnd) {
- h64 ^= (*p) * PRIME64_5;
- h64 = XXH_rotl64(h64, 11) * PRIME64_1;
- p++;
- }
-
- h64 ^= h64 >> 33;
- h64 *= PRIME64_2;
- h64 ^= h64 >> 29;
- h64 *= PRIME64_3;
- h64 ^= h64 >> 32;
-
- return h64;
-}
-
-
-XXH_PUBLIC_API unsigned long long XXH64_digest (const XXH64_state_t* state_in)
-{
- XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
-
- if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
- return XXH64_digest_endian(state_in, XXH_littleEndian);
- else
- return XXH64_digest_endian(state_in, XXH_bigEndian);
-}
-
-
-/* **************************
-* Canonical representation
-****************************/
-
-/*! Default XXH result types are basic unsigned 32 and 64 bits.
-* The canonical representation follows human-readable write convention, aka big-endian (large digits first).
-* These functions allow transformation of hash result into and from its canonical format.
-* This way, hash values can be written into a file or buffer, and remain comparable across different systems and programs.
-*/
-
-XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash)
-{
- XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t));
- if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash);
- memcpy(dst, &hash, sizeof(*dst));
-}
-
-XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash)
-{
- XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t));
- if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash);
- memcpy(dst, &hash, sizeof(*dst));
-}
-
-XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src)
-{
- return XXH_readBE32(src);
-}
-
-XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src)
-{
- return XXH_readBE64(src);
-}
-/**** ended inlining xxhash.c ****/
-# endif
-
-#endif /* XXH_STATIC_LINKING_ONLY && XXH_STATIC_H_3543687687345 */
-
-
-#if defined (__cplusplus)
-}
-#endif
-/**** ended inlining xxhash.h ****/
-
-#if defined (__cplusplus)
-extern "C" {
-#endif
-
-/* ---- static assert (debug) --- */
-#define ZSTD_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c)
-#define FSE_isError ERR_isError
-#define HUF_isError ERR_isError
-
-
-/*-*************************************
-* shared macros
-***************************************/
-#undef MIN
-#undef MAX
-#define MIN(a,b) ((a)<(b) ? (a) : (b))
-#define MAX(a,b) ((a)>(b) ? (a) : (b))
-
-/**
- * Ignore: this is an internal helper.
- *
- * This is a helper function to help force C99-correctness during compilation.
- * Under strict compilation modes, variadic macro arguments can't be empty.
- * However, variadic function arguments can be. Using a function therefore lets
- * us statically check that at least one (string) argument was passed,
- * independent of the compilation flags.
- */
-static INLINE_KEYWORD UNUSED_ATTR
-void _force_has_format_string(const char *format, ...) {
- (void)format;
-}
-
-/**
- * Ignore: this is an internal helper.
- *
- * We want to force this function invocation to be syntactically correct, but
- * we don't want to force runtime evaluation of its arguments.
- */
-#define _FORCE_HAS_FORMAT_STRING(...) \
- if (0) { \
- _force_has_format_string(__VA_ARGS__); \
- }
-
-/**
- * Return the specified error if the condition evaluates to true.
- *
- * In debug modes, prints additional information.
- * In order to do that (particularly, printing the conditional that failed),
- * this can't just wrap RETURN_ERROR().
- */
-#define RETURN_ERROR_IF(cond, err, ...) \
- if (cond) { \
- RAWLOG(3, "%s:%d: ERROR!: check %s failed, returning %s", \
- __FILE__, __LINE__, ZSTD_QUOTE(cond), ZSTD_QUOTE(ERROR(err))); \
- _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \
- RAWLOG(3, ": " __VA_ARGS__); \
- RAWLOG(3, "\n"); \
- return ERROR(err); \
- }
-
-/**
- * Unconditionally return the specified error.
- *
- * In debug modes, prints additional information.
- */
-#define RETURN_ERROR(err, ...) \
- do { \
- RAWLOG(3, "%s:%d: ERROR!: unconditional check failed, returning %s", \
- __FILE__, __LINE__, ZSTD_QUOTE(ERROR(err))); \
- _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \
- RAWLOG(3, ": " __VA_ARGS__); \
- RAWLOG(3, "\n"); \
- return ERROR(err); \
- } while(0);
-
-/**
- * If the provided expression evaluates to an error code, returns that error code.
- *
- * In debug modes, prints additional information.
- */
-#define FORWARD_IF_ERROR(err, ...) \
- do { \
- size_t const err_code = (err); \
- if (ERR_isError(err_code)) { \
- RAWLOG(3, "%s:%d: ERROR!: forwarding error in %s: %s", \
- __FILE__, __LINE__, ZSTD_QUOTE(err), ERR_getErrorName(err_code)); \
- _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \
- RAWLOG(3, ": " __VA_ARGS__); \
- RAWLOG(3, "\n"); \
- return err_code; \
- } \
- } while(0);
-
-
-/*-*************************************
-* Common constants
-***************************************/
-#define ZSTD_OPT_NUM (1<<12)
-
-#define ZSTD_REP_NUM 3 /* number of repcodes */
-#define ZSTD_REP_MOVE (ZSTD_REP_NUM-1)
-static const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 };
-
-#define KB *(1 <<10)
-#define MB *(1 <<20)
-#define GB *(1U<<30)
-
-#define BIT7 128
-#define BIT6 64
-#define BIT5 32
-#define BIT4 16
-#define BIT1 2
-#define BIT0 1
-
-#define ZSTD_WINDOWLOG_ABSOLUTEMIN 10
-static const size_t ZSTD_fcs_fieldSize[4] = { 0, 2, 4, 8 };
-static const size_t ZSTD_did_fieldSize[4] = { 0, 1, 2, 4 };
-
-#define ZSTD_FRAMEIDSIZE 4 /* magic number size */
-
-#define ZSTD_BLOCKHEADERSIZE 3 /* C standard doesn't allow `static const` variable to be init using another `static const` variable */
-static const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE;
-typedef enum { bt_raw, bt_rle, bt_compressed, bt_reserved } blockType_e;
-
-#define ZSTD_FRAMECHECKSUMSIZE 4
-
-#define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */
-#define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */) /* for a non-null block */
-
-#define HufLog 12
-typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingType_e;
-
-#define LONGNBSEQ 0x7F00
-
-#define MINMATCH 3
-
-#define Litbits 8
-#define MaxLit ((1<<Litbits) - 1)
-#define MaxML 52
-#define MaxLL 35
-#define DefaultMaxOff 28
-#define MaxOff 31
-#define MaxSeq MAX(MaxLL, MaxML) /* Assumption : MaxOff < MaxLL,MaxML */
-#define MLFSELog 9
-#define LLFSELog 9
-#define OffFSELog 8
-#define MaxFSELog MAX(MAX(MLFSELog, LLFSELog), OffFSELog)
-
-static const U32 LL_bits[MaxLL+1] = { 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 1, 1, 1, 2, 2, 3, 3,
- 4, 6, 7, 8, 9,10,11,12,
- 13,14,15,16 };
-static const S16 LL_defaultNorm[MaxLL+1] = { 4, 3, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 1, 1, 1,
- 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 3, 2, 1, 1, 1, 1, 1,
- -1,-1,-1,-1 };
-#define LL_DEFAULTNORMLOG 6 /* for static allocation */
-static const U32 LL_defaultNormLog = LL_DEFAULTNORMLOG;
-
-static const U32 ML_bits[MaxML+1] = { 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 1, 1, 1, 2, 2, 3, 3,
- 4, 4, 5, 7, 8, 9,10,11,
- 12,13,14,15,16 };
-static const S16 ML_defaultNorm[MaxML+1] = { 1, 4, 3, 2, 2, 2, 2, 2,
- 2, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1,-1,-1,
- -1,-1,-1,-1,-1 };
-#define ML_DEFAULTNORMLOG 6 /* for static allocation */
-static const U32 ML_defaultNormLog = ML_DEFAULTNORMLOG;
-
-static const S16 OF_defaultNorm[DefaultMaxOff+1] = { 1, 1, 1, 1, 1, 1, 2, 2,
- 2, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- -1,-1,-1,-1,-1 };
-#define OF_DEFAULTNORMLOG 5 /* for static allocation */
-static const U32 OF_defaultNormLog = OF_DEFAULTNORMLOG;
-
-
-/*-*******************************************
-* Shared functions to include for inlining
-*********************************************/
-static void ZSTD_copy8(void* dst, const void* src) {
-#if !defined(ZSTD_NO_INTRINSICS) && defined(__ARM_NEON)
- vst1_u8((uint8_t*)dst, vld1_u8((const uint8_t*)src));
-#else
- memcpy(dst, src, 8);
-#endif
-}
-
-#define COPY8(d,s) { ZSTD_copy8(d,s); d+=8; s+=8; }
-static void ZSTD_copy16(void* dst, const void* src) {
-#if !defined(ZSTD_NO_INTRINSICS) && defined(__ARM_NEON)
- vst1q_u8((uint8_t*)dst, vld1q_u8((const uint8_t*)src));
-#else
- memcpy(dst, src, 16);
-#endif
-}
-#define COPY16(d,s) { ZSTD_copy16(d,s); d+=16; s+=16; }
-
-#define WILDCOPY_OVERLENGTH 32
-#define WILDCOPY_VECLEN 16
-
-typedef enum {
- ZSTD_no_overlap,
- ZSTD_overlap_src_before_dst
- /* ZSTD_overlap_dst_before_src, */
-} ZSTD_overlap_e;
-
-/*! ZSTD_wildcopy() :
- * Custom version of memcpy(), can over read/write up to WILDCOPY_OVERLENGTH bytes (if length==0)
- * @param ovtype controls the overlap detection
- * - ZSTD_no_overlap: The source and destination are guaranteed to be at least WILDCOPY_VECLEN bytes apart.
- * - ZSTD_overlap_src_before_dst: The src and dst may overlap, but they MUST be at least 8 bytes apart.
- * The src buffer must be before the dst buffer.
- */
-MEM_STATIC FORCE_INLINE_ATTR
-void ZSTD_wildcopy(void* dst, const void* src, ptrdiff_t length, ZSTD_overlap_e const ovtype)
-{
- ptrdiff_t diff = (BYTE*)dst - (const BYTE*)src;
- const BYTE* ip = (const BYTE*)src;
- BYTE* op = (BYTE*)dst;
- BYTE* const oend = op + length;
-
- assert(diff >= 8 || (ovtype == ZSTD_no_overlap && diff <= -WILDCOPY_VECLEN));
-
- if (ovtype == ZSTD_overlap_src_before_dst && diff < WILDCOPY_VECLEN) {
- /* Handle short offset copies. */
- do {
- COPY8(op, ip)
- } while (op < oend);
- } else {
- assert(diff >= WILDCOPY_VECLEN || diff <= -WILDCOPY_VECLEN);
- /* Separate out the first COPY16() call because the copy length is
- * almost certain to be short, so the branches have different
- * probabilities. Since it is almost certain to be short, only do
- * one COPY16() in the first call. Then, do two calls per loop since
- * at that point it is more likely to have a high trip count.
- */
-#ifndef __aarch64__
- do {
- COPY16(op, ip);
- }
- while (op < oend);
-#else
- COPY16(op, ip);
- if (op >= oend) return;
- do {
- COPY16(op, ip);
- COPY16(op, ip);
- }
- while (op < oend);
-#endif
- }
-}
-
-MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
-{
- size_t const length = MIN(dstCapacity, srcSize);
- if (length > 0) {
- memcpy(dst, src, length);
- }
- return length;
-}
-
-/* define "workspace is too large" as this number of times larger than needed */
-#define ZSTD_WORKSPACETOOLARGE_FACTOR 3
-
-/* when workspace is continuously too large
- * during at least this number of times,
- * context's memory usage is considered wasteful,
- * because it's sized to handle a worst case scenario which rarely happens.
- * In which case, resize it down to free some memory */
-#define ZSTD_WORKSPACETOOLARGE_MAXDURATION 128
-
-
-/*-*******************************************
-* Private declarations
-*********************************************/
-typedef struct seqDef_s {
- U32 offset;
- U16 litLength;
- U16 matchLength;
-} seqDef;
-
-typedef struct {
- seqDef* sequencesStart;
- seqDef* sequences;
- BYTE* litStart;
- BYTE* lit;
- BYTE* llCode;
- BYTE* mlCode;
- BYTE* ofCode;
- size_t maxNbSeq;
- size_t maxNbLit;
- U32 longLengthID; /* 0 == no longLength; 1 == Lit.longLength; 2 == Match.longLength; */
- U32 longLengthPos;
-} seqStore_t;
-
-typedef struct {
- U32 litLength;
- U32 matchLength;
-} ZSTD_sequenceLength;
-
-/**
- * Returns the ZSTD_sequenceLength for the given sequences. It handles the decoding of long sequences
- * indicated by longLengthPos and longLengthID, and adds MINMATCH back to matchLength.
- */
-MEM_STATIC ZSTD_sequenceLength ZSTD_getSequenceLength(seqStore_t const* seqStore, seqDef const* seq)
-{
- ZSTD_sequenceLength seqLen;
- seqLen.litLength = seq->litLength;
- seqLen.matchLength = seq->matchLength + MINMATCH;
- if (seqStore->longLengthPos == (U32)(seq - seqStore->sequencesStart)) {
- if (seqStore->longLengthID == 1) {
- seqLen.litLength += 0xFFFF;
- }
- if (seqStore->longLengthID == 2) {
- seqLen.matchLength += 0xFFFF;
- }
- }
- return seqLen;
-}
-
-/**
- * Contains the compressed frame size and an upper-bound for the decompressed frame size.
- * Note: before using `compressedSize`, check for errors using ZSTD_isError().
- * similarly, before using `decompressedBound`, check for errors using:
- * `decompressedBound != ZSTD_CONTENTSIZE_ERROR`
- */
-typedef struct {
- size_t compressedSize;
- unsigned long long decompressedBound;
-} ZSTD_frameSizeInfo; /* decompress & legacy */
-
-const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx); /* compress & dictBuilder */
-void ZSTD_seqToCodes(const seqStore_t* seqStorePtr); /* compress, dictBuilder, decodeCorpus (shouldn't get its definition from here) */
-
-/* custom memory allocation functions */
-void* ZSTD_malloc(size_t size, ZSTD_customMem customMem);
-void* ZSTD_calloc(size_t size, ZSTD_customMem customMem);
-void ZSTD_free(void* ptr, ZSTD_customMem customMem);
-
-
-MEM_STATIC U32 ZSTD_highbit32(U32 val) /* compress, dictBuilder, decodeCorpus */
-{
- assert(val != 0);
- {
-# if defined(_MSC_VER) /* Visual */
- unsigned long r=0;
- return _BitScanReverse(&r, val) ? (unsigned)r : 0;
-# elif defined(__GNUC__) && (__GNUC__ >= 3) /* GCC Intrinsic */
- return __builtin_clz (val) ^ 31;
-# elif defined(__ICCARM__) /* IAR Intrinsic */
- return 31 - __CLZ(val);
-# else /* Software version */
- static const U32 DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 };
- U32 v = val;
- v |= v >> 1;
- v |= v >> 2;
- v |= v >> 4;
- v |= v >> 8;
- v |= v >> 16;
- return DeBruijnClz[(v * 0x07C4ACDDU) >> 27];
-# endif
- }
-}
-
-
-/* ZSTD_invalidateRepCodes() :
- * ensures next compression will not use repcodes from previous block.
- * Note : only works with regular variant;
- * do not use with extDict variant ! */
-void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx); /* zstdmt, adaptive_compression (shouldn't get this definition from here) */
-
-
-typedef struct {
- blockType_e blockType;
- U32 lastBlock;
- U32 origSize;
-} blockProperties_t; /* declared here for decompress and fullbench */
-
-/*! ZSTD_getcBlockSize() :
- * Provides the size of compressed block from block header `src` */
-/* Used by: decompress, fullbench (does not get its definition from here) */
-size_t ZSTD_getcBlockSize(const void* src, size_t srcSize,
- blockProperties_t* bpPtr);
-
-/*! ZSTD_decodeSeqHeaders() :
- * decode sequence header from src */
-/* Used by: decompress, fullbench (does not get its definition from here) */
-size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr,
- const void* src, size_t srcSize);
-
-
-#if defined (__cplusplus)
-}
-#endif
-
-#endif /* ZSTD_CCOMMON_H_MODULE */
-/**** ended inlining zstd_internal.h ****/
-/**** start inlining pool.h ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-#ifndef POOL_H
-#define POOL_H
-
-#if defined (__cplusplus)
-extern "C" {
-#endif
-
-
-#include <stddef.h> /* size_t */
-#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_customMem */
-/**** skipping file: ../zstd.h ****/
-
-typedef struct POOL_ctx_s POOL_ctx;
-
-/*! POOL_create() :
- * Create a thread pool with at most `numThreads` threads.
- * `numThreads` must be at least 1.
- * The maximum number of queued jobs before blocking is `queueSize`.
- * @return : POOL_ctx pointer on success, else NULL.
-*/
-POOL_ctx* POOL_create(size_t numThreads, size_t queueSize);
-
-POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize,
- ZSTD_customMem customMem);
-
-/*! POOL_free() :
- * Free a thread pool returned by POOL_create().
- */
-void POOL_free(POOL_ctx* ctx);
-
-/*! POOL_resize() :
- * Expands or shrinks pool's number of threads.
- * This is more efficient than releasing + creating a new context,
- * since it tries to preserve and re-use existing threads.
- * `numThreads` must be at least 1.
- * @return : 0 when resize was successful,
- * !0 (typically 1) if there is an error.
- * note : only numThreads can be resized, queueSize remains unchanged.
- */
-int POOL_resize(POOL_ctx* ctx, size_t numThreads);
-
-/*! POOL_sizeof() :
- * @return threadpool memory usage
- * note : compatible with NULL (returns 0 in this case)
- */
-size_t POOL_sizeof(POOL_ctx* ctx);
-
-/*! POOL_function :
- * The function type that can be added to a thread pool.
- */
-typedef void (*POOL_function)(void*);
-
-/*! POOL_add() :
- * Add the job `function(opaque)` to the thread pool. `ctx` must be valid.
- * Possibly blocks until there is room in the queue.
- * Note : The function may be executed asynchronously,
- * therefore, `opaque` must live until function has been completed.
- */
-void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque);
-
-
-/*! POOL_tryAdd() :
- * Add the job `function(opaque)` to thread pool _if_ a worker is available.
- * Returns immediately even if not (does not block).
- * @return : 1 if successful, 0 if not.
- */
-int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque);
-
-
-#if defined (__cplusplus)
-}
-#endif
-
-#endif
-/**** ended inlining pool.h ****/
-
-/* ====== Compiler specifics ====== */
-#if defined(_MSC_VER)
-# pragma warning(disable : 4204) /* disable: C4204: non-constant aggregate initializer */
-#endif
-
-
-#ifdef ZSTD_MULTITHREAD
-
-/**** start inlining threading.h ****/
-/**
- * Copyright (c) 2016 Tino Reichardt
- * All rights reserved.
- *
- * You can contact the author at:
- * - zstdmt source repository: https://github.com/mcmilk/zstdmt
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-#ifndef THREADING_H_938743
-#define THREADING_H_938743
-
-/**** skipping file: debug.h ****/
-
-#if defined (__cplusplus)
-extern "C" {
-#endif
-
-#if defined(ZSTD_MULTITHREAD) && defined(_WIN32)
-
-/**
- * Windows minimalist Pthread Wrapper, based on :
- * http://www.cse.wustl.edu/~schmidt/win32-cv-1.html
- */
-#ifdef WINVER
-# undef WINVER
-#endif
-#define WINVER 0x0600
-
-#ifdef _WIN32_WINNT
-# undef _WIN32_WINNT
-#endif
-#define _WIN32_WINNT 0x0600
-
-#ifndef WIN32_LEAN_AND_MEAN
-# define WIN32_LEAN_AND_MEAN
-#endif
-
-#undef ERROR /* reported already defined on VS 2015 (Rich Geldreich) */
-#include <windows.h>
-#undef ERROR
-#define ERROR(name) ZSTD_ERROR(name)
-
-
-/* mutex */
-#define ZSTD_pthread_mutex_t CRITICAL_SECTION
-#define ZSTD_pthread_mutex_init(a, b) ((void)(b), InitializeCriticalSection((a)), 0)
-#define ZSTD_pthread_mutex_destroy(a) DeleteCriticalSection((a))
-#define ZSTD_pthread_mutex_lock(a) EnterCriticalSection((a))
-#define ZSTD_pthread_mutex_unlock(a) LeaveCriticalSection((a))
-
-/* condition variable */
-#define ZSTD_pthread_cond_t CONDITION_VARIABLE
-#define ZSTD_pthread_cond_init(a, b) ((void)(b), InitializeConditionVariable((a)), 0)
-#define ZSTD_pthread_cond_destroy(a) ((void)(a))
-#define ZSTD_pthread_cond_wait(a, b) SleepConditionVariableCS((a), (b), INFINITE)
-#define ZSTD_pthread_cond_signal(a) WakeConditionVariable((a))
-#define ZSTD_pthread_cond_broadcast(a) WakeAllConditionVariable((a))
-
-/* ZSTD_pthread_create() and ZSTD_pthread_join() */
-typedef struct {
- HANDLE handle;
- void* (*start_routine)(void*);
- void* arg;
-} ZSTD_pthread_t;
-
-int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused,
- void* (*start_routine) (void*), void* arg);
-
-int ZSTD_pthread_join(ZSTD_pthread_t thread, void** value_ptr);
-
-/**
- * add here more wrappers as required
- */
-
-
-#elif defined(ZSTD_MULTITHREAD) /* posix assumed ; need a better detection method */
-/* === POSIX Systems === */
-# include <pthread.h>
-
-#if DEBUGLEVEL < 1
-
-#define ZSTD_pthread_mutex_t pthread_mutex_t
-#define ZSTD_pthread_mutex_init(a, b) pthread_mutex_init((a), (b))
-#define ZSTD_pthread_mutex_destroy(a) pthread_mutex_destroy((a))
-#define ZSTD_pthread_mutex_lock(a) pthread_mutex_lock((a))
-#define ZSTD_pthread_mutex_unlock(a) pthread_mutex_unlock((a))
-
-#define ZSTD_pthread_cond_t pthread_cond_t
-#define ZSTD_pthread_cond_init(a, b) pthread_cond_init((a), (b))
-#define ZSTD_pthread_cond_destroy(a) pthread_cond_destroy((a))
-#define ZSTD_pthread_cond_wait(a, b) pthread_cond_wait((a), (b))
-#define ZSTD_pthread_cond_signal(a) pthread_cond_signal((a))
-#define ZSTD_pthread_cond_broadcast(a) pthread_cond_broadcast((a))
-
-#define ZSTD_pthread_t pthread_t
-#define ZSTD_pthread_create(a, b, c, d) pthread_create((a), (b), (c), (d))
-#define ZSTD_pthread_join(a, b) pthread_join((a),(b))
-
-#else /* DEBUGLEVEL >= 1 */
-
-/* Debug implementation of threading.
- * In this implementation we use pointers for mutexes and condition variables.
- * This way, if we forget to init/destroy them the program will crash or ASAN
- * will report leaks.
- */
-
-#define ZSTD_pthread_mutex_t pthread_mutex_t*
-int ZSTD_pthread_mutex_init(ZSTD_pthread_mutex_t* mutex, pthread_mutexattr_t const* attr);
-int ZSTD_pthread_mutex_destroy(ZSTD_pthread_mutex_t* mutex);
-#define ZSTD_pthread_mutex_lock(a) pthread_mutex_lock(*(a))
-#define ZSTD_pthread_mutex_unlock(a) pthread_mutex_unlock(*(a))
-
-#define ZSTD_pthread_cond_t pthread_cond_t*
-int ZSTD_pthread_cond_init(ZSTD_pthread_cond_t* cond, pthread_condattr_t const* attr);
-int ZSTD_pthread_cond_destroy(ZSTD_pthread_cond_t* cond);
-#define ZSTD_pthread_cond_wait(a, b) pthread_cond_wait(*(a), *(b))
-#define ZSTD_pthread_cond_signal(a) pthread_cond_signal(*(a))
-#define ZSTD_pthread_cond_broadcast(a) pthread_cond_broadcast(*(a))
-
-#define ZSTD_pthread_t pthread_t
-#define ZSTD_pthread_create(a, b, c, d) pthread_create((a), (b), (c), (d))
-#define ZSTD_pthread_join(a, b) pthread_join((a),(b))
-
-#endif
-
-#else /* ZSTD_MULTITHREAD not defined */
-/* No multithreading support */
-
-typedef int ZSTD_pthread_mutex_t;
-#define ZSTD_pthread_mutex_init(a, b) ((void)(a), (void)(b), 0)
-#define ZSTD_pthread_mutex_destroy(a) ((void)(a))
-#define ZSTD_pthread_mutex_lock(a) ((void)(a))
-#define ZSTD_pthread_mutex_unlock(a) ((void)(a))
-
-typedef int ZSTD_pthread_cond_t;
-#define ZSTD_pthread_cond_init(a, b) ((void)(a), (void)(b), 0)
-#define ZSTD_pthread_cond_destroy(a) ((void)(a))
-#define ZSTD_pthread_cond_wait(a, b) ((void)(a), (void)(b))
-#define ZSTD_pthread_cond_signal(a) ((void)(a))
-#define ZSTD_pthread_cond_broadcast(a) ((void)(a))
-
-/* do not use ZSTD_pthread_t */
-
-#endif /* ZSTD_MULTITHREAD */
-
-#if defined (__cplusplus)
-}
-#endif
-
-#endif /* THREADING_H_938743 */
-/**** ended inlining threading.h ****/
-
-/* A job is a function and an opaque argument */
-typedef struct POOL_job_s {
- POOL_function function;
- void *opaque;
-} POOL_job;
-
-struct POOL_ctx_s {
- ZSTD_customMem customMem;
- /* Keep track of the threads */
- ZSTD_pthread_t* threads;
- size_t threadCapacity;
- size_t threadLimit;
-
- /* The queue is a circular buffer */
- POOL_job *queue;
- size_t queueHead;
- size_t queueTail;
- size_t queueSize;
-
- /* The number of threads working on jobs */
- size_t numThreadsBusy;
- /* Indicates if the queue is empty */
- int queueEmpty;
-
- /* The mutex protects the queue */
- ZSTD_pthread_mutex_t queueMutex;
- /* Condition variable for pushers to wait on when the queue is full */
- ZSTD_pthread_cond_t queuePushCond;
- /* Condition variables for poppers to wait on when the queue is empty */
- ZSTD_pthread_cond_t queuePopCond;
- /* Indicates if the queue is shutting down */
- int shutdown;
-};
-
-/* POOL_thread() :
- * Work thread for the thread pool.
- * Waits for jobs and executes them.
- * @returns : NULL on failure else non-null.
- */
-static void* POOL_thread(void* opaque) {
- POOL_ctx* const ctx = (POOL_ctx*)opaque;
- if (!ctx) { return NULL; }
- for (;;) {
- /* Lock the mutex and wait for a non-empty queue or until shutdown */
- ZSTD_pthread_mutex_lock(&ctx->queueMutex);
-
- while ( ctx->queueEmpty
- || (ctx->numThreadsBusy >= ctx->threadLimit) ) {
- if (ctx->shutdown) {
- /* even if !queueEmpty, (possible if numThreadsBusy >= threadLimit),
- * a few threads will be shutdown while !queueEmpty,
- * but enough threads will remain active to finish the queue */
- ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
- return opaque;
- }
- ZSTD_pthread_cond_wait(&ctx->queuePopCond, &ctx->queueMutex);
- }
- /* Pop a job off the queue */
- { POOL_job const job = ctx->queue[ctx->queueHead];
- ctx->queueHead = (ctx->queueHead + 1) % ctx->queueSize;
- ctx->numThreadsBusy++;
- ctx->queueEmpty = ctx->queueHead == ctx->queueTail;
- /* Unlock the mutex, signal a pusher, and run the job */
- ZSTD_pthread_cond_signal(&ctx->queuePushCond);
- ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
-
- job.function(job.opaque);
-
- /* If the intended queue size was 0, signal after finishing job */
- ZSTD_pthread_mutex_lock(&ctx->queueMutex);
- ctx->numThreadsBusy--;
- if (ctx->queueSize == 1) {
- ZSTD_pthread_cond_signal(&ctx->queuePushCond);
- }
- ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
- }
- } /* for (;;) */
- assert(0); /* Unreachable */
-}
-
-POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) {
- return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem);
-}
-
-POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize,
- ZSTD_customMem customMem) {
- POOL_ctx* ctx;
- /* Check parameters */
- if (!numThreads) { return NULL; }
- /* Allocate the context and zero initialize */
- ctx = (POOL_ctx*)ZSTD_calloc(sizeof(POOL_ctx), customMem);
- if (!ctx) { return NULL; }
- /* Initialize the job queue.
- * It needs one extra space since one space is wasted to differentiate
- * empty and full queues.
- */
- ctx->queueSize = queueSize + 1;
- ctx->queue = (POOL_job*)ZSTD_malloc(ctx->queueSize * sizeof(POOL_job), customMem);
- ctx->queueHead = 0;
- ctx->queueTail = 0;
- ctx->numThreadsBusy = 0;
- ctx->queueEmpty = 1;
- {
- int error = 0;
- error |= ZSTD_pthread_mutex_init(&ctx->queueMutex, NULL);
- error |= ZSTD_pthread_cond_init(&ctx->queuePushCond, NULL);
- error |= ZSTD_pthread_cond_init(&ctx->queuePopCond, NULL);
- if (error) { POOL_free(ctx); return NULL; }
- }
- ctx->shutdown = 0;
- /* Allocate space for the thread handles */
- ctx->threads = (ZSTD_pthread_t*)ZSTD_malloc(numThreads * sizeof(ZSTD_pthread_t), customMem);
- ctx->threadCapacity = 0;
- ctx->customMem = customMem;
- /* Check for errors */
- if (!ctx->threads || !ctx->queue) { POOL_free(ctx); return NULL; }
- /* Initialize the threads */
- { size_t i;
- for (i = 0; i < numThreads; ++i) {
- if (ZSTD_pthread_create(&ctx->threads[i], NULL, &POOL_thread, ctx)) {
- ctx->threadCapacity = i;
- POOL_free(ctx);
- return NULL;
- } }
- ctx->threadCapacity = numThreads;
- ctx->threadLimit = numThreads;
- }
- return ctx;
-}
-
-/*! POOL_join() :
- Shutdown the queue, wake any sleeping threads, and join all of the threads.
-*/
-static void POOL_join(POOL_ctx* ctx) {
- /* Shut down the queue */
- ZSTD_pthread_mutex_lock(&ctx->queueMutex);
- ctx->shutdown = 1;
- ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
- /* Wake up sleeping threads */
- ZSTD_pthread_cond_broadcast(&ctx->queuePushCond);
- ZSTD_pthread_cond_broadcast(&ctx->queuePopCond);
- /* Join all of the threads */
- { size_t i;
- for (i = 0; i < ctx->threadCapacity; ++i) {
- ZSTD_pthread_join(ctx->threads[i], NULL); /* note : could fail */
- } }
-}
-
-void POOL_free(POOL_ctx *ctx) {
- if (!ctx) { return; }
- POOL_join(ctx);
- ZSTD_pthread_mutex_destroy(&ctx->queueMutex);
- ZSTD_pthread_cond_destroy(&ctx->queuePushCond);
- ZSTD_pthread_cond_destroy(&ctx->queuePopCond);
- ZSTD_free(ctx->queue, ctx->customMem);
- ZSTD_free(ctx->threads, ctx->customMem);
- ZSTD_free(ctx, ctx->customMem);
-}
-
-
-
-size_t POOL_sizeof(POOL_ctx *ctx) {
- if (ctx==NULL) return 0; /* supports sizeof NULL */
- return sizeof(*ctx)
- + ctx->queueSize * sizeof(POOL_job)
- + ctx->threadCapacity * sizeof(ZSTD_pthread_t);
-}
-
-
-/* @return : 0 on success, 1 on error */
-static int POOL_resize_internal(POOL_ctx* ctx, size_t numThreads)
-{
- if (numThreads <= ctx->threadCapacity) {
- if (!numThreads) return 1;
- ctx->threadLimit = numThreads;
- return 0;
- }
- /* numThreads > threadCapacity */
- { ZSTD_pthread_t* const threadPool = (ZSTD_pthread_t*)ZSTD_malloc(numThreads * sizeof(ZSTD_pthread_t), ctx->customMem);
- if (!threadPool) return 1;
- /* replace existing thread pool */
- memcpy(threadPool, ctx->threads, ctx->threadCapacity * sizeof(*threadPool));
- ZSTD_free(ctx->threads, ctx->customMem);
- ctx->threads = threadPool;
- /* Initialize additional threads */
- { size_t threadId;
- for (threadId = ctx->threadCapacity; threadId < numThreads; ++threadId) {
- if (ZSTD_pthread_create(&threadPool[threadId], NULL, &POOL_thread, ctx)) {
- ctx->threadCapacity = threadId;
- return 1;
- } }
- } }
- /* successfully expanded */
- ctx->threadCapacity = numThreads;
- ctx->threadLimit = numThreads;
- return 0;
-}
-
-/* @return : 0 on success, 1 on error */
-int POOL_resize(POOL_ctx* ctx, size_t numThreads)
-{
- int result;
- if (ctx==NULL) return 1;
- ZSTD_pthread_mutex_lock(&ctx->queueMutex);
- result = POOL_resize_internal(ctx, numThreads);
- ZSTD_pthread_cond_broadcast(&ctx->queuePopCond);
- ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
- return result;
-}
-
-/**
- * Returns 1 if the queue is full and 0 otherwise.
- *
- * When queueSize is 1 (pool was created with an intended queueSize of 0),
- * then a queue is empty if there is a thread free _and_ no job is waiting.
- */
-static int isQueueFull(POOL_ctx const* ctx) {
- if (ctx->queueSize > 1) {
- return ctx->queueHead == ((ctx->queueTail + 1) % ctx->queueSize);
- } else {
- return (ctx->numThreadsBusy == ctx->threadLimit) ||
- !ctx->queueEmpty;
- }
-}
-
-
-static void POOL_add_internal(POOL_ctx* ctx, POOL_function function, void *opaque)
-{
- POOL_job const job = {function, opaque};
- assert(ctx != NULL);
- if (ctx->shutdown) return;
-
- ctx->queueEmpty = 0;
- ctx->queue[ctx->queueTail] = job;
- ctx->queueTail = (ctx->queueTail + 1) % ctx->queueSize;
- ZSTD_pthread_cond_signal(&ctx->queuePopCond);
-}
-
-void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque)
-{
- assert(ctx != NULL);
- ZSTD_pthread_mutex_lock(&ctx->queueMutex);
- /* Wait until there is space in the queue for the new job */
- while (isQueueFull(ctx) && (!ctx->shutdown)) {
- ZSTD_pthread_cond_wait(&ctx->queuePushCond, &ctx->queueMutex);
- }
- POOL_add_internal(ctx, function, opaque);
- ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
-}
-
-
-int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque)
-{
- assert(ctx != NULL);
- ZSTD_pthread_mutex_lock(&ctx->queueMutex);
- if (isQueueFull(ctx)) {
- ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
- return 0;
- }
- POOL_add_internal(ctx, function, opaque);
- ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
- return 1;
-}
-
-
-#else /* ZSTD_MULTITHREAD not defined */
-
-/* ========================== */
-/* No multi-threading support */
-/* ========================== */
-
-
-/* We don't need any data, but if it is empty, malloc() might return NULL. */
-struct POOL_ctx_s {
- int dummy;
-};
-static POOL_ctx g_ctx;
-
-POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) {
- return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem);
-}
-
-POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customMem customMem) {
- (void)numThreads;
- (void)queueSize;
- (void)customMem;
- return &g_ctx;
-}
-
-void POOL_free(POOL_ctx* ctx) {
- assert(!ctx || ctx == &g_ctx);
- (void)ctx;
-}
-
-int POOL_resize(POOL_ctx* ctx, size_t numThreads) {
- (void)ctx; (void)numThreads;
- return 0;
-}
-
-void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque) {
- (void)ctx;
- function(opaque);
-}
-
-int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque) {
- (void)ctx;
- function(opaque);
- return 1;
-}
-
-size_t POOL_sizeof(POOL_ctx* ctx) {
- if (ctx==NULL) return 0; /* supports sizeof NULL */
- assert(ctx == &g_ctx);
- return sizeof(*ctx);
-}
-
-#endif /* ZSTD_MULTITHREAD */
-/**** ended inlining common/pool.c ****/
-/**** start inlining common/zstd_common.c ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-
-
-/*-*************************************
-* Dependencies
-***************************************/
-#include <stdlib.h> /* malloc, calloc, free */
-#include <string.h> /* memset */
-/**** skipping file: error_private.h ****/
-/**** skipping file: zstd_internal.h ****/
-
-
-/*-****************************************
-* Version
-******************************************/
-unsigned ZSTD_versionNumber(void) { return ZSTD_VERSION_NUMBER; }
-
-const char* ZSTD_versionString(void) { return ZSTD_VERSION_STRING; }
-
-
-/*-****************************************
-* ZSTD Error Management
-******************************************/
-/*! ZSTD_isError() :
- * tells if a return value is an error code
- * symbol is required for external callers */
-unsigned ZSTD_isError(size_t code) { return ERR_isError(code); }
-
-/*! ZSTD_getErrorName() :
- * provides error code string from function result (useful for debugging) */
-const char* ZSTD_getErrorName(size_t code) { return ERR_getErrorName(code); }
-
-/*! ZSTD_getError() :
- * convert a `size_t` function result into a proper ZSTD_errorCode enum */
-ZSTD_ErrorCode ZSTD_getErrorCode(size_t code) { return ERR_getErrorCode(code); }
-
-/*! ZSTD_getErrorString() :
- * provides error code string from enum */
-const char* ZSTD_getErrorString(ZSTD_ErrorCode code) { return ERR_getErrorString(code); }
-
-
-
-/*=**************************************************************
-* Custom allocator
-****************************************************************/
-void* ZSTD_malloc(size_t size, ZSTD_customMem customMem)
-{
- if (customMem.customAlloc)
- return customMem.customAlloc(customMem.opaque, size);
- return malloc(size);
-}
-
-void* ZSTD_calloc(size_t size, ZSTD_customMem customMem)
-{
- if (customMem.customAlloc) {
- /* calloc implemented as malloc+memset;
- * not as efficient as calloc, but next best guess for custom malloc */
- void* const ptr = customMem.customAlloc(customMem.opaque, size);
- memset(ptr, 0, size);
- return ptr;
- }
- return calloc(1, size);
-}
-
-void ZSTD_free(void* ptr, ZSTD_customMem customMem)
-{
- if (ptr!=NULL) {
- if (customMem.customFree)
- customMem.customFree(customMem.opaque, ptr);
- else
- free(ptr);
- }
-}
-/**** ended inlining common/zstd_common.c ****/
-
-/**** start inlining compress/fse_compress.c ****/
-/* ******************************************************************
- * FSE : Finite State Entropy encoder
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
- *
- * You can contact the author at :
- * - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
- * - Public forum : https://groups.google.com/forum/#!forum/lz4c
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
-****************************************************************** */
-
-/* **************************************************************
-* Includes
-****************************************************************/
-#include <stdlib.h> /* malloc, free, qsort */
-#include <string.h> /* memcpy, memset */
-/**** skipping file: ../common/compiler.h ****/
-/**** skipping file: ../common/mem.h ****/
-/**** skipping file: ../common/debug.h ****/
-/**** start inlining hist.h ****/
-/* ******************************************************************
- * hist : Histogram functions
- * part of Finite State Entropy project
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
- *
- * You can contact the author at :
- * - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
- * - Public forum : https://groups.google.com/forum/#!forum/lz4c
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
-****************************************************************** */
-
-/* --- dependencies --- */
-#include <stddef.h> /* size_t */
-
-
-/* --- simple histogram functions --- */
-
-/*! HIST_count():
- * Provides the precise count of each byte within a table 'count'.
- * 'count' is a table of unsigned int, of minimum size (*maxSymbolValuePtr+1).
- * Updates *maxSymbolValuePtr with actual largest symbol value detected.
- * @return : count of the most frequent symbol (which isn't identified).
- * or an error code, which can be tested using HIST_isError().
- * note : if return == srcSize, there is only one symbol.
- */
-size_t HIST_count(unsigned* count, unsigned* maxSymbolValuePtr,
- const void* src, size_t srcSize);
-
-unsigned HIST_isError(size_t code); /**< tells if a return value is an error code */
-
-
-/* --- advanced histogram functions --- */
-
-#define HIST_WKSP_SIZE_U32 1024
-#define HIST_WKSP_SIZE (HIST_WKSP_SIZE_U32 * sizeof(unsigned))
-/** HIST_count_wksp() :
- * Same as HIST_count(), but using an externally provided scratch buffer.
- * Benefit is this function will use very little stack space.
- * `workSpace` is a writable buffer which must be 4-bytes aligned,
- * `workSpaceSize` must be >= HIST_WKSP_SIZE
- */
-size_t HIST_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
- const void* src, size_t srcSize,
- void* workSpace, size_t workSpaceSize);
-
-/** HIST_countFast() :
- * same as HIST_count(), but blindly trusts that all byte values within src are <= *maxSymbolValuePtr.
- * This function is unsafe, and will segfault if any value within `src` is `> *maxSymbolValuePtr`
- */
-size_t HIST_countFast(unsigned* count, unsigned* maxSymbolValuePtr,
- const void* src, size_t srcSize);
-
-/** HIST_countFast_wksp() :
- * Same as HIST_countFast(), but using an externally provided scratch buffer.
- * `workSpace` is a writable buffer which must be 4-bytes aligned,
- * `workSpaceSize` must be >= HIST_WKSP_SIZE
- */
-size_t HIST_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
- const void* src, size_t srcSize,
- void* workSpace, size_t workSpaceSize);
-
-/*! HIST_count_simple() :
- * Same as HIST_countFast(), this function is unsafe,
- * and will segfault if any value within `src` is `> *maxSymbolValuePtr`.
- * It is also a bit slower for large inputs.
- * However, it does not need any additional memory (not even on stack).
- * @return : count of the most frequent symbol.
- * Note this function doesn't produce any error (i.e. it must succeed).
- */
-unsigned HIST_count_simple(unsigned* count, unsigned* maxSymbolValuePtr,
- const void* src, size_t srcSize);
-/**** ended inlining hist.h ****/
-/**** skipping file: ../common/bitstream.h ****/
-#define FSE_STATIC_LINKING_ONLY
-/**** skipping file: ../common/fse.h ****/
-/**** skipping file: ../common/error_private.h ****/
-
-
-/* **************************************************************
-* Error Management
-****************************************************************/
-#define FSE_isError ERR_isError
-
-
-/* **************************************************************
-* Templates
-****************************************************************/
-/*
- designed to be included
- for type-specific functions (template emulation in C)
- Objective is to write these functions only once, for improved maintenance
-*/
-
-/* safety checks */
-#ifndef FSE_FUNCTION_EXTENSION
-# error "FSE_FUNCTION_EXTENSION must be defined"
-#endif
-#ifndef FSE_FUNCTION_TYPE
-# error "FSE_FUNCTION_TYPE must be defined"
-#endif
-
-/* Function names */
-#define FSE_CAT(X,Y) X##Y
-#define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y)
-#define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y)
-
-
-/* Function templates */
-
-/* FSE_buildCTable_wksp() :
- * Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`).
- * wkspSize should be sized to handle worst case situation, which is `1<<max_tableLog * sizeof(FSE_FUNCTION_TYPE)`
- * workSpace must also be properly aligned with FSE_FUNCTION_TYPE requirements
- */
-size_t FSE_buildCTable_wksp(FSE_CTable* ct,
- const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog,
- void* workSpace, size_t wkspSize)
-{
- U32 const tableSize = 1 << tableLog;
- U32 const tableMask = tableSize - 1;
- void* const ptr = ct;
- U16* const tableU16 = ( (U16*) ptr) + 2;
- void* const FSCT = ((U32*)ptr) + 1 /* header */ + (tableLog ? tableSize>>1 : 1) ;
- FSE_symbolCompressionTransform* const symbolTT = (FSE_symbolCompressionTransform*) (FSCT);
- U32 const step = FSE_TABLESTEP(tableSize);
- U32 cumul[FSE_MAX_SYMBOL_VALUE+2];
-
- FSE_FUNCTION_TYPE* const tableSymbol = (FSE_FUNCTION_TYPE*)workSpace;
- U32 highThreshold = tableSize-1;
-
- /* CTable header */
- if (((size_t)1 << tableLog) * sizeof(FSE_FUNCTION_TYPE) > wkspSize) return ERROR(tableLog_tooLarge);
- tableU16[-2] = (U16) tableLog;
- tableU16[-1] = (U16) maxSymbolValue;
- assert(tableLog < 16); /* required for threshold strategy to work */
-
- /* For explanations on how to distribute symbol values over the table :
- * http://fastcompression.blogspot.fr/2014/02/fse-distributing-symbol-values.html */
-
- #ifdef __clang_analyzer__
- memset(tableSymbol, 0, sizeof(*tableSymbol) * tableSize); /* useless initialization, just to keep scan-build happy */
- #endif
-
- /* symbol start positions */
- { U32 u;
- cumul[0] = 0;
- for (u=1; u <= maxSymbolValue+1; u++) {
- if (normalizedCounter[u-1]==-1) { /* Low proba symbol */
- cumul[u] = cumul[u-1] + 1;
- tableSymbol[highThreshold--] = (FSE_FUNCTION_TYPE)(u-1);
- } else {
- cumul[u] = cumul[u-1] + normalizedCounter[u-1];
- } }
- cumul[maxSymbolValue+1] = tableSize+1;
- }
-
- /* Spread symbols */
- { U32 position = 0;
- U32 symbol;
- for (symbol=0; symbol<=maxSymbolValue; symbol++) {
- int nbOccurrences;
- int const freq = normalizedCounter[symbol];
- for (nbOccurrences=0; nbOccurrences<freq; nbOccurrences++) {
- tableSymbol[position] = (FSE_FUNCTION_TYPE)symbol;
- position = (position + step) & tableMask;
- while (position > highThreshold)
- position = (position + step) & tableMask; /* Low proba area */
- } }
-
- assert(position==0); /* Must have initialized all positions */
- }
-
- /* Build table */
- { U32 u; for (u=0; u<tableSize; u++) {
- FSE_FUNCTION_TYPE s = tableSymbol[u]; /* note : static analyzer may not understand tableSymbol is properly initialized */
- tableU16[cumul[s]++] = (U16) (tableSize+u); /* TableU16 : sorted by symbol order; gives next state value */
- } }
-
- /* Build Symbol Transformation Table */
- { unsigned total = 0;
- unsigned s;
- for (s=0; s<=maxSymbolValue; s++) {
- switch (normalizedCounter[s])
- {
- case 0:
- /* filling nonetheless, for compatibility with FSE_getMaxNbBits() */
- symbolTT[s].deltaNbBits = ((tableLog+1) << 16) - (1<<tableLog);
- break;
-
- case -1:
- case 1:
- symbolTT[s].deltaNbBits = (tableLog << 16) - (1<<tableLog);
- symbolTT[s].deltaFindState = total - 1;
- total ++;
- break;
- default :
- {
- U32 const maxBitsOut = tableLog - BIT_highbit32 (normalizedCounter[s]-1);
- U32 const minStatePlus = normalizedCounter[s] << maxBitsOut;
- symbolTT[s].deltaNbBits = (maxBitsOut << 16) - minStatePlus;
- symbolTT[s].deltaFindState = total - normalizedCounter[s];
- total += normalizedCounter[s];
- } } } }
-
-#if 0 /* debug : symbol costs */
- DEBUGLOG(5, "\n --- table statistics : ");
- { U32 symbol;
- for (symbol=0; symbol<=maxSymbolValue; symbol++) {
- DEBUGLOG(5, "%3u: w=%3i, maxBits=%u, fracBits=%.2f",
- symbol, normalizedCounter[symbol],
- FSE_getMaxNbBits(symbolTT, symbol),
- (double)FSE_bitCost(symbolTT, tableLog, symbol, 8) / 256);
- }
- }
-#endif
-
- return 0;
-}
-
-
-size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)
-{
- FSE_FUNCTION_TYPE tableSymbol[FSE_MAX_TABLESIZE]; /* memset() is not necessary, even if static analyzer complain about it */
- return FSE_buildCTable_wksp(ct, normalizedCounter, maxSymbolValue, tableLog, tableSymbol, sizeof(tableSymbol));
-}
-
-
-
-#ifndef FSE_COMMONDEFS_ONLY
-
-
-/*-**************************************************************
-* FSE NCount encoding
-****************************************************************/
-size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog)
-{
- size_t const maxHeaderSize = (((maxSymbolValue+1) * tableLog) >> 3) + 3;
- return maxSymbolValue ? maxHeaderSize : FSE_NCOUNTBOUND; /* maxSymbolValue==0 ? use default */
-}
-
-static size_t
-FSE_writeNCount_generic (void* header, size_t headerBufferSize,
- const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog,
- unsigned writeIsSafe)
-{
- BYTE* const ostart = (BYTE*) header;
- BYTE* out = ostart;
- BYTE* const oend = ostart + headerBufferSize;
- int nbBits;
- const int tableSize = 1 << tableLog;
- int remaining;
- int threshold;
- U32 bitStream = 0;
- int bitCount = 0;
- unsigned symbol = 0;
- unsigned const alphabetSize = maxSymbolValue + 1;
- int previousIs0 = 0;
-
- /* Table Size */
- bitStream += (tableLog-FSE_MIN_TABLELOG) << bitCount;
- bitCount += 4;
-
- /* Init */
- remaining = tableSize+1; /* +1 for extra accuracy */
- threshold = tableSize;
- nbBits = tableLog+1;
-
- while ((symbol < alphabetSize) && (remaining>1)) { /* stops at 1 */
- if (previousIs0) {
- unsigned start = symbol;
- while ((symbol < alphabetSize) && !normalizedCounter[symbol]) symbol++;
- if (symbol == alphabetSize) break; /* incorrect distribution */
- while (symbol >= start+24) {
- start+=24;
- bitStream += 0xFFFFU << bitCount;
- if ((!writeIsSafe) && (out > oend-2))
- return ERROR(dstSize_tooSmall); /* Buffer overflow */
- out[0] = (BYTE) bitStream;
- out[1] = (BYTE)(bitStream>>8);
- out+=2;
- bitStream>>=16;
- }
- while (symbol >= start+3) {
- start+=3;
- bitStream += 3 << bitCount;
- bitCount += 2;
- }
- bitStream += (symbol-start) << bitCount;
- bitCount += 2;
- if (bitCount>16) {
- if ((!writeIsSafe) && (out > oend - 2))
- return ERROR(dstSize_tooSmall); /* Buffer overflow */
- out[0] = (BYTE)bitStream;
- out[1] = (BYTE)(bitStream>>8);
- out += 2;
- bitStream >>= 16;
- bitCount -= 16;
- } }
- { int count = normalizedCounter[symbol++];
- int const max = (2*threshold-1) - remaining;
- remaining -= count < 0 ? -count : count;
- count++; /* +1 for extra accuracy */
- if (count>=threshold)
- count += max; /* [0..max[ [max..threshold[ (...) [threshold+max 2*threshold[ */
- bitStream += count << bitCount;
- bitCount += nbBits;
- bitCount -= (count<max);
- previousIs0 = (count==1);
- if (remaining<1) return ERROR(GENERIC);
- while (remaining<threshold) { nbBits--; threshold>>=1; }
- }
- if (bitCount>16) {
- if ((!writeIsSafe) && (out > oend - 2))
- return ERROR(dstSize_tooSmall); /* Buffer overflow */
- out[0] = (BYTE)bitStream;
- out[1] = (BYTE)(bitStream>>8);
- out += 2;
- bitStream >>= 16;
- bitCount -= 16;
- } }
-
- if (remaining != 1)
- return ERROR(GENERIC); /* incorrect normalized distribution */
- assert(symbol <= alphabetSize);
-
- /* flush remaining bitStream */
- if ((!writeIsSafe) && (out > oend - 2))
- return ERROR(dstSize_tooSmall); /* Buffer overflow */
- out[0] = (BYTE)bitStream;
- out[1] = (BYTE)(bitStream>>8);
- out+= (bitCount+7) /8;
-
- return (out-ostart);
-}
-
-
-size_t FSE_writeNCount (void* buffer, size_t bufferSize,
- const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)
-{
- if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); /* Unsupported */
- if (tableLog < FSE_MIN_TABLELOG) return ERROR(GENERIC); /* Unsupported */
-
- if (bufferSize < FSE_NCountWriteBound(maxSymbolValue, tableLog))
- return FSE_writeNCount_generic(buffer, bufferSize, normalizedCounter, maxSymbolValue, tableLog, 0);
-
- return FSE_writeNCount_generic(buffer, bufferSize, normalizedCounter, maxSymbolValue, tableLog, 1 /* write in buffer is safe */);
-}
-
-
-/*-**************************************************************
-* FSE Compression Code
-****************************************************************/
-
-FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog)
-{
- size_t size;
- 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);
-}
-
-void FSE_freeCTable (FSE_CTable* ct) { free(ct); }
-
-/* provides the minimum logSize to safely represent a distribution */
-static unsigned FSE_minTableLog(size_t srcSize, unsigned maxSymbolValue)
-{
- U32 minBitsSrc = BIT_highbit32((U32)(srcSize)) + 1;
- U32 minBitsSymbols = BIT_highbit32(maxSymbolValue) + 2;
- U32 minBits = minBitsSrc < minBitsSymbols ? minBitsSrc : minBitsSymbols;
- assert(srcSize > 1); /* Not supported, RLE should be used instead */
- return minBits;
-}
-
-unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus)
-{
- U32 maxBitsSrc = BIT_highbit32((U32)(srcSize - 1)) - minus;
- U32 tableLog = maxTableLog;
- U32 minBits = FSE_minTableLog(srcSize, maxSymbolValue);
- assert(srcSize > 1); /* Not supported, RLE should be used instead */
- if (tableLog==0) tableLog = FSE_DEFAULT_TABLELOG;
- if (maxBitsSrc < tableLog) tableLog = maxBitsSrc; /* Accuracy can be reduced */
- if (minBits > tableLog) tableLog = minBits; /* Need a minimum to safely represent all symbol values */
- if (tableLog < FSE_MIN_TABLELOG) tableLog = FSE_MIN_TABLELOG;
- if (tableLog > FSE_MAX_TABLELOG) tableLog = FSE_MAX_TABLELOG;
- return tableLog;
-}
-
-unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue)
-{
- return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 2);
-}
-
-
-/* Secondary normalization method.
- To be used when primary method fails. */
-
-static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, size_t total, U32 maxSymbolValue)
-{
- short const NOT_YET_ASSIGNED = -2;
- U32 s;
- U32 distributed = 0;
- U32 ToDistribute;
-
- /* Init */
- U32 const lowThreshold = (U32)(total >> tableLog);
- U32 lowOne = (U32)((total * 3) >> (tableLog + 1));
-
- for (s=0; s<=maxSymbolValue; s++) {
- if (count[s] == 0) {
- norm[s]=0;
- continue;
- }
- if (count[s] <= lowThreshold) {
- norm[s] = -1;
- distributed++;
- total -= count[s];
- continue;
- }
- if (count[s] <= lowOne) {
- norm[s] = 1;
- distributed++;
- total -= count[s];
- continue;
- }
-
- norm[s]=NOT_YET_ASSIGNED;
- }
- ToDistribute = (1 << tableLog) - distributed;
-
- if (ToDistribute == 0)
- return 0;
-
- if ((total / ToDistribute) > lowOne) {
- /* risk of rounding to zero */
- lowOne = (U32)((total * 3) / (ToDistribute * 2));
- for (s=0; s<=maxSymbolValue; s++) {
- if ((norm[s] == NOT_YET_ASSIGNED) && (count[s] <= lowOne)) {
- norm[s] = 1;
- distributed++;
- total -= count[s];
- continue;
- } }
- ToDistribute = (1 << tableLog) - distributed;
- }
-
- if (distributed == maxSymbolValue+1) {
- /* all values are pretty poor;
- probably incompressible data (should have already been detected);
- find max, then give all remaining points to max */
- U32 maxV = 0, maxC = 0;
- for (s=0; s<=maxSymbolValue; s++)
- if (count[s] > maxC) { maxV=s; maxC=count[s]; }
- norm[maxV] += (short)ToDistribute;
- return 0;
- }
-
- if (total == 0) {
- /* all of the symbols were low enough for the lowOne or lowThreshold */
- for (s=0; ToDistribute > 0; s = (s+1)%(maxSymbolValue+1))
- if (norm[s] > 0) { ToDistribute--; norm[s]++; }
- return 0;
- }
-
- { U64 const vStepLog = 62 - tableLog;
- U64 const mid = (1ULL << (vStepLog-1)) - 1;
- U64 const rStep = ((((U64)1<<vStepLog) * ToDistribute) + mid) / total; /* scale on remaining */
- U64 tmpTotal = mid;
- for (s=0; s<=maxSymbolValue; s++) {
- if (norm[s]==NOT_YET_ASSIGNED) {
- U64 const end = tmpTotal + (count[s] * rStep);
- U32 const sStart = (U32)(tmpTotal >> vStepLog);
- U32 const sEnd = (U32)(end >> vStepLog);
- U32 const weight = sEnd - sStart;
- if (weight < 1)
- return ERROR(GENERIC);
- norm[s] = (short)weight;
- tmpTotal = end;
- } } }
-
- return 0;
-}
-
-
-size_t FSE_normalizeCount (short* normalizedCounter, unsigned tableLog,
- const unsigned* count, size_t total,
- unsigned maxSymbolValue)
-{
- /* Sanity checks */
- if (tableLog==0) tableLog = FSE_DEFAULT_TABLELOG;
- if (tableLog < FSE_MIN_TABLELOG) return ERROR(GENERIC); /* Unsupported size */
- if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); /* Unsupported size */
- if (tableLog < FSE_minTableLog(total, maxSymbolValue)) return ERROR(GENERIC); /* Too small tableLog, compression potentially impossible */
-
- { static U32 const rtbTable[] = { 0, 473195, 504333, 520860, 550000, 700000, 750000, 830000 };
- U64 const scale = 62 - tableLog;
- U64 const step = ((U64)1<<62) / total; /* <== here, one division ! */
- U64 const vStep = 1ULL<<(scale-20);
- int stillToDistribute = 1<<tableLog;
- unsigned s;
- unsigned largest=0;
- short largestP=0;
- U32 lowThreshold = (U32)(total >> tableLog);
-
- for (s=0; s<=maxSymbolValue; s++) {
- if (count[s] == total) return 0; /* rle special case */
- if (count[s] == 0) { normalizedCounter[s]=0; continue; }
- if (count[s] <= lowThreshold) {
- normalizedCounter[s] = -1;
- stillToDistribute--;
- } else {
- short proba = (short)((count[s]*step) >> scale);
- if (proba<8) {
- U64 restToBeat = vStep * rtbTable[proba];
- proba += (count[s]*step) - ((U64)proba<<scale) > restToBeat;
- }
- if (proba > largestP) { largestP=proba; largest=s; }
- normalizedCounter[s] = proba;
- stillToDistribute -= proba;
- } }
- if (-stillToDistribute >= (normalizedCounter[largest] >> 1)) {
- /* corner case, need another normalization method */
- size_t const errorCode = FSE_normalizeM2(normalizedCounter, tableLog, count, total, maxSymbolValue);
- if (FSE_isError(errorCode)) return errorCode;
- }
- else normalizedCounter[largest] += (short)stillToDistribute;
- }
-
-#if 0
- { /* Print Table (debug) */
- U32 s;
- U32 nTotal = 0;
- for (s=0; s<=maxSymbolValue; s++)
- RAWLOG(2, "%3i: %4i \n", s, normalizedCounter[s]);
- for (s=0; s<=maxSymbolValue; s++)
- nTotal += abs(normalizedCounter[s]);
- if (nTotal != (1U<<tableLog))
- RAWLOG(2, "Warning !!! Total == %u != %u !!!", nTotal, 1U<<tableLog);
- getchar();
- }
-#endif
-
- return tableLog;
-}
-
-
-/* fake FSE_CTable, for raw (uncompressed) input */
-size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits)
-{
- const unsigned tableSize = 1 << nbBits;
- const unsigned tableMask = tableSize - 1;
- const unsigned maxSymbolValue = tableMask;
- void* const ptr = ct;
- U16* const tableU16 = ( (U16*) ptr) + 2;
- void* const FSCT = ((U32*)ptr) + 1 /* header */ + (tableSize>>1); /* assumption : tableLog >= 1 */
- FSE_symbolCompressionTransform* const symbolTT = (FSE_symbolCompressionTransform*) (FSCT);
- unsigned s;
-
- /* Sanity checks */
- if (nbBits < 1) return ERROR(GENERIC); /* min size */
-
- /* header */
- tableU16[-2] = (U16) nbBits;
- tableU16[-1] = (U16) maxSymbolValue;
-
- /* Build table */
- for (s=0; s<tableSize; s++)
- tableU16[s] = (U16)(tableSize + s);
-
- /* Build Symbol Transformation Table */
- { const U32 deltaNbBits = (nbBits << 16) - (1 << nbBits);
- for (s=0; s<=maxSymbolValue; s++) {
- symbolTT[s].deltaNbBits = deltaNbBits;
- symbolTT[s].deltaFindState = s-1;
- } }
-
- return 0;
-}
-
-/* fake FSE_CTable, for rle input (always same symbol) */
-size_t FSE_buildCTable_rle (FSE_CTable* ct, BYTE symbolValue)
-{
- void* ptr = ct;
- U16* tableU16 = ( (U16*) ptr) + 2;
- void* FSCTptr = (U32*)ptr + 2;
- FSE_symbolCompressionTransform* symbolTT = (FSE_symbolCompressionTransform*) FSCTptr;
-
- /* header */
- tableU16[-2] = (U16) 0;
- tableU16[-1] = (U16) symbolValue;
-
- /* Build table */
- tableU16[0] = 0;
- tableU16[1] = 0; /* just in case */
-
- /* Build Symbol Transformation Table */
- symbolTT[symbolValue].deltaNbBits = 0;
- symbolTT[symbolValue].deltaFindState = 0;
-
- return 0;
-}
-
-
-static size_t FSE_compress_usingCTable_generic (void* dst, size_t dstSize,
- const void* src, size_t srcSize,
- const FSE_CTable* ct, const unsigned fast)
-{
- const BYTE* const istart = (const BYTE*) src;
- const BYTE* const iend = istart + srcSize;
- const BYTE* ip=iend;
-
- BIT_CStream_t bitC;
- FSE_CState_t CState1, CState2;
-
- /* init */
- if (srcSize <= 2) return 0;
- { size_t const initError = BIT_initCStream(&bitC, dst, dstSize);
- if (FSE_isError(initError)) return 0; /* not enough space available to write a bitstream */ }
-
-#define FSE_FLUSHBITS(s) (fast ? BIT_flushBitsFast(s) : BIT_flushBits(s))
-
- if (srcSize & 1) {
- FSE_initCState2(&CState1, ct, *--ip);
- FSE_initCState2(&CState2, ct, *--ip);
- FSE_encodeSymbol(&bitC, &CState1, *--ip);
- FSE_FLUSHBITS(&bitC);
- } else {
- FSE_initCState2(&CState2, ct, *--ip);
- FSE_initCState2(&CState1, ct, *--ip);
- }
-
- /* join to mod 4 */
- srcSize -= 2;
- if ((sizeof(bitC.bitContainer)*8 > FSE_MAX_TABLELOG*4+7 ) && (srcSize & 2)) { /* test bit 2 */
- FSE_encodeSymbol(&bitC, &CState2, *--ip);
- FSE_encodeSymbol(&bitC, &CState1, *--ip);
- FSE_FLUSHBITS(&bitC);
- }
-
- /* 2 or 4 encoding per loop */
- while ( ip>istart ) {
-
- FSE_encodeSymbol(&bitC, &CState2, *--ip);
-
- if (sizeof(bitC.bitContainer)*8 < FSE_MAX_TABLELOG*2+7 ) /* this test must be static */
- FSE_FLUSHBITS(&bitC);
-
- FSE_encodeSymbol(&bitC, &CState1, *--ip);
-
- if (sizeof(bitC.bitContainer)*8 > FSE_MAX_TABLELOG*4+7 ) { /* this test must be static */
- FSE_encodeSymbol(&bitC, &CState2, *--ip);
- FSE_encodeSymbol(&bitC, &CState1, *--ip);
- }
-
- FSE_FLUSHBITS(&bitC);
- }
-
- FSE_flushCState(&bitC, &CState2);
- FSE_flushCState(&bitC, &CState1);
- return BIT_closeCStream(&bitC);
-}
-
-size_t FSE_compress_usingCTable (void* dst, size_t dstSize,
- const void* src, size_t srcSize,
- const FSE_CTable* ct)
-{
- unsigned const fast = (dstSize >= FSE_BLOCKBOUND(srcSize));
-
- if (fast)
- return FSE_compress_usingCTable_generic(dst, dstSize, src, srcSize, ct, 1);
- else
- return FSE_compress_usingCTable_generic(dst, dstSize, src, srcSize, ct, 0);
-}
-
-
-size_t FSE_compressBound(size_t size) { return FSE_COMPRESSBOUND(size); }
-
-/* FSE_compress_wksp() :
- * Same as FSE_compress2(), but using an externally allocated scratch buffer (`workSpace`).
- * `wkspSize` size must be `(1<<tableLog)`.
- */
-size_t FSE_compress_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize)
-{
- BYTE* const ostart = (BYTE*) dst;
- BYTE* op = ostart;
- BYTE* const oend = ostart + dstSize;
-
- unsigned count[FSE_MAX_SYMBOL_VALUE+1];
- S16 norm[FSE_MAX_SYMBOL_VALUE+1];
- FSE_CTable* CTable = (FSE_CTable*)workSpace;
- size_t const CTableSize = FSE_CTABLE_SIZE_U32(tableLog, maxSymbolValue);
- void* scratchBuffer = (void*)(CTable + CTableSize);
- size_t const scratchBufferSize = wkspSize - (CTableSize * sizeof(FSE_CTable));
-
- /* init conditions */
- if (wkspSize < FSE_WKSP_SIZE_U32(tableLog, maxSymbolValue)) return ERROR(tableLog_tooLarge);
- if (srcSize <= 1) return 0; /* Not compressible */
- if (!maxSymbolValue) maxSymbolValue = FSE_MAX_SYMBOL_VALUE;
- if (!tableLog) tableLog = FSE_DEFAULT_TABLELOG;
-
- /* Scan input and build symbol stats */
- { CHECK_V_F(maxCount, HIST_count_wksp(count, &maxSymbolValue, src, srcSize, scratchBuffer, scratchBufferSize) );
- if (maxCount == srcSize) return 1; /* only a single symbol in src : rle */
- if (maxCount == 1) return 0; /* each symbol present maximum once => not compressible */
- if (maxCount < (srcSize >> 7)) return 0; /* Heuristic : not compressible enough */
- }
-
- tableLog = FSE_optimalTableLog(tableLog, srcSize, maxSymbolValue);
- CHECK_F( FSE_normalizeCount(norm, tableLog, count, srcSize, maxSymbolValue) );
-
- /* Write table description header */
- { CHECK_V_F(nc_err, FSE_writeNCount(op, oend-op, norm, maxSymbolValue, tableLog) );
- op += nc_err;
- }
-
- /* Compress */
- CHECK_F( FSE_buildCTable_wksp(CTable, norm, maxSymbolValue, tableLog, scratchBuffer, scratchBufferSize) );
- { CHECK_V_F(cSize, FSE_compress_usingCTable(op, oend - op, src, srcSize, CTable) );
- if (cSize == 0) return 0; /* not enough space for compressed data */
- op += cSize;
- }
-
- /* check compressibility */
- if ( (size_t)(op-ostart) >= srcSize-1 ) return 0;
-
- return op-ostart;
-}
-
-typedef struct {
- FSE_CTable CTable_max[FSE_CTABLE_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)];
- BYTE scratchBuffer[1 << FSE_MAX_TABLELOG];
-} fseWkspMax_t;
-
-size_t FSE_compress2 (void* dst, size_t dstCapacity, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog)
-{
- fseWkspMax_t scratchBuffer;
- DEBUG_STATIC_ASSERT(sizeof(scratchBuffer) >= FSE_WKSP_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)); /* compilation failures here means scratchBuffer is not large enough */
- if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge);
- return FSE_compress_wksp(dst, dstCapacity, src, srcSize, maxSymbolValue, tableLog, &scratchBuffer, sizeof(scratchBuffer));
-}
-
-size_t FSE_compress (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
-{
- return FSE_compress2(dst, dstCapacity, src, srcSize, FSE_MAX_SYMBOL_VALUE, FSE_DEFAULT_TABLELOG);
-}
-
-
-#endif /* FSE_COMMONDEFS_ONLY */
-/**** ended inlining compress/fse_compress.c ****/
-/**** start inlining compress/hist.c ****/
-/* ******************************************************************
- * hist : Histogram functions
- * part of Finite State Entropy project
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
- *
- * You can contact the author at :
- * - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
- * - Public forum : https://groups.google.com/forum/#!forum/lz4c
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
-****************************************************************** */
-
-/* --- dependencies --- */
-/**** skipping file: ../common/mem.h ****/
-/**** skipping file: ../common/debug.h ****/
-/**** skipping file: ../common/error_private.h ****/
-/**** skipping file: hist.h ****/
-
-
-/* --- Error management --- */
-unsigned HIST_isError(size_t code) { return ERR_isError(code); }
-
-/*-**************************************************************
- * Histogram functions
- ****************************************************************/
-unsigned HIST_count_simple(unsigned* count, unsigned* maxSymbolValuePtr,
- const void* src, size_t srcSize)
-{
- const BYTE* ip = (const BYTE*)src;
- const BYTE* const end = ip + srcSize;
- unsigned maxSymbolValue = *maxSymbolValuePtr;
- unsigned largestCount=0;
-
- memset(count, 0, (maxSymbolValue+1) * sizeof(*count));
- if (srcSize==0) { *maxSymbolValuePtr = 0; return 0; }
-
- while (ip<end) {
- assert(*ip <= maxSymbolValue);
- count[*ip++]++;
- }
-
- while (!count[maxSymbolValue]) maxSymbolValue--;
- *maxSymbolValuePtr = maxSymbolValue;
-
- { U32 s;
- for (s=0; s<=maxSymbolValue; s++)
- if (count[s] > largestCount) largestCount = count[s];
- }
-
- return largestCount;
-}
-
-typedef enum { trustInput, checkMaxSymbolValue } HIST_checkInput_e;
-
-/* HIST_count_parallel_wksp() :
- * store histogram into 4 intermediate tables, recombined at the end.
- * this design makes better use of OoO cpus,
- * and is noticeably faster when some values are heavily repeated.
- * But it needs some additional workspace for intermediate tables.
- * `workSpace` size must be a table of size >= HIST_WKSP_SIZE_U32.
- * @return : largest histogram frequency,
- * or an error code (notably when histogram would be larger than *maxSymbolValuePtr). */
-static size_t HIST_count_parallel_wksp(
- unsigned* count, unsigned* maxSymbolValuePtr,
- const void* source, size_t sourceSize,
- HIST_checkInput_e check,
- U32* const workSpace)
-{
- const BYTE* ip = (const BYTE*)source;
- const BYTE* const iend = ip+sourceSize;
- unsigned maxSymbolValue = *maxSymbolValuePtr;
- unsigned max=0;
- U32* const Counting1 = workSpace;
- U32* const Counting2 = Counting1 + 256;
- U32* const Counting3 = Counting2 + 256;
- U32* const Counting4 = Counting3 + 256;
-
- memset(workSpace, 0, 4*256*sizeof(unsigned));
-
- /* safety checks */
- if (!sourceSize) {
- memset(count, 0, maxSymbolValue + 1);
- *maxSymbolValuePtr = 0;
- return 0;
- }
- if (!maxSymbolValue) maxSymbolValue = 255; /* 0 == default */
-
- /* by stripes of 16 bytes */
- { U32 cached = MEM_read32(ip); ip += 4;
- while (ip < iend-15) {
- U32 c = cached; cached = MEM_read32(ip); ip += 4;
- Counting1[(BYTE) c ]++;
- Counting2[(BYTE)(c>>8) ]++;
- Counting3[(BYTE)(c>>16)]++;
- Counting4[ c>>24 ]++;
- c = cached; cached = MEM_read32(ip); ip += 4;
- Counting1[(BYTE) c ]++;
- Counting2[(BYTE)(c>>8) ]++;
- Counting3[(BYTE)(c>>16)]++;
- Counting4[ c>>24 ]++;
- c = cached; cached = MEM_read32(ip); ip += 4;
- Counting1[(BYTE) c ]++;
- Counting2[(BYTE)(c>>8) ]++;
- Counting3[(BYTE)(c>>16)]++;
- Counting4[ c>>24 ]++;
- c = cached; cached = MEM_read32(ip); ip += 4;
- Counting1[(BYTE) c ]++;
- Counting2[(BYTE)(c>>8) ]++;
- Counting3[(BYTE)(c>>16)]++;
- Counting4[ c>>24 ]++;
- }
- ip-=4;
- }
-
- /* finish last symbols */
- while (ip<iend) Counting1[*ip++]++;
-
- if (check) { /* verify stats will fit into destination table */
- U32 s; for (s=255; s>maxSymbolValue; s--) {
- Counting1[s] += Counting2[s] + Counting3[s] + Counting4[s];
- if (Counting1[s]) return ERROR(maxSymbolValue_tooSmall);
- } }
-
- { U32 s;
- if (maxSymbolValue > 255) maxSymbolValue = 255;
- for (s=0; s<=maxSymbolValue; s++) {
- count[s] = Counting1[s] + Counting2[s] + Counting3[s] + Counting4[s];
- if (count[s] > max) max = count[s];
- } }
-
- while (!count[maxSymbolValue]) maxSymbolValue--;
- *maxSymbolValuePtr = maxSymbolValue;
- return (size_t)max;
-}
-
-/* HIST_countFast_wksp() :
- * Same as HIST_countFast(), but using an externally provided scratch buffer.
- * `workSpace` is a writable buffer which must be 4-bytes aligned,
- * `workSpaceSize` must be >= HIST_WKSP_SIZE
- */
-size_t HIST_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
- const void* source, size_t sourceSize,
- void* workSpace, size_t workSpaceSize)
-{
- if (sourceSize < 1500) /* heuristic threshold */
- return HIST_count_simple(count, maxSymbolValuePtr, source, sourceSize);
- if ((size_t)workSpace & 3) return ERROR(GENERIC); /* must be aligned on 4-bytes boundaries */
- if (workSpaceSize < HIST_WKSP_SIZE) return ERROR(workSpace_tooSmall);
- return HIST_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, trustInput, (U32*)workSpace);
-}
-
-/* fast variant (unsafe : won't check if src contains values beyond count[] limit) */
-size_t HIST_countFast(unsigned* count, unsigned* maxSymbolValuePtr,
- const void* source, size_t sourceSize)
-{
- unsigned tmpCounters[HIST_WKSP_SIZE_U32];
- return HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, tmpCounters, sizeof(tmpCounters));
-}
-
-/* HIST_count_wksp() :
- * Same as HIST_count(), but using an externally provided scratch buffer.
- * `workSpace` size must be table of >= HIST_WKSP_SIZE_U32 unsigned */
-size_t HIST_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
- const void* source, size_t sourceSize,
- void* workSpace, size_t workSpaceSize)
-{
- if ((size_t)workSpace & 3) return ERROR(GENERIC); /* must be aligned on 4-bytes boundaries */
- if (workSpaceSize < HIST_WKSP_SIZE) return ERROR(workSpace_tooSmall);
- if (*maxSymbolValuePtr < 255)
- return HIST_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, checkMaxSymbolValue, (U32*)workSpace);
- *maxSymbolValuePtr = 255;
- return HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, workSpace, workSpaceSize);
-}
-
-size_t HIST_count(unsigned* count, unsigned* maxSymbolValuePtr,
- const void* src, size_t srcSize)
-{
- unsigned tmpCounters[HIST_WKSP_SIZE_U32];
- return HIST_count_wksp(count, maxSymbolValuePtr, src, srcSize, tmpCounters, sizeof(tmpCounters));
-}
-/**** ended inlining compress/hist.c ****/
-/**** start inlining compress/huf_compress.c ****/
-/* ******************************************************************
- * Huffman encoder, part of New Generation Entropy library
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
- *
- * You can contact the author at :
- * - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
- * - Public forum : https://groups.google.com/forum/#!forum/lz4c
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
-****************************************************************** */
-
-/* **************************************************************
-* Compiler specifics
-****************************************************************/
-#ifdef _MSC_VER /* Visual Studio */
-# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
-#endif
-
-
-/* **************************************************************
-* Includes
-****************************************************************/
-#include <string.h> /* memcpy, memset */
-#include <stdio.h> /* printf (debug) */
-/**** skipping file: ../common/compiler.h ****/
-/**** skipping file: ../common/bitstream.h ****/
-/**** skipping file: hist.h ****/
-#define FSE_STATIC_LINKING_ONLY /* FSE_optimalTableLog_internal */
-/**** skipping file: ../common/fse.h ****/
-#define HUF_STATIC_LINKING_ONLY
-/**** skipping file: ../common/huf.h ****/
-/**** skipping file: ../common/error_private.h ****/
-
-
-/* **************************************************************
-* Error Management
-****************************************************************/
-#define HUF_isError ERR_isError
-#define HUF_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) /* use only *after* variable declarations */
-
-
-/* **************************************************************
-* Utils
-****************************************************************/
-unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue)
-{
- return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 1);
-}
-
-
-/* *******************************************************
-* HUF : Huffman block compression
-*********************************************************/
-/* HUF_compressWeights() :
- * Same as FSE_compress(), but dedicated to huff0's weights compression.
- * The use case needs much less stack memory.
- * Note : all elements within weightTable are supposed to be <= HUF_TABLELOG_MAX.
- */
-#define MAX_FSE_TABLELOG_FOR_HUFF_HEADER 6
-static size_t HUF_compressWeights (void* dst, size_t dstSize, const void* weightTable, size_t wtSize)
-{
- BYTE* const ostart = (BYTE*) dst;
- BYTE* op = ostart;
- BYTE* const oend = ostart + dstSize;
-
- unsigned maxSymbolValue = HUF_TABLELOG_MAX;
- U32 tableLog = MAX_FSE_TABLELOG_FOR_HUFF_HEADER;
-
- FSE_CTable CTable[FSE_CTABLE_SIZE_U32(MAX_FSE_TABLELOG_FOR_HUFF_HEADER, HUF_TABLELOG_MAX)];
- BYTE scratchBuffer[1<<MAX_FSE_TABLELOG_FOR_HUFF_HEADER];
-
- unsigned count[HUF_TABLELOG_MAX+1];
- S16 norm[HUF_TABLELOG_MAX+1];
-
- /* init conditions */
- if (wtSize <= 1) return 0; /* Not compressible */
-
- /* Scan input and build symbol stats */
- { unsigned const maxCount = HIST_count_simple(count, &maxSymbolValue, weightTable, wtSize); /* never fails */
- if (maxCount == wtSize) return 1; /* only a single symbol in src : rle */
- if (maxCount == 1) return 0; /* each symbol present maximum once => not compressible */
- }
-
- tableLog = FSE_optimalTableLog(tableLog, wtSize, maxSymbolValue);
- CHECK_F( FSE_normalizeCount(norm, tableLog, count, wtSize, maxSymbolValue) );
-
- /* Write table description header */
- { CHECK_V_F(hSize, FSE_writeNCount(op, (size_t)(oend-op), norm, maxSymbolValue, tableLog) );
- op += hSize;
- }
-
- /* Compress */
- CHECK_F( FSE_buildCTable_wksp(CTable, norm, maxSymbolValue, tableLog, scratchBuffer, sizeof(scratchBuffer)) );
- { CHECK_V_F(cSize, FSE_compress_usingCTable(op, (size_t)(oend - op), weightTable, wtSize, CTable) );
- if (cSize == 0) return 0; /* not enough space for compressed data */
- op += cSize;
- }
-
- return (size_t)(op-ostart);
-}
-
-
-struct HUF_CElt_s {
- U16 val;
- BYTE nbBits;
-}; /* typedef'd to HUF_CElt within "huf.h" */
-
-/*! HUF_writeCTable() :
- `CTable` : Huffman tree to save, using huf representation.
- @return : size of saved CTable */
-size_t HUF_writeCTable (void* dst, size_t maxDstSize,
- const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog)
-{
- BYTE bitsToWeight[HUF_TABLELOG_MAX + 1]; /* precomputed conversion table */
- BYTE huffWeight[HUF_SYMBOLVALUE_MAX];
- BYTE* op = (BYTE*)dst;
- U32 n;
-
- /* check conditions */
- if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(maxSymbolValue_tooLarge);
-
- /* convert to weight */
- bitsToWeight[0] = 0;
- for (n=1; n<huffLog+1; n++)
- bitsToWeight[n] = (BYTE)(huffLog + 1 - n);
- for (n=0; n<maxSymbolValue; n++)
- huffWeight[n] = bitsToWeight[CTable[n].nbBits];
-
- /* attempt weights compression by FSE */
- { CHECK_V_F(hSize, HUF_compressWeights(op+1, maxDstSize-1, huffWeight, maxSymbolValue) );
- if ((hSize>1) & (hSize < maxSymbolValue/2)) { /* FSE compressed */
- op[0] = (BYTE)hSize;
- return hSize+1;
- } }
-
- /* write raw values as 4-bits (max : 15) */
- if (maxSymbolValue > (256-128)) return ERROR(GENERIC); /* should not happen : likely means source cannot be compressed */
- if (((maxSymbolValue+1)/2) + 1 > maxDstSize) return ERROR(dstSize_tooSmall); /* not enough space within dst buffer */
- op[0] = (BYTE)(128 /*special case*/ + (maxSymbolValue-1));
- huffWeight[maxSymbolValue] = 0; /* to be sure it doesn't cause msan issue in final combination */
- for (n=0; n<maxSymbolValue; n+=2)
- op[(n/2)+1] = (BYTE)((huffWeight[n] << 4) + huffWeight[n+1]);
- return ((maxSymbolValue+1)/2) + 1;
-}
-
-
-size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned* hasZeroWeights)
-{
- BYTE huffWeight[HUF_SYMBOLVALUE_MAX + 1]; /* init not required, even though some static analyzer may complain */
- U32 rankVal[HUF_TABLELOG_ABSOLUTEMAX + 1]; /* large enough for values from 0 to 16 */
- U32 tableLog = 0;
- U32 nbSymbols = 0;
-
- /* get symbol weights */
- CHECK_V_F(readSize, HUF_readStats(huffWeight, HUF_SYMBOLVALUE_MAX+1, rankVal, &nbSymbols, &tableLog, src, srcSize));
-
- /* check result */
- if (tableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge);
- if (nbSymbols > *maxSymbolValuePtr+1) return ERROR(maxSymbolValue_tooSmall);
-
- /* Prepare base value per rank */
- { U32 n, nextRankStart = 0;
- for (n=1; n<=tableLog; n++) {
- U32 current = nextRankStart;
- nextRankStart += (rankVal[n] << (n-1));
- rankVal[n] = current;
- } }
-
- /* fill nbBits */
- *hasZeroWeights = 0;
- { U32 n; for (n=0; n<nbSymbols; n++) {
- const U32 w = huffWeight[n];
- *hasZeroWeights |= (w == 0);
- CTable[n].nbBits = (BYTE)(tableLog + 1 - w) & -(w != 0);
- } }
-
- /* fill val */
- { U16 nbPerRank[HUF_TABLELOG_MAX+2] = {0}; /* support w=0=>n=tableLog+1 */
- U16 valPerRank[HUF_TABLELOG_MAX+2] = {0};
- { U32 n; for (n=0; n<nbSymbols; n++) nbPerRank[CTable[n].nbBits]++; }
- /* determine stating value per rank */
- valPerRank[tableLog+1] = 0; /* for w==0 */
- { U16 min = 0;
- U32 n; for (n=tableLog; n>0; n--) { /* start at n=tablelog <-> w=1 */
- valPerRank[n] = min; /* get starting value within each rank */
- min += nbPerRank[n];
- min >>= 1;
- } }
- /* assign value within rank, symbol order */
- { U32 n; for (n=0; n<nbSymbols; n++) CTable[n].val = valPerRank[CTable[n].nbBits]++; }
- }
-
- *maxSymbolValuePtr = nbSymbols - 1;
- return readSize;
-}
-
-U32 HUF_getNbBits(const void* symbolTable, U32 symbolValue)
-{
- const HUF_CElt* table = (const HUF_CElt*)symbolTable;
- assert(symbolValue <= HUF_SYMBOLVALUE_MAX);
- return table[symbolValue].nbBits;
-}
-
-
-typedef struct nodeElt_s {
- U32 count;
- U16 parent;
- BYTE byte;
- BYTE nbBits;
-} nodeElt;
-
-static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits)
-{
- const U32 largestBits = huffNode[lastNonNull].nbBits;
- if (largestBits <= maxNbBits) return largestBits; /* early exit : no elt > maxNbBits */
-
- /* there are several too large elements (at least >= 2) */
- { int totalCost = 0;
- const U32 baseCost = 1 << (largestBits - maxNbBits);
- int n = (int)lastNonNull;
-
- while (huffNode[n].nbBits > maxNbBits) {
- totalCost += baseCost - (1 << (largestBits - huffNode[n].nbBits));
- huffNode[n].nbBits = (BYTE)maxNbBits;
- n --;
- } /* n stops at huffNode[n].nbBits <= maxNbBits */
- while (huffNode[n].nbBits == maxNbBits) n--; /* n end at index of smallest symbol using < maxNbBits */
-
- /* renorm totalCost */
- totalCost >>= (largestBits - maxNbBits); /* note : totalCost is necessarily a multiple of baseCost */
-
- /* repay normalized cost */
- { U32 const noSymbol = 0xF0F0F0F0;
- U32 rankLast[HUF_TABLELOG_MAX+2];
-
- /* Get pos of last (smallest) symbol per rank */
- memset(rankLast, 0xF0, sizeof(rankLast));
- { U32 currentNbBits = maxNbBits;
- int pos;
- for (pos=n ; pos >= 0; pos--) {
- if (huffNode[pos].nbBits >= currentNbBits) continue;
- currentNbBits = huffNode[pos].nbBits; /* < maxNbBits */
- rankLast[maxNbBits-currentNbBits] = (U32)pos;
- } }
-
- while (totalCost > 0) {
- U32 nBitsToDecrease = BIT_highbit32((U32)totalCost) + 1;
- for ( ; nBitsToDecrease > 1; nBitsToDecrease--) {
- U32 const highPos = rankLast[nBitsToDecrease];
- U32 const lowPos = rankLast[nBitsToDecrease-1];
- if (highPos == noSymbol) continue;
- if (lowPos == noSymbol) break;
- { U32 const highTotal = huffNode[highPos].count;
- U32 const lowTotal = 2 * huffNode[lowPos].count;
- if (highTotal <= lowTotal) break;
- } }
- /* only triggered when no more rank 1 symbol left => find closest one (note : there is necessarily at least one !) */
- /* HUF_MAX_TABLELOG test just to please gcc 5+; but it should not be necessary */
- while ((nBitsToDecrease<=HUF_TABLELOG_MAX) && (rankLast[nBitsToDecrease] == noSymbol))
- nBitsToDecrease ++;
- totalCost -= 1 << (nBitsToDecrease-1);
- if (rankLast[nBitsToDecrease-1] == noSymbol)
- rankLast[nBitsToDecrease-1] = rankLast[nBitsToDecrease]; /* this rank is no longer empty */
- huffNode[rankLast[nBitsToDecrease]].nbBits ++;
- if (rankLast[nBitsToDecrease] == 0) /* special case, reached largest symbol */
- rankLast[nBitsToDecrease] = noSymbol;
- else {
- rankLast[nBitsToDecrease]--;
- if (huffNode[rankLast[nBitsToDecrease]].nbBits != maxNbBits-nBitsToDecrease)
- rankLast[nBitsToDecrease] = noSymbol; /* this rank is now empty */
- } } /* while (totalCost > 0) */
-
- while (totalCost < 0) { /* Sometimes, cost correction overshoot */
- if (rankLast[1] == noSymbol) { /* special case : no rank 1 symbol (using maxNbBits-1); let's create one from largest rank 0 (using maxNbBits) */
- while (huffNode[n].nbBits == maxNbBits) n--;
- huffNode[n+1].nbBits--;
- assert(n >= 0);
- rankLast[1] = (U32)(n+1);
- totalCost++;
- continue;
- }
- huffNode[ rankLast[1] + 1 ].nbBits--;
- rankLast[1]++;
- totalCost ++;
- } } } /* there are several too large elements (at least >= 2) */
-
- return maxNbBits;
-}
-
-typedef struct {
- U32 base;
- U32 current;
-} rankPos;
-
-typedef nodeElt huffNodeTable[HUF_CTABLE_WORKSPACE_SIZE_U32];
-
-#define RANK_POSITION_TABLE_SIZE 32
-
-typedef struct {
- huffNodeTable huffNodeTbl;
- rankPos rankPosition[RANK_POSITION_TABLE_SIZE];
-} HUF_buildCTable_wksp_tables;
-
-static void HUF_sort(nodeElt* huffNode, const unsigned* count, U32 maxSymbolValue, rankPos* rankPosition)
-{
- U32 n;
-
- memset(rankPosition, 0, sizeof(*rankPosition) * RANK_POSITION_TABLE_SIZE);
- for (n=0; n<=maxSymbolValue; n++) {
- U32 r = BIT_highbit32(count[n] + 1);
- rankPosition[r].base ++;
- }
- for (n=30; n>0; n--) rankPosition[n-1].base += rankPosition[n].base;
- for (n=0; n<32; n++) rankPosition[n].current = rankPosition[n].base;
- for (n=0; n<=maxSymbolValue; n++) {
- U32 const c = count[n];
- U32 const r = BIT_highbit32(c+1) + 1;
- U32 pos = rankPosition[r].current++;
- while ((pos > rankPosition[r].base) && (c > huffNode[pos-1].count)) {
- huffNode[pos] = huffNode[pos-1];
- pos--;
- }
- huffNode[pos].count = c;
- huffNode[pos].byte = (BYTE)n;
- }
-}
-
-
-/** HUF_buildCTable_wksp() :
- * Same as HUF_buildCTable(), but using externally allocated scratch buffer.
- * `workSpace` must be aligned on 4-bytes boundaries, and be at least as large as sizeof(HUF_buildCTable_wksp_tables).
- */
-#define STARTNODE (HUF_SYMBOLVALUE_MAX+1)
-
-size_t HUF_buildCTable_wksp (HUF_CElt* tree, const unsigned* count, U32 maxSymbolValue, U32 maxNbBits, void* workSpace, size_t wkspSize)
-{
- HUF_buildCTable_wksp_tables* const wksp_tables = (HUF_buildCTable_wksp_tables*)workSpace;
- nodeElt* const huffNode0 = wksp_tables->huffNodeTbl;
- nodeElt* const huffNode = huffNode0+1;
- int nonNullRank;
- int lowS, lowN;
- int nodeNb = STARTNODE;
- int n, nodeRoot;
-
- /* safety checks */
- if (((size_t)workSpace & 3) != 0) return ERROR(GENERIC); /* must be aligned on 4-bytes boundaries */
- if (wkspSize < sizeof(HUF_buildCTable_wksp_tables))
- return ERROR(workSpace_tooSmall);
- if (maxNbBits == 0) maxNbBits = HUF_TABLELOG_DEFAULT;
- if (maxSymbolValue > HUF_SYMBOLVALUE_MAX)
- return ERROR(maxSymbolValue_tooLarge);
- memset(huffNode0, 0, sizeof(huffNodeTable));
-
- /* sort, decreasing order */
- HUF_sort(huffNode, count, maxSymbolValue, wksp_tables->rankPosition);
-
- /* init for parents */
- nonNullRank = (int)maxSymbolValue;
- while(huffNode[nonNullRank].count == 0) nonNullRank--;
- lowS = nonNullRank; nodeRoot = nodeNb + lowS - 1; lowN = nodeNb;
- huffNode[nodeNb].count = huffNode[lowS].count + huffNode[lowS-1].count;
- huffNode[lowS].parent = huffNode[lowS-1].parent = (U16)nodeNb;
- nodeNb++; lowS-=2;
- for (n=nodeNb; n<=nodeRoot; n++) huffNode[n].count = (U32)(1U<<30);
- huffNode0[0].count = (U32)(1U<<31); /* fake entry, strong barrier */
-
- /* create parents */
- while (nodeNb <= nodeRoot) {
- int const n1 = (huffNode[lowS].count < huffNode[lowN].count) ? lowS-- : lowN++;
- int const n2 = (huffNode[lowS].count < huffNode[lowN].count) ? lowS-- : lowN++;
- huffNode[nodeNb].count = huffNode[n1].count + huffNode[n2].count;
- huffNode[n1].parent = huffNode[n2].parent = (U16)nodeNb;
- nodeNb++;
- }
-
- /* distribute weights (unlimited tree height) */
- huffNode[nodeRoot].nbBits = 0;
- for (n=nodeRoot-1; n>=STARTNODE; n--)
- huffNode[n].nbBits = huffNode[ huffNode[n].parent ].nbBits + 1;
- for (n=0; n<=nonNullRank; n++)
- huffNode[n].nbBits = huffNode[ huffNode[n].parent ].nbBits + 1;
-
- /* enforce maxTableLog */
- maxNbBits = HUF_setMaxHeight(huffNode, (U32)nonNullRank, maxNbBits);
-
- /* fill result into tree (val, nbBits) */
- { U16 nbPerRank[HUF_TABLELOG_MAX+1] = {0};
- U16 valPerRank[HUF_TABLELOG_MAX+1] = {0};
- int const alphabetSize = (int)(maxSymbolValue + 1);
- if (maxNbBits > HUF_TABLELOG_MAX) return ERROR(GENERIC); /* check fit into table */
- for (n=0; n<=nonNullRank; n++)
- nbPerRank[huffNode[n].nbBits]++;
- /* determine stating value per rank */
- { U16 min = 0;
- for (n=(int)maxNbBits; n>0; n--) {
- valPerRank[n] = min; /* get starting value within each rank */
- min += nbPerRank[n];
- min >>= 1;
- } }
- for (n=0; n<alphabetSize; n++)
- tree[huffNode[n].byte].nbBits = huffNode[n].nbBits; /* push nbBits per symbol, symbol order */
- for (n=0; n<alphabetSize; n++)
- tree[n].val = valPerRank[tree[n].nbBits]++; /* assign value within rank, symbol order */
- }
-
- return maxNbBits;
-}
-
-/** HUF_buildCTable() :
- * @return : maxNbBits
- * Note : count is used before tree is written, so they can safely overlap
- */
-size_t HUF_buildCTable (HUF_CElt* tree, const unsigned* count, unsigned maxSymbolValue, unsigned maxNbBits)
-{
- HUF_buildCTable_wksp_tables workspace;
- return HUF_buildCTable_wksp(tree, count, maxSymbolValue, maxNbBits, &workspace, sizeof(workspace));
-}
-
-size_t HUF_estimateCompressedSize(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue)
-{
- size_t nbBits = 0;
- int s;
- for (s = 0; s <= (int)maxSymbolValue; ++s) {
- nbBits += CTable[s].nbBits * count[s];
- }
- return nbBits >> 3;
-}
-
-int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue) {
- int bad = 0;
- int s;
- for (s = 0; s <= (int)maxSymbolValue; ++s) {
- bad |= (count[s] != 0) & (CTable[s].nbBits == 0);
- }
- return !bad;
-}
-
-size_t HUF_compressBound(size_t size) { return HUF_COMPRESSBOUND(size); }
-
-FORCE_INLINE_TEMPLATE void
-HUF_encodeSymbol(BIT_CStream_t* bitCPtr, U32 symbol, const HUF_CElt* CTable)
-{
- BIT_addBitsFast(bitCPtr, CTable[symbol].val, CTable[symbol].nbBits);
-}
-
-#define HUF_FLUSHBITS(s) BIT_flushBits(s)
-
-#define HUF_FLUSHBITS_1(stream) \
- if (sizeof((stream)->bitContainer)*8 < HUF_TABLELOG_MAX*2+7) HUF_FLUSHBITS(stream)
-
-#define HUF_FLUSHBITS_2(stream) \
- if (sizeof((stream)->bitContainer)*8 < HUF_TABLELOG_MAX*4+7) HUF_FLUSHBITS(stream)
-
-FORCE_INLINE_TEMPLATE size_t
-HUF_compress1X_usingCTable_internal_body(void* dst, size_t dstSize,
- const void* src, size_t srcSize,
- const HUF_CElt* CTable)
-{
- const BYTE* ip = (const BYTE*) src;
- BYTE* const ostart = (BYTE*)dst;
- BYTE* const oend = ostart + dstSize;
- BYTE* op = ostart;
- size_t n;
- BIT_CStream_t bitC;
-
- /* init */
- if (dstSize < 8) return 0; /* not enough space to compress */
- { size_t const initErr = BIT_initCStream(&bitC, op, (size_t)(oend-op));
- if (HUF_isError(initErr)) return 0; }
-
- n = srcSize & ~3; /* join to mod 4 */
- switch (srcSize & 3)
- {
- case 3 : HUF_encodeSymbol(&bitC, ip[n+ 2], CTable);
- HUF_FLUSHBITS_2(&bitC);
- /* fall-through */
- case 2 : HUF_encodeSymbol(&bitC, ip[n+ 1], CTable);
- HUF_FLUSHBITS_1(&bitC);
- /* fall-through */
- case 1 : HUF_encodeSymbol(&bitC, ip[n+ 0], CTable);
- HUF_FLUSHBITS(&bitC);
- /* fall-through */
- case 0 : /* fall-through */
- default: break;
- }
-
- for (; n>0; n-=4) { /* note : n&3==0 at this stage */
- HUF_encodeSymbol(&bitC, ip[n- 1], CTable);
- HUF_FLUSHBITS_1(&bitC);
- HUF_encodeSymbol(&bitC, ip[n- 2], CTable);
- HUF_FLUSHBITS_2(&bitC);
- HUF_encodeSymbol(&bitC, ip[n- 3], CTable);
- HUF_FLUSHBITS_1(&bitC);
- HUF_encodeSymbol(&bitC, ip[n- 4], CTable);
- HUF_FLUSHBITS(&bitC);
- }
-
- return BIT_closeCStream(&bitC);
-}
-
-#if DYNAMIC_BMI2
-
-static TARGET_ATTRIBUTE("bmi2") size_t
-HUF_compress1X_usingCTable_internal_bmi2(void* dst, size_t dstSize,
- const void* src, size_t srcSize,
- const HUF_CElt* CTable)
-{
- return HUF_compress1X_usingCTable_internal_body(dst, dstSize, src, srcSize, CTable);
-}
-
-static size_t
-HUF_compress1X_usingCTable_internal_default(void* dst, size_t dstSize,
- const void* src, size_t srcSize,
- const HUF_CElt* CTable)
-{
- return HUF_compress1X_usingCTable_internal_body(dst, dstSize, src, srcSize, CTable);
-}
-
-static size_t
-HUF_compress1X_usingCTable_internal(void* dst, size_t dstSize,
- const void* src, size_t srcSize,
- const HUF_CElt* CTable, const int bmi2)
-{
- if (bmi2) {
- return HUF_compress1X_usingCTable_internal_bmi2(dst, dstSize, src, srcSize, CTable);
- }
- return HUF_compress1X_usingCTable_internal_default(dst, dstSize, src, srcSize, CTable);
-}
-
-#else
-
-static size_t
-HUF_compress1X_usingCTable_internal(void* dst, size_t dstSize,
- const void* src, size_t srcSize,
- const HUF_CElt* CTable, const int bmi2)
-{
- (void)bmi2;
- return HUF_compress1X_usingCTable_internal_body(dst, dstSize, src, srcSize, CTable);
-}
-
-#endif
-
-size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable)
-{
- return HUF_compress1X_usingCTable_internal(dst, dstSize, src, srcSize, CTable, /* bmi2 */ 0);
-}
-
-
-static size_t
-HUF_compress4X_usingCTable_internal(void* dst, size_t dstSize,
- const void* src, size_t srcSize,
- const HUF_CElt* CTable, int bmi2)
-{
- size_t const segmentSize = (srcSize+3)/4; /* first 3 segments */
- const BYTE* ip = (const BYTE*) src;
- const BYTE* const iend = ip + srcSize;
- BYTE* const ostart = (BYTE*) dst;
- BYTE* const oend = ostart + dstSize;
- BYTE* op = ostart;
-
- if (dstSize < 6 + 1 + 1 + 1 + 8) return 0; /* minimum space to compress successfully */
- if (srcSize < 12) return 0; /* no saving possible : too small input */
- op += 6; /* jumpTable */
-
- assert(op <= oend);
- { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, segmentSize, CTable, bmi2) );
- if (cSize==0) return 0;
- assert(cSize <= 65535);
- MEM_writeLE16(ostart, (U16)cSize);
- op += cSize;
- }
-
- ip += segmentSize;
- assert(op <= oend);
- { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, segmentSize, CTable, bmi2) );
- if (cSize==0) return 0;
- assert(cSize <= 65535);
- MEM_writeLE16(ostart+2, (U16)cSize);
- op += cSize;
- }
-
- ip += segmentSize;
- assert(op <= oend);
- { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, segmentSize, CTable, bmi2) );
- if (cSize==0) return 0;
- assert(cSize <= 65535);
- MEM_writeLE16(ostart+4, (U16)cSize);
- op += cSize;
- }
-
- ip += segmentSize;
- assert(op <= oend);
- assert(ip <= iend);
- { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, (size_t)(iend-ip), CTable, bmi2) );
- if (cSize==0) return 0;
- op += cSize;
- }
-
- return (size_t)(op-ostart);
-}
-
-size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable)
-{
- return HUF_compress4X_usingCTable_internal(dst, dstSize, src, srcSize, CTable, /* bmi2 */ 0);
-}
-
-typedef enum { HUF_singleStream, HUF_fourStreams } HUF_nbStreams_e;
-
-static size_t HUF_compressCTable_internal(
- BYTE* const ostart, BYTE* op, BYTE* const oend,
- const void* src, size_t srcSize,
- HUF_nbStreams_e nbStreams, const HUF_CElt* CTable, const int bmi2)
-{
- size_t const cSize = (nbStreams==HUF_singleStream) ?
- HUF_compress1X_usingCTable_internal(op, (size_t)(oend - op), src, srcSize, CTable, bmi2) :
- HUF_compress4X_usingCTable_internal(op, (size_t)(oend - op), src, srcSize, CTable, bmi2);
- if (HUF_isError(cSize)) { return cSize; }
- if (cSize==0) { return 0; } /* uncompressible */
- op += cSize;
- /* check compressibility */
- assert(op >= ostart);
- if ((size_t)(op-ostart) >= srcSize-1) { return 0; }
- return (size_t)(op-ostart);
-}
-
-typedef struct {
- unsigned count[HUF_SYMBOLVALUE_MAX + 1];
- HUF_CElt CTable[HUF_SYMBOLVALUE_MAX + 1];
- HUF_buildCTable_wksp_tables buildCTable_wksp;
-} HUF_compress_tables_t;
-
-/* HUF_compress_internal() :
- * `workSpace` must a table of at least HUF_WORKSPACE_SIZE_U32 unsigned */
-static size_t
-HUF_compress_internal (void* dst, size_t dstSize,
- const void* src, size_t srcSize,
- unsigned maxSymbolValue, unsigned huffLog,
- HUF_nbStreams_e nbStreams,
- void* workSpace, size_t wkspSize,
- HUF_CElt* oldHufTable, HUF_repeat* repeat, int preferRepeat,
- const int bmi2)
-{
- HUF_compress_tables_t* const table = (HUF_compress_tables_t*)workSpace;
- BYTE* const ostart = (BYTE*)dst;
- BYTE* const oend = ostart + dstSize;
- BYTE* op = ostart;
-
- HUF_STATIC_ASSERT(sizeof(*table) <= HUF_WORKSPACE_SIZE);
-
- /* checks & inits */
- if (((size_t)workSpace & 3) != 0) return ERROR(GENERIC); /* must be aligned on 4-bytes boundaries */
- if (wkspSize < HUF_WORKSPACE_SIZE) return ERROR(workSpace_tooSmall);
- if (!srcSize) return 0; /* Uncompressed */
- if (!dstSize) return 0; /* cannot fit anything within dst budget */
- if (srcSize > HUF_BLOCKSIZE_MAX) return ERROR(srcSize_wrong); /* current block size limit */
- if (huffLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge);
- if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(maxSymbolValue_tooLarge);
- if (!maxSymbolValue) maxSymbolValue = HUF_SYMBOLVALUE_MAX;
- if (!huffLog) huffLog = HUF_TABLELOG_DEFAULT;
-
- /* Heuristic : If old table is valid, use it for small inputs */
- if (preferRepeat && repeat && *repeat == HUF_repeat_valid) {
- return HUF_compressCTable_internal(ostart, op, oend,
- src, srcSize,
- nbStreams, oldHufTable, bmi2);
- }
-
- /* Scan input and build symbol stats */
- { CHECK_V_F(largest, HIST_count_wksp (table->count, &maxSymbolValue, (const BYTE*)src, srcSize, workSpace, wkspSize) );
- if (largest == srcSize) { *ostart = ((const BYTE*)src)[0]; return 1; } /* single symbol, rle */
- if (largest <= (srcSize >> 7)+4) return 0; /* heuristic : probably not compressible enough */
- }
-
- /* Check validity of previous table */
- if ( repeat
- && *repeat == HUF_repeat_check
- && !HUF_validateCTable(oldHufTable, table->count, maxSymbolValue)) {
- *repeat = HUF_repeat_none;
- }
- /* Heuristic : use existing table for small inputs */
- if (preferRepeat && repeat && *repeat != HUF_repeat_none) {
- return HUF_compressCTable_internal(ostart, op, oend,
- src, srcSize,
- nbStreams, oldHufTable, bmi2);
- }
-
- /* Build Huffman Tree */
- huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue);
- { size_t const maxBits = HUF_buildCTable_wksp(table->CTable, table->count,
- maxSymbolValue, huffLog,
- &table->buildCTable_wksp, sizeof(table->buildCTable_wksp));
- CHECK_F(maxBits);
- huffLog = (U32)maxBits;
- /* Zero unused symbols in CTable, so we can check it for validity */
- memset(table->CTable + (maxSymbolValue + 1), 0,
- sizeof(table->CTable) - ((maxSymbolValue + 1) * sizeof(HUF_CElt)));
- }
-
- /* Write table description header */
- { CHECK_V_F(hSize, HUF_writeCTable (op, dstSize, table->CTable, maxSymbolValue, huffLog) );
- /* Check if using previous huffman table is beneficial */
- if (repeat && *repeat != HUF_repeat_none) {
- size_t const oldSize = HUF_estimateCompressedSize(oldHufTable, table->count, maxSymbolValue);
- size_t const newSize = HUF_estimateCompressedSize(table->CTable, table->count, maxSymbolValue);
- if (oldSize <= hSize + newSize || hSize + 12 >= srcSize) {
- return HUF_compressCTable_internal(ostart, op, oend,
- src, srcSize,
- nbStreams, oldHufTable, bmi2);
- } }
-
- /* Use the new huffman table */
- if (hSize + 12ul >= srcSize) { return 0; }
- op += hSize;
- if (repeat) { *repeat = HUF_repeat_none; }
- if (oldHufTable)
- memcpy(oldHufTable, table->CTable, sizeof(table->CTable)); /* Save new table */
- }
- return HUF_compressCTable_internal(ostart, op, oend,
- src, srcSize,
- nbStreams, table->CTable, bmi2);
-}
-
-
-size_t HUF_compress1X_wksp (void* dst, size_t dstSize,
- const void* src, size_t srcSize,
- unsigned maxSymbolValue, unsigned huffLog,
- void* workSpace, size_t wkspSize)
-{
- return HUF_compress_internal(dst, dstSize, src, srcSize,
- maxSymbolValue, huffLog, HUF_singleStream,
- workSpace, wkspSize,
- NULL, NULL, 0, 0 /*bmi2*/);
-}
-
-size_t HUF_compress1X_repeat (void* dst, size_t dstSize,
- const void* src, size_t srcSize,
- unsigned maxSymbolValue, unsigned huffLog,
- void* workSpace, size_t wkspSize,
- HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2)
-{
- return HUF_compress_internal(dst, dstSize, src, srcSize,
- maxSymbolValue, huffLog, HUF_singleStream,
- workSpace, wkspSize, hufTable,
- repeat, preferRepeat, bmi2);
-}
-
-size_t HUF_compress1X (void* dst, size_t dstSize,
- const void* src, size_t srcSize,
- unsigned maxSymbolValue, unsigned huffLog)
-{
- unsigned workSpace[HUF_WORKSPACE_SIZE_U32];
- return HUF_compress1X_wksp(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, workSpace, sizeof(workSpace));
-}
-
-/* HUF_compress4X_repeat():
- * compress input using 4 streams.
- * provide workspace to generate compression tables */
-size_t HUF_compress4X_wksp (void* dst, size_t dstSize,
- const void* src, size_t srcSize,
- unsigned maxSymbolValue, unsigned huffLog,
- void* workSpace, size_t wkspSize)
-{
- return HUF_compress_internal(dst, dstSize, src, srcSize,
- maxSymbolValue, huffLog, HUF_fourStreams,
- workSpace, wkspSize,
- NULL, NULL, 0, 0 /*bmi2*/);
-}
-
-/* HUF_compress4X_repeat():
- * compress input using 4 streams.
- * re-use an existing huffman compression table */
-size_t HUF_compress4X_repeat (void* dst, size_t dstSize,
- const void* src, size_t srcSize,
- unsigned maxSymbolValue, unsigned huffLog,
- void* workSpace, size_t wkspSize,
- HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2)
-{
- return HUF_compress_internal(dst, dstSize, src, srcSize,
- maxSymbolValue, huffLog, HUF_fourStreams,
- workSpace, wkspSize,
- hufTable, repeat, preferRepeat, bmi2);
-}
-
-size_t HUF_compress2 (void* dst, size_t dstSize,
- const void* src, size_t srcSize,
- unsigned maxSymbolValue, unsigned huffLog)
-{
- unsigned workSpace[HUF_WORKSPACE_SIZE_U32];
- return HUF_compress4X_wksp(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, workSpace, sizeof(workSpace));
-}
-
-size_t HUF_compress (void* dst, size_t maxDstSize, const void* src, size_t srcSize)
-{
- return HUF_compress2(dst, maxDstSize, src, srcSize, 255, HUF_TABLELOG_DEFAULT);
-}
-/**** ended inlining compress/huf_compress.c ****/
-/**** start inlining compress/zstd_compress_literals.c ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
- /*-*************************************
- * Dependencies
- ***************************************/
-/**** start inlining zstd_compress_literals.h ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-#ifndef ZSTD_COMPRESS_LITERALS_H
-#define ZSTD_COMPRESS_LITERALS_H
-
-/**** start inlining zstd_compress_internal.h ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-/* This header contains definitions
- * that shall **only** be used by modules within lib/compress.
- */
-
-#ifndef ZSTD_COMPRESS_H
-#define ZSTD_COMPRESS_H
-
-/*-*************************************
-* Dependencies
-***************************************/
-/**** skipping file: ../common/zstd_internal.h ****/
-/**** start inlining zstd_cwksp.h ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-#ifndef ZSTD_CWKSP_H
-#define ZSTD_CWKSP_H
-
-/*-*************************************
-* Dependencies
-***************************************/
-/**** skipping file: ../common/zstd_internal.h ****/
-
-#if defined (__cplusplus)
-extern "C" {
-#endif
-
-/*-*************************************
-* Constants
-***************************************/
-
-/* Since the workspace is effectively its own little malloc implementation /
- * arena, when we run under ASAN, we should similarly insert redzones between
- * each internal element of the workspace, so ASAN will catch overruns that
- * reach outside an object but that stay inside the workspace.
- *
- * This defines the size of that redzone.
- */
-#ifndef ZSTD_CWKSP_ASAN_REDZONE_SIZE
-#define ZSTD_CWKSP_ASAN_REDZONE_SIZE 128
-#endif
-
-/*-*************************************
-* Structures
-***************************************/
-typedef enum {
- ZSTD_cwksp_alloc_objects,
- ZSTD_cwksp_alloc_buffers,
- ZSTD_cwksp_alloc_aligned
-} ZSTD_cwksp_alloc_phase_e;
-
-/**
- * Zstd fits all its internal datastructures into a single continuous buffer,
- * so that it only needs to perform a single OS allocation (or so that a buffer
- * can be provided to it and it can perform no allocations at all). This buffer
- * is called the workspace.
- *
- * Several optimizations complicate that process of allocating memory ranges
- * from this workspace for each internal datastructure:
- *
- * - These different internal datastructures have different setup requirements:
- *
- * - The static objects need to be cleared once and can then be trivially
- * reused for each compression.
- *
- * - Various buffers don't need to be initialized at all--they are always
- * written into before they're read.
- *
- * - The matchstate tables have a unique requirement that they don't need
- * their memory to be totally cleared, but they do need the memory to have
- * some bound, i.e., a guarantee that all values in the memory they've been
- * allocated is less than some maximum value (which is the starting value
- * for the indices that they will then use for compression). When this
- * guarantee is provided to them, they can use the memory without any setup
- * work. When it can't, they have to clear the area.
- *
- * - These buffers also have different alignment requirements.
- *
- * - We would like to reuse the objects in the workspace for multiple
- * compressions without having to perform any expensive reallocation or
- * reinitialization work.
- *
- * - We would like to be able to efficiently reuse the workspace across
- * multiple compressions **even when the compression parameters change** and
- * we need to resize some of the objects (where possible).
- *
- * To attempt to manage this buffer, given these constraints, the ZSTD_cwksp
- * abstraction was created. It works as follows:
- *
- * Workspace Layout:
- *
- * [ ... workspace ... ]
- * [objects][tables ... ->] free space [<- ... aligned][<- ... buffers]
- *
- * The various objects that live in the workspace are divided into the
- * following categories, and are allocated separately:
- *
- * - Static objects: this is optionally the enclosing ZSTD_CCtx or ZSTD_CDict,
- * so that literally everything fits in a single buffer. Note: if present,
- * this must be the first object in the workspace, since ZSTD_free{CCtx,
- * CDict}() rely on a pointer comparison to see whether one or two frees are
- * required.
- *
- * - Fixed size objects: these are fixed-size, fixed-count objects that are
- * nonetheless "dynamically" allocated in the workspace so that we can
- * control how they're initialized separately from the broader ZSTD_CCtx.
- * Examples:
- * - Entropy Workspace
- * - 2 x ZSTD_compressedBlockState_t
- * - CDict dictionary contents
- *
- * - Tables: these are any of several different datastructures (hash tables,
- * chain tables, binary trees) that all respect a common format: they are
- * uint32_t arrays, all of whose values are between 0 and (nextSrc - base).
- * Their sizes depend on the cparams.
- *
- * - Aligned: these buffers are used for various purposes that require 4 byte
- * alignment, but don't require any initialization before they're used.
- *
- * - Buffers: these buffers are used for various purposes that don't require
- * any alignment or initialization before they're used. This means they can
- * be moved around at no cost for a new compression.
- *
- * Allocating Memory:
- *
- * The various types of objects must be allocated in order, so they can be
- * correctly packed into the workspace buffer. That order is:
- *
- * 1. Objects
- * 2. Buffers
- * 3. Aligned
- * 4. Tables
- *
- * Attempts to reserve objects of different types out of order will fail.
- */
-typedef struct {
- void* workspace;
- void* workspaceEnd;
-
- void* objectEnd;
- void* tableEnd;
- void* tableValidEnd;
- void* allocStart;
-
- int allocFailed;
- int workspaceOversizedDuration;
- ZSTD_cwksp_alloc_phase_e phase;
-} ZSTD_cwksp;
-
-/*-*************************************
-* Functions
-***************************************/
-
-MEM_STATIC size_t ZSTD_cwksp_available_space(ZSTD_cwksp* ws);
-
-MEM_STATIC void ZSTD_cwksp_assert_internal_consistency(ZSTD_cwksp* ws) {
- (void)ws;
- assert(ws->workspace <= ws->objectEnd);
- assert(ws->objectEnd <= ws->tableEnd);
- assert(ws->objectEnd <= ws->tableValidEnd);
- assert(ws->tableEnd <= ws->allocStart);
- assert(ws->tableValidEnd <= ws->allocStart);
- assert(ws->allocStart <= ws->workspaceEnd);
-}
-
-/**
- * Align must be a power of 2.
- */
-MEM_STATIC size_t ZSTD_cwksp_align(size_t size, size_t const align) {
- size_t const mask = align - 1;
- assert((align & mask) == 0);
- return (size + mask) & ~mask;
-}
-
-/**
- * Use this to determine how much space in the workspace we will consume to
- * allocate this object. (Normally it should be exactly the size of the object,
- * but under special conditions, like ASAN, where we pad each object, it might
- * be larger.)
- *
- * Since tables aren't currently redzoned, you don't need to call through this
- * to figure out how much space you need for the matchState tables. Everything
- * else is though.
- */
-MEM_STATIC size_t ZSTD_cwksp_alloc_size(size_t size) {
-#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
- return size + 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE;
-#else
- return size;
-#endif
-}
-
-MEM_STATIC void ZSTD_cwksp_internal_advance_phase(
- ZSTD_cwksp* ws, ZSTD_cwksp_alloc_phase_e phase) {
- assert(phase >= ws->phase);
- if (phase > ws->phase) {
- if (ws->phase < ZSTD_cwksp_alloc_buffers &&
- phase >= ZSTD_cwksp_alloc_buffers) {
- ws->tableValidEnd = ws->objectEnd;
- }
- if (ws->phase < ZSTD_cwksp_alloc_aligned &&
- phase >= ZSTD_cwksp_alloc_aligned) {
- /* If unaligned allocations down from a too-large top have left us
- * unaligned, we need to realign our alloc ptr. Technically, this
- * can consume space that is unaccounted for in the neededSpace
- * calculation. However, I believe this can only happen when the
- * workspace is too large, and specifically when it is too large
- * by a larger margin than the space that will be consumed. */
- /* TODO: cleaner, compiler warning friendly way to do this??? */
- ws->allocStart = (BYTE*)ws->allocStart - ((size_t)ws->allocStart & (sizeof(U32)-1));
- if (ws->allocStart < ws->tableValidEnd) {
- ws->tableValidEnd = ws->allocStart;
- }
- }
- ws->phase = phase;
- }
-}
-
-/**
- * Returns whether this object/buffer/etc was allocated in this workspace.
- */
-MEM_STATIC int ZSTD_cwksp_owns_buffer(const ZSTD_cwksp* ws, const void* ptr) {
- return (ptr != NULL) && (ws->workspace <= ptr) && (ptr <= ws->workspaceEnd);
-}
-
-/**
- * Internal function. Do not use directly.
- */
-MEM_STATIC void* ZSTD_cwksp_reserve_internal(
- ZSTD_cwksp* ws, size_t bytes, ZSTD_cwksp_alloc_phase_e phase) {
- void* alloc;
- void* bottom = ws->tableEnd;
- ZSTD_cwksp_internal_advance_phase(ws, phase);
- alloc = (BYTE *)ws->allocStart - bytes;
-
-#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
- /* over-reserve space */
- alloc = (BYTE *)alloc - 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE;
-#endif
-
- DEBUGLOG(5, "cwksp: reserving %p %zd bytes, %zd bytes remaining",
- alloc, bytes, ZSTD_cwksp_available_space(ws) - bytes);
- ZSTD_cwksp_assert_internal_consistency(ws);
- assert(alloc >= bottom);
- if (alloc < bottom) {
- DEBUGLOG(4, "cwksp: alloc failed!");
- ws->allocFailed = 1;
- return NULL;
- }
- if (alloc < ws->tableValidEnd) {
- ws->tableValidEnd = alloc;
- }
- ws->allocStart = alloc;
-
-#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
- /* Move alloc so there's ZSTD_CWKSP_ASAN_REDZONE_SIZE unused space on
- * either size. */
- alloc = (BYTE *)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE;
- __asan_unpoison_memory_region(alloc, bytes);
-#endif
-
- return alloc;
-}
-
-/**
- * Reserves and returns unaligned memory.
- */
-MEM_STATIC BYTE* ZSTD_cwksp_reserve_buffer(ZSTD_cwksp* ws, size_t bytes) {
- return (BYTE*)ZSTD_cwksp_reserve_internal(ws, bytes, ZSTD_cwksp_alloc_buffers);
-}
-
-/**
- * Reserves and returns memory sized on and aligned on sizeof(unsigned).
- */
-MEM_STATIC void* ZSTD_cwksp_reserve_aligned(ZSTD_cwksp* ws, size_t bytes) {
- assert((bytes & (sizeof(U32)-1)) == 0);
- return ZSTD_cwksp_reserve_internal(ws, ZSTD_cwksp_align(bytes, sizeof(U32)), ZSTD_cwksp_alloc_aligned);
-}
-
-/**
- * Aligned on sizeof(unsigned). These buffers have the special property that
- * their values remain constrained, allowing us to re-use them without
- * memset()-ing them.
- */
-MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes) {
- const ZSTD_cwksp_alloc_phase_e phase = ZSTD_cwksp_alloc_aligned;
- void* alloc = ws->tableEnd;
- void* end = (BYTE *)alloc + bytes;
- void* top = ws->allocStart;
-
- DEBUGLOG(5, "cwksp: reserving %p table %zd bytes, %zd bytes remaining",
- alloc, bytes, ZSTD_cwksp_available_space(ws) - bytes);
- assert((bytes & (sizeof(U32)-1)) == 0);
- ZSTD_cwksp_internal_advance_phase(ws, phase);
- ZSTD_cwksp_assert_internal_consistency(ws);
- assert(end <= top);
- if (end > top) {
- DEBUGLOG(4, "cwksp: table alloc failed!");
- ws->allocFailed = 1;
- return NULL;
- }
- ws->tableEnd = end;
-
-#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
- __asan_unpoison_memory_region(alloc, bytes);
-#endif
-
- return alloc;
-}
-
-/**
- * Aligned on sizeof(void*).
- */
-MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) {
- size_t roundedBytes = ZSTD_cwksp_align(bytes, sizeof(void*));
- void* alloc = ws->objectEnd;
- void* end = (BYTE*)alloc + roundedBytes;
-
-#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
- /* over-reserve space */
- end = (BYTE *)end + 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE;
-#endif
-
- DEBUGLOG(5,
- "cwksp: reserving %p object %zd bytes (rounded to %zd), %zd bytes remaining",
- alloc, bytes, roundedBytes, ZSTD_cwksp_available_space(ws) - roundedBytes);
- assert(((size_t)alloc & (sizeof(void*)-1)) == 0);
- assert((bytes & (sizeof(void*)-1)) == 0);
- ZSTD_cwksp_assert_internal_consistency(ws);
- /* we must be in the first phase, no advance is possible */
- if (ws->phase != ZSTD_cwksp_alloc_objects || end > ws->workspaceEnd) {
- DEBUGLOG(4, "cwksp: object alloc failed!");
- ws->allocFailed = 1;
- return NULL;
- }
- ws->objectEnd = end;
- ws->tableEnd = end;
- ws->tableValidEnd = end;
-
-#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
- /* Move alloc so there's ZSTD_CWKSP_ASAN_REDZONE_SIZE unused space on
- * either size. */
- alloc = (BYTE *)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE;
- __asan_unpoison_memory_region(alloc, bytes);
-#endif
-
- return alloc;
-}
-
-MEM_STATIC void ZSTD_cwksp_mark_tables_dirty(ZSTD_cwksp* ws) {
- DEBUGLOG(4, "cwksp: ZSTD_cwksp_mark_tables_dirty");
-
-#if defined (MEMORY_SANITIZER) && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE)
- /* To validate that the table re-use logic is sound, and that we don't
- * access table space that we haven't cleaned, we re-"poison" the table
- * space every time we mark it dirty. */
- {
- size_t size = (BYTE*)ws->tableValidEnd - (BYTE*)ws->objectEnd;
- assert(__msan_test_shadow(ws->objectEnd, size) == -1);
- __msan_poison(ws->objectEnd, size);
- }
-#endif
-
- assert(ws->tableValidEnd >= ws->objectEnd);
- assert(ws->tableValidEnd <= ws->allocStart);
- ws->tableValidEnd = ws->objectEnd;
- ZSTD_cwksp_assert_internal_consistency(ws);
-}
-
-MEM_STATIC void ZSTD_cwksp_mark_tables_clean(ZSTD_cwksp* ws) {
- DEBUGLOG(4, "cwksp: ZSTD_cwksp_mark_tables_clean");
- assert(ws->tableValidEnd >= ws->objectEnd);
- assert(ws->tableValidEnd <= ws->allocStart);
- if (ws->tableValidEnd < ws->tableEnd) {
- ws->tableValidEnd = ws->tableEnd;
- }
- ZSTD_cwksp_assert_internal_consistency(ws);
-}
-
-/**
- * Zero the part of the allocated tables not already marked clean.
- */
-MEM_STATIC void ZSTD_cwksp_clean_tables(ZSTD_cwksp* ws) {
- DEBUGLOG(4, "cwksp: ZSTD_cwksp_clean_tables");
- assert(ws->tableValidEnd >= ws->objectEnd);
- assert(ws->tableValidEnd <= ws->allocStart);
- if (ws->tableValidEnd < ws->tableEnd) {
- memset(ws->tableValidEnd, 0, (BYTE*)ws->tableEnd - (BYTE*)ws->tableValidEnd);
- }
- ZSTD_cwksp_mark_tables_clean(ws);
-}
-
-/**
- * Invalidates table allocations.
- * All other allocations remain valid.
- */
-MEM_STATIC void ZSTD_cwksp_clear_tables(ZSTD_cwksp* ws) {
- DEBUGLOG(4, "cwksp: clearing tables!");
-
-#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
- {
- size_t size = (BYTE*)ws->tableValidEnd - (BYTE*)ws->objectEnd;
- __asan_poison_memory_region(ws->objectEnd, size);
- }
-#endif
-
- ws->tableEnd = ws->objectEnd;
- ZSTD_cwksp_assert_internal_consistency(ws);
-}
-
-/**
- * Invalidates all buffer, aligned, and table allocations.
- * Object allocations remain valid.
- */
-MEM_STATIC void ZSTD_cwksp_clear(ZSTD_cwksp* ws) {
- DEBUGLOG(4, "cwksp: clearing!");
-
-#if defined (MEMORY_SANITIZER) && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE)
- /* To validate that the context re-use logic is sound, and that we don't
- * access stuff that this compression hasn't initialized, we re-"poison"
- * the workspace (or at least the non-static, non-table parts of it)
- * every time we start a new compression. */
- {
- size_t size = (BYTE*)ws->workspaceEnd - (BYTE*)ws->tableValidEnd;
- __msan_poison(ws->tableValidEnd, size);
- }
-#endif
-
-#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
- {
- size_t size = (BYTE*)ws->workspaceEnd - (BYTE*)ws->objectEnd;
- __asan_poison_memory_region(ws->objectEnd, size);
- }
-#endif
-
- ws->tableEnd = ws->objectEnd;
- ws->allocStart = ws->workspaceEnd;
- ws->allocFailed = 0;
- if (ws->phase > ZSTD_cwksp_alloc_buffers) {
- ws->phase = ZSTD_cwksp_alloc_buffers;
- }
- ZSTD_cwksp_assert_internal_consistency(ws);
-}
-
-/**
- * The provided workspace takes ownership of the buffer [start, start+size).
- * Any existing values in the workspace are ignored (the previously managed
- * buffer, if present, must be separately freed).
- */
-MEM_STATIC void ZSTD_cwksp_init(ZSTD_cwksp* ws, void* start, size_t size) {
- DEBUGLOG(4, "cwksp: init'ing workspace with %zd bytes", size);
- assert(((size_t)start & (sizeof(void*)-1)) == 0); /* ensure correct alignment */
- ws->workspace = start;
- ws->workspaceEnd = (BYTE*)start + size;
- ws->objectEnd = ws->workspace;
- ws->tableValidEnd = ws->objectEnd;
- ws->phase = ZSTD_cwksp_alloc_objects;
- ZSTD_cwksp_clear(ws);
- ws->workspaceOversizedDuration = 0;
- ZSTD_cwksp_assert_internal_consistency(ws);
-}
-
-MEM_STATIC size_t ZSTD_cwksp_create(ZSTD_cwksp* ws, size_t size, ZSTD_customMem customMem) {
- void* workspace = ZSTD_malloc(size, customMem);
- DEBUGLOG(4, "cwksp: creating new workspace with %zd bytes", size);
- RETURN_ERROR_IF(workspace == NULL, memory_allocation, "NULL pointer!");
- ZSTD_cwksp_init(ws, workspace, size);
- return 0;
-}
-
-MEM_STATIC void ZSTD_cwksp_free(ZSTD_cwksp* ws, ZSTD_customMem customMem) {
- void *ptr = ws->workspace;
- DEBUGLOG(4, "cwksp: freeing workspace");
- memset(ws, 0, sizeof(ZSTD_cwksp));
- ZSTD_free(ptr, customMem);
-}
-
-/**
- * Moves the management of a workspace from one cwksp to another. The src cwksp
- * is left in an invalid state (src must be re-init()'ed before its used again).
- */
-MEM_STATIC void ZSTD_cwksp_move(ZSTD_cwksp* dst, ZSTD_cwksp* src) {
- *dst = *src;
- memset(src, 0, sizeof(ZSTD_cwksp));
-}
-
-MEM_STATIC size_t ZSTD_cwksp_sizeof(const ZSTD_cwksp* ws) {
- return (size_t)((BYTE*)ws->workspaceEnd - (BYTE*)ws->workspace);
-}
-
-MEM_STATIC int ZSTD_cwksp_reserve_failed(const ZSTD_cwksp* ws) {
- return ws->allocFailed;
-}
-
-/*-*************************************
-* Functions Checking Free Space
-***************************************/
-
-MEM_STATIC size_t ZSTD_cwksp_available_space(ZSTD_cwksp* ws) {
- return (size_t)((BYTE*)ws->allocStart - (BYTE*)ws->tableEnd);
-}
-
-MEM_STATIC int ZSTD_cwksp_check_available(ZSTD_cwksp* ws, size_t additionalNeededSpace) {
- return ZSTD_cwksp_available_space(ws) >= additionalNeededSpace;
-}
-
-MEM_STATIC int ZSTD_cwksp_check_too_large(ZSTD_cwksp* ws, size_t additionalNeededSpace) {
- return ZSTD_cwksp_check_available(
- ws, additionalNeededSpace * ZSTD_WORKSPACETOOLARGE_FACTOR);
-}
-
-MEM_STATIC int ZSTD_cwksp_check_wasteful(ZSTD_cwksp* ws, size_t additionalNeededSpace) {
- return ZSTD_cwksp_check_too_large(ws, additionalNeededSpace)
- && ws->workspaceOversizedDuration > ZSTD_WORKSPACETOOLARGE_MAXDURATION;
-}
-
-MEM_STATIC void ZSTD_cwksp_bump_oversized_duration(
- ZSTD_cwksp* ws, size_t additionalNeededSpace) {
- if (ZSTD_cwksp_check_too_large(ws, additionalNeededSpace)) {
- ws->workspaceOversizedDuration++;
- } else {
- ws->workspaceOversizedDuration = 0;
- }
-}
-
-#if defined (__cplusplus)
-}
-#endif
-
-#endif /* ZSTD_CWKSP_H */
-/**** ended inlining zstd_cwksp.h ****/
-#ifdef ZSTD_MULTITHREAD
-/**** start inlining zstdmt_compress.h ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
- #ifndef ZSTDMT_COMPRESS_H
- #define ZSTDMT_COMPRESS_H
-
- #if defined (__cplusplus)
- extern "C" {
- #endif
-
-
-/* Note : This is an internal API.
- * These APIs used to be exposed with ZSTDLIB_API,
- * because it used to be the only way to invoke MT compression.
- * Now, it's recommended to use ZSTD_compress2 and ZSTD_compressStream2()
- * instead.
- *
- * If you depend on these APIs and can't switch, then define
- * ZSTD_LEGACY_MULTITHREADED_API when making the dynamic library.
- * However, we may completely remove these functions in a future
- * release, so please switch soon.
- *
- * This API requires ZSTD_MULTITHREAD to be defined during compilation,
- * otherwise ZSTDMT_createCCtx*() will fail.
- */
-
-#ifdef ZSTD_LEGACY_MULTITHREADED_API
-# define ZSTDMT_API ZSTDLIB_API
-#else
-# define ZSTDMT_API
-#endif
-
-/* === Dependencies === */
-#include <stddef.h> /* size_t */
-#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_parameters */
-/**** skipping file: ../zstd.h ****/
-
-
-/* === Constants === */
-#ifndef ZSTDMT_NBWORKERS_MAX
-# define ZSTDMT_NBWORKERS_MAX 200
-#endif
-#ifndef ZSTDMT_JOBSIZE_MIN
-# define ZSTDMT_JOBSIZE_MIN (1 MB)
-#endif
-#define ZSTDMT_JOBLOG_MAX (MEM_32bits() ? 29 : 30)
-#define ZSTDMT_JOBSIZE_MAX (MEM_32bits() ? (512 MB) : (1024 MB))
-
-
-/* === Memory management === */
-typedef struct ZSTDMT_CCtx_s ZSTDMT_CCtx;
-/* Requires ZSTD_MULTITHREAD to be defined during compilation, otherwise it will return NULL. */
-ZSTDMT_API ZSTDMT_CCtx* ZSTDMT_createCCtx(unsigned nbWorkers);
-/* Requires ZSTD_MULTITHREAD to be defined during compilation, otherwise it will return NULL. */
-ZSTDMT_API ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbWorkers,
- ZSTD_customMem cMem);
-ZSTDMT_API size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx);
-
-ZSTDMT_API size_t ZSTDMT_sizeof_CCtx(ZSTDMT_CCtx* mtctx);
-
-
-/* === Simple one-pass compression function === */
-
-ZSTDMT_API size_t ZSTDMT_compressCCtx(ZSTDMT_CCtx* mtctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- int compressionLevel);
-
-
-
-/* === Streaming functions === */
-
-ZSTDMT_API size_t ZSTDMT_initCStream(ZSTDMT_CCtx* mtctx, int compressionLevel);
-ZSTDMT_API size_t ZSTDMT_resetCStream(ZSTDMT_CCtx* mtctx, unsigned long long pledgedSrcSize); /**< if srcSize is not known at reset time, use ZSTD_CONTENTSIZE_UNKNOWN. Note: for compatibility with older programs, 0 means the same as ZSTD_CONTENTSIZE_UNKNOWN, but it will change in the future to mean "empty" */
-
-ZSTDMT_API size_t ZSTDMT_nextInputSizeHint(const ZSTDMT_CCtx* mtctx);
-ZSTDMT_API size_t ZSTDMT_compressStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input);
-
-ZSTDMT_API size_t ZSTDMT_flushStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output); /**< @return : 0 == all flushed; >0 : still some data to be flushed; or an error code (ZSTD_isError()) */
-ZSTDMT_API size_t ZSTDMT_endStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output); /**< @return : 0 == all flushed; >0 : still some data to be flushed; or an error code (ZSTD_isError()) */
-
-
-/* === Advanced functions and parameters === */
-
-ZSTDMT_API size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- const ZSTD_CDict* cdict,
- ZSTD_parameters params,
- int overlapLog);
-
-ZSTDMT_API size_t ZSTDMT_initCStream_advanced(ZSTDMT_CCtx* mtctx,
- const void* dict, size_t dictSize, /* dict can be released after init, a local copy is preserved within zcs */
- ZSTD_parameters params,
- unsigned long long pledgedSrcSize); /* pledgedSrcSize is optional and can be zero == unknown */
-
-ZSTDMT_API size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx,
- const ZSTD_CDict* cdict,
- ZSTD_frameParameters fparams,
- unsigned long long pledgedSrcSize); /* note : zero means empty */
-
-/* ZSTDMT_parameter :
- * List of parameters that can be set using ZSTDMT_setMTCtxParameter() */
-typedef enum {
- ZSTDMT_p_jobSize, /* Each job is compressed in parallel. By default, this value is dynamically determined depending on compression parameters. Can be set explicitly here. */
- ZSTDMT_p_overlapLog, /* Each job may reload a part of previous job to enhance compression ratio; 0 == no overlap, 6(default) == use 1/8th of window, >=9 == use full window. This is a "sticky" parameter : its value will be re-used on next compression job */
- ZSTDMT_p_rsyncable /* Enables rsyncable mode. */
-} ZSTDMT_parameter;
-
-/* ZSTDMT_setMTCtxParameter() :
- * allow setting individual parameters, one at a time, among a list of enums defined in ZSTDMT_parameter.
- * The function must be called typically after ZSTD_createCCtx() but __before ZSTDMT_init*() !__
- * Parameters not explicitly reset by ZSTDMT_init*() remain the same in consecutive compression sessions.
- * @return : 0, or an error code (which can be tested using ZSTD_isError()) */
-ZSTDMT_API size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, int value);
-
-/* ZSTDMT_getMTCtxParameter() :
- * Query the ZSTDMT_CCtx for a parameter value.
- * @return : 0, or an error code (which can be tested using ZSTD_isError()) */
-ZSTDMT_API size_t ZSTDMT_getMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, int* value);
-
-
-/*! ZSTDMT_compressStream_generic() :
- * Combines ZSTDMT_compressStream() with optional ZSTDMT_flushStream() or ZSTDMT_endStream()
- * depending on flush directive.
- * @return : minimum amount of data still to be flushed
- * 0 if fully flushed
- * or an error code
- * note : needs to be init using any ZSTD_initCStream*() variant */
-ZSTDMT_API size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
- ZSTD_outBuffer* output,
- ZSTD_inBuffer* input,
- ZSTD_EndDirective endOp);
-
-
-/* ========================================================
- * === Private interface, for use by ZSTD_compress.c ===
- * === Not exposed in libzstd. Never invoke directly ===
- * ======================================================== */
-
- /*! ZSTDMT_toFlushNow()
- * Tell how many bytes are ready to be flushed immediately.
- * Probe the oldest active job (not yet entirely flushed) and check its output buffer.
- * If return 0, it means there is no active job,
- * or, it means oldest job is still active, but everything produced has been flushed so far,
- * therefore flushing is limited by speed of oldest job. */
-size_t ZSTDMT_toFlushNow(ZSTDMT_CCtx* mtctx);
-
-/*! ZSTDMT_CCtxParam_setMTCtxParameter()
- * like ZSTDMT_setMTCtxParameter(), but into a ZSTD_CCtx_Params */
-size_t ZSTDMT_CCtxParam_setMTCtxParameter(ZSTD_CCtx_params* params, ZSTDMT_parameter parameter, int value);
-
-/*! ZSTDMT_CCtxParam_setNbWorkers()
- * Set nbWorkers, and clamp it.
- * Also reset jobSize and overlapLog */
-size_t ZSTDMT_CCtxParam_setNbWorkers(ZSTD_CCtx_params* params, unsigned nbWorkers);
-
-/*! ZSTDMT_updateCParams_whileCompressing() :
- * Updates only a selected set of compression parameters, to remain compatible with current frame.
- * New parameters will be applied to next compression job. */
-void ZSTDMT_updateCParams_whileCompressing(ZSTDMT_CCtx* mtctx, const ZSTD_CCtx_params* cctxParams);
-
-/*! ZSTDMT_getFrameProgression():
- * tells how much data has been consumed (input) and produced (output) for current frame.
- * able to count progression inside worker threads.
- */
-ZSTD_frameProgression ZSTDMT_getFrameProgression(ZSTDMT_CCtx* mtctx);
-
-
-/*! ZSTDMT_initCStream_internal() :
- * Private use only. Init streaming operation.
- * expects params to be valid.
- * must receive dict, or cdict, or none, but not both.
- * @return : 0, or an error code */
-size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs,
- const void* dict, size_t dictSize, ZSTD_dictContentType_e dictContentType,
- const ZSTD_CDict* cdict,
- ZSTD_CCtx_params params, unsigned long long pledgedSrcSize);
-
-
-#if defined (__cplusplus)
-}
-#endif
-
-#endif /* ZSTDMT_COMPRESS_H */
-/**** ended inlining zstdmt_compress.h ****/
-#endif
-
-#if defined (__cplusplus)
-extern "C" {
-#endif
-
-
-/*-*************************************
-* Constants
-***************************************/
-#define kSearchStrength 8
-#define HASH_READ_SIZE 8
-#define ZSTD_DUBT_UNSORTED_MARK 1 /* For btlazy2 strategy, index ZSTD_DUBT_UNSORTED_MARK==1 means "unsorted".
- It could be confused for a real successor at index "1", if sorted as larger than its predecessor.
- It's not a big deal though : candidate will just be sorted again.
- Additionally, candidate position 1 will be lost.
- But candidate 1 cannot hide a large tree of candidates, so it's a minimal loss.
- The benefit is that ZSTD_DUBT_UNSORTED_MARK cannot be mishandled after table re-use with a different strategy.
- This constant is required by ZSTD_compressBlock_btlazy2() and ZSTD_reduceTable_internal() */
-
-
-/*-*************************************
-* Context memory management
-***************************************/
-typedef enum { ZSTDcs_created=0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e;
-typedef enum { zcss_init=0, zcss_load, zcss_flush } ZSTD_cStreamStage;
-
-typedef struct ZSTD_prefixDict_s {
- const void* dict;
- size_t dictSize;
- ZSTD_dictContentType_e dictContentType;
-} ZSTD_prefixDict;
-
-typedef struct {
- void* dictBuffer;
- void const* dict;
- size_t dictSize;
- ZSTD_dictContentType_e dictContentType;
- ZSTD_CDict* cdict;
-} ZSTD_localDict;
-
-typedef struct {
- U32 CTable[HUF_CTABLE_SIZE_U32(255)];
- HUF_repeat repeatMode;
-} ZSTD_hufCTables_t;
-
-typedef struct {
- FSE_CTable offcodeCTable[FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
- FSE_CTable matchlengthCTable[FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
- FSE_CTable litlengthCTable[FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
- FSE_repeat offcode_repeatMode;
- FSE_repeat matchlength_repeatMode;
- FSE_repeat litlength_repeatMode;
-} ZSTD_fseCTables_t;
-
-typedef struct {
- ZSTD_hufCTables_t huf;
- ZSTD_fseCTables_t fse;
-} ZSTD_entropyCTables_t;
-
-typedef struct {
- U32 off;
- U32 len;
-} ZSTD_match_t;
-
-typedef struct {
- int price;
- U32 off;
- U32 mlen;
- U32 litlen;
- U32 rep[ZSTD_REP_NUM];
-} ZSTD_optimal_t;
-
-typedef enum { zop_dynamic=0, zop_predef } ZSTD_OptPrice_e;
-
-typedef struct {
- /* All tables are allocated inside cctx->workspace by ZSTD_resetCCtx_internal() */
- unsigned* litFreq; /* table of literals statistics, of size 256 */
- unsigned* litLengthFreq; /* table of litLength statistics, of size (MaxLL+1) */
- unsigned* matchLengthFreq; /* table of matchLength statistics, of size (MaxML+1) */
- unsigned* offCodeFreq; /* table of offCode statistics, of size (MaxOff+1) */
- ZSTD_match_t* matchTable; /* list of found matches, of size ZSTD_OPT_NUM+1 */
- ZSTD_optimal_t* priceTable; /* All positions tracked by optimal parser, of size ZSTD_OPT_NUM+1 */
-
- U32 litSum; /* nb of literals */
- U32 litLengthSum; /* nb of litLength codes */
- U32 matchLengthSum; /* nb of matchLength codes */
- U32 offCodeSum; /* nb of offset codes */
- U32 litSumBasePrice; /* to compare to log2(litfreq) */
- U32 litLengthSumBasePrice; /* to compare to log2(llfreq) */
- U32 matchLengthSumBasePrice;/* to compare to log2(mlfreq) */
- U32 offCodeSumBasePrice; /* to compare to log2(offreq) */
- ZSTD_OptPrice_e priceType; /* prices can be determined dynamically, or follow a pre-defined cost structure */
- const ZSTD_entropyCTables_t* symbolCosts; /* pre-calculated dictionary statistics */
- ZSTD_literalCompressionMode_e literalCompressionMode;
-} optState_t;
-
-typedef struct {
- ZSTD_entropyCTables_t entropy;
- U32 rep[ZSTD_REP_NUM];
-} ZSTD_compressedBlockState_t;
-
-typedef struct {
- BYTE const* nextSrc; /* next block here to continue on current prefix */
- BYTE const* base; /* All regular indexes relative to this position */
- BYTE const* dictBase; /* extDict indexes relative to this position */
- U32 dictLimit; /* below that point, need extDict */
- U32 lowLimit; /* below that point, no more valid data */
-} ZSTD_window_t;
-
-typedef struct ZSTD_matchState_t ZSTD_matchState_t;
-struct ZSTD_matchState_t {
- ZSTD_window_t window; /* State for window round buffer management */
- U32 loadedDictEnd; /* index of end of dictionary, within context's referential.
- * When loadedDictEnd != 0, a dictionary is in use, and still valid.
- * This relies on a mechanism to set loadedDictEnd=0 when dictionary is no longer within distance.
- * Such mechanism is provided within ZSTD_window_enforceMaxDist() and ZSTD_checkDictValidity().
- * When dict referential is copied into active context (i.e. not attached),
- * loadedDictEnd == dictSize, since referential starts from zero.
- */
- U32 nextToUpdate; /* index from which to continue table update */
- U32 hashLog3; /* dispatch table for matches of len==3 : larger == faster, more memory */
- U32* hashTable;
- U32* hashTable3;
- U32* chainTable;
- optState_t opt; /* optimal parser state */
- const ZSTD_matchState_t* dictMatchState;
- ZSTD_compressionParameters cParams;
-};
-
-typedef struct {
- ZSTD_compressedBlockState_t* prevCBlock;
- ZSTD_compressedBlockState_t* nextCBlock;
- ZSTD_matchState_t matchState;
-} ZSTD_blockState_t;
-
-typedef struct {
- U32 offset;
- U32 checksum;
-} ldmEntry_t;
-
-typedef struct {
- ZSTD_window_t window; /* State for the window round buffer management */
- ldmEntry_t* hashTable;
- U32 loadedDictEnd;
- BYTE* bucketOffsets; /* Next position in bucket to insert entry */
- U64 hashPower; /* Used to compute the rolling hash.
- * Depends on ldmParams.minMatchLength */
-} ldmState_t;
-
-typedef struct {
- U32 enableLdm; /* 1 if enable long distance matching */
- U32 hashLog; /* Log size of hashTable */
- U32 bucketSizeLog; /* Log bucket size for collision resolution, at most 8 */
- U32 minMatchLength; /* Minimum match length */
- U32 hashRateLog; /* Log number of entries to skip */
- U32 windowLog; /* Window log for the LDM */
-} ldmParams_t;
-
-typedef struct {
- U32 offset;
- U32 litLength;
- U32 matchLength;
-} rawSeq;
-
-typedef struct {
- rawSeq* seq; /* The start of the sequences */
- size_t pos; /* The position where reading stopped. <= size. */
- size_t size; /* The number of sequences. <= capacity. */
- size_t capacity; /* The capacity starting from `seq` pointer */
-} rawSeqStore_t;
-
-typedef struct {
- int collectSequences;
- ZSTD_Sequence* seqStart;
- size_t seqIndex;
- size_t maxSequences;
-} SeqCollector;
-
-struct ZSTD_CCtx_params_s {
- ZSTD_format_e format;
- ZSTD_compressionParameters cParams;
- ZSTD_frameParameters fParams;
-
- int compressionLevel;
- int forceWindow; /* force back-references to respect limit of
- * 1<<wLog, even for dictionary */
- size_t targetCBlockSize; /* Tries to fit compressed block size to be around targetCBlockSize.
- * No target when targetCBlockSize == 0.
- * There is no guarantee on compressed block size */
- int srcSizeHint; /* User's best guess of source size.
- * Hint is not valid when srcSizeHint == 0.
- * There is no guarantee that hint is close to actual source size */
-
- ZSTD_dictAttachPref_e attachDictPref;
- ZSTD_literalCompressionMode_e literalCompressionMode;
-
- /* Multithreading: used to pass parameters to mtctx */
- int nbWorkers;
- size_t jobSize;
- int overlapLog;
- int rsyncable;
-
- /* Long distance matching parameters */
- ldmParams_t ldmParams;
-
- /* Internal use, for createCCtxParams() and freeCCtxParams() only */
- ZSTD_customMem customMem;
-}; /* typedef'd to ZSTD_CCtx_params within "zstd.h" */
-
-struct ZSTD_CCtx_s {
- ZSTD_compressionStage_e stage;
- int cParamsChanged; /* == 1 if cParams(except wlog) or compression level are changed in requestedParams. Triggers transmission of new params to ZSTDMT (if available) then reset to 0. */
- int bmi2; /* == 1 if the CPU supports BMI2 and 0 otherwise. CPU support is determined dynamically once per context lifetime. */
- ZSTD_CCtx_params requestedParams;
- ZSTD_CCtx_params appliedParams;
- U32 dictID;
-
- ZSTD_cwksp workspace; /* manages buffer for dynamic allocations */
- size_t blockSize;
- unsigned long long pledgedSrcSizePlusOne; /* this way, 0 (default) == unknown */
- unsigned long long consumedSrcSize;
- unsigned long long producedCSize;
- XXH64_state_t xxhState;
- ZSTD_customMem customMem;
- size_t staticSize;
- SeqCollector seqCollector;
- int isFirstBlock;
- int initialized;
-
- seqStore_t seqStore; /* sequences storage ptrs */
- ldmState_t ldmState; /* long distance matching state */
- rawSeq* ldmSequences; /* Storage for the ldm output sequences */
- size_t maxNbLdmSequences;
- rawSeqStore_t externSeqStore; /* Mutable reference to external sequences */
- ZSTD_blockState_t blockState;
- U32* entropyWorkspace; /* entropy workspace of HUF_WORKSPACE_SIZE bytes */
-
- /* streaming */
- char* inBuff;
- size_t inBuffSize;
- size_t inToCompress;
- size_t inBuffPos;
- size_t inBuffTarget;
- char* outBuff;
- size_t outBuffSize;
- size_t outBuffContentSize;
- size_t outBuffFlushedSize;
- ZSTD_cStreamStage streamStage;
- U32 frameEnded;
-
- /* Dictionary */
- ZSTD_localDict localDict;
- const ZSTD_CDict* cdict;
- ZSTD_prefixDict prefixDict; /* single-usage dictionary */
-
- /* Multi-threading */
-#ifdef ZSTD_MULTITHREAD
- ZSTDMT_CCtx* mtctx;
-#endif
-};
-
-typedef enum { ZSTD_dtlm_fast, ZSTD_dtlm_full } ZSTD_dictTableLoadMethod_e;
-
-typedef enum { ZSTD_noDict = 0, ZSTD_extDict = 1, ZSTD_dictMatchState = 2 } ZSTD_dictMode_e;
-
-
-typedef size_t (*ZSTD_blockCompressor) (
- ZSTD_matchState_t* bs, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize);
-ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode);
-
-
-MEM_STATIC U32 ZSTD_LLcode(U32 litLength)
-{
- static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 16, 17, 17, 18, 18, 19, 19,
- 20, 20, 20, 20, 21, 21, 21, 21,
- 22, 22, 22, 22, 22, 22, 22, 22,
- 23, 23, 23, 23, 23, 23, 23, 23,
- 24, 24, 24, 24, 24, 24, 24, 24,
- 24, 24, 24, 24, 24, 24, 24, 24 };
- static const U32 LL_deltaCode = 19;
- return (litLength > 63) ? ZSTD_highbit32(litLength) + LL_deltaCode : LL_Code[litLength];
-}
-
-/* ZSTD_MLcode() :
- * note : mlBase = matchLength - MINMATCH;
- * because it's the format it's stored in seqStore->sequences */
-MEM_STATIC U32 ZSTD_MLcode(U32 mlBase)
-{
- static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
- 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
- 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
- 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
- 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
- static const U32 ML_deltaCode = 36;
- return (mlBase > 127) ? ZSTD_highbit32(mlBase) + ML_deltaCode : ML_Code[mlBase];
-}
-
-typedef struct repcodes_s {
- U32 rep[3];
-} repcodes_t;
-
-MEM_STATIC repcodes_t ZSTD_updateRep(U32 const rep[3], U32 const offset, U32 const ll0)
-{
- repcodes_t newReps;
- if (offset >= ZSTD_REP_NUM) { /* full offset */
- newReps.rep[2] = rep[1];
- newReps.rep[1] = rep[0];
- newReps.rep[0] = offset - ZSTD_REP_MOVE;
- } else { /* repcode */
- U32 const repCode = offset + ll0;
- if (repCode > 0) { /* note : if repCode==0, no change */
- U32 const currentOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode];
- newReps.rep[2] = (repCode >= 2) ? rep[1] : rep[2];
- newReps.rep[1] = rep[0];
- newReps.rep[0] = currentOffset;
- } else { /* repCode == 0 */
- memcpy(&newReps, rep, sizeof(newReps));
- }
- }
- return newReps;
-}
-
-/* ZSTD_cParam_withinBounds:
- * @return 1 if value is within cParam bounds,
- * 0 otherwise */
-MEM_STATIC int ZSTD_cParam_withinBounds(ZSTD_cParameter cParam, int value)
-{
- ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam);
- if (ZSTD_isError(bounds.error)) return 0;
- if (value < bounds.lowerBound) return 0;
- if (value > bounds.upperBound) return 0;
- return 1;
-}
-
-/* ZSTD_noCompressBlock() :
- * Writes uncompressed block to dst buffer from given src.
- * Returns the size of the block */
-MEM_STATIC size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize, U32 lastBlock)
-{
- U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(srcSize << 3);
- RETURN_ERROR_IF(srcSize + ZSTD_blockHeaderSize > dstCapacity,
- dstSize_tooSmall, "dst buf too small for uncompressed block");
- MEM_writeLE24(dst, cBlockHeader24);
- memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize);
- return ZSTD_blockHeaderSize + srcSize;
-}
-
-MEM_STATIC size_t ZSTD_rleCompressBlock (void* dst, size_t dstCapacity, BYTE src, size_t srcSize, U32 lastBlock)
-{
- BYTE* const op = (BYTE*)dst;
- U32 const cBlockHeader = lastBlock + (((U32)bt_rle)<<1) + (U32)(srcSize << 3);
- RETURN_ERROR_IF(dstCapacity < 4, dstSize_tooSmall, "");
- MEM_writeLE24(op, cBlockHeader);
- op[3] = src;
- return 4;
-}
-
-
-/* ZSTD_minGain() :
- * minimum compression required
- * to generate a compress block or a compressed literals section.
- * note : use same formula for both situations */
-MEM_STATIC size_t ZSTD_minGain(size_t srcSize, ZSTD_strategy strat)
-{
- U32 const minlog = (strat>=ZSTD_btultra) ? (U32)(strat) - 1 : 6;
- ZSTD_STATIC_ASSERT(ZSTD_btultra == 8);
- assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, strat));
- return (srcSize >> minlog) + 2;
-}
-
-MEM_STATIC int ZSTD_disableLiteralsCompression(const ZSTD_CCtx_params* cctxParams)
-{
- switch (cctxParams->literalCompressionMode) {
- case ZSTD_lcm_huffman:
- return 0;
- case ZSTD_lcm_uncompressed:
- return 1;
- default:
- assert(0 /* impossible: pre-validated */);
- /* fall-through */
- case ZSTD_lcm_auto:
- return (cctxParams->cParams.strategy == ZSTD_fast) && (cctxParams->cParams.targetLength > 0);
- }
-}
-
-/*! ZSTD_safecopyLiterals() :
- * memcpy() function that won't read beyond more than WILDCOPY_OVERLENGTH bytes past ilimit_w.
- * Only called when the sequence ends past ilimit_w, so it only needs to be optimized for single
- * large copies.
- */
-static void ZSTD_safecopyLiterals(BYTE* op, BYTE const* ip, BYTE const* const iend, BYTE const* ilimit_w) {
- assert(iend > ilimit_w);
- if (ip <= ilimit_w) {
- ZSTD_wildcopy(op, ip, ilimit_w - ip, ZSTD_no_overlap);
- op += ilimit_w - ip;
- ip = ilimit_w;
- }
- while (ip < iend) *op++ = *ip++;
-}
-
-/*! ZSTD_storeSeq() :
- * Store a sequence (litlen, litPtr, offCode and mlBase) into seqStore_t.
- * `offCode` : distance to match + ZSTD_REP_MOVE (values <= ZSTD_REP_MOVE are repCodes).
- * `mlBase` : matchLength - MINMATCH
- * Allowed to overread literals up to litLimit.
-*/
-HINT_INLINE UNUSED_ATTR
-void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, const BYTE* litLimit, U32 offCode, size_t mlBase)
-{
- BYTE const* const litLimit_w = litLimit - WILDCOPY_OVERLENGTH;
- BYTE const* const litEnd = literals + litLength;
-#if defined(DEBUGLEVEL) && (DEBUGLEVEL >= 6)
- static const BYTE* g_start = NULL;
- if (g_start==NULL) g_start = (const BYTE*)literals; /* note : index only works for compression within a single segment */
- { U32 const pos = (U32)((const BYTE*)literals - g_start);
- DEBUGLOG(6, "Cpos%7u :%3u literals, match%4u bytes at offCode%7u",
- pos, (U32)litLength, (U32)mlBase+MINMATCH, (U32)offCode);
- }
-#endif
- assert((size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart) < seqStorePtr->maxNbSeq);
- /* copy Literals */
- assert(seqStorePtr->maxNbLit <= 128 KB);
- assert(seqStorePtr->lit + litLength <= seqStorePtr->litStart + seqStorePtr->maxNbLit);
- assert(literals + litLength <= litLimit);
- if (litEnd <= litLimit_w) {
- /* Common case we can use wildcopy.
- * First copy 16 bytes, because literals are likely short.
- */
- assert(WILDCOPY_OVERLENGTH >= 16);
- ZSTD_copy16(seqStorePtr->lit, literals);
- if (litLength > 16) {
- ZSTD_wildcopy(seqStorePtr->lit+16, literals+16, (ptrdiff_t)litLength-16, ZSTD_no_overlap);
- }
- } else {
- ZSTD_safecopyLiterals(seqStorePtr->lit, literals, litEnd, litLimit_w);
- }
- seqStorePtr->lit += litLength;
-
- /* literal Length */
- if (litLength>0xFFFF) {
- assert(seqStorePtr->longLengthID == 0); /* there can only be a single long length */
- seqStorePtr->longLengthID = 1;
- seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
- }
- seqStorePtr->sequences[0].litLength = (U16)litLength;
-
- /* match offset */
- seqStorePtr->sequences[0].offset = offCode + 1;
-
- /* match Length */
- if (mlBase>0xFFFF) {
- assert(seqStorePtr->longLengthID == 0); /* there can only be a single long length */
- seqStorePtr->longLengthID = 2;
- seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
- }
- seqStorePtr->sequences[0].matchLength = (U16)mlBase;
-
- seqStorePtr->sequences++;
-}
-
-
-/*-*************************************
-* Match length counter
-***************************************/
-static unsigned ZSTD_NbCommonBytes (size_t val)
-{
- if (MEM_isLittleEndian()) {
- if (MEM_64bits()) {
-# if defined(_MSC_VER) && defined(_WIN64)
- unsigned long r = 0;
- return _BitScanForward64( &r, (U64)val ) ? (unsigned)(r >> 3) : 0;
-# elif defined(__GNUC__) && (__GNUC__ >= 4)
- return (__builtin_ctzll((U64)val) >> 3);
-# else
- static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2,
- 0, 3, 1, 3, 1, 4, 2, 7,
- 0, 2, 3, 6, 1, 5, 3, 5,
- 1, 3, 4, 4, 2, 5, 6, 7,
- 7, 0, 1, 2, 3, 3, 4, 6,
- 2, 6, 5, 5, 3, 4, 5, 6,
- 7, 1, 2, 4, 6, 4, 4, 5,
- 7, 2, 6, 5, 7, 6, 7, 7 };
- return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
-# endif
- } else { /* 32 bits */
-# if defined(_MSC_VER)
- unsigned long r=0;
- return _BitScanForward( &r, (U32)val ) ? (unsigned)(r >> 3) : 0;
-# elif defined(__GNUC__) && (__GNUC__ >= 3)
- return (__builtin_ctz((U32)val) >> 3);
-# else
- static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0,
- 3, 2, 2, 1, 3, 2, 0, 1,
- 3, 3, 1, 2, 2, 2, 2, 0,
- 3, 1, 2, 0, 1, 0, 1, 1 };
- return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
-# endif
- }
- } else { /* Big Endian CPU */
- if (MEM_64bits()) {
-# if defined(_MSC_VER) && defined(_WIN64)
- unsigned long r = 0;
- return _BitScanReverse64( &r, val ) ? (unsigned)(r >> 3) : 0;
-# elif defined(__GNUC__) && (__GNUC__ >= 4)
- return (__builtin_clzll(val) >> 3);
-# else
- unsigned r;
- const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
- if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
- if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
- r += (!val);
- return r;
-# endif
- } else { /* 32 bits */
-# if defined(_MSC_VER)
- unsigned long r = 0;
- return _BitScanReverse( &r, (unsigned long)val ) ? (unsigned)(r >> 3) : 0;
-# elif defined(__GNUC__) && (__GNUC__ >= 3)
- return (__builtin_clz((U32)val) >> 3);
-# else
- unsigned r;
- if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
- r += (!val);
- return r;
-# endif
- } }
-}
-
-
-MEM_STATIC size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit)
-{
- const BYTE* const pStart = pIn;
- const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1);
-
- if (pIn < pInLoopLimit) {
- { size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
- if (diff) return ZSTD_NbCommonBytes(diff); }
- pIn+=sizeof(size_t); pMatch+=sizeof(size_t);
- while (pIn < pInLoopLimit) {
- size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
- if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
- pIn += ZSTD_NbCommonBytes(diff);
- return (size_t)(pIn - pStart);
- } }
- if (MEM_64bits() && (pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
- if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
- if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
- return (size_t)(pIn - pStart);
-}
-
-/** ZSTD_count_2segments() :
- * can count match length with `ip` & `match` in 2 different segments.
- * convention : on reaching mEnd, match count continue starting from iStart
- */
-MEM_STATIC size_t
-ZSTD_count_2segments(const BYTE* ip, const BYTE* match,
- const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
-{
- const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd);
- size_t const matchLength = ZSTD_count(ip, match, vEnd);
- if (match + matchLength != mEnd) return matchLength;
- DEBUGLOG(7, "ZSTD_count_2segments: found a 2-parts match (current length==%zu)", matchLength);
- DEBUGLOG(7, "distance from match beginning to end dictionary = %zi", mEnd - match);
- DEBUGLOG(7, "distance from current pos to end buffer = %zi", iEnd - ip);
- DEBUGLOG(7, "next byte : ip==%02X, istart==%02X", ip[matchLength], *iStart);
- DEBUGLOG(7, "final match length = %zu", matchLength + ZSTD_count(ip+matchLength, iStart, iEnd));
- return matchLength + ZSTD_count(ip+matchLength, iStart, iEnd);
-}
-
-
-/*-*************************************
- * Hashes
- ***************************************/
-static const U32 prime3bytes = 506832829U;
-static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
-MEM_STATIC size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_readLE32(ptr), h); } /* only in zstd_opt.h */
-
-static const U32 prime4bytes = 2654435761U;
-static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
-static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
-
-static const U64 prime5bytes = 889523592379ULL;
-static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
-static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
-
-static const U64 prime6bytes = 227718039650203ULL;
-static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
-static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
-
-static const U64 prime7bytes = 58295818150454627ULL;
-static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
-static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
-
-static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
-static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
-static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
-
-MEM_STATIC size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
-{
- switch(mls)
- {
- default:
- case 4: return ZSTD_hash4Ptr(p, hBits);
- case 5: return ZSTD_hash5Ptr(p, hBits);
- case 6: return ZSTD_hash6Ptr(p, hBits);
- case 7: return ZSTD_hash7Ptr(p, hBits);
- case 8: return ZSTD_hash8Ptr(p, hBits);
- }
-}
-
-/** ZSTD_ipow() :
- * Return base^exponent.
- */
-static U64 ZSTD_ipow(U64 base, U64 exponent)
-{
- U64 power = 1;
- while (exponent) {
- if (exponent & 1) power *= base;
- exponent >>= 1;
- base *= base;
- }
- return power;
-}
-
-#define ZSTD_ROLL_HASH_CHAR_OFFSET 10
-
-/** ZSTD_rollingHash_append() :
- * Add the buffer to the hash value.
- */
-static U64 ZSTD_rollingHash_append(U64 hash, void const* buf, size_t size)
-{
- BYTE const* istart = (BYTE const*)buf;
- size_t pos;
- for (pos = 0; pos < size; ++pos) {
- hash *= prime8bytes;
- hash += istart[pos] + ZSTD_ROLL_HASH_CHAR_OFFSET;
- }
- return hash;
-}
-
-/** ZSTD_rollingHash_compute() :
- * Compute the rolling hash value of the buffer.
- */
-MEM_STATIC U64 ZSTD_rollingHash_compute(void const* buf, size_t size)
-{
- return ZSTD_rollingHash_append(0, buf, size);
-}
-
-/** ZSTD_rollingHash_primePower() :
- * Compute the primePower to be passed to ZSTD_rollingHash_rotate() for a hash
- * over a window of length bytes.
- */
-MEM_STATIC U64 ZSTD_rollingHash_primePower(U32 length)
-{
- return ZSTD_ipow(prime8bytes, length - 1);
-}
-
-/** ZSTD_rollingHash_rotate() :
- * Rotate the rolling hash by one byte.
- */
-MEM_STATIC U64 ZSTD_rollingHash_rotate(U64 hash, BYTE toRemove, BYTE toAdd, U64 primePower)
-{
- hash -= (toRemove + ZSTD_ROLL_HASH_CHAR_OFFSET) * primePower;
- hash *= prime8bytes;
- hash += toAdd + ZSTD_ROLL_HASH_CHAR_OFFSET;
- return hash;
-}
-
-/*-*************************************
-* Round buffer management
-***************************************/
-#if (ZSTD_WINDOWLOG_MAX_64 > 31)
-# error "ZSTD_WINDOWLOG_MAX is too large : would overflow ZSTD_CURRENT_MAX"
-#endif
-/* Max current allowed */
-#define ZSTD_CURRENT_MAX ((3U << 29) + (1U << ZSTD_WINDOWLOG_MAX))
-/* Maximum chunk size before overflow correction needs to be called again */
-#define ZSTD_CHUNKSIZE_MAX \
- ( ((U32)-1) /* Maximum ending current index */ \
- - ZSTD_CURRENT_MAX) /* Maximum beginning lowLimit */
-
-/**
- * ZSTD_window_clear():
- * Clears the window containing the history by simply setting it to empty.
- */
-MEM_STATIC void ZSTD_window_clear(ZSTD_window_t* window)
-{
- size_t const endT = (size_t)(window->nextSrc - window->base);
- U32 const end = (U32)endT;
-
- window->lowLimit = end;
- window->dictLimit = end;
-}
-
-/**
- * ZSTD_window_hasExtDict():
- * Returns non-zero if the window has a non-empty extDict.
- */
-MEM_STATIC U32 ZSTD_window_hasExtDict(ZSTD_window_t const window)
-{
- return window.lowLimit < window.dictLimit;
-}
-
-/**
- * ZSTD_matchState_dictMode():
- * Inspects the provided matchState and figures out what dictMode should be
- * passed to the compressor.
- */
-MEM_STATIC ZSTD_dictMode_e ZSTD_matchState_dictMode(const ZSTD_matchState_t *ms)
-{
- return ZSTD_window_hasExtDict(ms->window) ?
- ZSTD_extDict :
- ms->dictMatchState != NULL ?
- ZSTD_dictMatchState :
- ZSTD_noDict;
-}
-
-/**
- * ZSTD_window_needOverflowCorrection():
- * Returns non-zero if the indices are getting too large and need overflow
- * protection.
- */
-MEM_STATIC U32 ZSTD_window_needOverflowCorrection(ZSTD_window_t const window,
- void const* srcEnd)
-{
- U32 const current = (U32)((BYTE const*)srcEnd - window.base);
- return current > ZSTD_CURRENT_MAX;
-}
-
-/**
- * ZSTD_window_correctOverflow():
- * Reduces the indices to protect from index overflow.
- * Returns the correction made to the indices, which must be applied to every
- * stored index.
- *
- * The least significant cycleLog bits of the indices must remain the same,
- * which may be 0. Every index up to maxDist in the past must be valid.
- * NOTE: (maxDist & cycleMask) must be zero.
- */
-MEM_STATIC U32 ZSTD_window_correctOverflow(ZSTD_window_t* window, U32 cycleLog,
- U32 maxDist, void const* src)
-{
- /* preemptive overflow correction:
- * 1. correction is large enough:
- * lowLimit > (3<<29) ==> current > 3<<29 + 1<<windowLog
- * 1<<windowLog <= newCurrent < 1<<chainLog + 1<<windowLog
- *
- * current - newCurrent
- * > (3<<29 + 1<<windowLog) - (1<<windowLog + 1<<chainLog)
- * > (3<<29) - (1<<chainLog)
- * > (3<<29) - (1<<30) (NOTE: chainLog <= 30)
- * > 1<<29
- *
- * 2. (ip+ZSTD_CHUNKSIZE_MAX - cctx->base) doesn't overflow:
- * After correction, current is less than (1<<chainLog + 1<<windowLog).
- * In 64-bit mode we are safe, because we have 64-bit ptrdiff_t.
- * In 32-bit mode we are safe, because (chainLog <= 29), so
- * ip+ZSTD_CHUNKSIZE_MAX - cctx->base < 1<<32.
- * 3. (cctx->lowLimit + 1<<windowLog) < 1<<32:
- * windowLog <= 31 ==> 3<<29 + 1<<windowLog < 7<<29 < 1<<32.
- */
- U32 const cycleMask = (1U << cycleLog) - 1;
- U32 const current = (U32)((BYTE const*)src - window->base);
- U32 const currentCycle0 = current & cycleMask;
- /* Exclude zero so that newCurrent - maxDist >= 1. */
- U32 const currentCycle1 = currentCycle0 == 0 ? (1U << cycleLog) : currentCycle0;
- U32 const newCurrent = currentCycle1 + maxDist;
- U32 const correction = current - newCurrent;
- assert((maxDist & cycleMask) == 0);
- assert(current > newCurrent);
- /* Loose bound, should be around 1<<29 (see above) */
- assert(correction > 1<<28);
-
- window->base += correction;
- window->dictBase += correction;
- if (window->lowLimit <= correction) window->lowLimit = 1;
- else window->lowLimit -= correction;
- if (window->dictLimit <= correction) window->dictLimit = 1;
- else window->dictLimit -= correction;
-
- /* Ensure we can still reference the full window. */
- assert(newCurrent >= maxDist);
- assert(newCurrent - maxDist >= 1);
- /* Ensure that lowLimit and dictLimit didn't underflow. */
- assert(window->lowLimit <= newCurrent);
- assert(window->dictLimit <= newCurrent);
-
- DEBUGLOG(4, "Correction of 0x%x bytes to lowLimit=0x%x", correction,
- window->lowLimit);
- return correction;
-}
-
-/**
- * ZSTD_window_enforceMaxDist():
- * Updates lowLimit so that:
- * (srcEnd - base) - lowLimit == maxDist + loadedDictEnd
- *
- * It ensures index is valid as long as index >= lowLimit.
- * This must be called before a block compression call.
- *
- * loadedDictEnd is only defined if a dictionary is in use for current compression.
- * As the name implies, loadedDictEnd represents the index at end of dictionary.
- * The value lies within context's referential, it can be directly compared to blockEndIdx.
- *
- * If loadedDictEndPtr is NULL, no dictionary is in use, and we use loadedDictEnd == 0.
- * If loadedDictEndPtr is not NULL, we set it to zero after updating lowLimit.
- * This is because dictionaries are allowed to be referenced fully
- * as long as the last byte of the dictionary is in the window.
- * Once input has progressed beyond window size, dictionary cannot be referenced anymore.
- *
- * In normal dict mode, the dictionary lies between lowLimit and dictLimit.
- * In dictMatchState mode, lowLimit and dictLimit are the same,
- * and the dictionary is below them.
- * forceWindow and dictMatchState are therefore incompatible.
- */
-MEM_STATIC void
-ZSTD_window_enforceMaxDist(ZSTD_window_t* window,
- const void* blockEnd,
- U32 maxDist,
- U32* loadedDictEndPtr,
- const ZSTD_matchState_t** dictMatchStatePtr)
-{
- U32 const blockEndIdx = (U32)((BYTE const*)blockEnd - window->base);
- U32 const loadedDictEnd = (loadedDictEndPtr != NULL) ? *loadedDictEndPtr : 0;
- DEBUGLOG(5, "ZSTD_window_enforceMaxDist: blockEndIdx=%u, maxDist=%u, loadedDictEnd=%u",
- (unsigned)blockEndIdx, (unsigned)maxDist, (unsigned)loadedDictEnd);
-
- /* - When there is no dictionary : loadedDictEnd == 0.
- In which case, the test (blockEndIdx > maxDist) is merely to avoid
- overflowing next operation `newLowLimit = blockEndIdx - maxDist`.
- - When there is a standard dictionary :
- Index referential is copied from the dictionary,
- which means it starts from 0.
- In which case, loadedDictEnd == dictSize,
- and it makes sense to compare `blockEndIdx > maxDist + dictSize`
- since `blockEndIdx` also starts from zero.
- - When there is an attached dictionary :
- loadedDictEnd is expressed within the referential of the context,
- so it can be directly compared against blockEndIdx.
- */
- if (blockEndIdx > maxDist + loadedDictEnd) {
- U32 const newLowLimit = blockEndIdx - maxDist;
- if (window->lowLimit < newLowLimit) window->lowLimit = newLowLimit;
- if (window->dictLimit < window->lowLimit) {
- DEBUGLOG(5, "Update dictLimit to match lowLimit, from %u to %u",
- (unsigned)window->dictLimit, (unsigned)window->lowLimit);
- window->dictLimit = window->lowLimit;
- }
- /* On reaching window size, dictionaries are invalidated */
- if (loadedDictEndPtr) *loadedDictEndPtr = 0;
- if (dictMatchStatePtr) *dictMatchStatePtr = NULL;
- }
-}
-
-/* Similar to ZSTD_window_enforceMaxDist(),
- * but only invalidates dictionary
- * when input progresses beyond window size.
- * assumption : loadedDictEndPtr and dictMatchStatePtr are valid (non NULL)
- * loadedDictEnd uses same referential as window->base
- * maxDist is the window size */
-MEM_STATIC void
-ZSTD_checkDictValidity(const ZSTD_window_t* window,
- const void* blockEnd,
- U32 maxDist,
- U32* loadedDictEndPtr,
- const ZSTD_matchState_t** dictMatchStatePtr)
-{
- assert(loadedDictEndPtr != NULL);
- assert(dictMatchStatePtr != NULL);
- { U32 const blockEndIdx = (U32)((BYTE const*)blockEnd - window->base);
- U32 const loadedDictEnd = *loadedDictEndPtr;
- DEBUGLOG(5, "ZSTD_checkDictValidity: blockEndIdx=%u, maxDist=%u, loadedDictEnd=%u",
- (unsigned)blockEndIdx, (unsigned)maxDist, (unsigned)loadedDictEnd);
- assert(blockEndIdx >= loadedDictEnd);
-
- if (blockEndIdx > loadedDictEnd + maxDist) {
- /* On reaching window size, dictionaries are invalidated.
- * For simplification, if window size is reached anywhere within next block,
- * the dictionary is invalidated for the full block.
- */
- DEBUGLOG(6, "invalidating dictionary for current block (distance > windowSize)");
- *loadedDictEndPtr = 0;
- *dictMatchStatePtr = NULL;
- } else {
- if (*loadedDictEndPtr != 0) {
- DEBUGLOG(6, "dictionary considered valid for current block");
- } } }
-}
-
-MEM_STATIC void ZSTD_window_init(ZSTD_window_t* window) {
- memset(window, 0, sizeof(*window));
- window->base = (BYTE const*)"";
- window->dictBase = (BYTE const*)"";
- window->dictLimit = 1; /* start from 1, so that 1st position is valid */
- window->lowLimit = 1; /* it ensures first and later CCtx usages compress the same */
- window->nextSrc = window->base + 1; /* see issue #1241 */
-}
-
-/**
- * ZSTD_window_update():
- * Updates the window by appending [src, src + srcSize) to the window.
- * If it is not contiguous, the current prefix becomes the extDict, and we
- * forget about the extDict. Handles overlap of the prefix and extDict.
- * Returns non-zero if the segment is contiguous.
- */
-MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window,
- void const* src, size_t srcSize)
-{
- BYTE const* const ip = (BYTE const*)src;
- U32 contiguous = 1;
- DEBUGLOG(5, "ZSTD_window_update");
- if (srcSize == 0)
- return contiguous;
- assert(window->base != NULL);
- assert(window->dictBase != NULL);
- /* Check if blocks follow each other */
- if (src != window->nextSrc) {
- /* not contiguous */
- size_t const distanceFromBase = (size_t)(window->nextSrc - window->base);
- DEBUGLOG(5, "Non contiguous blocks, new segment starts at %u", window->dictLimit);
- window->lowLimit = window->dictLimit;
- assert(distanceFromBase == (size_t)(U32)distanceFromBase); /* should never overflow */
- window->dictLimit = (U32)distanceFromBase;
- window->dictBase = window->base;
- window->base = ip - distanceFromBase;
- /* ms->nextToUpdate = window->dictLimit; */
- if (window->dictLimit - window->lowLimit < HASH_READ_SIZE) window->lowLimit = window->dictLimit; /* too small extDict */
- contiguous = 0;
- }
- window->nextSrc = ip + srcSize;
- /* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */
- if ( (ip+srcSize > window->dictBase + window->lowLimit)
- & (ip < window->dictBase + window->dictLimit)) {
- ptrdiff_t const highInputIdx = (ip + srcSize) - window->dictBase;
- U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)window->dictLimit) ? window->dictLimit : (U32)highInputIdx;
- window->lowLimit = lowLimitMax;
- DEBUGLOG(5, "Overlapping extDict and input : new lowLimit = %u", window->lowLimit);
- }
- return contiguous;
-}
-
-/**
- * Returns the lowest allowed match index. It may either be in the ext-dict or the prefix.
- */
-MEM_STATIC U32 ZSTD_getLowestMatchIndex(const ZSTD_matchState_t* ms, U32 current, unsigned windowLog)
-{
- U32 const maxDistance = 1U << windowLog;
- U32 const lowestValid = ms->window.lowLimit;
- U32 const withinWindow = (current - lowestValid > maxDistance) ? current - maxDistance : lowestValid;
- U32 const isDictionary = (ms->loadedDictEnd != 0);
- U32 const matchLowest = isDictionary ? lowestValid : withinWindow;
- return matchLowest;
-}
-
-/**
- * Returns the lowest allowed match index in the prefix.
- */
-MEM_STATIC U32 ZSTD_getLowestPrefixIndex(const ZSTD_matchState_t* ms, U32 current, unsigned windowLog)
-{
- U32 const maxDistance = 1U << windowLog;
- U32 const lowestValid = ms->window.dictLimit;
- U32 const withinWindow = (current - lowestValid > maxDistance) ? current - maxDistance : lowestValid;
- U32 const isDictionary = (ms->loadedDictEnd != 0);
- U32 const matchLowest = isDictionary ? lowestValid : withinWindow;
- return matchLowest;
-}
-
-
-
-/* debug functions */
-#if (DEBUGLEVEL>=2)
-
-MEM_STATIC double ZSTD_fWeight(U32 rawStat)
-{
- U32 const fp_accuracy = 8;
- U32 const fp_multiplier = (1 << fp_accuracy);
- U32 const newStat = rawStat + 1;
- U32 const hb = ZSTD_highbit32(newStat);
- U32 const BWeight = hb * fp_multiplier;
- U32 const FWeight = (newStat << fp_accuracy) >> hb;
- U32 const weight = BWeight + FWeight;
- assert(hb + fp_accuracy < 31);
- return (double)weight / fp_multiplier;
-}
-
-/* display a table content,
- * listing each element, its frequency, and its predicted bit cost */
-MEM_STATIC void ZSTD_debugTable(const U32* table, U32 max)
-{
- unsigned u, sum;
- for (u=0, sum=0; u<=max; u++) sum += table[u];
- DEBUGLOG(2, "total nb elts: %u", sum);
- for (u=0; u<=max; u++) {
- DEBUGLOG(2, "%2u: %5u (%.2f)",
- u, table[u], ZSTD_fWeight(sum) - ZSTD_fWeight(table[u]) );
- }
-}
-
-#endif
-
-
-#if defined (__cplusplus)
-}
-#endif
-
-/* ===============================================================
- * Shared internal declarations
- * These prototypes may be called from sources not in lib/compress
- * =============================================================== */
-
-/* ZSTD_loadCEntropy() :
- * dict : must point at beginning of a valid zstd dictionary.
- * return : size of dictionary header (size of magic number + dict ID + entropy tables)
- * assumptions : magic number supposed already checked
- * and dictSize >= 8 */
-size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace,
- short* offcodeNCount, unsigned* offcodeMaxValue,
- const void* const dict, size_t dictSize);
-
-void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs);
-
-/* ==============================================================
- * Private declarations
- * These prototypes shall only be called from within lib/compress
- * ============================================================== */
-
-/* ZSTD_getCParamsFromCCtxParams() :
- * cParams are built depending on compressionLevel, src size hints,
- * LDM and manually set compression parameters.
- * Note: srcSizeHint == 0 means 0!
- */
-ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams(
- const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize);
-
-/*! ZSTD_initCStream_internal() :
- * Private use only. Init streaming operation.
- * expects params to be valid.
- * must receive dict, or cdict, or none, but not both.
- * @return : 0, or an error code */
-size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
- const void* dict, size_t dictSize,
- const ZSTD_CDict* cdict,
- const ZSTD_CCtx_params* params, unsigned long long pledgedSrcSize);
-
-void ZSTD_resetSeqStore(seqStore_t* ssPtr);
-
-/*! ZSTD_getCParamsFromCDict() :
- * as the name implies */
-ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict);
-
-/* ZSTD_compressBegin_advanced_internal() :
- * Private use only. To be called from zstdmt_compress.c. */
-size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx,
- const void* dict, size_t dictSize,
- ZSTD_dictContentType_e dictContentType,
- ZSTD_dictTableLoadMethod_e dtlm,
- const ZSTD_CDict* cdict,
- const ZSTD_CCtx_params* params,
- unsigned long long pledgedSrcSize);
-
-/* ZSTD_compress_advanced_internal() :
- * Private use only. To be called from zstdmt_compress.c. */
-size_t ZSTD_compress_advanced_internal(ZSTD_CCtx* cctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- const void* dict,size_t dictSize,
- const ZSTD_CCtx_params* params);
-
-
-/* ZSTD_writeLastEmptyBlock() :
- * output an empty Block with end-of-frame mark to complete a frame
- * @return : size of data written into `dst` (== ZSTD_blockHeaderSize (defined in zstd_internal.h))
- * or an error code if `dstCapacity` is too small (<ZSTD_blockHeaderSize)
- */
-size_t ZSTD_writeLastEmptyBlock(void* dst, size_t dstCapacity);
-
-
-/* ZSTD_referenceExternalSequences() :
- * Must be called before starting a compression operation.
- * seqs must parse a prefix of the source.
- * This cannot be used when long range matching is enabled.
- * Zstd will use these sequences, and pass the literals to a secondary block
- * compressor.
- * @return : An error code on failure.
- * NOTE: seqs are not verified! Invalid sequences can cause out-of-bounds memory
- * access and data corruption.
- */
-size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq);
-
-/** ZSTD_cycleLog() :
- * condition for correct operation : hashLog > 1 */
-U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat);
-
-#endif /* ZSTD_COMPRESS_H */
-/**** ended inlining zstd_compress_internal.h ****/
-
-
-size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize);
-
-size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize);
-
-size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf,
- ZSTD_hufCTables_t* nextHuf,
- ZSTD_strategy strategy, int disableLiteralCompression,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- void* entropyWorkspace, size_t entropyWorkspaceSize,
- const int bmi2);
-
-#endif /* ZSTD_COMPRESS_LITERALS_H */
-/**** ended inlining zstd_compress_literals.h ****/
-
-size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
-{
- BYTE* const ostart = (BYTE* const)dst;
- U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
-
- RETURN_ERROR_IF(srcSize + flSize > dstCapacity, dstSize_tooSmall, "");
-
- switch(flSize)
- {
- case 1: /* 2 - 1 - 5 */
- ostart[0] = (BYTE)((U32)set_basic + (srcSize<<3));
- break;
- case 2: /* 2 - 2 - 12 */
- MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4)));
- break;
- case 3: /* 2 - 2 - 20 */
- MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4)));
- break;
- default: /* not necessary : flSize is {1,2,3} */
- assert(0);
- }
-
- memcpy(ostart + flSize, src, srcSize);
- DEBUGLOG(5, "Raw literals: %u -> %u", (U32)srcSize, (U32)(srcSize + flSize));
- return srcSize + flSize;
-}
-
-size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
-{
- BYTE* const ostart = (BYTE* const)dst;
- U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
-
- (void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */
-
- switch(flSize)
- {
- case 1: /* 2 - 1 - 5 */
- ostart[0] = (BYTE)((U32)set_rle + (srcSize<<3));
- break;
- case 2: /* 2 - 2 - 12 */
- MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4)));
- break;
- case 3: /* 2 - 2 - 20 */
- MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4)));
- break;
- default: /* not necessary : flSize is {1,2,3} */
- assert(0);
- }
-
- ostart[flSize] = *(const BYTE*)src;
- DEBUGLOG(5, "RLE literals: %u -> %u", (U32)srcSize, (U32)flSize + 1);
- return flSize+1;
-}
-
-size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf,
- ZSTD_hufCTables_t* nextHuf,
- ZSTD_strategy strategy, int disableLiteralCompression,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- void* entropyWorkspace, size_t entropyWorkspaceSize,
- const int bmi2)
-{
- size_t const minGain = ZSTD_minGain(srcSize, strategy);
- size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
- BYTE* const ostart = (BYTE*)dst;
- U32 singleStream = srcSize < 256;
- symbolEncodingType_e hType = set_compressed;
- size_t cLitSize;
-
- DEBUGLOG(5,"ZSTD_compressLiterals (disableLiteralCompression=%i srcSize=%u)",
- disableLiteralCompression, (U32)srcSize);
-
- /* Prepare nextEntropy assuming reusing the existing table */
- memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
-
- if (disableLiteralCompression)
- return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
-
- /* small ? don't even attempt compression (speed opt) */
-# define COMPRESS_LITERALS_SIZE_MIN 63
- { size_t const minLitSize = (prevHuf->repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN;
- if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
- }
-
- RETURN_ERROR_IF(dstCapacity < lhSize+1, dstSize_tooSmall, "not enough space for compression");
- { HUF_repeat repeat = prevHuf->repeatMode;
- int const preferRepeat = strategy < ZSTD_lazy ? srcSize <= 1024 : 0;
- if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1;
- cLitSize = singleStream ?
- HUF_compress1X_repeat(
- ostart+lhSize, dstCapacity-lhSize, src, srcSize,
- HUF_SYMBOLVALUE_MAX, HUF_TABLELOG_DEFAULT, entropyWorkspace, entropyWorkspaceSize,
- (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2) :
- HUF_compress4X_repeat(
- ostart+lhSize, dstCapacity-lhSize, src, srcSize,
- HUF_SYMBOLVALUE_MAX, HUF_TABLELOG_DEFAULT, entropyWorkspace, entropyWorkspaceSize,
- (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2);
- if (repeat != HUF_repeat_none) {
- /* reused the existing table */
- DEBUGLOG(5, "Reusing previous huffman table");
- hType = set_repeat;
- }
- }
-
- if ((cLitSize==0) | (cLitSize >= srcSize - minGain) | ERR_isError(cLitSize)) {
- memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
- return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
- }
- if (cLitSize==1) {
- memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
- return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
- }
-
- if (hType == set_compressed) {
- /* using a newly constructed table */
- nextHuf->repeatMode = HUF_repeat_check;
- }
-
- /* Build header */
- switch(lhSize)
- {
- case 3: /* 2 - 2 - 10 - 10 */
- { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14);
- MEM_writeLE24(ostart, lhc);
- break;
- }
- case 4: /* 2 - 2 - 14 - 14 */
- { U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18);
- MEM_writeLE32(ostart, lhc);
- break;
- }
- case 5: /* 2 - 2 - 18 - 18 */
- { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22);
- MEM_writeLE32(ostart, lhc);
- ostart[4] = (BYTE)(cLitSize >> 10);
- break;
- }
- default: /* not possible : lhSize is {3,4,5} */
- assert(0);
- }
- DEBUGLOG(5, "Compressed literals: %u -> %u", (U32)srcSize, (U32)(lhSize+cLitSize));
- return lhSize+cLitSize;
-}
-/**** ended inlining compress/zstd_compress_literals.c ****/
-/**** start inlining compress/zstd_compress_sequences.c ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
- /*-*************************************
- * Dependencies
- ***************************************/
-/**** start inlining zstd_compress_sequences.h ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-#ifndef ZSTD_COMPRESS_SEQUENCES_H
-#define ZSTD_COMPRESS_SEQUENCES_H
-
-/**** skipping file: ../common/fse.h ****/
-/**** skipping file: ../common/zstd_internal.h ****/
-
-typedef enum {
- ZSTD_defaultDisallowed = 0,
- ZSTD_defaultAllowed = 1
-} ZSTD_defaultPolicy_e;
-
-symbolEncodingType_e
-ZSTD_selectEncodingType(
- FSE_repeat* repeatMode, unsigned const* count, unsigned const max,
- size_t const mostFrequent, size_t nbSeq, unsigned const FSELog,
- FSE_CTable const* prevCTable,
- short const* defaultNorm, U32 defaultNormLog,
- ZSTD_defaultPolicy_e const isDefaultAllowed,
- ZSTD_strategy const strategy);
-
-size_t
-ZSTD_buildCTable(void* dst, size_t dstCapacity,
- FSE_CTable* nextCTable, U32 FSELog, symbolEncodingType_e type,
- unsigned* count, U32 max,
- const BYTE* codeTable, size_t nbSeq,
- const S16* defaultNorm, U32 defaultNormLog, U32 defaultMax,
- const FSE_CTable* prevCTable, size_t prevCTableSize,
- void* entropyWorkspace, size_t entropyWorkspaceSize);
-
-size_t ZSTD_encodeSequences(
- void* dst, size_t dstCapacity,
- FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
- FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
- FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
- seqDef const* sequences, size_t nbSeq, int longOffsets, int bmi2);
-
-size_t ZSTD_fseBitCost(
- FSE_CTable const* ctable,
- unsigned const* count,
- unsigned const max);
-
-size_t ZSTD_crossEntropyCost(short const* norm, unsigned accuracyLog,
- unsigned const* count, unsigned const max);
-#endif /* ZSTD_COMPRESS_SEQUENCES_H */
-/**** ended inlining zstd_compress_sequences.h ****/
-
-/**
- * -log2(x / 256) lookup table for x in [0, 256).
- * If x == 0: Return 0
- * Else: Return floor(-log2(x / 256) * 256)
- */
-static unsigned const kInverseProbabilityLog256[256] = {
- 0, 2048, 1792, 1642, 1536, 1453, 1386, 1329, 1280, 1236, 1197, 1162,
- 1130, 1100, 1073, 1047, 1024, 1001, 980, 960, 941, 923, 906, 889,
- 874, 859, 844, 830, 817, 804, 791, 779, 768, 756, 745, 734,
- 724, 714, 704, 694, 685, 676, 667, 658, 650, 642, 633, 626,
- 618, 610, 603, 595, 588, 581, 574, 567, 561, 554, 548, 542,
- 535, 529, 523, 517, 512, 506, 500, 495, 489, 484, 478, 473,
- 468, 463, 458, 453, 448, 443, 438, 434, 429, 424, 420, 415,
- 411, 407, 402, 398, 394, 390, 386, 382, 377, 373, 370, 366,
- 362, 358, 354, 350, 347, 343, 339, 336, 332, 329, 325, 322,
- 318, 315, 311, 308, 305, 302, 298, 295, 292, 289, 286, 282,
- 279, 276, 273, 270, 267, 264, 261, 258, 256, 253, 250, 247,
- 244, 241, 239, 236, 233, 230, 228, 225, 222, 220, 217, 215,
- 212, 209, 207, 204, 202, 199, 197, 194, 192, 190, 187, 185,
- 182, 180, 178, 175, 173, 171, 168, 166, 164, 162, 159, 157,
- 155, 153, 151, 149, 146, 144, 142, 140, 138, 136, 134, 132,
- 130, 128, 126, 123, 121, 119, 117, 115, 114, 112, 110, 108,
- 106, 104, 102, 100, 98, 96, 94, 93, 91, 89, 87, 85,
- 83, 82, 80, 78, 76, 74, 73, 71, 69, 67, 66, 64,
- 62, 61, 59, 57, 55, 54, 52, 50, 49, 47, 46, 44,
- 42, 41, 39, 37, 36, 34, 33, 31, 30, 28, 26, 25,
- 23, 22, 20, 19, 17, 16, 14, 13, 11, 10, 8, 7,
- 5, 4, 2, 1,
-};
-
-static unsigned ZSTD_getFSEMaxSymbolValue(FSE_CTable const* ctable) {
- void const* ptr = ctable;
- U16 const* u16ptr = (U16 const*)ptr;
- U32 const maxSymbolValue = MEM_read16(u16ptr + 1);
- return maxSymbolValue;
-}
-
-/**
- * Returns the cost in bytes of encoding the normalized count header.
- * Returns an error if any of the helper functions return an error.
- */
-static size_t ZSTD_NCountCost(unsigned const* count, unsigned const max,
- size_t const nbSeq, unsigned const FSELog)
-{
- BYTE wksp[FSE_NCOUNTBOUND];
- S16 norm[MaxSeq + 1];
- const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max);
- FORWARD_IF_ERROR(FSE_normalizeCount(norm, tableLog, count, nbSeq, max), "");
- return FSE_writeNCount(wksp, sizeof(wksp), norm, max, tableLog);
-}
-
-/**
- * Returns the cost in bits of encoding the distribution described by count
- * using the entropy bound.
- */
-static size_t ZSTD_entropyCost(unsigned const* count, unsigned const max, size_t const total)
-{
- unsigned cost = 0;
- unsigned s;
- for (s = 0; s <= max; ++s) {
- unsigned norm = (unsigned)((256 * count[s]) / total);
- if (count[s] != 0 && norm == 0)
- norm = 1;
- assert(count[s] < total);
- cost += count[s] * kInverseProbabilityLog256[norm];
- }
- return cost >> 8;
-}
-
-/**
- * Returns the cost in bits of encoding the distribution in count using ctable.
- * Returns an error if ctable cannot represent all the symbols in count.
- */
-size_t ZSTD_fseBitCost(
- FSE_CTable const* ctable,
- unsigned const* count,
- unsigned const max)
-{
- unsigned const kAccuracyLog = 8;
- size_t cost = 0;
- unsigned s;
- FSE_CState_t cstate;
- FSE_initCState(&cstate, ctable);
- if (ZSTD_getFSEMaxSymbolValue(ctable) < max) {
- DEBUGLOG(5, "Repeat FSE_CTable has maxSymbolValue %u < %u",
- ZSTD_getFSEMaxSymbolValue(ctable), max);
- return ERROR(GENERIC);
- }
- for (s = 0; s <= max; ++s) {
- unsigned const tableLog = cstate.stateLog;
- unsigned const badCost = (tableLog + 1) << kAccuracyLog;
- unsigned const bitCost = FSE_bitCost(cstate.symbolTT, tableLog, s, kAccuracyLog);
- if (count[s] == 0)
- continue;
- if (bitCost >= badCost) {
- DEBUGLOG(5, "Repeat FSE_CTable has Prob[%u] == 0", s);
- return ERROR(GENERIC);
- }
- cost += (size_t)count[s] * bitCost;
- }
- return cost >> kAccuracyLog;
-}
-
-/**
- * Returns the cost in bits of encoding the distribution in count using the
- * table described by norm. The max symbol support by norm is assumed >= max.
- * norm must be valid for every symbol with non-zero probability in count.
- */
-size_t ZSTD_crossEntropyCost(short const* norm, unsigned accuracyLog,
- unsigned const* count, unsigned const max)
-{
- unsigned const shift = 8 - accuracyLog;
- size_t cost = 0;
- unsigned s;
- assert(accuracyLog <= 8);
- for (s = 0; s <= max; ++s) {
- unsigned const normAcc = (norm[s] != -1) ? (unsigned)norm[s] : 1;
- unsigned const norm256 = normAcc << shift;
- assert(norm256 > 0);
- assert(norm256 < 256);
- cost += count[s] * kInverseProbabilityLog256[norm256];
- }
- return cost >> 8;
-}
-
-symbolEncodingType_e
-ZSTD_selectEncodingType(
- FSE_repeat* repeatMode, unsigned const* count, unsigned const max,
- size_t const mostFrequent, size_t nbSeq, unsigned const FSELog,
- FSE_CTable const* prevCTable,
- short const* defaultNorm, U32 defaultNormLog,
- ZSTD_defaultPolicy_e const isDefaultAllowed,
- ZSTD_strategy const strategy)
-{
- ZSTD_STATIC_ASSERT(ZSTD_defaultDisallowed == 0 && ZSTD_defaultAllowed != 0);
- if (mostFrequent == nbSeq) {
- *repeatMode = FSE_repeat_none;
- if (isDefaultAllowed && nbSeq <= 2) {
- /* Prefer set_basic over set_rle when there are 2 or less symbols,
- * since RLE uses 1 byte, but set_basic uses 5-6 bits per symbol.
- * If basic encoding isn't possible, always choose RLE.
- */
- DEBUGLOG(5, "Selected set_basic");
- return set_basic;
- }
- DEBUGLOG(5, "Selected set_rle");
- return set_rle;
- }
- if (strategy < ZSTD_lazy) {
- if (isDefaultAllowed) {
- size_t const staticFse_nbSeq_max = 1000;
- size_t const mult = 10 - strategy;
- size_t const baseLog = 3;
- size_t const dynamicFse_nbSeq_min = (((size_t)1 << defaultNormLog) * mult) >> baseLog; /* 28-36 for offset, 56-72 for lengths */
- assert(defaultNormLog >= 5 && defaultNormLog <= 6); /* xx_DEFAULTNORMLOG */
- assert(mult <= 9 && mult >= 7);
- if ( (*repeatMode == FSE_repeat_valid)
- && (nbSeq < staticFse_nbSeq_max) ) {
- DEBUGLOG(5, "Selected set_repeat");
- return set_repeat;
- }
- if ( (nbSeq < dynamicFse_nbSeq_min)
- || (mostFrequent < (nbSeq >> (defaultNormLog-1))) ) {
- DEBUGLOG(5, "Selected set_basic");
- /* The format allows default tables to be repeated, but it isn't useful.
- * When using simple heuristics to select encoding type, we don't want
- * to confuse these tables with dictionaries. When running more careful
- * analysis, we don't need to waste time checking both repeating tables
- * and default tables.
- */
- *repeatMode = FSE_repeat_none;
- return set_basic;
- }
- }
- } else {
- size_t const basicCost = isDefaultAllowed ? ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, count, max) : ERROR(GENERIC);
- size_t const repeatCost = *repeatMode != FSE_repeat_none ? ZSTD_fseBitCost(prevCTable, count, max) : ERROR(GENERIC);
- size_t const NCountCost = ZSTD_NCountCost(count, max, nbSeq, FSELog);
- size_t const compressedCost = (NCountCost << 3) + ZSTD_entropyCost(count, max, nbSeq);
-
- if (isDefaultAllowed) {
- assert(!ZSTD_isError(basicCost));
- assert(!(*repeatMode == FSE_repeat_valid && ZSTD_isError(repeatCost)));
- }
- assert(!ZSTD_isError(NCountCost));
- assert(compressedCost < ERROR(maxCode));
- DEBUGLOG(5, "Estimated bit costs: basic=%u\trepeat=%u\tcompressed=%u",
- (unsigned)basicCost, (unsigned)repeatCost, (unsigned)compressedCost);
- if (basicCost <= repeatCost && basicCost <= compressedCost) {
- DEBUGLOG(5, "Selected set_basic");
- assert(isDefaultAllowed);
- *repeatMode = FSE_repeat_none;
- return set_basic;
- }
- if (repeatCost <= compressedCost) {
- DEBUGLOG(5, "Selected set_repeat");
- assert(!ZSTD_isError(repeatCost));
- return set_repeat;
- }
- assert(compressedCost < basicCost && compressedCost < repeatCost);
- }
- DEBUGLOG(5, "Selected set_compressed");
- *repeatMode = FSE_repeat_check;
- return set_compressed;
-}
-
-size_t
-ZSTD_buildCTable(void* dst, size_t dstCapacity,
- FSE_CTable* nextCTable, U32 FSELog, symbolEncodingType_e type,
- unsigned* count, U32 max,
- const BYTE* codeTable, size_t nbSeq,
- const S16* defaultNorm, U32 defaultNormLog, U32 defaultMax,
- const FSE_CTable* prevCTable, size_t prevCTableSize,
- void* entropyWorkspace, size_t entropyWorkspaceSize)
-{
- BYTE* op = (BYTE*)dst;
- const BYTE* const oend = op + dstCapacity;
- DEBUGLOG(6, "ZSTD_buildCTable (dstCapacity=%u)", (unsigned)dstCapacity);
-
- switch (type) {
- case set_rle:
- FORWARD_IF_ERROR(FSE_buildCTable_rle(nextCTable, (BYTE)max), "");
- RETURN_ERROR_IF(dstCapacity==0, dstSize_tooSmall, "not enough space");
- *op = codeTable[0];
- return 1;
- case set_repeat:
- memcpy(nextCTable, prevCTable, prevCTableSize);
- return 0;
- case set_basic:
- FORWARD_IF_ERROR(FSE_buildCTable_wksp(nextCTable, defaultNorm, defaultMax, defaultNormLog, entropyWorkspace, entropyWorkspaceSize), ""); /* note : could be pre-calculated */
- return 0;
- case set_compressed: {
- S16 norm[MaxSeq + 1];
- size_t nbSeq_1 = nbSeq;
- const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max);
- if (count[codeTable[nbSeq-1]] > 1) {
- count[codeTable[nbSeq-1]]--;
- nbSeq_1--;
- }
- assert(nbSeq_1 > 1);
- FORWARD_IF_ERROR(FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max), "");
- { size_t const NCountSize = FSE_writeNCount(op, oend - op, norm, max, tableLog); /* overflow protected */
- FORWARD_IF_ERROR(NCountSize, "FSE_writeNCount failed");
- FORWARD_IF_ERROR(FSE_buildCTable_wksp(nextCTable, norm, max, tableLog, entropyWorkspace, entropyWorkspaceSize), "");
- return NCountSize;
- }
- }
- default: assert(0); RETURN_ERROR(GENERIC, "impossible to reach");
- }
-}
-
-FORCE_INLINE_TEMPLATE size_t
-ZSTD_encodeSequences_body(
- void* dst, size_t dstCapacity,
- FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
- FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
- FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
- seqDef const* sequences, size_t nbSeq, int longOffsets)
-{
- BIT_CStream_t blockStream;
- FSE_CState_t stateMatchLength;
- FSE_CState_t stateOffsetBits;
- FSE_CState_t stateLitLength;
-
- RETURN_ERROR_IF(
- ERR_isError(BIT_initCStream(&blockStream, dst, dstCapacity)),
- dstSize_tooSmall, "not enough space remaining");
- DEBUGLOG(6, "available space for bitstream : %i (dstCapacity=%u)",
- (int)(blockStream.endPtr - blockStream.startPtr),
- (unsigned)dstCapacity);
-
- /* first symbols */
- FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
- FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
- FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
- BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]);
- if (MEM_32bits()) BIT_flushBits(&blockStream);
- BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]);
- if (MEM_32bits()) BIT_flushBits(&blockStream);
- if (longOffsets) {
- U32 const ofBits = ofCodeTable[nbSeq-1];
- unsigned const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
- if (extraBits) {
- BIT_addBits(&blockStream, sequences[nbSeq-1].offset, extraBits);
- BIT_flushBits(&blockStream);
- }
- BIT_addBits(&blockStream, sequences[nbSeq-1].offset >> extraBits,
- ofBits - extraBits);
- } else {
- BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]);
- }
- BIT_flushBits(&blockStream);
-
- { size_t n;
- for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */
- BYTE const llCode = llCodeTable[n];
- BYTE const ofCode = ofCodeTable[n];
- BYTE const mlCode = mlCodeTable[n];
- U32 const llBits = LL_bits[llCode];
- U32 const ofBits = ofCode;
- U32 const mlBits = ML_bits[mlCode];
- DEBUGLOG(6, "encoding: litlen:%2u - matchlen:%2u - offCode:%7u",
- (unsigned)sequences[n].litLength,
- (unsigned)sequences[n].matchLength + MINMATCH,
- (unsigned)sequences[n].offset);
- /* 32b*/ /* 64b*/
- /* (7)*/ /* (7)*/
- FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
- FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
- if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
- FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
- if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
- BIT_flushBits(&blockStream); /* (7)*/
- BIT_addBits(&blockStream, sequences[n].litLength, llBits);
- if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
- BIT_addBits(&blockStream, sequences[n].matchLength, mlBits);
- if (MEM_32bits() || (ofBits+mlBits+llBits > 56)) BIT_flushBits(&blockStream);
- if (longOffsets) {
- unsigned const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
- if (extraBits) {
- BIT_addBits(&blockStream, sequences[n].offset, extraBits);
- BIT_flushBits(&blockStream); /* (7)*/
- }
- BIT_addBits(&blockStream, sequences[n].offset >> extraBits,
- ofBits - extraBits); /* 31 */
- } else {
- BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */
- }
- BIT_flushBits(&blockStream); /* (7)*/
- DEBUGLOG(7, "remaining space : %i", (int)(blockStream.endPtr - blockStream.ptr));
- } }
-
- DEBUGLOG(6, "ZSTD_encodeSequences: flushing ML state with %u bits", stateMatchLength.stateLog);
- FSE_flushCState(&blockStream, &stateMatchLength);
- DEBUGLOG(6, "ZSTD_encodeSequences: flushing Off state with %u bits", stateOffsetBits.stateLog);
- FSE_flushCState(&blockStream, &stateOffsetBits);
- DEBUGLOG(6, "ZSTD_encodeSequences: flushing LL state with %u bits", stateLitLength.stateLog);
- FSE_flushCState(&blockStream, &stateLitLength);
-
- { size_t const streamSize = BIT_closeCStream(&blockStream);
- RETURN_ERROR_IF(streamSize==0, dstSize_tooSmall, "not enough space");
- return streamSize;
- }
-}
-
-static size_t
-ZSTD_encodeSequences_default(
- void* dst, size_t dstCapacity,
- FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
- FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
- FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
- seqDef const* sequences, size_t nbSeq, int longOffsets)
-{
- return ZSTD_encodeSequences_body(dst, dstCapacity,
- CTable_MatchLength, mlCodeTable,
- CTable_OffsetBits, ofCodeTable,
- CTable_LitLength, llCodeTable,
- sequences, nbSeq, longOffsets);
-}
-
-
-#if DYNAMIC_BMI2
-
-static TARGET_ATTRIBUTE("bmi2") size_t
-ZSTD_encodeSequences_bmi2(
- void* dst, size_t dstCapacity,
- FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
- FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
- FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
- seqDef const* sequences, size_t nbSeq, int longOffsets)
-{
- return ZSTD_encodeSequences_body(dst, dstCapacity,
- CTable_MatchLength, mlCodeTable,
- CTable_OffsetBits, ofCodeTable,
- CTable_LitLength, llCodeTable,
- sequences, nbSeq, longOffsets);
-}
-
-#endif
-
-size_t ZSTD_encodeSequences(
- void* dst, size_t dstCapacity,
- FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
- FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
- FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
- seqDef const* sequences, size_t nbSeq, int longOffsets, int bmi2)
-{
- DEBUGLOG(5, "ZSTD_encodeSequences: dstCapacity = %u", (unsigned)dstCapacity);
-#if DYNAMIC_BMI2
- if (bmi2) {
- return ZSTD_encodeSequences_bmi2(dst, dstCapacity,
- CTable_MatchLength, mlCodeTable,
- CTable_OffsetBits, ofCodeTable,
- CTable_LitLength, llCodeTable,
- sequences, nbSeq, longOffsets);
- }
-#endif
- (void)bmi2;
- return ZSTD_encodeSequences_default(dst, dstCapacity,
- CTable_MatchLength, mlCodeTable,
- CTable_OffsetBits, ofCodeTable,
- CTable_LitLength, llCodeTable,
- sequences, nbSeq, longOffsets);
-}
-/**** ended inlining compress/zstd_compress_sequences.c ****/
-/**** start inlining compress/zstd_compress_superblock.c ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
- /*-*************************************
- * Dependencies
- ***************************************/
-/**** start inlining zstd_compress_superblock.h ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-#ifndef ZSTD_COMPRESS_ADVANCED_H
-#define ZSTD_COMPRESS_ADVANCED_H
-
-/*-*************************************
-* Dependencies
-***************************************/
-
-/**** skipping file: ../zstd.h ****/
-
-/*-*************************************
-* Target Compressed Block Size
-***************************************/
-
-/* ZSTD_compressSuperBlock() :
- * Used to compress a super block when targetCBlockSize is being used.
- * The given block will be compressed into multiple sub blocks that are around targetCBlockSize. */
-size_t ZSTD_compressSuperBlock(ZSTD_CCtx* zc,
- void* dst, size_t dstCapacity,
- void const* src, size_t srcSize,
- unsigned lastBlock);
-
-#endif /* ZSTD_COMPRESS_ADVANCED_H */
-/**** ended inlining zstd_compress_superblock.h ****/
-
-/**** skipping file: ../common/zstd_internal.h ****/
-/**** skipping file: hist.h ****/
-/**** skipping file: zstd_compress_internal.h ****/
-/**** skipping file: zstd_compress_sequences.h ****/
-/**** skipping file: zstd_compress_literals.h ****/
-
-/*-*************************************
-* Superblock entropy buffer structs
-***************************************/
-/** ZSTD_hufCTablesMetadata_t :
- * Stores Literals Block Type for a super-block in hType, and
- * huffman tree description in hufDesBuffer.
- * hufDesSize refers to the size of huffman tree description in bytes.
- * This metadata is populated in ZSTD_buildSuperBlockEntropy_literal() */
-typedef struct {
- symbolEncodingType_e hType;
- BYTE hufDesBuffer[500]; /* TODO give name to this value */
- size_t hufDesSize;
-} ZSTD_hufCTablesMetadata_t;
-
-/** ZSTD_fseCTablesMetadata_t :
- * Stores symbol compression modes for a super-block in {ll, ol, ml}Type, and
- * fse tables in fseTablesBuffer.
- * fseTablesSize refers to the size of fse tables in bytes.
- * This metadata is populated in ZSTD_buildSuperBlockEntropy_sequences() */
-typedef struct {
- symbolEncodingType_e llType;
- symbolEncodingType_e ofType;
- symbolEncodingType_e mlType;
- BYTE fseTablesBuffer[500]; /* TODO give name to this value */
- size_t fseTablesSize;
- size_t lastCountSize; /* This is to account for bug in 1.3.4. More detail in ZSTD_compressSubBlock_sequences() */
-} ZSTD_fseCTablesMetadata_t;
-
-typedef struct {
- ZSTD_hufCTablesMetadata_t hufMetadata;
- ZSTD_fseCTablesMetadata_t fseMetadata;
-} ZSTD_entropyCTablesMetadata_t;
-
-
-/** ZSTD_buildSuperBlockEntropy_literal() :
- * Builds entropy for the super-block literals.
- * Stores literals block type (raw, rle, compressed, repeat) and
- * huffman description table to hufMetadata.
- * @return : size of huffman description table or error code */
-static size_t ZSTD_buildSuperBlockEntropy_literal(void* const src, size_t srcSize,
- const ZSTD_hufCTables_t* prevHuf,
- ZSTD_hufCTables_t* nextHuf,
- ZSTD_hufCTablesMetadata_t* hufMetadata,
- const int disableLiteralsCompression,
- void* workspace, size_t wkspSize)
-{
- BYTE* const wkspStart = (BYTE*)workspace;
- BYTE* const wkspEnd = wkspStart + wkspSize;
- BYTE* const countWkspStart = wkspStart;
- unsigned* const countWksp = (unsigned*)workspace;
- const size_t countWkspSize = (HUF_SYMBOLVALUE_MAX + 1) * sizeof(unsigned);
- BYTE* const nodeWksp = countWkspStart + countWkspSize;
- const size_t nodeWkspSize = wkspEnd-nodeWksp;
- unsigned maxSymbolValue = 255;
- unsigned huffLog = HUF_TABLELOG_DEFAULT;
- HUF_repeat repeat = prevHuf->repeatMode;
-
- DEBUGLOG(5, "ZSTD_buildSuperBlockEntropy_literal (srcSize=%zu)", srcSize);
-
- /* Prepare nextEntropy assuming reusing the existing table */
- memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
-
- if (disableLiteralsCompression) {
- DEBUGLOG(5, "set_basic - disabled");
- hufMetadata->hType = set_basic;
- return 0;
- }
-
- /* small ? don't even attempt compression (speed opt) */
-# define COMPRESS_LITERALS_SIZE_MIN 63
- { size_t const minLitSize = (prevHuf->repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN;
- if (srcSize <= minLitSize) {
- DEBUGLOG(5, "set_basic - too small");
- hufMetadata->hType = set_basic;
- return 0;
- }
- }
-
- /* Scan input and build symbol stats */
- { size_t const largest = HIST_count_wksp (countWksp, &maxSymbolValue, (const BYTE*)src, srcSize, workspace, wkspSize);
- FORWARD_IF_ERROR(largest, "HIST_count_wksp failed");
- if (largest == srcSize) {
- DEBUGLOG(5, "set_rle");
- hufMetadata->hType = set_rle;
- return 0;
- }
- if (largest <= (srcSize >> 7)+4) {
- DEBUGLOG(5, "set_basic - no gain");
- hufMetadata->hType = set_basic;
- return 0;
- }
- }
-
- /* Validate the previous Huffman table */
- if (repeat == HUF_repeat_check && !HUF_validateCTable((HUF_CElt const*)prevHuf->CTable, countWksp, maxSymbolValue)) {
- repeat = HUF_repeat_none;
- }
-
- /* Build Huffman Tree */
- memset(nextHuf->CTable, 0, sizeof(nextHuf->CTable));
- huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue);
- { size_t const maxBits = HUF_buildCTable_wksp((HUF_CElt*)nextHuf->CTable, countWksp,
- maxSymbolValue, huffLog,
- nodeWksp, nodeWkspSize);
- FORWARD_IF_ERROR(maxBits, "HUF_buildCTable_wksp");
- huffLog = (U32)maxBits;
- { /* Build and write the CTable */
- size_t const newCSize = HUF_estimateCompressedSize(
- (HUF_CElt*)nextHuf->CTable, countWksp, maxSymbolValue);
- size_t const hSize = HUF_writeCTable(
- hufMetadata->hufDesBuffer, sizeof(hufMetadata->hufDesBuffer),
- (HUF_CElt*)nextHuf->CTable, maxSymbolValue, huffLog);
- /* Check against repeating the previous CTable */
- if (repeat != HUF_repeat_none) {
- size_t const oldCSize = HUF_estimateCompressedSize(
- (HUF_CElt const*)prevHuf->CTable, countWksp, maxSymbolValue);
- if (oldCSize < srcSize && (oldCSize <= hSize + newCSize || hSize + 12 >= srcSize)) {
- DEBUGLOG(5, "set_repeat - smaller");
- memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
- hufMetadata->hType = set_repeat;
- return 0;
- }
- }
- if (newCSize + hSize >= srcSize) {
- DEBUGLOG(5, "set_basic - no gains");
- memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
- hufMetadata->hType = set_basic;
- return 0;
- }
- DEBUGLOG(5, "set_compressed (hSize=%u)", (U32)hSize);
- hufMetadata->hType = set_compressed;
- nextHuf->repeatMode = HUF_repeat_check;
- return hSize;
- }
- }
-}
-
-/** ZSTD_buildSuperBlockEntropy_sequences() :
- * Builds entropy for the super-block sequences.
- * Stores symbol compression modes and fse table to fseMetadata.
- * @return : size of fse tables or error code */
-static size_t ZSTD_buildSuperBlockEntropy_sequences(seqStore_t* seqStorePtr,
- const ZSTD_fseCTables_t* prevEntropy,
- ZSTD_fseCTables_t* nextEntropy,
- const ZSTD_CCtx_params* cctxParams,
- ZSTD_fseCTablesMetadata_t* fseMetadata,
- void* workspace, size_t wkspSize)
-{
- BYTE* const wkspStart = (BYTE*)workspace;
- BYTE* const wkspEnd = wkspStart + wkspSize;
- BYTE* const countWkspStart = wkspStart;
- unsigned* const countWksp = (unsigned*)workspace;
- const size_t countWkspSize = (MaxSeq + 1) * sizeof(unsigned);
- BYTE* const cTableWksp = countWkspStart + countWkspSize;
- const size_t cTableWkspSize = wkspEnd-cTableWksp;
- ZSTD_strategy const strategy = cctxParams->cParams.strategy;
- FSE_CTable* CTable_LitLength = nextEntropy->litlengthCTable;
- FSE_CTable* CTable_OffsetBits = nextEntropy->offcodeCTable;
- FSE_CTable* CTable_MatchLength = nextEntropy->matchlengthCTable;
- const BYTE* const ofCodeTable = seqStorePtr->ofCode;
- const BYTE* const llCodeTable = seqStorePtr->llCode;
- const BYTE* const mlCodeTable = seqStorePtr->mlCode;
- size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
- BYTE* const ostart = fseMetadata->fseTablesBuffer;
- BYTE* const oend = ostart + sizeof(fseMetadata->fseTablesBuffer);
- BYTE* op = ostart;
-
- assert(cTableWkspSize >= (1 << MaxFSELog) * sizeof(FSE_FUNCTION_TYPE));
- DEBUGLOG(5, "ZSTD_buildSuperBlockEntropy_sequences (nbSeq=%zu)", nbSeq);
- memset(workspace, 0, wkspSize);
-
- fseMetadata->lastCountSize = 0;
- /* convert length/distances into codes */
- ZSTD_seqToCodes(seqStorePtr);
- /* build CTable for Literal Lengths */
- { U32 LLtype;
- unsigned max = MaxLL;
- size_t const mostFrequent = HIST_countFast_wksp(countWksp, &max, llCodeTable, nbSeq, workspace, wkspSize); /* can't fail */
- DEBUGLOG(5, "Building LL table");
- nextEntropy->litlength_repeatMode = prevEntropy->litlength_repeatMode;
- LLtype = ZSTD_selectEncodingType(&nextEntropy->litlength_repeatMode,
- countWksp, max, mostFrequent, nbSeq,
- LLFSELog, prevEntropy->litlengthCTable,
- LL_defaultNorm, LL_defaultNormLog,
- ZSTD_defaultAllowed, strategy);
- assert(set_basic < set_compressed && set_rle < set_compressed);
- assert(!(LLtype < set_compressed && nextEntropy->litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
- { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype,
- countWksp, max, llCodeTable, nbSeq, LL_defaultNorm, LL_defaultNormLog, MaxLL,
- prevEntropy->litlengthCTable, sizeof(prevEntropy->litlengthCTable),
- cTableWksp, cTableWkspSize);
- FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for LitLens failed");
- if (LLtype == set_compressed)
- fseMetadata->lastCountSize = countSize;
- op += countSize;
- fseMetadata->llType = (symbolEncodingType_e) LLtype;
- } }
- /* build CTable for Offsets */
- { U32 Offtype;
- unsigned max = MaxOff;
- size_t const mostFrequent = HIST_countFast_wksp(countWksp, &max, ofCodeTable, nbSeq, workspace, wkspSize); /* can't fail */
- /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */
- ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed;
- DEBUGLOG(5, "Building OF table");
- nextEntropy->offcode_repeatMode = prevEntropy->offcode_repeatMode;
- Offtype = ZSTD_selectEncodingType(&nextEntropy->offcode_repeatMode,
- countWksp, max, mostFrequent, nbSeq,
- OffFSELog, prevEntropy->offcodeCTable,
- OF_defaultNorm, OF_defaultNormLog,
- defaultPolicy, strategy);
- assert(!(Offtype < set_compressed && nextEntropy->offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */
- { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype,
- countWksp, max, ofCodeTable, nbSeq, OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
- prevEntropy->offcodeCTable, sizeof(prevEntropy->offcodeCTable),
- cTableWksp, cTableWkspSize);
- FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for Offsets failed");
- if (Offtype == set_compressed)
- fseMetadata->lastCountSize = countSize;
- op += countSize;
- fseMetadata->ofType = (symbolEncodingType_e) Offtype;
- } }
- /* build CTable for MatchLengths */
- { U32 MLtype;
- unsigned max = MaxML;
- size_t const mostFrequent = HIST_countFast_wksp(countWksp, &max, mlCodeTable, nbSeq, workspace, wkspSize); /* can't fail */
- DEBUGLOG(5, "Building ML table (remaining space : %i)", (int)(oend-op));
- nextEntropy->matchlength_repeatMode = prevEntropy->matchlength_repeatMode;
- MLtype = ZSTD_selectEncodingType(&nextEntropy->matchlength_repeatMode,
- countWksp, max, mostFrequent, nbSeq,
- MLFSELog, prevEntropy->matchlengthCTable,
- ML_defaultNorm, ML_defaultNormLog,
- ZSTD_defaultAllowed, strategy);
- assert(!(MLtype < set_compressed && nextEntropy->matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
- { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype,
- countWksp, max, mlCodeTable, nbSeq, ML_defaultNorm, ML_defaultNormLog, MaxML,
- prevEntropy->matchlengthCTable, sizeof(prevEntropy->matchlengthCTable),
- cTableWksp, cTableWkspSize);
- FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for MatchLengths failed");
- if (MLtype == set_compressed)
- fseMetadata->lastCountSize = countSize;
- op += countSize;
- fseMetadata->mlType = (symbolEncodingType_e) MLtype;
- } }
- assert((size_t) (op-ostart) <= sizeof(fseMetadata->fseTablesBuffer));
- return op-ostart;
-}
-
-
-/** ZSTD_buildSuperBlockEntropy() :
- * Builds entropy for the super-block.
- * @return : 0 on success or error code */
-static size_t
-ZSTD_buildSuperBlockEntropy(seqStore_t* seqStorePtr,
- const ZSTD_entropyCTables_t* prevEntropy,
- ZSTD_entropyCTables_t* nextEntropy,
- const ZSTD_CCtx_params* cctxParams,
- ZSTD_entropyCTablesMetadata_t* entropyMetadata,
- void* workspace, size_t wkspSize)
-{
- size_t const litSize = seqStorePtr->lit - seqStorePtr->litStart;
- DEBUGLOG(5, "ZSTD_buildSuperBlockEntropy");
- entropyMetadata->hufMetadata.hufDesSize =
- ZSTD_buildSuperBlockEntropy_literal(seqStorePtr->litStart, litSize,
- &prevEntropy->huf, &nextEntropy->huf,
- &entropyMetadata->hufMetadata,
- ZSTD_disableLiteralsCompression(cctxParams),
- workspace, wkspSize);
- FORWARD_IF_ERROR(entropyMetadata->hufMetadata.hufDesSize, "ZSTD_buildSuperBlockEntropy_literal failed");
- entropyMetadata->fseMetadata.fseTablesSize =
- ZSTD_buildSuperBlockEntropy_sequences(seqStorePtr,
- &prevEntropy->fse, &nextEntropy->fse,
- cctxParams,
- &entropyMetadata->fseMetadata,
- workspace, wkspSize);
- FORWARD_IF_ERROR(entropyMetadata->fseMetadata.fseTablesSize, "ZSTD_buildSuperBlockEntropy_sequences failed");
- return 0;
-}
-
-/** ZSTD_compressSubBlock_literal() :
- * Compresses literals section for a sub-block.
- * When we have to write the Huffman table we will sometimes choose a header
- * size larger than necessary. This is because we have to pick the header size
- * before we know the table size + compressed size, so we have a bound on the
- * table size. If we guessed incorrectly, we fall back to uncompressed literals.
- *
- * We write the header when writeEntropy=1 and set entropyWrriten=1 when we succeeded
- * in writing the header, otherwise it is set to 0.
- *
- * hufMetadata->hType has literals block type info.
- * If it is set_basic, all sub-blocks literals section will be Raw_Literals_Block.
- * If it is set_rle, all sub-blocks literals section will be RLE_Literals_Block.
- * If it is set_compressed, first sub-block's literals section will be Compressed_Literals_Block
- * If it is set_compressed, first sub-block's literals section will be Treeless_Literals_Block
- * and the following sub-blocks' literals sections will be Treeless_Literals_Block.
- * @return : compressed size of literals section of a sub-block
- * Or 0 if it unable to compress.
- * Or error code */
-static size_t ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable,
- const ZSTD_hufCTablesMetadata_t* hufMetadata,
- const BYTE* literals, size_t litSize,
- void* dst, size_t dstSize,
- const int bmi2, int writeEntropy, int* entropyWritten)
-{
- size_t const header = writeEntropy ? 200 : 0;
- size_t const lhSize = 3 + (litSize >= (1 KB - header)) + (litSize >= (16 KB - header));
- BYTE* const ostart = (BYTE*)dst;
- BYTE* const oend = ostart + dstSize;
- BYTE* op = ostart + lhSize;
- U32 const singleStream = lhSize == 3;
- symbolEncodingType_e hType = writeEntropy ? hufMetadata->hType : set_repeat;
- size_t cLitSize = 0;
-
- (void)bmi2; /* TODO bmi2... */
-
- DEBUGLOG(5, "ZSTD_compressSubBlock_literal (litSize=%zu, lhSize=%zu, writeEntropy=%d)", litSize, lhSize, writeEntropy);
-
- *entropyWritten = 0;
- if (litSize == 0 || hufMetadata->hType == set_basic) {
- DEBUGLOG(5, "ZSTD_compressSubBlock_literal using raw literal");
- return ZSTD_noCompressLiterals(dst, dstSize, literals, litSize);
- } else if (hufMetadata->hType == set_rle) {
- DEBUGLOG(5, "ZSTD_compressSubBlock_literal using rle literal");
- return ZSTD_compressRleLiteralsBlock(dst, dstSize, literals, litSize);
- }
-
- assert(litSize > 0);
- assert(hufMetadata->hType == set_compressed || hufMetadata->hType == set_repeat);
-
- if (writeEntropy && hufMetadata->hType == set_compressed) {
- memcpy(op, hufMetadata->hufDesBuffer, hufMetadata->hufDesSize);
- op += hufMetadata->hufDesSize;
- cLitSize += hufMetadata->hufDesSize;
- DEBUGLOG(5, "ZSTD_compressSubBlock_literal (hSize=%zu)", hufMetadata->hufDesSize);
- }
-
- /* TODO bmi2 */
- { const size_t cSize = singleStream ? HUF_compress1X_usingCTable(op, oend-op, literals, litSize, hufTable)
- : HUF_compress4X_usingCTable(op, oend-op, literals, litSize, hufTable);
- op += cSize;
- cLitSize += cSize;
- if (cSize == 0 || ERR_isError(cSize)) {
- DEBUGLOG(5, "Failed to write entropy tables %s", ZSTD_getErrorName(cSize));
- return 0;
- }
- /* If we expand and we aren't writing a header then emit uncompressed */
- if (!writeEntropy && cLitSize >= litSize) {
- DEBUGLOG(5, "ZSTD_compressSubBlock_literal using raw literal because uncompressible");
- return ZSTD_noCompressLiterals(dst, dstSize, literals, litSize);
- }
- /* If we are writing headers then allow expansion that doesn't change our header size. */
- if (lhSize < (size_t)(3 + (cLitSize >= 1 KB) + (cLitSize >= 16 KB))) {
- assert(cLitSize > litSize);
- DEBUGLOG(5, "Literals expanded beyond allowed header size");
- return ZSTD_noCompressLiterals(dst, dstSize, literals, litSize);
- }
- DEBUGLOG(5, "ZSTD_compressSubBlock_literal (cSize=%zu)", cSize);
- }
-
- /* Build header */
- switch(lhSize)
- {
- case 3: /* 2 - 2 - 10 - 10 */
- { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<14);
- MEM_writeLE24(ostart, lhc);
- break;
- }
- case 4: /* 2 - 2 - 14 - 14 */
- { U32 const lhc = hType + (2 << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<18);
- MEM_writeLE32(ostart, lhc);
- break;
- }
- case 5: /* 2 - 2 - 18 - 18 */
- { U32 const lhc = hType + (3 << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<22);
- MEM_writeLE32(ostart, lhc);
- ostart[4] = (BYTE)(cLitSize >> 10);
- break;
- }
- default: /* not possible : lhSize is {3,4,5} */
- assert(0);
- }
- *entropyWritten = 1;
- DEBUGLOG(5, "Compressed literals: %u -> %u", (U32)litSize, (U32)(op-ostart));
- return op-ostart;
-}
-
-static size_t ZSTD_seqDecompressedSize(seqStore_t const* seqStore, const seqDef* sequences, size_t nbSeq, size_t litSize, int lastSequence) {
- const seqDef* const sstart = sequences;
- const seqDef* const send = sequences + nbSeq;
- const seqDef* sp = sstart;
- size_t matchLengthSum = 0;
- size_t litLengthSum = 0;
- while (send-sp > 0) {
- ZSTD_sequenceLength const seqLen = ZSTD_getSequenceLength(seqStore, sp);
- litLengthSum += seqLen.litLength;
- matchLengthSum += seqLen.matchLength;
- sp++;
- }
- assert(litLengthSum <= litSize);
- if (!lastSequence) {
- assert(litLengthSum == litSize);
- }
- return matchLengthSum + litSize;
-}
-
-/** ZSTD_compressSubBlock_sequences() :
- * Compresses sequences section for a sub-block.
- * fseMetadata->llType, fseMetadata->ofType, and fseMetadata->mlType have
- * symbol compression modes for the super-block.
- * The first successfully compressed block will have these in its header.
- * We set entropyWritten=1 when we succeed in compressing the sequences.
- * The following sub-blocks will always have repeat mode.
- * @return : compressed size of sequences section of a sub-block
- * Or 0 if it is unable to compress
- * Or error code. */
-static size_t ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables,
- const ZSTD_fseCTablesMetadata_t* fseMetadata,
- const seqDef* sequences, size_t nbSeq,
- const BYTE* llCode, const BYTE* mlCode, const BYTE* ofCode,
- const ZSTD_CCtx_params* cctxParams,
- void* dst, size_t dstCapacity,
- const int bmi2, int writeEntropy, int* entropyWritten)
-{
- const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN;
- BYTE* const ostart = (BYTE*)dst;
- BYTE* const oend = ostart + dstCapacity;
- BYTE* op = ostart;
- BYTE* seqHead;
-
- DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (nbSeq=%zu, writeEntropy=%d, longOffsets=%d)", nbSeq, writeEntropy, longOffsets);
-
- *entropyWritten = 0;
- /* Sequences Header */
- RETURN_ERROR_IF((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead*/,
- dstSize_tooSmall, "");
- if (nbSeq < 0x7F)
- *op++ = (BYTE)nbSeq;
- else if (nbSeq < LONGNBSEQ)
- op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
- else
- op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
- if (nbSeq==0) {
- return op - ostart;
- }
-
- /* seqHead : flags for FSE encoding type */
- seqHead = op++;
-
- DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (seqHeadSize=%u)", (unsigned)(op-ostart));
-
- if (writeEntropy) {
- const U32 LLtype = fseMetadata->llType;
- const U32 Offtype = fseMetadata->ofType;
- const U32 MLtype = fseMetadata->mlType;
- DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (fseTablesSize=%zu)", fseMetadata->fseTablesSize);
- *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
- memcpy(op, fseMetadata->fseTablesBuffer, fseMetadata->fseTablesSize);
- op += fseMetadata->fseTablesSize;
- } else {
- const U32 repeat = set_repeat;
- *seqHead = (BYTE)((repeat<<6) + (repeat<<4) + (repeat<<2));
- }
-
- { size_t const bitstreamSize = ZSTD_encodeSequences(
- op, oend - op,
- fseTables->matchlengthCTable, mlCode,
- fseTables->offcodeCTable, ofCode,
- fseTables->litlengthCTable, llCode,
- sequences, nbSeq,
- longOffsets, bmi2);
- FORWARD_IF_ERROR(bitstreamSize, "ZSTD_encodeSequences failed");
- op += bitstreamSize;
- /* zstd versions <= 1.3.4 mistakenly report corruption when
- * FSE_readNCount() receives a buffer < 4 bytes.
- * Fixed by https://github.com/facebook/zstd/pull/1146.
- * This can happen when the last set_compressed table present is 2
- * bytes and the bitstream is only one byte.
- * In this exceedingly rare case, we will simply emit an uncompressed
- * block, since it isn't worth optimizing.
- */
-#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
- if (writeEntropy && fseMetadata->lastCountSize && fseMetadata->lastCountSize + bitstreamSize < 4) {
- /* NCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */
- assert(fseMetadata->lastCountSize + bitstreamSize == 3);
- DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.3.4 by "
- "emitting an uncompressed block.");
- return 0;
- }
-#endif
- DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (bitstreamSize=%zu)", bitstreamSize);
- }
-
- /* zstd versions <= 1.4.0 mistakenly report error when
- * sequences section body size is less than 3 bytes.
- * Fixed by https://github.com/facebook/zstd/pull/1664.
- * This can happen when the previous sequences section block is compressed
- * with rle mode and the current block's sequences section is compressed
- * with repeat mode where sequences section body size can be 1 byte.
- */
-#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
- if (op-seqHead < 4) {
- DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.4.0 by emitting "
- "an uncompressed block when sequences are < 4 bytes");
- return 0;
- }
-#endif
-
- *entropyWritten = 1;
- return op - ostart;
-}
-
-/** ZSTD_compressSubBlock() :
- * Compresses a single sub-block.
- * @return : compressed size of the sub-block
- * Or 0 if it failed to compress. */
-static size_t ZSTD_compressSubBlock(const ZSTD_entropyCTables_t* entropy,
- const ZSTD_entropyCTablesMetadata_t* entropyMetadata,
- const seqDef* sequences, size_t nbSeq,
- const BYTE* literals, size_t litSize,
- const BYTE* llCode, const BYTE* mlCode, const BYTE* ofCode,
- const ZSTD_CCtx_params* cctxParams,
- void* dst, size_t dstCapacity,
- const int bmi2,
- int writeLitEntropy, int writeSeqEntropy,
- int* litEntropyWritten, int* seqEntropyWritten,
- U32 lastBlock)
-{
- BYTE* const ostart = (BYTE*)dst;
- BYTE* const oend = ostart + dstCapacity;
- BYTE* op = ostart + ZSTD_blockHeaderSize;
- DEBUGLOG(5, "ZSTD_compressSubBlock (litSize=%zu, nbSeq=%zu, writeLitEntropy=%d, writeSeqEntropy=%d, lastBlock=%d)",
- litSize, nbSeq, writeLitEntropy, writeSeqEntropy, lastBlock);
- { size_t cLitSize = ZSTD_compressSubBlock_literal((const HUF_CElt*)entropy->huf.CTable,
- &entropyMetadata->hufMetadata, literals, litSize,
- op, oend-op, bmi2, writeLitEntropy, litEntropyWritten);
- FORWARD_IF_ERROR(cLitSize, "ZSTD_compressSubBlock_literal failed");
- if (cLitSize == 0) return 0;
- op += cLitSize;
- }
- { size_t cSeqSize = ZSTD_compressSubBlock_sequences(&entropy->fse,
- &entropyMetadata->fseMetadata,
- sequences, nbSeq,
- llCode, mlCode, ofCode,
- cctxParams,
- op, oend-op,
- bmi2, writeSeqEntropy, seqEntropyWritten);
- FORWARD_IF_ERROR(cSeqSize, "ZSTD_compressSubBlock_sequences failed");
- if (cSeqSize == 0) return 0;
- op += cSeqSize;
- }
- /* Write block header */
- { size_t cSize = (op-ostart)-ZSTD_blockHeaderSize;
- U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
- MEM_writeLE24(ostart, cBlockHeader24);
- }
- return op-ostart;
-}
-
-static size_t ZSTD_estimateSubBlockSize_literal(const BYTE* literals, size_t litSize,
- const ZSTD_hufCTables_t* huf,
- const ZSTD_hufCTablesMetadata_t* hufMetadata,
- void* workspace, size_t wkspSize,
- int writeEntropy)
-{
- unsigned* const countWksp = (unsigned*)workspace;
- unsigned maxSymbolValue = 255;
- size_t literalSectionHeaderSize = 3; /* Use hard coded size of 3 bytes */
-
- if (hufMetadata->hType == set_basic) return litSize;
- else if (hufMetadata->hType == set_rle) return 1;
- else if (hufMetadata->hType == set_compressed || hufMetadata->hType == set_repeat) {
- size_t const largest = HIST_count_wksp (countWksp, &maxSymbolValue, (const BYTE*)literals, litSize, workspace, wkspSize);
- if (ZSTD_isError(largest)) return litSize;
- { size_t cLitSizeEstimate = HUF_estimateCompressedSize((const HUF_CElt*)huf->CTable, countWksp, maxSymbolValue);
- if (writeEntropy) cLitSizeEstimate += hufMetadata->hufDesSize;
- return cLitSizeEstimate + literalSectionHeaderSize;
- } }
- assert(0); /* impossible */
- return 0;
-}
-
-static size_t ZSTD_estimateSubBlockSize_symbolType(symbolEncodingType_e type,
- const BYTE* codeTable, unsigned maxCode,
- size_t nbSeq, const FSE_CTable* fseCTable,
- const U32* additionalBits,
- short const* defaultNorm, U32 defaultNormLog,
- void* workspace, size_t wkspSize)
-{
- unsigned* const countWksp = (unsigned*)workspace;
- const BYTE* ctp = codeTable;
- const BYTE* const ctStart = ctp;
- const BYTE* const ctEnd = ctStart + nbSeq;
- size_t cSymbolTypeSizeEstimateInBits = 0;
- unsigned max = maxCode;
-
- HIST_countFast_wksp(countWksp, &max, codeTable, nbSeq, workspace, wkspSize); /* can't fail */
- if (type == set_basic) {
- cSymbolTypeSizeEstimateInBits = ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, countWksp, max);
- } else if (type == set_rle) {
- cSymbolTypeSizeEstimateInBits = 0;
- } else if (type == set_compressed || type == set_repeat) {
- cSymbolTypeSizeEstimateInBits = ZSTD_fseBitCost(fseCTable, countWksp, max);
- }
- if (ZSTD_isError(cSymbolTypeSizeEstimateInBits)) return nbSeq * 10;
- while (ctp < ctEnd) {
- if (additionalBits) cSymbolTypeSizeEstimateInBits += additionalBits[*ctp];
- else cSymbolTypeSizeEstimateInBits += *ctp; /* for offset, offset code is also the number of additional bits */
- ctp++;
- }
- return cSymbolTypeSizeEstimateInBits / 8;
-}
-
-static size_t ZSTD_estimateSubBlockSize_sequences(const BYTE* ofCodeTable,
- const BYTE* llCodeTable,
- const BYTE* mlCodeTable,
- size_t nbSeq,
- const ZSTD_fseCTables_t* fseTables,
- const ZSTD_fseCTablesMetadata_t* fseMetadata,
- void* workspace, size_t wkspSize,
- int writeEntropy)
-{
- size_t sequencesSectionHeaderSize = 3; /* Use hard coded size of 3 bytes */
- size_t cSeqSizeEstimate = 0;
- cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->ofType, ofCodeTable, MaxOff,
- nbSeq, fseTables->offcodeCTable, NULL,
- OF_defaultNorm, OF_defaultNormLog,
- workspace, wkspSize);
- cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->llType, llCodeTable, MaxLL,
- nbSeq, fseTables->litlengthCTable, LL_bits,
- LL_defaultNorm, LL_defaultNormLog,
- workspace, wkspSize);
- cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->mlType, mlCodeTable, MaxML,
- nbSeq, fseTables->matchlengthCTable, ML_bits,
- ML_defaultNorm, ML_defaultNormLog,
- workspace, wkspSize);
- if (writeEntropy) cSeqSizeEstimate += fseMetadata->fseTablesSize;
- return cSeqSizeEstimate + sequencesSectionHeaderSize;
-}
-
-static size_t ZSTD_estimateSubBlockSize(const BYTE* literals, size_t litSize,
- const BYTE* ofCodeTable,
- const BYTE* llCodeTable,
- const BYTE* mlCodeTable,
- size_t nbSeq,
- const ZSTD_entropyCTables_t* entropy,
- const ZSTD_entropyCTablesMetadata_t* entropyMetadata,
- void* workspace, size_t wkspSize,
- int writeLitEntropy, int writeSeqEntropy) {
- size_t cSizeEstimate = 0;
- cSizeEstimate += ZSTD_estimateSubBlockSize_literal(literals, litSize,
- &entropy->huf, &entropyMetadata->hufMetadata,
- workspace, wkspSize, writeLitEntropy);
- cSizeEstimate += ZSTD_estimateSubBlockSize_sequences(ofCodeTable, llCodeTable, mlCodeTable,
- nbSeq, &entropy->fse, &entropyMetadata->fseMetadata,
- workspace, wkspSize, writeSeqEntropy);
- return cSizeEstimate + ZSTD_blockHeaderSize;
-}
-
-static int ZSTD_needSequenceEntropyTables(ZSTD_fseCTablesMetadata_t const* fseMetadata)
-{
- if (fseMetadata->llType == set_compressed || fseMetadata->llType == set_rle)
- return 1;
- if (fseMetadata->mlType == set_compressed || fseMetadata->mlType == set_rle)
- return 1;
- if (fseMetadata->ofType == set_compressed || fseMetadata->ofType == set_rle)
- return 1;
- return 0;
-}
-
-/** ZSTD_compressSubBlock_multi() :
- * Breaks super-block into multiple sub-blocks and compresses them.
- * Entropy will be written to the first block.
- * The following blocks will use repeat mode to compress.
- * All sub-blocks are compressed blocks (no raw or rle blocks).
- * @return : compressed size of the super block (which is multiple ZSTD blocks)
- * Or 0 if it failed to compress. */
-static size_t ZSTD_compressSubBlock_multi(const seqStore_t* seqStorePtr,
- const ZSTD_compressedBlockState_t* prevCBlock,
- ZSTD_compressedBlockState_t* nextCBlock,
- const ZSTD_entropyCTablesMetadata_t* entropyMetadata,
- const ZSTD_CCtx_params* cctxParams,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- const int bmi2, U32 lastBlock,
- void* workspace, size_t wkspSize)
-{
- const seqDef* const sstart = seqStorePtr->sequencesStart;
- const seqDef* const send = seqStorePtr->sequences;
- const seqDef* sp = sstart;
- const BYTE* const lstart = seqStorePtr->litStart;
- const BYTE* const lend = seqStorePtr->lit;
- const BYTE* lp = lstart;
- BYTE const* ip = (BYTE const*)src;
- BYTE const* const iend = ip + srcSize;
- BYTE* const ostart = (BYTE*)dst;
- BYTE* const oend = ostart + dstCapacity;
- BYTE* op = ostart;
- const BYTE* llCodePtr = seqStorePtr->llCode;
- const BYTE* mlCodePtr = seqStorePtr->mlCode;
- const BYTE* ofCodePtr = seqStorePtr->ofCode;
- size_t targetCBlockSize = cctxParams->targetCBlockSize;
- size_t litSize, seqCount;
- int writeLitEntropy = entropyMetadata->hufMetadata.hType == set_compressed;
- int writeSeqEntropy = 1;
- int lastSequence = 0;
-
- DEBUGLOG(5, "ZSTD_compressSubBlock_multi (litSize=%u, nbSeq=%u)",
- (unsigned)(lend-lp), (unsigned)(send-sstart));
-
- litSize = 0;
- seqCount = 0;
- do {
- size_t cBlockSizeEstimate = 0;
- if (sstart == send) {
- lastSequence = 1;
- } else {
- const seqDef* const sequence = sp + seqCount;
- lastSequence = sequence == send - 1;
- litSize += ZSTD_getSequenceLength(seqStorePtr, sequence).litLength;
- seqCount++;
- }
- if (lastSequence) {
- assert(lp <= lend);
- assert(litSize <= (size_t)(lend - lp));
- litSize = (size_t)(lend - lp);
- }
- /* I think there is an optimization opportunity here.
- * Calling ZSTD_estimateSubBlockSize for every sequence can be wasteful
- * since it recalculates estimate from scratch.
- * For example, it would recount literal distribution and symbol codes everytime.
- */
- cBlockSizeEstimate = ZSTD_estimateSubBlockSize(lp, litSize, ofCodePtr, llCodePtr, mlCodePtr, seqCount,
- &nextCBlock->entropy, entropyMetadata,
- workspace, wkspSize, writeLitEntropy, writeSeqEntropy);
- if (cBlockSizeEstimate > targetCBlockSize || lastSequence) {
- int litEntropyWritten = 0;
- int seqEntropyWritten = 0;
- const size_t decompressedSize = ZSTD_seqDecompressedSize(seqStorePtr, sp, seqCount, litSize, lastSequence);
- const size_t cSize = ZSTD_compressSubBlock(&nextCBlock->entropy, entropyMetadata,
- sp, seqCount,
- lp, litSize,
- llCodePtr, mlCodePtr, ofCodePtr,
- cctxParams,
- op, oend-op,
- bmi2, writeLitEntropy, writeSeqEntropy,
- &litEntropyWritten, &seqEntropyWritten,
- lastBlock && lastSequence);
- FORWARD_IF_ERROR(cSize, "ZSTD_compressSubBlock failed");
- if (cSize > 0 && cSize < decompressedSize) {
- DEBUGLOG(5, "Committed the sub-block");
- assert(ip + decompressedSize <= iend);
- ip += decompressedSize;
- sp += seqCount;
- lp += litSize;
- op += cSize;
- llCodePtr += seqCount;
- mlCodePtr += seqCount;
- ofCodePtr += seqCount;
- litSize = 0;
- seqCount = 0;
- /* Entropy only needs to be written once */
- if (litEntropyWritten) {
- writeLitEntropy = 0;
- }
- if (seqEntropyWritten) {
- writeSeqEntropy = 0;
- }
- }
- }
- } while (!lastSequence);
- if (writeLitEntropy) {
- DEBUGLOG(5, "ZSTD_compressSubBlock_multi has literal entropy tables unwritten");
- memcpy(&nextCBlock->entropy.huf, &prevCBlock->entropy.huf, sizeof(prevCBlock->entropy.huf));
- }
- if (writeSeqEntropy && ZSTD_needSequenceEntropyTables(&entropyMetadata->fseMetadata)) {
- /* If we haven't written our entropy tables, then we've violated our contract and
- * must emit an uncompressed block.
- */
- DEBUGLOG(5, "ZSTD_compressSubBlock_multi has sequence entropy tables unwritten");
- return 0;
- }
- if (ip < iend) {
- size_t const cSize = ZSTD_noCompressBlock(op, oend - op, ip, iend - ip, lastBlock);
- DEBUGLOG(5, "ZSTD_compressSubBlock_multi last sub-block uncompressed, %zu bytes", (size_t)(iend - ip));
- FORWARD_IF_ERROR(cSize, "ZSTD_noCompressBlock failed");
- assert(cSize != 0);
- op += cSize;
- /* We have to regenerate the repcodes because we've skipped some sequences */
- if (sp < send) {
- seqDef const* seq;
- repcodes_t rep;
- memcpy(&rep, prevCBlock->rep, sizeof(rep));
- for (seq = sstart; seq < sp; ++seq) {
- rep = ZSTD_updateRep(rep.rep, seq->offset - 1, ZSTD_getSequenceLength(seqStorePtr, seq).litLength == 0);
- }
- memcpy(nextCBlock->rep, &rep, sizeof(rep));
- }
- }
- DEBUGLOG(5, "ZSTD_compressSubBlock_multi compressed");
- return op-ostart;
-}
-
-size_t ZSTD_compressSuperBlock(ZSTD_CCtx* zc,
- void* dst, size_t dstCapacity,
- void const* src, size_t srcSize,
- unsigned lastBlock) {
- ZSTD_entropyCTablesMetadata_t entropyMetadata;
-
- FORWARD_IF_ERROR(ZSTD_buildSuperBlockEntropy(&zc->seqStore,
- &zc->blockState.prevCBlock->entropy,
- &zc->blockState.nextCBlock->entropy,
- &zc->appliedParams,
- &entropyMetadata,
- zc->entropyWorkspace, HUF_WORKSPACE_SIZE /* statically allocated in resetCCtx */), "");
-
- return ZSTD_compressSubBlock_multi(&zc->seqStore,
- zc->blockState.prevCBlock,
- zc->blockState.nextCBlock,
- &entropyMetadata,
- &zc->appliedParams,
- dst, dstCapacity,
- src, srcSize,
- zc->bmi2, lastBlock,
- zc->entropyWorkspace, HUF_WORKSPACE_SIZE /* statically allocated in resetCCtx */);
-}
-/**** ended inlining compress/zstd_compress_superblock.c ****/
-/**** start inlining compress/zstd_compress.c ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-/*-*************************************
-* Dependencies
-***************************************/
-#include <limits.h> /* INT_MAX */
-#include <string.h> /* memset */
-/**** start inlining ../common/cpu.h ****/
-/*
- * Copyright (c) 2018-2020, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-#ifndef ZSTD_COMMON_CPU_H
-#define ZSTD_COMMON_CPU_H
-
-/**
- * Implementation taken from folly/CpuId.h
- * https://github.com/facebook/folly/blob/master/folly/CpuId.h
- */
-
-#include <string.h>
-
-/**** skipping file: mem.h ****/
-
-#ifdef _MSC_VER
-#include <intrin.h>
-#endif
-
-typedef struct {
- U32 f1c;
- U32 f1d;
- U32 f7b;
- U32 f7c;
-} ZSTD_cpuid_t;
-
-MEM_STATIC ZSTD_cpuid_t ZSTD_cpuid(void) {
- U32 f1c = 0;
- U32 f1d = 0;
- U32 f7b = 0;
- U32 f7c = 0;
-#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86))
- int reg[4];
- __cpuid((int*)reg, 0);
- {
- int const n = reg[0];
- if (n >= 1) {
- __cpuid((int*)reg, 1);
- f1c = (U32)reg[2];
- f1d = (U32)reg[3];
- }
- if (n >= 7) {
- __cpuidex((int*)reg, 7, 0);
- f7b = (U32)reg[1];
- f7c = (U32)reg[2];
- }
- }
-#elif defined(__i386__) && defined(__PIC__) && !defined(__clang__) && defined(__GNUC__)
- /* The following block like the normal cpuid branch below, but gcc
- * reserves ebx for use of its pic register so we must specially
- * handle the save and restore to avoid clobbering the register
- */
- U32 n;
- __asm__(
- "pushl %%ebx\n\t"
- "cpuid\n\t"
- "popl %%ebx\n\t"
- : "=a"(n)
- : "a"(0)
- : "ecx", "edx");
- if (n >= 1) {
- U32 f1a;
- __asm__(
- "pushl %%ebx\n\t"
- "cpuid\n\t"
- "popl %%ebx\n\t"
- : "=a"(f1a), "=c"(f1c), "=d"(f1d)
- : "a"(1));
- }
- if (n >= 7) {
- __asm__(
- "pushl %%ebx\n\t"
- "cpuid\n\t"
- "movl %%ebx, %%eax\n\t"
- "popl %%ebx"
- : "=a"(f7b), "=c"(f7c)
- : "a"(7), "c"(0)
- : "edx");
- }
-#elif defined(__x86_64__) || defined(_M_X64) || defined(__i386__)
- U32 n;
- __asm__("cpuid" : "=a"(n) : "a"(0) : "ebx", "ecx", "edx");
- if (n >= 1) {
- U32 f1a;
- __asm__("cpuid" : "=a"(f1a), "=c"(f1c), "=d"(f1d) : "a"(1) : "ebx");
- }
- if (n >= 7) {
- U32 f7a;
- __asm__("cpuid"
- : "=a"(f7a), "=b"(f7b), "=c"(f7c)
- : "a"(7), "c"(0)
- : "edx");
- }
-#endif
- {
- ZSTD_cpuid_t cpuid;
- cpuid.f1c = f1c;
- cpuid.f1d = f1d;
- cpuid.f7b = f7b;
- cpuid.f7c = f7c;
- return cpuid;
- }
-}
-
-#define X(name, r, bit) \
- MEM_STATIC int ZSTD_cpuid_##name(ZSTD_cpuid_t const cpuid) { \
- return ((cpuid.r) & (1U << bit)) != 0; \
- }
-
-/* cpuid(1): Processor Info and Feature Bits. */
-#define C(name, bit) X(name, f1c, bit)
- C(sse3, 0)
- C(pclmuldq, 1)
- C(dtes64, 2)
- C(monitor, 3)
- C(dscpl, 4)
- C(vmx, 5)
- C(smx, 6)
- C(eist, 7)
- C(tm2, 8)
- C(ssse3, 9)
- C(cnxtid, 10)
- C(fma, 12)
- C(cx16, 13)
- C(xtpr, 14)
- C(pdcm, 15)
- C(pcid, 17)
- C(dca, 18)
- C(sse41, 19)
- C(sse42, 20)
- C(x2apic, 21)
- C(movbe, 22)
- C(popcnt, 23)
- C(tscdeadline, 24)
- C(aes, 25)
- C(xsave, 26)
- C(osxsave, 27)
- C(avx, 28)
- C(f16c, 29)
- C(rdrand, 30)
-#undef C
-#define D(name, bit) X(name, f1d, bit)
- D(fpu, 0)
- D(vme, 1)
- D(de, 2)
- D(pse, 3)
- D(tsc, 4)
- D(msr, 5)
- D(pae, 6)
- D(mce, 7)
- D(cx8, 8)
- D(apic, 9)
- D(sep, 11)
- D(mtrr, 12)
- D(pge, 13)
- D(mca, 14)
- D(cmov, 15)
- D(pat, 16)
- D(pse36, 17)
- D(psn, 18)
- D(clfsh, 19)
- D(ds, 21)
- D(acpi, 22)
- D(mmx, 23)
- D(fxsr, 24)
- D(sse, 25)
- D(sse2, 26)
- D(ss, 27)
- D(htt, 28)
- D(tm, 29)
- D(pbe, 31)
-#undef D
-
-/* cpuid(7): Extended Features. */
-#define B(name, bit) X(name, f7b, bit)
- B(bmi1, 3)
- B(hle, 4)
- B(avx2, 5)
- B(smep, 7)
- B(bmi2, 8)
- B(erms, 9)
- B(invpcid, 10)
- B(rtm, 11)
- B(mpx, 14)
- B(avx512f, 16)
- B(avx512dq, 17)
- B(rdseed, 18)
- B(adx, 19)
- B(smap, 20)
- B(avx512ifma, 21)
- B(pcommit, 22)
- B(clflushopt, 23)
- B(clwb, 24)
- B(avx512pf, 26)
- B(avx512er, 27)
- B(avx512cd, 28)
- B(sha, 29)
- B(avx512bw, 30)
- B(avx512vl, 31)
-#undef B
-#define C(name, bit) X(name, f7c, bit)
- C(prefetchwt1, 0)
- C(avx512vbmi, 1)
-#undef C
-
-#undef X
-
-#endif /* ZSTD_COMMON_CPU_H */
-/**** ended inlining ../common/cpu.h ****/
-/**** skipping file: ../common/mem.h ****/
-/**** skipping file: hist.h ****/
-#define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */
-/**** skipping file: ../common/fse.h ****/
-#define HUF_STATIC_LINKING_ONLY
-/**** skipping file: ../common/huf.h ****/
-/**** skipping file: zstd_compress_internal.h ****/
-/**** skipping file: zstd_compress_sequences.h ****/
-/**** skipping file: zstd_compress_literals.h ****/
-/**** start inlining zstd_fast.h ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-#ifndef ZSTD_FAST_H
-#define ZSTD_FAST_H
-
-#if defined (__cplusplus)
-extern "C" {
-#endif
-
-/**** skipping file: ../common/mem.h ****/
-/**** skipping file: zstd_compress_internal.h ****/
-
-void ZSTD_fillHashTable(ZSTD_matchState_t* ms,
- void const* end, ZSTD_dictTableLoadMethod_e dtlm);
-size_t ZSTD_compressBlock_fast(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize);
-size_t ZSTD_compressBlock_fast_dictMatchState(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize);
-size_t ZSTD_compressBlock_fast_extDict(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize);
-
-#if defined (__cplusplus)
-}
-#endif
-
-#endif /* ZSTD_FAST_H */
-/**** ended inlining zstd_fast.h ****/
-/**** start inlining zstd_double_fast.h ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-#ifndef ZSTD_DOUBLE_FAST_H
-#define ZSTD_DOUBLE_FAST_H
-
-#if defined (__cplusplus)
-extern "C" {
-#endif
-
-/**** skipping file: ../common/mem.h ****/
-/**** skipping file: zstd_compress_internal.h ****/
-
-void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms,
- void const* end, ZSTD_dictTableLoadMethod_e dtlm);
-size_t ZSTD_compressBlock_doubleFast(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize);
-size_t ZSTD_compressBlock_doubleFast_dictMatchState(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize);
-size_t ZSTD_compressBlock_doubleFast_extDict(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize);
-
-
-#if defined (__cplusplus)
-}
-#endif
-
-#endif /* ZSTD_DOUBLE_FAST_H */
-/**** ended inlining zstd_double_fast.h ****/
-/**** start inlining zstd_lazy.h ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-#ifndef ZSTD_LAZY_H
-#define ZSTD_LAZY_H
-
-#if defined (__cplusplus)
-extern "C" {
-#endif
-
-/**** skipping file: zstd_compress_internal.h ****/
-
-U32 ZSTD_insertAndFindFirstIndex(ZSTD_matchState_t* ms, const BYTE* ip);
-
-void ZSTD_preserveUnsortedMark (U32* const table, U32 const size, U32 const reducerValue); /*! used in ZSTD_reduceIndex(). preemptively increase value of ZSTD_DUBT_UNSORTED_MARK */
-
-size_t ZSTD_compressBlock_btlazy2(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize);
-size_t ZSTD_compressBlock_lazy2(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize);
-size_t ZSTD_compressBlock_lazy(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize);
-size_t ZSTD_compressBlock_greedy(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize);
-
-size_t ZSTD_compressBlock_btlazy2_dictMatchState(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize);
-size_t ZSTD_compressBlock_lazy2_dictMatchState(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize);
-size_t ZSTD_compressBlock_lazy_dictMatchState(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize);
-size_t ZSTD_compressBlock_greedy_dictMatchState(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize);
-
-size_t ZSTD_compressBlock_greedy_extDict(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize);
-size_t ZSTD_compressBlock_lazy_extDict(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize);
-size_t ZSTD_compressBlock_lazy2_extDict(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize);
-size_t ZSTD_compressBlock_btlazy2_extDict(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize);
-
-#if defined (__cplusplus)
-}
-#endif
-
-#endif /* ZSTD_LAZY_H */
-/**** ended inlining zstd_lazy.h ****/
-/**** start inlining zstd_opt.h ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-#ifndef ZSTD_OPT_H
-#define ZSTD_OPT_H
-
-#if defined (__cplusplus)
-extern "C" {
-#endif
-
-/**** skipping file: zstd_compress_internal.h ****/
-
-/* used in ZSTD_loadDictionaryContent() */
-void ZSTD_updateTree(ZSTD_matchState_t* ms, const BYTE* ip, const BYTE* iend);
-
-size_t ZSTD_compressBlock_btopt(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize);
-size_t ZSTD_compressBlock_btultra(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize);
-size_t ZSTD_compressBlock_btultra2(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize);
-
-
-size_t ZSTD_compressBlock_btopt_dictMatchState(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize);
-size_t ZSTD_compressBlock_btultra_dictMatchState(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize);
-
-size_t ZSTD_compressBlock_btopt_extDict(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize);
-size_t ZSTD_compressBlock_btultra_extDict(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize);
-
- /* note : no btultra2 variant for extDict nor dictMatchState,
- * because btultra2 is not meant to work with dictionaries
- * and is only specific for the first block (no prefix) */
-
-#if defined (__cplusplus)
-}
-#endif
-
-#endif /* ZSTD_OPT_H */
-/**** ended inlining zstd_opt.h ****/
-/**** start inlining zstd_ldm.h ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-#ifndef ZSTD_LDM_H
-#define ZSTD_LDM_H
-
-#if defined (__cplusplus)
-extern "C" {
-#endif
-
-/**** skipping file: zstd_compress_internal.h ****/
-/**** skipping file: ../zstd.h ****/
-
-/*-*************************************
-* Long distance matching
-***************************************/
-
-#define ZSTD_LDM_DEFAULT_WINDOW_LOG ZSTD_WINDOWLOG_LIMIT_DEFAULT
-
-void ZSTD_ldm_fillHashTable(
- ldmState_t* state, const BYTE* ip,
- const BYTE* iend, ldmParams_t const* params);
-
-/**
- * ZSTD_ldm_generateSequences():
- *
- * Generates the sequences using the long distance match finder.
- * Generates long range matching sequences in `sequences`, which parse a prefix
- * of the source. `sequences` must be large enough to store every sequence,
- * which can be checked with `ZSTD_ldm_getMaxNbSeq()`.
- * @returns 0 or an error code.
- *
- * NOTE: The user must have called ZSTD_window_update() for all of the input
- * they have, even if they pass it to ZSTD_ldm_generateSequences() in chunks.
- * NOTE: This function returns an error if it runs out of space to store
- * sequences.
- */
-size_t ZSTD_ldm_generateSequences(
- ldmState_t* ldms, rawSeqStore_t* sequences,
- ldmParams_t const* params, void const* src, size_t srcSize);
-
-/**
- * ZSTD_ldm_blockCompress():
- *
- * Compresses a block using the predefined sequences, along with a secondary
- * block compressor. The literals section of every sequence is passed to the
- * secondary block compressor, and those sequences are interspersed with the
- * predefined sequences. Returns the length of the last literals.
- * Updates `rawSeqStore.pos` to indicate how many sequences have been consumed.
- * `rawSeqStore.seq` may also be updated to split the last sequence between two
- * blocks.
- * @return The length of the last literals.
- *
- * NOTE: The source must be at most the maximum block size, but the predefined
- * sequences can be any size, and may be longer than the block. In the case that
- * they are longer than the block, the last sequences may need to be split into
- * two. We handle that case correctly, and update `rawSeqStore` appropriately.
- * NOTE: This function does not return any errors.
- */
-size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize);
-
-/**
- * ZSTD_ldm_skipSequences():
- *
- * Skip past `srcSize` bytes worth of sequences in `rawSeqStore`.
- * Avoids emitting matches less than `minMatch` bytes.
- * Must be called for data with is not passed to ZSTD_ldm_blockCompress().
- */
-void ZSTD_ldm_skipSequences(rawSeqStore_t* rawSeqStore, size_t srcSize,
- U32 const minMatch);
-
-
-/** ZSTD_ldm_getTableSize() :
- * Estimate the space needed for long distance matching tables or 0 if LDM is
- * disabled.
- */
-size_t ZSTD_ldm_getTableSize(ldmParams_t params);
-
-/** ZSTD_ldm_getSeqSpace() :
- * Return an upper bound on the number of sequences that can be produced by
- * the long distance matcher, or 0 if LDM is disabled.
- */
-size_t ZSTD_ldm_getMaxNbSeq(ldmParams_t params, size_t maxChunkSize);
-
-/** ZSTD_ldm_adjustParameters() :
- * If the params->hashRateLog is not set, set it to its default value based on
- * windowLog and params->hashLog.
- *
- * Ensures that params->bucketSizeLog is <= params->hashLog (setting it to
- * params->hashLog if it is not).
- *
- * Ensures that the minMatchLength >= targetLength during optimal parsing.
- */
-void ZSTD_ldm_adjustParameters(ldmParams_t* params,
- ZSTD_compressionParameters const* cParams);
-
-#if defined (__cplusplus)
-}
-#endif
-
-#endif /* ZSTD_FAST_H */
-/**** ended inlining zstd_ldm.h ****/
-/**** skipping file: zstd_compress_superblock.h ****/
-
-
-/*-*************************************
-* Helper functions
-***************************************/
-/* ZSTD_compressBound()
- * Note that the result from this function is only compatible with the "normal"
- * full-block strategy.
- * When there are a lot of small blocks due to frequent flush in streaming mode
- * the overhead of headers can make the compressed data to be larger than the
- * return value of ZSTD_compressBound().
- */
-size_t ZSTD_compressBound(size_t srcSize) {
- return ZSTD_COMPRESSBOUND(srcSize);
-}
-
-
-/*-*************************************
-* Context memory management
-***************************************/
-struct ZSTD_CDict_s {
- const void* dictContent;
- size_t dictContentSize;
- U32* entropyWorkspace; /* entropy workspace of HUF_WORKSPACE_SIZE bytes */
- ZSTD_cwksp workspace;
- ZSTD_matchState_t matchState;
- ZSTD_compressedBlockState_t cBlockState;
- ZSTD_customMem customMem;
- U32 dictID;
- int compressionLevel; /* 0 indicates that advanced API was used to select CDict params */
-}; /* typedef'd to ZSTD_CDict within "zstd.h" */
-
-ZSTD_CCtx* ZSTD_createCCtx(void)
-{
- return ZSTD_createCCtx_advanced(ZSTD_defaultCMem);
-}
-
-static void ZSTD_initCCtx(ZSTD_CCtx* cctx, ZSTD_customMem memManager)
-{
- assert(cctx != NULL);
- memset(cctx, 0, sizeof(*cctx));
- cctx->customMem = memManager;
- cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
- { size_t const err = ZSTD_CCtx_reset(cctx, ZSTD_reset_parameters);
- assert(!ZSTD_isError(err));
- (void)err;
- }
-}
-
-ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
-{
- ZSTD_STATIC_ASSERT(zcss_init==0);
- ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1));
- if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
- { ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_malloc(sizeof(ZSTD_CCtx), customMem);
- if (!cctx) return NULL;
- ZSTD_initCCtx(cctx, customMem);
- return cctx;
- }
-}
-
-ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize)
-{
- ZSTD_cwksp ws;
- ZSTD_CCtx* cctx;
- if (workspaceSize <= sizeof(ZSTD_CCtx)) return NULL; /* minimum size */
- if ((size_t)workspace & 7) return NULL; /* must be 8-aligned */
- ZSTD_cwksp_init(&ws, workspace, workspaceSize);
-
- cctx = (ZSTD_CCtx*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CCtx));
- if (cctx == NULL) return NULL;
-
- memset(cctx, 0, sizeof(ZSTD_CCtx));
- ZSTD_cwksp_move(&cctx->workspace, &ws);
- cctx->staticSize = workspaceSize;
-
- /* statically sized space. entropyWorkspace never moves (but prev/next block swap places) */
- if (!ZSTD_cwksp_check_available(&cctx->workspace, HUF_WORKSPACE_SIZE + 2 * sizeof(ZSTD_compressedBlockState_t))) return NULL;
- cctx->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)ZSTD_cwksp_reserve_object(&cctx->workspace, sizeof(ZSTD_compressedBlockState_t));
- cctx->blockState.nextCBlock = (ZSTD_compressedBlockState_t*)ZSTD_cwksp_reserve_object(&cctx->workspace, sizeof(ZSTD_compressedBlockState_t));
- cctx->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object(&cctx->workspace, HUF_WORKSPACE_SIZE);
- cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
- return cctx;
-}
-
-/**
- * Clears and frees all of the dictionaries in the CCtx.
- */
-static void ZSTD_clearAllDicts(ZSTD_CCtx* cctx)
-{
- ZSTD_free(cctx->localDict.dictBuffer, cctx->customMem);
- ZSTD_freeCDict(cctx->localDict.cdict);
- memset(&cctx->localDict, 0, sizeof(cctx->localDict));
- memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict));
- cctx->cdict = NULL;
-}
-
-static size_t ZSTD_sizeof_localDict(ZSTD_localDict dict)
-{
- size_t const bufferSize = dict.dictBuffer != NULL ? dict.dictSize : 0;
- size_t const cdictSize = ZSTD_sizeof_CDict(dict.cdict);
- return bufferSize + cdictSize;
-}
-
-static void ZSTD_freeCCtxContent(ZSTD_CCtx* cctx)
-{
- assert(cctx != NULL);
- assert(cctx->staticSize == 0);
- ZSTD_clearAllDicts(cctx);
-#ifdef ZSTD_MULTITHREAD
- ZSTDMT_freeCCtx(cctx->mtctx); cctx->mtctx = NULL;
-#endif
- ZSTD_cwksp_free(&cctx->workspace, cctx->customMem);
-}
-
-size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
-{
- if (cctx==NULL) return 0; /* support free on NULL */
- RETURN_ERROR_IF(cctx->staticSize, memory_allocation,
- "not compatible with static CCtx");
- {
- int cctxInWorkspace = ZSTD_cwksp_owns_buffer(&cctx->workspace, cctx);
- ZSTD_freeCCtxContent(cctx);
- if (!cctxInWorkspace) {
- ZSTD_free(cctx, cctx->customMem);
- }
- }
- return 0;
-}
-
-
-static size_t ZSTD_sizeof_mtctx(const ZSTD_CCtx* cctx)
-{
-#ifdef ZSTD_MULTITHREAD
- return ZSTDMT_sizeof_CCtx(cctx->mtctx);
-#else
- (void)cctx;
- return 0;
-#endif
-}
-
-
-size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)
-{
- if (cctx==NULL) return 0; /* support sizeof on NULL */
- /* cctx may be in the workspace */
- return (cctx->workspace.workspace == cctx ? 0 : sizeof(*cctx))
- + ZSTD_cwksp_sizeof(&cctx->workspace)
- + ZSTD_sizeof_localDict(cctx->localDict)
- + ZSTD_sizeof_mtctx(cctx);
-}
-
-size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
-{
- return ZSTD_sizeof_CCtx(zcs); /* same object */
-}
-
-/* private API call, for dictBuilder only */
-const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); }
-
-static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams(
- ZSTD_compressionParameters cParams)
-{
- ZSTD_CCtx_params cctxParams;
- memset(&cctxParams, 0, sizeof(cctxParams));
- cctxParams.cParams = cParams;
- cctxParams.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */
- assert(!ZSTD_checkCParams(cParams));
- cctxParams.fParams.contentSizeFlag = 1;
- return cctxParams;
-}
-
-static ZSTD_CCtx_params* ZSTD_createCCtxParams_advanced(
- ZSTD_customMem customMem)
-{
- ZSTD_CCtx_params* params;
- if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
- params = (ZSTD_CCtx_params*)ZSTD_calloc(
- sizeof(ZSTD_CCtx_params), customMem);
- if (!params) { return NULL; }
- params->customMem = customMem;
- params->compressionLevel = ZSTD_CLEVEL_DEFAULT;
- params->fParams.contentSizeFlag = 1;
- return params;
-}
-
-ZSTD_CCtx_params* ZSTD_createCCtxParams(void)
-{
- return ZSTD_createCCtxParams_advanced(ZSTD_defaultCMem);
-}
-
-size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params)
-{
- if (params == NULL) { return 0; }
- ZSTD_free(params, params->customMem);
- return 0;
-}
-
-size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params)
-{
- return ZSTD_CCtxParams_init(params, ZSTD_CLEVEL_DEFAULT);
-}
-
-size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel) {
- RETURN_ERROR_IF(!cctxParams, GENERIC, "NULL pointer!");
- memset(cctxParams, 0, sizeof(*cctxParams));
- cctxParams->compressionLevel = compressionLevel;
- cctxParams->fParams.contentSizeFlag = 1;
- return 0;
-}
-
-size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params)
-{
- RETURN_ERROR_IF(!cctxParams, GENERIC, "NULL pointer!");
- FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) , "");
- memset(cctxParams, 0, sizeof(*cctxParams));
- assert(!ZSTD_checkCParams(params.cParams));
- cctxParams->cParams = params.cParams;
- cctxParams->fParams = params.fParams;
- cctxParams->compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */
- return 0;
-}
-
-/* ZSTD_assignParamsToCCtxParams() :
- * params is presumed valid at this stage */
-static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams(
- const ZSTD_CCtx_params* cctxParams, const ZSTD_parameters* params)
-{
- ZSTD_CCtx_params ret = *cctxParams;
- assert(!ZSTD_checkCParams(params->cParams));
- ret.cParams = params->cParams;
- ret.fParams = params->fParams;
- ret.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */
- return ret;
-}
-
-ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param)
-{
- ZSTD_bounds bounds = { 0, 0, 0 };
-
- switch(param)
- {
- case ZSTD_c_compressionLevel:
- bounds.lowerBound = ZSTD_minCLevel();
- bounds.upperBound = ZSTD_maxCLevel();
- return bounds;
-
- case ZSTD_c_windowLog:
- bounds.lowerBound = ZSTD_WINDOWLOG_MIN;
- bounds.upperBound = ZSTD_WINDOWLOG_MAX;
- return bounds;
-
- case ZSTD_c_hashLog:
- bounds.lowerBound = ZSTD_HASHLOG_MIN;
- bounds.upperBound = ZSTD_HASHLOG_MAX;
- return bounds;
-
- case ZSTD_c_chainLog:
- bounds.lowerBound = ZSTD_CHAINLOG_MIN;
- bounds.upperBound = ZSTD_CHAINLOG_MAX;
- return bounds;
-
- case ZSTD_c_searchLog:
- bounds.lowerBound = ZSTD_SEARCHLOG_MIN;
- bounds.upperBound = ZSTD_SEARCHLOG_MAX;
- return bounds;
-
- case ZSTD_c_minMatch:
- bounds.lowerBound = ZSTD_MINMATCH_MIN;
- bounds.upperBound = ZSTD_MINMATCH_MAX;
- return bounds;
-
- case ZSTD_c_targetLength:
- bounds.lowerBound = ZSTD_TARGETLENGTH_MIN;
- bounds.upperBound = ZSTD_TARGETLENGTH_MAX;
- return bounds;
-
- case ZSTD_c_strategy:
- bounds.lowerBound = ZSTD_STRATEGY_MIN;
- bounds.upperBound = ZSTD_STRATEGY_MAX;
- return bounds;
-
- case ZSTD_c_contentSizeFlag:
- bounds.lowerBound = 0;
- bounds.upperBound = 1;
- return bounds;
-
- case ZSTD_c_checksumFlag:
- bounds.lowerBound = 0;
- bounds.upperBound = 1;
- return bounds;
-
- case ZSTD_c_dictIDFlag:
- bounds.lowerBound = 0;
- bounds.upperBound = 1;
- return bounds;
-
- case ZSTD_c_nbWorkers:
- bounds.lowerBound = 0;
-#ifdef ZSTD_MULTITHREAD
- bounds.upperBound = ZSTDMT_NBWORKERS_MAX;
-#else
- bounds.upperBound = 0;
-#endif
- return bounds;
-
- case ZSTD_c_jobSize:
- bounds.lowerBound = 0;
-#ifdef ZSTD_MULTITHREAD
- bounds.upperBound = ZSTDMT_JOBSIZE_MAX;
-#else
- bounds.upperBound = 0;
-#endif
- return bounds;
-
- case ZSTD_c_overlapLog:
-#ifdef ZSTD_MULTITHREAD
- bounds.lowerBound = ZSTD_OVERLAPLOG_MIN;
- bounds.upperBound = ZSTD_OVERLAPLOG_MAX;
-#else
- bounds.lowerBound = 0;
- bounds.upperBound = 0;
-#endif
- return bounds;
-
- case ZSTD_c_enableLongDistanceMatching:
- bounds.lowerBound = 0;
- bounds.upperBound = 1;
- return bounds;
-
- case ZSTD_c_ldmHashLog:
- bounds.lowerBound = ZSTD_LDM_HASHLOG_MIN;
- bounds.upperBound = ZSTD_LDM_HASHLOG_MAX;
- return bounds;
-
- case ZSTD_c_ldmMinMatch:
- bounds.lowerBound = ZSTD_LDM_MINMATCH_MIN;
- bounds.upperBound = ZSTD_LDM_MINMATCH_MAX;
- return bounds;
-
- case ZSTD_c_ldmBucketSizeLog:
- bounds.lowerBound = ZSTD_LDM_BUCKETSIZELOG_MIN;
- bounds.upperBound = ZSTD_LDM_BUCKETSIZELOG_MAX;
- return bounds;
-
- case ZSTD_c_ldmHashRateLog:
- bounds.lowerBound = ZSTD_LDM_HASHRATELOG_MIN;
- bounds.upperBound = ZSTD_LDM_HASHRATELOG_MAX;
- return bounds;
-
- /* experimental parameters */
- case ZSTD_c_rsyncable:
- bounds.lowerBound = 0;
- bounds.upperBound = 1;
- return bounds;
-
- case ZSTD_c_forceMaxWindow :
- bounds.lowerBound = 0;
- bounds.upperBound = 1;
- return bounds;
-
- case ZSTD_c_format:
- ZSTD_STATIC_ASSERT(ZSTD_f_zstd1 < ZSTD_f_zstd1_magicless);
- bounds.lowerBound = ZSTD_f_zstd1;
- bounds.upperBound = ZSTD_f_zstd1_magicless; /* note : how to ensure at compile time that this is the highest value enum ? */
- return bounds;
-
- case ZSTD_c_forceAttachDict:
- ZSTD_STATIC_ASSERT(ZSTD_dictDefaultAttach < ZSTD_dictForceCopy);
- bounds.lowerBound = ZSTD_dictDefaultAttach;
- bounds.upperBound = ZSTD_dictForceLoad; /* note : how to ensure at compile time that this is the highest value enum ? */
- return bounds;
-
- case ZSTD_c_literalCompressionMode:
- ZSTD_STATIC_ASSERT(ZSTD_lcm_auto < ZSTD_lcm_huffman && ZSTD_lcm_huffman < ZSTD_lcm_uncompressed);
- bounds.lowerBound = ZSTD_lcm_auto;
- bounds.upperBound = ZSTD_lcm_uncompressed;
- return bounds;
-
- case ZSTD_c_targetCBlockSize:
- bounds.lowerBound = ZSTD_TARGETCBLOCKSIZE_MIN;
- bounds.upperBound = ZSTD_TARGETCBLOCKSIZE_MAX;
- return bounds;
-
- case ZSTD_c_srcSizeHint:
- bounds.lowerBound = ZSTD_SRCSIZEHINT_MIN;
- bounds.upperBound = ZSTD_SRCSIZEHINT_MAX;
- return bounds;
-
- default:
- bounds.error = ERROR(parameter_unsupported);
- return bounds;
- }
-}
-
-/* ZSTD_cParam_clampBounds:
- * Clamps the value into the bounded range.
- */
-static size_t ZSTD_cParam_clampBounds(ZSTD_cParameter cParam, int* value)
-{
- ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam);
- if (ZSTD_isError(bounds.error)) return bounds.error;
- if (*value < bounds.lowerBound) *value = bounds.lowerBound;
- if (*value > bounds.upperBound) *value = bounds.upperBound;
- return 0;
-}
-
-#define BOUNDCHECK(cParam, val) { \
- RETURN_ERROR_IF(!ZSTD_cParam_withinBounds(cParam,val), \
- parameter_outOfBound, "Param out of bounds"); \
-}
-
-
-static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param)
-{
- switch(param)
- {
- case ZSTD_c_compressionLevel:
- case ZSTD_c_hashLog:
- case ZSTD_c_chainLog:
- case ZSTD_c_searchLog:
- case ZSTD_c_minMatch:
- case ZSTD_c_targetLength:
- case ZSTD_c_strategy:
- return 1;
-
- case ZSTD_c_format:
- case ZSTD_c_windowLog:
- case ZSTD_c_contentSizeFlag:
- case ZSTD_c_checksumFlag:
- case ZSTD_c_dictIDFlag:
- case ZSTD_c_forceMaxWindow :
- case ZSTD_c_nbWorkers:
- case ZSTD_c_jobSize:
- case ZSTD_c_overlapLog:
- case ZSTD_c_rsyncable:
- case ZSTD_c_enableLongDistanceMatching:
- case ZSTD_c_ldmHashLog:
- case ZSTD_c_ldmMinMatch:
- case ZSTD_c_ldmBucketSizeLog:
- case ZSTD_c_ldmHashRateLog:
- case ZSTD_c_forceAttachDict:
- case ZSTD_c_literalCompressionMode:
- case ZSTD_c_targetCBlockSize:
- case ZSTD_c_srcSizeHint:
- default:
- return 0;
- }
-}
-
-size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value)
-{
- DEBUGLOG(4, "ZSTD_CCtx_setParameter (%i, %i)", (int)param, value);
- if (cctx->streamStage != zcss_init) {
- if (ZSTD_isUpdateAuthorized(param)) {
- cctx->cParamsChanged = 1;
- } else {
- RETURN_ERROR(stage_wrong, "can only set params in ctx init stage");
- } }
-
- switch(param)
- {
- case ZSTD_c_nbWorkers:
- RETURN_ERROR_IF((value!=0) && cctx->staticSize, parameter_unsupported,
- "MT not compatible with static alloc");
- break;
-
- case ZSTD_c_compressionLevel:
- case ZSTD_c_windowLog:
- case ZSTD_c_hashLog:
- case ZSTD_c_chainLog:
- case ZSTD_c_searchLog:
- case ZSTD_c_minMatch:
- case ZSTD_c_targetLength:
- case ZSTD_c_strategy:
- case ZSTD_c_ldmHashRateLog:
- case ZSTD_c_format:
- case ZSTD_c_contentSizeFlag:
- case ZSTD_c_checksumFlag:
- case ZSTD_c_dictIDFlag:
- case ZSTD_c_forceMaxWindow:
- case ZSTD_c_forceAttachDict:
- case ZSTD_c_literalCompressionMode:
- case ZSTD_c_jobSize:
- case ZSTD_c_overlapLog:
- case ZSTD_c_rsyncable:
- case ZSTD_c_enableLongDistanceMatching:
- case ZSTD_c_ldmHashLog:
- case ZSTD_c_ldmMinMatch:
- case ZSTD_c_ldmBucketSizeLog:
- case ZSTD_c_targetCBlockSize:
- case ZSTD_c_srcSizeHint:
- break;
-
- default: RETURN_ERROR(parameter_unsupported, "unknown parameter");
- }
- return ZSTD_CCtxParams_setParameter(&cctx->requestedParams, param, value);
-}
-
-size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams,
- ZSTD_cParameter param, int value)
-{
- DEBUGLOG(4, "ZSTD_CCtxParams_setParameter (%i, %i)", (int)param, value);
- switch(param)
- {
- case ZSTD_c_format :
- BOUNDCHECK(ZSTD_c_format, value);
- CCtxParams->format = (ZSTD_format_e)value;
- return (size_t)CCtxParams->format;
-
- case ZSTD_c_compressionLevel : {
- FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value), "");
- if (value) { /* 0 : does not change current level */
- CCtxParams->compressionLevel = value;
- }
- if (CCtxParams->compressionLevel >= 0) return (size_t)CCtxParams->compressionLevel;
- return 0; /* return type (size_t) cannot represent negative values */
- }
-
- case ZSTD_c_windowLog :
- if (value!=0) /* 0 => use default */
- BOUNDCHECK(ZSTD_c_windowLog, value);
- CCtxParams->cParams.windowLog = (U32)value;
- return CCtxParams->cParams.windowLog;
-
- case ZSTD_c_hashLog :
- if (value!=0) /* 0 => use default */
- BOUNDCHECK(ZSTD_c_hashLog, value);
- CCtxParams->cParams.hashLog = (U32)value;
- return CCtxParams->cParams.hashLog;
-
- case ZSTD_c_chainLog :
- if (value!=0) /* 0 => use default */
- BOUNDCHECK(ZSTD_c_chainLog, value);
- CCtxParams->cParams.chainLog = (U32)value;
- return CCtxParams->cParams.chainLog;
-
- case ZSTD_c_searchLog :
- if (value!=0) /* 0 => use default */
- BOUNDCHECK(ZSTD_c_searchLog, value);
- CCtxParams->cParams.searchLog = (U32)value;
- return (size_t)value;
-
- case ZSTD_c_minMatch :
- if (value!=0) /* 0 => use default */
- BOUNDCHECK(ZSTD_c_minMatch, value);
- CCtxParams->cParams.minMatch = value;
- return CCtxParams->cParams.minMatch;
-
- case ZSTD_c_targetLength :
- BOUNDCHECK(ZSTD_c_targetLength, value);
- CCtxParams->cParams.targetLength = value;
- return CCtxParams->cParams.targetLength;
-
- case ZSTD_c_strategy :
- if (value!=0) /* 0 => use default */
- BOUNDCHECK(ZSTD_c_strategy, value);
- CCtxParams->cParams.strategy = (ZSTD_strategy)value;
- return (size_t)CCtxParams->cParams.strategy;
-
- case ZSTD_c_contentSizeFlag :
- /* Content size written in frame header _when known_ (default:1) */
- DEBUGLOG(4, "set content size flag = %u", (value!=0));
- CCtxParams->fParams.contentSizeFlag = value != 0;
- return CCtxParams->fParams.contentSizeFlag;
-
- case ZSTD_c_checksumFlag :
- /* A 32-bits content checksum will be calculated and written at end of frame (default:0) */
- CCtxParams->fParams.checksumFlag = value != 0;
- return CCtxParams->fParams.checksumFlag;
-
- case ZSTD_c_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */
- DEBUGLOG(4, "set dictIDFlag = %u", (value!=0));
- CCtxParams->fParams.noDictIDFlag = !value;
- return !CCtxParams->fParams.noDictIDFlag;
-
- case ZSTD_c_forceMaxWindow :
- CCtxParams->forceWindow = (value != 0);
- return CCtxParams->forceWindow;
-
- case ZSTD_c_forceAttachDict : {
- const ZSTD_dictAttachPref_e pref = (ZSTD_dictAttachPref_e)value;
- BOUNDCHECK(ZSTD_c_forceAttachDict, pref);
- CCtxParams->attachDictPref = pref;
- return CCtxParams->attachDictPref;
- }
-
- case ZSTD_c_literalCompressionMode : {
- const ZSTD_literalCompressionMode_e lcm = (ZSTD_literalCompressionMode_e)value;
- BOUNDCHECK(ZSTD_c_literalCompressionMode, lcm);
- CCtxParams->literalCompressionMode = lcm;
- return CCtxParams->literalCompressionMode;
- }
-
- case ZSTD_c_nbWorkers :
-#ifndef ZSTD_MULTITHREAD
- RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading");
- return 0;
-#else
- FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value), "");
- CCtxParams->nbWorkers = value;
- return CCtxParams->nbWorkers;
-#endif
-
- case ZSTD_c_jobSize :
-#ifndef ZSTD_MULTITHREAD
- RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading");
- return 0;
-#else
- /* Adjust to the minimum non-default value. */
- if (value != 0 && value < ZSTDMT_JOBSIZE_MIN)
- value = ZSTDMT_JOBSIZE_MIN;
- FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value), "");
- assert(value >= 0);
- CCtxParams->jobSize = value;
- return CCtxParams->jobSize;
-#endif
-
- case ZSTD_c_overlapLog :
-#ifndef ZSTD_MULTITHREAD
- RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading");
- return 0;
-#else
- FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(ZSTD_c_overlapLog, &value), "");
- CCtxParams->overlapLog = value;
- return CCtxParams->overlapLog;
-#endif
-
- case ZSTD_c_rsyncable :
-#ifndef ZSTD_MULTITHREAD
- RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading");
- return 0;
-#else
- FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(ZSTD_c_overlapLog, &value), "");
- CCtxParams->rsyncable = value;
- return CCtxParams->rsyncable;
-#endif
-
- case ZSTD_c_enableLongDistanceMatching :
- CCtxParams->ldmParams.enableLdm = (value!=0);
- return CCtxParams->ldmParams.enableLdm;
-
- case ZSTD_c_ldmHashLog :
- if (value!=0) /* 0 ==> auto */
- BOUNDCHECK(ZSTD_c_ldmHashLog, value);
- CCtxParams->ldmParams.hashLog = value;
- return CCtxParams->ldmParams.hashLog;
-
- case ZSTD_c_ldmMinMatch :
- if (value!=0) /* 0 ==> default */
- BOUNDCHECK(ZSTD_c_ldmMinMatch, value);
- CCtxParams->ldmParams.minMatchLength = value;
- return CCtxParams->ldmParams.minMatchLength;
-
- case ZSTD_c_ldmBucketSizeLog :
- if (value!=0) /* 0 ==> default */
- BOUNDCHECK(ZSTD_c_ldmBucketSizeLog, value);
- CCtxParams->ldmParams.bucketSizeLog = value;
- return CCtxParams->ldmParams.bucketSizeLog;
-
- case ZSTD_c_ldmHashRateLog :
- RETURN_ERROR_IF(value > ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN,
- parameter_outOfBound, "Param out of bounds!");
- CCtxParams->ldmParams.hashRateLog = value;
- return CCtxParams->ldmParams.hashRateLog;
-
- case ZSTD_c_targetCBlockSize :
- if (value!=0) /* 0 ==> default */
- BOUNDCHECK(ZSTD_c_targetCBlockSize, value);
- CCtxParams->targetCBlockSize = value;
- return CCtxParams->targetCBlockSize;
-
- case ZSTD_c_srcSizeHint :
- if (value!=0) /* 0 ==> default */
- BOUNDCHECK(ZSTD_c_srcSizeHint, value);
- CCtxParams->srcSizeHint = value;
- return CCtxParams->srcSizeHint;
-
- default: RETURN_ERROR(parameter_unsupported, "unknown parameter");
- }
-}
-
-size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value)
-{
- return ZSTD_CCtxParams_getParameter(&cctx->requestedParams, param, value);
-}
-
-size_t ZSTD_CCtxParams_getParameter(
- ZSTD_CCtx_params* CCtxParams, ZSTD_cParameter param, int* value)
-{
- switch(param)
- {
- case ZSTD_c_format :
- *value = CCtxParams->format;
- break;
- case ZSTD_c_compressionLevel :
- *value = CCtxParams->compressionLevel;
- break;
- case ZSTD_c_windowLog :
- *value = (int)CCtxParams->cParams.windowLog;
- break;
- case ZSTD_c_hashLog :
- *value = (int)CCtxParams->cParams.hashLog;
- break;
- case ZSTD_c_chainLog :
- *value = (int)CCtxParams->cParams.chainLog;
- break;
- case ZSTD_c_searchLog :
- *value = CCtxParams->cParams.searchLog;
- break;
- case ZSTD_c_minMatch :
- *value = CCtxParams->cParams.minMatch;
- break;
- case ZSTD_c_targetLength :
- *value = CCtxParams->cParams.targetLength;
- break;
- case ZSTD_c_strategy :
- *value = (unsigned)CCtxParams->cParams.strategy;
- break;
- case ZSTD_c_contentSizeFlag :
- *value = CCtxParams->fParams.contentSizeFlag;
- break;
- case ZSTD_c_checksumFlag :
- *value = CCtxParams->fParams.checksumFlag;
- break;
- case ZSTD_c_dictIDFlag :
- *value = !CCtxParams->fParams.noDictIDFlag;
- break;
- case ZSTD_c_forceMaxWindow :
- *value = CCtxParams->forceWindow;
- break;
- case ZSTD_c_forceAttachDict :
- *value = CCtxParams->attachDictPref;
- break;
- case ZSTD_c_literalCompressionMode :
- *value = CCtxParams->literalCompressionMode;
- break;
- case ZSTD_c_nbWorkers :
-#ifndef ZSTD_MULTITHREAD
- assert(CCtxParams->nbWorkers == 0);
-#endif
- *value = CCtxParams->nbWorkers;
- break;
- case ZSTD_c_jobSize :
-#ifndef ZSTD_MULTITHREAD
- RETURN_ERROR(parameter_unsupported, "not compiled with multithreading");
-#else
- assert(CCtxParams->jobSize <= INT_MAX);
- *value = (int)CCtxParams->jobSize;
- break;
-#endif
- case ZSTD_c_overlapLog :
-#ifndef ZSTD_MULTITHREAD
- RETURN_ERROR(parameter_unsupported, "not compiled with multithreading");
-#else
- *value = CCtxParams->overlapLog;
- break;
-#endif
- case ZSTD_c_rsyncable :
-#ifndef ZSTD_MULTITHREAD
- RETURN_ERROR(parameter_unsupported, "not compiled with multithreading");
-#else
- *value = CCtxParams->rsyncable;
- break;
-#endif
- case ZSTD_c_enableLongDistanceMatching :
- *value = CCtxParams->ldmParams.enableLdm;
- break;
- case ZSTD_c_ldmHashLog :
- *value = CCtxParams->ldmParams.hashLog;
- break;
- case ZSTD_c_ldmMinMatch :
- *value = CCtxParams->ldmParams.minMatchLength;
- break;
- case ZSTD_c_ldmBucketSizeLog :
- *value = CCtxParams->ldmParams.bucketSizeLog;
- break;
- case ZSTD_c_ldmHashRateLog :
- *value = CCtxParams->ldmParams.hashRateLog;
- break;
- case ZSTD_c_targetCBlockSize :
- *value = (int)CCtxParams->targetCBlockSize;
- break;
- case ZSTD_c_srcSizeHint :
- *value = (int)CCtxParams->srcSizeHint;
- break;
- default: RETURN_ERROR(parameter_unsupported, "unknown parameter");
- }
- return 0;
-}
-
-/** ZSTD_CCtx_setParametersUsingCCtxParams() :
- * just applies `params` into `cctx`
- * no action is performed, parameters are merely stored.
- * If ZSTDMT is enabled, parameters are pushed to cctx->mtctx.
- * This is possible even if a compression is ongoing.
- * In which case, new parameters will be applied on the fly, starting with next compression job.
- */
-size_t ZSTD_CCtx_setParametersUsingCCtxParams(
- ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params)
-{
- DEBUGLOG(4, "ZSTD_CCtx_setParametersUsingCCtxParams");
- RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
- "The context is in the wrong stage!");
- RETURN_ERROR_IF(cctx->cdict, stage_wrong,
- "Can't override parameters with cdict attached (some must "
- "be inherited from the cdict).");
-
- cctx->requestedParams = *params;
- return 0;
-}
-
-ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize)
-{
- DEBUGLOG(4, "ZSTD_CCtx_setPledgedSrcSize to %u bytes", (U32)pledgedSrcSize);
- RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
- "Can't set pledgedSrcSize when not in init stage.");
- cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1;
- return 0;
-}
-
-/**
- * Initializes the local dict using the requested parameters.
- * NOTE: This does not use the pledged src size, because it may be used for more
- * than one compression.
- */
-static size_t ZSTD_initLocalDict(ZSTD_CCtx* cctx)
-{
- ZSTD_localDict* const dl = &cctx->localDict;
- ZSTD_compressionParameters const cParams = ZSTD_getCParamsFromCCtxParams(
- &cctx->requestedParams, ZSTD_CONTENTSIZE_UNKNOWN, dl->dictSize);
- if (dl->dict == NULL) {
- /* No local dictionary. */
- assert(dl->dictBuffer == NULL);
- assert(dl->cdict == NULL);
- assert(dl->dictSize == 0);
- return 0;
- }
- if (dl->cdict != NULL) {
- assert(cctx->cdict == dl->cdict);
- /* Local dictionary already initialized. */
- return 0;
- }
- assert(dl->dictSize > 0);
- assert(cctx->cdict == NULL);
- assert(cctx->prefixDict.dict == NULL);
-
- dl->cdict = ZSTD_createCDict_advanced(
- dl->dict,
- dl->dictSize,
- ZSTD_dlm_byRef,
- dl->dictContentType,
- cParams,
- cctx->customMem);
- RETURN_ERROR_IF(!dl->cdict, memory_allocation, "ZSTD_createCDict_advanced failed");
- cctx->cdict = dl->cdict;
- return 0;
-}
-
-size_t ZSTD_CCtx_loadDictionary_advanced(
- ZSTD_CCtx* cctx, const void* dict, size_t dictSize,
- ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType)
-{
- RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
- "Can't load a dictionary when ctx is not in init stage.");
- RETURN_ERROR_IF(cctx->staticSize, memory_allocation,
- "no malloc for static CCtx");
- DEBUGLOG(4, "ZSTD_CCtx_loadDictionary_advanced (size: %u)", (U32)dictSize);
- ZSTD_clearAllDicts(cctx); /* in case one already exists */
- if (dict == NULL || dictSize == 0) /* no dictionary mode */
- return 0;
- if (dictLoadMethod == ZSTD_dlm_byRef) {
- cctx->localDict.dict = dict;
- } else {
- void* dictBuffer = ZSTD_malloc(dictSize, cctx->customMem);
- RETURN_ERROR_IF(!dictBuffer, memory_allocation, "NULL pointer!");
- memcpy(dictBuffer, dict, dictSize);
- cctx->localDict.dictBuffer = dictBuffer;
- cctx->localDict.dict = dictBuffer;
- }
- cctx->localDict.dictSize = dictSize;
- cctx->localDict.dictContentType = dictContentType;
- return 0;
-}
-
-ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference(
- ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
-{
- return ZSTD_CCtx_loadDictionary_advanced(
- cctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto);
-}
-
-ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
-{
- return ZSTD_CCtx_loadDictionary_advanced(
- cctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto);
-}
-
-
-size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
-{
- RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
- "Can't ref a dict when ctx not in init stage.");
- /* Free the existing local cdict (if any) to save memory. */
- ZSTD_clearAllDicts(cctx);
- cctx->cdict = cdict;
- return 0;
-}
-
-size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize)
-{
- return ZSTD_CCtx_refPrefix_advanced(cctx, prefix, prefixSize, ZSTD_dct_rawContent);
-}
-
-size_t ZSTD_CCtx_refPrefix_advanced(
- ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType)
-{
- RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
- "Can't ref a prefix when ctx not in init stage.");
- ZSTD_clearAllDicts(cctx);
- if (prefix != NULL && prefixSize > 0) {
- cctx->prefixDict.dict = prefix;
- cctx->prefixDict.dictSize = prefixSize;
- cctx->prefixDict.dictContentType = dictContentType;
- }
- return 0;
-}
-
-/*! ZSTD_CCtx_reset() :
- * Also dumps dictionary */
-size_t ZSTD_CCtx_reset(ZSTD_CCtx* cctx, ZSTD_ResetDirective reset)
-{
- if ( (reset == ZSTD_reset_session_only)
- || (reset == ZSTD_reset_session_and_parameters) ) {
- cctx->streamStage = zcss_init;
- cctx->pledgedSrcSizePlusOne = 0;
- }
- if ( (reset == ZSTD_reset_parameters)
- || (reset == ZSTD_reset_session_and_parameters) ) {
- RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
- "Can't reset parameters only when not in init stage.");
- ZSTD_clearAllDicts(cctx);
- return ZSTD_CCtxParams_reset(&cctx->requestedParams);
- }
- return 0;
-}
-
-
-/** ZSTD_checkCParams() :
- control CParam values remain within authorized range.
- @return : 0, or an error code if one value is beyond authorized range */
-size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
-{
- BOUNDCHECK(ZSTD_c_windowLog, (int)cParams.windowLog);
- BOUNDCHECK(ZSTD_c_chainLog, (int)cParams.chainLog);
- BOUNDCHECK(ZSTD_c_hashLog, (int)cParams.hashLog);
- BOUNDCHECK(ZSTD_c_searchLog, (int)cParams.searchLog);
- BOUNDCHECK(ZSTD_c_minMatch, (int)cParams.minMatch);
- BOUNDCHECK(ZSTD_c_targetLength,(int)cParams.targetLength);
- BOUNDCHECK(ZSTD_c_strategy, cParams.strategy);
- return 0;
-}
-
-/** ZSTD_clampCParams() :
- * make CParam values within valid range.
- * @return : valid CParams */
-static ZSTD_compressionParameters
-ZSTD_clampCParams(ZSTD_compressionParameters cParams)
-{
-# define CLAMP_TYPE(cParam, val, type) { \
- ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam); \
- if ((int)val<bounds.lowerBound) val=(type)bounds.lowerBound; \
- else if ((int)val>bounds.upperBound) val=(type)bounds.upperBound; \
- }
-# define CLAMP(cParam, val) CLAMP_TYPE(cParam, val, unsigned)
- CLAMP(ZSTD_c_windowLog, cParams.windowLog);
- CLAMP(ZSTD_c_chainLog, cParams.chainLog);
- CLAMP(ZSTD_c_hashLog, cParams.hashLog);
- CLAMP(ZSTD_c_searchLog, cParams.searchLog);
- CLAMP(ZSTD_c_minMatch, cParams.minMatch);
- CLAMP(ZSTD_c_targetLength,cParams.targetLength);
- CLAMP_TYPE(ZSTD_c_strategy,cParams.strategy, ZSTD_strategy);
- return cParams;
-}
-
-/** ZSTD_cycleLog() :
- * condition for correct operation : hashLog > 1 */
-U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
-{
- U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2);
- return hashLog - btScale;
-}
-
-/** ZSTD_adjustCParams_internal() :
- * optimize `cPar` for a specified input (`srcSize` and `dictSize`).
- * mostly downsize to reduce memory consumption and initialization latency.
- * `srcSize` can be ZSTD_CONTENTSIZE_UNKNOWN when not known.
- * note : `srcSize==0` means 0!
- * condition : cPar is presumed validated (can be checked using ZSTD_checkCParams()). */
-static ZSTD_compressionParameters
-ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar,
- unsigned long long srcSize,
- size_t dictSize)
-{
- static const U64 minSrcSize = 513; /* (1<<9) + 1 */
- static const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1);
- assert(ZSTD_checkCParams(cPar)==0);
-
- if (dictSize && srcSize == ZSTD_CONTENTSIZE_UNKNOWN)
- srcSize = minSrcSize;
-
- /* resize windowLog if input is small enough, to use less memory */
- if ( (srcSize < maxWindowResize)
- && (dictSize < maxWindowResize) ) {
- U32 const tSize = (U32)(srcSize + dictSize);
- static U32 const hashSizeMin = 1 << ZSTD_HASHLOG_MIN;
- U32 const srcLog = (tSize < hashSizeMin) ? ZSTD_HASHLOG_MIN :
- ZSTD_highbit32(tSize-1) + 1;
- if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
- }
- if (cPar.hashLog > cPar.windowLog+1) cPar.hashLog = cPar.windowLog+1;
- { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
- if (cycleLog > cPar.windowLog)
- cPar.chainLog -= (cycleLog - cPar.windowLog);
- }
-
- if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN)
- cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* minimum wlog required for valid frame header */
-
- return cPar;
-}
-
-ZSTD_compressionParameters
-ZSTD_adjustCParams(ZSTD_compressionParameters cPar,
- unsigned long long srcSize,
- size_t dictSize)
-{
- cPar = ZSTD_clampCParams(cPar); /* resulting cPar is necessarily valid (all parameters within range) */
- if (srcSize == 0) srcSize = ZSTD_CONTENTSIZE_UNKNOWN;
- return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize);
-}
-
-static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize);
-static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize);
-
-ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams(
- const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize)
-{
- ZSTD_compressionParameters cParams;
- if (srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN && CCtxParams->srcSizeHint > 0) {
- srcSizeHint = CCtxParams->srcSizeHint;
- }
- cParams = ZSTD_getCParams_internal(CCtxParams->compressionLevel, srcSizeHint, dictSize);
- if (CCtxParams->ldmParams.enableLdm) cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG;
- if (CCtxParams->cParams.windowLog) cParams.windowLog = CCtxParams->cParams.windowLog;
- if (CCtxParams->cParams.hashLog) cParams.hashLog = CCtxParams->cParams.hashLog;
- if (CCtxParams->cParams.chainLog) cParams.chainLog = CCtxParams->cParams.chainLog;
- if (CCtxParams->cParams.searchLog) cParams.searchLog = CCtxParams->cParams.searchLog;
- if (CCtxParams->cParams.minMatch) cParams.minMatch = CCtxParams->cParams.minMatch;
- if (CCtxParams->cParams.targetLength) cParams.targetLength = CCtxParams->cParams.targetLength;
- if (CCtxParams->cParams.strategy) cParams.strategy = CCtxParams->cParams.strategy;
- assert(!ZSTD_checkCParams(cParams));
- /* srcSizeHint == 0 means 0 */
- return ZSTD_adjustCParams_internal(cParams, srcSizeHint, dictSize);
-}
-
-static size_t
-ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams,
- const U32 forCCtx)
-{
- size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog);
- size_t const hSize = ((size_t)1) << cParams->hashLog;
- U32 const hashLog3 = (forCCtx && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0;
- size_t const h3Size = hashLog3 ? ((size_t)1) << hashLog3 : 0;
- /* We don't use ZSTD_cwksp_alloc_size() here because the tables aren't
- * surrounded by redzones in ASAN. */
- size_t const tableSpace = chainSize * sizeof(U32)
- + hSize * sizeof(U32)
- + h3Size * sizeof(U32);
- size_t const optPotentialSpace =
- ZSTD_cwksp_alloc_size((MaxML+1) * sizeof(U32))
- + ZSTD_cwksp_alloc_size((MaxLL+1) * sizeof(U32))
- + ZSTD_cwksp_alloc_size((MaxOff+1) * sizeof(U32))
- + ZSTD_cwksp_alloc_size((1<<Litbits) * sizeof(U32))
- + ZSTD_cwksp_alloc_size((ZSTD_OPT_NUM+1) * sizeof(ZSTD_match_t))
- + ZSTD_cwksp_alloc_size((ZSTD_OPT_NUM+1) * sizeof(ZSTD_optimal_t));
- size_t const optSpace = (forCCtx && (cParams->strategy >= ZSTD_btopt))
- ? optPotentialSpace
- : 0;
- DEBUGLOG(4, "chainSize: %u - hSize: %u - h3Size: %u",
- (U32)chainSize, (U32)hSize, (U32)h3Size);
- return tableSpace + optSpace;
-}
-
-size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params)
-{
- RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only.");
- { ZSTD_compressionParameters const cParams =
- ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0);
- size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
- U32 const divider = (cParams.minMatch==3) ? 3 : 4;
- size_t const maxNbSeq = blockSize / divider;
- size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize)
- + ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(seqDef))
- + 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE));
- size_t const entropySpace = ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE);
- size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t));
- size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 1);
-
- size_t const ldmSpace = ZSTD_ldm_getTableSize(params->ldmParams);
- size_t const ldmSeqSpace = ZSTD_cwksp_alloc_size(ZSTD_ldm_getMaxNbSeq(params->ldmParams, blockSize) * sizeof(rawSeq));
-
- /* estimateCCtxSize is for one-shot compression. So no buffers should
- * be needed. However, we still allocate two 0-sized buffers, which can
- * take space under ASAN. */
- size_t const bufferSpace = ZSTD_cwksp_alloc_size(0)
- + ZSTD_cwksp_alloc_size(0);
-
- size_t const cctxSpace = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx));
-
- size_t const neededSpace =
- cctxSpace +
- entropySpace +
- blockStateSpace +
- ldmSpace +
- ldmSeqSpace +
- matchStateSize +
- tokenSpace +
- bufferSpace;
-
- DEBUGLOG(5, "estimate workspace : %u", (U32)neededSpace);
- return neededSpace;
- }
-}
-
-size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams)
-{
- ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams);
- return ZSTD_estimateCCtxSize_usingCCtxParams(&params);
-}
-
-static size_t ZSTD_estimateCCtxSize_internal(int compressionLevel)
-{
- ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0);
- return ZSTD_estimateCCtxSize_usingCParams(cParams);
-}
-
-size_t ZSTD_estimateCCtxSize(int compressionLevel)
-{
- int level;
- size_t memBudget = 0;
- for (level=MIN(compressionLevel, 1); level<=compressionLevel; level++) {
- size_t const newMB = ZSTD_estimateCCtxSize_internal(level);
- if (newMB > memBudget) memBudget = newMB;
- }
- return memBudget;
-}
-
-size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params)
-{
- RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only.");
- { ZSTD_compressionParameters const cParams =
- ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0);
- size_t const CCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params);
- size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
- size_t const inBuffSize = ((size_t)1 << cParams.windowLog) + blockSize;
- size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1;
- size_t const streamingSize = ZSTD_cwksp_alloc_size(inBuffSize)
- + ZSTD_cwksp_alloc_size(outBuffSize);
-
- return CCtxSize + streamingSize;
- }
-}
-
-size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams)
-{
- ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams);
- return ZSTD_estimateCStreamSize_usingCCtxParams(&params);
-}
-
-static size_t ZSTD_estimateCStreamSize_internal(int compressionLevel)
-{
- ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0);
- return ZSTD_estimateCStreamSize_usingCParams(cParams);
-}
-
-size_t ZSTD_estimateCStreamSize(int compressionLevel)
-{
- int level;
- size_t memBudget = 0;
- for (level=MIN(compressionLevel, 1); level<=compressionLevel; level++) {
- size_t const newMB = ZSTD_estimateCStreamSize_internal(level);
- if (newMB > memBudget) memBudget = newMB;
- }
- return memBudget;
-}
-
-/* ZSTD_getFrameProgression():
- * tells how much data has been consumed (input) and produced (output) for current frame.
- * able to count progression inside worker threads (non-blocking mode).
- */
-ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx)
-{
-#ifdef ZSTD_MULTITHREAD
- if (cctx->appliedParams.nbWorkers > 0) {
- return ZSTDMT_getFrameProgression(cctx->mtctx);
- }
-#endif
- { ZSTD_frameProgression fp;
- size_t const buffered = (cctx->inBuff == NULL) ? 0 :
- cctx->inBuffPos - cctx->inToCompress;
- if (buffered) assert(cctx->inBuffPos >= cctx->inToCompress);
- assert(buffered <= ZSTD_BLOCKSIZE_MAX);
- fp.ingested = cctx->consumedSrcSize + buffered;
- fp.consumed = cctx->consumedSrcSize;
- fp.produced = cctx->producedCSize;
- fp.flushed = cctx->producedCSize; /* simplified; some data might still be left within streaming output buffer */
- fp.currentJobID = 0;
- fp.nbActiveWorkers = 0;
- return fp;
-} }
-
-/*! ZSTD_toFlushNow()
- * Only useful for multithreading scenarios currently (nbWorkers >= 1).
- */
-size_t ZSTD_toFlushNow(ZSTD_CCtx* cctx)
-{
-#ifdef ZSTD_MULTITHREAD
- if (cctx->appliedParams.nbWorkers > 0) {
- return ZSTDMT_toFlushNow(cctx->mtctx);
- }
-#endif
- (void)cctx;
- return 0; /* over-simplification; could also check if context is currently running in streaming mode, and in which case, report how many bytes are left to be flushed within output buffer */
-}
-
-static void ZSTD_assertEqualCParams(ZSTD_compressionParameters cParams1,
- ZSTD_compressionParameters cParams2)
-{
- (void)cParams1;
- (void)cParams2;
- assert(cParams1.windowLog == cParams2.windowLog);
- assert(cParams1.chainLog == cParams2.chainLog);
- assert(cParams1.hashLog == cParams2.hashLog);
- assert(cParams1.searchLog == cParams2.searchLog);
- assert(cParams1.minMatch == cParams2.minMatch);
- assert(cParams1.targetLength == cParams2.targetLength);
- assert(cParams1.strategy == cParams2.strategy);
-}
-
-void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs)
-{
- int i;
- for (i = 0; i < ZSTD_REP_NUM; ++i)
- bs->rep[i] = repStartValue[i];
- bs->entropy.huf.repeatMode = HUF_repeat_none;
- bs->entropy.fse.offcode_repeatMode = FSE_repeat_none;
- bs->entropy.fse.matchlength_repeatMode = FSE_repeat_none;
- bs->entropy.fse.litlength_repeatMode = FSE_repeat_none;
-}
-
-/*! ZSTD_invalidateMatchState()
- * Invalidate all the matches in the match finder tables.
- * Requires nextSrc and base to be set (can be NULL).
- */
-static void ZSTD_invalidateMatchState(ZSTD_matchState_t* ms)
-{
- ZSTD_window_clear(&ms->window);
-
- ms->nextToUpdate = ms->window.dictLimit;
- ms->loadedDictEnd = 0;
- ms->opt.litLengthSum = 0; /* force reset of btopt stats */
- ms->dictMatchState = NULL;
-}
-
-/**
- * Indicates whether this compression proceeds directly from user-provided
- * source buffer to user-provided destination buffer (ZSTDb_not_buffered), or
- * whether the context needs to buffer the input/output (ZSTDb_buffered).
- */
-typedef enum {
- ZSTDb_not_buffered,
- ZSTDb_buffered
-} ZSTD_buffered_policy_e;
-
-/**
- * Controls, for this matchState reset, whether the tables need to be cleared /
- * prepared for the coming compression (ZSTDcrp_makeClean), or whether the
- * tables can be left unclean (ZSTDcrp_leaveDirty), because we know that a
- * subsequent operation will overwrite the table space anyways (e.g., copying
- * the matchState contents in from a CDict).
- */
-typedef enum {
- ZSTDcrp_makeClean,
- ZSTDcrp_leaveDirty
-} ZSTD_compResetPolicy_e;
-
-/**
- * Controls, for this matchState reset, whether indexing can continue where it
- * left off (ZSTDirp_continue), or whether it needs to be restarted from zero
- * (ZSTDirp_reset).
- */
-typedef enum {
- ZSTDirp_continue,
- ZSTDirp_reset
-} ZSTD_indexResetPolicy_e;
-
-typedef enum {
- ZSTD_resetTarget_CDict,
- ZSTD_resetTarget_CCtx
-} ZSTD_resetTarget_e;
-
-static size_t
-ZSTD_reset_matchState(ZSTD_matchState_t* ms,
- ZSTD_cwksp* ws,
- const ZSTD_compressionParameters* cParams,
- const ZSTD_compResetPolicy_e crp,
- const ZSTD_indexResetPolicy_e forceResetIndex,
- const ZSTD_resetTarget_e forWho)
-{
- size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog);
- size_t const hSize = ((size_t)1) << cParams->hashLog;
- U32 const hashLog3 = ((forWho == ZSTD_resetTarget_CCtx) && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0;
- size_t const h3Size = hashLog3 ? ((size_t)1) << hashLog3 : 0;
-
- DEBUGLOG(4, "reset indices : %u", forceResetIndex == ZSTDirp_reset);
- if (forceResetIndex == ZSTDirp_reset) {
- ZSTD_window_init(&ms->window);
- ZSTD_cwksp_mark_tables_dirty(ws);
- }
-
- ms->hashLog3 = hashLog3;
-
- ZSTD_invalidateMatchState(ms);
-
- assert(!ZSTD_cwksp_reserve_failed(ws)); /* check that allocation hasn't already failed */
-
- ZSTD_cwksp_clear_tables(ws);
-
- DEBUGLOG(5, "reserving table space");
- /* table Space */
- ms->hashTable = (U32*)ZSTD_cwksp_reserve_table(ws, hSize * sizeof(U32));
- ms->chainTable = (U32*)ZSTD_cwksp_reserve_table(ws, chainSize * sizeof(U32));
- ms->hashTable3 = (U32*)ZSTD_cwksp_reserve_table(ws, h3Size * sizeof(U32));
- RETURN_ERROR_IF(ZSTD_cwksp_reserve_failed(ws), memory_allocation,
- "failed a workspace allocation in ZSTD_reset_matchState");
-
- DEBUGLOG(4, "reset table : %u", crp!=ZSTDcrp_leaveDirty);
- if (crp!=ZSTDcrp_leaveDirty) {
- /* reset tables only */
- ZSTD_cwksp_clean_tables(ws);
- }
-
- /* opt parser space */
- if ((forWho == ZSTD_resetTarget_CCtx) && (cParams->strategy >= ZSTD_btopt)) {
- DEBUGLOG(4, "reserving optimal parser space");
- ms->opt.litFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (1<<Litbits) * sizeof(unsigned));
- ms->opt.litLengthFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (MaxLL+1) * sizeof(unsigned));
- ms->opt.matchLengthFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (MaxML+1) * sizeof(unsigned));
- ms->opt.offCodeFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (MaxOff+1) * sizeof(unsigned));
- ms->opt.matchTable = (ZSTD_match_t*)ZSTD_cwksp_reserve_aligned(ws, (ZSTD_OPT_NUM+1) * sizeof(ZSTD_match_t));
- ms->opt.priceTable = (ZSTD_optimal_t*)ZSTD_cwksp_reserve_aligned(ws, (ZSTD_OPT_NUM+1) * sizeof(ZSTD_optimal_t));
- }
-
- ms->cParams = *cParams;
-
- RETURN_ERROR_IF(ZSTD_cwksp_reserve_failed(ws), memory_allocation,
- "failed a workspace allocation in ZSTD_reset_matchState");
-
- return 0;
-}
-
-/* ZSTD_indexTooCloseToMax() :
- * minor optimization : prefer memset() rather than reduceIndex()
- * which is measurably slow in some circumstances (reported for Visual Studio).
- * Works when re-using a context for a lot of smallish inputs :
- * if all inputs are smaller than ZSTD_INDEXOVERFLOW_MARGIN,
- * memset() will be triggered before reduceIndex().
- */
-#define ZSTD_INDEXOVERFLOW_MARGIN (16 MB)
-static int ZSTD_indexTooCloseToMax(ZSTD_window_t w)
-{
- return (size_t)(w.nextSrc - w.base) > (ZSTD_CURRENT_MAX - ZSTD_INDEXOVERFLOW_MARGIN);
-}
-
-/*! ZSTD_resetCCtx_internal() :
- note : `params` are assumed fully validated at this stage */
-static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
- ZSTD_CCtx_params params,
- U64 const pledgedSrcSize,
- ZSTD_compResetPolicy_e const crp,
- ZSTD_buffered_policy_e const zbuff)
-{
- ZSTD_cwksp* const ws = &zc->workspace;
- DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u",
- (U32)pledgedSrcSize, params.cParams.windowLog);
- assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
-
- zc->isFirstBlock = 1;
-
- if (params.ldmParams.enableLdm) {
- /* Adjust long distance matching parameters */
- ZSTD_ldm_adjustParameters(&params.ldmParams, &params.cParams);
- assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog);
- assert(params.ldmParams.hashRateLog < 32);
- zc->ldmState.hashPower = ZSTD_rollingHash_primePower(params.ldmParams.minMatchLength);
- }
-
- { size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize));
- size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
- U32 const divider = (params.cParams.minMatch==3) ? 3 : 4;
- size_t const maxNbSeq = blockSize / divider;
- size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize)
- + ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(seqDef))
- + 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE));
- size_t const buffOutSize = (zbuff==ZSTDb_buffered) ? ZSTD_compressBound(blockSize)+1 : 0;
- size_t const buffInSize = (zbuff==ZSTDb_buffered) ? windowSize + blockSize : 0;
- size_t const matchStateSize = ZSTD_sizeof_matchState(&params.cParams, /* forCCtx */ 1);
- size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params.ldmParams, blockSize);
-
- ZSTD_indexResetPolicy_e needsIndexReset = zc->initialized ? ZSTDirp_continue : ZSTDirp_reset;
-
- if (ZSTD_indexTooCloseToMax(zc->blockState.matchState.window)) {
- needsIndexReset = ZSTDirp_reset;
- }
-
- if (!zc->staticSize) ZSTD_cwksp_bump_oversized_duration(ws, 0);
-
- /* Check if workspace is large enough, alloc a new one if needed */
- { size_t const cctxSpace = zc->staticSize ? ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx)) : 0;
- size_t const entropySpace = ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE);
- size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t));
- size_t const bufferSpace = ZSTD_cwksp_alloc_size(buffInSize) + ZSTD_cwksp_alloc_size(buffOutSize);
- size_t const ldmSpace = ZSTD_ldm_getTableSize(params.ldmParams);
- size_t const ldmSeqSpace = ZSTD_cwksp_alloc_size(maxNbLdmSeq * sizeof(rawSeq));
-
- size_t const neededSpace =
- cctxSpace +
- entropySpace +
- blockStateSpace +
- ldmSpace +
- ldmSeqSpace +
- matchStateSize +
- tokenSpace +
- bufferSpace;
-
- int const workspaceTooSmall = ZSTD_cwksp_sizeof(ws) < neededSpace;
- int const workspaceWasteful = ZSTD_cwksp_check_wasteful(ws, neededSpace);
-
- DEBUGLOG(4, "Need %zuKB workspace, including %zuKB for match state, and %zuKB for buffers",
- neededSpace>>10, matchStateSize>>10, bufferSpace>>10);
- DEBUGLOG(4, "windowSize: %zu - blockSize: %zu", windowSize, blockSize);
-
- if (workspaceTooSmall || workspaceWasteful) {
- DEBUGLOG(4, "Resize workspaceSize from %zuKB to %zuKB",
- ZSTD_cwksp_sizeof(ws) >> 10,
- neededSpace >> 10);
-
- RETURN_ERROR_IF(zc->staticSize, memory_allocation, "static cctx : no resize");
-
- needsIndexReset = ZSTDirp_reset;
-
- ZSTD_cwksp_free(ws, zc->customMem);
- FORWARD_IF_ERROR(ZSTD_cwksp_create(ws, neededSpace, zc->customMem), "");
-
- DEBUGLOG(5, "reserving object space");
- /* Statically sized space.
- * entropyWorkspace never moves,
- * though prev/next block swap places */
- assert(ZSTD_cwksp_check_available(ws, 2 * sizeof(ZSTD_compressedBlockState_t)));
- zc->blockState.prevCBlock = (ZSTD_compressedBlockState_t*) ZSTD_cwksp_reserve_object(ws, sizeof(ZSTD_compressedBlockState_t));
- RETURN_ERROR_IF(zc->blockState.prevCBlock == NULL, memory_allocation, "couldn't allocate prevCBlock");
- zc->blockState.nextCBlock = (ZSTD_compressedBlockState_t*) ZSTD_cwksp_reserve_object(ws, sizeof(ZSTD_compressedBlockState_t));
- RETURN_ERROR_IF(zc->blockState.nextCBlock == NULL, memory_allocation, "couldn't allocate nextCBlock");
- zc->entropyWorkspace = (U32*) ZSTD_cwksp_reserve_object(ws, HUF_WORKSPACE_SIZE);
- RETURN_ERROR_IF(zc->blockState.nextCBlock == NULL, memory_allocation, "couldn't allocate entropyWorkspace");
- } }
-
- ZSTD_cwksp_clear(ws);
-
- /* init params */
- zc->appliedParams = params;
- zc->blockState.matchState.cParams = params.cParams;
- zc->pledgedSrcSizePlusOne = pledgedSrcSize+1;
- zc->consumedSrcSize = 0;
- zc->producedCSize = 0;
- if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)
- zc->appliedParams.fParams.contentSizeFlag = 0;
- DEBUGLOG(4, "pledged content size : %u ; flag : %u",
- (unsigned)pledgedSrcSize, zc->appliedParams.fParams.contentSizeFlag);
- zc->blockSize = blockSize;
-
- XXH64_reset(&zc->xxhState, 0);
- zc->stage = ZSTDcs_init;
- zc->dictID = 0;
-
- ZSTD_reset_compressedBlockState(zc->blockState.prevCBlock);
-
- /* ZSTD_wildcopy() is used to copy into the literals buffer,
- * so we have to oversize the buffer by WILDCOPY_OVERLENGTH bytes.
- */
- zc->seqStore.litStart = ZSTD_cwksp_reserve_buffer(ws, blockSize + WILDCOPY_OVERLENGTH);
- zc->seqStore.maxNbLit = blockSize;
-
- /* buffers */
- zc->inBuffSize = buffInSize;
- zc->inBuff = (char*)ZSTD_cwksp_reserve_buffer(ws, buffInSize);
- zc->outBuffSize = buffOutSize;
- zc->outBuff = (char*)ZSTD_cwksp_reserve_buffer(ws, buffOutSize);
-
- /* ldm bucketOffsets table */
- if (params.ldmParams.enableLdm) {
- /* TODO: avoid memset? */
- size_t const ldmBucketSize =
- ((size_t)1) << (params.ldmParams.hashLog -
- params.ldmParams.bucketSizeLog);
- zc->ldmState.bucketOffsets = ZSTD_cwksp_reserve_buffer(ws, ldmBucketSize);
- memset(zc->ldmState.bucketOffsets, 0, ldmBucketSize);
- }
-
- /* sequences storage */
- ZSTD_referenceExternalSequences(zc, NULL, 0);
- zc->seqStore.maxNbSeq = maxNbSeq;
- zc->seqStore.llCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE));
- zc->seqStore.mlCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE));
- zc->seqStore.ofCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE));
- zc->seqStore.sequencesStart = (seqDef*)ZSTD_cwksp_reserve_aligned(ws, maxNbSeq * sizeof(seqDef));
-
- FORWARD_IF_ERROR(ZSTD_reset_matchState(
- &zc->blockState.matchState,
- ws,
- &params.cParams,
- crp,
- needsIndexReset,
- ZSTD_resetTarget_CCtx), "");
-
- /* ldm hash table */
- if (params.ldmParams.enableLdm) {
- /* TODO: avoid memset? */
- size_t const ldmHSize = ((size_t)1) << params.ldmParams.hashLog;
- zc->ldmState.hashTable = (ldmEntry_t*)ZSTD_cwksp_reserve_aligned(ws, ldmHSize * sizeof(ldmEntry_t));
- memset(zc->ldmState.hashTable, 0, ldmHSize * sizeof(ldmEntry_t));
- zc->ldmSequences = (rawSeq*)ZSTD_cwksp_reserve_aligned(ws, maxNbLdmSeq * sizeof(rawSeq));
- zc->maxNbLdmSequences = maxNbLdmSeq;
-
- ZSTD_window_init(&zc->ldmState.window);
- ZSTD_window_clear(&zc->ldmState.window);
- zc->ldmState.loadedDictEnd = 0;
- }
-
- DEBUGLOG(3, "wksp: finished allocating, %zd bytes remain available", ZSTD_cwksp_available_space(ws));
- zc->initialized = 1;
-
- return 0;
- }
-}
-
-/* ZSTD_invalidateRepCodes() :
- * ensures next compression will not use repcodes from previous block.
- * Note : only works with regular variant;
- * do not use with extDict variant ! */
-void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
- int i;
- for (i=0; i<ZSTD_REP_NUM; i++) cctx->blockState.prevCBlock->rep[i] = 0;
- assert(!ZSTD_window_hasExtDict(cctx->blockState.matchState.window));
-}
-
-/* These are the approximate sizes for each strategy past which copying the
- * dictionary tables into the working context is faster than using them
- * in-place.
- */
-static const size_t attachDictSizeCutoffs[ZSTD_STRATEGY_MAX+1] = {
- 8 KB, /* unused */
- 8 KB, /* ZSTD_fast */
- 16 KB, /* ZSTD_dfast */
- 32 KB, /* ZSTD_greedy */
- 32 KB, /* ZSTD_lazy */
- 32 KB, /* ZSTD_lazy2 */
- 32 KB, /* ZSTD_btlazy2 */
- 32 KB, /* ZSTD_btopt */
- 8 KB, /* ZSTD_btultra */
- 8 KB /* ZSTD_btultra2 */
-};
-
-static int ZSTD_shouldAttachDict(const ZSTD_CDict* cdict,
- const ZSTD_CCtx_params* params,
- U64 pledgedSrcSize)
-{
- size_t cutoff = attachDictSizeCutoffs[cdict->matchState.cParams.strategy];
- return ( pledgedSrcSize <= cutoff
- || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN
- || params->attachDictPref == ZSTD_dictForceAttach )
- && params->attachDictPref != ZSTD_dictForceCopy
- && !params->forceWindow; /* dictMatchState isn't correctly
- * handled in _enforceMaxDist */
-}
-
-static size_t
-ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx,
- const ZSTD_CDict* cdict,
- ZSTD_CCtx_params params,
- U64 pledgedSrcSize,
- ZSTD_buffered_policy_e zbuff)
-{
- { const ZSTD_compressionParameters* const cdict_cParams = &cdict->matchState.cParams;
- unsigned const windowLog = params.cParams.windowLog;
- assert(windowLog != 0);
- /* Resize working context table params for input only, since the dict
- * has its own tables. */
- /* pledgeSrcSize == 0 means 0! */
- params.cParams = ZSTD_adjustCParams_internal(*cdict_cParams, pledgedSrcSize, 0);
- params.cParams.windowLog = windowLog;
- FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
- ZSTDcrp_makeClean, zbuff), "");
- assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy);
- }
-
- { const U32 cdictEnd = (U32)( cdict->matchState.window.nextSrc
- - cdict->matchState.window.base);
- const U32 cdictLen = cdictEnd - cdict->matchState.window.dictLimit;
- if (cdictLen == 0) {
- /* don't even attach dictionaries with no contents */
- DEBUGLOG(4, "skipping attaching empty dictionary");
- } else {
- DEBUGLOG(4, "attaching dictionary into context");
- cctx->blockState.matchState.dictMatchState = &cdict->matchState;
-
- /* prep working match state so dict matches never have negative indices
- * when they are translated to the working context's index space. */
- if (cctx->blockState.matchState.window.dictLimit < cdictEnd) {
- cctx->blockState.matchState.window.nextSrc =
- cctx->blockState.matchState.window.base + cdictEnd;
- ZSTD_window_clear(&cctx->blockState.matchState.window);
- }
- /* loadedDictEnd is expressed within the referential of the active context */
- cctx->blockState.matchState.loadedDictEnd = cctx->blockState.matchState.window.dictLimit;
- } }
-
- cctx->dictID = cdict->dictID;
-
- /* copy block state */
- memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState));
-
- return 0;
-}
-
-static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx,
- const ZSTD_CDict* cdict,
- ZSTD_CCtx_params params,
- U64 pledgedSrcSize,
- ZSTD_buffered_policy_e zbuff)
-{
- const ZSTD_compressionParameters *cdict_cParams = &cdict->matchState.cParams;
-
- DEBUGLOG(4, "copying dictionary into context");
-
- { unsigned const windowLog = params.cParams.windowLog;
- assert(windowLog != 0);
- /* Copy only compression parameters related to tables. */
- params.cParams = *cdict_cParams;
- params.cParams.windowLog = windowLog;
- FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
- ZSTDcrp_leaveDirty, zbuff), "");
- assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy);
- assert(cctx->appliedParams.cParams.hashLog == cdict_cParams->hashLog);
- assert(cctx->appliedParams.cParams.chainLog == cdict_cParams->chainLog);
- }
-
- ZSTD_cwksp_mark_tables_dirty(&cctx->workspace);
-
- /* copy tables */
- { size_t const chainSize = (cdict_cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cdict_cParams->chainLog);
- size_t const hSize = (size_t)1 << cdict_cParams->hashLog;
-
- memcpy(cctx->blockState.matchState.hashTable,
- cdict->matchState.hashTable,
- hSize * sizeof(U32));
- memcpy(cctx->blockState.matchState.chainTable,
- cdict->matchState.chainTable,
- chainSize * sizeof(U32));
- }
-
- /* Zero the hashTable3, since the cdict never fills it */
- { int const h3log = cctx->blockState.matchState.hashLog3;
- size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0;
- assert(cdict->matchState.hashLog3 == 0);
- memset(cctx->blockState.matchState.hashTable3, 0, h3Size * sizeof(U32));
- }
-
- ZSTD_cwksp_mark_tables_clean(&cctx->workspace);
-
- /* copy dictionary offsets */
- { ZSTD_matchState_t const* srcMatchState = &cdict->matchState;
- ZSTD_matchState_t* dstMatchState = &cctx->blockState.matchState;
- dstMatchState->window = srcMatchState->window;
- dstMatchState->nextToUpdate = srcMatchState->nextToUpdate;
- dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd;
- }
-
- cctx->dictID = cdict->dictID;
-
- /* copy block state */
- memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState));
-
- return 0;
-}
-
-/* We have a choice between copying the dictionary context into the working
- * context, or referencing the dictionary context from the working context
- * in-place. We decide here which strategy to use. */
-static size_t ZSTD_resetCCtx_usingCDict(ZSTD_CCtx* cctx,
- const ZSTD_CDict* cdict,
- const ZSTD_CCtx_params* params,
- U64 pledgedSrcSize,
- ZSTD_buffered_policy_e zbuff)
-{
-
- DEBUGLOG(4, "ZSTD_resetCCtx_usingCDict (pledgedSrcSize=%u)",
- (unsigned)pledgedSrcSize);
-
- if (ZSTD_shouldAttachDict(cdict, params, pledgedSrcSize)) {
- return ZSTD_resetCCtx_byAttachingCDict(
- cctx, cdict, *params, pledgedSrcSize, zbuff);
- } else {
- return ZSTD_resetCCtx_byCopyingCDict(
- cctx, cdict, *params, pledgedSrcSize, zbuff);
- }
-}
-
-/*! ZSTD_copyCCtx_internal() :
- * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
- * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
- * The "context", in this case, refers to the hash and chain tables,
- * entropy tables, and dictionary references.
- * `windowLog` value is enforced if != 0, otherwise value is copied from srcCCtx.
- * @return : 0, or an error code */
-static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
- const ZSTD_CCtx* srcCCtx,
- ZSTD_frameParameters fParams,
- U64 pledgedSrcSize,
- ZSTD_buffered_policy_e zbuff)
-{
- DEBUGLOG(5, "ZSTD_copyCCtx_internal");
- RETURN_ERROR_IF(srcCCtx->stage!=ZSTDcs_init, stage_wrong,
- "Can't copy a ctx that's not in init stage.");
-
- memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
- { ZSTD_CCtx_params params = dstCCtx->requestedParams;
- /* Copy only compression parameters related to tables. */
- params.cParams = srcCCtx->appliedParams.cParams;
- params.fParams = fParams;
- ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize,
- ZSTDcrp_leaveDirty, zbuff);
- assert(dstCCtx->appliedParams.cParams.windowLog == srcCCtx->appliedParams.cParams.windowLog);
- assert(dstCCtx->appliedParams.cParams.strategy == srcCCtx->appliedParams.cParams.strategy);
- assert(dstCCtx->appliedParams.cParams.hashLog == srcCCtx->appliedParams.cParams.hashLog);
- assert(dstCCtx->appliedParams.cParams.chainLog == srcCCtx->appliedParams.cParams.chainLog);
- assert(dstCCtx->blockState.matchState.hashLog3 == srcCCtx->blockState.matchState.hashLog3);
- }
-
- ZSTD_cwksp_mark_tables_dirty(&dstCCtx->workspace);
-
- /* copy tables */
- { size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog);
- size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog;
- int const h3log = srcCCtx->blockState.matchState.hashLog3;
- size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0;
-
- memcpy(dstCCtx->blockState.matchState.hashTable,
- srcCCtx->blockState.matchState.hashTable,
- hSize * sizeof(U32));
- memcpy(dstCCtx->blockState.matchState.chainTable,
- srcCCtx->blockState.matchState.chainTable,
- chainSize * sizeof(U32));
- memcpy(dstCCtx->blockState.matchState.hashTable3,
- srcCCtx->blockState.matchState.hashTable3,
- h3Size * sizeof(U32));
- }
-
- ZSTD_cwksp_mark_tables_clean(&dstCCtx->workspace);
-
- /* copy dictionary offsets */
- {
- const ZSTD_matchState_t* srcMatchState = &srcCCtx->blockState.matchState;
- ZSTD_matchState_t* dstMatchState = &dstCCtx->blockState.matchState;
- dstMatchState->window = srcMatchState->window;
- dstMatchState->nextToUpdate = srcMatchState->nextToUpdate;
- dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd;
- }
- dstCCtx->dictID = srcCCtx->dictID;
-
- /* copy block state */
- memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock));
-
- return 0;
-}
-
-/*! ZSTD_copyCCtx() :
- * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
- * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
- * pledgedSrcSize==0 means "unknown".
-* @return : 0, or an error code */
-size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize)
-{
- ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
- ZSTD_buffered_policy_e const zbuff = (ZSTD_buffered_policy_e)(srcCCtx->inBuffSize>0);
- ZSTD_STATIC_ASSERT((U32)ZSTDb_buffered==1);
- if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;
- fParams.contentSizeFlag = (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN);
-
- return ZSTD_copyCCtx_internal(dstCCtx, srcCCtx,
- fParams, pledgedSrcSize,
- zbuff);
-}
-
-
-#define ZSTD_ROWSIZE 16
-/*! ZSTD_reduceTable() :
- * reduce table indexes by `reducerValue`, or squash to zero.
- * PreserveMark preserves "unsorted mark" for btlazy2 strategy.
- * It must be set to a clear 0/1 value, to remove branch during inlining.
- * Presume table size is a multiple of ZSTD_ROWSIZE
- * to help auto-vectorization */
-FORCE_INLINE_TEMPLATE void
-ZSTD_reduceTable_internal (U32* const table, U32 const size, U32 const reducerValue, int const preserveMark)
-{
- int const nbRows = (int)size / ZSTD_ROWSIZE;
- int cellNb = 0;
- int rowNb;
- assert((size & (ZSTD_ROWSIZE-1)) == 0); /* multiple of ZSTD_ROWSIZE */
- assert(size < (1U<<31)); /* can be casted to int */
-
-#if defined (MEMORY_SANITIZER) && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE)
- /* To validate that the table re-use logic is sound, and that we don't
- * access table space that we haven't cleaned, we re-"poison" the table
- * space every time we mark it dirty.
- *
- * This function however is intended to operate on those dirty tables and
- * re-clean them. So when this function is used correctly, we can unpoison
- * the memory it operated on. This introduces a blind spot though, since
- * if we now try to operate on __actually__ poisoned memory, we will not
- * detect that. */
- __msan_unpoison(table, size * sizeof(U32));
-#endif
-
- for (rowNb=0 ; rowNb < nbRows ; rowNb++) {
- int column;
- for (column=0; column<ZSTD_ROWSIZE; column++) {
- if (preserveMark) {
- U32 const adder = (table[cellNb] == ZSTD_DUBT_UNSORTED_MARK) ? reducerValue : 0;
- table[cellNb] += adder;
- }
- if (table[cellNb] < reducerValue) table[cellNb] = 0;
- else table[cellNb] -= reducerValue;
- cellNb++;
- } }
-}
-
-static void ZSTD_reduceTable(U32* const table, U32 const size, U32 const reducerValue)
-{
- ZSTD_reduceTable_internal(table, size, reducerValue, 0);
-}
-
-static void ZSTD_reduceTable_btlazy2(U32* const table, U32 const size, U32 const reducerValue)
-{
- ZSTD_reduceTable_internal(table, size, reducerValue, 1);
-}
-
-/*! ZSTD_reduceIndex() :
-* rescale all indexes to avoid future overflow (indexes are U32) */
-static void ZSTD_reduceIndex (ZSTD_matchState_t* ms, ZSTD_CCtx_params const* params, const U32 reducerValue)
-{
- { U32 const hSize = (U32)1 << params->cParams.hashLog;
- ZSTD_reduceTable(ms->hashTable, hSize, reducerValue);
- }
-
- if (params->cParams.strategy != ZSTD_fast) {
- U32 const chainSize = (U32)1 << params->cParams.chainLog;
- if (params->cParams.strategy == ZSTD_btlazy2)
- ZSTD_reduceTable_btlazy2(ms->chainTable, chainSize, reducerValue);
- else
- ZSTD_reduceTable(ms->chainTable, chainSize, reducerValue);
- }
-
- if (ms->hashLog3) {
- U32 const h3Size = (U32)1 << ms->hashLog3;
- ZSTD_reduceTable(ms->hashTable3, h3Size, reducerValue);
- }
-}
-
-
-/*-*******************************************************
-* Block entropic compression
-*********************************************************/
-
-/* See doc/zstd_compression_format.md for detailed format description */
-
-void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
-{
- const seqDef* const sequences = seqStorePtr->sequencesStart;
- BYTE* const llCodeTable = seqStorePtr->llCode;
- BYTE* const ofCodeTable = seqStorePtr->ofCode;
- BYTE* const mlCodeTable = seqStorePtr->mlCode;
- U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
- U32 u;
- assert(nbSeq <= seqStorePtr->maxNbSeq);
- for (u=0; u<nbSeq; u++) {
- U32 const llv = sequences[u].litLength;
- U32 const mlv = sequences[u].matchLength;
- llCodeTable[u] = (BYTE)ZSTD_LLcode(llv);
- ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset);
- mlCodeTable[u] = (BYTE)ZSTD_MLcode(mlv);
- }
- if (seqStorePtr->longLengthID==1)
- llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
- if (seqStorePtr->longLengthID==2)
- mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
-}
-
-/* ZSTD_useTargetCBlockSize():
- * Returns if target compressed block size param is being used.
- * If used, compression will do best effort to make a compressed block size to be around targetCBlockSize.
- * Returns 1 if true, 0 otherwise. */
-static int ZSTD_useTargetCBlockSize(const ZSTD_CCtx_params* cctxParams)
-{
- DEBUGLOG(5, "ZSTD_useTargetCBlockSize (targetCBlockSize=%zu)", cctxParams->targetCBlockSize);
- return (cctxParams->targetCBlockSize != 0);
-}
-
-/* ZSTD_compressSequences_internal():
- * actually compresses both literals and sequences */
-MEM_STATIC size_t
-ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
- const ZSTD_entropyCTables_t* prevEntropy,
- ZSTD_entropyCTables_t* nextEntropy,
- const ZSTD_CCtx_params* cctxParams,
- void* dst, size_t dstCapacity,
- void* entropyWorkspace, size_t entropyWkspSize,
- const int bmi2)
-{
- const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN;
- ZSTD_strategy const strategy = cctxParams->cParams.strategy;
- unsigned count[MaxSeq+1];
- FSE_CTable* CTable_LitLength = nextEntropy->fse.litlengthCTable;
- FSE_CTable* CTable_OffsetBits = nextEntropy->fse.offcodeCTable;
- FSE_CTable* CTable_MatchLength = nextEntropy->fse.matchlengthCTable;
- U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
- const seqDef* const sequences = seqStorePtr->sequencesStart;
- const BYTE* const ofCodeTable = seqStorePtr->ofCode;
- const BYTE* const llCodeTable = seqStorePtr->llCode;
- const BYTE* const mlCodeTable = seqStorePtr->mlCode;
- BYTE* const ostart = (BYTE*)dst;
- BYTE* const oend = ostart + dstCapacity;
- BYTE* op = ostart;
- size_t const nbSeq = (size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
- BYTE* seqHead;
- BYTE* lastNCount = NULL;
-
- DEBUGLOG(5, "ZSTD_compressSequences_internal (nbSeq=%zu)", nbSeq);
- ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog)));
-
- /* Compress literals */
- { const BYTE* const literals = seqStorePtr->litStart;
- size_t const litSize = (size_t)(seqStorePtr->lit - literals);
- size_t const cSize = ZSTD_compressLiterals(
- &prevEntropy->huf, &nextEntropy->huf,
- cctxParams->cParams.strategy,
- ZSTD_disableLiteralsCompression(cctxParams),
- op, dstCapacity,
- literals, litSize,
- entropyWorkspace, entropyWkspSize,
- bmi2);
- FORWARD_IF_ERROR(cSize, "ZSTD_compressLiterals failed");
- assert(cSize <= dstCapacity);
- op += cSize;
- }
-
- /* Sequences Header */
- RETURN_ERROR_IF((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead*/,
- dstSize_tooSmall, "Can't fit seq hdr in output buf!");
- if (nbSeq < 128) {
- *op++ = (BYTE)nbSeq;
- } else if (nbSeq < LONGNBSEQ) {
- op[0] = (BYTE)((nbSeq>>8) + 0x80);
- op[1] = (BYTE)nbSeq;
- op+=2;
- } else {
- op[0]=0xFF;
- MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ));
- op+=3;
- }
- assert(op <= oend);
- if (nbSeq==0) {
- /* Copy the old tables over as if we repeated them */
- memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse));
- return (size_t)(op - ostart);
- }
-
- /* seqHead : flags for FSE encoding type */
- seqHead = op++;
- assert(op <= oend);
-
- /* convert length/distances into codes */
- ZSTD_seqToCodes(seqStorePtr);
- /* build CTable for Literal Lengths */
- { unsigned max = MaxLL;
- size_t const mostFrequent = HIST_countFast_wksp(count, &max, llCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */
- DEBUGLOG(5, "Building LL table");
- nextEntropy->fse.litlength_repeatMode = prevEntropy->fse.litlength_repeatMode;
- LLtype = ZSTD_selectEncodingType(&nextEntropy->fse.litlength_repeatMode,
- count, max, mostFrequent, nbSeq,
- LLFSELog, prevEntropy->fse.litlengthCTable,
- LL_defaultNorm, LL_defaultNormLog,
- ZSTD_defaultAllowed, strategy);
- assert(set_basic < set_compressed && set_rle < set_compressed);
- assert(!(LLtype < set_compressed && nextEntropy->fse.litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
- { size_t const countSize = ZSTD_buildCTable(
- op, (size_t)(oend - op),
- CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype,
- count, max, llCodeTable, nbSeq,
- LL_defaultNorm, LL_defaultNormLog, MaxLL,
- prevEntropy->fse.litlengthCTable,
- sizeof(prevEntropy->fse.litlengthCTable),
- entropyWorkspace, entropyWkspSize);
- FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for LitLens failed");
- if (LLtype == set_compressed)
- lastNCount = op;
- op += countSize;
- assert(op <= oend);
- } }
- /* build CTable for Offsets */
- { unsigned max = MaxOff;
- size_t const mostFrequent = HIST_countFast_wksp(
- count, &max, ofCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */
- /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */
- ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed;
- DEBUGLOG(5, "Building OF table");
- nextEntropy->fse.offcode_repeatMode = prevEntropy->fse.offcode_repeatMode;
- Offtype = ZSTD_selectEncodingType(&nextEntropy->fse.offcode_repeatMode,
- count, max, mostFrequent, nbSeq,
- OffFSELog, prevEntropy->fse.offcodeCTable,
- OF_defaultNorm, OF_defaultNormLog,
- defaultPolicy, strategy);
- assert(!(Offtype < set_compressed && nextEntropy->fse.offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */
- { size_t const countSize = ZSTD_buildCTable(
- op, (size_t)(oend - op),
- CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype,
- count, max, ofCodeTable, nbSeq,
- OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
- prevEntropy->fse.offcodeCTable,
- sizeof(prevEntropy->fse.offcodeCTable),
- entropyWorkspace, entropyWkspSize);
- FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for Offsets failed");
- if (Offtype == set_compressed)
- lastNCount = op;
- op += countSize;
- assert(op <= oend);
- } }
- /* build CTable for MatchLengths */
- { unsigned max = MaxML;
- size_t const mostFrequent = HIST_countFast_wksp(
- count, &max, mlCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */
- DEBUGLOG(5, "Building ML table (remaining space : %i)", (int)(oend-op));
- nextEntropy->fse.matchlength_repeatMode = prevEntropy->fse.matchlength_repeatMode;
- MLtype = ZSTD_selectEncodingType(&nextEntropy->fse.matchlength_repeatMode,
- count, max, mostFrequent, nbSeq,
- MLFSELog, prevEntropy->fse.matchlengthCTable,
- ML_defaultNorm, ML_defaultNormLog,
- ZSTD_defaultAllowed, strategy);
- assert(!(MLtype < set_compressed && nextEntropy->fse.matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
- { size_t const countSize = ZSTD_buildCTable(
- op, (size_t)(oend - op),
- CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype,
- count, max, mlCodeTable, nbSeq,
- ML_defaultNorm, ML_defaultNormLog, MaxML,
- prevEntropy->fse.matchlengthCTable,
- sizeof(prevEntropy->fse.matchlengthCTable),
- entropyWorkspace, entropyWkspSize);
- FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for MatchLengths failed");
- if (MLtype == set_compressed)
- lastNCount = op;
- op += countSize;
- assert(op <= oend);
- } }
-
- *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
-
- { size_t const bitstreamSize = ZSTD_encodeSequences(
- op, (size_t)(oend - op),
- CTable_MatchLength, mlCodeTable,
- CTable_OffsetBits, ofCodeTable,
- CTable_LitLength, llCodeTable,
- sequences, nbSeq,
- longOffsets, bmi2);
- FORWARD_IF_ERROR(bitstreamSize, "ZSTD_encodeSequences failed");
- op += bitstreamSize;
- assert(op <= oend);
- /* zstd versions <= 1.3.4 mistakenly report corruption when
- * FSE_readNCount() receives a buffer < 4 bytes.
- * Fixed by https://github.com/facebook/zstd/pull/1146.
- * This can happen when the last set_compressed table present is 2
- * bytes and the bitstream is only one byte.
- * In this exceedingly rare case, we will simply emit an uncompressed
- * block, since it isn't worth optimizing.
- */
- if (lastNCount && (op - lastNCount) < 4) {
- /* NCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */
- assert(op - lastNCount == 3);
- DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.3.4 by "
- "emitting an uncompressed block.");
- return 0;
- }
- }
-
- DEBUGLOG(5, "compressed block size : %u", (unsigned)(op - ostart));
- return (size_t)(op - ostart);
-}
-
-MEM_STATIC size_t
-ZSTD_compressSequences(seqStore_t* seqStorePtr,
- const ZSTD_entropyCTables_t* prevEntropy,
- ZSTD_entropyCTables_t* nextEntropy,
- const ZSTD_CCtx_params* cctxParams,
- void* dst, size_t dstCapacity,
- size_t srcSize,
- void* entropyWorkspace, size_t entropyWkspSize,
- int bmi2)
-{
- size_t const cSize = ZSTD_compressSequences_internal(
- seqStorePtr, prevEntropy, nextEntropy, cctxParams,
- dst, dstCapacity,
- entropyWorkspace, entropyWkspSize, bmi2);
- if (cSize == 0) return 0;
- /* When srcSize <= dstCapacity, there is enough space to write a raw uncompressed block.
- * Since we ran out of space, block must be not compressible, so fall back to raw uncompressed block.
- */
- if ((cSize == ERROR(dstSize_tooSmall)) & (srcSize <= dstCapacity))
- return 0; /* block not compressed */
- FORWARD_IF_ERROR(cSize, "ZSTD_compressSequences_internal failed");
-
- /* Check compressibility */
- { size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, cctxParams->cParams.strategy);
- if (cSize >= maxCSize) return 0; /* block not compressed */
- }
-
- return cSize;
-}
-
-/* ZSTD_selectBlockCompressor() :
- * Not static, but internal use only (used by long distance matcher)
- * assumption : strat is a valid strategy */
-ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode)
-{
- static const ZSTD_blockCompressor blockCompressor[3][ZSTD_STRATEGY_MAX+1] = {
- { ZSTD_compressBlock_fast /* default for 0 */,
- ZSTD_compressBlock_fast,
- ZSTD_compressBlock_doubleFast,
- ZSTD_compressBlock_greedy,
- ZSTD_compressBlock_lazy,
- ZSTD_compressBlock_lazy2,
- ZSTD_compressBlock_btlazy2,
- ZSTD_compressBlock_btopt,
- ZSTD_compressBlock_btultra,
- ZSTD_compressBlock_btultra2 },
- { ZSTD_compressBlock_fast_extDict /* default for 0 */,
- ZSTD_compressBlock_fast_extDict,
- ZSTD_compressBlock_doubleFast_extDict,
- ZSTD_compressBlock_greedy_extDict,
- ZSTD_compressBlock_lazy_extDict,
- ZSTD_compressBlock_lazy2_extDict,
- ZSTD_compressBlock_btlazy2_extDict,
- ZSTD_compressBlock_btopt_extDict,
- ZSTD_compressBlock_btultra_extDict,
- ZSTD_compressBlock_btultra_extDict },
- { ZSTD_compressBlock_fast_dictMatchState /* default for 0 */,
- ZSTD_compressBlock_fast_dictMatchState,
- ZSTD_compressBlock_doubleFast_dictMatchState,
- ZSTD_compressBlock_greedy_dictMatchState,
- ZSTD_compressBlock_lazy_dictMatchState,
- ZSTD_compressBlock_lazy2_dictMatchState,
- ZSTD_compressBlock_btlazy2_dictMatchState,
- ZSTD_compressBlock_btopt_dictMatchState,
- ZSTD_compressBlock_btultra_dictMatchState,
- ZSTD_compressBlock_btultra_dictMatchState }
- };
- ZSTD_blockCompressor selectedCompressor;
- ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1);
-
- assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, strat));
- selectedCompressor = blockCompressor[(int)dictMode][(int)strat];
- assert(selectedCompressor != NULL);
- return selectedCompressor;
-}
-
-static void ZSTD_storeLastLiterals(seqStore_t* seqStorePtr,
- const BYTE* anchor, size_t lastLLSize)
-{
- memcpy(seqStorePtr->lit, anchor, lastLLSize);
- seqStorePtr->lit += lastLLSize;
-}
-
-void ZSTD_resetSeqStore(seqStore_t* ssPtr)
-{
- ssPtr->lit = ssPtr->litStart;
- ssPtr->sequences = ssPtr->sequencesStart;
- ssPtr->longLengthID = 0;
-}
-
-typedef enum { ZSTDbss_compress, ZSTDbss_noCompress } ZSTD_buildSeqStore_e;
-
-static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize)
-{
- ZSTD_matchState_t* const ms = &zc->blockState.matchState;
- DEBUGLOG(5, "ZSTD_buildSeqStore (srcSize=%zu)", srcSize);
- assert(srcSize <= ZSTD_BLOCKSIZE_MAX);
- /* Assert that we have correctly flushed the ctx params into the ms's copy */
- ZSTD_assertEqualCParams(zc->appliedParams.cParams, ms->cParams);
- if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) {
- ZSTD_ldm_skipSequences(&zc->externSeqStore, srcSize, zc->appliedParams.cParams.minMatch);
- return ZSTDbss_noCompress; /* don't even attempt compression below a certain srcSize */
- }
- ZSTD_resetSeqStore(&(zc->seqStore));
- /* required for optimal parser to read stats from dictionary */
- ms->opt.symbolCosts = &zc->blockState.prevCBlock->entropy;
- /* tell the optimal parser how we expect to compress literals */
- ms->opt.literalCompressionMode = zc->appliedParams.literalCompressionMode;
- /* a gap between an attached dict and the current window is not safe,
- * they must remain adjacent,
- * and when that stops being the case, the dict must be unset */
- assert(ms->dictMatchState == NULL || ms->loadedDictEnd == ms->window.dictLimit);
-
- /* limited update after a very long match */
- { const BYTE* const base = ms->window.base;
- const BYTE* const istart = (const BYTE*)src;
- const U32 current = (U32)(istart-base);
- if (sizeof(ptrdiff_t)==8) assert(istart - base < (ptrdiff_t)(U32)(-1)); /* ensure no overflow */
- if (current > ms->nextToUpdate + 384)
- ms->nextToUpdate = current - MIN(192, (U32)(current - ms->nextToUpdate - 384));
- }
-
- /* select and store sequences */
- { ZSTD_dictMode_e const dictMode = ZSTD_matchState_dictMode(ms);
- size_t lastLLSize;
- { int i;
- for (i = 0; i < ZSTD_REP_NUM; ++i)
- zc->blockState.nextCBlock->rep[i] = zc->blockState.prevCBlock->rep[i];
- }
- if (zc->externSeqStore.pos < zc->externSeqStore.size) {
- assert(!zc->appliedParams.ldmParams.enableLdm);
- /* Updates ldmSeqStore.pos */
- lastLLSize =
- ZSTD_ldm_blockCompress(&zc->externSeqStore,
- ms, &zc->seqStore,
- zc->blockState.nextCBlock->rep,
- src, srcSize);
- assert(zc->externSeqStore.pos <= zc->externSeqStore.size);
- } else if (zc->appliedParams.ldmParams.enableLdm) {
- rawSeqStore_t ldmSeqStore = {NULL, 0, 0, 0};
-
- ldmSeqStore.seq = zc->ldmSequences;
- ldmSeqStore.capacity = zc->maxNbLdmSequences;
- /* Updates ldmSeqStore.size */
- FORWARD_IF_ERROR(ZSTD_ldm_generateSequences(&zc->ldmState, &ldmSeqStore,
- &zc->appliedParams.ldmParams,
- src, srcSize), "");
- /* Updates ldmSeqStore.pos */
- lastLLSize =
- ZSTD_ldm_blockCompress(&ldmSeqStore,
- ms, &zc->seqStore,
- zc->blockState.nextCBlock->rep,
- src, srcSize);
- assert(ldmSeqStore.pos == ldmSeqStore.size);
- } else { /* not long range mode */
- ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, dictMode);
- lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, src, srcSize);
- }
- { const BYTE* const lastLiterals = (const BYTE*)src + srcSize - lastLLSize;
- ZSTD_storeLastLiterals(&zc->seqStore, lastLiterals, lastLLSize);
- } }
- return ZSTDbss_compress;
-}
-
-static void ZSTD_copyBlockSequences(ZSTD_CCtx* zc)
-{
- const seqStore_t* seqStore = ZSTD_getSeqStore(zc);
- const seqDef* seqs = seqStore->sequencesStart;
- size_t seqsSize = seqStore->sequences - seqs;
-
- ZSTD_Sequence* outSeqs = &zc->seqCollector.seqStart[zc->seqCollector.seqIndex];
- size_t i; size_t position; int repIdx;
-
- assert(zc->seqCollector.seqIndex + 1 < zc->seqCollector.maxSequences);
- for (i = 0, position = 0; i < seqsSize; ++i) {
- outSeqs[i].offset = seqs[i].offset;
- outSeqs[i].litLength = seqs[i].litLength;
- outSeqs[i].matchLength = seqs[i].matchLength + MINMATCH;
-
- if (i == seqStore->longLengthPos) {
- if (seqStore->longLengthID == 1) {
- outSeqs[i].litLength += 0x10000;
- } else if (seqStore->longLengthID == 2) {
- outSeqs[i].matchLength += 0x10000;
- }
- }
-
- if (outSeqs[i].offset <= ZSTD_REP_NUM) {
- outSeqs[i].rep = outSeqs[i].offset;
- repIdx = (unsigned int)i - outSeqs[i].offset;
-
- if (outSeqs[i].litLength == 0) {
- if (outSeqs[i].offset < 3) {
- --repIdx;
- } else {
- repIdx = (unsigned int)i - 1;
- }
- ++outSeqs[i].rep;
- }
- assert(repIdx >= -3);
- outSeqs[i].offset = repIdx >= 0 ? outSeqs[repIdx].offset : repStartValue[-repIdx - 1];
- if (outSeqs[i].rep == 4) {
- --outSeqs[i].offset;
- }
- } else {
- outSeqs[i].offset -= ZSTD_REP_NUM;
- }
-
- position += outSeqs[i].litLength;
- outSeqs[i].matchPos = (unsigned int)position;
- position += outSeqs[i].matchLength;
- }
- zc->seqCollector.seqIndex += seqsSize;
-}
-
-size_t ZSTD_getSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs,
- size_t outSeqsSize, const void* src, size_t srcSize)
-{
- const size_t dstCapacity = ZSTD_compressBound(srcSize);
- void* dst = ZSTD_malloc(dstCapacity, ZSTD_defaultCMem);
- SeqCollector seqCollector;
-
- RETURN_ERROR_IF(dst == NULL, memory_allocation, "NULL pointer!");
-
- seqCollector.collectSequences = 1;
- seqCollector.seqStart = outSeqs;
- seqCollector.seqIndex = 0;
- seqCollector.maxSequences = outSeqsSize;
- zc->seqCollector = seqCollector;
-
- ZSTD_compress2(zc, dst, dstCapacity, src, srcSize);
- ZSTD_free(dst, ZSTD_defaultCMem);
- return zc->seqCollector.seqIndex;
-}
-
-/* Returns true if the given block is a RLE block */
-static int ZSTD_isRLE(const BYTE *ip, size_t length) {
- size_t i;
- if (length < 2) return 1;
- for (i = 1; i < length; ++i) {
- if (ip[0] != ip[i]) return 0;
- }
- return 1;
-}
-
-/* Returns true if the given block may be RLE.
- * This is just a heuristic based on the compressibility.
- * It may return both false positives and false negatives.
- */
-static int ZSTD_maybeRLE(seqStore_t const* seqStore)
-{
- size_t const nbSeqs = (size_t)(seqStore->sequences - seqStore->sequencesStart);
- size_t const nbLits = (size_t)(seqStore->lit - seqStore->litStart);
-
- return nbSeqs < 4 && nbLits < 10;
-}
-
-static void ZSTD_confirmRepcodesAndEntropyTables(ZSTD_CCtx* zc)
-{
- ZSTD_compressedBlockState_t* const tmp = zc->blockState.prevCBlock;
- zc->blockState.prevCBlock = zc->blockState.nextCBlock;
- zc->blockState.nextCBlock = tmp;
-}
-
-static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize, U32 frame)
-{
- /* This the upper bound for the length of an rle block.
- * This isn't the actual upper bound. Finding the real threshold
- * needs further investigation.
- */
- const U32 rleMaxLength = 25;
- size_t cSize;
- const BYTE* ip = (const BYTE*)src;
- BYTE* op = (BYTE*)dst;
- DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)",
- (unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit,
- (unsigned)zc->blockState.matchState.nextToUpdate);
-
- { const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize);
- FORWARD_IF_ERROR(bss, "ZSTD_buildSeqStore failed");
- if (bss == ZSTDbss_noCompress) { cSize = 0; goto out; }
- }
-
- if (zc->seqCollector.collectSequences) {
- ZSTD_copyBlockSequences(zc);
- return 0;
- }
-
- /* encode sequences and literals */
- cSize = ZSTD_compressSequences(&zc->seqStore,
- &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy,
- &zc->appliedParams,
- dst, dstCapacity,
- srcSize,
- zc->entropyWorkspace, HUF_WORKSPACE_SIZE /* statically allocated in resetCCtx */,
- zc->bmi2);
-
- if (frame &&
- /* We don't want to emit our first block as a RLE even if it qualifies because
- * doing so will cause the decoder (cli only) to throw a "should consume all input error."
- * This is only an issue for zstd <= v1.4.3
- */
- !zc->isFirstBlock &&
- cSize < rleMaxLength &&
- ZSTD_isRLE(ip, srcSize))
- {
- cSize = 1;
- op[0] = ip[0];
- }
-
-out:
- if (!ZSTD_isError(cSize) && cSize > 1) {
- ZSTD_confirmRepcodesAndEntropyTables(zc);
- }
- /* We check that dictionaries have offset codes available for the first
- * block. After the first block, the offcode table might not have large
- * enough codes to represent the offsets in the data.
- */
- if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid)
- zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check;
-
- return cSize;
-}
-
-static size_t ZSTD_compressBlock_targetCBlockSize_body(ZSTD_CCtx* zc,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- const size_t bss, U32 lastBlock)
-{
- DEBUGLOG(6, "Attempting ZSTD_compressSuperBlock()");
- if (bss == ZSTDbss_compress) {
- if (/* We don't want to emit our first block as a RLE even if it qualifies because
- * doing so will cause the decoder (cli only) to throw a "should consume all input error."
- * This is only an issue for zstd <= v1.4.3
- */
- !zc->isFirstBlock &&
- ZSTD_maybeRLE(&zc->seqStore) &&
- ZSTD_isRLE((BYTE const*)src, srcSize))
- {
- return ZSTD_rleCompressBlock(dst, dstCapacity, *(BYTE const*)src, srcSize, lastBlock);
- }
- /* Attempt superblock compression.
- *
- * Note that compressed size of ZSTD_compressSuperBlock() is not bound by the
- * standard ZSTD_compressBound(). This is a problem, because even if we have
- * space now, taking an extra byte now could cause us to run out of space later
- * and violate ZSTD_compressBound().
- *
- * Define blockBound(blockSize) = blockSize + ZSTD_blockHeaderSize.
- *
- * In order to respect ZSTD_compressBound() we must attempt to emit a raw
- * uncompressed block in these cases:
- * * cSize == 0: Return code for an uncompressed block.
- * * cSize == dstSize_tooSmall: We may have expanded beyond blockBound(srcSize).
- * ZSTD_noCompressBlock() will return dstSize_tooSmall if we are really out of
- * output space.
- * * cSize >= blockBound(srcSize): We have expanded the block too much so
- * emit an uncompressed block.
- */
- {
- size_t const cSize = ZSTD_compressSuperBlock(zc, dst, dstCapacity, src, srcSize, lastBlock);
- if (cSize != ERROR(dstSize_tooSmall)) {
- size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, zc->appliedParams.cParams.strategy);
- FORWARD_IF_ERROR(cSize, "ZSTD_compressSuperBlock failed");
- if (cSize != 0 && cSize < maxCSize + ZSTD_blockHeaderSize) {
- ZSTD_confirmRepcodesAndEntropyTables(zc);
- return cSize;
- }
- }
- }
- }
-
- DEBUGLOG(6, "Resorting to ZSTD_noCompressBlock()");
- /* Superblock compression failed, attempt to emit a single no compress block.
- * The decoder will be able to stream this block since it is uncompressed.
- */
- return ZSTD_noCompressBlock(dst, dstCapacity, src, srcSize, lastBlock);
-}
-
-static size_t ZSTD_compressBlock_targetCBlockSize(ZSTD_CCtx* zc,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- U32 lastBlock)
-{
- size_t cSize = 0;
- const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize);
- DEBUGLOG(5, "ZSTD_compressBlock_targetCBlockSize (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u, srcSize=%zu)",
- (unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit, (unsigned)zc->blockState.matchState.nextToUpdate, srcSize);
- FORWARD_IF_ERROR(bss, "ZSTD_buildSeqStore failed");
-
- cSize = ZSTD_compressBlock_targetCBlockSize_body(zc, dst, dstCapacity, src, srcSize, bss, lastBlock);
- FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_targetCBlockSize_body failed");
-
- if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid)
- zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check;
-
- return cSize;
-}
-
-static void ZSTD_overflowCorrectIfNeeded(ZSTD_matchState_t* ms,
- ZSTD_cwksp* ws,
- ZSTD_CCtx_params const* params,
- void const* ip,
- void const* iend)
-{
- if (ZSTD_window_needOverflowCorrection(ms->window, iend)) {
- U32 const maxDist = (U32)1 << params->cParams.windowLog;
- U32 const cycleLog = ZSTD_cycleLog(params->cParams.chainLog, params->cParams.strategy);
- U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, maxDist, ip);
- ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30);
- ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30);
- ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31);
- ZSTD_cwksp_mark_tables_dirty(ws);
- ZSTD_reduceIndex(ms, params, correction);
- ZSTD_cwksp_mark_tables_clean(ws);
- if (ms->nextToUpdate < correction) ms->nextToUpdate = 0;
- else ms->nextToUpdate -= correction;
- /* invalidate dictionaries on overflow correction */
- ms->loadedDictEnd = 0;
- ms->dictMatchState = NULL;
- }
-}
-
-/*! ZSTD_compress_frameChunk() :
-* Compress a chunk of data into one or multiple blocks.
-* All blocks will be terminated, all input will be consumed.
-* Function will issue an error if there is not enough `dstCapacity` to hold the compressed content.
-* Frame is supposed already started (header already produced)
-* @return : compressed size, or an error code
-*/
-static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- U32 lastFrameChunk)
-{
- size_t blockSize = cctx->blockSize;
- size_t remaining = srcSize;
- const BYTE* ip = (const BYTE*)src;
- BYTE* const ostart = (BYTE*)dst;
- BYTE* op = ostart;
- U32 const maxDist = (U32)1 << cctx->appliedParams.cParams.windowLog;
-
- assert(cctx->appliedParams.cParams.windowLog <= ZSTD_WINDOWLOG_MAX);
-
- DEBUGLOG(5, "ZSTD_compress_frameChunk (blockSize=%u)", (unsigned)blockSize);
- if (cctx->appliedParams.fParams.checksumFlag && srcSize)
- XXH64_update(&cctx->xxhState, src, srcSize);
-
- while (remaining) {
- ZSTD_matchState_t* const ms = &cctx->blockState.matchState;
- U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
-
- RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE,
- dstSize_tooSmall,
- "not enough space to store compressed block");
- if (remaining < blockSize) blockSize = remaining;
-
- ZSTD_overflowCorrectIfNeeded(
- ms, &cctx->workspace, &cctx->appliedParams, ip, ip + blockSize);
- ZSTD_checkDictValidity(&ms->window, ip + blockSize, maxDist, &ms->loadedDictEnd, &ms->dictMatchState);
-
- /* Ensure hash/chain table insertion resumes no sooner than lowlimit */
- if (ms->nextToUpdate < ms->window.lowLimit) ms->nextToUpdate = ms->window.lowLimit;
-
- { size_t cSize;
- if (ZSTD_useTargetCBlockSize(&cctx->appliedParams)) {
- cSize = ZSTD_compressBlock_targetCBlockSize(cctx, op, dstCapacity, ip, blockSize, lastBlock);
- FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_targetCBlockSize failed");
- assert(cSize > 0);
- assert(cSize <= blockSize + ZSTD_blockHeaderSize);
- } else {
- cSize = ZSTD_compressBlock_internal(cctx,
- op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize,
- ip, blockSize, 1 /* frame */);
- FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_internal failed");
-
- if (cSize == 0) { /* block is not compressible */
- cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock);
- FORWARD_IF_ERROR(cSize, "ZSTD_noCompressBlock failed");
- } else {
- U32 const cBlockHeader = cSize == 1 ?
- lastBlock + (((U32)bt_rle)<<1) + (U32)(blockSize << 3) :
- lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
- MEM_writeLE24(op, cBlockHeader);
- cSize += ZSTD_blockHeaderSize;
- }
- }
-
-
- ip += blockSize;
- assert(remaining >= blockSize);
- remaining -= blockSize;
- op += cSize;
- assert(dstCapacity >= cSize);
- dstCapacity -= cSize;
- cctx->isFirstBlock = 0;
- DEBUGLOG(5, "ZSTD_compress_frameChunk: adding a block of size %u",
- (unsigned)cSize);
- } }
-
- if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending;
- return (size_t)(op-ostart);
-}
-
-
-static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
- const ZSTD_CCtx_params* params, U64 pledgedSrcSize, U32 dictID)
-{ BYTE* const op = (BYTE*)dst;
- U32 const dictIDSizeCodeLength = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */
- U32 const dictIDSizeCode = params->fParams.noDictIDFlag ? 0 : dictIDSizeCodeLength; /* 0-3 */
- U32 const checksumFlag = params->fParams.checksumFlag>0;
- U32 const windowSize = (U32)1 << params->cParams.windowLog;
- U32 const singleSegment = params->fParams.contentSizeFlag && (windowSize >= pledgedSrcSize);
- BYTE const windowLogByte = (BYTE)((params->cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);
- U32 const fcsCode = params->fParams.contentSizeFlag ?
- (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : 0; /* 0-3 */
- BYTE const frameHeaderDescriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) );
- size_t pos=0;
-
- assert(!(params->fParams.contentSizeFlag && pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN));
- RETURN_ERROR_IF(dstCapacity < ZSTD_FRAMEHEADERSIZE_MAX, dstSize_tooSmall,
- "dst buf is too small to fit worst-case frame header size.");
- DEBUGLOG(4, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u",
- !params->fParams.noDictIDFlag, (unsigned)dictID, (unsigned)dictIDSizeCode);
-
- if (params->format == ZSTD_f_zstd1) {
- MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
- pos = 4;
- }
- op[pos++] = frameHeaderDescriptionByte;
- if (!singleSegment) op[pos++] = windowLogByte;
- switch(dictIDSizeCode)
- {
- default: assert(0); /* impossible */
- case 0 : break;
- case 1 : op[pos] = (BYTE)(dictID); pos++; break;
- case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break;
- case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break;
- }
- switch(fcsCode)
- {
- default: assert(0); /* impossible */
- case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break;
- case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break;
- case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break;
- case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break;
- }
- return pos;
-}
-
-/* ZSTD_writeLastEmptyBlock() :
- * output an empty Block with end-of-frame mark to complete a frame
- * @return : size of data written into `dst` (== ZSTD_blockHeaderSize (defined in zstd_internal.h))
- * or an error code if `dstCapacity` is too small (<ZSTD_blockHeaderSize)
- */
-size_t ZSTD_writeLastEmptyBlock(void* dst, size_t dstCapacity)
-{
- RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize, dstSize_tooSmall,
- "dst buf is too small to write frame trailer empty block.");
- { U32 const cBlockHeader24 = 1 /*lastBlock*/ + (((U32)bt_raw)<<1); /* 0 size */
- MEM_writeLE24(dst, cBlockHeader24);
- return ZSTD_blockHeaderSize;
- }
-}
-
-size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq)
-{
- RETURN_ERROR_IF(cctx->stage != ZSTDcs_init, stage_wrong,
- "wrong cctx stage");
- RETURN_ERROR_IF(cctx->appliedParams.ldmParams.enableLdm,
- parameter_unsupported,
- "incompatible with ldm");
- cctx->externSeqStore.seq = seq;
- cctx->externSeqStore.size = nbSeq;
- cctx->externSeqStore.capacity = nbSeq;
- cctx->externSeqStore.pos = 0;
- return 0;
-}
-
-
-static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- U32 frame, U32 lastFrameChunk)
-{
- ZSTD_matchState_t* const ms = &cctx->blockState.matchState;
- size_t fhSize = 0;
-
- DEBUGLOG(5, "ZSTD_compressContinue_internal, stage: %u, srcSize: %u",
- cctx->stage, (unsigned)srcSize);
- RETURN_ERROR_IF(cctx->stage==ZSTDcs_created, stage_wrong,
- "missing init (ZSTD_compressBegin)");
-
- if (frame && (cctx->stage==ZSTDcs_init)) {
- fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, &cctx->appliedParams,
- cctx->pledgedSrcSizePlusOne-1, cctx->dictID);
- FORWARD_IF_ERROR(fhSize, "ZSTD_writeFrameHeader failed");
- assert(fhSize <= dstCapacity);
- dstCapacity -= fhSize;
- dst = (char*)dst + fhSize;
- cctx->stage = ZSTDcs_ongoing;
- }
-
- if (!srcSize) return fhSize; /* do not generate an empty block if no input */
-
- if (!ZSTD_window_update(&ms->window, src, srcSize)) {
- ms->nextToUpdate = ms->window.dictLimit;
- }
- if (cctx->appliedParams.ldmParams.enableLdm) {
- ZSTD_window_update(&cctx->ldmState.window, src, srcSize);
- }
-
- if (!frame) {
- /* overflow check and correction for block mode */
- ZSTD_overflowCorrectIfNeeded(
- ms, &cctx->workspace, &cctx->appliedParams,
- src, (BYTE const*)src + srcSize);
- }
-
- DEBUGLOG(5, "ZSTD_compressContinue_internal (blockSize=%u)", (unsigned)cctx->blockSize);
- { size_t const cSize = frame ?
- ZSTD_compress_frameChunk (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) :
- ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize, 0 /* frame */);
- FORWARD_IF_ERROR(cSize, "%s", frame ? "ZSTD_compress_frameChunk failed" : "ZSTD_compressBlock_internal failed");
- cctx->consumedSrcSize += srcSize;
- cctx->producedCSize += (cSize + fhSize);
- assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0));
- if (cctx->pledgedSrcSizePlusOne != 0) { /* control src size */
- ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (unsigned long long)-1);
- RETURN_ERROR_IF(
- cctx->consumedSrcSize+1 > cctx->pledgedSrcSizePlusOne,
- srcSize_wrong,
- "error : pledgedSrcSize = %u, while realSrcSize >= %u",
- (unsigned)cctx->pledgedSrcSizePlusOne-1,
- (unsigned)cctx->consumedSrcSize);
- }
- return cSize + fhSize;
- }
-}
-
-size_t ZSTD_compressContinue (ZSTD_CCtx* cctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize)
-{
- DEBUGLOG(5, "ZSTD_compressContinue (srcSize=%u)", (unsigned)srcSize);
- return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 0 /* last chunk */);
-}
-
-
-size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx)
-{
- ZSTD_compressionParameters const cParams = cctx->appliedParams.cParams;
- assert(!ZSTD_checkCParams(cParams));
- return MIN (ZSTD_BLOCKSIZE_MAX, (U32)1 << cParams.windowLog);
-}
-
-size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
-{
- DEBUGLOG(5, "ZSTD_compressBlock: srcSize = %u", (unsigned)srcSize);
- { size_t const blockSizeMax = ZSTD_getBlockSize(cctx);
- RETURN_ERROR_IF(srcSize > blockSizeMax, srcSize_wrong, "input is larger than a block"); }
-
- return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0 /* frame mode */, 0 /* last chunk */);
-}
-
-/*! ZSTD_loadDictionaryContent() :
- * @return : 0, or an error code
- */
-static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms,
- ldmState_t* ls,
- ZSTD_cwksp* ws,
- ZSTD_CCtx_params const* params,
- const void* src, size_t srcSize,
- ZSTD_dictTableLoadMethod_e dtlm)
-{
- const BYTE* ip = (const BYTE*) src;
- const BYTE* const iend = ip + srcSize;
-
- ZSTD_window_update(&ms->window, src, srcSize);
- ms->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ms->window.base);
-
- if (params->ldmParams.enableLdm && ls != NULL) {
- ZSTD_window_update(&ls->window, src, srcSize);
- ls->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ls->window.base);
- }
-
- /* Assert that we the ms params match the params we're being given */
- ZSTD_assertEqualCParams(params->cParams, ms->cParams);
-
- if (srcSize <= HASH_READ_SIZE) return 0;
-
- while (iend - ip > HASH_READ_SIZE) {
- size_t const remaining = (size_t)(iend - ip);
- size_t const chunk = MIN(remaining, ZSTD_CHUNKSIZE_MAX);
- const BYTE* const ichunk = ip + chunk;
-
- ZSTD_overflowCorrectIfNeeded(ms, ws, params, ip, ichunk);
-
- if (params->ldmParams.enableLdm && ls != NULL)
- ZSTD_ldm_fillHashTable(ls, (const BYTE*)src, (const BYTE*)src + srcSize, &params->ldmParams);
-
- switch(params->cParams.strategy)
- {
- case ZSTD_fast:
- ZSTD_fillHashTable(ms, ichunk, dtlm);
- break;
- case ZSTD_dfast:
- ZSTD_fillDoubleHashTable(ms, ichunk, dtlm);
- break;
-
- case ZSTD_greedy:
- case ZSTD_lazy:
- case ZSTD_lazy2:
- if (chunk >= HASH_READ_SIZE)
- ZSTD_insertAndFindFirstIndex(ms, ichunk-HASH_READ_SIZE);
- break;
-
- case ZSTD_btlazy2: /* we want the dictionary table fully sorted */
- case ZSTD_btopt:
- case ZSTD_btultra:
- case ZSTD_btultra2:
- if (chunk >= HASH_READ_SIZE)
- ZSTD_updateTree(ms, ichunk-HASH_READ_SIZE, ichunk);
- break;
-
- default:
- assert(0); /* not possible : not a valid strategy id */
- }
-
- ip = ichunk;
- }
-
- ms->nextToUpdate = (U32)(iend - ms->window.base);
- return 0;
-}
-
-
-/* Dictionaries that assign zero probability to symbols that show up causes problems
- when FSE encoding. Refuse dictionaries that assign zero probability to symbols
- that we may encounter during compression.
- NOTE: This behavior is not standard and could be improved in the future. */
-static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) {
- U32 s;
- RETURN_ERROR_IF(dictMaxSymbolValue < maxSymbolValue, dictionary_corrupted, "dict fse tables don't have all symbols");
- for (s = 0; s <= maxSymbolValue; ++s) {
- RETURN_ERROR_IF(normalizedCounter[s] == 0, dictionary_corrupted, "dict fse tables don't have all symbols");
- }
- return 0;
-}
-
-size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace,
- short* offcodeNCount, unsigned* offcodeMaxValue,
- const void* const dict, size_t dictSize)
-{
- const BYTE* dictPtr = (const BYTE*)dict; /* skip magic num and dict ID */
- const BYTE* const dictEnd = dictPtr + dictSize;
- dictPtr += 8;
- bs->entropy.huf.repeatMode = HUF_repeat_check;
-
- { unsigned maxSymbolValue = 255;
- unsigned hasZeroWeights = 1;
- size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)bs->entropy.huf.CTable, &maxSymbolValue, dictPtr,
- dictEnd-dictPtr, &hasZeroWeights);
-
- /* We only set the loaded table as valid if it contains all non-zero
- * weights. Otherwise, we set it to check */
- if (!hasZeroWeights)
- bs->entropy.huf.repeatMode = HUF_repeat_valid;
-
- RETURN_ERROR_IF(HUF_isError(hufHeaderSize), dictionary_corrupted, "");
- RETURN_ERROR_IF(maxSymbolValue < 255, dictionary_corrupted, "");
- dictPtr += hufHeaderSize;
- }
-
- { unsigned offcodeLog;
- size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
- RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted, "");
- RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted, "");
- /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
- /* fill all offset symbols to avoid garbage at end of table */
- RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp(
- bs->entropy.fse.offcodeCTable,
- offcodeNCount, MaxOff, offcodeLog,
- workspace, HUF_WORKSPACE_SIZE)),
- dictionary_corrupted, "");
- dictPtr += offcodeHeaderSize;
- }
-
- { short matchlengthNCount[MaxML+1];
- unsigned matchlengthMaxValue = MaxML, matchlengthLog;
- size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
- RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted, "");
- RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted, "");
- /* Every match length code must have non-zero probability */
- FORWARD_IF_ERROR( ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML), "");
- RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp(
- bs->entropy.fse.matchlengthCTable,
- matchlengthNCount, matchlengthMaxValue, matchlengthLog,
- workspace, HUF_WORKSPACE_SIZE)),
- dictionary_corrupted, "");
- dictPtr += matchlengthHeaderSize;
- }
-
- { short litlengthNCount[MaxLL+1];
- unsigned litlengthMaxValue = MaxLL, litlengthLog;
- size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
- RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted, "");
- RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted, "");
- /* Every literal length code must have non-zero probability */
- FORWARD_IF_ERROR( ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL), "");
- RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp(
- bs->entropy.fse.litlengthCTable,
- litlengthNCount, litlengthMaxValue, litlengthLog,
- workspace, HUF_WORKSPACE_SIZE)),
- dictionary_corrupted, "");
- dictPtr += litlengthHeaderSize;
- }
-
- RETURN_ERROR_IF(dictPtr+12 > dictEnd, dictionary_corrupted, "");
- bs->rep[0] = MEM_readLE32(dictPtr+0);
- bs->rep[1] = MEM_readLE32(dictPtr+4);
- bs->rep[2] = MEM_readLE32(dictPtr+8);
- dictPtr += 12;
-
- return dictPtr - (const BYTE*)dict;
-}
-
-/* Dictionary format :
- * See :
- * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format
- */
-/*! ZSTD_loadZstdDictionary() :
- * @return : dictID, or an error code
- * assumptions : magic number supposed already checked
- * dictSize supposed >= 8
- */
-static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs,
- ZSTD_matchState_t* ms,
- ZSTD_cwksp* ws,
- ZSTD_CCtx_params const* params,
- const void* dict, size_t dictSize,
- ZSTD_dictTableLoadMethod_e dtlm,
- void* workspace)
-{
- const BYTE* dictPtr = (const BYTE*)dict;
- const BYTE* const dictEnd = dictPtr + dictSize;
- short offcodeNCount[MaxOff+1];
- unsigned offcodeMaxValue = MaxOff;
- size_t dictID;
- size_t eSize;
-
- ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog)));
- assert(dictSize >= 8);
- assert(MEM_readLE32(dictPtr) == ZSTD_MAGIC_DICTIONARY);
-
- dictID = params->fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr + 4 /* skip magic number */ );
- eSize = ZSTD_loadCEntropy(bs, workspace, offcodeNCount, &offcodeMaxValue, dict, dictSize);
- FORWARD_IF_ERROR(eSize, "ZSTD_loadCEntropy failed");
- dictPtr += eSize;
-
- { size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
- U32 offcodeMax = MaxOff;
- if (dictContentSize <= ((U32)-1) - 128 KB) {
- U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */
- offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */
- }
- /* All offset values <= dictContentSize + 128 KB must be representable */
- FORWARD_IF_ERROR(ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)), "");
- /* All repCodes must be <= dictContentSize and != 0*/
- { U32 u;
- for (u=0; u<3; u++) {
- RETURN_ERROR_IF(bs->rep[u] == 0, dictionary_corrupted, "");
- RETURN_ERROR_IF(bs->rep[u] > dictContentSize, dictionary_corrupted, "");
- } }
-
- bs->entropy.fse.offcode_repeatMode = FSE_repeat_valid;
- bs->entropy.fse.matchlength_repeatMode = FSE_repeat_valid;
- bs->entropy.fse.litlength_repeatMode = FSE_repeat_valid;
- FORWARD_IF_ERROR(ZSTD_loadDictionaryContent(
- ms, NULL, ws, params, dictPtr, dictContentSize, dtlm), "");
- return dictID;
- }
-}
-
-/** ZSTD_compress_insertDictionary() :
-* @return : dictID, or an error code */
-static size_t
-ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs,
- ZSTD_matchState_t* ms,
- ldmState_t* ls,
- ZSTD_cwksp* ws,
- const ZSTD_CCtx_params* params,
- const void* dict, size_t dictSize,
- ZSTD_dictContentType_e dictContentType,
- ZSTD_dictTableLoadMethod_e dtlm,
- void* workspace)
-{
- DEBUGLOG(4, "ZSTD_compress_insertDictionary (dictSize=%u)", (U32)dictSize);
- if ((dict==NULL) || (dictSize<8)) {
- RETURN_ERROR_IF(dictContentType == ZSTD_dct_fullDict, dictionary_wrong, "");
- return 0;
- }
-
- ZSTD_reset_compressedBlockState(bs);
-
- /* dict restricted modes */
- if (dictContentType == ZSTD_dct_rawContent)
- return ZSTD_loadDictionaryContent(ms, ls, ws, params, dict, dictSize, dtlm);
-
- if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) {
- if (dictContentType == ZSTD_dct_auto) {
- DEBUGLOG(4, "raw content dictionary detected");
- return ZSTD_loadDictionaryContent(
- ms, ls, ws, params, dict, dictSize, dtlm);
- }
- RETURN_ERROR_IF(dictContentType == ZSTD_dct_fullDict, dictionary_wrong, "");
- assert(0); /* impossible */
- }
-
- /* dict as full zstd dictionary */
- return ZSTD_loadZstdDictionary(
- bs, ms, ws, params, dict, dictSize, dtlm, workspace);
-}
-
-#define ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF (128 KB)
-#define ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER (6)
-
-/*! ZSTD_compressBegin_internal() :
- * @return : 0, or an error code */
-static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
- const void* dict, size_t dictSize,
- ZSTD_dictContentType_e dictContentType,
- ZSTD_dictTableLoadMethod_e dtlm,
- const ZSTD_CDict* cdict,
- const ZSTD_CCtx_params* params, U64 pledgedSrcSize,
- ZSTD_buffered_policy_e zbuff)
-{
- DEBUGLOG(4, "ZSTD_compressBegin_internal: wlog=%u", params->cParams.windowLog);
- /* params are supposed to be fully validated at this point */
- assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams)));
- assert(!((dict) && (cdict))); /* either dict or cdict, not both */
- if ( (cdict)
- && (cdict->dictContentSize > 0)
- && ( pledgedSrcSize < ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF
- || pledgedSrcSize < cdict->dictContentSize * ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER
- || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN
- || cdict->compressionLevel == 0)
- && (params->attachDictPref != ZSTD_dictForceLoad) ) {
- return ZSTD_resetCCtx_usingCDict(cctx, cdict, params, pledgedSrcSize, zbuff);
- }
-
- FORWARD_IF_ERROR( ZSTD_resetCCtx_internal(cctx, *params, pledgedSrcSize,
- ZSTDcrp_makeClean, zbuff) , "");
- { size_t const dictID = cdict ?
- ZSTD_compress_insertDictionary(
- cctx->blockState.prevCBlock, &cctx->blockState.matchState,
- &cctx->ldmState, &cctx->workspace, &cctx->appliedParams, cdict->dictContent,
- cdict->dictContentSize, dictContentType, dtlm,
- cctx->entropyWorkspace)
- : ZSTD_compress_insertDictionary(
- cctx->blockState.prevCBlock, &cctx->blockState.matchState,
- &cctx->ldmState, &cctx->workspace, &cctx->appliedParams, dict, dictSize,
- dictContentType, dtlm, cctx->entropyWorkspace);
- FORWARD_IF_ERROR(dictID, "ZSTD_compress_insertDictionary failed");
- assert(dictID <= UINT_MAX);
- cctx->dictID = (U32)dictID;
- }
- return 0;
-}
-
-size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx,
- const void* dict, size_t dictSize,
- ZSTD_dictContentType_e dictContentType,
- ZSTD_dictTableLoadMethod_e dtlm,
- const ZSTD_CDict* cdict,
- const ZSTD_CCtx_params* params,
- unsigned long long pledgedSrcSize)
-{
- DEBUGLOG(4, "ZSTD_compressBegin_advanced_internal: wlog=%u", params->cParams.windowLog);
- /* compression parameters verification and optimization */
- FORWARD_IF_ERROR( ZSTD_checkCParams(params->cParams) , "");
- return ZSTD_compressBegin_internal(cctx,
- dict, dictSize, dictContentType, dtlm,
- cdict,
- params, pledgedSrcSize,
- ZSTDb_not_buffered);
-}
-
-/*! ZSTD_compressBegin_advanced() :
-* @return : 0, or an error code */
-size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
- const void* dict, size_t dictSize,
- ZSTD_parameters params, unsigned long long pledgedSrcSize)
-{
- ZSTD_CCtx_params const cctxParams =
- ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, &params);
- return ZSTD_compressBegin_advanced_internal(cctx,
- dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast,
- NULL /*cdict*/,
- &cctxParams, pledgedSrcSize);
-}
-
-size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
-{
- ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize);
- ZSTD_CCtx_params const cctxParams =
- ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, &params);
- DEBUGLOG(4, "ZSTD_compressBegin_usingDict (dictSize=%u)", (unsigned)dictSize);
- return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL,
- &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered);
-}
-
-size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel)
-{
- return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel);
-}
-
-
-/*! ZSTD_writeEpilogue() :
-* Ends a frame.
-* @return : nb of bytes written into dst (or an error code) */
-static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
-{
- BYTE* const ostart = (BYTE*)dst;
- BYTE* op = ostart;
- size_t fhSize = 0;
-
- DEBUGLOG(4, "ZSTD_writeEpilogue");
- RETURN_ERROR_IF(cctx->stage == ZSTDcs_created, stage_wrong, "init missing");
-
- /* special case : empty frame */
- if (cctx->stage == ZSTDcs_init) {
- fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, &cctx->appliedParams, 0, 0);
- FORWARD_IF_ERROR(fhSize, "ZSTD_writeFrameHeader failed");
- dstCapacity -= fhSize;
- op += fhSize;
- cctx->stage = ZSTDcs_ongoing;
- }
-
- if (cctx->stage != ZSTDcs_ending) {
- /* write one last empty block, make it the "last" block */
- U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0;
- RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "no room for epilogue");
- MEM_writeLE32(op, cBlockHeader24);
- op += ZSTD_blockHeaderSize;
- dstCapacity -= ZSTD_blockHeaderSize;
- }
-
- if (cctx->appliedParams.fParams.checksumFlag) {
- U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
- RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "no room for checksum");
- DEBUGLOG(4, "ZSTD_writeEpilogue: write checksum : %08X", (unsigned)checksum);
- MEM_writeLE32(op, checksum);
- op += 4;
- }
-
- cctx->stage = ZSTDcs_created; /* return to "created but no init" status */
- return op-ostart;
-}
-
-size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize)
-{
- size_t endResult;
- size_t const cSize = ZSTD_compressContinue_internal(cctx,
- dst, dstCapacity, src, srcSize,
- 1 /* frame mode */, 1 /* last chunk */);
- FORWARD_IF_ERROR(cSize, "ZSTD_compressContinue_internal failed");
- endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize);
- FORWARD_IF_ERROR(endResult, "ZSTD_writeEpilogue failed");
- assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0));
- if (cctx->pledgedSrcSizePlusOne != 0) { /* control src size */
- ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (unsigned long long)-1);
- DEBUGLOG(4, "end of frame : controlling src size");
- RETURN_ERROR_IF(
- cctx->pledgedSrcSizePlusOne != cctx->consumedSrcSize+1,
- srcSize_wrong,
- "error : pledgedSrcSize = %u, while realSrcSize = %u",
- (unsigned)cctx->pledgedSrcSizePlusOne-1,
- (unsigned)cctx->consumedSrcSize);
- }
- return cSize + endResult;
-}
-
-
-static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- const void* dict,size_t dictSize,
- const ZSTD_parameters* params)
-{
- ZSTD_CCtx_params const cctxParams =
- ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, params);
- DEBUGLOG(4, "ZSTD_compress_internal");
- return ZSTD_compress_advanced_internal(cctx,
- dst, dstCapacity,
- src, srcSize,
- dict, dictSize,
- &cctxParams);
-}
-
-size_t ZSTD_compress_advanced (ZSTD_CCtx* cctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- const void* dict,size_t dictSize,
- ZSTD_parameters params)
-{
- DEBUGLOG(4, "ZSTD_compress_advanced");
- FORWARD_IF_ERROR(ZSTD_checkCParams(params.cParams), "");
- return ZSTD_compress_internal(cctx,
- dst, dstCapacity,
- src, srcSize,
- dict, dictSize,
- &params);
-}
-
-/* Internal */
-size_t ZSTD_compress_advanced_internal(
- ZSTD_CCtx* cctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- const void* dict,size_t dictSize,
- const ZSTD_CCtx_params* params)
-{
- DEBUGLOG(4, "ZSTD_compress_advanced_internal (srcSize:%u)", (unsigned)srcSize);
- FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx,
- dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL,
- params, srcSize, ZSTDb_not_buffered) , "");
- return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
-}
-
-size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- const void* dict, size_t dictSize,
- int compressionLevel)
-{
- ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, srcSize, dict ? dictSize : 0);
- ZSTD_CCtx_params cctxParams = ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, &params);
- DEBUGLOG(4, "ZSTD_compress_usingDict (srcSize=%u)", (unsigned)srcSize);
- assert(params.fParams.contentSizeFlag == 1);
- return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, &cctxParams);
-}
-
-size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- int compressionLevel)
-{
- DEBUGLOG(4, "ZSTD_compressCCtx (srcSize=%u)", (unsigned)srcSize);
- assert(cctx != NULL);
- return ZSTD_compress_usingDict(cctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
-}
-
-size_t ZSTD_compress(void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- int compressionLevel)
-{
- size_t result;
- ZSTD_CCtx ctxBody;
- ZSTD_initCCtx(&ctxBody, ZSTD_defaultCMem);
- result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
- ZSTD_freeCCtxContent(&ctxBody); /* can't free ctxBody itself, as it's on stack; free only heap content */
- return result;
-}
-
-
-/* ===== Dictionary API ===== */
-
-/*! ZSTD_estimateCDictSize_advanced() :
- * Estimate amount of memory that will be needed to create a dictionary with following arguments */
-size_t ZSTD_estimateCDictSize_advanced(
- size_t dictSize, ZSTD_compressionParameters cParams,
- ZSTD_dictLoadMethod_e dictLoadMethod)
-{
- DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (unsigned)sizeof(ZSTD_CDict));
- return ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict))
- + ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE)
- + ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0)
- + (dictLoadMethod == ZSTD_dlm_byRef ? 0
- : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void *))));
-}
-
-size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel)
-{
- ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize);
- return ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy);
-}
-
-size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict)
-{
- if (cdict==NULL) return 0; /* support sizeof on NULL */
- DEBUGLOG(5, "sizeof(*cdict) : %u", (unsigned)sizeof(*cdict));
- /* cdict may be in the workspace */
- return (cdict->workspace.workspace == cdict ? 0 : sizeof(*cdict))
- + ZSTD_cwksp_sizeof(&cdict->workspace);
-}
-
-static size_t ZSTD_initCDict_internal(
- ZSTD_CDict* cdict,
- const void* dictBuffer, size_t dictSize,
- ZSTD_dictLoadMethod_e dictLoadMethod,
- ZSTD_dictContentType_e dictContentType,
- ZSTD_compressionParameters cParams)
-{
- DEBUGLOG(3, "ZSTD_initCDict_internal (dictContentType:%u)", (unsigned)dictContentType);
- assert(!ZSTD_checkCParams(cParams));
- cdict->matchState.cParams = cParams;
- if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) {
- cdict->dictContent = dictBuffer;
- } else {
- void *internalBuffer = ZSTD_cwksp_reserve_object(&cdict->workspace, ZSTD_cwksp_align(dictSize, sizeof(void*)));
- RETURN_ERROR_IF(!internalBuffer, memory_allocation, "NULL pointer!");
- cdict->dictContent = internalBuffer;
- memcpy(internalBuffer, dictBuffer, dictSize);
- }
- cdict->dictContentSize = dictSize;
-
- cdict->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object(&cdict->workspace, HUF_WORKSPACE_SIZE);
-
-
- /* Reset the state to no dictionary */
- ZSTD_reset_compressedBlockState(&cdict->cBlockState);
- FORWARD_IF_ERROR(ZSTD_reset_matchState(
- &cdict->matchState,
- &cdict->workspace,
- &cParams,
- ZSTDcrp_makeClean,
- ZSTDirp_reset,
- ZSTD_resetTarget_CDict), "");
- /* (Maybe) load the dictionary
- * Skips loading the dictionary if it is < 8 bytes.
- */
- { ZSTD_CCtx_params params;
- memset(&params, 0, sizeof(params));
- params.compressionLevel = ZSTD_CLEVEL_DEFAULT;
- params.fParams.contentSizeFlag = 1;
- params.cParams = cParams;
- { size_t const dictID = ZSTD_compress_insertDictionary(
- &cdict->cBlockState, &cdict->matchState, NULL, &cdict->workspace,
- &params, cdict->dictContent, cdict->dictContentSize,
- dictContentType, ZSTD_dtlm_full, cdict->entropyWorkspace);
- FORWARD_IF_ERROR(dictID, "ZSTD_compress_insertDictionary failed");
- assert(dictID <= (size_t)(U32)-1);
- cdict->dictID = (U32)dictID;
- }
- }
-
- return 0;
-}
-
-ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize,
- ZSTD_dictLoadMethod_e dictLoadMethod,
- ZSTD_dictContentType_e dictContentType,
- ZSTD_compressionParameters cParams, ZSTD_customMem customMem)
-{
- DEBUGLOG(3, "ZSTD_createCDict_advanced, mode %u", (unsigned)dictContentType);
- if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
-
- { size_t const workspaceSize =
- ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict)) +
- ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE) +
- ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0) +
- (dictLoadMethod == ZSTD_dlm_byRef ? 0
- : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*))));
- void* const workspace = ZSTD_malloc(workspaceSize, customMem);
- ZSTD_cwksp ws;
- ZSTD_CDict* cdict;
-
- if (!workspace) {
- ZSTD_free(workspace, customMem);
- return NULL;
- }
-
- ZSTD_cwksp_init(&ws, workspace, workspaceSize);
-
- cdict = (ZSTD_CDict*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CDict));
- assert(cdict != NULL);
- ZSTD_cwksp_move(&cdict->workspace, &ws);
- cdict->customMem = customMem;
- cdict->compressionLevel = 0; /* signals advanced API usage */
-
- if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
- dictBuffer, dictSize,
- dictLoadMethod, dictContentType,
- cParams) )) {
- ZSTD_freeCDict(cdict);
- return NULL;
- }
-
- return cdict;
- }
-}
-
-ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)
-{
- ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize);
- ZSTD_CDict* cdict = ZSTD_createCDict_advanced(dict, dictSize,
- ZSTD_dlm_byCopy, ZSTD_dct_auto,
- cParams, ZSTD_defaultCMem);
- if (cdict)
- cdict->compressionLevel = compressionLevel == 0 ? ZSTD_CLEVEL_DEFAULT : compressionLevel;
- return cdict;
-}
-
-ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel)
-{
- ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize);
- return ZSTD_createCDict_advanced(dict, dictSize,
- ZSTD_dlm_byRef, ZSTD_dct_auto,
- cParams, ZSTD_defaultCMem);
-}
-
-size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
-{
- if (cdict==NULL) return 0; /* support free on NULL */
- { ZSTD_customMem const cMem = cdict->customMem;
- int cdictInWorkspace = ZSTD_cwksp_owns_buffer(&cdict->workspace, cdict);
- ZSTD_cwksp_free(&cdict->workspace, cMem);
- if (!cdictInWorkspace) {
- ZSTD_free(cdict, cMem);
- }
- return 0;
- }
-}
-
-/*! ZSTD_initStaticCDict_advanced() :
- * Generate a digested dictionary in provided memory area.
- * workspace: The memory area to emplace the dictionary into.
- * Provided pointer must 8-bytes aligned.
- * It must outlive dictionary usage.
- * workspaceSize: Use ZSTD_estimateCDictSize()
- * to determine how large workspace must be.
- * cParams : use ZSTD_getCParams() to transform a compression level
- * into its relevants cParams.
- * @return : pointer to ZSTD_CDict*, or NULL if error (size too small)
- * Note : there is no corresponding "free" function.
- * Since workspace was allocated externally, it must be freed externally.
- */
-const ZSTD_CDict* ZSTD_initStaticCDict(
- void* workspace, size_t workspaceSize,
- const void* dict, size_t dictSize,
- ZSTD_dictLoadMethod_e dictLoadMethod,
- ZSTD_dictContentType_e dictContentType,
- ZSTD_compressionParameters cParams)
-{
- size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0);
- size_t const neededSize = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict))
- + (dictLoadMethod == ZSTD_dlm_byRef ? 0
- : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*))))
- + ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE)
- + matchStateSize;
- ZSTD_CDict* cdict;
-
- if ((size_t)workspace & 7) return NULL; /* 8-aligned */
-
- {
- ZSTD_cwksp ws;
- ZSTD_cwksp_init(&ws, workspace, workspaceSize);
- cdict = (ZSTD_CDict*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CDict));
- if (cdict == NULL) return NULL;
- ZSTD_cwksp_move(&cdict->workspace, &ws);
- }
-
- DEBUGLOG(4, "(workspaceSize < neededSize) : (%u < %u) => %u",
- (unsigned)workspaceSize, (unsigned)neededSize, (unsigned)(workspaceSize < neededSize));
- if (workspaceSize < neededSize) return NULL;
-
- if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
- dict, dictSize,
- dictLoadMethod, dictContentType,
- cParams) ))
- return NULL;
-
- return cdict;
-}
-
-ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict)
-{
- assert(cdict != NULL);
- return cdict->matchState.cParams;
-}
-
-/* ZSTD_compressBegin_usingCDict_advanced() :
- * cdict must be != NULL */
-size_t ZSTD_compressBegin_usingCDict_advanced(
- ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict,
- ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize)
-{
- DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_advanced");
- RETURN_ERROR_IF(cdict==NULL, dictionary_wrong, "NULL pointer!");
- { ZSTD_CCtx_params params = cctx->requestedParams;
- params.cParams = ( pledgedSrcSize < ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF
- || pledgedSrcSize < cdict->dictContentSize * ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER
- || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN
- || cdict->compressionLevel == 0 )
- && (params.attachDictPref != ZSTD_dictForceLoad) ?
- ZSTD_getCParamsFromCDict(cdict)
- : ZSTD_getCParams(cdict->compressionLevel,
- pledgedSrcSize,
- cdict->dictContentSize);
- /* Increase window log to fit the entire dictionary and source if the
- * source size is known. Limit the increase to 19, which is the
- * window log for compression level 1 with the largest source size.
- */
- if (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN) {
- U32 const limitedSrcSize = (U32)MIN(pledgedSrcSize, 1U << 19);
- U32 const limitedSrcLog = limitedSrcSize > 1 ? ZSTD_highbit32(limitedSrcSize - 1) + 1 : 1;
- params.cParams.windowLog = MAX(params.cParams.windowLog, limitedSrcLog);
- }
- params.fParams = fParams;
- return ZSTD_compressBegin_internal(cctx,
- NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast,
- cdict,
- &params, pledgedSrcSize,
- ZSTDb_not_buffered);
- }
-}
-
-/* ZSTD_compressBegin_usingCDict() :
- * pledgedSrcSize=0 means "unknown"
- * if pledgedSrcSize>0, it will enable contentSizeFlag */
-size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
-{
- ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
- DEBUGLOG(4, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u", !fParams.noDictIDFlag);
- return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN);
-}
-
-size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- const ZSTD_CDict* cdict, ZSTD_frameParameters fParams)
-{
- FORWARD_IF_ERROR(ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, srcSize), ""); /* will check if cdict != NULL */
- return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
-}
-
-/*! ZSTD_compress_usingCDict() :
- * Compression using a digested Dictionary.
- * Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times.
- * Note that compression parameters are decided at CDict creation time
- * while frame parameters are hardcoded */
-size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- const ZSTD_CDict* cdict)
-{
- ZSTD_frameParameters const fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
- return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, fParams);
-}
-
-
-
-/* ******************************************************************
-* Streaming
-********************************************************************/
-
-ZSTD_CStream* ZSTD_createCStream(void)
-{
- DEBUGLOG(3, "ZSTD_createCStream");
- return ZSTD_createCStream_advanced(ZSTD_defaultCMem);
-}
-
-ZSTD_CStream* ZSTD_initStaticCStream(void *workspace, size_t workspaceSize)
-{
- return ZSTD_initStaticCCtx(workspace, workspaceSize);
-}
-
-ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem)
-{ /* CStream and CCtx are now same object */
- return ZSTD_createCCtx_advanced(customMem);
-}
-
-size_t ZSTD_freeCStream(ZSTD_CStream* zcs)
-{
- return ZSTD_freeCCtx(zcs); /* same object */
-}
-
-
-
-/*====== Initialization ======*/
-
-size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX; }
-
-size_t ZSTD_CStreamOutSize(void)
-{
- return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ;
-}
-
-static size_t ZSTD_resetCStream_internal(ZSTD_CStream* cctx,
- const void* const dict, size_t const dictSize, ZSTD_dictContentType_e const dictContentType,
- const ZSTD_CDict* const cdict,
- ZSTD_CCtx_params params, unsigned long long const pledgedSrcSize)
-{
- DEBUGLOG(4, "ZSTD_resetCStream_internal");
- /* Finalize the compression parameters */
- params.cParams = ZSTD_getCParamsFromCCtxParams(&params, pledgedSrcSize, dictSize);
- /* params are supposed to be fully validated at this point */
- assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
- assert(!((dict) && (cdict))); /* either dict or cdict, not both */
-
- FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx,
- dict, dictSize, dictContentType, ZSTD_dtlm_fast,
- cdict,
- &params, pledgedSrcSize,
- ZSTDb_buffered) , "");
-
- cctx->inToCompress = 0;
- cctx->inBuffPos = 0;
- cctx->inBuffTarget = cctx->blockSize
- + (cctx->blockSize == pledgedSrcSize); /* for small input: avoid automatic flush on reaching end of block, since it would require to add a 3-bytes null block to end frame */
- cctx->outBuffContentSize = cctx->outBuffFlushedSize = 0;
- cctx->streamStage = zcss_load;
- cctx->frameEnded = 0;
- return 0; /* ready to go */
-}
-
-/* ZSTD_resetCStream():
- * pledgedSrcSize == 0 means "unknown" */
-size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pss)
-{
- /* temporary : 0 interpreted as "unknown" during transition period.
- * Users willing to specify "unknown" **must** use ZSTD_CONTENTSIZE_UNKNOWN.
- * 0 will be interpreted as "empty" in the future.
- */
- U64 const pledgedSrcSize = (pss==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss;
- DEBUGLOG(4, "ZSTD_resetCStream: pledgedSrcSize = %u", (unsigned)pledgedSrcSize);
- FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
- FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , "");
- return 0;
-}
-
-/*! ZSTD_initCStream_internal() :
- * Note : for lib/compress only. Used by zstdmt_compress.c.
- * Assumption 1 : params are valid
- * Assumption 2 : either dict, or cdict, is defined, not both */
-size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
- const void* dict, size_t dictSize, const ZSTD_CDict* cdict,
- const ZSTD_CCtx_params* params,
- unsigned long long pledgedSrcSize)
-{
- DEBUGLOG(4, "ZSTD_initCStream_internal");
- FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
- FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , "");
- assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams)));
- zcs->requestedParams = *params;
- assert(!((dict) && (cdict))); /* either dict or cdict, not both */
- if (dict) {
- FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) , "");
- } else {
- /* Dictionary is cleared if !cdict */
- FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) , "");
- }
- return 0;
-}
-
-/* ZSTD_initCStream_usingCDict_advanced() :
- * same as ZSTD_initCStream_usingCDict(), with control over frame parameters */
-size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs,
- const ZSTD_CDict* cdict,
- ZSTD_frameParameters fParams,
- unsigned long long pledgedSrcSize)
-{
- DEBUGLOG(4, "ZSTD_initCStream_usingCDict_advanced");
- FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
- FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , "");
- zcs->requestedParams.fParams = fParams;
- FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) , "");
- return 0;
-}
-
-/* note : cdict must outlive compression session */
-size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict)
-{
- DEBUGLOG(4, "ZSTD_initCStream_usingCDict");
- FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
- FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) , "");
- return 0;
-}
-
-
-/* ZSTD_initCStream_advanced() :
- * pledgedSrcSize must be exact.
- * if srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN.
- * dict is loaded with default parameters ZSTD_dct_auto and ZSTD_dlm_byCopy. */
-size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
- const void* dict, size_t dictSize,
- ZSTD_parameters params, unsigned long long pss)
-{
- /* for compatibility with older programs relying on this behavior.
- * Users should now specify ZSTD_CONTENTSIZE_UNKNOWN.
- * This line will be removed in the future.
- */
- U64 const pledgedSrcSize = (pss==0 && params.fParams.contentSizeFlag==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss;
- DEBUGLOG(4, "ZSTD_initCStream_advanced");
- FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
- FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , "");
- FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) , "");
- zcs->requestedParams = ZSTD_assignParamsToCCtxParams(&zcs->requestedParams, &params);
- FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) , "");
- return 0;
-}
-
-size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel)
-{
- DEBUGLOG(4, "ZSTD_initCStream_usingDict");
- FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
- FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) , "");
- FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) , "");
- return 0;
-}
-
-size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pss)
-{
- /* temporary : 0 interpreted as "unknown" during transition period.
- * Users willing to specify "unknown" **must** use ZSTD_CONTENTSIZE_UNKNOWN.
- * 0 will be interpreted as "empty" in the future.
- */
- U64 const pledgedSrcSize = (pss==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss;
- DEBUGLOG(4, "ZSTD_initCStream_srcSize");
- FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
- FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, NULL) , "");
- FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) , "");
- FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , "");
- return 0;
-}
-
-size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel)
-{
- DEBUGLOG(4, "ZSTD_initCStream");
- FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
- FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, NULL) , "");
- FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) , "");
- return 0;
-}
-
-/*====== Compression ======*/
-
-static size_t ZSTD_nextInputSizeHint(const ZSTD_CCtx* cctx)
-{
- size_t hintInSize = cctx->inBuffTarget - cctx->inBuffPos;
- if (hintInSize==0) hintInSize = cctx->blockSize;
- return hintInSize;
-}
-
-/** ZSTD_compressStream_generic():
- * internal function for all *compressStream*() variants
- * non-static, because can be called from zstdmt_compress.c
- * @return : hint size for next input */
-static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
- ZSTD_outBuffer* output,
- ZSTD_inBuffer* input,
- ZSTD_EndDirective const flushMode)
-{
- const char* const istart = (const char*)input->src;
- const char* const iend = input->size != 0 ? istart + input->size : istart;
- const char* ip = input->pos != 0 ? istart + input->pos : istart;
- char* const ostart = (char*)output->dst;
- char* const oend = output->size != 0 ? ostart + output->size : ostart;
- char* op = output->pos != 0 ? ostart + output->pos : ostart;
- U32 someMoreWork = 1;
-
- /* check expectations */
- DEBUGLOG(5, "ZSTD_compressStream_generic, flush=%u", (unsigned)flushMode);
- assert(zcs->inBuff != NULL);
- assert(zcs->inBuffSize > 0);
- assert(zcs->outBuff != NULL);
- assert(zcs->outBuffSize > 0);
- assert(output->pos <= output->size);
- assert(input->pos <= input->size);
-
- while (someMoreWork) {
- switch(zcs->streamStage)
- {
- case zcss_init:
- RETURN_ERROR(init_missing, "call ZSTD_initCStream() first!");
-
- case zcss_load:
- if ( (flushMode == ZSTD_e_end)
- && ((size_t)(oend-op) >= ZSTD_compressBound(iend-ip)) /* enough dstCapacity */
- && (zcs->inBuffPos == 0) ) {
- /* shortcut to compression pass directly into output buffer */
- size_t const cSize = ZSTD_compressEnd(zcs,
- op, oend-op, ip, iend-ip);
- DEBUGLOG(4, "ZSTD_compressEnd : cSize=%u", (unsigned)cSize);
- FORWARD_IF_ERROR(cSize, "ZSTD_compressEnd failed");
- ip = iend;
- op += cSize;
- zcs->frameEnded = 1;
- ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
- someMoreWork = 0; break;
- }
- /* complete loading into inBuffer */
- { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
- size_t const loaded = ZSTD_limitCopy(
- zcs->inBuff + zcs->inBuffPos, toLoad,
- ip, iend-ip);
- zcs->inBuffPos += loaded;
- if (loaded != 0)
- ip += loaded;
- if ( (flushMode == ZSTD_e_continue)
- && (zcs->inBuffPos < zcs->inBuffTarget) ) {
- /* not enough input to fill full block : stop here */
- someMoreWork = 0; break;
- }
- if ( (flushMode == ZSTD_e_flush)
- && (zcs->inBuffPos == zcs->inToCompress) ) {
- /* empty */
- someMoreWork = 0; break;
- }
- }
- /* compress current block (note : this stage cannot be stopped in the middle) */
- DEBUGLOG(5, "stream compression stage (flushMode==%u)", flushMode);
- { void* cDst;
- size_t cSize;
- size_t const iSize = zcs->inBuffPos - zcs->inToCompress;
- size_t oSize = oend-op;
- unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend);
- if (oSize >= ZSTD_compressBound(iSize))
- cDst = op; /* compress into output buffer, to skip flush stage */
- else
- cDst = zcs->outBuff, oSize = zcs->outBuffSize;
- cSize = lastBlock ?
- ZSTD_compressEnd(zcs, cDst, oSize,
- zcs->inBuff + zcs->inToCompress, iSize) :
- ZSTD_compressContinue(zcs, cDst, oSize,
- zcs->inBuff + zcs->inToCompress, iSize);
- FORWARD_IF_ERROR(cSize, "%s", lastBlock ? "ZSTD_compressEnd failed" : "ZSTD_compressContinue failed");
- zcs->frameEnded = lastBlock;
- /* prepare next block */
- zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize;
- if (zcs->inBuffTarget > zcs->inBuffSize)
- zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize;
- DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u",
- (unsigned)zcs->inBuffTarget, (unsigned)zcs->inBuffSize);
- if (!lastBlock)
- assert(zcs->inBuffTarget <= zcs->inBuffSize);
- zcs->inToCompress = zcs->inBuffPos;
- if (cDst == op) { /* no need to flush */
- op += cSize;
- if (zcs->frameEnded) {
- DEBUGLOG(5, "Frame completed directly in outBuffer");
- someMoreWork = 0;
- ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
- }
- break;
- }
- zcs->outBuffContentSize = cSize;
- zcs->outBuffFlushedSize = 0;
- zcs->streamStage = zcss_flush; /* pass-through to flush stage */
- }
- /* fall-through */
- case zcss_flush:
- DEBUGLOG(5, "flush stage");
- { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
- size_t const flushed = ZSTD_limitCopy(op, (size_t)(oend-op),
- zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
- DEBUGLOG(5, "toFlush: %u into %u ==> flushed: %u",
- (unsigned)toFlush, (unsigned)(oend-op), (unsigned)flushed);
- if (flushed)
- op += flushed;
- zcs->outBuffFlushedSize += flushed;
- if (toFlush!=flushed) {
- /* flush not fully completed, presumably because dst is too small */
- assert(op==oend);
- someMoreWork = 0;
- break;
- }
- zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
- if (zcs->frameEnded) {
- DEBUGLOG(5, "Frame completed on flush");
- someMoreWork = 0;
- ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
- break;
- }
- zcs->streamStage = zcss_load;
- break;
- }
-
- default: /* impossible */
- assert(0);
- }
- }
-
- input->pos = ip - istart;
- output->pos = op - ostart;
- if (zcs->frameEnded) return 0;
- return ZSTD_nextInputSizeHint(zcs);
-}
-
-static size_t ZSTD_nextInputSizeHint_MTorST(const ZSTD_CCtx* cctx)
-{
-#ifdef ZSTD_MULTITHREAD
- if (cctx->appliedParams.nbWorkers >= 1) {
- assert(cctx->mtctx != NULL);
- return ZSTDMT_nextInputSizeHint(cctx->mtctx);
- }
-#endif
- return ZSTD_nextInputSizeHint(cctx);
-
-}
-
-size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
-{
- FORWARD_IF_ERROR( ZSTD_compressStream2(zcs, output, input, ZSTD_e_continue) , "");
- return ZSTD_nextInputSizeHint_MTorST(zcs);
-}
-
-
-size_t ZSTD_compressStream2( ZSTD_CCtx* cctx,
- ZSTD_outBuffer* output,
- ZSTD_inBuffer* input,
- ZSTD_EndDirective endOp)
-{
- DEBUGLOG(5, "ZSTD_compressStream2, endOp=%u ", (unsigned)endOp);
- /* check conditions */
- RETURN_ERROR_IF(output->pos > output->size, GENERIC, "invalid buffer");
- RETURN_ERROR_IF(input->pos > input->size, GENERIC, "invalid buffer");
- assert(cctx!=NULL);
-
- /* transparent initialization stage */
- if (cctx->streamStage == zcss_init) {
- ZSTD_CCtx_params params = cctx->requestedParams;
- ZSTD_prefixDict const prefixDict = cctx->prefixDict;
- FORWARD_IF_ERROR( ZSTD_initLocalDict(cctx) , ""); /* Init the local dict if present. */
- memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* single usage */
- assert(prefixDict.dict==NULL || cctx->cdict==NULL); /* only one can be set */
- DEBUGLOG(4, "ZSTD_compressStream2 : transparent init stage");
- if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = input->size + 1; /* auto-fix pledgedSrcSize */
- params.cParams = ZSTD_getCParamsFromCCtxParams(
- &cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/);
-
-
-#ifdef ZSTD_MULTITHREAD
- if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN) {
- params.nbWorkers = 0; /* do not invoke multi-threading when src size is too small */
- }
- if (params.nbWorkers > 0) {
- /* mt context creation */
- if (cctx->mtctx == NULL) {
- DEBUGLOG(4, "ZSTD_compressStream2: creating new mtctx for nbWorkers=%u",
- params.nbWorkers);
- cctx->mtctx = ZSTDMT_createCCtx_advanced((U32)params.nbWorkers, cctx->customMem);
- RETURN_ERROR_IF(cctx->mtctx == NULL, memory_allocation, "NULL pointer!");
- }
- /* mt compression */
- DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbWorkers=%u", params.nbWorkers);
- FORWARD_IF_ERROR( ZSTDMT_initCStream_internal(
- cctx->mtctx,
- prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType,
- cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) , "");
- cctx->streamStage = zcss_load;
- cctx->appliedParams.nbWorkers = params.nbWorkers;
- } else
-#endif
- { FORWARD_IF_ERROR( ZSTD_resetCStream_internal(cctx,
- prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType,
- cctx->cdict,
- params, cctx->pledgedSrcSizePlusOne-1) , "");
- assert(cctx->streamStage == zcss_load);
- assert(cctx->appliedParams.nbWorkers == 0);
- } }
- /* end of transparent initialization stage */
-
- /* compression stage */
-#ifdef ZSTD_MULTITHREAD
- if (cctx->appliedParams.nbWorkers > 0) {
- int const forceMaxProgress = (endOp == ZSTD_e_flush || endOp == ZSTD_e_end);
- size_t flushMin;
- assert(forceMaxProgress || endOp == ZSTD_e_continue /* Protection for a new flush type */);
- if (cctx->cParamsChanged) {
- ZSTDMT_updateCParams_whileCompressing(cctx->mtctx, &cctx->requestedParams);
- cctx->cParamsChanged = 0;
- }
- do {
- flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp);
- if ( ZSTD_isError(flushMin)
- || (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */
- ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only);
- }
- FORWARD_IF_ERROR(flushMin, "ZSTDMT_compressStream_generic failed");
- } while (forceMaxProgress && flushMin != 0 && output->pos < output->size);
- DEBUGLOG(5, "completed ZSTD_compressStream2 delegating to ZSTDMT_compressStream_generic");
- /* Either we don't require maximum forward progress, we've finished the
- * flush, or we are out of output space.
- */
- assert(!forceMaxProgress || flushMin == 0 || output->pos == output->size);
- return flushMin;
- }
-#endif
- FORWARD_IF_ERROR( ZSTD_compressStream_generic(cctx, output, input, endOp) , "");
- DEBUGLOG(5, "completed ZSTD_compressStream2");
- return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */
-}
-
-size_t ZSTD_compressStream2_simpleArgs (
- ZSTD_CCtx* cctx,
- void* dst, size_t dstCapacity, size_t* dstPos,
- const void* src, size_t srcSize, size_t* srcPos,
- ZSTD_EndDirective endOp)
-{
- ZSTD_outBuffer output = { dst, dstCapacity, *dstPos };
- ZSTD_inBuffer input = { src, srcSize, *srcPos };
- /* ZSTD_compressStream2() will check validity of dstPos and srcPos */
- size_t const cErr = ZSTD_compressStream2(cctx, &output, &input, endOp);
- *dstPos = output.pos;
- *srcPos = input.pos;
- return cErr;
-}
-
-size_t ZSTD_compress2(ZSTD_CCtx* cctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize)
-{
- DEBUGLOG(4, "ZSTD_compress2 (srcSize=%u)", (unsigned)srcSize);
- ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only);
- { size_t oPos = 0;
- size_t iPos = 0;
- size_t const result = ZSTD_compressStream2_simpleArgs(cctx,
- dst, dstCapacity, &oPos,
- src, srcSize, &iPos,
- ZSTD_e_end);
- FORWARD_IF_ERROR(result, "ZSTD_compressStream2_simpleArgs failed");
- if (result != 0) { /* compression not completed, due to lack of output space */
- assert(oPos == dstCapacity);
- RETURN_ERROR(dstSize_tooSmall, "");
- }
- assert(iPos == srcSize); /* all input is expected consumed */
- return oPos;
- }
-}
-
-/*====== Finalize ======*/
-
-/*! ZSTD_flushStream() :
- * @return : amount of data remaining to flush */
-size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
-{
- ZSTD_inBuffer input = { NULL, 0, 0 };
- return ZSTD_compressStream2(zcs, output, &input, ZSTD_e_flush);
-}
-
-
-size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
-{
- ZSTD_inBuffer input = { NULL, 0, 0 };
- size_t const remainingToFlush = ZSTD_compressStream2(zcs, output, &input, ZSTD_e_end);
- FORWARD_IF_ERROR( remainingToFlush , "ZSTD_compressStream2 failed");
- if (zcs->appliedParams.nbWorkers > 0) return remainingToFlush; /* minimal estimation */
- /* single thread mode : attempt to calculate remaining to flush more precisely */
- { size_t const lastBlockSize = zcs->frameEnded ? 0 : ZSTD_BLOCKHEADERSIZE;
- size_t const checksumSize = (size_t)(zcs->frameEnded ? 0 : zcs->appliedParams.fParams.checksumFlag * 4);
- size_t const toFlush = remainingToFlush + lastBlockSize + checksumSize;
- DEBUGLOG(4, "ZSTD_endStream : remaining to flush : %u", (unsigned)toFlush);
- return toFlush;
- }
-}
-
-
-/*-===== Pre-defined compression levels =====-*/
-
-#define ZSTD_MAX_CLEVEL 22
-int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
-int ZSTD_minCLevel(void) { return (int)-ZSTD_TARGETLENGTH_MAX; }
-
-static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
-{ /* "default" - for any srcSize > 256 KB */
- /* W, C, H, S, L, TL, strat */
- { 19, 12, 13, 1, 6, 1, ZSTD_fast }, /* base for negative levels */
- { 19, 13, 14, 1, 7, 0, ZSTD_fast }, /* level 1 */
- { 20, 15, 16, 1, 6, 0, ZSTD_fast }, /* level 2 */
- { 21, 16, 17, 1, 5, 0, ZSTD_dfast }, /* level 3 */
- { 21, 18, 18, 1, 5, 0, ZSTD_dfast }, /* level 4 */
- { 21, 18, 19, 2, 5, 2, ZSTD_greedy }, /* level 5 */
- { 21, 19, 19, 3, 5, 4, ZSTD_greedy }, /* level 6 */
- { 21, 19, 19, 3, 5, 8, ZSTD_lazy }, /* level 7 */
- { 21, 19, 19, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */
- { 21, 19, 20, 4, 5, 16, ZSTD_lazy2 }, /* level 9 */
- { 22, 20, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */
- { 22, 21, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */
- { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
- { 22, 21, 22, 5, 5, 32, ZSTD_btlazy2 }, /* level 13 */
- { 22, 22, 23, 5, 5, 32, ZSTD_btlazy2 }, /* level 14 */
- { 22, 23, 23, 6, 5, 32, ZSTD_btlazy2 }, /* level 15 */
- { 22, 22, 22, 5, 5, 48, ZSTD_btopt }, /* level 16 */
- { 23, 23, 22, 5, 4, 64, ZSTD_btopt }, /* level 17 */
- { 23, 23, 22, 6, 3, 64, ZSTD_btultra }, /* level 18 */
- { 23, 24, 22, 7, 3,256, ZSTD_btultra2}, /* level 19 */
- { 25, 25, 23, 7, 3,256, ZSTD_btultra2}, /* level 20 */
- { 26, 26, 24, 7, 3,512, ZSTD_btultra2}, /* level 21 */
- { 27, 27, 25, 9, 3,999, ZSTD_btultra2}, /* level 22 */
-},
-{ /* for srcSize <= 256 KB */
- /* W, C, H, S, L, T, strat */
- { 18, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */
- { 18, 13, 14, 1, 6, 0, ZSTD_fast }, /* level 1 */
- { 18, 14, 14, 1, 5, 0, ZSTD_dfast }, /* level 2 */
- { 18, 16, 16, 1, 4, 0, ZSTD_dfast }, /* level 3 */
- { 18, 16, 17, 2, 5, 2, ZSTD_greedy }, /* level 4.*/
- { 18, 18, 18, 3, 5, 2, ZSTD_greedy }, /* level 5.*/
- { 18, 18, 19, 3, 5, 4, ZSTD_lazy }, /* level 6.*/
- { 18, 18, 19, 4, 4, 4, ZSTD_lazy }, /* level 7 */
- { 18, 18, 19, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
- { 18, 18, 19, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
- { 18, 18, 19, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
- { 18, 18, 19, 5, 4, 12, ZSTD_btlazy2 }, /* level 11.*/
- { 18, 19, 19, 7, 4, 12, ZSTD_btlazy2 }, /* level 12.*/
- { 18, 18, 19, 4, 4, 16, ZSTD_btopt }, /* level 13 */
- { 18, 18, 19, 4, 3, 32, ZSTD_btopt }, /* level 14.*/
- { 18, 18, 19, 6, 3,128, ZSTD_btopt }, /* level 15.*/
- { 18, 19, 19, 6, 3,128, ZSTD_btultra }, /* level 16.*/
- { 18, 19, 19, 8, 3,256, ZSTD_btultra }, /* level 17.*/
- { 18, 19, 19, 6, 3,128, ZSTD_btultra2}, /* level 18.*/
- { 18, 19, 19, 8, 3,256, ZSTD_btultra2}, /* level 19.*/
- { 18, 19, 19, 10, 3,512, ZSTD_btultra2}, /* level 20.*/
- { 18, 19, 19, 12, 3,512, ZSTD_btultra2}, /* level 21.*/
- { 18, 19, 19, 13, 3,999, ZSTD_btultra2}, /* level 22.*/
-},
-{ /* for srcSize <= 128 KB */
- /* W, C, H, S, L, T, strat */
- { 17, 12, 12, 1, 5, 1, ZSTD_fast }, /* base for negative levels */
- { 17, 12, 13, 1, 6, 0, ZSTD_fast }, /* level 1 */
- { 17, 13, 15, 1, 5, 0, ZSTD_fast }, /* level 2 */
- { 17, 15, 16, 2, 5, 0, ZSTD_dfast }, /* level 3 */
- { 17, 17, 17, 2, 4, 0, ZSTD_dfast }, /* level 4 */
- { 17, 16, 17, 3, 4, 2, ZSTD_greedy }, /* level 5 */
- { 17, 17, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */
- { 17, 17, 17, 3, 4, 8, ZSTD_lazy2 }, /* level 7 */
- { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
- { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
- { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
- { 17, 17, 17, 5, 4, 8, ZSTD_btlazy2 }, /* level 11 */
- { 17, 18, 17, 7, 4, 12, ZSTD_btlazy2 }, /* level 12 */
- { 17, 18, 17, 3, 4, 12, ZSTD_btopt }, /* level 13.*/
- { 17, 18, 17, 4, 3, 32, ZSTD_btopt }, /* level 14.*/
- { 17, 18, 17, 6, 3,256, ZSTD_btopt }, /* level 15.*/
- { 17, 18, 17, 6, 3,128, ZSTD_btultra }, /* level 16.*/
- { 17, 18, 17, 8, 3,256, ZSTD_btultra }, /* level 17.*/
- { 17, 18, 17, 10, 3,512, ZSTD_btultra }, /* level 18.*/
- { 17, 18, 17, 5, 3,256, ZSTD_btultra2}, /* level 19.*/
- { 17, 18, 17, 7, 3,512, ZSTD_btultra2}, /* level 20.*/
- { 17, 18, 17, 9, 3,512, ZSTD_btultra2}, /* level 21.*/
- { 17, 18, 17, 11, 3,999, ZSTD_btultra2}, /* level 22.*/
-},
-{ /* for srcSize <= 16 KB */
- /* W, C, H, S, L, T, strat */
- { 14, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */
- { 14, 14, 15, 1, 5, 0, ZSTD_fast }, /* level 1 */
- { 14, 14, 15, 1, 4, 0, ZSTD_fast }, /* level 2 */
- { 14, 14, 15, 2, 4, 0, ZSTD_dfast }, /* level 3 */
- { 14, 14, 14, 4, 4, 2, ZSTD_greedy }, /* level 4 */
- { 14, 14, 14, 3, 4, 4, ZSTD_lazy }, /* level 5.*/
- { 14, 14, 14, 4, 4, 8, ZSTD_lazy2 }, /* level 6 */
- { 14, 14, 14, 6, 4, 8, ZSTD_lazy2 }, /* level 7 */
- { 14, 14, 14, 8, 4, 8, ZSTD_lazy2 }, /* level 8.*/
- { 14, 15, 14, 5, 4, 8, ZSTD_btlazy2 }, /* level 9.*/
- { 14, 15, 14, 9, 4, 8, ZSTD_btlazy2 }, /* level 10.*/
- { 14, 15, 14, 3, 4, 12, ZSTD_btopt }, /* level 11.*/
- { 14, 15, 14, 4, 3, 24, ZSTD_btopt }, /* level 12.*/
- { 14, 15, 14, 5, 3, 32, ZSTD_btultra }, /* level 13.*/
- { 14, 15, 15, 6, 3, 64, ZSTD_btultra }, /* level 14.*/
- { 14, 15, 15, 7, 3,256, ZSTD_btultra }, /* level 15.*/
- { 14, 15, 15, 5, 3, 48, ZSTD_btultra2}, /* level 16.*/
- { 14, 15, 15, 6, 3,128, ZSTD_btultra2}, /* level 17.*/
- { 14, 15, 15, 7, 3,256, ZSTD_btultra2}, /* level 18.*/
- { 14, 15, 15, 8, 3,256, ZSTD_btultra2}, /* level 19.*/
- { 14, 15, 15, 8, 3,512, ZSTD_btultra2}, /* level 20.*/
- { 14, 15, 15, 9, 3,512, ZSTD_btultra2}, /* level 21.*/
- { 14, 15, 15, 10, 3,999, ZSTD_btultra2}, /* level 22.*/
-},
-};
-
-/*! ZSTD_getCParams_internal() :
- * @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize.
- * Note: srcSizeHint 0 means 0, use ZSTD_CONTENTSIZE_UNKNOWN for unknown.
- * Use dictSize == 0 for unknown or unused. */
-static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize)
-{
- int const unknown = srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN;
- size_t const addedSize = unknown && dictSize > 0 ? 500 : 0;
- U64 const rSize = unknown && dictSize == 0 ? ZSTD_CONTENTSIZE_UNKNOWN : srcSizeHint+dictSize+addedSize;
- U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB);
- int row = compressionLevel;
- DEBUGLOG(5, "ZSTD_getCParams_internal (cLevel=%i)", compressionLevel);
- if (compressionLevel == 0) row = ZSTD_CLEVEL_DEFAULT; /* 0 == default */
- if (compressionLevel < 0) row = 0; /* entry 0 is baseline for fast mode */
- if (compressionLevel > ZSTD_MAX_CLEVEL) row = ZSTD_MAX_CLEVEL;
- { ZSTD_compressionParameters cp = ZSTD_defaultCParameters[tableID][row];
- if (compressionLevel < 0) cp.targetLength = (unsigned)(-compressionLevel); /* acceleration factor */
- /* refine parameters based on srcSize & dictSize */
- return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize);
- }
-}
-
-/*! ZSTD_getCParams() :
- * @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize.
- * Size values are optional, provide 0 if not known or unused */
-ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize)
-{
- if (srcSizeHint == 0) srcSizeHint = ZSTD_CONTENTSIZE_UNKNOWN;
- return ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize);
-}
-
-/*! ZSTD_getParams() :
- * same idea as ZSTD_getCParams()
- * @return a `ZSTD_parameters` structure (instead of `ZSTD_compressionParameters`).
- * Fields of `ZSTD_frameParameters` are set to default values */
-static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) {
- ZSTD_parameters params;
- ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize);
- DEBUGLOG(5, "ZSTD_getParams (cLevel=%i)", compressionLevel);
- memset(&params, 0, sizeof(params));
- params.cParams = cParams;
- params.fParams.contentSizeFlag = 1;
- return params;
-}
-
-/*! ZSTD_getParams() :
- * same idea as ZSTD_getCParams()
- * @return a `ZSTD_parameters` structure (instead of `ZSTD_compressionParameters`).
- * Fields of `ZSTD_frameParameters` are set to default values */
-ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) {
- if (srcSizeHint == 0) srcSizeHint = ZSTD_CONTENTSIZE_UNKNOWN;
- return ZSTD_getParams_internal(compressionLevel, srcSizeHint, dictSize);
-}
-/**** ended inlining compress/zstd_compress.c ****/
-/**** start inlining compress/zstd_double_fast.c ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-/**** skipping file: zstd_compress_internal.h ****/
-/**** skipping file: zstd_double_fast.h ****/
-
-
-void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms,
- void const* end, ZSTD_dictTableLoadMethod_e dtlm)
-{
- const ZSTD_compressionParameters* const cParams = &ms->cParams;
- U32* const hashLarge = ms->hashTable;
- U32 const hBitsL = cParams->hashLog;
- U32 const mls = cParams->minMatch;
- U32* const hashSmall = ms->chainTable;
- U32 const hBitsS = cParams->chainLog;
- const BYTE* const base = ms->window.base;
- const BYTE* ip = base + ms->nextToUpdate;
- const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
- const U32 fastHashFillStep = 3;
-
- /* Always insert every fastHashFillStep position into the hash tables.
- * Insert the other positions into the large hash table if their entry
- * is empty.
- */
- for (; ip + fastHashFillStep - 1 <= iend; ip += fastHashFillStep) {
- U32 const current = (U32)(ip - base);
- U32 i;
- for (i = 0; i < fastHashFillStep; ++i) {
- size_t const smHash = ZSTD_hashPtr(ip + i, hBitsS, mls);
- size_t const lgHash = ZSTD_hashPtr(ip + i, hBitsL, 8);
- if (i == 0)
- hashSmall[smHash] = current + i;
- if (i == 0 || hashLarge[lgHash] == 0)
- hashLarge[lgHash] = current + i;
- /* Only load extra positions for ZSTD_dtlm_full */
- if (dtlm == ZSTD_dtlm_fast)
- break;
- } }
-}
-
-
-FORCE_INLINE_TEMPLATE
-size_t ZSTD_compressBlock_doubleFast_generic(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize,
- U32 const mls /* template */, ZSTD_dictMode_e const dictMode)
-{
- ZSTD_compressionParameters const* cParams = &ms->cParams;
- U32* const hashLong = ms->hashTable;
- const U32 hBitsL = cParams->hashLog;
- U32* const hashSmall = ms->chainTable;
- const U32 hBitsS = cParams->chainLog;
- const BYTE* const base = ms->window.base;
- const BYTE* const istart = (const BYTE*)src;
- const BYTE* ip = istart;
- const BYTE* anchor = istart;
- const U32 endIndex = (U32)((size_t)(istart - base) + srcSize);
- /* presumes that, if there is a dictionary, it must be using Attach mode */
- const U32 prefixLowestIndex = ZSTD_getLowestPrefixIndex(ms, endIndex, cParams->windowLog);
- const BYTE* const prefixLowest = base + prefixLowestIndex;
- const BYTE* const iend = istart + srcSize;
- const BYTE* const ilimit = iend - HASH_READ_SIZE;
- U32 offset_1=rep[0], offset_2=rep[1];
- U32 offsetSaved = 0;
-
- const ZSTD_matchState_t* const dms = ms->dictMatchState;
- const ZSTD_compressionParameters* const dictCParams =
- dictMode == ZSTD_dictMatchState ?
- &dms->cParams : NULL;
- const U32* const dictHashLong = dictMode == ZSTD_dictMatchState ?
- dms->hashTable : NULL;
- const U32* const dictHashSmall = dictMode == ZSTD_dictMatchState ?
- dms->chainTable : NULL;
- const U32 dictStartIndex = dictMode == ZSTD_dictMatchState ?
- dms->window.dictLimit : 0;
- const BYTE* const dictBase = dictMode == ZSTD_dictMatchState ?
- dms->window.base : NULL;
- const BYTE* const dictStart = dictMode == ZSTD_dictMatchState ?
- dictBase + dictStartIndex : NULL;
- const BYTE* const dictEnd = dictMode == ZSTD_dictMatchState ?
- dms->window.nextSrc : NULL;
- const U32 dictIndexDelta = dictMode == ZSTD_dictMatchState ?
- prefixLowestIndex - (U32)(dictEnd - dictBase) :
- 0;
- const U32 dictHBitsL = dictMode == ZSTD_dictMatchState ?
- dictCParams->hashLog : hBitsL;
- const U32 dictHBitsS = dictMode == ZSTD_dictMatchState ?
- dictCParams->chainLog : hBitsS;
- const U32 dictAndPrefixLength = (U32)((ip - prefixLowest) + (dictEnd - dictStart));
-
- DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_generic");
-
- assert(dictMode == ZSTD_noDict || dictMode == ZSTD_dictMatchState);
-
- /* if a dictionary is attached, it must be within window range */
- if (dictMode == ZSTD_dictMatchState) {
- assert(ms->window.dictLimit + (1U << cParams->windowLog) >= endIndex);
- }
-
- /* init */
- ip += (dictAndPrefixLength == 0);
- if (dictMode == ZSTD_noDict) {
- U32 const current = (U32)(ip - base);
- U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, current, cParams->windowLog);
- U32 const maxRep = current - windowLow;
- if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
- if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
- }
- if (dictMode == ZSTD_dictMatchState) {
- /* dictMatchState repCode checks don't currently handle repCode == 0
- * disabling. */
- assert(offset_1 <= dictAndPrefixLength);
- assert(offset_2 <= dictAndPrefixLength);
- }
-
- /* Main Search Loop */
- while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
- size_t mLength;
- U32 offset;
- size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
- size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
- size_t const dictHL = ZSTD_hashPtr(ip, dictHBitsL, 8);
- size_t const dictHS = ZSTD_hashPtr(ip, dictHBitsS, mls);
- U32 const current = (U32)(ip-base);
- U32 const matchIndexL = hashLong[h2];
- U32 matchIndexS = hashSmall[h];
- const BYTE* matchLong = base + matchIndexL;
- const BYTE* match = base + matchIndexS;
- const U32 repIndex = current + 1 - offset_1;
- const BYTE* repMatch = (dictMode == ZSTD_dictMatchState
- && repIndex < prefixLowestIndex) ?
- dictBase + (repIndex - dictIndexDelta) :
- base + repIndex;
- hashLong[h2] = hashSmall[h] = current; /* update hash tables */
-
- /* check dictMatchState repcode */
- if (dictMode == ZSTD_dictMatchState
- && ((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */)
- && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
- const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend;
- mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4;
- ip++;
- ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, 0, mLength-MINMATCH);
- goto _match_stored;
- }
-
- /* check noDict repcode */
- if ( dictMode == ZSTD_noDict
- && ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)))) {
- mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
- ip++;
- ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, 0, mLength-MINMATCH);
- goto _match_stored;
- }
-
- if (matchIndexL > prefixLowestIndex) {
- /* check prefix long match */
- if (MEM_read64(matchLong) == MEM_read64(ip)) {
- mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
- offset = (U32)(ip-matchLong);
- while (((ip>anchor) & (matchLong>prefixLowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
- goto _match_found;
- }
- } else if (dictMode == ZSTD_dictMatchState) {
- /* check dictMatchState long match */
- U32 const dictMatchIndexL = dictHashLong[dictHL];
- const BYTE* dictMatchL = dictBase + dictMatchIndexL;
- assert(dictMatchL < dictEnd);
-
- if (dictMatchL > dictStart && MEM_read64(dictMatchL) == MEM_read64(ip)) {
- mLength = ZSTD_count_2segments(ip+8, dictMatchL+8, iend, dictEnd, prefixLowest) + 8;
- offset = (U32)(current - dictMatchIndexL - dictIndexDelta);
- while (((ip>anchor) & (dictMatchL>dictStart)) && (ip[-1] == dictMatchL[-1])) { ip--; dictMatchL--; mLength++; } /* catch up */
- goto _match_found;
- } }
-
- if (matchIndexS > prefixLowestIndex) {
- /* check prefix short match */
- if (MEM_read32(match) == MEM_read32(ip)) {
- goto _search_next_long;
- }
- } else if (dictMode == ZSTD_dictMatchState) {
- /* check dictMatchState short match */
- U32 const dictMatchIndexS = dictHashSmall[dictHS];
- match = dictBase + dictMatchIndexS;
- matchIndexS = dictMatchIndexS + dictIndexDelta;
-
- if (match > dictStart && MEM_read32(match) == MEM_read32(ip)) {
- goto _search_next_long;
- } }
-
- ip += ((ip-anchor) >> kSearchStrength) + 1;
-#if defined(__aarch64__)
- PREFETCH_L1(ip+256);
-#endif
- continue;
-
-_search_next_long:
-
- { size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
- size_t const dictHLNext = ZSTD_hashPtr(ip+1, dictHBitsL, 8);
- U32 const matchIndexL3 = hashLong[hl3];
- const BYTE* matchL3 = base + matchIndexL3;
- hashLong[hl3] = current + 1;
-
- /* check prefix long +1 match */
- if (matchIndexL3 > prefixLowestIndex) {
- if (MEM_read64(matchL3) == MEM_read64(ip+1)) {
- mLength = ZSTD_count(ip+9, matchL3+8, iend) + 8;
- ip++;
- offset = (U32)(ip-matchL3);
- while (((ip>anchor) & (matchL3>prefixLowest)) && (ip[-1] == matchL3[-1])) { ip--; matchL3--; mLength++; } /* catch up */
- goto _match_found;
- }
- } else if (dictMode == ZSTD_dictMatchState) {
- /* check dict long +1 match */
- U32 const dictMatchIndexL3 = dictHashLong[dictHLNext];
- const BYTE* dictMatchL3 = dictBase + dictMatchIndexL3;
- assert(dictMatchL3 < dictEnd);
- if (dictMatchL3 > dictStart && MEM_read64(dictMatchL3) == MEM_read64(ip+1)) {
- mLength = ZSTD_count_2segments(ip+1+8, dictMatchL3+8, iend, dictEnd, prefixLowest) + 8;
- ip++;
- offset = (U32)(current + 1 - dictMatchIndexL3 - dictIndexDelta);
- while (((ip>anchor) & (dictMatchL3>dictStart)) && (ip[-1] == dictMatchL3[-1])) { ip--; dictMatchL3--; mLength++; } /* catch up */
- goto _match_found;
- } } }
-
- /* if no long +1 match, explore the short match we found */
- if (dictMode == ZSTD_dictMatchState && matchIndexS < prefixLowestIndex) {
- mLength = ZSTD_count_2segments(ip+4, match+4, iend, dictEnd, prefixLowest) + 4;
- offset = (U32)(current - matchIndexS);
- while (((ip>anchor) & (match>dictStart)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
- } else {
- mLength = ZSTD_count(ip+4, match+4, iend) + 4;
- offset = (U32)(ip - match);
- while (((ip>anchor) & (match>prefixLowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
- }
-
- /* fall-through */
-
-_match_found:
- offset_2 = offset_1;
- offset_1 = offset;
-
- ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
-
-_match_stored:
- /* match found */
- ip += mLength;
- anchor = ip;
-
- if (ip <= ilimit) {
- /* Complementary insertion */
- /* done after iLimit test, as candidates could be > iend-8 */
- { U32 const indexToInsert = current+2;
- hashLong[ZSTD_hashPtr(base+indexToInsert, hBitsL, 8)] = indexToInsert;
- hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
- hashSmall[ZSTD_hashPtr(base+indexToInsert, hBitsS, mls)] = indexToInsert;
- hashSmall[ZSTD_hashPtr(ip-1, hBitsS, mls)] = (U32)(ip-1-base);
- }
-
- /* check immediate repcode */
- if (dictMode == ZSTD_dictMatchState) {
- while (ip <= ilimit) {
- U32 const current2 = (U32)(ip-base);
- U32 const repIndex2 = current2 - offset_2;
- const BYTE* repMatch2 = dictMode == ZSTD_dictMatchState
- && repIndex2 < prefixLowestIndex ?
- dictBase + repIndex2 - dictIndexDelta :
- base + repIndex2;
- if ( ((U32)((prefixLowestIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */)
- && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
- const BYTE* const repEnd2 = repIndex2 < prefixLowestIndex ? dictEnd : iend;
- size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixLowest) + 4;
- U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
- ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, repLength2-MINMATCH);
- hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
- hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
- ip += repLength2;
- anchor = ip;
- continue;
- }
- break;
- } }
-
- if (dictMode == ZSTD_noDict) {
- while ( (ip <= ilimit)
- && ( (offset_2>0)
- & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
- /* store sequence */
- size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
- U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; /* swap offset_2 <=> offset_1 */
- hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
- hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
- ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, rLength-MINMATCH);
- ip += rLength;
- anchor = ip;
- continue; /* faster when present ... (?) */
- } } }
- } /* while (ip < ilimit) */
-
- /* save reps for next block */
- rep[0] = offset_1 ? offset_1 : offsetSaved;
- rep[1] = offset_2 ? offset_2 : offsetSaved;
-
- /* Return the last literals size */
- return (size_t)(iend - anchor);
-}
-
-
-size_t ZSTD_compressBlock_doubleFast(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize)
-{
- const U32 mls = ms->cParams.minMatch;
- switch(mls)
- {
- default: /* includes case 3 */
- case 4 :
- return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 4, ZSTD_noDict);
- case 5 :
- return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 5, ZSTD_noDict);
- case 6 :
- return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 6, ZSTD_noDict);
- case 7 :
- return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 7, ZSTD_noDict);
- }
-}
-
-
-size_t ZSTD_compressBlock_doubleFast_dictMatchState(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize)
-{
- const U32 mls = ms->cParams.minMatch;
- switch(mls)
- {
- default: /* includes case 3 */
- case 4 :
- return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 4, ZSTD_dictMatchState);
- case 5 :
- return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 5, ZSTD_dictMatchState);
- case 6 :
- return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 6, ZSTD_dictMatchState);
- case 7 :
- return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 7, ZSTD_dictMatchState);
- }
-}
-
-
-static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize,
- U32 const mls /* template */)
-{
- ZSTD_compressionParameters const* cParams = &ms->cParams;
- U32* const hashLong = ms->hashTable;
- U32 const hBitsL = cParams->hashLog;
- U32* const hashSmall = ms->chainTable;
- U32 const hBitsS = cParams->chainLog;
- const BYTE* const istart = (const BYTE*)src;
- const BYTE* ip = istart;
- const BYTE* anchor = istart;
- const BYTE* const iend = istart + srcSize;
- const BYTE* const ilimit = iend - 8;
- const BYTE* const base = ms->window.base;
- const U32 endIndex = (U32)((size_t)(istart - base) + srcSize);
- const U32 lowLimit = ZSTD_getLowestMatchIndex(ms, endIndex, cParams->windowLog);
- const U32 dictStartIndex = lowLimit;
- const U32 dictLimit = ms->window.dictLimit;
- const U32 prefixStartIndex = (dictLimit > lowLimit) ? dictLimit : lowLimit;
- const BYTE* const prefixStart = base + prefixStartIndex;
- const BYTE* const dictBase = ms->window.dictBase;
- const BYTE* const dictStart = dictBase + dictStartIndex;
- const BYTE* const dictEnd = dictBase + prefixStartIndex;
- U32 offset_1=rep[0], offset_2=rep[1];
-
- DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_extDict_generic (srcSize=%zu)", srcSize);
-
- /* if extDict is invalidated due to maxDistance, switch to "regular" variant */
- if (prefixStartIndex == dictStartIndex)
- return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, mls, ZSTD_noDict);
-
- /* Search Loop */
- while (ip < ilimit) { /* < instead of <=, because (ip+1) */
- const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
- const U32 matchIndex = hashSmall[hSmall];
- const BYTE* const matchBase = matchIndex < prefixStartIndex ? dictBase : base;
- const BYTE* match = matchBase + matchIndex;
-
- const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
- const U32 matchLongIndex = hashLong[hLong];
- const BYTE* const matchLongBase = matchLongIndex < prefixStartIndex ? dictBase : base;
- const BYTE* matchLong = matchLongBase + matchLongIndex;
-
- const U32 current = (U32)(ip-base);
- const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
- const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base;
- const BYTE* const repMatch = repBase + repIndex;
- size_t mLength;
- hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */
-
- if ((((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow : ensure repIndex doesn't overlap dict + prefix */
- & (repIndex > dictStartIndex))
- && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
- const BYTE* repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
- mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4;
- ip++;
- ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, 0, mLength-MINMATCH);
- } else {
- if ((matchLongIndex > dictStartIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
- const BYTE* const matchEnd = matchLongIndex < prefixStartIndex ? dictEnd : iend;
- const BYTE* const lowMatchPtr = matchLongIndex < prefixStartIndex ? dictStart : prefixStart;
- U32 offset;
- mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, prefixStart) + 8;
- offset = current - matchLongIndex;
- while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
- offset_2 = offset_1;
- offset_1 = offset;
- ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
-
- } else if ((matchIndex > dictStartIndex) && (MEM_read32(match) == MEM_read32(ip))) {
- size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
- U32 const matchIndex3 = hashLong[h3];
- const BYTE* const match3Base = matchIndex3 < prefixStartIndex ? dictBase : base;
- const BYTE* match3 = match3Base + matchIndex3;
- U32 offset;
- hashLong[h3] = current + 1;
- if ( (matchIndex3 > dictStartIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
- const BYTE* const matchEnd = matchIndex3 < prefixStartIndex ? dictEnd : iend;
- const BYTE* const lowMatchPtr = matchIndex3 < prefixStartIndex ? dictStart : prefixStart;
- mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, prefixStart) + 8;
- ip++;
- offset = current+1 - matchIndex3;
- while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
- } else {
- const BYTE* const matchEnd = matchIndex < prefixStartIndex ? dictEnd : iend;
- const BYTE* const lowMatchPtr = matchIndex < prefixStartIndex ? dictStart : prefixStart;
- mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, prefixStart) + 4;
- offset = current - matchIndex;
- while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
- }
- offset_2 = offset_1;
- offset_1 = offset;
- ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
-
- } else {
- ip += ((ip-anchor) >> kSearchStrength) + 1;
- continue;
- } }
-
- /* move to next sequence start */
- ip += mLength;
- anchor = ip;
-
- if (ip <= ilimit) {
- /* Complementary insertion */
- /* done after iLimit test, as candidates could be > iend-8 */
- { U32 const indexToInsert = current+2;
- hashLong[ZSTD_hashPtr(base+indexToInsert, hBitsL, 8)] = indexToInsert;
- hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
- hashSmall[ZSTD_hashPtr(base+indexToInsert, hBitsS, mls)] = indexToInsert;
- hashSmall[ZSTD_hashPtr(ip-1, hBitsS, mls)] = (U32)(ip-1-base);
- }
-
- /* check immediate repcode */
- while (ip <= ilimit) {
- U32 const current2 = (U32)(ip-base);
- U32 const repIndex2 = current2 - offset_2;
- const BYTE* repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2;
- if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) /* intentional overflow : ensure repIndex2 doesn't overlap dict + prefix */
- & (repIndex2 > dictStartIndex))
- && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
- const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend;
- size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4;
- U32 const tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
- ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, repLength2-MINMATCH);
- hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
- hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
- ip += repLength2;
- anchor = ip;
- continue;
- }
- break;
- } } }
-
- /* save reps for next block */
- rep[0] = offset_1;
- rep[1] = offset_2;
-
- /* Return the last literals size */
- return (size_t)(iend - anchor);
-}
-
-
-size_t ZSTD_compressBlock_doubleFast_extDict(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize)
-{
- U32 const mls = ms->cParams.minMatch;
- switch(mls)
- {
- default: /* includes case 3 */
- case 4 :
- return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 4);
- case 5 :
- return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 5);
- case 6 :
- return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 6);
- case 7 :
- return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 7);
- }
-}
-/**** ended inlining compress/zstd_double_fast.c ****/
-/**** start inlining compress/zstd_fast.c ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-/**** skipping file: zstd_compress_internal.h ****/
-/**** skipping file: zstd_fast.h ****/
-
-
-void ZSTD_fillHashTable(ZSTD_matchState_t* ms,
- const void* const end,
- ZSTD_dictTableLoadMethod_e dtlm)
-{
- const ZSTD_compressionParameters* const cParams = &ms->cParams;
- U32* const hashTable = ms->hashTable;
- U32 const hBits = cParams->hashLog;
- U32 const mls = cParams->minMatch;
- const BYTE* const base = ms->window.base;
- const BYTE* ip = base + ms->nextToUpdate;
- const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
- const U32 fastHashFillStep = 3;
-
- /* Always insert every fastHashFillStep position into the hash table.
- * Insert the other positions if their hash entry is empty.
- */
- for ( ; ip + fastHashFillStep < iend + 2; ip += fastHashFillStep) {
- U32 const current = (U32)(ip - base);
- size_t const hash0 = ZSTD_hashPtr(ip, hBits, mls);
- hashTable[hash0] = current;
- if (dtlm == ZSTD_dtlm_fast) continue;
- /* Only load extra positions for ZSTD_dtlm_full */
- { U32 p;
- for (p = 1; p < fastHashFillStep; ++p) {
- size_t const hash = ZSTD_hashPtr(ip + p, hBits, mls);
- if (hashTable[hash] == 0) { /* not yet filled */
- hashTable[hash] = current + p;
- } } } }
-}
-
-
-FORCE_INLINE_TEMPLATE size_t
-ZSTD_compressBlock_fast_generic(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize,
- U32 const mls)
-{
- const ZSTD_compressionParameters* const cParams = &ms->cParams;
- U32* const hashTable = ms->hashTable;
- U32 const hlog = cParams->hashLog;
- /* support stepSize of 0 */
- size_t const stepSize = cParams->targetLength + !(cParams->targetLength) + 1;
- const BYTE* const base = ms->window.base;
- const BYTE* const istart = (const BYTE*)src;
- /* We check ip0 (ip + 0) and ip1 (ip + 1) each loop */
- const BYTE* ip0 = istart;
- const BYTE* ip1;
- const BYTE* anchor = istart;
- const U32 endIndex = (U32)((size_t)(istart - base) + srcSize);
- const U32 prefixStartIndex = ZSTD_getLowestPrefixIndex(ms, endIndex, cParams->windowLog);
- const BYTE* const prefixStart = base + prefixStartIndex;
- const BYTE* const iend = istart + srcSize;
- const BYTE* const ilimit = iend - HASH_READ_SIZE;
- U32 offset_1=rep[0], offset_2=rep[1];
- U32 offsetSaved = 0;
-
- /* init */
- DEBUGLOG(5, "ZSTD_compressBlock_fast_generic");
- ip0 += (ip0 == prefixStart);
- ip1 = ip0 + 1;
- { U32 const current = (U32)(ip0 - base);
- U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, current, cParams->windowLog);
- U32 const maxRep = current - windowLow;
- if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
- if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
- }
-
- /* Main Search Loop */
-#ifdef __INTEL_COMPILER
- /* From intel 'The vector pragma indicates that the loop should be
- * vectorized if it is legal to do so'. Can be used together with
- * #pragma ivdep (but have opted to exclude that because intel
- * warns against using it).*/
- #pragma vector always
-#endif
- while (ip1 < ilimit) { /* < instead of <=, because check at ip0+2 */
- size_t mLength;
- BYTE const* ip2 = ip0 + 2;
- size_t const h0 = ZSTD_hashPtr(ip0, hlog, mls);
- U32 const val0 = MEM_read32(ip0);
- size_t const h1 = ZSTD_hashPtr(ip1, hlog, mls);
- U32 const val1 = MEM_read32(ip1);
- U32 const current0 = (U32)(ip0-base);
- U32 const current1 = (U32)(ip1-base);
- U32 const matchIndex0 = hashTable[h0];
- U32 const matchIndex1 = hashTable[h1];
- BYTE const* repMatch = ip2 - offset_1;
- const BYTE* match0 = base + matchIndex0;
- const BYTE* match1 = base + matchIndex1;
- U32 offcode;
-
-#if defined(__aarch64__)
- PREFETCH_L1(ip0+256);
-#endif
-
- hashTable[h0] = current0; /* update hash table */
- hashTable[h1] = current1; /* update hash table */
-
- assert(ip0 + 1 == ip1);
-
- if ((offset_1 > 0) & (MEM_read32(repMatch) == MEM_read32(ip2))) {
- mLength = (ip2[-1] == repMatch[-1]) ? 1 : 0;
- ip0 = ip2 - mLength;
- match0 = repMatch - mLength;
- mLength += 4;
- offcode = 0;
- goto _match;
- }
- if ((matchIndex0 > prefixStartIndex) && MEM_read32(match0) == val0) {
- /* found a regular match */
- goto _offset;
- }
- if ((matchIndex1 > prefixStartIndex) && MEM_read32(match1) == val1) {
- /* found a regular match after one literal */
- ip0 = ip1;
- match0 = match1;
- goto _offset;
- }
- { size_t const step = ((size_t)(ip0-anchor) >> (kSearchStrength - 1)) + stepSize;
- assert(step >= 2);
- ip0 += step;
- ip1 += step;
- continue;
- }
-_offset: /* Requires: ip0, match0 */
- /* Compute the offset code */
- offset_2 = offset_1;
- offset_1 = (U32)(ip0-match0);
- offcode = offset_1 + ZSTD_REP_MOVE;
- mLength = 4;
- /* Count the backwards match length */
- while (((ip0>anchor) & (match0>prefixStart))
- && (ip0[-1] == match0[-1])) { ip0--; match0--; mLength++; } /* catch up */
-
-_match: /* Requires: ip0, match0, offcode */
- /* Count the forward length */
- mLength += ZSTD_count(ip0+mLength, match0+mLength, iend);
- ZSTD_storeSeq(seqStore, (size_t)(ip0-anchor), anchor, iend, offcode, mLength-MINMATCH);
- /* match found */
- ip0 += mLength;
- anchor = ip0;
-
- if (ip0 <= ilimit) {
- /* Fill Table */
- assert(base+current0+2 > istart); /* check base overflow */
- hashTable[ZSTD_hashPtr(base+current0+2, hlog, mls)] = current0+2; /* here because current+2 could be > iend-8 */
- hashTable[ZSTD_hashPtr(ip0-2, hlog, mls)] = (U32)(ip0-2-base);
-
- if (offset_2 > 0) { /* offset_2==0 means offset_2 is invalidated */
- while ( (ip0 <= ilimit) && (MEM_read32(ip0) == MEM_read32(ip0 - offset_2)) ) {
- /* store sequence */
- size_t const rLength = ZSTD_count(ip0+4, ip0+4-offset_2, iend) + 4;
- { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
- hashTable[ZSTD_hashPtr(ip0, hlog, mls)] = (U32)(ip0-base);
- ip0 += rLength;
- ZSTD_storeSeq(seqStore, 0 /*litLen*/, anchor, iend, 0 /*offCode*/, rLength-MINMATCH);
- anchor = ip0;
- continue; /* faster when present (confirmed on gcc-8) ... (?) */
- } } }
- ip1 = ip0 + 1;
- }
-
- /* save reps for next block */
- rep[0] = offset_1 ? offset_1 : offsetSaved;
- rep[1] = offset_2 ? offset_2 : offsetSaved;
-
- /* Return the last literals size */
- return (size_t)(iend - anchor);
-}
-
-
-size_t ZSTD_compressBlock_fast(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize)
-{
- U32 const mls = ms->cParams.minMatch;
- assert(ms->dictMatchState == NULL);
- switch(mls)
- {
- default: /* includes case 3 */
- case 4 :
- return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 4);
- case 5 :
- return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 5);
- case 6 :
- return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 6);
- case 7 :
- return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 7);
- }
-}
-
-FORCE_INLINE_TEMPLATE
-size_t ZSTD_compressBlock_fast_dictMatchState_generic(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize, U32 const mls)
-{
- const ZSTD_compressionParameters* const cParams = &ms->cParams;
- U32* const hashTable = ms->hashTable;
- U32 const hlog = cParams->hashLog;
- /* support stepSize of 0 */
- U32 const stepSize = cParams->targetLength + !(cParams->targetLength);
- const BYTE* const base = ms->window.base;
- const BYTE* const istart = (const BYTE*)src;
- const BYTE* ip = istart;
- const BYTE* anchor = istart;
- const U32 prefixStartIndex = ms->window.dictLimit;
- const BYTE* const prefixStart = base + prefixStartIndex;
- const BYTE* const iend = istart + srcSize;
- const BYTE* const ilimit = iend - HASH_READ_SIZE;
- U32 offset_1=rep[0], offset_2=rep[1];
- U32 offsetSaved = 0;
-
- const ZSTD_matchState_t* const dms = ms->dictMatchState;
- const ZSTD_compressionParameters* const dictCParams = &dms->cParams ;
- const U32* const dictHashTable = dms->hashTable;
- const U32 dictStartIndex = dms->window.dictLimit;
- const BYTE* const dictBase = dms->window.base;
- const BYTE* const dictStart = dictBase + dictStartIndex;
- const BYTE* const dictEnd = dms->window.nextSrc;
- const U32 dictIndexDelta = prefixStartIndex - (U32)(dictEnd - dictBase);
- const U32 dictAndPrefixLength = (U32)(ip - prefixStart + dictEnd - dictStart);
- const U32 dictHLog = dictCParams->hashLog;
-
- /* if a dictionary is still attached, it necessarily means that
- * it is within window size. So we just check it. */
- const U32 maxDistance = 1U << cParams->windowLog;
- const U32 endIndex = (U32)((size_t)(ip - base) + srcSize);
- assert(endIndex - prefixStartIndex <= maxDistance);
- (void)maxDistance; (void)endIndex; /* these variables are not used when assert() is disabled */
-
- /* ensure there will be no no underflow
- * when translating a dict index into a local index */
- assert(prefixStartIndex >= (U32)(dictEnd - dictBase));
-
- /* init */
- DEBUGLOG(5, "ZSTD_compressBlock_fast_dictMatchState_generic");
- ip += (dictAndPrefixLength == 0);
- /* dictMatchState repCode checks don't currently handle repCode == 0
- * disabling. */
- assert(offset_1 <= dictAndPrefixLength);
- assert(offset_2 <= dictAndPrefixLength);
-
- /* Main Search Loop */
- while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
- size_t mLength;
- size_t const h = ZSTD_hashPtr(ip, hlog, mls);
- U32 const current = (U32)(ip-base);
- U32 const matchIndex = hashTable[h];
- const BYTE* match = base + matchIndex;
- const U32 repIndex = current + 1 - offset_1;
- const BYTE* repMatch = (repIndex < prefixStartIndex) ?
- dictBase + (repIndex - dictIndexDelta) :
- base + repIndex;
- hashTable[h] = current; /* update hash table */
-
- if ( ((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow : ensure repIndex isn't overlapping dict + prefix */
- && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
- const BYTE* const repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
- mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4;
- ip++;
- ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, 0, mLength-MINMATCH);
- } else if ( (matchIndex <= prefixStartIndex) ) {
- size_t const dictHash = ZSTD_hashPtr(ip, dictHLog, mls);
- U32 const dictMatchIndex = dictHashTable[dictHash];
- const BYTE* dictMatch = dictBase + dictMatchIndex;
- if (dictMatchIndex <= dictStartIndex ||
- MEM_read32(dictMatch) != MEM_read32(ip)) {
- assert(stepSize >= 1);
- ip += ((ip-anchor) >> kSearchStrength) + stepSize;
- continue;
- } else {
- /* found a dict match */
- U32 const offset = (U32)(current-dictMatchIndex-dictIndexDelta);
- mLength = ZSTD_count_2segments(ip+4, dictMatch+4, iend, dictEnd, prefixStart) + 4;
- while (((ip>anchor) & (dictMatch>dictStart))
- && (ip[-1] == dictMatch[-1])) {
- ip--; dictMatch--; mLength++;
- } /* catch up */
- offset_2 = offset_1;
- offset_1 = offset;
- ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
- }
- } else if (MEM_read32(match) != MEM_read32(ip)) {
- /* it's not a match, and we're not going to check the dictionary */
- assert(stepSize >= 1);
- ip += ((ip-anchor) >> kSearchStrength) + stepSize;
- continue;
- } else {
- /* found a regular match */
- U32 const offset = (U32)(ip-match);
- mLength = ZSTD_count(ip+4, match+4, iend) + 4;
- while (((ip>anchor) & (match>prefixStart))
- && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
- offset_2 = offset_1;
- offset_1 = offset;
- ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
- }
-
- /* match found */
- ip += mLength;
- anchor = ip;
-
- if (ip <= ilimit) {
- /* Fill Table */
- assert(base+current+2 > istart); /* check base overflow */
- hashTable[ZSTD_hashPtr(base+current+2, hlog, mls)] = current+2; /* here because current+2 could be > iend-8 */
- hashTable[ZSTD_hashPtr(ip-2, hlog, mls)] = (U32)(ip-2-base);
-
- /* check immediate repcode */
- while (ip <= ilimit) {
- U32 const current2 = (U32)(ip-base);
- U32 const repIndex2 = current2 - offset_2;
- const BYTE* repMatch2 = repIndex2 < prefixStartIndex ?
- dictBase - dictIndexDelta + repIndex2 :
- base + repIndex2;
- if ( ((U32)((prefixStartIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */)
- && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
- const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend;
- size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4;
- U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
- ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, repLength2-MINMATCH);
- hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2;
- ip += repLength2;
- anchor = ip;
- continue;
- }
- break;
- }
- }
- }
-
- /* save reps for next block */
- rep[0] = offset_1 ? offset_1 : offsetSaved;
- rep[1] = offset_2 ? offset_2 : offsetSaved;
-
- /* Return the last literals size */
- return (size_t)(iend - anchor);
-}
-
-size_t ZSTD_compressBlock_fast_dictMatchState(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize)
-{
- U32 const mls = ms->cParams.minMatch;
- assert(ms->dictMatchState != NULL);
- switch(mls)
- {
- default: /* includes case 3 */
- case 4 :
- return ZSTD_compressBlock_fast_dictMatchState_generic(ms, seqStore, rep, src, srcSize, 4);
- case 5 :
- return ZSTD_compressBlock_fast_dictMatchState_generic(ms, seqStore, rep, src, srcSize, 5);
- case 6 :
- return ZSTD_compressBlock_fast_dictMatchState_generic(ms, seqStore, rep, src, srcSize, 6);
- case 7 :
- return ZSTD_compressBlock_fast_dictMatchState_generic(ms, seqStore, rep, src, srcSize, 7);
- }
-}
-
-
-static size_t ZSTD_compressBlock_fast_extDict_generic(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize, U32 const mls)
-{
- const ZSTD_compressionParameters* const cParams = &ms->cParams;
- U32* const hashTable = ms->hashTable;
- U32 const hlog = cParams->hashLog;
- /* support stepSize of 0 */
- U32 const stepSize = cParams->targetLength + !(cParams->targetLength);
- const BYTE* const base = ms->window.base;
- const BYTE* const dictBase = ms->window.dictBase;
- const BYTE* const istart = (const BYTE*)src;
- const BYTE* ip = istart;
- const BYTE* anchor = istart;
- const U32 endIndex = (U32)((size_t)(istart - base) + srcSize);
- const U32 lowLimit = ZSTD_getLowestMatchIndex(ms, endIndex, cParams->windowLog);
- const U32 dictStartIndex = lowLimit;
- const BYTE* const dictStart = dictBase + dictStartIndex;
- const U32 dictLimit = ms->window.dictLimit;
- const U32 prefixStartIndex = dictLimit < lowLimit ? lowLimit : dictLimit;
- const BYTE* const prefixStart = base + prefixStartIndex;
- const BYTE* const dictEnd = dictBase + prefixStartIndex;
- const BYTE* const iend = istart + srcSize;
- const BYTE* const ilimit = iend - 8;
- U32 offset_1=rep[0], offset_2=rep[1];
-
- DEBUGLOG(5, "ZSTD_compressBlock_fast_extDict_generic (offset_1=%u)", offset_1);
-
- /* switch to "regular" variant if extDict is invalidated due to maxDistance */
- if (prefixStartIndex == dictStartIndex)
- return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, mls);
-
- /* Search Loop */
- while (ip < ilimit) { /* < instead of <=, because (ip+1) */
- const size_t h = ZSTD_hashPtr(ip, hlog, mls);
- const U32 matchIndex = hashTable[h];
- const BYTE* const matchBase = matchIndex < prefixStartIndex ? dictBase : base;
- const BYTE* match = matchBase + matchIndex;
- const U32 current = (U32)(ip-base);
- const U32 repIndex = current + 1 - offset_1;
- const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base;
- const BYTE* const repMatch = repBase + repIndex;
- hashTable[h] = current; /* update hash table */
- DEBUGLOG(7, "offset_1 = %u , current = %u", offset_1, current);
- assert(offset_1 <= current +1); /* check repIndex */
-
- if ( (((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > dictStartIndex))
- && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
- const BYTE* const repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
- size_t const rLength = ZSTD_count_2segments(ip+1 +4, repMatch +4, iend, repMatchEnd, prefixStart) + 4;
- ip++;
- ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, 0, rLength-MINMATCH);
- ip += rLength;
- anchor = ip;
- } else {
- if ( (matchIndex < dictStartIndex) ||
- (MEM_read32(match) != MEM_read32(ip)) ) {
- assert(stepSize >= 1);
- ip += ((ip-anchor) >> kSearchStrength) + stepSize;
- continue;
- }
- { const BYTE* const matchEnd = matchIndex < prefixStartIndex ? dictEnd : iend;
- const BYTE* const lowMatchPtr = matchIndex < prefixStartIndex ? dictStart : prefixStart;
- U32 const offset = current - matchIndex;
- size_t mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, prefixStart) + 4;
- while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
- offset_2 = offset_1; offset_1 = offset; /* update offset history */
- ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
- ip += mLength;
- anchor = ip;
- } }
-
- if (ip <= ilimit) {
- /* Fill Table */
- hashTable[ZSTD_hashPtr(base+current+2, hlog, mls)] = current+2;
- hashTable[ZSTD_hashPtr(ip-2, hlog, mls)] = (U32)(ip-2-base);
- /* check immediate repcode */
- while (ip <= ilimit) {
- U32 const current2 = (U32)(ip-base);
- U32 const repIndex2 = current2 - offset_2;
- const BYTE* const repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2;
- if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) & (repIndex2 > dictStartIndex)) /* intentional overflow */
- && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
- const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend;
- size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4;
- { U32 const tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; } /* swap offset_2 <=> offset_1 */
- ZSTD_storeSeq(seqStore, 0 /*litlen*/, anchor, iend, 0 /*offcode*/, repLength2-MINMATCH);
- hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2;
- ip += repLength2;
- anchor = ip;
- continue;
- }
- break;
- } } }
-
- /* save reps for next block */
- rep[0] = offset_1;
- rep[1] = offset_2;
-
- /* Return the last literals size */
- return (size_t)(iend - anchor);
-}
-
-
-size_t ZSTD_compressBlock_fast_extDict(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize)
-{
- U32 const mls = ms->cParams.minMatch;
- switch(mls)
- {
- default: /* includes case 3 */
- case 4 :
- return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 4);
- case 5 :
- return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 5);
- case 6 :
- return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 6);
- case 7 :
- return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 7);
- }
-}
-/**** ended inlining compress/zstd_fast.c ****/
-/**** start inlining compress/zstd_lazy.c ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-/**** skipping file: zstd_compress_internal.h ****/
-/**** skipping file: zstd_lazy.h ****/
-
-
-/*-*************************************
-* Binary Tree search
-***************************************/
-
-static void
-ZSTD_updateDUBT(ZSTD_matchState_t* ms,
- const BYTE* ip, const BYTE* iend,
- U32 mls)
-{
- const ZSTD_compressionParameters* const cParams = &ms->cParams;
- U32* const hashTable = ms->hashTable;
- U32 const hashLog = cParams->hashLog;
-
- U32* const bt = ms->chainTable;
- U32 const btLog = cParams->chainLog - 1;
- U32 const btMask = (1 << btLog) - 1;
-
- const BYTE* const base = ms->window.base;
- U32 const target = (U32)(ip - base);
- U32 idx = ms->nextToUpdate;
-
- if (idx != target)
- DEBUGLOG(7, "ZSTD_updateDUBT, from %u to %u (dictLimit:%u)",
- idx, target, ms->window.dictLimit);
- assert(ip + 8 <= iend); /* condition for ZSTD_hashPtr */
- (void)iend;
-
- assert(idx >= ms->window.dictLimit); /* condition for valid base+idx */
- for ( ; idx < target ; idx++) {
- size_t const h = ZSTD_hashPtr(base + idx, hashLog, mls); /* assumption : ip + 8 <= iend */
- U32 const matchIndex = hashTable[h];
-
- U32* const nextCandidatePtr = bt + 2*(idx&btMask);
- U32* const sortMarkPtr = nextCandidatePtr + 1;
-
- DEBUGLOG(8, "ZSTD_updateDUBT: insert %u", idx);
- hashTable[h] = idx; /* Update Hash Table */
- *nextCandidatePtr = matchIndex; /* update BT like a chain */
- *sortMarkPtr = ZSTD_DUBT_UNSORTED_MARK;
- }
- ms->nextToUpdate = target;
-}
-
-
-/** ZSTD_insertDUBT1() :
- * sort one already inserted but unsorted position
- * assumption : current >= btlow == (current - btmask)
- * doesn't fail */
-static void
-ZSTD_insertDUBT1(ZSTD_matchState_t* ms,
- U32 current, const BYTE* inputEnd,
- U32 nbCompares, U32 btLow,
- const ZSTD_dictMode_e dictMode)
-{
- const ZSTD_compressionParameters* const cParams = &ms->cParams;
- U32* const bt = ms->chainTable;
- U32 const btLog = cParams->chainLog - 1;
- U32 const btMask = (1 << btLog) - 1;
- size_t commonLengthSmaller=0, commonLengthLarger=0;
- const BYTE* const base = ms->window.base;
- const BYTE* const dictBase = ms->window.dictBase;
- const U32 dictLimit = ms->window.dictLimit;
- const BYTE* const ip = (current>=dictLimit) ? base + current : dictBase + current;
- const BYTE* const iend = (current>=dictLimit) ? inputEnd : dictBase + dictLimit;
- const BYTE* const dictEnd = dictBase + dictLimit;
- const BYTE* const prefixStart = base + dictLimit;
- const BYTE* match;
- U32* smallerPtr = bt + 2*(current&btMask);
- U32* largerPtr = smallerPtr + 1;
- U32 matchIndex = *smallerPtr; /* this candidate is unsorted : next sorted candidate is reached through *smallerPtr, while *largerPtr contains previous unsorted candidate (which is already saved and can be overwritten) */
- U32 dummy32; /* to be nullified at the end */
- U32 const windowValid = ms->window.lowLimit;
- U32 const maxDistance = 1U << cParams->windowLog;
- U32 const windowLow = (current - windowValid > maxDistance) ? current - maxDistance : windowValid;
-
-
- DEBUGLOG(8, "ZSTD_insertDUBT1(%u) (dictLimit=%u, lowLimit=%u)",
- current, dictLimit, windowLow);
- assert(current >= btLow);
- assert(ip < iend); /* condition for ZSTD_count */
-
- while (nbCompares-- && (matchIndex > windowLow)) {
- U32* const nextPtr = bt + 2*(matchIndex & btMask);
- size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
- assert(matchIndex < current);
- /* note : all candidates are now supposed sorted,
- * but it's still possible to have nextPtr[1] == ZSTD_DUBT_UNSORTED_MARK
- * when a real index has the same value as ZSTD_DUBT_UNSORTED_MARK */
-
- if ( (dictMode != ZSTD_extDict)
- || (matchIndex+matchLength >= dictLimit) /* both in current segment*/
- || (current < dictLimit) /* both in extDict */) {
- const BYTE* const mBase = ( (dictMode != ZSTD_extDict)
- || (matchIndex+matchLength >= dictLimit)) ?
- base : dictBase;
- assert( (matchIndex+matchLength >= dictLimit) /* might be wrong if extDict is incorrectly set to 0 */
- || (current < dictLimit) );
- match = mBase + matchIndex;
- matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
- } else {
- match = dictBase + matchIndex;
- matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
- if (matchIndex+matchLength >= dictLimit)
- match = base + matchIndex; /* preparation for next read of match[matchLength] */
- }
-
- DEBUGLOG(8, "ZSTD_insertDUBT1: comparing %u with %u : found %u common bytes ",
- current, matchIndex, (U32)matchLength);
-
- if (ip+matchLength == iend) { /* equal : no way to know if inf or sup */
- break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt tree */
- }
-
- if (match[matchLength] < ip[matchLength]) { /* necessarily within buffer */
- /* match is smaller than current */
- *smallerPtr = matchIndex; /* update smaller idx */
- commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
- if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop searching */
- DEBUGLOG(8, "ZSTD_insertDUBT1: %u (>btLow=%u) is smaller : next => %u",
- matchIndex, btLow, nextPtr[1]);
- smallerPtr = nextPtr+1; /* new "candidate" => larger than match, which was smaller than target */
- matchIndex = nextPtr[1]; /* new matchIndex, larger than previous and closer to current */
- } else {
- /* match is larger than current */
- *largerPtr = matchIndex;
- commonLengthLarger = matchLength;
- if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop searching */
- DEBUGLOG(8, "ZSTD_insertDUBT1: %u (>btLow=%u) is larger => %u",
- matchIndex, btLow, nextPtr[0]);
- largerPtr = nextPtr;
- matchIndex = nextPtr[0];
- } }
-
- *smallerPtr = *largerPtr = 0;
-}
-
-
-static size_t
-ZSTD_DUBT_findBetterDictMatch (
- ZSTD_matchState_t* ms,
- const BYTE* const ip, const BYTE* const iend,
- size_t* offsetPtr,
- size_t bestLength,
- U32 nbCompares,
- U32 const mls,
- const ZSTD_dictMode_e dictMode)
-{
- const ZSTD_matchState_t * const dms = ms->dictMatchState;
- const ZSTD_compressionParameters* const dmsCParams = &dms->cParams;
- const U32 * const dictHashTable = dms->hashTable;
- U32 const hashLog = dmsCParams->hashLog;
- size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
- U32 dictMatchIndex = dictHashTable[h];
-
- const BYTE* const base = ms->window.base;
- const BYTE* const prefixStart = base + ms->window.dictLimit;
- U32 const current = (U32)(ip-base);
- const BYTE* const dictBase = dms->window.base;
- const BYTE* const dictEnd = dms->window.nextSrc;
- U32 const dictHighLimit = (U32)(dms->window.nextSrc - dms->window.base);
- U32 const dictLowLimit = dms->window.lowLimit;
- U32 const dictIndexDelta = ms->window.lowLimit - dictHighLimit;
-
- U32* const dictBt = dms->chainTable;
- U32 const btLog = dmsCParams->chainLog - 1;
- U32 const btMask = (1 << btLog) - 1;
- U32 const btLow = (btMask >= dictHighLimit - dictLowLimit) ? dictLowLimit : dictHighLimit - btMask;
-
- size_t commonLengthSmaller=0, commonLengthLarger=0;
-
- (void)dictMode;
- assert(dictMode == ZSTD_dictMatchState);
-
- while (nbCompares-- && (dictMatchIndex > dictLowLimit)) {
- U32* const nextPtr = dictBt + 2*(dictMatchIndex & btMask);
- size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
- const BYTE* match = dictBase + dictMatchIndex;
- matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
- if (dictMatchIndex+matchLength >= dictHighLimit)
- match = base + dictMatchIndex + dictIndexDelta; /* to prepare for next usage of match[matchLength] */
-
- if (matchLength > bestLength) {
- U32 matchIndex = dictMatchIndex + dictIndexDelta;
- if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) ) {
- DEBUGLOG(9, "ZSTD_DUBT_findBetterDictMatch(%u) : found better match length %u -> %u and offsetCode %u -> %u (dictMatchIndex %u, matchIndex %u)",
- current, (U32)bestLength, (U32)matchLength, (U32)*offsetPtr, ZSTD_REP_MOVE + current - matchIndex, dictMatchIndex, matchIndex);
- bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
- }
- if (ip+matchLength == iend) { /* reached end of input : ip[matchLength] is not valid, no way to know if it's larger or smaller than match */
- break; /* drop, to guarantee consistency (miss a little bit of compression) */
- }
- }
-
- if (match[matchLength] < ip[matchLength]) {
- if (dictMatchIndex <= btLow) { break; } /* beyond tree size, stop the search */
- commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
- dictMatchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
- } else {
- /* match is larger than current */
- if (dictMatchIndex <= btLow) { break; } /* beyond tree size, stop the search */
- commonLengthLarger = matchLength;
- dictMatchIndex = nextPtr[0];
- }
- }
-
- if (bestLength >= MINMATCH) {
- U32 const mIndex = current - ((U32)*offsetPtr - ZSTD_REP_MOVE); (void)mIndex;
- DEBUGLOG(8, "ZSTD_DUBT_findBetterDictMatch(%u) : found match of length %u and offsetCode %u (pos %u)",
- current, (U32)bestLength, (U32)*offsetPtr, mIndex);
- }
- return bestLength;
-
-}
-
-
-static size_t
-ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms,
- const BYTE* const ip, const BYTE* const iend,
- size_t* offsetPtr,
- U32 const mls,
- const ZSTD_dictMode_e dictMode)
-{
- const ZSTD_compressionParameters* const cParams = &ms->cParams;
- U32* const hashTable = ms->hashTable;
- U32 const hashLog = cParams->hashLog;
- size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
- U32 matchIndex = hashTable[h];
-
- const BYTE* const base = ms->window.base;
- U32 const current = (U32)(ip-base);
- U32 const windowLow = ZSTD_getLowestMatchIndex(ms, current, cParams->windowLog);
-
- U32* const bt = ms->chainTable;
- U32 const btLog = cParams->chainLog - 1;
- U32 const btMask = (1 << btLog) - 1;
- U32 const btLow = (btMask >= current) ? 0 : current - btMask;
- U32 const unsortLimit = MAX(btLow, windowLow);
-
- U32* nextCandidate = bt + 2*(matchIndex&btMask);
- U32* unsortedMark = bt + 2*(matchIndex&btMask) + 1;
- U32 nbCompares = 1U << cParams->searchLog;
- U32 nbCandidates = nbCompares;
- U32 previousCandidate = 0;
-
- DEBUGLOG(7, "ZSTD_DUBT_findBestMatch (%u) ", current);
- assert(ip <= iend-8); /* required for h calculation */
-
- /* reach end of unsorted candidates list */
- while ( (matchIndex > unsortLimit)
- && (*unsortedMark == ZSTD_DUBT_UNSORTED_MARK)
- && (nbCandidates > 1) ) {
- DEBUGLOG(8, "ZSTD_DUBT_findBestMatch: candidate %u is unsorted",
- matchIndex);
- *unsortedMark = previousCandidate; /* the unsortedMark becomes a reversed chain, to move up back to original position */
- previousCandidate = matchIndex;
- matchIndex = *nextCandidate;
- nextCandidate = bt + 2*(matchIndex&btMask);
- unsortedMark = bt + 2*(matchIndex&btMask) + 1;
- nbCandidates --;
- }
-
- /* nullify last candidate if it's still unsorted
- * simplification, detrimental to compression ratio, beneficial for speed */
- if ( (matchIndex > unsortLimit)
- && (*unsortedMark==ZSTD_DUBT_UNSORTED_MARK) ) {
- DEBUGLOG(7, "ZSTD_DUBT_findBestMatch: nullify last unsorted candidate %u",
- matchIndex);
- *nextCandidate = *unsortedMark = 0;
- }
-
- /* batch sort stacked candidates */
- matchIndex = previousCandidate;
- while (matchIndex) { /* will end on matchIndex == 0 */
- U32* const nextCandidateIdxPtr = bt + 2*(matchIndex&btMask) + 1;
- U32 const nextCandidateIdx = *nextCandidateIdxPtr;
- ZSTD_insertDUBT1(ms, matchIndex, iend,
- nbCandidates, unsortLimit, dictMode);
- matchIndex = nextCandidateIdx;
- nbCandidates++;
- }
-
- /* find longest match */
- { size_t commonLengthSmaller = 0, commonLengthLarger = 0;
- const BYTE* const dictBase = ms->window.dictBase;
- const U32 dictLimit = ms->window.dictLimit;
- const BYTE* const dictEnd = dictBase + dictLimit;
- const BYTE* const prefixStart = base + dictLimit;
- U32* smallerPtr = bt + 2*(current&btMask);
- U32* largerPtr = bt + 2*(current&btMask) + 1;
- U32 matchEndIdx = current + 8 + 1;
- U32 dummy32; /* to be nullified at the end */
- size_t bestLength = 0;
-
- matchIndex = hashTable[h];
- hashTable[h] = current; /* Update Hash Table */
-
- while (nbCompares-- && (matchIndex > windowLow)) {
- U32* const nextPtr = bt + 2*(matchIndex & btMask);
- size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
- const BYTE* match;
-
- if ((dictMode != ZSTD_extDict) || (matchIndex+matchLength >= dictLimit)) {
- match = base + matchIndex;
- matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
- } else {
- match = dictBase + matchIndex;
- matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
- if (matchIndex+matchLength >= dictLimit)
- match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
- }
-
- if (matchLength > bestLength) {
- if (matchLength > matchEndIdx - matchIndex)
- matchEndIdx = matchIndex + (U32)matchLength;
- if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
- bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
- if (ip+matchLength == iend) { /* equal : no way to know if inf or sup */
- if (dictMode == ZSTD_dictMatchState) {
- nbCompares = 0; /* in addition to avoiding checking any
- * further in this loop, make sure we
- * skip checking in the dictionary. */
- }
- break; /* drop, to guarantee consistency (miss a little bit of compression) */
- }
- }
-
- if (match[matchLength] < ip[matchLength]) {
- /* match is smaller than current */
- *smallerPtr = matchIndex; /* update smaller idx */
- commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
- if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
- smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
- matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
- } else {
- /* match is larger than current */
- *largerPtr = matchIndex;
- commonLengthLarger = matchLength;
- if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
- largerPtr = nextPtr;
- matchIndex = nextPtr[0];
- } }
-
- *smallerPtr = *largerPtr = 0;
-
- if (dictMode == ZSTD_dictMatchState && nbCompares) {
- bestLength = ZSTD_DUBT_findBetterDictMatch(
- ms, ip, iend,
- offsetPtr, bestLength, nbCompares,
- mls, dictMode);
- }
-
- assert(matchEndIdx > current+8); /* ensure nextToUpdate is increased */
- ms->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */
- if (bestLength >= MINMATCH) {
- U32 const mIndex = current - ((U32)*offsetPtr - ZSTD_REP_MOVE); (void)mIndex;
- DEBUGLOG(8, "ZSTD_DUBT_findBestMatch(%u) : found match of length %u and offsetCode %u (pos %u)",
- current, (U32)bestLength, (U32)*offsetPtr, mIndex);
- }
- return bestLength;
- }
-}
-
-
-/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
-FORCE_INLINE_TEMPLATE size_t
-ZSTD_BtFindBestMatch( ZSTD_matchState_t* ms,
- const BYTE* const ip, const BYTE* const iLimit,
- size_t* offsetPtr,
- const U32 mls /* template */,
- const ZSTD_dictMode_e dictMode)
-{
- DEBUGLOG(7, "ZSTD_BtFindBestMatch");
- if (ip < ms->window.base + ms->nextToUpdate) return 0; /* skipped area */
- ZSTD_updateDUBT(ms, ip, iLimit, mls);
- return ZSTD_DUBT_findBestMatch(ms, ip, iLimit, offsetPtr, mls, dictMode);
-}
-
-
-static size_t
-ZSTD_BtFindBestMatch_selectMLS ( ZSTD_matchState_t* ms,
- const BYTE* ip, const BYTE* const iLimit,
- size_t* offsetPtr)
-{
- switch(ms->cParams.minMatch)
- {
- default : /* includes case 3 */
- case 4 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 4, ZSTD_noDict);
- case 5 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 5, ZSTD_noDict);
- case 7 :
- case 6 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 6, ZSTD_noDict);
- }
-}
-
-
-static size_t ZSTD_BtFindBestMatch_dictMatchState_selectMLS (
- ZSTD_matchState_t* ms,
- const BYTE* ip, const BYTE* const iLimit,
- size_t* offsetPtr)
-{
- switch(ms->cParams.minMatch)
- {
- default : /* includes case 3 */
- case 4 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 4, ZSTD_dictMatchState);
- case 5 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 5, ZSTD_dictMatchState);
- case 7 :
- case 6 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 6, ZSTD_dictMatchState);
- }
-}
-
-
-static size_t ZSTD_BtFindBestMatch_extDict_selectMLS (
- ZSTD_matchState_t* ms,
- const BYTE* ip, const BYTE* const iLimit,
- size_t* offsetPtr)
-{
- switch(ms->cParams.minMatch)
- {
- default : /* includes case 3 */
- case 4 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 4, ZSTD_extDict);
- case 5 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 5, ZSTD_extDict);
- case 7 :
- case 6 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 6, ZSTD_extDict);
- }
-}
-
-
-
-/* *********************************
-* Hash Chain
-***********************************/
-#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & (mask)]
-
-/* Update chains up to ip (excluded)
- Assumption : always within prefix (i.e. not within extDict) */
-static U32 ZSTD_insertAndFindFirstIndex_internal(
- ZSTD_matchState_t* ms,
- const ZSTD_compressionParameters* const cParams,
- const BYTE* ip, U32 const mls)
-{
- U32* const hashTable = ms->hashTable;
- const U32 hashLog = cParams->hashLog;
- U32* const chainTable = ms->chainTable;
- const U32 chainMask = (1 << cParams->chainLog) - 1;
- const BYTE* const base = ms->window.base;
- const U32 target = (U32)(ip - base);
- U32 idx = ms->nextToUpdate;
-
- while(idx < target) { /* catch up */
- size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
- NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
- hashTable[h] = idx;
- idx++;
- }
-
- ms->nextToUpdate = target;
- return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
-}
-
-U32 ZSTD_insertAndFindFirstIndex(ZSTD_matchState_t* ms, const BYTE* ip) {
- const ZSTD_compressionParameters* const cParams = &ms->cParams;
- return ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, ms->cParams.minMatch);
-}
-
-
-/* inlining is important to hardwire a hot branch (template emulation) */
-FORCE_INLINE_TEMPLATE
-size_t ZSTD_HcFindBestMatch_generic (
- ZSTD_matchState_t* ms,
- const BYTE* const ip, const BYTE* const iLimit,
- size_t* offsetPtr,
- const U32 mls, const ZSTD_dictMode_e dictMode)
-{
- const ZSTD_compressionParameters* const cParams = &ms->cParams;
- U32* const chainTable = ms->chainTable;
- const U32 chainSize = (1 << cParams->chainLog);
- const U32 chainMask = chainSize-1;
- const BYTE* const base = ms->window.base;
- const BYTE* const dictBase = ms->window.dictBase;
- const U32 dictLimit = ms->window.dictLimit;
- const BYTE* const prefixStart = base + dictLimit;
- const BYTE* const dictEnd = dictBase + dictLimit;
- const U32 current = (U32)(ip-base);
- const U32 maxDistance = 1U << cParams->windowLog;
- const U32 lowestValid = ms->window.lowLimit;
- const U32 withinMaxDistance = (current - lowestValid > maxDistance) ? current - maxDistance : lowestValid;
- const U32 isDictionary = (ms->loadedDictEnd != 0);
- const U32 lowLimit = isDictionary ? lowestValid : withinMaxDistance;
- const U32 minChain = current > chainSize ? current - chainSize : 0;
- U32 nbAttempts = 1U << cParams->searchLog;
- size_t ml=4-1;
-
- /* HC4 match finder */
- U32 matchIndex = ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, mls);
-
- for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
- size_t currentMl=0;
- if ((dictMode != ZSTD_extDict) || matchIndex >= dictLimit) {
- const BYTE* const match = base + matchIndex;
- assert(matchIndex >= dictLimit); /* ensures this is true if dictMode != ZSTD_extDict */
- if (match[ml] == ip[ml]) /* potentially better */
- currentMl = ZSTD_count(ip, match, iLimit);
- } else {
- const BYTE* const match = dictBase + matchIndex;
- assert(match+4 <= dictEnd);
- if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
- currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dictEnd, prefixStart) + 4;
- }
-
- /* save best solution */
- if (currentMl > ml) {
- ml = currentMl;
- *offsetPtr = current - matchIndex + ZSTD_REP_MOVE;
- if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */
- }
-
- if (matchIndex <= minChain) break;
- matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
- }
-
- if (dictMode == ZSTD_dictMatchState) {
- const ZSTD_matchState_t* const dms = ms->dictMatchState;
- const U32* const dmsChainTable = dms->chainTable;
- const U32 dmsChainSize = (1 << dms->cParams.chainLog);
- const U32 dmsChainMask = dmsChainSize - 1;
- const U32 dmsLowestIndex = dms->window.dictLimit;
- const BYTE* const dmsBase = dms->window.base;
- const BYTE* const dmsEnd = dms->window.nextSrc;
- const U32 dmsSize = (U32)(dmsEnd - dmsBase);
- const U32 dmsIndexDelta = dictLimit - dmsSize;
- const U32 dmsMinChain = dmsSize > dmsChainSize ? dmsSize - dmsChainSize : 0;
-
- matchIndex = dms->hashTable[ZSTD_hashPtr(ip, dms->cParams.hashLog, mls)];
-
- for ( ; (matchIndex>dmsLowestIndex) & (nbAttempts>0) ; nbAttempts--) {
- size_t currentMl=0;
- const BYTE* const match = dmsBase + matchIndex;
- assert(match+4 <= dmsEnd);
- if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
- currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dmsEnd, prefixStart) + 4;
-
- /* save best solution */
- if (currentMl > ml) {
- ml = currentMl;
- *offsetPtr = current - (matchIndex + dmsIndexDelta) + ZSTD_REP_MOVE;
- if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */
- }
-
- if (matchIndex <= dmsMinChain) break;
- matchIndex = dmsChainTable[matchIndex & dmsChainMask];
- }
- }
-
- return ml;
-}
-
-
-FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_selectMLS (
- ZSTD_matchState_t* ms,
- const BYTE* ip, const BYTE* const iLimit,
- size_t* offsetPtr)
-{
- switch(ms->cParams.minMatch)
- {
- default : /* includes case 3 */
- case 4 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 4, ZSTD_noDict);
- case 5 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 5, ZSTD_noDict);
- case 7 :
- case 6 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 6, ZSTD_noDict);
- }
-}
-
-
-static size_t ZSTD_HcFindBestMatch_dictMatchState_selectMLS (
- ZSTD_matchState_t* ms,
- const BYTE* ip, const BYTE* const iLimit,
- size_t* offsetPtr)
-{
- switch(ms->cParams.minMatch)
- {
- default : /* includes case 3 */
- case 4 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 4, ZSTD_dictMatchState);
- case 5 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 5, ZSTD_dictMatchState);
- case 7 :
- case 6 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 6, ZSTD_dictMatchState);
- }
-}
-
-
-FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
- ZSTD_matchState_t* ms,
- const BYTE* ip, const BYTE* const iLimit,
- size_t* offsetPtr)
-{
- switch(ms->cParams.minMatch)
- {
- default : /* includes case 3 */
- case 4 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 4, ZSTD_extDict);
- case 5 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 5, ZSTD_extDict);
- case 7 :
- case 6 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 6, ZSTD_extDict);
- }
-}
-
-
-/* *******************************
-* Common parser - lazy strategy
-*********************************/
-typedef enum { search_hashChain, search_binaryTree } searchMethod_e;
-
-FORCE_INLINE_TEMPLATE size_t
-ZSTD_compressBlock_lazy_generic(
- ZSTD_matchState_t* ms, seqStore_t* seqStore,
- U32 rep[ZSTD_REP_NUM],
- const void* src, size_t srcSize,
- const searchMethod_e searchMethod, const U32 depth,
- ZSTD_dictMode_e const dictMode)
-{
- const BYTE* const istart = (const BYTE*)src;
- const BYTE* ip = istart;
- const BYTE* anchor = istart;
- const BYTE* const iend = istart + srcSize;
- const BYTE* const ilimit = iend - 8;
- const BYTE* const base = ms->window.base;
- const U32 prefixLowestIndex = ms->window.dictLimit;
- const BYTE* const prefixLowest = base + prefixLowestIndex;
-
- typedef size_t (*searchMax_f)(
- ZSTD_matchState_t* ms,
- const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr);
- searchMax_f const searchMax = dictMode == ZSTD_dictMatchState ?
- (searchMethod==search_binaryTree ? ZSTD_BtFindBestMatch_dictMatchState_selectMLS
- : ZSTD_HcFindBestMatch_dictMatchState_selectMLS) :
- (searchMethod==search_binaryTree ? ZSTD_BtFindBestMatch_selectMLS
- : ZSTD_HcFindBestMatch_selectMLS);
- U32 offset_1 = rep[0], offset_2 = rep[1], savedOffset=0;
-
- const ZSTD_matchState_t* const dms = ms->dictMatchState;
- const U32 dictLowestIndex = dictMode == ZSTD_dictMatchState ?
- dms->window.dictLimit : 0;
- const BYTE* const dictBase = dictMode == ZSTD_dictMatchState ?
- dms->window.base : NULL;
- const BYTE* const dictLowest = dictMode == ZSTD_dictMatchState ?
- dictBase + dictLowestIndex : NULL;
- const BYTE* const dictEnd = dictMode == ZSTD_dictMatchState ?
- dms->window.nextSrc : NULL;
- const U32 dictIndexDelta = dictMode == ZSTD_dictMatchState ?
- prefixLowestIndex - (U32)(dictEnd - dictBase) :
- 0;
- const U32 dictAndPrefixLength = (U32)((ip - prefixLowest) + (dictEnd - dictLowest));
-
- DEBUGLOG(5, "ZSTD_compressBlock_lazy_generic (dictMode=%u)", (U32)dictMode);
-
- /* init */
- ip += (dictAndPrefixLength == 0);
- if (dictMode == ZSTD_noDict) {
- U32 const current = (U32)(ip - base);
- U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, current, ms->cParams.windowLog);
- U32 const maxRep = current - windowLow;
- if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
- if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
- }
- if (dictMode == ZSTD_dictMatchState) {
- /* dictMatchState repCode checks don't currently handle repCode == 0
- * disabling. */
- assert(offset_1 <= dictAndPrefixLength);
- assert(offset_2 <= dictAndPrefixLength);
- }
-
- /* Match Loop */
-#if defined(__GNUC__) && defined(__x86_64__)
- /* I've measured random a 5% speed loss on levels 5 & 6 (greedy) when the
- * code alignment is perturbed. To fix the instability align the loop on 32-bytes.
- */
- __asm__(".p2align 5");
-#endif
- while (ip < ilimit) {
- size_t matchLength=0;
- size_t offset=0;
- const BYTE* start=ip+1;
-
- /* check repCode */
- if (dictMode == ZSTD_dictMatchState) {
- const U32 repIndex = (U32)(ip - base) + 1 - offset_1;
- const BYTE* repMatch = (dictMode == ZSTD_dictMatchState
- && repIndex < prefixLowestIndex) ?
- dictBase + (repIndex - dictIndexDelta) :
- base + repIndex;
- if (((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */)
- && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
- const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend;
- matchLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4;
- if (depth==0) goto _storeSequence;
- }
- }
- if ( dictMode == ZSTD_noDict
- && ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)))) {
- matchLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
- if (depth==0) goto _storeSequence;
- }
-
- /* first search (depth 0) */
- { size_t offsetFound = 999999999;
- size_t const ml2 = searchMax(ms, ip, iend, &offsetFound);
- if (ml2 > matchLength)
- matchLength = ml2, start = ip, offset=offsetFound;
- }
-
- if (matchLength < 4) {
- ip += ((ip-anchor) >> kSearchStrength) + 1; /* jump faster over incompressible sections */
- continue;
- }
-
- /* let's try to find a better solution */
- if (depth>=1)
- while (ip<ilimit) {
- ip ++;
- if ( (dictMode == ZSTD_noDict)
- && (offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
- size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
- int const gain2 = (int)(mlRep * 3);
- int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
- if ((mlRep >= 4) && (gain2 > gain1))
- matchLength = mlRep, offset = 0, start = ip;
- }
- if (dictMode == ZSTD_dictMatchState) {
- const U32 repIndex = (U32)(ip - base) - offset_1;
- const BYTE* repMatch = repIndex < prefixLowestIndex ?
- dictBase + (repIndex - dictIndexDelta) :
- base + repIndex;
- if (((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */)
- && (MEM_read32(repMatch) == MEM_read32(ip)) ) {
- const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend;
- size_t const mlRep = ZSTD_count_2segments(ip+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4;
- int const gain2 = (int)(mlRep * 3);
- int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
- if ((mlRep >= 4) && (gain2 > gain1))
- matchLength = mlRep, offset = 0, start = ip;
- }
- }
- { size_t offset2=999999999;
- size_t const ml2 = searchMax(ms, ip, iend, &offset2);
- int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
- int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
- if ((ml2 >= 4) && (gain2 > gain1)) {
- matchLength = ml2, offset = offset2, start = ip;
- continue; /* search a better one */
- } }
-
- /* let's find an even better one */
- if ((depth==2) && (ip<ilimit)) {
- ip ++;
- if ( (dictMode == ZSTD_noDict)
- && (offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
- size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
- int const gain2 = (int)(mlRep * 4);
- int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
- if ((mlRep >= 4) && (gain2 > gain1))
- matchLength = mlRep, offset = 0, start = ip;
- }
- if (dictMode == ZSTD_dictMatchState) {
- const U32 repIndex = (U32)(ip - base) - offset_1;
- const BYTE* repMatch = repIndex < prefixLowestIndex ?
- dictBase + (repIndex - dictIndexDelta) :
- base + repIndex;
- if (((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */)
- && (MEM_read32(repMatch) == MEM_read32(ip)) ) {
- const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend;
- size_t const mlRep = ZSTD_count_2segments(ip+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4;
- int const gain2 = (int)(mlRep * 4);
- int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
- if ((mlRep >= 4) && (gain2 > gain1))
- matchLength = mlRep, offset = 0, start = ip;
- }
- }
- { size_t offset2=999999999;
- size_t const ml2 = searchMax(ms, ip, iend, &offset2);
- int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
- int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
- if ((ml2 >= 4) && (gain2 > gain1)) {
- matchLength = ml2, offset = offset2, start = ip;
- continue;
- } } }
- break; /* nothing found : store previous solution */
- }
-
- /* NOTE:
- * start[-offset+ZSTD_REP_MOVE-1] is undefined behavior.
- * (-offset+ZSTD_REP_MOVE-1) is unsigned, and is added to start, which
- * overflows the pointer, which is undefined behavior.
- */
- /* catch up */
- if (offset) {
- if (dictMode == ZSTD_noDict) {
- while ( ((start > anchor) & (start - (offset-ZSTD_REP_MOVE) > prefixLowest))
- && (start[-1] == (start-(offset-ZSTD_REP_MOVE))[-1]) ) /* only search for offset within prefix */
- { start--; matchLength++; }
- }
- if (dictMode == ZSTD_dictMatchState) {
- U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
- const BYTE* match = (matchIndex < prefixLowestIndex) ? dictBase + matchIndex - dictIndexDelta : base + matchIndex;
- const BYTE* const mStart = (matchIndex < prefixLowestIndex) ? dictLowest : prefixLowest;
- while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
- }
- offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
- }
- /* store sequence */
-_storeSequence:
- { size_t const litLength = start - anchor;
- ZSTD_storeSeq(seqStore, litLength, anchor, iend, (U32)offset, matchLength-MINMATCH);
- anchor = ip = start + matchLength;
- }
-
- /* check immediate repcode */
- if (dictMode == ZSTD_dictMatchState) {
- while (ip <= ilimit) {
- U32 const current2 = (U32)(ip-base);
- U32 const repIndex = current2 - offset_2;
- const BYTE* repMatch = dictMode == ZSTD_dictMatchState
- && repIndex < prefixLowestIndex ?
- dictBase - dictIndexDelta + repIndex :
- base + repIndex;
- if ( ((U32)((prefixLowestIndex-1) - (U32)repIndex) >= 3 /* intentional overflow */)
- && (MEM_read32(repMatch) == MEM_read32(ip)) ) {
- const BYTE* const repEnd2 = repIndex < prefixLowestIndex ? dictEnd : iend;
- matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd2, prefixLowest) + 4;
- offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset_2 <=> offset_1 */
- ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, matchLength-MINMATCH);
- ip += matchLength;
- anchor = ip;
- continue;
- }
- break;
- }
- }
-
- if (dictMode == ZSTD_noDict) {
- while ( ((ip <= ilimit) & (offset_2>0))
- && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) {
- /* store sequence */
- matchLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
- offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
- ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, matchLength-MINMATCH);
- ip += matchLength;
- anchor = ip;
- continue; /* faster when present ... (?) */
- } } }
-
- /* Save reps for next block */
- rep[0] = offset_1 ? offset_1 : savedOffset;
- rep[1] = offset_2 ? offset_2 : savedOffset;
-
- /* Return the last literals size */
- return (size_t)(iend - anchor);
-}
-
-
-size_t ZSTD_compressBlock_btlazy2(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize)
-{
- return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_binaryTree, 2, ZSTD_noDict);
-}
-
-size_t ZSTD_compressBlock_lazy2(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize)
-{
- return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 2, ZSTD_noDict);
-}
-
-size_t ZSTD_compressBlock_lazy(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize)
-{
- return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 1, ZSTD_noDict);
-}
-
-size_t ZSTD_compressBlock_greedy(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize)
-{
- return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 0, ZSTD_noDict);
-}
-
-size_t ZSTD_compressBlock_btlazy2_dictMatchState(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize)
-{
- return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_binaryTree, 2, ZSTD_dictMatchState);
-}
-
-size_t ZSTD_compressBlock_lazy2_dictMatchState(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize)
-{
- return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 2, ZSTD_dictMatchState);
-}
-
-size_t ZSTD_compressBlock_lazy_dictMatchState(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize)
-{
- return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 1, ZSTD_dictMatchState);
-}
-
-size_t ZSTD_compressBlock_greedy_dictMatchState(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize)
-{
- return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 0, ZSTD_dictMatchState);
-}
-
-
-FORCE_INLINE_TEMPLATE
-size_t ZSTD_compressBlock_lazy_extDict_generic(
- ZSTD_matchState_t* ms, seqStore_t* seqStore,
- U32 rep[ZSTD_REP_NUM],
- const void* src, size_t srcSize,
- const searchMethod_e searchMethod, const U32 depth)
-{
- const BYTE* const istart = (const BYTE*)src;
- const BYTE* ip = istart;
- const BYTE* anchor = istart;
- const BYTE* const iend = istart + srcSize;
- const BYTE* const ilimit = iend - 8;
- const BYTE* const base = ms->window.base;
- const U32 dictLimit = ms->window.dictLimit;
- const BYTE* const prefixStart = base + dictLimit;
- const BYTE* const dictBase = ms->window.dictBase;
- const BYTE* const dictEnd = dictBase + dictLimit;
- const BYTE* const dictStart = dictBase + ms->window.lowLimit;
- const U32 windowLog = ms->cParams.windowLog;
-
- typedef size_t (*searchMax_f)(
- ZSTD_matchState_t* ms,
- const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr);
- searchMax_f searchMax = searchMethod==search_binaryTree ? ZSTD_BtFindBestMatch_extDict_selectMLS : ZSTD_HcFindBestMatch_extDict_selectMLS;
-
- U32 offset_1 = rep[0], offset_2 = rep[1];
-
- DEBUGLOG(5, "ZSTD_compressBlock_lazy_extDict_generic");
-
- /* init */
- ip += (ip == prefixStart);
-
- /* Match Loop */
-#if defined(__GNUC__) && defined(__x86_64__)
- /* I've measured random a 5% speed loss on levels 5 & 6 (greedy) when the
- * code alignment is perturbed. To fix the instability align the loop on 32-bytes.
- */
- __asm__(".p2align 5");
-#endif
- while (ip < ilimit) {
- size_t matchLength=0;
- size_t offset=0;
- const BYTE* start=ip+1;
- U32 current = (U32)(ip-base);
-
- /* check repCode */
- { const U32 windowLow = ZSTD_getLowestMatchIndex(ms, current+1, windowLog);
- const U32 repIndex = (U32)(current+1 - offset_1);
- const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
- const BYTE* const repMatch = repBase + repIndex;
- if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > windowLow)) /* intentional overflow */
- if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
- /* repcode detected we should take it */
- const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
- matchLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repEnd, prefixStart) + 4;
- if (depth==0) goto _storeSequence;
- } }
-
- /* first search (depth 0) */
- { size_t offsetFound = 999999999;
- size_t const ml2 = searchMax(ms, ip, iend, &offsetFound);
- if (ml2 > matchLength)
- matchLength = ml2, start = ip, offset=offsetFound;
- }
-
- if (matchLength < 4) {
- ip += ((ip-anchor) >> kSearchStrength) + 1; /* jump faster over incompressible sections */
- continue;
- }
-
- /* let's try to find a better solution */
- if (depth>=1)
- while (ip<ilimit) {
- ip ++;
- current++;
- /* check repCode */
- if (offset) {
- const U32 windowLow = ZSTD_getLowestMatchIndex(ms, current, windowLog);
- const U32 repIndex = (U32)(current - offset_1);
- const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
- const BYTE* const repMatch = repBase + repIndex;
- if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > windowLow)) /* intentional overflow */
- if (MEM_read32(ip) == MEM_read32(repMatch)) {
- /* repcode detected */
- const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
- size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
- int const gain2 = (int)(repLength * 3);
- int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
- if ((repLength >= 4) && (gain2 > gain1))
- matchLength = repLength, offset = 0, start = ip;
- } }
-
- /* search match, depth 1 */
- { size_t offset2=999999999;
- size_t const ml2 = searchMax(ms, ip, iend, &offset2);
- int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
- int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
- if ((ml2 >= 4) && (gain2 > gain1)) {
- matchLength = ml2, offset = offset2, start = ip;
- continue; /* search a better one */
- } }
-
- /* let's find an even better one */
- if ((depth==2) && (ip<ilimit)) {
- ip ++;
- current++;
- /* check repCode */
- if (offset) {
- const U32 windowLow = ZSTD_getLowestMatchIndex(ms, current, windowLog);
- const U32 repIndex = (U32)(current - offset_1);
- const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
- const BYTE* const repMatch = repBase + repIndex;
- if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > windowLow)) /* intentional overflow */
- if (MEM_read32(ip) == MEM_read32(repMatch)) {
- /* repcode detected */
- const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
- size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
- int const gain2 = (int)(repLength * 4);
- int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
- if ((repLength >= 4) && (gain2 > gain1))
- matchLength = repLength, offset = 0, start = ip;
- } }
-
- /* search match, depth 2 */
- { size_t offset2=999999999;
- size_t const ml2 = searchMax(ms, ip, iend, &offset2);
- int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
- int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
- if ((ml2 >= 4) && (gain2 > gain1)) {
- matchLength = ml2, offset = offset2, start = ip;
- continue;
- } } }
- break; /* nothing found : store previous solution */
- }
-
- /* catch up */
- if (offset) {
- U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
- const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
- const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
- while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
- offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
- }
-
- /* store sequence */
-_storeSequence:
- { size_t const litLength = start - anchor;
- ZSTD_storeSeq(seqStore, litLength, anchor, iend, (U32)offset, matchLength-MINMATCH);
- anchor = ip = start + matchLength;
- }
-
- /* check immediate repcode */
- while (ip <= ilimit) {
- const U32 repCurrent = (U32)(ip-base);
- const U32 windowLow = ZSTD_getLowestMatchIndex(ms, repCurrent, windowLog);
- const U32 repIndex = repCurrent - offset_2;
- const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
- const BYTE* const repMatch = repBase + repIndex;
- if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > windowLow)) /* intentional overflow */
- if (MEM_read32(ip) == MEM_read32(repMatch)) {
- /* repcode detected we should take it */
- const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
- matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
- offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset history */
- ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, matchLength-MINMATCH);
- ip += matchLength;
- anchor = ip;
- continue; /* faster when present ... (?) */
- }
- break;
- } }
-
- /* Save reps for next block */
- rep[0] = offset_1;
- rep[1] = offset_2;
-
- /* Return the last literals size */
- return (size_t)(iend - anchor);
-}
-
-
-size_t ZSTD_compressBlock_greedy_extDict(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize)
-{
- return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 0);
-}
-
-size_t ZSTD_compressBlock_lazy_extDict(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize)
-
-{
- return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 1);
-}
-
-size_t ZSTD_compressBlock_lazy2_extDict(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize)
-
-{
- return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 2);
-}
-
-size_t ZSTD_compressBlock_btlazy2_extDict(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize)
-
-{
- return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_binaryTree, 2);
-}
-/**** ended inlining compress/zstd_lazy.c ****/
-/**** start inlining compress/zstd_ldm.c ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-/**** skipping file: zstd_ldm.h ****/
-
-/**** skipping file: ../common/debug.h ****/
-/**** skipping file: zstd_fast.h ****/
-/**** skipping file: zstd_double_fast.h ****/
-
-#define LDM_BUCKET_SIZE_LOG 3
-#define LDM_MIN_MATCH_LENGTH 64
-#define LDM_HASH_RLOG 7
-#define LDM_HASH_CHAR_OFFSET 10
-
-void ZSTD_ldm_adjustParameters(ldmParams_t* params,
- ZSTD_compressionParameters const* cParams)
-{
- params->windowLog = cParams->windowLog;
- ZSTD_STATIC_ASSERT(LDM_BUCKET_SIZE_LOG <= ZSTD_LDM_BUCKETSIZELOG_MAX);
- DEBUGLOG(4, "ZSTD_ldm_adjustParameters");
- if (!params->bucketSizeLog) params->bucketSizeLog = LDM_BUCKET_SIZE_LOG;
- if (!params->minMatchLength) params->minMatchLength = LDM_MIN_MATCH_LENGTH;
- if (cParams->strategy >= ZSTD_btopt) {
- /* Get out of the way of the optimal parser */
- U32 const minMatch = MAX(cParams->targetLength, params->minMatchLength);
- assert(minMatch >= ZSTD_LDM_MINMATCH_MIN);
- assert(minMatch <= ZSTD_LDM_MINMATCH_MAX);
- params->minMatchLength = minMatch;
- }
- if (params->hashLog == 0) {
- params->hashLog = MAX(ZSTD_HASHLOG_MIN, params->windowLog - LDM_HASH_RLOG);
- assert(params->hashLog <= ZSTD_HASHLOG_MAX);
- }
- if (params->hashRateLog == 0) {
- params->hashRateLog = params->windowLog < params->hashLog
- ? 0
- : params->windowLog - params->hashLog;
- }
- params->bucketSizeLog = MIN(params->bucketSizeLog, params->hashLog);
-}
-
-size_t ZSTD_ldm_getTableSize(ldmParams_t params)
-{
- size_t const ldmHSize = ((size_t)1) << params.hashLog;
- size_t const ldmBucketSizeLog = MIN(params.bucketSizeLog, params.hashLog);
- size_t const ldmBucketSize = ((size_t)1) << (params.hashLog - ldmBucketSizeLog);
- size_t const totalSize = ZSTD_cwksp_alloc_size(ldmBucketSize)
- + ZSTD_cwksp_alloc_size(ldmHSize * sizeof(ldmEntry_t));
- return params.enableLdm ? totalSize : 0;
-}
-
-size_t ZSTD_ldm_getMaxNbSeq(ldmParams_t params, size_t maxChunkSize)
-{
- return params.enableLdm ? (maxChunkSize / params.minMatchLength) : 0;
-}
-
-/** ZSTD_ldm_getSmallHash() :
- * numBits should be <= 32
- * If numBits==0, returns 0.
- * @return : the most significant numBits of value. */
-static U32 ZSTD_ldm_getSmallHash(U64 value, U32 numBits)
-{
- assert(numBits <= 32);
- return numBits == 0 ? 0 : (U32)(value >> (64 - numBits));
-}
-
-/** ZSTD_ldm_getChecksum() :
- * numBitsToDiscard should be <= 32
- * @return : the next most significant 32 bits after numBitsToDiscard */
-static U32 ZSTD_ldm_getChecksum(U64 hash, U32 numBitsToDiscard)
-{
- assert(numBitsToDiscard <= 32);
- return (hash >> (64 - 32 - numBitsToDiscard)) & 0xFFFFFFFF;
-}
-
-/** ZSTD_ldm_getTag() ;
- * Given the hash, returns the most significant numTagBits bits
- * after (32 + hbits) bits.
- *
- * If there are not enough bits remaining, return the last
- * numTagBits bits. */
-static U32 ZSTD_ldm_getTag(U64 hash, U32 hbits, U32 numTagBits)
-{
- assert(numTagBits < 32 && hbits <= 32);
- if (32 - hbits < numTagBits) {
- return hash & (((U32)1 << numTagBits) - 1);
- } else {
- return (hash >> (32 - hbits - numTagBits)) & (((U32)1 << numTagBits) - 1);
- }
-}
-
-/** ZSTD_ldm_getBucket() :
- * Returns a pointer to the start of the bucket associated with hash. */
-static ldmEntry_t* ZSTD_ldm_getBucket(
- ldmState_t* ldmState, size_t hash, ldmParams_t const ldmParams)
-{
- return ldmState->hashTable + (hash << ldmParams.bucketSizeLog);
-}
-
-/** ZSTD_ldm_insertEntry() :
- * Insert the entry with corresponding hash into the hash table */
-static void ZSTD_ldm_insertEntry(ldmState_t* ldmState,
- size_t const hash, const ldmEntry_t entry,
- ldmParams_t const ldmParams)
-{
- BYTE* const bucketOffsets = ldmState->bucketOffsets;
- *(ZSTD_ldm_getBucket(ldmState, hash, ldmParams) + bucketOffsets[hash]) = entry;
- bucketOffsets[hash]++;
- bucketOffsets[hash] &= ((U32)1 << ldmParams.bucketSizeLog) - 1;
-}
-
-/** ZSTD_ldm_makeEntryAndInsertByTag() :
- *
- * Gets the small hash, checksum, and tag from the rollingHash.
- *
- * If the tag matches (1 << ldmParams.hashRateLog)-1, then
- * creates an ldmEntry from the offset, and inserts it into the hash table.
- *
- * hBits is the length of the small hash, which is the most significant hBits
- * of rollingHash. The checksum is the next 32 most significant bits, followed
- * by ldmParams.hashRateLog bits that make up the tag. */
-static void ZSTD_ldm_makeEntryAndInsertByTag(ldmState_t* ldmState,
- U64 const rollingHash,
- U32 const hBits,
- U32 const offset,
- ldmParams_t const ldmParams)
-{
- U32 const tag = ZSTD_ldm_getTag(rollingHash, hBits, ldmParams.hashRateLog);
- U32 const tagMask = ((U32)1 << ldmParams.hashRateLog) - 1;
- if (tag == tagMask) {
- U32 const hash = ZSTD_ldm_getSmallHash(rollingHash, hBits);
- U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits);
- ldmEntry_t entry;
- entry.offset = offset;
- entry.checksum = checksum;
- ZSTD_ldm_insertEntry(ldmState, hash, entry, ldmParams);
- }
-}
-
-/** ZSTD_ldm_countBackwardsMatch() :
- * Returns the number of bytes that match backwards before pIn and pMatch.
- *
- * We count only bytes where pMatch >= pBase and pIn >= pAnchor. */
-static size_t ZSTD_ldm_countBackwardsMatch(
- const BYTE* pIn, const BYTE* pAnchor,
- const BYTE* pMatch, const BYTE* pBase)
-{
- size_t matchLength = 0;
- while (pIn > pAnchor && pMatch > pBase && pIn[-1] == pMatch[-1]) {
- pIn--;
- pMatch--;
- matchLength++;
- }
- return matchLength;
-}
-
-/** ZSTD_ldm_fillFastTables() :
- *
- * Fills the relevant tables for the ZSTD_fast and ZSTD_dfast strategies.
- * This is similar to ZSTD_loadDictionaryContent.
- *
- * The tables for the other strategies are filled within their
- * block compressors. */
-static size_t ZSTD_ldm_fillFastTables(ZSTD_matchState_t* ms,
- void const* end)
-{
- const BYTE* const iend = (const BYTE*)end;
-
- switch(ms->cParams.strategy)
- {
- case ZSTD_fast:
- ZSTD_fillHashTable(ms, iend, ZSTD_dtlm_fast);
- break;
-
- case ZSTD_dfast:
- ZSTD_fillDoubleHashTable(ms, iend, ZSTD_dtlm_fast);
- break;
-
- case ZSTD_greedy:
- case ZSTD_lazy:
- case ZSTD_lazy2:
- case ZSTD_btlazy2:
- case ZSTD_btopt:
- case ZSTD_btultra:
- case ZSTD_btultra2:
- break;
- default:
- assert(0); /* not possible : not a valid strategy id */
- }
-
- return 0;
-}
-
-/** ZSTD_ldm_fillLdmHashTable() :
- *
- * Fills hashTable from (lastHashed + 1) to iend (non-inclusive).
- * lastHash is the rolling hash that corresponds to lastHashed.
- *
- * Returns the rolling hash corresponding to position iend-1. */
-static U64 ZSTD_ldm_fillLdmHashTable(ldmState_t* state,
- U64 lastHash, const BYTE* lastHashed,
- const BYTE* iend, const BYTE* base,
- U32 hBits, ldmParams_t const ldmParams)
-{
- U64 rollingHash = lastHash;
- const BYTE* cur = lastHashed + 1;
-
- while (cur < iend) {
- rollingHash = ZSTD_rollingHash_rotate(rollingHash, cur[-1],
- cur[ldmParams.minMatchLength-1],
- state->hashPower);
- ZSTD_ldm_makeEntryAndInsertByTag(state,
- rollingHash, hBits,
- (U32)(cur - base), ldmParams);
- ++cur;
- }
- return rollingHash;
-}
-
-void ZSTD_ldm_fillHashTable(
- ldmState_t* state, const BYTE* ip,
- const BYTE* iend, ldmParams_t const* params)
-{
- DEBUGLOG(5, "ZSTD_ldm_fillHashTable");
- if ((size_t)(iend - ip) >= params->minMatchLength) {
- U64 startingHash = ZSTD_rollingHash_compute(ip, params->minMatchLength);
- ZSTD_ldm_fillLdmHashTable(
- state, startingHash, ip, iend - params->minMatchLength, state->window.base,
- params->hashLog - params->bucketSizeLog,
- *params);
- }
-}
-
-
-/** ZSTD_ldm_limitTableUpdate() :
- *
- * Sets cctx->nextToUpdate to a position corresponding closer to anchor
- * if it is far way
- * (after a long match, only update tables a limited amount). */
-static void ZSTD_ldm_limitTableUpdate(ZSTD_matchState_t* ms, const BYTE* anchor)
-{
- U32 const current = (U32)(anchor - ms->window.base);
- if (current > ms->nextToUpdate + 1024) {
- ms->nextToUpdate =
- current - MIN(512, current - ms->nextToUpdate - 1024);
- }
-}
-
-static size_t ZSTD_ldm_generateSequences_internal(
- ldmState_t* ldmState, rawSeqStore_t* rawSeqStore,
- ldmParams_t const* params, void const* src, size_t srcSize)
-{
- /* LDM parameters */
- int const extDict = ZSTD_window_hasExtDict(ldmState->window);
- U32 const minMatchLength = params->minMatchLength;
- U64 const hashPower = ldmState->hashPower;
- U32 const hBits = params->hashLog - params->bucketSizeLog;
- U32 const ldmBucketSize = 1U << params->bucketSizeLog;
- U32 const hashRateLog = params->hashRateLog;
- U32 const ldmTagMask = (1U << params->hashRateLog) - 1;
- /* Prefix and extDict parameters */
- U32 const dictLimit = ldmState->window.dictLimit;
- U32 const lowestIndex = extDict ? ldmState->window.lowLimit : dictLimit;
- BYTE const* const base = ldmState->window.base;
- BYTE const* const dictBase = extDict ? ldmState->window.dictBase : NULL;
- BYTE const* const dictStart = extDict ? dictBase + lowestIndex : NULL;
- BYTE const* const dictEnd = extDict ? dictBase + dictLimit : NULL;
- BYTE const* const lowPrefixPtr = base + dictLimit;
- /* Input bounds */
- BYTE const* const istart = (BYTE const*)src;
- BYTE const* const iend = istart + srcSize;
- BYTE const* const ilimit = iend - MAX(minMatchLength, HASH_READ_SIZE);
- /* Input positions */
- BYTE const* anchor = istart;
- BYTE const* ip = istart;
- /* Rolling hash */
- BYTE const* lastHashed = NULL;
- U64 rollingHash = 0;
-
- while (ip <= ilimit) {
- size_t mLength;
- U32 const current = (U32)(ip - base);
- size_t forwardMatchLength = 0, backwardMatchLength = 0;
- ldmEntry_t* bestEntry = NULL;
- if (ip != istart) {
- rollingHash = ZSTD_rollingHash_rotate(rollingHash, lastHashed[0],
- lastHashed[minMatchLength],
- hashPower);
- } else {
- rollingHash = ZSTD_rollingHash_compute(ip, minMatchLength);
- }
- lastHashed = ip;
-
- /* Do not insert and do not look for a match */
- if (ZSTD_ldm_getTag(rollingHash, hBits, hashRateLog) != ldmTagMask) {
- ip++;
- continue;
- }
-
- /* Get the best entry and compute the match lengths */
- {
- ldmEntry_t* const bucket =
- ZSTD_ldm_getBucket(ldmState,
- ZSTD_ldm_getSmallHash(rollingHash, hBits),
- *params);
- ldmEntry_t* cur;
- size_t bestMatchLength = 0;
- U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits);
-
- for (cur = bucket; cur < bucket + ldmBucketSize; ++cur) {
- size_t curForwardMatchLength, curBackwardMatchLength,
- curTotalMatchLength;
- if (cur->checksum != checksum || cur->offset <= lowestIndex) {
- continue;
- }
- if (extDict) {
- BYTE const* const curMatchBase =
- cur->offset < dictLimit ? dictBase : base;
- BYTE const* const pMatch = curMatchBase + cur->offset;
- BYTE const* const matchEnd =
- cur->offset < dictLimit ? dictEnd : iend;
- BYTE const* const lowMatchPtr =
- cur->offset < dictLimit ? dictStart : lowPrefixPtr;
-
- curForwardMatchLength = ZSTD_count_2segments(
- ip, pMatch, iend,
- matchEnd, lowPrefixPtr);
- if (curForwardMatchLength < minMatchLength) {
- continue;
- }
- curBackwardMatchLength =
- ZSTD_ldm_countBackwardsMatch(ip, anchor, pMatch,
- lowMatchPtr);
- curTotalMatchLength = curForwardMatchLength +
- curBackwardMatchLength;
- } else { /* !extDict */
- BYTE const* const pMatch = base + cur->offset;
- curForwardMatchLength = ZSTD_count(ip, pMatch, iend);
- if (curForwardMatchLength < minMatchLength) {
- continue;
- }
- curBackwardMatchLength =
- ZSTD_ldm_countBackwardsMatch(ip, anchor, pMatch,
- lowPrefixPtr);
- curTotalMatchLength = curForwardMatchLength +
- curBackwardMatchLength;
- }
-
- if (curTotalMatchLength > bestMatchLength) {
- bestMatchLength = curTotalMatchLength;
- forwardMatchLength = curForwardMatchLength;
- backwardMatchLength = curBackwardMatchLength;
- bestEntry = cur;
- }
- }
- }
-
- /* No match found -- continue searching */
- if (bestEntry == NULL) {
- ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash,
- hBits, current,
- *params);
- ip++;
- continue;
- }
-
- /* Match found */
- mLength = forwardMatchLength + backwardMatchLength;
- ip -= backwardMatchLength;
-
- {
- /* Store the sequence:
- * ip = current - backwardMatchLength
- * The match is at (bestEntry->offset - backwardMatchLength)
- */
- U32 const matchIndex = bestEntry->offset;
- U32 const offset = current - matchIndex;
- rawSeq* const seq = rawSeqStore->seq + rawSeqStore->size;
-
- /* Out of sequence storage */
- if (rawSeqStore->size == rawSeqStore->capacity)
- return ERROR(dstSize_tooSmall);
- seq->litLength = (U32)(ip - anchor);
- seq->matchLength = (U32)mLength;
- seq->offset = offset;
- rawSeqStore->size++;
- }
-
- /* Insert the current entry into the hash table */
- ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits,
- (U32)(lastHashed - base),
- *params);
-
- assert(ip + backwardMatchLength == lastHashed);
-
- /* Fill the hash table from lastHashed+1 to ip+mLength*/
- /* Heuristic: don't need to fill the entire table at end of block */
- if (ip + mLength <= ilimit) {
- rollingHash = ZSTD_ldm_fillLdmHashTable(
- ldmState, rollingHash, lastHashed,
- ip + mLength, base, hBits, *params);
- lastHashed = ip + mLength - 1;
- }
- ip += mLength;
- anchor = ip;
- }
- return iend - anchor;
-}
-
-/*! ZSTD_ldm_reduceTable() :
- * reduce table indexes by `reducerValue` */
-static void ZSTD_ldm_reduceTable(ldmEntry_t* const table, U32 const size,
- U32 const reducerValue)
-{
- U32 u;
- for (u = 0; u < size; u++) {
- if (table[u].offset < reducerValue) table[u].offset = 0;
- else table[u].offset -= reducerValue;
- }
-}
-
-size_t ZSTD_ldm_generateSequences(
- ldmState_t* ldmState, rawSeqStore_t* sequences,
- ldmParams_t const* params, void const* src, size_t srcSize)
-{
- U32 const maxDist = 1U << params->windowLog;
- BYTE const* const istart = (BYTE const*)src;
- BYTE const* const iend = istart + srcSize;
- size_t const kMaxChunkSize = 1 << 20;
- size_t const nbChunks = (srcSize / kMaxChunkSize) + ((srcSize % kMaxChunkSize) != 0);
- size_t chunk;
- size_t leftoverSize = 0;
-
- assert(ZSTD_CHUNKSIZE_MAX >= kMaxChunkSize);
- /* Check that ZSTD_window_update() has been called for this chunk prior
- * to passing it to this function.
- */
- assert(ldmState->window.nextSrc >= (BYTE const*)src + srcSize);
- /* The input could be very large (in zstdmt), so it must be broken up into
- * chunks to enforce the maximum distance and handle overflow correction.
- */
- assert(sequences->pos <= sequences->size);
- assert(sequences->size <= sequences->capacity);
- for (chunk = 0; chunk < nbChunks && sequences->size < sequences->capacity; ++chunk) {
- BYTE const* const chunkStart = istart + chunk * kMaxChunkSize;
- size_t const remaining = (size_t)(iend - chunkStart);
- BYTE const *const chunkEnd =
- (remaining < kMaxChunkSize) ? iend : chunkStart + kMaxChunkSize;
- size_t const chunkSize = chunkEnd - chunkStart;
- size_t newLeftoverSize;
- size_t const prevSize = sequences->size;
-
- assert(chunkStart < iend);
- /* 1. Perform overflow correction if necessary. */
- if (ZSTD_window_needOverflowCorrection(ldmState->window, chunkEnd)) {
- U32 const ldmHSize = 1U << params->hashLog;
- U32 const correction = ZSTD_window_correctOverflow(
- &ldmState->window, /* cycleLog */ 0, maxDist, chunkStart);
- ZSTD_ldm_reduceTable(ldmState->hashTable, ldmHSize, correction);
- /* invalidate dictionaries on overflow correction */
- ldmState->loadedDictEnd = 0;
- }
- /* 2. We enforce the maximum offset allowed.
- *
- * kMaxChunkSize should be small enough that we don't lose too much of
- * the window through early invalidation.
- * TODO: * Test the chunk size.
- * * Try invalidation after the sequence generation and test the
- * the offset against maxDist directly.
- *
- * NOTE: Because of dictionaries + sequence splitting we MUST make sure
- * that any offset used is valid at the END of the sequence, since it may
- * be split into two sequences. This condition holds when using
- * ZSTD_window_enforceMaxDist(), but if we move to checking offsets
- * against maxDist directly, we'll have to carefully handle that case.
- */
- ZSTD_window_enforceMaxDist(&ldmState->window, chunkEnd, maxDist, &ldmState->loadedDictEnd, NULL);
- /* 3. Generate the sequences for the chunk, and get newLeftoverSize. */
- newLeftoverSize = ZSTD_ldm_generateSequences_internal(
- ldmState, sequences, params, chunkStart, chunkSize);
- if (ZSTD_isError(newLeftoverSize))
- return newLeftoverSize;
- /* 4. We add the leftover literals from previous iterations to the first
- * newly generated sequence, or add the `newLeftoverSize` if none are
- * generated.
- */
- /* Prepend the leftover literals from the last call */
- if (prevSize < sequences->size) {
- sequences->seq[prevSize].litLength += (U32)leftoverSize;
- leftoverSize = newLeftoverSize;
- } else {
- assert(newLeftoverSize == chunkSize);
- leftoverSize += chunkSize;
- }
- }
- return 0;
-}
-
-void ZSTD_ldm_skipSequences(rawSeqStore_t* rawSeqStore, size_t srcSize, U32 const minMatch) {
- while (srcSize > 0 && rawSeqStore->pos < rawSeqStore->size) {
- rawSeq* seq = rawSeqStore->seq + rawSeqStore->pos;
- if (srcSize <= seq->litLength) {
- /* Skip past srcSize literals */
- seq->litLength -= (U32)srcSize;
- return;
- }
- srcSize -= seq->litLength;
- seq->litLength = 0;
- if (srcSize < seq->matchLength) {
- /* Skip past the first srcSize of the match */
- seq->matchLength -= (U32)srcSize;
- if (seq->matchLength < minMatch) {
- /* The match is too short, omit it */
- if (rawSeqStore->pos + 1 < rawSeqStore->size) {
- seq[1].litLength += seq[0].matchLength;
- }
- rawSeqStore->pos++;
- }
- return;
- }
- srcSize -= seq->matchLength;
- seq->matchLength = 0;
- rawSeqStore->pos++;
- }
-}
-
-/**
- * If the sequence length is longer than remaining then the sequence is split
- * between this block and the next.
- *
- * Returns the current sequence to handle, or if the rest of the block should
- * be literals, it returns a sequence with offset == 0.
- */
-static rawSeq maybeSplitSequence(rawSeqStore_t* rawSeqStore,
- U32 const remaining, U32 const minMatch)
-{
- rawSeq sequence = rawSeqStore->seq[rawSeqStore->pos];
- assert(sequence.offset > 0);
- /* Likely: No partial sequence */
- if (remaining >= sequence.litLength + sequence.matchLength) {
- rawSeqStore->pos++;
- return sequence;
- }
- /* Cut the sequence short (offset == 0 ==> rest is literals). */
- if (remaining <= sequence.litLength) {
- sequence.offset = 0;
- } else if (remaining < sequence.litLength + sequence.matchLength) {
- sequence.matchLength = remaining - sequence.litLength;
- if (sequence.matchLength < minMatch) {
- sequence.offset = 0;
- }
- }
- /* Skip past `remaining` bytes for the future sequences. */
- ZSTD_ldm_skipSequences(rawSeqStore, remaining, minMatch);
- return sequence;
-}
-
-size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- void const* src, size_t srcSize)
-{
- const ZSTD_compressionParameters* const cParams = &ms->cParams;
- unsigned const minMatch = cParams->minMatch;
- ZSTD_blockCompressor const blockCompressor =
- ZSTD_selectBlockCompressor(cParams->strategy, ZSTD_matchState_dictMode(ms));
- /* Input bounds */
- BYTE const* const istart = (BYTE const*)src;
- BYTE const* const iend = istart + srcSize;
- /* Input positions */
- BYTE const* ip = istart;
-
- DEBUGLOG(5, "ZSTD_ldm_blockCompress: srcSize=%zu", srcSize);
- assert(rawSeqStore->pos <= rawSeqStore->size);
- assert(rawSeqStore->size <= rawSeqStore->capacity);
- /* Loop through each sequence and apply the block compressor to the lits */
- while (rawSeqStore->pos < rawSeqStore->size && ip < iend) {
- /* maybeSplitSequence updates rawSeqStore->pos */
- rawSeq const sequence = maybeSplitSequence(rawSeqStore,
- (U32)(iend - ip), minMatch);
- int i;
- /* End signal */
- if (sequence.offset == 0)
- break;
-
- assert(ip + sequence.litLength + sequence.matchLength <= iend);
-
- /* Fill tables for block compressor */
- ZSTD_ldm_limitTableUpdate(ms, ip);
- ZSTD_ldm_fillFastTables(ms, ip);
- /* Run the block compressor */
- DEBUGLOG(5, "pos %u : calling block compressor on segment of size %u", (unsigned)(ip-istart), sequence.litLength);
- {
- size_t const newLitLength =
- blockCompressor(ms, seqStore, rep, ip, sequence.litLength);
- ip += sequence.litLength;
- /* Update the repcodes */
- for (i = ZSTD_REP_NUM - 1; i > 0; i--)
- rep[i] = rep[i-1];
- rep[0] = sequence.offset;
- /* Store the sequence */
- ZSTD_storeSeq(seqStore, newLitLength, ip - newLitLength, iend,
- sequence.offset + ZSTD_REP_MOVE,
- sequence.matchLength - MINMATCH);
- ip += sequence.matchLength;
- }
- }
- /* Fill the tables for the block compressor */
- ZSTD_ldm_limitTableUpdate(ms, ip);
- ZSTD_ldm_fillFastTables(ms, ip);
- /* Compress the last literals */
- return blockCompressor(ms, seqStore, rep, ip, iend - ip);
-}
-/**** ended inlining compress/zstd_ldm.c ****/
-/**** start inlining compress/zstd_opt.c ****/
-/*
- * Copyright (c) 2016-2020, Przemyslaw Skibinski, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-/**** skipping file: zstd_compress_internal.h ****/
-/**** skipping file: hist.h ****/
-/**** skipping file: zstd_opt.h ****/
-
-
-#define ZSTD_LITFREQ_ADD 2 /* scaling factor for litFreq, so that frequencies adapt faster to new stats */
-#define ZSTD_FREQ_DIV 4 /* log factor when using previous stats to init next stats */
-#define ZSTD_MAX_PRICE (1<<30)
-
-#define ZSTD_PREDEF_THRESHOLD 1024 /* if srcSize < ZSTD_PREDEF_THRESHOLD, symbols' cost is assumed static, directly determined by pre-defined distributions */
-
-
-/*-*************************************
-* Price functions for optimal parser
-***************************************/
-
-#if 0 /* approximation at bit level */
-# define BITCOST_ACCURACY 0
-# define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY)
-# define WEIGHT(stat) ((void)opt, ZSTD_bitWeight(stat))
-#elif 0 /* fractional bit accuracy */
-# define BITCOST_ACCURACY 8
-# define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY)
-# define WEIGHT(stat,opt) ((void)opt, ZSTD_fracWeight(stat))
-#else /* opt==approx, ultra==accurate */
-# define BITCOST_ACCURACY 8
-# define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY)
-# define WEIGHT(stat,opt) (opt ? ZSTD_fracWeight(stat) : ZSTD_bitWeight(stat))
-#endif
-
-MEM_STATIC U32 ZSTD_bitWeight(U32 stat)
-{
- return (ZSTD_highbit32(stat+1) * BITCOST_MULTIPLIER);
-}
-
-MEM_STATIC U32 ZSTD_fracWeight(U32 rawStat)
-{
- U32 const stat = rawStat + 1;
- U32 const hb = ZSTD_highbit32(stat);
- U32 const BWeight = hb * BITCOST_MULTIPLIER;
- U32 const FWeight = (stat << BITCOST_ACCURACY) >> hb;
- U32 const weight = BWeight + FWeight;
- assert(hb + BITCOST_ACCURACY < 31);
- return weight;
-}
-
-#if (DEBUGLEVEL>=2)
-/* debugging function,
- * @return price in bytes as fractional value
- * for debug messages only */
-MEM_STATIC double ZSTD_fCost(U32 price)
-{
- return (double)price / (BITCOST_MULTIPLIER*8);
-}
-#endif
-
-static int ZSTD_compressedLiterals(optState_t const* const optPtr)
-{
- return optPtr->literalCompressionMode != ZSTD_lcm_uncompressed;
-}
-
-static void ZSTD_setBasePrices(optState_t* optPtr, int optLevel)
-{
- if (ZSTD_compressedLiterals(optPtr))
- optPtr->litSumBasePrice = WEIGHT(optPtr->litSum, optLevel);
- optPtr->litLengthSumBasePrice = WEIGHT(optPtr->litLengthSum, optLevel);
- optPtr->matchLengthSumBasePrice = WEIGHT(optPtr->matchLengthSum, optLevel);
- optPtr->offCodeSumBasePrice = WEIGHT(optPtr->offCodeSum, optLevel);
-}
-
-
-/* ZSTD_downscaleStat() :
- * reduce all elements in table by a factor 2^(ZSTD_FREQ_DIV+malus)
- * return the resulting sum of elements */
-static U32 ZSTD_downscaleStat(unsigned* table, U32 lastEltIndex, int malus)
-{
- U32 s, sum=0;
- DEBUGLOG(5, "ZSTD_downscaleStat (nbElts=%u)", (unsigned)lastEltIndex+1);
- assert(ZSTD_FREQ_DIV+malus > 0 && ZSTD_FREQ_DIV+malus < 31);
- for (s=0; s<lastEltIndex+1; s++) {
- table[s] = 1 + (table[s] >> (ZSTD_FREQ_DIV+malus));
- sum += table[s];
- }
- return sum;
-}
-
-/* ZSTD_rescaleFreqs() :
- * if first block (detected by optPtr->litLengthSum == 0) : init statistics
- * take hints from dictionary if there is one
- * or init from zero, using src for literals stats, or flat 1 for match symbols
- * otherwise downscale existing stats, to be used as seed for next block.
- */
-static void
-ZSTD_rescaleFreqs(optState_t* const optPtr,
- const BYTE* const src, size_t const srcSize,
- int const optLevel)
-{
- int const compressedLiterals = ZSTD_compressedLiterals(optPtr);
- DEBUGLOG(5, "ZSTD_rescaleFreqs (srcSize=%u)", (unsigned)srcSize);
- optPtr->priceType = zop_dynamic;
-
- if (optPtr->litLengthSum == 0) { /* first block : init */
- if (srcSize <= ZSTD_PREDEF_THRESHOLD) { /* heuristic */
- DEBUGLOG(5, "(srcSize <= ZSTD_PREDEF_THRESHOLD) => zop_predef");
- optPtr->priceType = zop_predef;
- }
-
- assert(optPtr->symbolCosts != NULL);
- if (optPtr->symbolCosts->huf.repeatMode == HUF_repeat_valid) {
- /* huffman table presumed generated by dictionary */
- optPtr->priceType = zop_dynamic;
-
- if (compressedLiterals) {
- unsigned lit;
- assert(optPtr->litFreq != NULL);
- optPtr->litSum = 0;
- for (lit=0; lit<=MaxLit; lit++) {
- U32 const scaleLog = 11; /* scale to 2K */
- U32 const bitCost = HUF_getNbBits(optPtr->symbolCosts->huf.CTable, lit);
- assert(bitCost <= scaleLog);
- optPtr->litFreq[lit] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/;
- optPtr->litSum += optPtr->litFreq[lit];
- } }
-
- { unsigned ll;
- FSE_CState_t llstate;
- FSE_initCState(&llstate, optPtr->symbolCosts->fse.litlengthCTable);
- optPtr->litLengthSum = 0;
- for (ll=0; ll<=MaxLL; ll++) {
- U32 const scaleLog = 10; /* scale to 1K */
- U32 const bitCost = FSE_getMaxNbBits(llstate.symbolTT, ll);
- assert(bitCost < scaleLog);
- optPtr->litLengthFreq[ll] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/;
- optPtr->litLengthSum += optPtr->litLengthFreq[ll];
- } }
-
- { unsigned ml;
- FSE_CState_t mlstate;
- FSE_initCState(&mlstate, optPtr->symbolCosts->fse.matchlengthCTable);
- optPtr->matchLengthSum = 0;
- for (ml=0; ml<=MaxML; ml++) {
- U32 const scaleLog = 10;
- U32 const bitCost = FSE_getMaxNbBits(mlstate.symbolTT, ml);
- assert(bitCost < scaleLog);
- optPtr->matchLengthFreq[ml] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/;
- optPtr->matchLengthSum += optPtr->matchLengthFreq[ml];
- } }
-
- { unsigned of;
- FSE_CState_t ofstate;
- FSE_initCState(&ofstate, optPtr->symbolCosts->fse.offcodeCTable);
- optPtr->offCodeSum = 0;
- for (of=0; of<=MaxOff; of++) {
- U32 const scaleLog = 10;
- U32 const bitCost = FSE_getMaxNbBits(ofstate.symbolTT, of);
- assert(bitCost < scaleLog);
- optPtr->offCodeFreq[of] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/;
- optPtr->offCodeSum += optPtr->offCodeFreq[of];
- } }
-
- } else { /* not a dictionary */
-
- assert(optPtr->litFreq != NULL);
- if (compressedLiterals) {
- unsigned lit = MaxLit;
- HIST_count_simple(optPtr->litFreq, &lit, src, srcSize); /* use raw first block to init statistics */
- optPtr->litSum = ZSTD_downscaleStat(optPtr->litFreq, MaxLit, 1);
- }
-
- { unsigned ll;
- for (ll=0; ll<=MaxLL; ll++)
- optPtr->litLengthFreq[ll] = 1;
- }
- optPtr->litLengthSum = MaxLL+1;
-
- { unsigned ml;
- for (ml=0; ml<=MaxML; ml++)
- optPtr->matchLengthFreq[ml] = 1;
- }
- optPtr->matchLengthSum = MaxML+1;
-
- { unsigned of;
- for (of=0; of<=MaxOff; of++)
- optPtr->offCodeFreq[of] = 1;
- }
- optPtr->offCodeSum = MaxOff+1;
-
- }
-
- } else { /* new block : re-use previous statistics, scaled down */
-
- if (compressedLiterals)
- optPtr->litSum = ZSTD_downscaleStat(optPtr->litFreq, MaxLit, 1);
- optPtr->litLengthSum = ZSTD_downscaleStat(optPtr->litLengthFreq, MaxLL, 0);
- optPtr->matchLengthSum = ZSTD_downscaleStat(optPtr->matchLengthFreq, MaxML, 0);
- optPtr->offCodeSum = ZSTD_downscaleStat(optPtr->offCodeFreq, MaxOff, 0);
- }
-
- ZSTD_setBasePrices(optPtr, optLevel);
-}
-
-/* ZSTD_rawLiteralsCost() :
- * price of literals (only) in specified segment (which length can be 0).
- * does not include price of literalLength symbol */
-static U32 ZSTD_rawLiteralsCost(const BYTE* const literals, U32 const litLength,
- const optState_t* const optPtr,
- int optLevel)
-{
- if (litLength == 0) return 0;
-
- if (!ZSTD_compressedLiterals(optPtr))
- return (litLength << 3) * BITCOST_MULTIPLIER; /* Uncompressed - 8 bytes per literal. */
-
- if (optPtr->priceType == zop_predef)
- return (litLength*6) * BITCOST_MULTIPLIER; /* 6 bit per literal - no statistic used */
-
- /* dynamic statistics */
- { U32 price = litLength * optPtr->litSumBasePrice;
- U32 u;
- for (u=0; u < litLength; u++) {
- assert(WEIGHT(optPtr->litFreq[literals[u]], optLevel) <= optPtr->litSumBasePrice); /* literal cost should never be negative */
- price -= WEIGHT(optPtr->litFreq[literals[u]], optLevel);
- }
- return price;
- }
-}
-
-/* ZSTD_litLengthPrice() :
- * cost of literalLength symbol */
-static U32 ZSTD_litLengthPrice(U32 const litLength, const optState_t* const optPtr, int optLevel)
-{
- if (optPtr->priceType == zop_predef) return WEIGHT(litLength, optLevel);
-
- /* dynamic statistics */
- { U32 const llCode = ZSTD_LLcode(litLength);
- return (LL_bits[llCode] * BITCOST_MULTIPLIER)
- + optPtr->litLengthSumBasePrice
- - WEIGHT(optPtr->litLengthFreq[llCode], optLevel);
- }
-}
-
-/* ZSTD_getMatchPrice() :
- * Provides the cost of the match part (offset + matchLength) of a sequence
- * Must be combined with ZSTD_fullLiteralsCost() to get the full cost of a sequence.
- * optLevel: when <2, favors small offset for decompression speed (improved cache efficiency) */
-FORCE_INLINE_TEMPLATE U32
-ZSTD_getMatchPrice(U32 const offset,
- U32 const matchLength,
- const optState_t* const optPtr,
- int const optLevel)
-{
- U32 price;
- U32 const offCode = ZSTD_highbit32(offset+1);
- U32 const mlBase = matchLength - MINMATCH;
- assert(matchLength >= MINMATCH);
-
- if (optPtr->priceType == zop_predef) /* fixed scheme, do not use statistics */
- return WEIGHT(mlBase, optLevel) + ((16 + offCode) * BITCOST_MULTIPLIER);
-
- /* dynamic statistics */
- price = (offCode * BITCOST_MULTIPLIER) + (optPtr->offCodeSumBasePrice - WEIGHT(optPtr->offCodeFreq[offCode], optLevel));
- if ((optLevel<2) /*static*/ && offCode >= 20)
- price += (offCode-19)*2 * BITCOST_MULTIPLIER; /* handicap for long distance offsets, favor decompression speed */
-
- /* match Length */
- { U32 const mlCode = ZSTD_MLcode(mlBase);
- price += (ML_bits[mlCode] * BITCOST_MULTIPLIER) + (optPtr->matchLengthSumBasePrice - WEIGHT(optPtr->matchLengthFreq[mlCode], optLevel));
- }
-
- price += BITCOST_MULTIPLIER / 5; /* heuristic : make matches a bit more costly to favor less sequences -> faster decompression speed */
-
- DEBUGLOG(8, "ZSTD_getMatchPrice(ml:%u) = %u", matchLength, price);
- return price;
-}
-
-/* ZSTD_updateStats() :
- * assumption : literals + litLengtn <= iend */
-static void ZSTD_updateStats(optState_t* const optPtr,
- U32 litLength, const BYTE* literals,
- U32 offsetCode, U32 matchLength)
-{
- /* literals */
- if (ZSTD_compressedLiterals(optPtr)) {
- U32 u;
- for (u=0; u < litLength; u++)
- optPtr->litFreq[literals[u]] += ZSTD_LITFREQ_ADD;
- optPtr->litSum += litLength*ZSTD_LITFREQ_ADD;
- }
-
- /* literal Length */
- { U32 const llCode = ZSTD_LLcode(litLength);
- optPtr->litLengthFreq[llCode]++;
- optPtr->litLengthSum++;
- }
-
- /* match offset code (0-2=>repCode; 3+=>offset+2) */
- { U32 const offCode = ZSTD_highbit32(offsetCode+1);
- assert(offCode <= MaxOff);
- optPtr->offCodeFreq[offCode]++;
- optPtr->offCodeSum++;
- }
-
- /* match Length */
- { U32 const mlBase = matchLength - MINMATCH;
- U32 const mlCode = ZSTD_MLcode(mlBase);
- optPtr->matchLengthFreq[mlCode]++;
- optPtr->matchLengthSum++;
- }
-}
-
-
-/* ZSTD_readMINMATCH() :
- * function safe only for comparisons
- * assumption : memPtr must be at least 4 bytes before end of buffer */
-MEM_STATIC U32 ZSTD_readMINMATCH(const void* memPtr, U32 length)
-{
- switch (length)
- {
- default :
- case 4 : return MEM_read32(memPtr);
- case 3 : if (MEM_isLittleEndian())
- return MEM_read32(memPtr)<<8;
- else
- return MEM_read32(memPtr)>>8;
- }
-}
-
-
-/* Update hashTable3 up to ip (excluded)
- Assumption : always within prefix (i.e. not within extDict) */
-static U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_matchState_t* ms,
- U32* nextToUpdate3,
- const BYTE* const ip)
-{
- U32* const hashTable3 = ms->hashTable3;
- U32 const hashLog3 = ms->hashLog3;
- const BYTE* const base = ms->window.base;
- U32 idx = *nextToUpdate3;
- U32 const target = (U32)(ip - base);
- size_t const hash3 = ZSTD_hash3Ptr(ip, hashLog3);
- assert(hashLog3 > 0);
-
- while(idx < target) {
- hashTable3[ZSTD_hash3Ptr(base+idx, hashLog3)] = idx;
- idx++;
- }
-
- *nextToUpdate3 = target;
- return hashTable3[hash3];
-}
-
-
-/*-*************************************
-* Binary Tree search
-***************************************/
-/** ZSTD_insertBt1() : add one or multiple positions to tree.
- * ip : assumed <= iend-8 .
- * @return : nb of positions added */
-static U32 ZSTD_insertBt1(
- ZSTD_matchState_t* ms,
- const BYTE* const ip, const BYTE* const iend,
- U32 const mls, const int extDict)
-{
- const ZSTD_compressionParameters* const cParams = &ms->cParams;
- U32* const hashTable = ms->hashTable;
- U32 const hashLog = cParams->hashLog;
- size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
- U32* const bt = ms->chainTable;
- U32 const btLog = cParams->chainLog - 1;
- U32 const btMask = (1 << btLog) - 1;
- U32 matchIndex = hashTable[h];
- size_t commonLengthSmaller=0, commonLengthLarger=0;
- const BYTE* const base = ms->window.base;
- const BYTE* const dictBase = ms->window.dictBase;
- const U32 dictLimit = ms->window.dictLimit;
- const BYTE* const dictEnd = dictBase + dictLimit;
- const BYTE* const prefixStart = base + dictLimit;
- const BYTE* match;
- const U32 current = (U32)(ip-base);
- const U32 btLow = btMask >= current ? 0 : current - btMask;
- U32* smallerPtr = bt + 2*(current&btMask);
- U32* largerPtr = smallerPtr + 1;
- U32 dummy32; /* to be nullified at the end */
- U32 const windowLow = ms->window.lowLimit;
- U32 matchEndIdx = current+8+1;
- size_t bestLength = 8;
- U32 nbCompares = 1U << cParams->searchLog;
-#ifdef ZSTD_C_PREDICT
- U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
- U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
- predictedSmall += (predictedSmall>0);
- predictedLarge += (predictedLarge>0);
-#endif /* ZSTD_C_PREDICT */
-
- DEBUGLOG(8, "ZSTD_insertBt1 (%u)", current);
-
- assert(ip <= iend-8); /* required for h calculation */
- hashTable[h] = current; /* Update Hash Table */
-
- assert(windowLow > 0);
- while (nbCompares-- && (matchIndex >= windowLow)) {
- U32* const nextPtr = bt + 2*(matchIndex & btMask);
- size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
- assert(matchIndex < current);
-
-#ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */
- const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
- if (matchIndex == predictedSmall) {
- /* no need to check length, result known */
- *smallerPtr = matchIndex;
- if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
- smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
- matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
- predictedSmall = predictPtr[1] + (predictPtr[1]>0);
- continue;
- }
- if (matchIndex == predictedLarge) {
- *largerPtr = matchIndex;
- if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
- largerPtr = nextPtr;
- matchIndex = nextPtr[0];
- predictedLarge = predictPtr[0] + (predictPtr[0]>0);
- continue;
- }
-#endif
-
- if (!extDict || (matchIndex+matchLength >= dictLimit)) {
- assert(matchIndex+matchLength >= dictLimit); /* might be wrong if actually extDict */
- match = base + matchIndex;
- matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
- } else {
- match = dictBase + matchIndex;
- matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
- if (matchIndex+matchLength >= dictLimit)
- match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
- }
-
- if (matchLength > bestLength) {
- bestLength = matchLength;
- if (matchLength > matchEndIdx - matchIndex)
- matchEndIdx = matchIndex + (U32)matchLength;
- }
-
- if (ip+matchLength == iend) { /* equal : no way to know if inf or sup */
- break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt tree */
- }
-
- if (match[matchLength] < ip[matchLength]) { /* necessarily within buffer */
- /* match is smaller than current */
- *smallerPtr = matchIndex; /* update smaller idx */
- commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
- if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop searching */
- smallerPtr = nextPtr+1; /* new "candidate" => larger than match, which was smaller than target */
- matchIndex = nextPtr[1]; /* new matchIndex, larger than previous and closer to current */
- } else {
- /* match is larger than current */
- *largerPtr = matchIndex;
- commonLengthLarger = matchLength;
- if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop searching */
- largerPtr = nextPtr;
- matchIndex = nextPtr[0];
- } }
-
- *smallerPtr = *largerPtr = 0;
- { U32 positions = 0;
- if (bestLength > 384) positions = MIN(192, (U32)(bestLength - 384)); /* speed optimization */
- assert(matchEndIdx > current + 8);
- return MAX(positions, matchEndIdx - (current + 8));
- }
-}
-
-FORCE_INLINE_TEMPLATE
-void ZSTD_updateTree_internal(
- ZSTD_matchState_t* ms,
- const BYTE* const ip, const BYTE* const iend,
- const U32 mls, const ZSTD_dictMode_e dictMode)
-{
- const BYTE* const base = ms->window.base;
- U32 const target = (U32)(ip - base);
- U32 idx = ms->nextToUpdate;
- DEBUGLOG(6, "ZSTD_updateTree_internal, from %u to %u (dictMode:%u)",
- idx, target, dictMode);
-
- while(idx < target) {
- U32 const forward = ZSTD_insertBt1(ms, base+idx, iend, mls, dictMode == ZSTD_extDict);
- assert(idx < (U32)(idx + forward));
- idx += forward;
- }
- assert((size_t)(ip - base) <= (size_t)(U32)(-1));
- assert((size_t)(iend - base) <= (size_t)(U32)(-1));
- ms->nextToUpdate = target;
-}
-
-void ZSTD_updateTree(ZSTD_matchState_t* ms, const BYTE* ip, const BYTE* iend) {
- ZSTD_updateTree_internal(ms, ip, iend, ms->cParams.minMatch, ZSTD_noDict);
-}
-
-FORCE_INLINE_TEMPLATE
-U32 ZSTD_insertBtAndGetAllMatches (
- ZSTD_match_t* matches, /* store result (found matches) in this table (presumed large enough) */
- ZSTD_matchState_t* ms,
- U32* nextToUpdate3,
- const BYTE* const ip, const BYTE* const iLimit, const ZSTD_dictMode_e dictMode,
- const U32 rep[ZSTD_REP_NUM],
- U32 const ll0, /* tells if associated literal length is 0 or not. This value must be 0 or 1 */
- const U32 lengthToBeat,
- U32 const mls /* template */)
-{
- const ZSTD_compressionParameters* const cParams = &ms->cParams;
- U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1);
- const BYTE* const base = ms->window.base;
- U32 const current = (U32)(ip-base);
- U32 const hashLog = cParams->hashLog;
- U32 const minMatch = (mls==3) ? 3 : 4;
- U32* const hashTable = ms->hashTable;
- size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
- U32 matchIndex = hashTable[h];
- U32* const bt = ms->chainTable;
- U32 const btLog = cParams->chainLog - 1;
- U32 const btMask= (1U << btLog) - 1;
- size_t commonLengthSmaller=0, commonLengthLarger=0;
- const BYTE* const dictBase = ms->window.dictBase;
- U32 const dictLimit = ms->window.dictLimit;
- const BYTE* const dictEnd = dictBase + dictLimit;
- const BYTE* const prefixStart = base + dictLimit;
- U32 const btLow = (btMask >= current) ? 0 : current - btMask;
- U32 const windowLow = ZSTD_getLowestMatchIndex(ms, current, cParams->windowLog);
- U32 const matchLow = windowLow ? windowLow : 1;
- U32* smallerPtr = bt + 2*(current&btMask);
- U32* largerPtr = bt + 2*(current&btMask) + 1;
- U32 matchEndIdx = current+8+1; /* farthest referenced position of any match => detects repetitive patterns */
- U32 dummy32; /* to be nullified at the end */
- U32 mnum = 0;
- U32 nbCompares = 1U << cParams->searchLog;
-
- const ZSTD_matchState_t* dms = dictMode == ZSTD_dictMatchState ? ms->dictMatchState : NULL;
- const ZSTD_compressionParameters* const dmsCParams =
- dictMode == ZSTD_dictMatchState ? &dms->cParams : NULL;
- const BYTE* const dmsBase = dictMode == ZSTD_dictMatchState ? dms->window.base : NULL;
- const BYTE* const dmsEnd = dictMode == ZSTD_dictMatchState ? dms->window.nextSrc : NULL;
- U32 const dmsHighLimit = dictMode == ZSTD_dictMatchState ? (U32)(dmsEnd - dmsBase) : 0;
- U32 const dmsLowLimit = dictMode == ZSTD_dictMatchState ? dms->window.lowLimit : 0;
- U32 const dmsIndexDelta = dictMode == ZSTD_dictMatchState ? windowLow - dmsHighLimit : 0;
- U32 const dmsHashLog = dictMode == ZSTD_dictMatchState ? dmsCParams->hashLog : hashLog;
- U32 const dmsBtLog = dictMode == ZSTD_dictMatchState ? dmsCParams->chainLog - 1 : btLog;
- U32 const dmsBtMask = dictMode == ZSTD_dictMatchState ? (1U << dmsBtLog) - 1 : 0;
- U32 const dmsBtLow = dictMode == ZSTD_dictMatchState && dmsBtMask < dmsHighLimit - dmsLowLimit ? dmsHighLimit - dmsBtMask : dmsLowLimit;
-
- size_t bestLength = lengthToBeat-1;
- DEBUGLOG(8, "ZSTD_insertBtAndGetAllMatches: current=%u", current);
-
- /* check repCode */
- assert(ll0 <= 1); /* necessarily 1 or 0 */
- { U32 const lastR = ZSTD_REP_NUM + ll0;
- U32 repCode;
- for (repCode = ll0; repCode < lastR; repCode++) {
- U32 const repOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode];
- U32 const repIndex = current - repOffset;
- U32 repLen = 0;
- assert(current >= dictLimit);
- if (repOffset-1 /* intentional overflow, discards 0 and -1 */ < current-dictLimit) { /* equivalent to `current > repIndex >= dictLimit` */
- /* We must validate the repcode offset because when we're using a dictionary the
- * valid offset range shrinks when the dictionary goes out of bounds.
- */
- if ((repIndex >= windowLow) & (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(ip - repOffset, minMatch))) {
- repLen = (U32)ZSTD_count(ip+minMatch, ip+minMatch-repOffset, iLimit) + minMatch;
- }
- } else { /* repIndex < dictLimit || repIndex >= current */
- const BYTE* const repMatch = dictMode == ZSTD_dictMatchState ?
- dmsBase + repIndex - dmsIndexDelta :
- dictBase + repIndex;
- assert(current >= windowLow);
- if ( dictMode == ZSTD_extDict
- && ( ((repOffset-1) /*intentional overflow*/ < current - windowLow) /* equivalent to `current > repIndex >= windowLow` */
- & (((U32)((dictLimit-1) - repIndex) >= 3) ) /* intentional overflow : do not test positions overlapping 2 memory segments */)
- && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) {
- repLen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iLimit, dictEnd, prefixStart) + minMatch;
- }
- if (dictMode == ZSTD_dictMatchState
- && ( ((repOffset-1) /*intentional overflow*/ < current - (dmsLowLimit + dmsIndexDelta)) /* equivalent to `current > repIndex >= dmsLowLimit` */
- & ((U32)((dictLimit-1) - repIndex) >= 3) ) /* intentional overflow : do not test positions overlapping 2 memory segments */
- && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) {
- repLen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iLimit, dmsEnd, prefixStart) + minMatch;
- } }
- /* save longer solution */
- if (repLen > bestLength) {
- DEBUGLOG(8, "found repCode %u (ll0:%u, offset:%u) of length %u",
- repCode, ll0, repOffset, repLen);
- bestLength = repLen;
- matches[mnum].off = repCode - ll0;
- matches[mnum].len = (U32)repLen;
- mnum++;
- if ( (repLen > sufficient_len)
- | (ip+repLen == iLimit) ) { /* best possible */
- return mnum;
- } } } }
-
- /* HC3 match finder */
- if ((mls == 3) /*static*/ && (bestLength < mls)) {
- U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3(ms, nextToUpdate3, ip);
- if ((matchIndex3 >= matchLow)
- & (current - matchIndex3 < (1<<18)) /*heuristic : longer distance likely too expensive*/ ) {
- size_t mlen;
- if ((dictMode == ZSTD_noDict) /*static*/ || (dictMode == ZSTD_dictMatchState) /*static*/ || (matchIndex3 >= dictLimit)) {
- const BYTE* const match = base + matchIndex3;
- mlen = ZSTD_count(ip, match, iLimit);
- } else {
- const BYTE* const match = dictBase + matchIndex3;
- mlen = ZSTD_count_2segments(ip, match, iLimit, dictEnd, prefixStart);
- }
-
- /* save best solution */
- if (mlen >= mls /* == 3 > bestLength */) {
- DEBUGLOG(8, "found small match with hlog3, of length %u",
- (U32)mlen);
- bestLength = mlen;
- assert(current > matchIndex3);
- assert(mnum==0); /* no prior solution */
- matches[0].off = (current - matchIndex3) + ZSTD_REP_MOVE;
- matches[0].len = (U32)mlen;
- mnum = 1;
- if ( (mlen > sufficient_len) |
- (ip+mlen == iLimit) ) { /* best possible length */
- ms->nextToUpdate = current+1; /* skip insertion */
- return 1;
- } } }
- /* no dictMatchState lookup: dicts don't have a populated HC3 table */
- }
-
- hashTable[h] = current; /* Update Hash Table */
-
- while (nbCompares-- && (matchIndex >= matchLow)) {
- U32* const nextPtr = bt + 2*(matchIndex & btMask);
- const BYTE* match;
- size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
- assert(current > matchIndex);
-
- if ((dictMode == ZSTD_noDict) || (dictMode == ZSTD_dictMatchState) || (matchIndex+matchLength >= dictLimit)) {
- assert(matchIndex+matchLength >= dictLimit); /* ensure the condition is correct when !extDict */
- match = base + matchIndex;
- if (matchIndex >= dictLimit) assert(memcmp(match, ip, matchLength) == 0); /* ensure early section of match is equal as expected */
- matchLength += ZSTD_count(ip+matchLength, match+matchLength, iLimit);
- } else {
- match = dictBase + matchIndex;
- assert(memcmp(match, ip, matchLength) == 0); /* ensure early section of match is equal as expected */
- matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iLimit, dictEnd, prefixStart);
- if (matchIndex+matchLength >= dictLimit)
- match = base + matchIndex; /* prepare for match[matchLength] read */
- }
-
- if (matchLength > bestLength) {
- DEBUGLOG(8, "found match of length %u at distance %u (offCode=%u)",
- (U32)matchLength, current - matchIndex, current - matchIndex + ZSTD_REP_MOVE);
- assert(matchEndIdx > matchIndex);
- if (matchLength > matchEndIdx - matchIndex)
- matchEndIdx = matchIndex + (U32)matchLength;
- bestLength = matchLength;
- matches[mnum].off = (current - matchIndex) + ZSTD_REP_MOVE;
- matches[mnum].len = (U32)matchLength;
- mnum++;
- if ( (matchLength > ZSTD_OPT_NUM)
- | (ip+matchLength == iLimit) /* equal : no way to know if inf or sup */) {
- if (dictMode == ZSTD_dictMatchState) nbCompares = 0; /* break should also skip searching dms */
- break; /* drop, to preserve bt consistency (miss a little bit of compression) */
- }
- }
-
- if (match[matchLength] < ip[matchLength]) {
- /* match smaller than current */
- *smallerPtr = matchIndex; /* update smaller idx */
- commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
- if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
- smallerPtr = nextPtr+1; /* new candidate => larger than match, which was smaller than current */
- matchIndex = nextPtr[1]; /* new matchIndex, larger than previous, closer to current */
- } else {
- *largerPtr = matchIndex;
- commonLengthLarger = matchLength;
- if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
- largerPtr = nextPtr;
- matchIndex = nextPtr[0];
- } }
-
- *smallerPtr = *largerPtr = 0;
-
- if (dictMode == ZSTD_dictMatchState && nbCompares) {
- size_t const dmsH = ZSTD_hashPtr(ip, dmsHashLog, mls);
- U32 dictMatchIndex = dms->hashTable[dmsH];
- const U32* const dmsBt = dms->chainTable;
- commonLengthSmaller = commonLengthLarger = 0;
- while (nbCompares-- && (dictMatchIndex > dmsLowLimit)) {
- const U32* const nextPtr = dmsBt + 2*(dictMatchIndex & dmsBtMask);
- size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
- const BYTE* match = dmsBase + dictMatchIndex;
- matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iLimit, dmsEnd, prefixStart);
- if (dictMatchIndex+matchLength >= dmsHighLimit)
- match = base + dictMatchIndex + dmsIndexDelta; /* to prepare for next usage of match[matchLength] */
-
- if (matchLength > bestLength) {
- matchIndex = dictMatchIndex + dmsIndexDelta;
- DEBUGLOG(8, "found dms match of length %u at distance %u (offCode=%u)",
- (U32)matchLength, current - matchIndex, current - matchIndex + ZSTD_REP_MOVE);
- if (matchLength > matchEndIdx - matchIndex)
- matchEndIdx = matchIndex + (U32)matchLength;
- bestLength = matchLength;
- matches[mnum].off = (current - matchIndex) + ZSTD_REP_MOVE;
- matches[mnum].len = (U32)matchLength;
- mnum++;
- if ( (matchLength > ZSTD_OPT_NUM)
- | (ip+matchLength == iLimit) /* equal : no way to know if inf or sup */) {
- break; /* drop, to guarantee consistency (miss a little bit of compression) */
- }
- }
-
- if (dictMatchIndex <= dmsBtLow) { break; } /* beyond tree size, stop the search */
- if (match[matchLength] < ip[matchLength]) {
- commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
- dictMatchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
- } else {
- /* match is larger than current */
- commonLengthLarger = matchLength;
- dictMatchIndex = nextPtr[0];
- }
- }
- }
-
- assert(matchEndIdx > current+8);
- ms->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */
- return mnum;
-}
-
-
-FORCE_INLINE_TEMPLATE U32 ZSTD_BtGetAllMatches (
- ZSTD_match_t* matches, /* store result (match found, increasing size) in this table */
- ZSTD_matchState_t* ms,
- U32* nextToUpdate3,
- const BYTE* ip, const BYTE* const iHighLimit, const ZSTD_dictMode_e dictMode,
- const U32 rep[ZSTD_REP_NUM],
- U32 const ll0,
- U32 const lengthToBeat)
-{
- const ZSTD_compressionParameters* const cParams = &ms->cParams;
- U32 const matchLengthSearch = cParams->minMatch;
- DEBUGLOG(8, "ZSTD_BtGetAllMatches");
- if (ip < ms->window.base + ms->nextToUpdate) return 0; /* skipped area */
- ZSTD_updateTree_internal(ms, ip, iHighLimit, matchLengthSearch, dictMode);
- switch(matchLengthSearch)
- {
- case 3 : return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, 3);
- default :
- case 4 : return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, 4);
- case 5 : return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, 5);
- case 7 :
- case 6 : return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, 6);
- }
-}
-
-
-/*-*******************************
-* Optimal parser
-*********************************/
-
-
-static U32 ZSTD_totalLen(ZSTD_optimal_t sol)
-{
- return sol.litlen + sol.mlen;
-}
-
-#if 0 /* debug */
-
-static void
-listStats(const U32* table, int lastEltID)
-{
- int const nbElts = lastEltID + 1;
- int enb;
- for (enb=0; enb < nbElts; enb++) {
- (void)table;
- /* RAWLOG(2, "%3i:%3i, ", enb, table[enb]); */
- RAWLOG(2, "%4i,", table[enb]);
- }
- RAWLOG(2, " \n");
-}
-
-#endif
-
-FORCE_INLINE_TEMPLATE size_t
-ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,
- seqStore_t* seqStore,
- U32 rep[ZSTD_REP_NUM],
- const void* src, size_t srcSize,
- const int optLevel,
- const ZSTD_dictMode_e dictMode)
-{
- optState_t* const optStatePtr = &ms->opt;
- const BYTE* const istart = (const BYTE*)src;
- const BYTE* ip = istart;
- const BYTE* anchor = istart;
- const BYTE* const iend = istart + srcSize;
- const BYTE* const ilimit = iend - 8;
- const BYTE* const base = ms->window.base;
- const BYTE* const prefixStart = base + ms->window.dictLimit;
- const ZSTD_compressionParameters* const cParams = &ms->cParams;
-
- U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1);
- U32 const minMatch = (cParams->minMatch == 3) ? 3 : 4;
- U32 nextToUpdate3 = ms->nextToUpdate;
-
- ZSTD_optimal_t* const opt = optStatePtr->priceTable;
- ZSTD_match_t* const matches = optStatePtr->matchTable;
- ZSTD_optimal_t lastSequence;
-
- /* init */
- DEBUGLOG(5, "ZSTD_compressBlock_opt_generic: current=%u, prefix=%u, nextToUpdate=%u",
- (U32)(ip - base), ms->window.dictLimit, ms->nextToUpdate);
- assert(optLevel <= 2);
- ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize, optLevel);
- ip += (ip==prefixStart);
-
- /* Match Loop */
- while (ip < ilimit) {
- U32 cur, last_pos = 0;
-
- /* find first match */
- { U32 const litlen = (U32)(ip - anchor);
- U32 const ll0 = !litlen;
- U32 const nbMatches = ZSTD_BtGetAllMatches(matches, ms, &nextToUpdate3, ip, iend, dictMode, rep, ll0, minMatch);
- if (!nbMatches) { ip++; continue; }
-
- /* initialize opt[0] */
- { U32 i ; for (i=0; i<ZSTD_REP_NUM; i++) opt[0].rep[i] = rep[i]; }
- opt[0].mlen = 0; /* means is_a_literal */
- opt[0].litlen = litlen;
- /* We don't need to include the actual price of the literals because
- * it is static for the duration of the forward pass, and is included
- * in every price. We include the literal length to avoid negative
- * prices when we subtract the previous literal length.
- */
- opt[0].price = ZSTD_litLengthPrice(litlen, optStatePtr, optLevel);
-
- /* large match -> immediate encoding */
- { U32 const maxML = matches[nbMatches-1].len;
- U32 const maxOffset = matches[nbMatches-1].off;
- DEBUGLOG(6, "found %u matches of maxLength=%u and maxOffCode=%u at cPos=%u => start new series",
- nbMatches, maxML, maxOffset, (U32)(ip-prefixStart));
-
- if (maxML > sufficient_len) {
- lastSequence.litlen = litlen;
- lastSequence.mlen = maxML;
- lastSequence.off = maxOffset;
- DEBUGLOG(6, "large match (%u>%u), immediate encoding",
- maxML, sufficient_len);
- cur = 0;
- last_pos = ZSTD_totalLen(lastSequence);
- goto _shortestPath;
- } }
-
- /* set prices for first matches starting position == 0 */
- { U32 const literalsPrice = opt[0].price + ZSTD_litLengthPrice(0, optStatePtr, optLevel);
- U32 pos;
- U32 matchNb;
- for (pos = 1; pos < minMatch; pos++) {
- opt[pos].price = ZSTD_MAX_PRICE; /* mlen, litlen and price will be fixed during forward scanning */
- }
- for (matchNb = 0; matchNb < nbMatches; matchNb++) {
- U32 const offset = matches[matchNb].off;
- U32 const end = matches[matchNb].len;
- for ( ; pos <= end ; pos++ ) {
- U32 const matchPrice = ZSTD_getMatchPrice(offset, pos, optStatePtr, optLevel);
- U32 const sequencePrice = literalsPrice + matchPrice;
- DEBUGLOG(7, "rPos:%u => set initial price : %.2f",
- pos, ZSTD_fCost(sequencePrice));
- opt[pos].mlen = pos;
- opt[pos].off = offset;
- opt[pos].litlen = litlen;
- opt[pos].price = sequencePrice;
- } }
- last_pos = pos-1;
- }
- }
-
- /* check further positions */
- for (cur = 1; cur <= last_pos; cur++) {
- const BYTE* const inr = ip + cur;
- assert(cur < ZSTD_OPT_NUM);
- DEBUGLOG(7, "cPos:%zi==rPos:%u", inr-istart, cur)
-
- /* Fix current position with one literal if cheaper */
- { U32 const litlen = (opt[cur-1].mlen == 0) ? opt[cur-1].litlen + 1 : 1;
- int const price = opt[cur-1].price
- + ZSTD_rawLiteralsCost(ip+cur-1, 1, optStatePtr, optLevel)
- + ZSTD_litLengthPrice(litlen, optStatePtr, optLevel)
- - ZSTD_litLengthPrice(litlen-1, optStatePtr, optLevel);
- assert(price < 1000000000); /* overflow check */
- if (price <= opt[cur].price) {
- DEBUGLOG(7, "cPos:%zi==rPos:%u : better price (%.2f<=%.2f) using literal (ll==%u) (hist:%u,%u,%u)",
- inr-istart, cur, ZSTD_fCost(price), ZSTD_fCost(opt[cur].price), litlen,
- opt[cur-1].rep[0], opt[cur-1].rep[1], opt[cur-1].rep[2]);
- opt[cur].mlen = 0;
- opt[cur].off = 0;
- opt[cur].litlen = litlen;
- opt[cur].price = price;
- } else {
- DEBUGLOG(7, "cPos:%zi==rPos:%u : literal would cost more (%.2f>%.2f) (hist:%u,%u,%u)",
- inr-istart, cur, ZSTD_fCost(price), ZSTD_fCost(opt[cur].price),
- opt[cur].rep[0], opt[cur].rep[1], opt[cur].rep[2]);
- }
- }
-
- /* Set the repcodes of the current position. We must do it here
- * because we rely on the repcodes of the 2nd to last sequence being
- * correct to set the next chunks repcodes during the backward
- * traversal.
- */
- ZSTD_STATIC_ASSERT(sizeof(opt[cur].rep) == sizeof(repcodes_t));
- assert(cur >= opt[cur].mlen);
- if (opt[cur].mlen != 0) {
- U32 const prev = cur - opt[cur].mlen;
- repcodes_t newReps = ZSTD_updateRep(opt[prev].rep, opt[cur].off, opt[cur].litlen==0);
- memcpy(opt[cur].rep, &newReps, sizeof(repcodes_t));
- } else {
- memcpy(opt[cur].rep, opt[cur - 1].rep, sizeof(repcodes_t));
- }
-
- /* last match must start at a minimum distance of 8 from oend */
- if (inr > ilimit) continue;
-
- if (cur == last_pos) break;
-
- if ( (optLevel==0) /*static_test*/
- && (opt[cur+1].price <= opt[cur].price + (BITCOST_MULTIPLIER/2)) ) {
- DEBUGLOG(7, "move to next rPos:%u : price is <=", cur+1);
- continue; /* skip unpromising positions; about ~+6% speed, -0.01 ratio */
- }
-
- { U32 const ll0 = (opt[cur].mlen != 0);
- U32 const litlen = (opt[cur].mlen == 0) ? opt[cur].litlen : 0;
- U32 const previousPrice = opt[cur].price;
- U32 const basePrice = previousPrice + ZSTD_litLengthPrice(0, optStatePtr, optLevel);
- U32 const nbMatches = ZSTD_BtGetAllMatches(matches, ms, &nextToUpdate3, inr, iend, dictMode, opt[cur].rep, ll0, minMatch);
- U32 matchNb;
- if (!nbMatches) {
- DEBUGLOG(7, "rPos:%u : no match found", cur);
- continue;
- }
-
- { U32 const maxML = matches[nbMatches-1].len;
- DEBUGLOG(7, "cPos:%zi==rPos:%u, found %u matches, of maxLength=%u",
- inr-istart, cur, nbMatches, maxML);
-
- if ( (maxML > sufficient_len)
- || (cur + maxML >= ZSTD_OPT_NUM) ) {
- lastSequence.mlen = maxML;
- lastSequence.off = matches[nbMatches-1].off;
- lastSequence.litlen = litlen;
- cur -= (opt[cur].mlen==0) ? opt[cur].litlen : 0; /* last sequence is actually only literals, fix cur to last match - note : may underflow, in which case, it's first sequence, and it's okay */
- last_pos = cur + ZSTD_totalLen(lastSequence);
- if (cur > ZSTD_OPT_NUM) cur = 0; /* underflow => first match */
- goto _shortestPath;
- } }
-
- /* set prices using matches found at position == cur */
- for (matchNb = 0; matchNb < nbMatches; matchNb++) {
- U32 const offset = matches[matchNb].off;
- U32 const lastML = matches[matchNb].len;
- U32 const startML = (matchNb>0) ? matches[matchNb-1].len+1 : minMatch;
- U32 mlen;
-
- DEBUGLOG(7, "testing match %u => offCode=%4u, mlen=%2u, llen=%2u",
- matchNb, matches[matchNb].off, lastML, litlen);
-
- for (mlen = lastML; mlen >= startML; mlen--) { /* scan downward */
- U32 const pos = cur + mlen;
- int const price = basePrice + ZSTD_getMatchPrice(offset, mlen, optStatePtr, optLevel);
-
- if ((pos > last_pos) || (price < opt[pos].price)) {
- DEBUGLOG(7, "rPos:%u (ml=%2u) => new better price (%.2f<%.2f)",
- pos, mlen, ZSTD_fCost(price), ZSTD_fCost(opt[pos].price));
- while (last_pos < pos) { opt[last_pos+1].price = ZSTD_MAX_PRICE; last_pos++; } /* fill empty positions */
- opt[pos].mlen = mlen;
- opt[pos].off = offset;
- opt[pos].litlen = litlen;
- opt[pos].price = price;
- } else {
- DEBUGLOG(7, "rPos:%u (ml=%2u) => new price is worse (%.2f>=%.2f)",
- pos, mlen, ZSTD_fCost(price), ZSTD_fCost(opt[pos].price));
- if (optLevel==0) break; /* early update abort; gets ~+10% speed for about -0.01 ratio loss */
- }
- } } }
- } /* for (cur = 1; cur <= last_pos; cur++) */
-
- lastSequence = opt[last_pos];
- cur = last_pos > ZSTD_totalLen(lastSequence) ? last_pos - ZSTD_totalLen(lastSequence) : 0; /* single sequence, and it starts before `ip` */
- assert(cur < ZSTD_OPT_NUM); /* control overflow*/
-
-_shortestPath: /* cur, last_pos, best_mlen, best_off have to be set */
- assert(opt[0].mlen == 0);
-
- /* Set the next chunk's repcodes based on the repcodes of the beginning
- * of the last match, and the last sequence. This avoids us having to
- * update them while traversing the sequences.
- */
- if (lastSequence.mlen != 0) {
- repcodes_t reps = ZSTD_updateRep(opt[cur].rep, lastSequence.off, lastSequence.litlen==0);
- memcpy(rep, &reps, sizeof(reps));
- } else {
- memcpy(rep, opt[cur].rep, sizeof(repcodes_t));
- }
-
- { U32 const storeEnd = cur + 1;
- U32 storeStart = storeEnd;
- U32 seqPos = cur;
-
- DEBUGLOG(6, "start reverse traversal (last_pos:%u, cur:%u)",
- last_pos, cur); (void)last_pos;
- assert(storeEnd < ZSTD_OPT_NUM);
- DEBUGLOG(6, "last sequence copied into pos=%u (llen=%u,mlen=%u,ofc=%u)",
- storeEnd, lastSequence.litlen, lastSequence.mlen, lastSequence.off);
- opt[storeEnd] = lastSequence;
- while (seqPos > 0) {
- U32 const backDist = ZSTD_totalLen(opt[seqPos]);
- storeStart--;
- DEBUGLOG(6, "sequence from rPos=%u copied into pos=%u (llen=%u,mlen=%u,ofc=%u)",
- seqPos, storeStart, opt[seqPos].litlen, opt[seqPos].mlen, opt[seqPos].off);
- opt[storeStart] = opt[seqPos];
- seqPos = (seqPos > backDist) ? seqPos - backDist : 0;
- }
-
- /* save sequences */
- DEBUGLOG(6, "sending selected sequences into seqStore")
- { U32 storePos;
- for (storePos=storeStart; storePos <= storeEnd; storePos++) {
- U32 const llen = opt[storePos].litlen;
- U32 const mlen = opt[storePos].mlen;
- U32 const offCode = opt[storePos].off;
- U32 const advance = llen + mlen;
- DEBUGLOG(6, "considering seq starting at %zi, llen=%u, mlen=%u",
- anchor - istart, (unsigned)llen, (unsigned)mlen);
-
- if (mlen==0) { /* only literals => must be last "sequence", actually starting a new stream of sequences */
- assert(storePos == storeEnd); /* must be last sequence */
- ip = anchor + llen; /* last "sequence" is a bunch of literals => don't progress anchor */
- continue; /* will finish */
- }
-
- assert(anchor + llen <= iend);
- ZSTD_updateStats(optStatePtr, llen, anchor, offCode, mlen);
- ZSTD_storeSeq(seqStore, llen, anchor, iend, offCode, mlen-MINMATCH);
- anchor += advance;
- ip = anchor;
- } }
- ZSTD_setBasePrices(optStatePtr, optLevel);
- }
- } /* while (ip < ilimit) */
-
- /* Return the last literals size */
- return (size_t)(iend - anchor);
-}
-
-
-size_t ZSTD_compressBlock_btopt(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- const void* src, size_t srcSize)
-{
- DEBUGLOG(5, "ZSTD_compressBlock_btopt");
- return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /*optLevel*/, ZSTD_noDict);
-}
-
-
-/* used in 2-pass strategy */
-static U32 ZSTD_upscaleStat(unsigned* table, U32 lastEltIndex, int bonus)
-{
- U32 s, sum=0;
- assert(ZSTD_FREQ_DIV+bonus >= 0);
- for (s=0; s<lastEltIndex+1; s++) {
- table[s] <<= ZSTD_FREQ_DIV+bonus;
- table[s]--;
- sum += table[s];
- }
- return sum;
-}
-
-/* used in 2-pass strategy */
-MEM_STATIC void ZSTD_upscaleStats(optState_t* optPtr)
-{
- if (ZSTD_compressedLiterals(optPtr))
- optPtr->litSum = ZSTD_upscaleStat(optPtr->litFreq, MaxLit, 0);
- optPtr->litLengthSum = ZSTD_upscaleStat(optPtr->litLengthFreq, MaxLL, 0);
- optPtr->matchLengthSum = ZSTD_upscaleStat(optPtr->matchLengthFreq, MaxML, 0);
- optPtr->offCodeSum = ZSTD_upscaleStat(optPtr->offCodeFreq, MaxOff, 0);
-}
-
-/* ZSTD_initStats_ultra():
- * make a first compression pass, just to seed stats with more accurate starting values.
- * only works on first block, with no dictionary and no ldm.
- * this function cannot error, hence its contract must be respected.
- */
-static void
-ZSTD_initStats_ultra(ZSTD_matchState_t* ms,
- seqStore_t* seqStore,
- U32 rep[ZSTD_REP_NUM],
- const void* src, size_t srcSize)
-{
- U32 tmpRep[ZSTD_REP_NUM]; /* updated rep codes will sink here */
- memcpy(tmpRep, rep, sizeof(tmpRep));
-
- DEBUGLOG(4, "ZSTD_initStats_ultra (srcSize=%zu)", srcSize);
- assert(ms->opt.litLengthSum == 0); /* first block */
- assert(seqStore->sequences == seqStore->sequencesStart); /* no ldm */
- assert(ms->window.dictLimit == ms->window.lowLimit); /* no dictionary */
- assert(ms->window.dictLimit - ms->nextToUpdate <= 1); /* no prefix (note: intentional overflow, defined as 2-complement) */
-
- ZSTD_compressBlock_opt_generic(ms, seqStore, tmpRep, src, srcSize, 2 /*optLevel*/, ZSTD_noDict); /* generate stats into ms->opt*/
-
- /* invalidate first scan from history */
- ZSTD_resetSeqStore(seqStore);
- ms->window.base -= srcSize;
- ms->window.dictLimit += (U32)srcSize;
- ms->window.lowLimit = ms->window.dictLimit;
- ms->nextToUpdate = ms->window.dictLimit;
-
- /* re-inforce weight of collected statistics */
- ZSTD_upscaleStats(&ms->opt);
-}
-
-size_t ZSTD_compressBlock_btultra(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- const void* src, size_t srcSize)
-{
- DEBUGLOG(5, "ZSTD_compressBlock_btultra (srcSize=%zu)", srcSize);
- return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_noDict);
-}
-
-size_t ZSTD_compressBlock_btultra2(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- const void* src, size_t srcSize)
-{
- U32 const current = (U32)((const BYTE*)src - ms->window.base);
- DEBUGLOG(5, "ZSTD_compressBlock_btultra2 (srcSize=%zu)", srcSize);
-
- /* 2-pass strategy:
- * this strategy makes a first pass over first block to collect statistics
- * and seed next round's statistics with it.
- * After 1st pass, function forgets everything, and starts a new block.
- * Consequently, this can only work if no data has been previously loaded in tables,
- * aka, no dictionary, no prefix, no ldm preprocessing.
- * The compression ratio gain is generally small (~0.5% on first block),
- * the cost is 2x cpu time on first block. */
- assert(srcSize <= ZSTD_BLOCKSIZE_MAX);
- if ( (ms->opt.litLengthSum==0) /* first block */
- && (seqStore->sequences == seqStore->sequencesStart) /* no ldm */
- && (ms->window.dictLimit == ms->window.lowLimit) /* no dictionary */
- && (current == ms->window.dictLimit) /* start of frame, nothing already loaded nor skipped */
- && (srcSize > ZSTD_PREDEF_THRESHOLD)
- ) {
- ZSTD_initStats_ultra(ms, seqStore, rep, src, srcSize);
- }
-
- return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_noDict);
-}
-
-size_t ZSTD_compressBlock_btopt_dictMatchState(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- const void* src, size_t srcSize)
-{
- return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /*optLevel*/, ZSTD_dictMatchState);
-}
-
-size_t ZSTD_compressBlock_btultra_dictMatchState(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- const void* src, size_t srcSize)
-{
- return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_dictMatchState);
-}
-
-size_t ZSTD_compressBlock_btopt_extDict(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- const void* src, size_t srcSize)
-{
- return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /*optLevel*/, ZSTD_extDict);
-}
-
-size_t ZSTD_compressBlock_btultra_extDict(
- ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
- const void* src, size_t srcSize)
-{
- return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_extDict);
-}
-
-/* note : no btultra2 variant for extDict nor dictMatchState,
- * because btultra2 is not meant to work with dictionaries
- * and is only specific for the first block (no prefix) */
-/**** ended inlining compress/zstd_opt.c ****/
-
-/**** start inlining decompress/huf_decompress.c ****/
-/* ******************************************************************
- * huff0 huffman decoder,
- * part of Finite State Entropy library
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
- *
- * You can contact the author at :
- * - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
-****************************************************************** */
-
-/* **************************************************************
-* Dependencies
-****************************************************************/
-#include <string.h> /* memcpy, memset */
-/**** skipping file: ../common/compiler.h ****/
-/**** skipping file: ../common/bitstream.h ****/
-/**** skipping file: ../common/fse.h ****/
-#define HUF_STATIC_LINKING_ONLY
-/**** skipping file: ../common/huf.h ****/
-/**** skipping file: ../common/error_private.h ****/
-
-/* **************************************************************
-* Macros
-****************************************************************/
-
-/* These two optional macros force the use one way or another of the two
- * Huffman decompression implementations. You can't force in both directions
- * at the same time.
- */
-#if defined(HUF_FORCE_DECOMPRESS_X1) && \
- defined(HUF_FORCE_DECOMPRESS_X2)
-#error "Cannot force the use of the X1 and X2 decoders at the same time!"
-#endif
-
-
-/* **************************************************************
-* Error Management
-****************************************************************/
-#define HUF_isError ERR_isError
-
-
-/* **************************************************************
-* Byte alignment for workSpace management
-****************************************************************/
-#define HUF_ALIGN(x, a) HUF_ALIGN_MASK((x), (a) - 1)
-#define HUF_ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
-
-
-/* **************************************************************
-* BMI2 Variant Wrappers
-****************************************************************/
-#if DYNAMIC_BMI2
-
-#define HUF_DGEN(fn) \
- \
- static size_t fn##_default( \
- void* dst, size_t dstSize, \
- const void* cSrc, size_t cSrcSize, \
- const HUF_DTable* DTable) \
- { \
- return fn##_body(dst, dstSize, cSrc, cSrcSize, DTable); \
- } \
- \
- static TARGET_ATTRIBUTE("bmi2") size_t fn##_bmi2( \
- void* dst, size_t dstSize, \
- const void* cSrc, size_t cSrcSize, \
- const HUF_DTable* DTable) \
- { \
- return fn##_body(dst, dstSize, cSrc, cSrcSize, DTable); \
- } \
- \
- static size_t fn(void* dst, size_t dstSize, void const* cSrc, \
- size_t cSrcSize, HUF_DTable const* DTable, int bmi2) \
- { \
- if (bmi2) { \
- return fn##_bmi2(dst, dstSize, cSrc, cSrcSize, DTable); \
- } \
- return fn##_default(dst, dstSize, cSrc, cSrcSize, DTable); \
- }
-
-#else
-
-#define HUF_DGEN(fn) \
- static size_t fn(void* dst, size_t dstSize, void const* cSrc, \
- size_t cSrcSize, HUF_DTable const* DTable, int bmi2) \
- { \
- (void)bmi2; \
- return fn##_body(dst, dstSize, cSrc, cSrcSize, DTable); \
- }
-
-#endif
-
-
-/*-***************************/
-/* generic DTableDesc */
-/*-***************************/
-typedef struct { BYTE maxTableLog; BYTE tableType; BYTE tableLog; BYTE reserved; } DTableDesc;
-
-static DTableDesc HUF_getDTableDesc(const HUF_DTable* table)
-{
- DTableDesc dtd;
- memcpy(&dtd, table, sizeof(dtd));
- return dtd;
-}
-
-
-#ifndef HUF_FORCE_DECOMPRESS_X2
-
-/*-***************************/
-/* single-symbol decoding */
-/*-***************************/
-typedef struct { BYTE byte; BYTE nbBits; } HUF_DEltX1; /* single-symbol decoding */
-
-size_t HUF_readDTableX1_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize)
-{
- U32 tableLog = 0;
- U32 nbSymbols = 0;
- size_t iSize;
- void* const dtPtr = DTable + 1;
- HUF_DEltX1* const dt = (HUF_DEltX1*)dtPtr;
-
- U32* rankVal;
- BYTE* huffWeight;
- size_t spaceUsed32 = 0;
-
- rankVal = (U32 *)workSpace + spaceUsed32;
- spaceUsed32 += HUF_TABLELOG_ABSOLUTEMAX + 1;
- huffWeight = (BYTE *)((U32 *)workSpace + spaceUsed32);
- spaceUsed32 += HUF_ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2;
-
- if ((spaceUsed32 << 2) > wkspSize) return ERROR(tableLog_tooLarge);
-
- DEBUG_STATIC_ASSERT(sizeof(DTableDesc) == sizeof(HUF_DTable));
- /* memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */
-
- iSize = HUF_readStats(huffWeight, HUF_SYMBOLVALUE_MAX + 1, rankVal, &nbSymbols, &tableLog, src, srcSize);
- if (HUF_isError(iSize)) return iSize;
-
- /* Table header */
- { DTableDesc dtd = HUF_getDTableDesc(DTable);
- if (tableLog > (U32)(dtd.maxTableLog+1)) return ERROR(tableLog_tooLarge); /* DTable too small, Huffman tree cannot fit in */
- dtd.tableType = 0;
- dtd.tableLog = (BYTE)tableLog;
- memcpy(DTable, &dtd, sizeof(dtd));
- }
-
- /* Calculate starting value for each rank */
- { U32 n, nextRankStart = 0;
- for (n=1; n<tableLog+1; n++) {
- U32 const current = nextRankStart;
- nextRankStart += (rankVal[n] << (n-1));
- rankVal[n] = current;
- } }
-
- /* fill DTable */
- { U32 n;
- size_t const nEnd = nbSymbols;
- for (n=0; n<nEnd; n++) {
- size_t const w = huffWeight[n];
- size_t const length = (1 << w) >> 1;
- size_t const uStart = rankVal[w];
- size_t const uEnd = uStart + length;
- size_t u;
- HUF_DEltX1 D;
- D.byte = (BYTE)n;
- D.nbBits = (BYTE)(tableLog + 1 - w);
- rankVal[w] = (U32)uEnd;
- if (length < 4) {
- /* Use length in the loop bound so the compiler knows it is short. */
- for (u = 0; u < length; ++u)
- dt[uStart + u] = D;
- } else {
- /* Unroll the loop 4 times, we know it is a power of 2. */
- for (u = uStart; u < uEnd; u += 4) {
- dt[u + 0] = D;
- dt[u + 1] = D;
- dt[u + 2] = D;
- dt[u + 3] = D;
- } } } }
- return iSize;
-}
-
-size_t HUF_readDTableX1(HUF_DTable* DTable, const void* src, size_t srcSize)
-{
- U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
- return HUF_readDTableX1_wksp(DTable, src, srcSize,
- workSpace, sizeof(workSpace));
-}
-
-FORCE_INLINE_TEMPLATE BYTE
-HUF_decodeSymbolX1(BIT_DStream_t* Dstream, const HUF_DEltX1* dt, const U32 dtLog)
-{
- size_t const val = BIT_lookBitsFast(Dstream, dtLog); /* note : dtLog >= 1 */
- BYTE const c = dt[val].byte;
- BIT_skipBits(Dstream, dt[val].nbBits);
- return c;
-}
-
-#define HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr) \
- *ptr++ = HUF_decodeSymbolX1(DStreamPtr, dt, dtLog)
-
-#define HUF_DECODE_SYMBOLX1_1(ptr, DStreamPtr) \
- if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \
- HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr)
-
-#define HUF_DECODE_SYMBOLX1_2(ptr, DStreamPtr) \
- if (MEM_64bits()) \
- HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr)
-
-HINT_INLINE size_t
-HUF_decodeStreamX1(BYTE* p, BIT_DStream_t* const bitDPtr, BYTE* const pEnd, const HUF_DEltX1* const dt, const U32 dtLog)
-{
- BYTE* const pStart = p;
-
- /* up to 4 symbols at a time */
- while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-3)) {
- HUF_DECODE_SYMBOLX1_2(p, bitDPtr);
- HUF_DECODE_SYMBOLX1_1(p, bitDPtr);
- HUF_DECODE_SYMBOLX1_2(p, bitDPtr);
- HUF_DECODE_SYMBOLX1_0(p, bitDPtr);
- }
-
- /* [0-3] symbols remaining */
- if (MEM_32bits())
- while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd))
- HUF_DECODE_SYMBOLX1_0(p, bitDPtr);
-
- /* no more data to retrieve from bitstream, no need to reload */
- while (p < pEnd)
- HUF_DECODE_SYMBOLX1_0(p, bitDPtr);
-
- return pEnd-pStart;
-}
-
-FORCE_INLINE_TEMPLATE size_t
-HUF_decompress1X1_usingDTable_internal_body(
- void* dst, size_t dstSize,
- const void* cSrc, size_t cSrcSize,
- const HUF_DTable* DTable)
-{
- BYTE* op = (BYTE*)dst;
- BYTE* const oend = op + dstSize;
- const void* dtPtr = DTable + 1;
- const HUF_DEltX1* const dt = (const HUF_DEltX1*)dtPtr;
- BIT_DStream_t bitD;
- DTableDesc const dtd = HUF_getDTableDesc(DTable);
- U32 const dtLog = dtd.tableLog;
-
- CHECK_F( BIT_initDStream(&bitD, cSrc, cSrcSize) );
-
- HUF_decodeStreamX1(op, &bitD, oend, dt, dtLog);
-
- if (!BIT_endOfDStream(&bitD)) return ERROR(corruption_detected);
-
- return dstSize;
-}
-
-FORCE_INLINE_TEMPLATE size_t
-HUF_decompress4X1_usingDTable_internal_body(
- void* dst, size_t dstSize,
- const void* cSrc, size_t cSrcSize,
- const HUF_DTable* DTable)
-{
- /* Check */
- if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */
-
- { const BYTE* const istart = (const BYTE*) cSrc;
- BYTE* const ostart = (BYTE*) dst;
- BYTE* const oend = ostart + dstSize;
- BYTE* const olimit = oend - 3;
- const void* const dtPtr = DTable + 1;
- const HUF_DEltX1* const dt = (const HUF_DEltX1*)dtPtr;
-
- /* Init */
- BIT_DStream_t bitD1;
- BIT_DStream_t bitD2;
- BIT_DStream_t bitD3;
- BIT_DStream_t bitD4;
- size_t const length1 = MEM_readLE16(istart);
- size_t const length2 = MEM_readLE16(istart+2);
- size_t const length3 = MEM_readLE16(istart+4);
- size_t const length4 = cSrcSize - (length1 + length2 + length3 + 6);
- const BYTE* const istart1 = istart + 6; /* jumpTable */
- const BYTE* const istart2 = istart1 + length1;
- const BYTE* const istart3 = istart2 + length2;
- const BYTE* const istart4 = istart3 + length3;
- const size_t segmentSize = (dstSize+3) / 4;
- BYTE* const opStart2 = ostart + segmentSize;
- BYTE* const opStart3 = opStart2 + segmentSize;
- BYTE* const opStart4 = opStart3 + segmentSize;
- BYTE* op1 = ostart;
- BYTE* op2 = opStart2;
- BYTE* op3 = opStart3;
- BYTE* op4 = opStart4;
- DTableDesc const dtd = HUF_getDTableDesc(DTable);
- U32 const dtLog = dtd.tableLog;
- U32 endSignal = 1;
-
- if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */
- CHECK_F( BIT_initDStream(&bitD1, istart1, length1) );
- CHECK_F( BIT_initDStream(&bitD2, istart2, length2) );
- CHECK_F( BIT_initDStream(&bitD3, istart3, length3) );
- CHECK_F( BIT_initDStream(&bitD4, istart4, length4) );
-
- /* up to 16 symbols per loop (4 symbols per stream) in 64-bit mode */
- for ( ; (endSignal) & (op4 < olimit) ; ) {
- HUF_DECODE_SYMBOLX1_2(op1, &bitD1);
- HUF_DECODE_SYMBOLX1_2(op2, &bitD2);
- HUF_DECODE_SYMBOLX1_2(op3, &bitD3);
- HUF_DECODE_SYMBOLX1_2(op4, &bitD4);
- HUF_DECODE_SYMBOLX1_1(op1, &bitD1);
- HUF_DECODE_SYMBOLX1_1(op2, &bitD2);
- HUF_DECODE_SYMBOLX1_1(op3, &bitD3);
- HUF_DECODE_SYMBOLX1_1(op4, &bitD4);
- HUF_DECODE_SYMBOLX1_2(op1, &bitD1);
- HUF_DECODE_SYMBOLX1_2(op2, &bitD2);
- HUF_DECODE_SYMBOLX1_2(op3, &bitD3);
- HUF_DECODE_SYMBOLX1_2(op4, &bitD4);
- HUF_DECODE_SYMBOLX1_0(op1, &bitD1);
- HUF_DECODE_SYMBOLX1_0(op2, &bitD2);
- HUF_DECODE_SYMBOLX1_0(op3, &bitD3);
- HUF_DECODE_SYMBOLX1_0(op4, &bitD4);
- endSignal &= BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished;
- endSignal &= BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished;
- endSignal &= BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished;
- endSignal &= BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished;
- }
-
- /* check corruption */
- /* note : should not be necessary : op# advance in lock step, and we control op4.
- * but curiously, binary generated by gcc 7.2 & 7.3 with -mbmi2 runs faster when >=1 test is present */
- if (op1 > opStart2) return ERROR(corruption_detected);
- if (op2 > opStart3) return ERROR(corruption_detected);
- if (op3 > opStart4) return ERROR(corruption_detected);
- /* note : op4 supposed already verified within main loop */
-
- /* finish bitStreams one by one */
- HUF_decodeStreamX1(op1, &bitD1, opStart2, dt, dtLog);
- HUF_decodeStreamX1(op2, &bitD2, opStart3, dt, dtLog);
- HUF_decodeStreamX1(op3, &bitD3, opStart4, dt, dtLog);
- HUF_decodeStreamX1(op4, &bitD4, oend, dt, dtLog);
-
- /* check */
- { U32 const endCheck = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4);
- if (!endCheck) return ERROR(corruption_detected); }
-
- /* decoded size */
- return dstSize;
- }
-}
-
-
-typedef size_t (*HUF_decompress_usingDTable_t)(void *dst, size_t dstSize,
- const void *cSrc,
- size_t cSrcSize,
- const HUF_DTable *DTable);
-
-HUF_DGEN(HUF_decompress1X1_usingDTable_internal)
-HUF_DGEN(HUF_decompress4X1_usingDTable_internal)
-
-
-
-size_t HUF_decompress1X1_usingDTable(
- void* dst, size_t dstSize,
- const void* cSrc, size_t cSrcSize,
- const HUF_DTable* DTable)
-{
- DTableDesc dtd = HUF_getDTableDesc(DTable);
- if (dtd.tableType != 0) return ERROR(GENERIC);
- return HUF_decompress1X1_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
-}
-
-size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize,
- const void* cSrc, size_t cSrcSize,
- void* workSpace, size_t wkspSize)
-{
- const BYTE* ip = (const BYTE*) cSrc;
-
- size_t const hSize = HUF_readDTableX1_wksp(DCtx, cSrc, cSrcSize, workSpace, wkspSize);
- if (HUF_isError(hSize)) return hSize;
- if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
- ip += hSize; cSrcSize -= hSize;
-
- return HUF_decompress1X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx, /* bmi2 */ 0);
-}
-
-
-size_t HUF_decompress1X1_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize,
- const void* cSrc, size_t cSrcSize)
-{
- U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
- return HUF_decompress1X1_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize,
- workSpace, sizeof(workSpace));
-}
-
-size_t HUF_decompress1X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
-{
- HUF_CREATE_STATIC_DTABLEX1(DTable, HUF_TABLELOG_MAX);
- return HUF_decompress1X1_DCtx (DTable, dst, dstSize, cSrc, cSrcSize);
-}
-
-size_t HUF_decompress4X1_usingDTable(
- void* dst, size_t dstSize,
- const void* cSrc, size_t cSrcSize,
- const HUF_DTable* DTable)
-{
- DTableDesc dtd = HUF_getDTableDesc(DTable);
- if (dtd.tableType != 0) return ERROR(GENERIC);
- return HUF_decompress4X1_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
-}
-
-static size_t HUF_decompress4X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize,
- const void* cSrc, size_t cSrcSize,
- void* workSpace, size_t wkspSize, int bmi2)
-{
- const BYTE* ip = (const BYTE*) cSrc;
-
- size_t const hSize = HUF_readDTableX1_wksp (dctx, cSrc, cSrcSize,
- workSpace, wkspSize);
- if (HUF_isError(hSize)) return hSize;
- if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
- ip += hSize; cSrcSize -= hSize;
-
- return HUF_decompress4X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2);
-}
-
-size_t HUF_decompress4X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize,
- const void* cSrc, size_t cSrcSize,
- void* workSpace, size_t wkspSize)
-{
- return HUF_decompress4X1_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, 0);
-}
-
-
-size_t HUF_decompress4X1_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
-{
- U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
- return HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize,
- workSpace, sizeof(workSpace));
-}
-size_t HUF_decompress4X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
-{
- HUF_CREATE_STATIC_DTABLEX1(DTable, HUF_TABLELOG_MAX);
- return HUF_decompress4X1_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);
-}
-
-#endif /* HUF_FORCE_DECOMPRESS_X2 */
-
-
-#ifndef HUF_FORCE_DECOMPRESS_X1
-
-/* *************************/
-/* double-symbols decoding */
-/* *************************/
-
-typedef struct { U16 sequence; BYTE nbBits; BYTE length; } HUF_DEltX2; /* double-symbols decoding */
-typedef struct { BYTE symbol; BYTE weight; } sortedSymbol_t;
-typedef U32 rankValCol_t[HUF_TABLELOG_MAX + 1];
-typedef rankValCol_t rankVal_t[HUF_TABLELOG_MAX];
-
-
-/* HUF_fillDTableX2Level2() :
- * `rankValOrigin` must be a table of at least (HUF_TABLELOG_MAX + 1) U32 */
-static void HUF_fillDTableX2Level2(HUF_DEltX2* DTable, U32 sizeLog, const U32 consumed,
- const U32* rankValOrigin, const int minWeight,
- const sortedSymbol_t* sortedSymbols, const U32 sortedListSize,
- U32 nbBitsBaseline, U16 baseSeq)
-{
- HUF_DEltX2 DElt;
- U32 rankVal[HUF_TABLELOG_MAX + 1];
-
- /* get pre-calculated rankVal */
- memcpy(rankVal, rankValOrigin, sizeof(rankVal));
-
- /* fill skipped values */
- if (minWeight>1) {
- U32 i, skipSize = rankVal[minWeight];
- MEM_writeLE16(&(DElt.sequence), baseSeq);
- DElt.nbBits = (BYTE)(consumed);
- DElt.length = 1;
- for (i = 0; i < skipSize; i++)
- DTable[i] = DElt;
- }
-
- /* fill DTable */
- { U32 s; for (s=0; s<sortedListSize; s++) { /* note : sortedSymbols already skipped */
- const U32 symbol = sortedSymbols[s].symbol;
- const U32 weight = sortedSymbols[s].weight;
- const U32 nbBits = nbBitsBaseline - weight;
- const U32 length = 1 << (sizeLog-nbBits);
- const U32 start = rankVal[weight];
- U32 i = start;
- const U32 end = start + length;
-
- MEM_writeLE16(&(DElt.sequence), (U16)(baseSeq + (symbol << 8)));
- DElt.nbBits = (BYTE)(nbBits + consumed);
- DElt.length = 2;
- do { DTable[i++] = DElt; } while (i<end); /* since length >= 1 */
-
- rankVal[weight] += length;
- } }
-}
-
-
-static void HUF_fillDTableX2(HUF_DEltX2* DTable, const U32 targetLog,
- const sortedSymbol_t* sortedList, const U32 sortedListSize,
- const U32* rankStart, rankVal_t rankValOrigin, const U32 maxWeight,
- const U32 nbBitsBaseline)
-{
- U32 rankVal[HUF_TABLELOG_MAX + 1];
- const int scaleLog = nbBitsBaseline - targetLog; /* note : targetLog >= srcLog, hence scaleLog <= 1 */
- const U32 minBits = nbBitsBaseline - maxWeight;
- U32 s;
-
- memcpy(rankVal, rankValOrigin, sizeof(rankVal));
-
- /* fill DTable */
- for (s=0; s<sortedListSize; s++) {
- const U16 symbol = sortedList[s].symbol;
- const U32 weight = sortedList[s].weight;
- const U32 nbBits = nbBitsBaseline - weight;
- const U32 start = rankVal[weight];
- const U32 length = 1 << (targetLog-nbBits);
-
- if (targetLog-nbBits >= minBits) { /* enough room for a second symbol */
- U32 sortedRank;
- int minWeight = nbBits + scaleLog;
- if (minWeight < 1) minWeight = 1;
- sortedRank = rankStart[minWeight];
- HUF_fillDTableX2Level2(DTable+start, targetLog-nbBits, nbBits,
- rankValOrigin[nbBits], minWeight,
- sortedList+sortedRank, sortedListSize-sortedRank,
- nbBitsBaseline, symbol);
- } else {
- HUF_DEltX2 DElt;
- MEM_writeLE16(&(DElt.sequence), symbol);
- DElt.nbBits = (BYTE)(nbBits);
- DElt.length = 1;
- { U32 const end = start + length;
- U32 u;
- for (u = start; u < end; u++) DTable[u] = DElt;
- } }
- rankVal[weight] += length;
- }
-}
-
-size_t HUF_readDTableX2_wksp(HUF_DTable* DTable,
- const void* src, size_t srcSize,
- void* workSpace, size_t wkspSize)
-{
- U32 tableLog, maxW, sizeOfSort, nbSymbols;
- DTableDesc dtd = HUF_getDTableDesc(DTable);
- U32 const maxTableLog = dtd.maxTableLog;
- size_t iSize;
- void* dtPtr = DTable+1; /* force compiler to avoid strict-aliasing */
- HUF_DEltX2* const dt = (HUF_DEltX2*)dtPtr;
- U32 *rankStart;
-
- rankValCol_t* rankVal;
- U32* rankStats;
- U32* rankStart0;
- sortedSymbol_t* sortedSymbol;
- BYTE* weightList;
- size_t spaceUsed32 = 0;
-
- rankVal = (rankValCol_t *)((U32 *)workSpace + spaceUsed32);
- spaceUsed32 += (sizeof(rankValCol_t) * HUF_TABLELOG_MAX) >> 2;
- rankStats = (U32 *)workSpace + spaceUsed32;
- spaceUsed32 += HUF_TABLELOG_MAX + 1;
- rankStart0 = (U32 *)workSpace + spaceUsed32;
- spaceUsed32 += HUF_TABLELOG_MAX + 2;
- sortedSymbol = (sortedSymbol_t *)workSpace + (spaceUsed32 * sizeof(U32)) / sizeof(sortedSymbol_t);
- spaceUsed32 += HUF_ALIGN(sizeof(sortedSymbol_t) * (HUF_SYMBOLVALUE_MAX + 1), sizeof(U32)) >> 2;
- weightList = (BYTE *)((U32 *)workSpace + spaceUsed32);
- spaceUsed32 += HUF_ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2;
-
- if ((spaceUsed32 << 2) > wkspSize) return ERROR(tableLog_tooLarge);
-
- rankStart = rankStart0 + 1;
- memset(rankStats, 0, sizeof(U32) * (2 * HUF_TABLELOG_MAX + 2 + 1));
-
- DEBUG_STATIC_ASSERT(sizeof(HUF_DEltX2) == sizeof(HUF_DTable)); /* if compiler fails here, assertion is wrong */
- if (maxTableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge);
- /* memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, even though some analyzer complain ... */
-
- iSize = HUF_readStats(weightList, HUF_SYMBOLVALUE_MAX + 1, rankStats, &nbSymbols, &tableLog, src, srcSize);
- if (HUF_isError(iSize)) return iSize;
-
- /* check result */
- if (tableLog > maxTableLog) return ERROR(tableLog_tooLarge); /* DTable can't fit code depth */
-
- /* find maxWeight */
- for (maxW = tableLog; rankStats[maxW]==0; maxW--) {} /* necessarily finds a solution before 0 */
-
- /* Get start index of each weight */
- { U32 w, nextRankStart = 0;
- for (w=1; w<maxW+1; w++) {
- U32 current = nextRankStart;
- nextRankStart += rankStats[w];
- rankStart[w] = current;
- }
- rankStart[0] = nextRankStart; /* put all 0w symbols at the end of sorted list*/
- sizeOfSort = nextRankStart;
- }
-
- /* sort symbols by weight */
- { U32 s;
- for (s=0; s<nbSymbols; s++) {
- U32 const w = weightList[s];
- U32 const r = rankStart[w]++;
- sortedSymbol[r].symbol = (BYTE)s;
- sortedSymbol[r].weight = (BYTE)w;
- }
- rankStart[0] = 0; /* forget 0w symbols; this is beginning of weight(1) */
- }
-
- /* Build rankVal */
- { U32* const rankVal0 = rankVal[0];
- { int const rescale = (maxTableLog-tableLog) - 1; /* tableLog <= maxTableLog */
- U32 nextRankVal = 0;
- U32 w;
- for (w=1; w<maxW+1; w++) {
- U32 current = nextRankVal;
- nextRankVal += rankStats[w] << (w+rescale);
- rankVal0[w] = current;
- } }
- { U32 const minBits = tableLog+1 - maxW;
- U32 consumed;
- for (consumed = minBits; consumed < maxTableLog - minBits + 1; consumed++) {
- U32* const rankValPtr = rankVal[consumed];
- U32 w;
- for (w = 1; w < maxW+1; w++) {
- rankValPtr[w] = rankVal0[w] >> consumed;
- } } } }
-
- HUF_fillDTableX2(dt, maxTableLog,
- sortedSymbol, sizeOfSort,
- rankStart0, rankVal, maxW,
- tableLog+1);
-
- dtd.tableLog = (BYTE)maxTableLog;
- dtd.tableType = 1;
- memcpy(DTable, &dtd, sizeof(dtd));
- return iSize;
-}
-
-size_t HUF_readDTableX2(HUF_DTable* DTable, const void* src, size_t srcSize)
-{
- U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
- return HUF_readDTableX2_wksp(DTable, src, srcSize,
- workSpace, sizeof(workSpace));
-}
-
-
-FORCE_INLINE_TEMPLATE U32
-HUF_decodeSymbolX2(void* op, BIT_DStream_t* DStream, const HUF_DEltX2* dt, const U32 dtLog)
-{
- size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */
- memcpy(op, dt+val, 2);
- BIT_skipBits(DStream, dt[val].nbBits);
- return dt[val].length;
-}
-
-FORCE_INLINE_TEMPLATE U32
-HUF_decodeLastSymbolX2(void* op, BIT_DStream_t* DStream, const HUF_DEltX2* dt, const U32 dtLog)
-{
- size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */
- memcpy(op, dt+val, 1);
- if (dt[val].length==1) BIT_skipBits(DStream, dt[val].nbBits);
- else {
- if (DStream->bitsConsumed < (sizeof(DStream->bitContainer)*8)) {
- BIT_skipBits(DStream, dt[val].nbBits);
- if (DStream->bitsConsumed > (sizeof(DStream->bitContainer)*8))
- /* ugly hack; works only because it's the last symbol. Note : can't easily extract nbBits from just this symbol */
- DStream->bitsConsumed = (sizeof(DStream->bitContainer)*8);
- } }
- return 1;
-}
-
-#define HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr) \
- ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog)
-
-#define HUF_DECODE_SYMBOLX2_1(ptr, DStreamPtr) \
- if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \
- ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog)
-
-#define HUF_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \
- if (MEM_64bits()) \
- ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog)
-
-HINT_INLINE size_t
-HUF_decodeStreamX2(BYTE* p, BIT_DStream_t* bitDPtr, BYTE* const pEnd,
- const HUF_DEltX2* const dt, const U32 dtLog)
-{
- BYTE* const pStart = p;
-
- /* up to 8 symbols at a time */
- while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-(sizeof(bitDPtr->bitContainer)-1))) {
- HUF_DECODE_SYMBOLX2_2(p, bitDPtr);
- HUF_DECODE_SYMBOLX2_1(p, bitDPtr);
- HUF_DECODE_SYMBOLX2_2(p, bitDPtr);
- HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
- }
-
- /* closer to end : up to 2 symbols at a time */
- while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p <= pEnd-2))
- HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
-
- while (p <= pEnd-2)
- HUF_DECODE_SYMBOLX2_0(p, bitDPtr); /* no need to reload : reached the end of DStream */
-
- if (p < pEnd)
- p += HUF_decodeLastSymbolX2(p, bitDPtr, dt, dtLog);
-
- return p-pStart;
-}
-
-FORCE_INLINE_TEMPLATE size_t
-HUF_decompress1X2_usingDTable_internal_body(
- void* dst, size_t dstSize,
- const void* cSrc, size_t cSrcSize,
- const HUF_DTable* DTable)
-{
- BIT_DStream_t bitD;
-
- /* Init */
- CHECK_F( BIT_initDStream(&bitD, cSrc, cSrcSize) );
-
- /* decode */
- { BYTE* const ostart = (BYTE*) dst;
- BYTE* const oend = ostart + dstSize;
- const void* const dtPtr = DTable+1; /* force compiler to not use strict-aliasing */
- const HUF_DEltX2* const dt = (const HUF_DEltX2*)dtPtr;
- DTableDesc const dtd = HUF_getDTableDesc(DTable);
- HUF_decodeStreamX2(ostart, &bitD, oend, dt, dtd.tableLog);
- }
-
- /* check */
- if (!BIT_endOfDStream(&bitD)) return ERROR(corruption_detected);
-
- /* decoded size */
- return dstSize;
-}
-
-FORCE_INLINE_TEMPLATE size_t
-HUF_decompress4X2_usingDTable_internal_body(
- void* dst, size_t dstSize,
- const void* cSrc, size_t cSrcSize,
- const HUF_DTable* DTable)
-{
- if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */
-
- { const BYTE* const istart = (const BYTE*) cSrc;
- BYTE* const ostart = (BYTE*) dst;
- BYTE* const oend = ostart + dstSize;
- BYTE* const olimit = oend - (sizeof(size_t)-1);
- const void* const dtPtr = DTable+1;
- const HUF_DEltX2* const dt = (const HUF_DEltX2*)dtPtr;
-
- /* Init */
- BIT_DStream_t bitD1;
- BIT_DStream_t bitD2;
- BIT_DStream_t bitD3;
- BIT_DStream_t bitD4;
- size_t const length1 = MEM_readLE16(istart);
- size_t const length2 = MEM_readLE16(istart+2);
- size_t const length3 = MEM_readLE16(istart+4);
- size_t const length4 = cSrcSize - (length1 + length2 + length3 + 6);
- const BYTE* const istart1 = istart + 6; /* jumpTable */
- const BYTE* const istart2 = istart1 + length1;
- const BYTE* const istart3 = istart2 + length2;
- const BYTE* const istart4 = istart3 + length3;
- size_t const segmentSize = (dstSize+3) / 4;
- BYTE* const opStart2 = ostart + segmentSize;
- BYTE* const opStart3 = opStart2 + segmentSize;
- BYTE* const opStart4 = opStart3 + segmentSize;
- BYTE* op1 = ostart;
- BYTE* op2 = opStart2;
- BYTE* op3 = opStart3;
- BYTE* op4 = opStart4;
- U32 endSignal = 1;
- DTableDesc const dtd = HUF_getDTableDesc(DTable);
- U32 const dtLog = dtd.tableLog;
-
- if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */
- CHECK_F( BIT_initDStream(&bitD1, istart1, length1) );
- CHECK_F( BIT_initDStream(&bitD2, istart2, length2) );
- CHECK_F( BIT_initDStream(&bitD3, istart3, length3) );
- CHECK_F( BIT_initDStream(&bitD4, istart4, length4) );
-
- /* 16-32 symbols per loop (4-8 symbols per stream) */
- for ( ; (endSignal) & (op4 < olimit); ) {
-#if defined(__clang__) && (defined(__x86_64__) || defined(__i386__))
- HUF_DECODE_SYMBOLX2_2(op1, &bitD1);
- HUF_DECODE_SYMBOLX2_1(op1, &bitD1);
- HUF_DECODE_SYMBOLX2_2(op1, &bitD1);
- HUF_DECODE_SYMBOLX2_0(op1, &bitD1);
- HUF_DECODE_SYMBOLX2_2(op2, &bitD2);
- HUF_DECODE_SYMBOLX2_1(op2, &bitD2);
- HUF_DECODE_SYMBOLX2_2(op2, &bitD2);
- HUF_DECODE_SYMBOLX2_0(op2, &bitD2);
- endSignal &= BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished;
- endSignal &= BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished;
- HUF_DECODE_SYMBOLX2_2(op3, &bitD3);
- HUF_DECODE_SYMBOLX2_1(op3, &bitD3);
- HUF_DECODE_SYMBOLX2_2(op3, &bitD3);
- HUF_DECODE_SYMBOLX2_0(op3, &bitD3);
- HUF_DECODE_SYMBOLX2_2(op4, &bitD4);
- HUF_DECODE_SYMBOLX2_1(op4, &bitD4);
- HUF_DECODE_SYMBOLX2_2(op4, &bitD4);
- HUF_DECODE_SYMBOLX2_0(op4, &bitD4);
- endSignal &= BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished;
- endSignal &= BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished;
-#else
- HUF_DECODE_SYMBOLX2_2(op1, &bitD1);
- HUF_DECODE_SYMBOLX2_2(op2, &bitD2);
- HUF_DECODE_SYMBOLX2_2(op3, &bitD3);
- HUF_DECODE_SYMBOLX2_2(op4, &bitD4);
- HUF_DECODE_SYMBOLX2_1(op1, &bitD1);
- HUF_DECODE_SYMBOLX2_1(op2, &bitD2);
- HUF_DECODE_SYMBOLX2_1(op3, &bitD3);
- HUF_DECODE_SYMBOLX2_1(op4, &bitD4);
- HUF_DECODE_SYMBOLX2_2(op1, &bitD1);
- HUF_DECODE_SYMBOLX2_2(op2, &bitD2);
- HUF_DECODE_SYMBOLX2_2(op3, &bitD3);
- HUF_DECODE_SYMBOLX2_2(op4, &bitD4);
- HUF_DECODE_SYMBOLX2_0(op1, &bitD1);
- HUF_DECODE_SYMBOLX2_0(op2, &bitD2);
- HUF_DECODE_SYMBOLX2_0(op3, &bitD3);
- HUF_DECODE_SYMBOLX2_0(op4, &bitD4);
- endSignal = (U32)LIKELY(
- (BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished)
- & (BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished)
- & (BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished)
- & (BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished));
-#endif
- }
-
- /* check corruption */
- if (op1 > opStart2) return ERROR(corruption_detected);
- if (op2 > opStart3) return ERROR(corruption_detected);
- if (op3 > opStart4) return ERROR(corruption_detected);
- /* note : op4 already verified within main loop */
-
- /* finish bitStreams one by one */
- HUF_decodeStreamX2(op1, &bitD1, opStart2, dt, dtLog);
- HUF_decodeStreamX2(op2, &bitD2, opStart3, dt, dtLog);
- HUF_decodeStreamX2(op3, &bitD3, opStart4, dt, dtLog);
- HUF_decodeStreamX2(op4, &bitD4, oend, dt, dtLog);
-
- /* check */
- { U32 const endCheck = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4);
- if (!endCheck) return ERROR(corruption_detected); }
-
- /* decoded size */
- return dstSize;
- }
-}
-
-HUF_DGEN(HUF_decompress1X2_usingDTable_internal)
-HUF_DGEN(HUF_decompress4X2_usingDTable_internal)
-
-size_t HUF_decompress1X2_usingDTable(
- void* dst, size_t dstSize,
- const void* cSrc, size_t cSrcSize,
- const HUF_DTable* DTable)
-{
- DTableDesc dtd = HUF_getDTableDesc(DTable);
- if (dtd.tableType != 1) return ERROR(GENERIC);
- return HUF_decompress1X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
-}
-
-size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize,
- const void* cSrc, size_t cSrcSize,
- void* workSpace, size_t wkspSize)
-{
- const BYTE* ip = (const BYTE*) cSrc;
-
- size_t const hSize = HUF_readDTableX2_wksp(DCtx, cSrc, cSrcSize,
- workSpace, wkspSize);
- if (HUF_isError(hSize)) return hSize;
- if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
- ip += hSize; cSrcSize -= hSize;
-
- return HUF_decompress1X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx, /* bmi2 */ 0);
-}
-
-
-size_t HUF_decompress1X2_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize,
- const void* cSrc, size_t cSrcSize)
-{
- U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
- return HUF_decompress1X2_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize,
- workSpace, sizeof(workSpace));
-}
-
-size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
-{
- HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX);
- return HUF_decompress1X2_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);
-}
-
-size_t HUF_decompress4X2_usingDTable(
- void* dst, size_t dstSize,
- const void* cSrc, size_t cSrcSize,
- const HUF_DTable* DTable)
-{
- DTableDesc dtd = HUF_getDTableDesc(DTable);
- if (dtd.tableType != 1) return ERROR(GENERIC);
- return HUF_decompress4X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
-}
-
-static size_t HUF_decompress4X2_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize,
- const void* cSrc, size_t cSrcSize,
- void* workSpace, size_t wkspSize, int bmi2)
-{
- const BYTE* ip = (const BYTE*) cSrc;
-
- size_t hSize = HUF_readDTableX2_wksp(dctx, cSrc, cSrcSize,
- workSpace, wkspSize);
- if (HUF_isError(hSize)) return hSize;
- if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
- ip += hSize; cSrcSize -= hSize;
-
- return HUF_decompress4X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2);
-}
-
-size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize,
- const void* cSrc, size_t cSrcSize,
- void* workSpace, size_t wkspSize)
-{
- return HUF_decompress4X2_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, /* bmi2 */ 0);
-}
-
-
-size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize,
- const void* cSrc, size_t cSrcSize)
-{
- U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
- return HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize,
- workSpace, sizeof(workSpace));
-}
-
-size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
-{
- HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX);
- return HUF_decompress4X2_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);
-}
-
-#endif /* HUF_FORCE_DECOMPRESS_X1 */
-
-
-/* ***********************************/
-/* Universal decompression selectors */
-/* ***********************************/
-
-size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize,
- const void* cSrc, size_t cSrcSize,
- const HUF_DTable* DTable)
-{
- DTableDesc const dtd = HUF_getDTableDesc(DTable);
-#if defined(HUF_FORCE_DECOMPRESS_X1)
- (void)dtd;
- assert(dtd.tableType == 0);
- return HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
-#elif defined(HUF_FORCE_DECOMPRESS_X2)
- (void)dtd;
- assert(dtd.tableType == 1);
- return HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
-#else
- return dtd.tableType ? HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0) :
- HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
-#endif
-}
-
-size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize,
- const void* cSrc, size_t cSrcSize,
- const HUF_DTable* DTable)
-{
- DTableDesc const dtd = HUF_getDTableDesc(DTable);
-#if defined(HUF_FORCE_DECOMPRESS_X1)
- (void)dtd;
- assert(dtd.tableType == 0);
- return HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
-#elif defined(HUF_FORCE_DECOMPRESS_X2)
- (void)dtd;
- assert(dtd.tableType == 1);
- return HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
-#else
- return dtd.tableType ? HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0) :
- HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0);
-#endif
-}
-
-
-#if !defined(HUF_FORCE_DECOMPRESS_X1) && !defined(HUF_FORCE_DECOMPRESS_X2)
-typedef struct { U32 tableTime; U32 decode256Time; } algo_time_t;
-static const algo_time_t algoTime[16 /* Quantization */][3 /* single, double, quad */] =
-{
- /* single, double, quad */
- {{0,0}, {1,1}, {2,2}}, /* Q==0 : impossible */
- {{0,0}, {1,1}, {2,2}}, /* Q==1 : impossible */
- {{ 38,130}, {1313, 74}, {2151, 38}}, /* Q == 2 : 12-18% */
- {{ 448,128}, {1353, 74}, {2238, 41}}, /* Q == 3 : 18-25% */
- {{ 556,128}, {1353, 74}, {2238, 47}}, /* Q == 4 : 25-32% */
- {{ 714,128}, {1418, 74}, {2436, 53}}, /* Q == 5 : 32-38% */
- {{ 883,128}, {1437, 74}, {2464, 61}}, /* Q == 6 : 38-44% */
- {{ 897,128}, {1515, 75}, {2622, 68}}, /* Q == 7 : 44-50% */
- {{ 926,128}, {1613, 75}, {2730, 75}}, /* Q == 8 : 50-56% */
- {{ 947,128}, {1729, 77}, {3359, 77}}, /* Q == 9 : 56-62% */
- {{1107,128}, {2083, 81}, {4006, 84}}, /* Q ==10 : 62-69% */
- {{1177,128}, {2379, 87}, {4785, 88}}, /* Q ==11 : 69-75% */
- {{1242,128}, {2415, 93}, {5155, 84}}, /* Q ==12 : 75-81% */
- {{1349,128}, {2644,106}, {5260,106}}, /* Q ==13 : 81-87% */
- {{1455,128}, {2422,124}, {4174,124}}, /* Q ==14 : 87-93% */
- {{ 722,128}, {1891,145}, {1936,146}}, /* Q ==15 : 93-99% */
-};
-#endif
-
-/** HUF_selectDecoder() :
- * Tells which decoder is likely to decode faster,
- * based on a set of pre-computed metrics.
- * @return : 0==HUF_decompress4X1, 1==HUF_decompress4X2 .
- * Assumption : 0 < dstSize <= 128 KB */
-U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize)
-{
- assert(dstSize > 0);
- assert(dstSize <= 128*1024);
-#if defined(HUF_FORCE_DECOMPRESS_X1)
- (void)dstSize;
- (void)cSrcSize;
- return 0;
-#elif defined(HUF_FORCE_DECOMPRESS_X2)
- (void)dstSize;
- (void)cSrcSize;
- return 1;
-#else
- /* decoder timing evaluation */
- { U32 const Q = (cSrcSize >= dstSize) ? 15 : (U32)(cSrcSize * 16 / dstSize); /* Q < 16 */
- U32 const D256 = (U32)(dstSize >> 8);
- U32 const DTime0 = algoTime[Q][0].tableTime + (algoTime[Q][0].decode256Time * D256);
- U32 DTime1 = algoTime[Q][1].tableTime + (algoTime[Q][1].decode256Time * D256);
- DTime1 += DTime1 >> 3; /* advantage to algorithm using less memory, to reduce cache eviction */
- return DTime1 < DTime0;
- }
-#endif
-}
-
-
-typedef size_t (*decompressionAlgo)(void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);
-
-size_t HUF_decompress (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
-{
-#if !defined(HUF_FORCE_DECOMPRESS_X1) && !defined(HUF_FORCE_DECOMPRESS_X2)
- static const decompressionAlgo decompress[2] = { HUF_decompress4X1, HUF_decompress4X2 };
-#endif
-
- /* validation checks */
- if (dstSize == 0) return ERROR(dstSize_tooSmall);
- if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */
- if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */
- if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */
-
- { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
-#if defined(HUF_FORCE_DECOMPRESS_X1)
- (void)algoNb;
- assert(algoNb == 0);
- return HUF_decompress4X1(dst, dstSize, cSrc, cSrcSize);
-#elif defined(HUF_FORCE_DECOMPRESS_X2)
- (void)algoNb;
- assert(algoNb == 1);
- return HUF_decompress4X2(dst, dstSize, cSrc, cSrcSize);
-#else
- return decompress[algoNb](dst, dstSize, cSrc, cSrcSize);
-#endif
- }
-}
-
-size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
-{
- /* validation checks */
- if (dstSize == 0) return ERROR(dstSize_tooSmall);
- if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */
- if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */
- if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */
-
- { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
-#if defined(HUF_FORCE_DECOMPRESS_X1)
- (void)algoNb;
- assert(algoNb == 0);
- return HUF_decompress4X1_DCtx(dctx, dst, dstSize, cSrc, cSrcSize);
-#elif defined(HUF_FORCE_DECOMPRESS_X2)
- (void)algoNb;
- assert(algoNb == 1);
- return HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize);
-#else
- return algoNb ? HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) :
- HUF_decompress4X1_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) ;
-#endif
- }
-}
-
-size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
-{
- U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
- return HUF_decompress4X_hufOnly_wksp(dctx, dst, dstSize, cSrc, cSrcSize,
- workSpace, sizeof(workSpace));
-}
-
-
-size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst,
- size_t dstSize, const void* cSrc,
- size_t cSrcSize, void* workSpace,
- size_t wkspSize)
-{
- /* validation checks */
- if (dstSize == 0) return ERROR(dstSize_tooSmall);
- if (cSrcSize == 0) return ERROR(corruption_detected);
-
- { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
-#if defined(HUF_FORCE_DECOMPRESS_X1)
- (void)algoNb;
- assert(algoNb == 0);
- return HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize);
-#elif defined(HUF_FORCE_DECOMPRESS_X2)
- (void)algoNb;
- assert(algoNb == 1);
- return HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize);
-#else
- return algoNb ? HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc,
- cSrcSize, workSpace, wkspSize):
- HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize);
-#endif
- }
-}
-
-size_t HUF_decompress1X_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize,
- const void* cSrc, size_t cSrcSize,
- void* workSpace, size_t wkspSize)
-{
- /* validation checks */
- if (dstSize == 0) return ERROR(dstSize_tooSmall);
- if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */
- if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */
- if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */
-
- { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
-#if defined(HUF_FORCE_DECOMPRESS_X1)
- (void)algoNb;
- assert(algoNb == 0);
- return HUF_decompress1X1_DCtx_wksp(dctx, dst, dstSize, cSrc,
- cSrcSize, workSpace, wkspSize);
-#elif defined(HUF_FORCE_DECOMPRESS_X2)
- (void)algoNb;
- assert(algoNb == 1);
- return HUF_decompress1X2_DCtx_wksp(dctx, dst, dstSize, cSrc,
- cSrcSize, workSpace, wkspSize);
-#else
- return algoNb ? HUF_decompress1X2_DCtx_wksp(dctx, dst, dstSize, cSrc,
- cSrcSize, workSpace, wkspSize):
- HUF_decompress1X1_DCtx_wksp(dctx, dst, dstSize, cSrc,
- cSrcSize, workSpace, wkspSize);
-#endif
- }
-}
-
-size_t HUF_decompress1X_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize,
- const void* cSrc, size_t cSrcSize)
-{
- U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
- return HUF_decompress1X_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize,
- workSpace, sizeof(workSpace));
-}
-
-
-size_t HUF_decompress1X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2)
-{
- DTableDesc const dtd = HUF_getDTableDesc(DTable);
-#if defined(HUF_FORCE_DECOMPRESS_X1)
- (void)dtd;
- assert(dtd.tableType == 0);
- return HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2);
-#elif defined(HUF_FORCE_DECOMPRESS_X2)
- (void)dtd;
- assert(dtd.tableType == 1);
- return HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2);
-#else
- return dtd.tableType ? HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2) :
- HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2);
-#endif
-}
-
-#ifndef HUF_FORCE_DECOMPRESS_X2
-size_t HUF_decompress1X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2)
-{
- const BYTE* ip = (const BYTE*) cSrc;
-
- size_t const hSize = HUF_readDTableX1_wksp(dctx, cSrc, cSrcSize, workSpace, wkspSize);
- if (HUF_isError(hSize)) return hSize;
- if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
- ip += hSize; cSrcSize -= hSize;
-
- return HUF_decompress1X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2);
-}
-#endif
-
-size_t HUF_decompress4X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2)
-{
- DTableDesc const dtd = HUF_getDTableDesc(DTable);
-#if defined(HUF_FORCE_DECOMPRESS_X1)
- (void)dtd;
- assert(dtd.tableType == 0);
- return HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2);
-#elif defined(HUF_FORCE_DECOMPRESS_X2)
- (void)dtd;
- assert(dtd.tableType == 1);
- return HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2);
-#else
- return dtd.tableType ? HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2) :
- HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2);
-#endif
-}
-
-size_t HUF_decompress4X_hufOnly_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2)
-{
- /* validation checks */
- if (dstSize == 0) return ERROR(dstSize_tooSmall);
- if (cSrcSize == 0) return ERROR(corruption_detected);
-
- { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
-#if defined(HUF_FORCE_DECOMPRESS_X1)
- (void)algoNb;
- assert(algoNb == 0);
- return HUF_decompress4X1_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2);
-#elif defined(HUF_FORCE_DECOMPRESS_X2)
- (void)algoNb;
- assert(algoNb == 1);
- return HUF_decompress4X2_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2);
-#else
- return algoNb ? HUF_decompress4X2_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2) :
- HUF_decompress4X1_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2);
-#endif
- }
-}
-/**** ended inlining decompress/huf_decompress.c ****/
-/**** start inlining decompress/zstd_ddict.c ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-/* zstd_ddict.c :
- * concentrates all logic that needs to know the internals of ZSTD_DDict object */
-
-/*-*******************************************************
-* Dependencies
-*********************************************************/
-#include <string.h> /* memcpy, memmove, memset */
-/**** skipping file: ../common/cpu.h ****/
-/**** skipping file: ../common/mem.h ****/
-#define FSE_STATIC_LINKING_ONLY
-/**** skipping file: ../common/fse.h ****/
-#define HUF_STATIC_LINKING_ONLY
-/**** skipping file: ../common/huf.h ****/
-/**** start inlining zstd_decompress_internal.h ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-
-/* zstd_decompress_internal:
- * objects and definitions shared within lib/decompress modules */
-
- #ifndef ZSTD_DECOMPRESS_INTERNAL_H
- #define ZSTD_DECOMPRESS_INTERNAL_H
-
-
-/*-*******************************************************
- * Dependencies
- *********************************************************/
-/**** skipping file: ../common/mem.h ****/
-/**** skipping file: ../common/zstd_internal.h ****/
-
-
-
-/*-*******************************************************
- * Constants
- *********************************************************/
-static const U32 LL_base[MaxLL+1] = {
- 0, 1, 2, 3, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 18, 20, 22, 24, 28, 32, 40,
- 48, 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000,
- 0x2000, 0x4000, 0x8000, 0x10000 };
-
-static const U32 OF_base[MaxOff+1] = {
- 0, 1, 1, 5, 0xD, 0x1D, 0x3D, 0x7D,
- 0xFD, 0x1FD, 0x3FD, 0x7FD, 0xFFD, 0x1FFD, 0x3FFD, 0x7FFD,
- 0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD, 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD,
- 0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD, 0x1FFFFFFD, 0x3FFFFFFD, 0x7FFFFFFD };
-
-static const U32 OF_bits[MaxOff+1] = {
- 0, 1, 2, 3, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31 };
-
-static const U32 ML_base[MaxML+1] = {
- 3, 4, 5, 6, 7, 8, 9, 10,
- 11, 12, 13, 14, 15, 16, 17, 18,
- 19, 20, 21, 22, 23, 24, 25, 26,
- 27, 28, 29, 30, 31, 32, 33, 34,
- 35, 37, 39, 41, 43, 47, 51, 59,
- 67, 83, 99, 0x83, 0x103, 0x203, 0x403, 0x803,
- 0x1003, 0x2003, 0x4003, 0x8003, 0x10003 };
-
-
-/*-*******************************************************
- * Decompression types
- *********************************************************/
- typedef struct {
- U32 fastMode;
- U32 tableLog;
- } ZSTD_seqSymbol_header;
-
- typedef struct {
- U16 nextState;
- BYTE nbAdditionalBits;
- BYTE nbBits;
- U32 baseValue;
- } ZSTD_seqSymbol;
-
- #define SEQSYMBOL_TABLE_SIZE(log) (1 + (1 << (log)))
-
-typedef struct {
- ZSTD_seqSymbol LLTable[SEQSYMBOL_TABLE_SIZE(LLFSELog)]; /* Note : Space reserved for FSE Tables */
- ZSTD_seqSymbol OFTable[SEQSYMBOL_TABLE_SIZE(OffFSELog)]; /* is also used as temporary workspace while building hufTable during DDict creation */
- ZSTD_seqSymbol MLTable[SEQSYMBOL_TABLE_SIZE(MLFSELog)]; /* and therefore must be at least HUF_DECOMPRESS_WORKSPACE_SIZE large */
- HUF_DTable hufTable[HUF_DTABLE_SIZE(HufLog)]; /* can accommodate HUF_decompress4X */
- U32 rep[ZSTD_REP_NUM];
-} ZSTD_entropyDTables_t;
-
-typedef enum { ZSTDds_getFrameHeaderSize, ZSTDds_decodeFrameHeader,
- ZSTDds_decodeBlockHeader, ZSTDds_decompressBlock,
- ZSTDds_decompressLastBlock, ZSTDds_checkChecksum,
- ZSTDds_decodeSkippableHeader, ZSTDds_skipFrame } ZSTD_dStage;
-
-typedef enum { zdss_init=0, zdss_loadHeader,
- zdss_read, zdss_load, zdss_flush } ZSTD_dStreamStage;
-
-typedef enum {
- ZSTD_use_indefinitely = -1, /* Use the dictionary indefinitely */
- ZSTD_dont_use = 0, /* Do not use the dictionary (if one exists free it) */
- ZSTD_use_once = 1 /* Use the dictionary once and set to ZSTD_dont_use */
-} ZSTD_dictUses_e;
-
-typedef enum {
- ZSTD_obm_buffered = 0, /* Buffer the output */
- ZSTD_obm_stable = 1 /* ZSTD_outBuffer is stable */
-} ZSTD_outBufferMode_e;
-
-struct ZSTD_DCtx_s
-{
- const ZSTD_seqSymbol* LLTptr;
- const ZSTD_seqSymbol* MLTptr;
- const ZSTD_seqSymbol* OFTptr;
- const HUF_DTable* HUFptr;
- ZSTD_entropyDTables_t entropy;
- U32 workspace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; /* space needed when building huffman tables */
- const void* previousDstEnd; /* detect continuity */
- const void* prefixStart; /* start of current segment */
- const void* virtualStart; /* virtual start of previous segment if it was just before current one */
- const void* dictEnd; /* end of previous segment */
- size_t expected;
- ZSTD_frameHeader fParams;
- U64 decodedSize;
- blockType_e bType; /* used in ZSTD_decompressContinue(), store blockType between block header decoding and block decompression stages */
- ZSTD_dStage stage;
- U32 litEntropy;
- U32 fseEntropy;
- XXH64_state_t xxhState;
- size_t headerSize;
- ZSTD_format_e format;
- const BYTE* litPtr;
- ZSTD_customMem customMem;
- size_t litSize;
- size_t rleSize;
- size_t staticSize;
- int bmi2; /* == 1 if the CPU supports BMI2 and 0 otherwise. CPU support is determined dynamically once per context lifetime. */
-
- /* dictionary */
- ZSTD_DDict* ddictLocal;
- const ZSTD_DDict* ddict; /* set by ZSTD_initDStream_usingDDict(), or ZSTD_DCtx_refDDict() */
- U32 dictID;
- int ddictIsCold; /* if == 1 : dictionary is "new" for working context, and presumed "cold" (not in cpu cache) */
- ZSTD_dictUses_e dictUses;
-
- /* streaming */
- ZSTD_dStreamStage streamStage;
- char* inBuff;
- size_t inBuffSize;
- size_t inPos;
- size_t maxWindowSize;
- char* outBuff;
- size_t outBuffSize;
- size_t outStart;
- size_t outEnd;
- size_t lhSize;
- void* legacyContext;
- U32 previousLegacyVersion;
- U32 legacyVersion;
- U32 hostageByte;
- int noForwardProgress;
- ZSTD_outBufferMode_e outBufferMode;
- ZSTD_outBuffer expectedOutBuffer;
-
- /* workspace */
- BYTE litBuffer[ZSTD_BLOCKSIZE_MAX + WILDCOPY_OVERLENGTH];
- BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX];
-
- size_t oversizedDuration;
-
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
- void const* dictContentBeginForFuzzing;
- void const* dictContentEndForFuzzing;
-#endif
-}; /* typedef'd to ZSTD_DCtx within "zstd.h" */
-
-
-/*-*******************************************************
- * Shared internal functions
- *********************************************************/
-
-/*! ZSTD_loadDEntropy() :
- * dict : must point at beginning of a valid zstd dictionary.
- * @return : size of dictionary header (size of magic number + dict ID + entropy tables) */
-size_t ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy,
- const void* const dict, size_t const dictSize);
-
-/*! ZSTD_checkContinuity() :
- * check if next `dst` follows previous position, where decompression ended.
- * If yes, do nothing (continue on current segment).
- * If not, classify previous segment as "external dictionary", and start a new segment.
- * This function cannot fail. */
-void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst);
-
-
-#endif /* ZSTD_DECOMPRESS_INTERNAL_H */
-/**** ended inlining zstd_decompress_internal.h ****/
-/**** start inlining zstd_ddict.h ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-
-#ifndef ZSTD_DDICT_H
-#define ZSTD_DDICT_H
-
-/*-*******************************************************
- * Dependencies
- *********************************************************/
-#include <stddef.h> /* size_t */
-/**** skipping file: ../zstd.h ****/
-
-
-/*-*******************************************************
- * Interface
- *********************************************************/
-
-/* note: several prototypes are already published in `zstd.h` :
- * ZSTD_createDDict()
- * ZSTD_createDDict_byReference()
- * ZSTD_createDDict_advanced()
- * ZSTD_freeDDict()
- * ZSTD_initStaticDDict()
- * ZSTD_sizeof_DDict()
- * ZSTD_estimateDDictSize()
- * ZSTD_getDictID_fromDict()
- */
-
-const void* ZSTD_DDict_dictContent(const ZSTD_DDict* ddict);
-size_t ZSTD_DDict_dictSize(const ZSTD_DDict* ddict);
-
-void ZSTD_copyDDictParameters(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict);
-
-
-
-#endif /* ZSTD_DDICT_H */
-/**** ended inlining zstd_ddict.h ****/
-
-#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
-/**** start inlining ../legacy/zstd_legacy.h ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-#ifndef ZSTD_LEGACY_H
-#define ZSTD_LEGACY_H
-
-#if defined (__cplusplus)
-extern "C" {
-#endif
-
-/* *************************************
-* Includes
-***************************************/
-/**** skipping file: ../common/mem.h ****/
-/**** skipping file: ../common/error_private.h ****/
-/**** skipping file: ../common/zstd_internal.h ****/
-
-#if !defined (ZSTD_LEGACY_SUPPORT) || (ZSTD_LEGACY_SUPPORT == 0)
-# undef ZSTD_LEGACY_SUPPORT
-# define ZSTD_LEGACY_SUPPORT 8
-#endif
-
-#if (ZSTD_LEGACY_SUPPORT <= 1)
-/**** start inlining zstd_v01.h ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-#ifndef ZSTD_V01_H_28739879432
-#define ZSTD_V01_H_28739879432
-
-#if defined (__cplusplus)
-extern "C" {
-#endif
-
-/* *************************************
-* Includes
-***************************************/
-#include <stddef.h> /* size_t */
-
-
-/* *************************************
-* Simple one-step function
-***************************************/
-/**
-ZSTDv01_decompress() : decompress ZSTD frames compliant with v0.1.x format
- compressedSize : is the exact source size
- maxOriginalSize : is the size of the 'dst' buffer, which must be already allocated.
- It must be equal or larger than originalSize, otherwise decompression will fail.
- return : the number of bytes decompressed into destination buffer (originalSize)
- or an errorCode if it fails (which can be tested using ZSTDv01_isError())
-*/
-size_t ZSTDv01_decompress( void* dst, size_t maxOriginalSize,
- const void* src, size_t compressedSize);
-
- /**
- ZSTDv01_findFrameSizeInfoLegacy() : get the source length and decompressed bound of a ZSTD frame compliant with v0.1.x format
- srcSize : The size of the 'src' buffer, at least as large as the frame pointed to by 'src'
- cSize (output parameter) : the number of bytes that would be read to decompress this frame
- or an error code if it fails (which can be tested using ZSTDv01_isError())
- dBound (output parameter) : an upper-bound for the decompressed size of the data in the frame
- or ZSTD_CONTENTSIZE_ERROR if an error occurs
-
- note : assumes `cSize` and `dBound` are _not_ NULL.
- */
-void ZSTDv01_findFrameSizeInfoLegacy(const void *src, size_t srcSize,
- size_t* cSize, unsigned long long* dBound);
-
-/**
-ZSTDv01_isError() : tells if the result of ZSTDv01_decompress() is an error
-*/
-unsigned ZSTDv01_isError(size_t code);
-
-
-/* *************************************
-* Advanced functions
-***************************************/
-typedef struct ZSTDv01_Dctx_s ZSTDv01_Dctx;
-ZSTDv01_Dctx* ZSTDv01_createDCtx(void);
-size_t ZSTDv01_freeDCtx(ZSTDv01_Dctx* dctx);
-
-size_t ZSTDv01_decompressDCtx(void* ctx,
- void* dst, size_t maxOriginalSize,
- const void* src, size_t compressedSize);
-
-/* *************************************
-* Streaming functions
-***************************************/
-size_t ZSTDv01_resetDCtx(ZSTDv01_Dctx* dctx);
-
-size_t ZSTDv01_nextSrcSizeToDecompress(ZSTDv01_Dctx* dctx);
-size_t ZSTDv01_decompressContinue(ZSTDv01_Dctx* dctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize);
-/**
- Use above functions alternatively.
- ZSTD_nextSrcSizeToDecompress() tells how much bytes to provide as 'srcSize' to ZSTD_decompressContinue().
- ZSTD_decompressContinue() will use previous data blocks to improve compression if they are located prior to current block.
- Result is the number of bytes regenerated within 'dst'.
- It can be zero, which is not an error; it just means ZSTD_decompressContinue() has decoded some header.
-*/
-
-/* *************************************
-* Prefix - version detection
-***************************************/
-#define ZSTDv01_magicNumber 0xFD2FB51E /* Big Endian version */
-#define ZSTDv01_magicNumberLE 0x1EB52FFD /* Little Endian version */
-
-
-#if defined (__cplusplus)
-}
-#endif
-
-#endif /* ZSTD_V01_H_28739879432 */
-/**** ended inlining zstd_v01.h ****/
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 2)
-/**** start inlining zstd_v02.h ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-#ifndef ZSTD_V02_H_4174539423
-#define ZSTD_V02_H_4174539423
-
-#if defined (__cplusplus)
-extern "C" {
-#endif
-
-/* *************************************
-* Includes
-***************************************/
-#include <stddef.h> /* size_t */
-
-
-/* *************************************
-* Simple one-step function
-***************************************/
-/**
-ZSTDv02_decompress() : decompress ZSTD frames compliant with v0.2.x format
- compressedSize : is the exact source size
- maxOriginalSize : is the size of the 'dst' buffer, which must be already allocated.
- It must be equal or larger than originalSize, otherwise decompression will fail.
- return : the number of bytes decompressed into destination buffer (originalSize)
- or an errorCode if it fails (which can be tested using ZSTDv01_isError())
-*/
-size_t ZSTDv02_decompress( void* dst, size_t maxOriginalSize,
- const void* src, size_t compressedSize);
-
- /**
- ZSTDv02_findFrameSizeInfoLegacy() : get the source length and decompressed bound of a ZSTD frame compliant with v0.2.x format
- srcSize : The size of the 'src' buffer, at least as large as the frame pointed to by 'src'
- cSize (output parameter) : the number of bytes that would be read to decompress this frame
- or an error code if it fails (which can be tested using ZSTDv01_isError())
- dBound (output parameter) : an upper-bound for the decompressed size of the data in the frame
- or ZSTD_CONTENTSIZE_ERROR if an error occurs
-
- note : assumes `cSize` and `dBound` are _not_ NULL.
- */
-void ZSTDv02_findFrameSizeInfoLegacy(const void *src, size_t srcSize,
- size_t* cSize, unsigned long long* dBound);
-
-/**
-ZSTDv02_isError() : tells if the result of ZSTDv02_decompress() is an error
-*/
-unsigned ZSTDv02_isError(size_t code);
-
-
-/* *************************************
-* Advanced functions
-***************************************/
-typedef struct ZSTDv02_Dctx_s ZSTDv02_Dctx;
-ZSTDv02_Dctx* ZSTDv02_createDCtx(void);
-size_t ZSTDv02_freeDCtx(ZSTDv02_Dctx* dctx);
-
-size_t ZSTDv02_decompressDCtx(void* ctx,
- void* dst, size_t maxOriginalSize,
- const void* src, size_t compressedSize);
-
-/* *************************************
-* Streaming functions
-***************************************/
-size_t ZSTDv02_resetDCtx(ZSTDv02_Dctx* dctx);
-
-size_t ZSTDv02_nextSrcSizeToDecompress(ZSTDv02_Dctx* dctx);
-size_t ZSTDv02_decompressContinue(ZSTDv02_Dctx* dctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize);
-/**
- Use above functions alternatively.
- ZSTD_nextSrcSizeToDecompress() tells how much bytes to provide as 'srcSize' to ZSTD_decompressContinue().
- ZSTD_decompressContinue() will use previous data blocks to improve compression if they are located prior to current block.
- Result is the number of bytes regenerated within 'dst'.
- It can be zero, which is not an error; it just means ZSTD_decompressContinue() has decoded some header.
-*/
-
-/* *************************************
-* Prefix - version detection
-***************************************/
-#define ZSTDv02_magicNumber 0xFD2FB522 /* v0.2 */
-
-
-#if defined (__cplusplus)
-}
-#endif
-
-#endif /* ZSTD_V02_H_4174539423 */
-/**** ended inlining zstd_v02.h ****/
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 3)
-/**** start inlining zstd_v03.h ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-#ifndef ZSTD_V03_H_298734209782
-#define ZSTD_V03_H_298734209782
-
-#if defined (__cplusplus)
-extern "C" {
-#endif
-
-/* *************************************
-* Includes
-***************************************/
-#include <stddef.h> /* size_t */
-
-
-/* *************************************
-* Simple one-step function
-***************************************/
-/**
-ZSTDv03_decompress() : decompress ZSTD frames compliant with v0.3.x format
- compressedSize : is the exact source size
- maxOriginalSize : is the size of the 'dst' buffer, which must be already allocated.
- It must be equal or larger than originalSize, otherwise decompression will fail.
- return : the number of bytes decompressed into destination buffer (originalSize)
- or an errorCode if it fails (which can be tested using ZSTDv01_isError())
-*/
-size_t ZSTDv03_decompress( void* dst, size_t maxOriginalSize,
- const void* src, size_t compressedSize);
-
- /**
- ZSTDv03_findFrameSizeInfoLegacy() : get the source length and decompressed bound of a ZSTD frame compliant with v0.3.x format
- srcSize : The size of the 'src' buffer, at least as large as the frame pointed to by 'src'
- cSize (output parameter) : the number of bytes that would be read to decompress this frame
- or an error code if it fails (which can be tested using ZSTDv01_isError())
- dBound (output parameter) : an upper-bound for the decompressed size of the data in the frame
- or ZSTD_CONTENTSIZE_ERROR if an error occurs
-
- note : assumes `cSize` and `dBound` are _not_ NULL.
- */
- void ZSTDv03_findFrameSizeInfoLegacy(const void *src, size_t srcSize,
- size_t* cSize, unsigned long long* dBound);
-
- /**
-ZSTDv03_isError() : tells if the result of ZSTDv03_decompress() is an error
-*/
-unsigned ZSTDv03_isError(size_t code);
-
-
-/* *************************************
-* Advanced functions
-***************************************/
-typedef struct ZSTDv03_Dctx_s ZSTDv03_Dctx;
-ZSTDv03_Dctx* ZSTDv03_createDCtx(void);
-size_t ZSTDv03_freeDCtx(ZSTDv03_Dctx* dctx);
-
-size_t ZSTDv03_decompressDCtx(void* ctx,
- void* dst, size_t maxOriginalSize,
- const void* src, size_t compressedSize);
-
-/* *************************************
-* Streaming functions
-***************************************/
-size_t ZSTDv03_resetDCtx(ZSTDv03_Dctx* dctx);
-
-size_t ZSTDv03_nextSrcSizeToDecompress(ZSTDv03_Dctx* dctx);
-size_t ZSTDv03_decompressContinue(ZSTDv03_Dctx* dctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize);
-/**
- Use above functions alternatively.
- ZSTD_nextSrcSizeToDecompress() tells how much bytes to provide as 'srcSize' to ZSTD_decompressContinue().
- ZSTD_decompressContinue() will use previous data blocks to improve compression if they are located prior to current block.
- Result is the number of bytes regenerated within 'dst'.
- It can be zero, which is not an error; it just means ZSTD_decompressContinue() has decoded some header.
-*/
-
-/* *************************************
-* Prefix - version detection
-***************************************/
-#define ZSTDv03_magicNumber 0xFD2FB523 /* v0.3 */
-
-
-#if defined (__cplusplus)
-}
-#endif
-
-#endif /* ZSTD_V03_H_298734209782 */
-/**** ended inlining zstd_v03.h ****/
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 4)
-/**** start inlining zstd_v04.h ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-#ifndef ZSTD_V04_H_91868324769238
-#define ZSTD_V04_H_91868324769238
-
-#if defined (__cplusplus)
-extern "C" {
-#endif
-
-/* *************************************
-* Includes
-***************************************/
-#include <stddef.h> /* size_t */
-
-
-/* *************************************
-* Simple one-step function
-***************************************/
-/**
-ZSTDv04_decompress() : decompress ZSTD frames compliant with v0.4.x format
- compressedSize : is the exact source size
- maxOriginalSize : is the size of the 'dst' buffer, which must be already allocated.
- It must be equal or larger than originalSize, otherwise decompression will fail.
- return : the number of bytes decompressed into destination buffer (originalSize)
- or an errorCode if it fails (which can be tested using ZSTDv01_isError())
-*/
-size_t ZSTDv04_decompress( void* dst, size_t maxOriginalSize,
- const void* src, size_t compressedSize);
-
- /**
- ZSTDv04_findFrameSizeInfoLegacy() : get the source length and decompressed bound of a ZSTD frame compliant with v0.4.x format
- srcSize : The size of the 'src' buffer, at least as large as the frame pointed to by 'src'
- cSize (output parameter) : the number of bytes that would be read to decompress this frame
- or an error code if it fails (which can be tested using ZSTDv01_isError())
- dBound (output parameter) : an upper-bound for the decompressed size of the data in the frame
- or ZSTD_CONTENTSIZE_ERROR if an error occurs
-
- note : assumes `cSize` and `dBound` are _not_ NULL.
- */
- void ZSTDv04_findFrameSizeInfoLegacy(const void *src, size_t srcSize,
- size_t* cSize, unsigned long long* dBound);
-
-/**
-ZSTDv04_isError() : tells if the result of ZSTDv04_decompress() is an error
-*/
-unsigned ZSTDv04_isError(size_t code);
-
-
-/* *************************************
-* Advanced functions
-***************************************/
-typedef struct ZSTDv04_Dctx_s ZSTDv04_Dctx;
-ZSTDv04_Dctx* ZSTDv04_createDCtx(void);
-size_t ZSTDv04_freeDCtx(ZSTDv04_Dctx* dctx);
-
-size_t ZSTDv04_decompressDCtx(ZSTDv04_Dctx* dctx,
- void* dst, size_t maxOriginalSize,
- const void* src, size_t compressedSize);
-
-
-/* *************************************
-* Direct Streaming
-***************************************/
-size_t ZSTDv04_resetDCtx(ZSTDv04_Dctx* dctx);
-
-size_t ZSTDv04_nextSrcSizeToDecompress(ZSTDv04_Dctx* dctx);
-size_t ZSTDv04_decompressContinue(ZSTDv04_Dctx* dctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize);
-/**
- Use above functions alternatively.
- ZSTD_nextSrcSizeToDecompress() tells how much bytes to provide as 'srcSize' to ZSTD_decompressContinue().
- ZSTD_decompressContinue() will use previous data blocks to improve compression if they are located prior to current block.
- Result is the number of bytes regenerated within 'dst'.
- It can be zero, which is not an error; it just means ZSTD_decompressContinue() has decoded some header.
-*/
-
-
-/* *************************************
-* Buffered Streaming
-***************************************/
-typedef struct ZBUFFv04_DCtx_s ZBUFFv04_DCtx;
-ZBUFFv04_DCtx* ZBUFFv04_createDCtx(void);
-size_t ZBUFFv04_freeDCtx(ZBUFFv04_DCtx* dctx);
-
-size_t ZBUFFv04_decompressInit(ZBUFFv04_DCtx* dctx);
-size_t ZBUFFv04_decompressWithDictionary(ZBUFFv04_DCtx* dctx, const void* dict, size_t dictSize);
-
-size_t ZBUFFv04_decompressContinue(ZBUFFv04_DCtx* dctx, void* dst, size_t* maxDstSizePtr, const void* src, size_t* srcSizePtr);
-
-/** ************************************************
-* Streaming decompression
-*
-* A ZBUFF_DCtx object is required to track streaming operation.
-* Use ZBUFF_createDCtx() and ZBUFF_freeDCtx() to create/release resources.
-* Use ZBUFF_decompressInit() to start a new decompression operation.
-* ZBUFF_DCtx objects can be reused multiple times.
-*
-* Optionally, a reference to a static dictionary can be set, using ZBUFF_decompressWithDictionary()
-* It must be the same content as the one set during compression phase.
-* Dictionary content must remain accessible during the decompression process.
-*
-* Use ZBUFF_decompressContinue() repetitively to consume your input.
-* *srcSizePtr and *maxDstSizePtr can be any size.
-* The function will report how many bytes were read or written by modifying *srcSizePtr and *maxDstSizePtr.
-* Note that it may not consume the entire input, in which case it's up to the caller to present remaining input again.
-* The content of dst will be overwritten (up to *maxDstSizePtr) at each function call, so save its content if it matters or change dst.
-* @return : a hint to preferred nb of bytes to use as input for next function call (it's only a hint, to improve latency)
-* or 0 when a frame is completely decoded
-* or an error code, which can be tested using ZBUFF_isError().
-*
-* Hint : recommended buffer sizes (not compulsory) : ZBUFF_recommendedDInSize / ZBUFF_recommendedDOutSize
-* output : ZBUFF_recommendedDOutSize==128 KB block size is the internal unit, it ensures it's always possible to write a full block when it's decoded.
-* input : ZBUFF_recommendedDInSize==128Kb+3; just follow indications from ZBUFF_decompressContinue() to minimize latency. It should always be <= 128 KB + 3 .
-* **************************************************/
-unsigned ZBUFFv04_isError(size_t errorCode);
-const char* ZBUFFv04_getErrorName(size_t errorCode);
-
-
-/** The below functions provide recommended buffer sizes for Compression or Decompression operations.
-* These sizes are not compulsory, they just tend to offer better latency */
-size_t ZBUFFv04_recommendedDInSize(void);
-size_t ZBUFFv04_recommendedDOutSize(void);
-
-
-/* *************************************
-* Prefix - version detection
-***************************************/
-#define ZSTDv04_magicNumber 0xFD2FB524 /* v0.4 */
-
-
-#if defined (__cplusplus)
-}
-#endif
-
-#endif /* ZSTD_V04_H_91868324769238 */
-/**** ended inlining zstd_v04.h ****/
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 5)
-/**** start inlining zstd_v05.h ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-#ifndef ZSTDv05_H
-#define ZSTDv05_H
-
-#if defined (__cplusplus)
-extern "C" {
-#endif
-
-/*-*************************************
-* Dependencies
-***************************************/
-#include <stddef.h> /* size_t */
-/**** skipping file: ../common/mem.h ****/
-
-
-/* *************************************
-* Simple functions
-***************************************/
-/*! ZSTDv05_decompress() :
- `compressedSize` : is the _exact_ size of the compressed blob, otherwise decompression will fail.
- `dstCapacity` must be large enough, equal or larger than originalSize.
- @return : the number of bytes decompressed into `dst` (<= `dstCapacity`),
- or an errorCode if it fails (which can be tested using ZSTDv05_isError()) */
-size_t ZSTDv05_decompress( void* dst, size_t dstCapacity,
- const void* src, size_t compressedSize);
-
- /**
- ZSTDv05_findFrameSizeInfoLegacy() : get the source length and decompressed bound of a ZSTD frame compliant with v0.5.x format
- srcSize : The size of the 'src' buffer, at least as large as the frame pointed to by 'src'
- cSize (output parameter) : the number of bytes that would be read to decompress this frame
- or an error code if it fails (which can be tested using ZSTDv01_isError())
- dBound (output parameter) : an upper-bound for the decompressed size of the data in the frame
- or ZSTD_CONTENTSIZE_ERROR if an error occurs
-
- note : assumes `cSize` and `dBound` are _not_ NULL.
- */
-void ZSTDv05_findFrameSizeInfoLegacy(const void *src, size_t srcSize,
- size_t* cSize, unsigned long long* dBound);
-
-/* *************************************
-* Helper functions
-***************************************/
-/* Error Management */
-unsigned ZSTDv05_isError(size_t code); /*!< tells if a `size_t` function result is an error code */
-const char* ZSTDv05_getErrorName(size_t code); /*!< provides readable string for an error code */
-
-
-/* *************************************
-* Explicit memory management
-***************************************/
-/** Decompression context */
-typedef struct ZSTDv05_DCtx_s ZSTDv05_DCtx;
-ZSTDv05_DCtx* ZSTDv05_createDCtx(void);
-size_t ZSTDv05_freeDCtx(ZSTDv05_DCtx* dctx); /*!< @return : errorCode */
-
-/** ZSTDv05_decompressDCtx() :
-* Same as ZSTDv05_decompress(), but requires an already allocated ZSTDv05_DCtx (see ZSTDv05_createDCtx()) */
-size_t ZSTDv05_decompressDCtx(ZSTDv05_DCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
-
-
-/*-***********************
-* Simple Dictionary API
-*************************/
-/*! ZSTDv05_decompress_usingDict() :
-* Decompression using a pre-defined Dictionary content (see dictBuilder).
-* Dictionary must be identical to the one used during compression, otherwise regenerated data will be corrupted.
-* Note : dict can be NULL, in which case, it's equivalent to ZSTDv05_decompressDCtx() */
-size_t ZSTDv05_decompress_usingDict(ZSTDv05_DCtx* dctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- const void* dict,size_t dictSize);
-
-/*-************************
-* Advanced Streaming API
-***************************/
-typedef enum { ZSTDv05_fast, ZSTDv05_greedy, ZSTDv05_lazy, ZSTDv05_lazy2, ZSTDv05_btlazy2, ZSTDv05_opt, ZSTDv05_btopt } ZSTDv05_strategy;
-typedef struct {
- U64 srcSize;
- U32 windowLog; /* the only useful information to retrieve */
- U32 contentLog; U32 hashLog; U32 searchLog; U32 searchLength; U32 targetLength; ZSTDv05_strategy strategy;
-} ZSTDv05_parameters;
-size_t ZSTDv05_getFrameParams(ZSTDv05_parameters* params, const void* src, size_t srcSize);
-
-size_t ZSTDv05_decompressBegin_usingDict(ZSTDv05_DCtx* dctx, const void* dict, size_t dictSize);
-void ZSTDv05_copyDCtx(ZSTDv05_DCtx* dstDCtx, const ZSTDv05_DCtx* srcDCtx);
-size_t ZSTDv05_nextSrcSizeToDecompress(ZSTDv05_DCtx* dctx);
-size_t ZSTDv05_decompressContinue(ZSTDv05_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
-
-
-/*-***********************
-* ZBUFF API
-*************************/
-typedef struct ZBUFFv05_DCtx_s ZBUFFv05_DCtx;
-ZBUFFv05_DCtx* ZBUFFv05_createDCtx(void);
-size_t ZBUFFv05_freeDCtx(ZBUFFv05_DCtx* dctx);
-
-size_t ZBUFFv05_decompressInit(ZBUFFv05_DCtx* dctx);
-size_t ZBUFFv05_decompressInitDictionary(ZBUFFv05_DCtx* dctx, const void* dict, size_t dictSize);
-
-size_t ZBUFFv05_decompressContinue(ZBUFFv05_DCtx* dctx,
- void* dst, size_t* dstCapacityPtr,
- const void* src, size_t* srcSizePtr);
-
-/*-***************************************************************************
-* Streaming decompression
-*
-* A ZBUFFv05_DCtx object is required to track streaming operations.
-* Use ZBUFFv05_createDCtx() and ZBUFFv05_freeDCtx() to create/release resources.
-* Use ZBUFFv05_decompressInit() to start a new decompression operation,
-* or ZBUFFv05_decompressInitDictionary() if decompression requires a dictionary.
-* Note that ZBUFFv05_DCtx objects can be reused multiple times.
-*
-* Use ZBUFFv05_decompressContinue() repetitively to consume your input.
-* *srcSizePtr and *dstCapacityPtr can be any size.
-* The function will report how many bytes were read or written by modifying *srcSizePtr and *dstCapacityPtr.
-* Note that it may not consume the entire input, in which case it's up to the caller to present remaining input again.
-* The content of @dst will be overwritten (up to *dstCapacityPtr) at each function call, so save its content if it matters or change @dst.
-* @return : a hint to preferred nb of bytes to use as input for next function call (it's only a hint, to help latency)
-* or 0 when a frame is completely decoded
-* or an error code, which can be tested using ZBUFFv05_isError().
-*
-* Hint : recommended buffer sizes (not compulsory) : ZBUFFv05_recommendedDInSize() / ZBUFFv05_recommendedDOutSize()
-* output : ZBUFFv05_recommendedDOutSize==128 KB block size is the internal unit, it ensures it's always possible to write a full block when decoded.
-* input : ZBUFFv05_recommendedDInSize==128Kb+3; just follow indications from ZBUFFv05_decompressContinue() to minimize latency. It should always be <= 128 KB + 3 .
-* *******************************************************************************/
-
-
-/* *************************************
-* Tool functions
-***************************************/
-unsigned ZBUFFv05_isError(size_t errorCode);
-const char* ZBUFFv05_getErrorName(size_t errorCode);
-
-/** Functions below provide recommended buffer sizes for Compression or Decompression operations.
-* These sizes are just hints, and tend to offer better latency */
-size_t ZBUFFv05_recommendedDInSize(void);
-size_t ZBUFFv05_recommendedDOutSize(void);
-
-
-
-/*-*************************************
-* Constants
-***************************************/
-#define ZSTDv05_MAGICNUMBER 0xFD2FB525 /* v0.5 */
-
-
-
-
-#if defined (__cplusplus)
-}
-#endif
-
-#endif /* ZSTDv0505_H */
-/**** ended inlining zstd_v05.h ****/
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 6)
-/**** start inlining zstd_v06.h ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-#ifndef ZSTDv06_H
-#define ZSTDv06_H
-
-#if defined (__cplusplus)
-extern "C" {
-#endif
-
-/*====== Dependency ======*/
-#include <stddef.h> /* size_t */
-
-
-/*====== Export for Windows ======*/
-/*!
-* ZSTDv06_DLL_EXPORT :
-* Enable exporting of functions when building a Windows DLL
-*/
-#if defined(_WIN32) && defined(ZSTDv06_DLL_EXPORT) && (ZSTDv06_DLL_EXPORT==1)
-# define ZSTDLIBv06_API __declspec(dllexport)
-#else
-# define ZSTDLIBv06_API
-#endif
-
-
-/* *************************************
-* Simple functions
-***************************************/
-/*! ZSTDv06_decompress() :
- `compressedSize` : is the _exact_ size of the compressed blob, otherwise decompression will fail.
- `dstCapacity` must be large enough, equal or larger than originalSize.
- @return : the number of bytes decompressed into `dst` (<= `dstCapacity`),
- or an errorCode if it fails (which can be tested using ZSTDv06_isError()) */
-ZSTDLIBv06_API size_t ZSTDv06_decompress( void* dst, size_t dstCapacity,
- const void* src, size_t compressedSize);
-
-/**
-ZSTDv06_findFrameSizeInfoLegacy() : get the source length and decompressed bound of a ZSTD frame compliant with v0.6.x format
- srcSize : The size of the 'src' buffer, at least as large as the frame pointed to by 'src'
- cSize (output parameter) : the number of bytes that would be read to decompress this frame
- or an error code if it fails (which can be tested using ZSTDv01_isError())
- dBound (output parameter) : an upper-bound for the decompressed size of the data in the frame
- or ZSTD_CONTENTSIZE_ERROR if an error occurs
-
- note : assumes `cSize` and `dBound` are _not_ NULL.
-*/
-void ZSTDv06_findFrameSizeInfoLegacy(const void *src, size_t srcSize,
- size_t* cSize, unsigned long long* dBound);
-
-/* *************************************
-* Helper functions
-***************************************/
-ZSTDLIBv06_API size_t ZSTDv06_compressBound(size_t srcSize); /*!< maximum compressed size (worst case scenario) */
-
-/* Error Management */
-ZSTDLIBv06_API unsigned ZSTDv06_isError(size_t code); /*!< tells if a `size_t` function result is an error code */
-ZSTDLIBv06_API const char* ZSTDv06_getErrorName(size_t code); /*!< provides readable string for an error code */
-
-
-/* *************************************
-* Explicit memory management
-***************************************/
-/** Decompression context */
-typedef struct ZSTDv06_DCtx_s ZSTDv06_DCtx;
-ZSTDLIBv06_API ZSTDv06_DCtx* ZSTDv06_createDCtx(void);
-ZSTDLIBv06_API size_t ZSTDv06_freeDCtx(ZSTDv06_DCtx* dctx); /*!< @return : errorCode */
-
-/** ZSTDv06_decompressDCtx() :
-* Same as ZSTDv06_decompress(), but requires an already allocated ZSTDv06_DCtx (see ZSTDv06_createDCtx()) */
-ZSTDLIBv06_API size_t ZSTDv06_decompressDCtx(ZSTDv06_DCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
-
-
-/*-***********************
-* Dictionary API
-*************************/
-/*! ZSTDv06_decompress_usingDict() :
-* Decompression using a pre-defined Dictionary content (see dictBuilder).
-* Dictionary must be identical to the one used during compression, otherwise regenerated data will be corrupted.
-* Note : dict can be NULL, in which case, it's equivalent to ZSTDv06_decompressDCtx() */
-ZSTDLIBv06_API size_t ZSTDv06_decompress_usingDict(ZSTDv06_DCtx* dctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- const void* dict,size_t dictSize);
-
-
-/*-************************
-* Advanced Streaming API
-***************************/
-struct ZSTDv06_frameParams_s { unsigned long long frameContentSize; unsigned windowLog; };
-typedef struct ZSTDv06_frameParams_s ZSTDv06_frameParams;
-
-ZSTDLIBv06_API size_t ZSTDv06_getFrameParams(ZSTDv06_frameParams* fparamsPtr, const void* src, size_t srcSize); /**< doesn't consume input */
-ZSTDLIBv06_API size_t ZSTDv06_decompressBegin_usingDict(ZSTDv06_DCtx* dctx, const void* dict, size_t dictSize);
-ZSTDLIBv06_API void ZSTDv06_copyDCtx(ZSTDv06_DCtx* dctx, const ZSTDv06_DCtx* preparedDCtx);
-
-ZSTDLIBv06_API size_t ZSTDv06_nextSrcSizeToDecompress(ZSTDv06_DCtx* dctx);
-ZSTDLIBv06_API size_t ZSTDv06_decompressContinue(ZSTDv06_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
-
-
-
-/* *************************************
-* ZBUFF API
-***************************************/
-
-typedef struct ZBUFFv06_DCtx_s ZBUFFv06_DCtx;
-ZSTDLIBv06_API ZBUFFv06_DCtx* ZBUFFv06_createDCtx(void);
-ZSTDLIBv06_API size_t ZBUFFv06_freeDCtx(ZBUFFv06_DCtx* dctx);
-
-ZSTDLIBv06_API size_t ZBUFFv06_decompressInit(ZBUFFv06_DCtx* dctx);
-ZSTDLIBv06_API size_t ZBUFFv06_decompressInitDictionary(ZBUFFv06_DCtx* dctx, const void* dict, size_t dictSize);
-
-ZSTDLIBv06_API size_t ZBUFFv06_decompressContinue(ZBUFFv06_DCtx* dctx,
- void* dst, size_t* dstCapacityPtr,
- const void* src, size_t* srcSizePtr);
-
-/*-***************************************************************************
-* Streaming decompression howto
-*
-* A ZBUFFv06_DCtx object is required to track streaming operations.
-* Use ZBUFFv06_createDCtx() and ZBUFFv06_freeDCtx() to create/release resources.
-* Use ZBUFFv06_decompressInit() to start a new decompression operation,
-* or ZBUFFv06_decompressInitDictionary() if decompression requires a dictionary.
-* Note that ZBUFFv06_DCtx objects can be re-init multiple times.
-*
-* Use ZBUFFv06_decompressContinue() repetitively to consume your input.
-* *srcSizePtr and *dstCapacityPtr can be any size.
-* The function will report how many bytes were read or written by modifying *srcSizePtr and *dstCapacityPtr.
-* Note that it may not consume the entire input, in which case it's up to the caller to present remaining input again.
-* The content of `dst` will be overwritten (up to *dstCapacityPtr) at each function call, so save its content if it matters, or change `dst`.
-* @return : a hint to preferred nb of bytes to use as input for next function call (it's only a hint, to help latency),
-* or 0 when a frame is completely decoded,
-* or an error code, which can be tested using ZBUFFv06_isError().
-*
-* Hint : recommended buffer sizes (not compulsory) : ZBUFFv06_recommendedDInSize() and ZBUFFv06_recommendedDOutSize()
-* output : ZBUFFv06_recommendedDOutSize== 128 KB block size is the internal unit, it ensures it's always possible to write a full block when decoded.
-* input : ZBUFFv06_recommendedDInSize == 128KB + 3;
-* just follow indications from ZBUFFv06_decompressContinue() to minimize latency. It should always be <= 128 KB + 3 .
-* *******************************************************************************/
-
-
-/* *************************************
-* Tool functions
-***************************************/
-ZSTDLIBv06_API unsigned ZBUFFv06_isError(size_t errorCode);
-ZSTDLIBv06_API const char* ZBUFFv06_getErrorName(size_t errorCode);
-
-/** Functions below provide recommended buffer sizes for Compression or Decompression operations.
-* These sizes are just hints, they tend to offer better latency */
-ZSTDLIBv06_API size_t ZBUFFv06_recommendedDInSize(void);
-ZSTDLIBv06_API size_t ZBUFFv06_recommendedDOutSize(void);
-
-
-/*-*************************************
-* Constants
-***************************************/
-#define ZSTDv06_MAGICNUMBER 0xFD2FB526 /* v0.6 */
-
-
-
-#if defined (__cplusplus)
-}
-#endif
-
-#endif /* ZSTDv06_BUFFERED_H */
-/**** ended inlining zstd_v06.h ****/
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 7)
-/**** start inlining zstd_v07.h ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-#ifndef ZSTDv07_H_235446
-#define ZSTDv07_H_235446
-
-#if defined (__cplusplus)
-extern "C" {
-#endif
-
-/*====== Dependency ======*/
-#include <stddef.h> /* size_t */
-
-
-/*====== Export for Windows ======*/
-/*!
-* ZSTDv07_DLL_EXPORT :
-* Enable exporting of functions when building a Windows DLL
-*/
-#if defined(_WIN32) && defined(ZSTDv07_DLL_EXPORT) && (ZSTDv07_DLL_EXPORT==1)
-# define ZSTDLIBv07_API __declspec(dllexport)
-#else
-# define ZSTDLIBv07_API
-#endif
-
-
-/* *************************************
-* Simple API
-***************************************/
-/*! ZSTDv07_getDecompressedSize() :
-* @return : decompressed size if known, 0 otherwise.
- note 1 : if `0`, follow up with ZSTDv07_getFrameParams() to know precise failure cause.
- note 2 : decompressed size could be wrong or intentionally modified !
- always ensure results fit within application's authorized limits */
-unsigned long long ZSTDv07_getDecompressedSize(const void* src, size_t srcSize);
-
-/*! ZSTDv07_decompress() :
- `compressedSize` : must be _exact_ size of compressed input, otherwise decompression will fail.
- `dstCapacity` must be equal or larger than originalSize.
- @return : the number of bytes decompressed into `dst` (<= `dstCapacity`),
- or an errorCode if it fails (which can be tested using ZSTDv07_isError()) */
-ZSTDLIBv07_API size_t ZSTDv07_decompress( void* dst, size_t dstCapacity,
- const void* src, size_t compressedSize);
-
-/**
-ZSTDv07_findFrameSizeInfoLegacy() : get the source length and decompressed bound of a ZSTD frame compliant with v0.7.x format
- srcSize : The size of the 'src' buffer, at least as large as the frame pointed to by 'src'
- cSize (output parameter) : the number of bytes that would be read to decompress this frame
- or an error code if it fails (which can be tested using ZSTDv01_isError())
- dBound (output parameter) : an upper-bound for the decompressed size of the data in the frame
- or ZSTD_CONTENTSIZE_ERROR if an error occurs
-
- note : assumes `cSize` and `dBound` are _not_ NULL.
-*/
-void ZSTDv07_findFrameSizeInfoLegacy(const void *src, size_t srcSize,
- size_t* cSize, unsigned long long* dBound);
-
-/*====== Helper functions ======*/
-ZSTDLIBv07_API unsigned ZSTDv07_isError(size_t code); /*!< tells if a `size_t` function result is an error code */
-ZSTDLIBv07_API const char* ZSTDv07_getErrorName(size_t code); /*!< provides readable string from an error code */
-
-
-/*-*************************************
-* Explicit memory management
-***************************************/
-/** Decompression context */
-typedef struct ZSTDv07_DCtx_s ZSTDv07_DCtx;
-ZSTDLIBv07_API ZSTDv07_DCtx* ZSTDv07_createDCtx(void);
-ZSTDLIBv07_API size_t ZSTDv07_freeDCtx(ZSTDv07_DCtx* dctx); /*!< @return : errorCode */
-
-/** ZSTDv07_decompressDCtx() :
-* Same as ZSTDv07_decompress(), requires an allocated ZSTDv07_DCtx (see ZSTDv07_createDCtx()) */
-ZSTDLIBv07_API size_t ZSTDv07_decompressDCtx(ZSTDv07_DCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
-
-
-/*-************************
-* Simple dictionary API
-***************************/
-/*! ZSTDv07_decompress_usingDict() :
-* Decompression using a pre-defined Dictionary content (see dictBuilder).
-* Dictionary must be identical to the one used during compression.
-* Note : This function load the dictionary, resulting in a significant startup time */
-ZSTDLIBv07_API size_t ZSTDv07_decompress_usingDict(ZSTDv07_DCtx* dctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- const void* dict,size_t dictSize);
-
-
-/*-**************************
-* Advanced Dictionary API
-****************************/
-/*! ZSTDv07_createDDict() :
-* Create a digested dictionary, ready to start decompression operation without startup delay.
-* `dict` can be released after creation */
-typedef struct ZSTDv07_DDict_s ZSTDv07_DDict;
-ZSTDLIBv07_API ZSTDv07_DDict* ZSTDv07_createDDict(const void* dict, size_t dictSize);
-ZSTDLIBv07_API size_t ZSTDv07_freeDDict(ZSTDv07_DDict* ddict);
-
-/*! ZSTDv07_decompress_usingDDict() :
-* Decompression using a pre-digested Dictionary
-* Faster startup than ZSTDv07_decompress_usingDict(), recommended when same dictionary is used multiple times. */
-ZSTDLIBv07_API size_t ZSTDv07_decompress_usingDDict(ZSTDv07_DCtx* dctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- const ZSTDv07_DDict* ddict);
-
-typedef struct {
- unsigned long long frameContentSize;
- unsigned windowSize;
- unsigned dictID;
- unsigned checksumFlag;
-} ZSTDv07_frameParams;
-
-ZSTDLIBv07_API size_t ZSTDv07_getFrameParams(ZSTDv07_frameParams* fparamsPtr, const void* src, size_t srcSize); /**< doesn't consume input */
-
-
-
-
-/* *************************************
-* Streaming functions
-***************************************/
-typedef struct ZBUFFv07_DCtx_s ZBUFFv07_DCtx;
-ZSTDLIBv07_API ZBUFFv07_DCtx* ZBUFFv07_createDCtx(void);
-ZSTDLIBv07_API size_t ZBUFFv07_freeDCtx(ZBUFFv07_DCtx* dctx);
-
-ZSTDLIBv07_API size_t ZBUFFv07_decompressInit(ZBUFFv07_DCtx* dctx);
-ZSTDLIBv07_API size_t ZBUFFv07_decompressInitDictionary(ZBUFFv07_DCtx* dctx, const void* dict, size_t dictSize);
-
-ZSTDLIBv07_API size_t ZBUFFv07_decompressContinue(ZBUFFv07_DCtx* dctx,
- void* dst, size_t* dstCapacityPtr,
- const void* src, size_t* srcSizePtr);
-
-/*-***************************************************************************
-* Streaming decompression howto
-*
-* A ZBUFFv07_DCtx object is required to track streaming operations.
-* Use ZBUFFv07_createDCtx() and ZBUFFv07_freeDCtx() to create/release resources.
-* Use ZBUFFv07_decompressInit() to start a new decompression operation,
-* or ZBUFFv07_decompressInitDictionary() if decompression requires a dictionary.
-* Note that ZBUFFv07_DCtx objects can be re-init multiple times.
-*
-* Use ZBUFFv07_decompressContinue() repetitively to consume your input.
-* *srcSizePtr and *dstCapacityPtr can be any size.
-* The function will report how many bytes were read or written by modifying *srcSizePtr and *dstCapacityPtr.
-* Note that it may not consume the entire input, in which case it's up to the caller to present remaining input again.
-* The content of `dst` will be overwritten (up to *dstCapacityPtr) at each function call, so save its content if it matters, or change `dst`.
-* @return : a hint to preferred nb of bytes to use as input for next function call (it's only a hint, to help latency),
-* or 0 when a frame is completely decoded,
-* or an error code, which can be tested using ZBUFFv07_isError().
-*
-* Hint : recommended buffer sizes (not compulsory) : ZBUFFv07_recommendedDInSize() and ZBUFFv07_recommendedDOutSize()
-* output : ZBUFFv07_recommendedDOutSize== 128 KB block size is the internal unit, it ensures it's always possible to write a full block when decoded.
-* input : ZBUFFv07_recommendedDInSize == 128KB + 3;
-* just follow indications from ZBUFFv07_decompressContinue() to minimize latency. It should always be <= 128 KB + 3 .
-* *******************************************************************************/
-
-
-/* *************************************
-* Tool functions
-***************************************/
-ZSTDLIBv07_API unsigned ZBUFFv07_isError(size_t errorCode);
-ZSTDLIBv07_API const char* ZBUFFv07_getErrorName(size_t errorCode);
-
-/** Functions below provide recommended buffer sizes for Compression or Decompression operations.
-* These sizes are just hints, they tend to offer better latency */
-ZSTDLIBv07_API size_t ZBUFFv07_recommendedDInSize(void);
-ZSTDLIBv07_API size_t ZBUFFv07_recommendedDOutSize(void);
-
-
-/*-*************************************
-* Constants
-***************************************/
-#define ZSTDv07_MAGICNUMBER 0xFD2FB527 /* v0.7 */
-
-
-#if defined (__cplusplus)
-}
-#endif
-
-#endif /* ZSTDv07_H_235446 */
-/**** ended inlining zstd_v07.h ****/
-#endif
-
-/** ZSTD_isLegacy() :
- @return : > 0 if supported by legacy decoder. 0 otherwise.
- return value is the version.
-*/
-MEM_STATIC unsigned ZSTD_isLegacy(const void* src, size_t srcSize)
-{
- U32 magicNumberLE;
- if (srcSize<4) return 0;
- magicNumberLE = MEM_readLE32(src);
- switch(magicNumberLE)
- {
-#if (ZSTD_LEGACY_SUPPORT <= 1)
- case ZSTDv01_magicNumberLE:return 1;
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 2)
- case ZSTDv02_magicNumber : return 2;
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 3)
- case ZSTDv03_magicNumber : return 3;
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 4)
- case ZSTDv04_magicNumber : return 4;
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 5)
- case ZSTDv05_MAGICNUMBER : return 5;
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 6)
- case ZSTDv06_MAGICNUMBER : return 6;
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 7)
- case ZSTDv07_MAGICNUMBER : return 7;
-#endif
- default : return 0;
- }
-}
-
-
-MEM_STATIC unsigned long long ZSTD_getDecompressedSize_legacy(const void* src, size_t srcSize)
-{
- U32 const version = ZSTD_isLegacy(src, srcSize);
- if (version < 5) return 0; /* no decompressed size in frame header, or not a legacy format */
-#if (ZSTD_LEGACY_SUPPORT <= 5)
- if (version==5) {
- ZSTDv05_parameters fParams;
- size_t const frResult = ZSTDv05_getFrameParams(&fParams, src, srcSize);
- if (frResult != 0) return 0;
- return fParams.srcSize;
- }
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 6)
- if (version==6) {
- ZSTDv06_frameParams fParams;
- size_t const frResult = ZSTDv06_getFrameParams(&fParams, src, srcSize);
- if (frResult != 0) return 0;
- return fParams.frameContentSize;
- }
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 7)
- if (version==7) {
- ZSTDv07_frameParams fParams;
- size_t const frResult = ZSTDv07_getFrameParams(&fParams, src, srcSize);
- if (frResult != 0) return 0;
- return fParams.frameContentSize;
- }
-#endif
- return 0; /* should not be possible */
-}
-
-
-MEM_STATIC size_t ZSTD_decompressLegacy(
- void* dst, size_t dstCapacity,
- const void* src, size_t compressedSize,
- const void* dict,size_t dictSize)
-{
- U32 const version = ZSTD_isLegacy(src, compressedSize);
- (void)dst; (void)dstCapacity; (void)dict; (void)dictSize; /* unused when ZSTD_LEGACY_SUPPORT >= 8 */
- switch(version)
- {
-#if (ZSTD_LEGACY_SUPPORT <= 1)
- case 1 :
- return ZSTDv01_decompress(dst, dstCapacity, src, compressedSize);
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 2)
- case 2 :
- return ZSTDv02_decompress(dst, dstCapacity, src, compressedSize);
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 3)
- case 3 :
- return ZSTDv03_decompress(dst, dstCapacity, src, compressedSize);
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 4)
- case 4 :
- return ZSTDv04_decompress(dst, dstCapacity, src, compressedSize);
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 5)
- case 5 :
- { size_t result;
- ZSTDv05_DCtx* const zd = ZSTDv05_createDCtx();
- if (zd==NULL) return ERROR(memory_allocation);
- result = ZSTDv05_decompress_usingDict(zd, dst, dstCapacity, src, compressedSize, dict, dictSize);
- ZSTDv05_freeDCtx(zd);
- return result;
- }
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 6)
- case 6 :
- { size_t result;
- ZSTDv06_DCtx* const zd = ZSTDv06_createDCtx();
- if (zd==NULL) return ERROR(memory_allocation);
- result = ZSTDv06_decompress_usingDict(zd, dst, dstCapacity, src, compressedSize, dict, dictSize);
- ZSTDv06_freeDCtx(zd);
- return result;
- }
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 7)
- case 7 :
- { size_t result;
- ZSTDv07_DCtx* const zd = ZSTDv07_createDCtx();
- if (zd==NULL) return ERROR(memory_allocation);
- result = ZSTDv07_decompress_usingDict(zd, dst, dstCapacity, src, compressedSize, dict, dictSize);
- ZSTDv07_freeDCtx(zd);
- return result;
- }
-#endif
- default :
- return ERROR(prefix_unknown);
- }
-}
-
-MEM_STATIC ZSTD_frameSizeInfo ZSTD_findFrameSizeInfoLegacy(const void *src, size_t srcSize)
-{
- ZSTD_frameSizeInfo frameSizeInfo;
- U32 const version = ZSTD_isLegacy(src, srcSize);
- switch(version)
- {
-#if (ZSTD_LEGACY_SUPPORT <= 1)
- case 1 :
- ZSTDv01_findFrameSizeInfoLegacy(src, srcSize,
- &frameSizeInfo.compressedSize,
- &frameSizeInfo.decompressedBound);
- break;
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 2)
- case 2 :
- ZSTDv02_findFrameSizeInfoLegacy(src, srcSize,
- &frameSizeInfo.compressedSize,
- &frameSizeInfo.decompressedBound);
- break;
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 3)
- case 3 :
- ZSTDv03_findFrameSizeInfoLegacy(src, srcSize,
- &frameSizeInfo.compressedSize,
- &frameSizeInfo.decompressedBound);
- break;
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 4)
- case 4 :
- ZSTDv04_findFrameSizeInfoLegacy(src, srcSize,
- &frameSizeInfo.compressedSize,
- &frameSizeInfo.decompressedBound);
- break;
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 5)
- case 5 :
- ZSTDv05_findFrameSizeInfoLegacy(src, srcSize,
- &frameSizeInfo.compressedSize,
- &frameSizeInfo.decompressedBound);
- break;
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 6)
- case 6 :
- ZSTDv06_findFrameSizeInfoLegacy(src, srcSize,
- &frameSizeInfo.compressedSize,
- &frameSizeInfo.decompressedBound);
- break;
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 7)
- case 7 :
- ZSTDv07_findFrameSizeInfoLegacy(src, srcSize,
- &frameSizeInfo.compressedSize,
- &frameSizeInfo.decompressedBound);
- break;
-#endif
- default :
- frameSizeInfo.compressedSize = ERROR(prefix_unknown);
- frameSizeInfo.decompressedBound = ZSTD_CONTENTSIZE_ERROR;
- break;
- }
- if (!ZSTD_isError(frameSizeInfo.compressedSize) && frameSizeInfo.compressedSize > srcSize) {
- frameSizeInfo.compressedSize = ERROR(srcSize_wrong);
- frameSizeInfo.decompressedBound = ZSTD_CONTENTSIZE_ERROR;
- }
- return frameSizeInfo;
-}
-
-MEM_STATIC size_t ZSTD_findFrameCompressedSizeLegacy(const void *src, size_t srcSize)
-{
- ZSTD_frameSizeInfo frameSizeInfo = ZSTD_findFrameSizeInfoLegacy(src, srcSize);
- return frameSizeInfo.compressedSize;
-}
-
-MEM_STATIC size_t ZSTD_freeLegacyStreamContext(void* legacyContext, U32 version)
-{
- switch(version)
- {
- default :
- case 1 :
- case 2 :
- case 3 :
- (void)legacyContext;
- return ERROR(version_unsupported);
-#if (ZSTD_LEGACY_SUPPORT <= 4)
- case 4 : return ZBUFFv04_freeDCtx((ZBUFFv04_DCtx*)legacyContext);
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 5)
- case 5 : return ZBUFFv05_freeDCtx((ZBUFFv05_DCtx*)legacyContext);
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 6)
- case 6 : return ZBUFFv06_freeDCtx((ZBUFFv06_DCtx*)legacyContext);
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 7)
- case 7 : return ZBUFFv07_freeDCtx((ZBUFFv07_DCtx*)legacyContext);
-#endif
- }
-}
-
-
-MEM_STATIC size_t ZSTD_initLegacyStream(void** legacyContext, U32 prevVersion, U32 newVersion,
- const void* dict, size_t dictSize)
-{
- DEBUGLOG(5, "ZSTD_initLegacyStream for v0.%u", newVersion);
- if (prevVersion != newVersion) ZSTD_freeLegacyStreamContext(*legacyContext, prevVersion);
- switch(newVersion)
- {
- default :
- case 1 :
- case 2 :
- case 3 :
- (void)dict; (void)dictSize;
- return 0;
-#if (ZSTD_LEGACY_SUPPORT <= 4)
- case 4 :
- {
- ZBUFFv04_DCtx* dctx = (prevVersion != newVersion) ? ZBUFFv04_createDCtx() : (ZBUFFv04_DCtx*)*legacyContext;
- if (dctx==NULL) return ERROR(memory_allocation);
- ZBUFFv04_decompressInit(dctx);
- ZBUFFv04_decompressWithDictionary(dctx, dict, dictSize);
- *legacyContext = dctx;
- return 0;
- }
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 5)
- case 5 :
- {
- ZBUFFv05_DCtx* dctx = (prevVersion != newVersion) ? ZBUFFv05_createDCtx() : (ZBUFFv05_DCtx*)*legacyContext;
- if (dctx==NULL) return ERROR(memory_allocation);
- ZBUFFv05_decompressInitDictionary(dctx, dict, dictSize);
- *legacyContext = dctx;
- return 0;
- }
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 6)
- case 6 :
- {
- ZBUFFv06_DCtx* dctx = (prevVersion != newVersion) ? ZBUFFv06_createDCtx() : (ZBUFFv06_DCtx*)*legacyContext;
- if (dctx==NULL) return ERROR(memory_allocation);
- ZBUFFv06_decompressInitDictionary(dctx, dict, dictSize);
- *legacyContext = dctx;
- return 0;
- }
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 7)
- case 7 :
- {
- ZBUFFv07_DCtx* dctx = (prevVersion != newVersion) ? ZBUFFv07_createDCtx() : (ZBUFFv07_DCtx*)*legacyContext;
- if (dctx==NULL) return ERROR(memory_allocation);
- ZBUFFv07_decompressInitDictionary(dctx, dict, dictSize);
- *legacyContext = dctx;
- return 0;
- }
-#endif
- }
-}
-
-
-
-MEM_STATIC size_t ZSTD_decompressLegacyStream(void* legacyContext, U32 version,
- ZSTD_outBuffer* output, ZSTD_inBuffer* input)
-{
- DEBUGLOG(5, "ZSTD_decompressLegacyStream for v0.%u", version);
- switch(version)
- {
- default :
- case 1 :
- case 2 :
- case 3 :
- (void)legacyContext; (void)output; (void)input;
- return ERROR(version_unsupported);
-#if (ZSTD_LEGACY_SUPPORT <= 4)
- case 4 :
- {
- ZBUFFv04_DCtx* dctx = (ZBUFFv04_DCtx*) legacyContext;
- const void* src = (const char*)input->src + input->pos;
- size_t readSize = input->size - input->pos;
- void* dst = (char*)output->dst + output->pos;
- size_t decodedSize = output->size - output->pos;
- size_t const hintSize = ZBUFFv04_decompressContinue(dctx, dst, &decodedSize, src, &readSize);
- output->pos += decodedSize;
- input->pos += readSize;
- return hintSize;
- }
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 5)
- case 5 :
- {
- ZBUFFv05_DCtx* dctx = (ZBUFFv05_DCtx*) legacyContext;
- const void* src = (const char*)input->src + input->pos;
- size_t readSize = input->size - input->pos;
- void* dst = (char*)output->dst + output->pos;
- size_t decodedSize = output->size - output->pos;
- size_t const hintSize = ZBUFFv05_decompressContinue(dctx, dst, &decodedSize, src, &readSize);
- output->pos += decodedSize;
- input->pos += readSize;
- return hintSize;
- }
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 6)
- case 6 :
- {
- ZBUFFv06_DCtx* dctx = (ZBUFFv06_DCtx*) legacyContext;
- const void* src = (const char*)input->src + input->pos;
- size_t readSize = input->size - input->pos;
- void* dst = (char*)output->dst + output->pos;
- size_t decodedSize = output->size - output->pos;
- size_t const hintSize = ZBUFFv06_decompressContinue(dctx, dst, &decodedSize, src, &readSize);
- output->pos += decodedSize;
- input->pos += readSize;
- return hintSize;
- }
-#endif
-#if (ZSTD_LEGACY_SUPPORT <= 7)
- case 7 :
- {
- ZBUFFv07_DCtx* dctx = (ZBUFFv07_DCtx*) legacyContext;
- const void* src = (const char*)input->src + input->pos;
- size_t readSize = input->size - input->pos;
- void* dst = (char*)output->dst + output->pos;
- size_t decodedSize = output->size - output->pos;
- size_t const hintSize = ZBUFFv07_decompressContinue(dctx, dst, &decodedSize, src, &readSize);
- output->pos += decodedSize;
- input->pos += readSize;
- return hintSize;
- }
-#endif
- }
-}
-
-
-#if defined (__cplusplus)
-}
-#endif
-
-#endif /* ZSTD_LEGACY_H */
-/**** ended inlining ../legacy/zstd_legacy.h ****/
-#endif
-
-
-
-/*-*******************************************************
-* Types
-*********************************************************/
-struct ZSTD_DDict_s {
- void* dictBuffer;
- const void* dictContent;
- size_t dictSize;
- ZSTD_entropyDTables_t entropy;
- U32 dictID;
- U32 entropyPresent;
- ZSTD_customMem cMem;
-}; /* typedef'd to ZSTD_DDict within "zstd.h" */
-
-const void* ZSTD_DDict_dictContent(const ZSTD_DDict* ddict)
-{
- assert(ddict != NULL);
- return ddict->dictContent;
-}
-
-size_t ZSTD_DDict_dictSize(const ZSTD_DDict* ddict)
-{
- assert(ddict != NULL);
- return ddict->dictSize;
-}
-
-void ZSTD_copyDDictParameters(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)
-{
- DEBUGLOG(4, "ZSTD_copyDDictParameters");
- assert(dctx != NULL);
- assert(ddict != NULL);
- dctx->dictID = ddict->dictID;
- dctx->prefixStart = ddict->dictContent;
- dctx->virtualStart = ddict->dictContent;
- dctx->dictEnd = (const BYTE*)ddict->dictContent + ddict->dictSize;
- dctx->previousDstEnd = dctx->dictEnd;
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
- dctx->dictContentBeginForFuzzing = dctx->prefixStart;
- dctx->dictContentEndForFuzzing = dctx->previousDstEnd;
-#endif
- if (ddict->entropyPresent) {
- dctx->litEntropy = 1;
- dctx->fseEntropy = 1;
- dctx->LLTptr = ddict->entropy.LLTable;
- dctx->MLTptr = ddict->entropy.MLTable;
- dctx->OFTptr = ddict->entropy.OFTable;
- dctx->HUFptr = ddict->entropy.hufTable;
- dctx->entropy.rep[0] = ddict->entropy.rep[0];
- dctx->entropy.rep[1] = ddict->entropy.rep[1];
- dctx->entropy.rep[2] = ddict->entropy.rep[2];
- } else {
- dctx->litEntropy = 0;
- dctx->fseEntropy = 0;
- }
-}
-
-
-static size_t
-ZSTD_loadEntropy_intoDDict(ZSTD_DDict* ddict,
- ZSTD_dictContentType_e dictContentType)
-{
- ddict->dictID = 0;
- ddict->entropyPresent = 0;
- if (dictContentType == ZSTD_dct_rawContent) return 0;
-
- if (ddict->dictSize < 8) {
- if (dictContentType == ZSTD_dct_fullDict)
- return ERROR(dictionary_corrupted); /* only accept specified dictionaries */
- return 0; /* pure content mode */
- }
- { U32 const magic = MEM_readLE32(ddict->dictContent);
- if (magic != ZSTD_MAGIC_DICTIONARY) {
- if (dictContentType == ZSTD_dct_fullDict)
- return ERROR(dictionary_corrupted); /* only accept specified dictionaries */
- return 0; /* pure content mode */
- }
- }
- ddict->dictID = MEM_readLE32((const char*)ddict->dictContent + ZSTD_FRAMEIDSIZE);
-
- /* load entropy tables */
- RETURN_ERROR_IF(ZSTD_isError(ZSTD_loadDEntropy(
- &ddict->entropy, ddict->dictContent, ddict->dictSize)),
- dictionary_corrupted, "");
- ddict->entropyPresent = 1;
- return 0;
-}
-
-
-static size_t ZSTD_initDDict_internal(ZSTD_DDict* ddict,
- const void* dict, size_t dictSize,
- ZSTD_dictLoadMethod_e dictLoadMethod,
- ZSTD_dictContentType_e dictContentType)
-{
- if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dict) || (!dictSize)) {
- ddict->dictBuffer = NULL;
- ddict->dictContent = dict;
- if (!dict) dictSize = 0;
- } else {
- void* const internalBuffer = ZSTD_malloc(dictSize, ddict->cMem);
- ddict->dictBuffer = internalBuffer;
- ddict->dictContent = internalBuffer;
- if (!internalBuffer) return ERROR(memory_allocation);
- memcpy(internalBuffer, dict, dictSize);
- }
- ddict->dictSize = dictSize;
- ddict->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */
-
- /* parse dictionary content */
- FORWARD_IF_ERROR( ZSTD_loadEntropy_intoDDict(ddict, dictContentType) , "");
-
- return 0;
-}
-
-ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize,
- ZSTD_dictLoadMethod_e dictLoadMethod,
- ZSTD_dictContentType_e dictContentType,
- ZSTD_customMem customMem)
-{
- if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
-
- { ZSTD_DDict* const ddict = (ZSTD_DDict*) ZSTD_malloc(sizeof(ZSTD_DDict), customMem);
- if (ddict == NULL) return NULL;
- ddict->cMem = customMem;
- { size_t const initResult = ZSTD_initDDict_internal(ddict,
- dict, dictSize,
- dictLoadMethod, dictContentType);
- if (ZSTD_isError(initResult)) {
- ZSTD_freeDDict(ddict);
- return NULL;
- } }
- return ddict;
- }
-}
-
-/*! ZSTD_createDDict() :
-* Create a digested dictionary, to start decompression without startup delay.
-* `dict` content is copied inside DDict.
-* Consequently, `dict` can be released after `ZSTD_DDict` creation */
-ZSTD_DDict* ZSTD_createDDict(const void* dict, size_t dictSize)
-{
- ZSTD_customMem const allocator = { NULL, NULL, NULL };
- return ZSTD_createDDict_advanced(dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto, allocator);
-}
-
-/*! ZSTD_createDDict_byReference() :
- * Create a digested dictionary, to start decompression without startup delay.
- * Dictionary content is simply referenced, it will be accessed during decompression.
- * Warning : dictBuffer must outlive DDict (DDict must be freed before dictBuffer) */
-ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize)
-{
- ZSTD_customMem const allocator = { NULL, NULL, NULL };
- return ZSTD_createDDict_advanced(dictBuffer, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto, allocator);
-}
-
-
-const ZSTD_DDict* ZSTD_initStaticDDict(
- void* sBuffer, size_t sBufferSize,
- const void* dict, size_t dictSize,
- ZSTD_dictLoadMethod_e dictLoadMethod,
- ZSTD_dictContentType_e dictContentType)
-{
- size_t const neededSpace = sizeof(ZSTD_DDict)
- + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize);
- ZSTD_DDict* const ddict = (ZSTD_DDict*)sBuffer;
- assert(sBuffer != NULL);
- assert(dict != NULL);
- if ((size_t)sBuffer & 7) return NULL; /* 8-aligned */
- if (sBufferSize < neededSpace) return NULL;
- if (dictLoadMethod == ZSTD_dlm_byCopy) {
- memcpy(ddict+1, dict, dictSize); /* local copy */
- dict = ddict+1;
- }
- if (ZSTD_isError( ZSTD_initDDict_internal(ddict,
- dict, dictSize,
- ZSTD_dlm_byRef, dictContentType) ))
- return NULL;
- return ddict;
-}
-
-
-size_t ZSTD_freeDDict(ZSTD_DDict* ddict)
-{
- if (ddict==NULL) return 0; /* support free on NULL */
- { ZSTD_customMem const cMem = ddict->cMem;
- ZSTD_free(ddict->dictBuffer, cMem);
- ZSTD_free(ddict, cMem);
- return 0;
- }
-}
-
-/*! ZSTD_estimateDDictSize() :
- * Estimate amount of memory that will be needed to create a dictionary for decompression.
- * Note : dictionary created by reference using ZSTD_dlm_byRef are smaller */
-size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod)
-{
- return sizeof(ZSTD_DDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize);
-}
-
-size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict)
-{
- if (ddict==NULL) return 0; /* support sizeof on NULL */
- return sizeof(*ddict) + (ddict->dictBuffer ? ddict->dictSize : 0) ;
-}
-
-/*! ZSTD_getDictID_fromDDict() :
- * Provides the dictID of the dictionary loaded into `ddict`.
- * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty.
- * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */
-unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict)
-{
- if (ddict==NULL) return 0;
- return ZSTD_getDictID_fromDict(ddict->dictContent, ddict->dictSize);
-}
-/**** ended inlining decompress/zstd_ddict.c ****/
-/**** start inlining decompress/zstd_decompress.c ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-
-/* ***************************************************************
-* Tuning parameters
-*****************************************************************/
-/*!
- * HEAPMODE :
- * Select how default decompression function ZSTD_decompress() allocates its context,
- * on stack (0), or into heap (1, default; requires malloc()).
- * Note that functions with explicit context such as ZSTD_decompressDCtx() are unaffected.
- */
-#ifndef ZSTD_HEAPMODE
-# define ZSTD_HEAPMODE 1
-#endif
-
-/*!
-* LEGACY_SUPPORT :
-* if set to 1+, ZSTD_decompress() can decode older formats (v0.1+)
-*/
-#ifndef ZSTD_LEGACY_SUPPORT
-# define ZSTD_LEGACY_SUPPORT 0
-#endif
-
-/*!
- * MAXWINDOWSIZE_DEFAULT :
- * maximum window size accepted by DStream __by default__.
- * Frames requiring more memory will be rejected.
- * It's possible to set a different limit using ZSTD_DCtx_setMaxWindowSize().
- */
-#ifndef ZSTD_MAXWINDOWSIZE_DEFAULT
-# define ZSTD_MAXWINDOWSIZE_DEFAULT (((U32)1 << ZSTD_WINDOWLOG_LIMIT_DEFAULT) + 1)
-#endif
-
-/*!
- * NO_FORWARD_PROGRESS_MAX :
- * maximum allowed nb of calls to ZSTD_decompressStream()
- * without any forward progress
- * (defined as: no byte read from input, and no byte flushed to output)
- * before triggering an error.
- */
-#ifndef ZSTD_NO_FORWARD_PROGRESS_MAX
-# define ZSTD_NO_FORWARD_PROGRESS_MAX 16
-#endif
-
-
-/*-*******************************************************
-* Dependencies
-*********************************************************/
-#include <string.h> /* memcpy, memmove, memset */
-/**** skipping file: ../common/cpu.h ****/
-/**** skipping file: ../common/mem.h ****/
-#define FSE_STATIC_LINKING_ONLY
-/**** skipping file: ../common/fse.h ****/
-#define HUF_STATIC_LINKING_ONLY
-/**** skipping file: ../common/huf.h ****/
-/**** skipping file: ../common/zstd_internal.h ****/
-/**** skipping file: zstd_decompress_internal.h ****/
-/**** skipping file: zstd_ddict.h ****/
-/**** start inlining zstd_decompress_block.h ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-
-#ifndef ZSTD_DEC_BLOCK_H
-#define ZSTD_DEC_BLOCK_H
-
-/*-*******************************************************
- * Dependencies
- *********************************************************/
-#include <stddef.h> /* size_t */
-/**** skipping file: ../zstd.h ****/
-/**** skipping file: ../common/zstd_internal.h ****/
-/**** skipping file: zstd_decompress_internal.h ****/
-
-
-/* === Prototypes === */
-
-/* note: prototypes already published within `zstd.h` :
- * ZSTD_decompressBlock()
- */
-
-/* note: prototypes already published within `zstd_internal.h` :
- * ZSTD_getcBlockSize()
- * ZSTD_decodeSeqHeaders()
- */
-
-
-/* ZSTD_decompressBlock_internal() :
- * decompress block, starting at `src`,
- * into destination buffer `dst`.
- * @return : decompressed block size,
- * or an error code (which can be tested using ZSTD_isError())
- */
-size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize, const int frame);
-
-/* ZSTD_buildFSETable() :
- * generate FSE decoding table for one symbol (ll, ml or off)
- * this function must be called with valid parameters only
- * (dt is large enough, normalizedCounter distribution total is a power of 2, max is within range, etc.)
- * in which case it cannot fail.
- * Internal use only.
- */
-void ZSTD_buildFSETable(ZSTD_seqSymbol* dt,
- const short* normalizedCounter, unsigned maxSymbolValue,
- const U32* baseValue, const U32* nbAdditionalBits,
- unsigned tableLog);
-
-
-#endif /* ZSTD_DEC_BLOCK_H */
-/**** ended inlining zstd_decompress_block.h ****/
-
-#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
-/**** skipping file: ../legacy/zstd_legacy.h ****/
-#endif
-
-
-/*-*************************************************************
-* Context management
-***************************************************************/
-size_t ZSTD_sizeof_DCtx (const ZSTD_DCtx* dctx)
-{
- if (dctx==NULL) return 0; /* support sizeof NULL */
- return sizeof(*dctx)
- + ZSTD_sizeof_DDict(dctx->ddictLocal)
- + dctx->inBuffSize + dctx->outBuffSize;
-}
-
-size_t ZSTD_estimateDCtxSize(void) { return sizeof(ZSTD_DCtx); }
-
-
-static size_t ZSTD_startingInputLength(ZSTD_format_e format)
-{
- size_t const startingInputLength = ZSTD_FRAMEHEADERSIZE_PREFIX(format);
- /* only supports formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless */
- assert( (format == ZSTD_f_zstd1) || (format == ZSTD_f_zstd1_magicless) );
- return startingInputLength;
-}
-
-static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx)
-{
- dctx->format = ZSTD_f_zstd1; /* ZSTD_decompressBegin() invokes ZSTD_startingInputLength() with argument dctx->format */
- dctx->staticSize = 0;
- dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT;
- dctx->ddict = NULL;
- dctx->ddictLocal = NULL;
- dctx->dictEnd = NULL;
- dctx->ddictIsCold = 0;
- dctx->dictUses = ZSTD_dont_use;
- dctx->inBuff = NULL;
- dctx->inBuffSize = 0;
- dctx->outBuffSize = 0;
- dctx->streamStage = zdss_init;
- dctx->legacyContext = NULL;
- dctx->previousLegacyVersion = 0;
- dctx->noForwardProgress = 0;
- dctx->oversizedDuration = 0;
- dctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
- dctx->outBufferMode = ZSTD_obm_buffered;
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
- dctx->dictContentEndForFuzzing = NULL;
-#endif
-}
-
-ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize)
-{
- ZSTD_DCtx* const dctx = (ZSTD_DCtx*) workspace;
-
- if ((size_t)workspace & 7) return NULL; /* 8-aligned */
- if (workspaceSize < sizeof(ZSTD_DCtx)) return NULL; /* minimum size */
-
- ZSTD_initDCtx_internal(dctx);
- dctx->staticSize = workspaceSize;
- dctx->inBuff = (char*)(dctx+1);
- return dctx;
-}
-
-ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem)
-{
- if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
-
- { ZSTD_DCtx* const dctx = (ZSTD_DCtx*)ZSTD_malloc(sizeof(*dctx), customMem);
- if (!dctx) return NULL;
- dctx->customMem = customMem;
- ZSTD_initDCtx_internal(dctx);
- return dctx;
- }
-}
-
-ZSTD_DCtx* ZSTD_createDCtx(void)
-{
- DEBUGLOG(3, "ZSTD_createDCtx");
- return ZSTD_createDCtx_advanced(ZSTD_defaultCMem);
-}
-
-static void ZSTD_clearDict(ZSTD_DCtx* dctx)
-{
- ZSTD_freeDDict(dctx->ddictLocal);
- dctx->ddictLocal = NULL;
- dctx->ddict = NULL;
- dctx->dictUses = ZSTD_dont_use;
-}
-
-size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx)
-{
- if (dctx==NULL) return 0; /* support free on NULL */
- RETURN_ERROR_IF(dctx->staticSize, memory_allocation, "not compatible with static DCtx");
- { ZSTD_customMem const cMem = dctx->customMem;
- ZSTD_clearDict(dctx);
- ZSTD_free(dctx->inBuff, cMem);
- dctx->inBuff = NULL;
-#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
- if (dctx->legacyContext)
- ZSTD_freeLegacyStreamContext(dctx->legacyContext, dctx->previousLegacyVersion);
-#endif
- ZSTD_free(dctx, cMem);
- return 0;
- }
-}
-
-/* no longer useful */
-void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx)
-{
- size_t const toCopy = (size_t)((char*)(&dstDCtx->inBuff) - (char*)dstDCtx);
- memcpy(dstDCtx, srcDCtx, toCopy); /* no need to copy workspace */
-}
-
-
-/*-*************************************************************
- * Frame header decoding
- ***************************************************************/
-
-/*! ZSTD_isFrame() :
- * Tells if the content of `buffer` starts with a valid Frame Identifier.
- * Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0.
- * Note 2 : Legacy Frame Identifiers are considered valid only if Legacy Support is enabled.
- * Note 3 : Skippable Frame Identifiers are considered valid. */
-unsigned ZSTD_isFrame(const void* buffer, size_t size)
-{
- if (size < ZSTD_FRAMEIDSIZE) return 0;
- { U32 const magic = MEM_readLE32(buffer);
- if (magic == ZSTD_MAGICNUMBER) return 1;
- if ((magic & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) return 1;
- }
-#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
- if (ZSTD_isLegacy(buffer, size)) return 1;
-#endif
- return 0;
-}
-
-/** ZSTD_frameHeaderSize_internal() :
- * srcSize must be large enough to reach header size fields.
- * note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless.
- * @return : size of the Frame Header
- * or an error code, which can be tested with ZSTD_isError() */
-static size_t ZSTD_frameHeaderSize_internal(const void* src, size_t srcSize, ZSTD_format_e format)
-{
- size_t const minInputSize = ZSTD_startingInputLength(format);
- RETURN_ERROR_IF(srcSize < minInputSize, srcSize_wrong, "");
-
- { BYTE const fhd = ((const BYTE*)src)[minInputSize-1];
- U32 const dictID= fhd & 3;
- U32 const singleSegment = (fhd >> 5) & 1;
- U32 const fcsId = fhd >> 6;
- return minInputSize + !singleSegment
- + ZSTD_did_fieldSize[dictID] + ZSTD_fcs_fieldSize[fcsId]
- + (singleSegment && !fcsId);
- }
-}
-
-/** ZSTD_frameHeaderSize() :
- * srcSize must be >= ZSTD_frameHeaderSize_prefix.
- * @return : size of the Frame Header,
- * or an error code (if srcSize is too small) */
-size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize)
-{
- return ZSTD_frameHeaderSize_internal(src, srcSize, ZSTD_f_zstd1);
-}
-
-
-/** ZSTD_getFrameHeader_advanced() :
- * decode Frame Header, or require larger `srcSize`.
- * note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless
- * @return : 0, `zfhPtr` is correctly filled,
- * >0, `srcSize` is too small, value is wanted `srcSize` amount,
- * or an error code, which can be tested using ZSTD_isError() */
-size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format)
-{
- const BYTE* ip = (const BYTE*)src;
- size_t const minInputSize = ZSTD_startingInputLength(format);
-
- memset(zfhPtr, 0, sizeof(*zfhPtr)); /* not strictly necessary, but static analyzer do not understand that zfhPtr is only going to be read only if return value is zero, since they are 2 different signals */
- if (srcSize < minInputSize) return minInputSize;
- RETURN_ERROR_IF(src==NULL, GENERIC, "invalid parameter");
-
- if ( (format != ZSTD_f_zstd1_magicless)
- && (MEM_readLE32(src) != ZSTD_MAGICNUMBER) ) {
- if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
- /* skippable frame */
- if (srcSize < ZSTD_SKIPPABLEHEADERSIZE)
- return ZSTD_SKIPPABLEHEADERSIZE; /* magic number + frame length */
- memset(zfhPtr, 0, sizeof(*zfhPtr));
- zfhPtr->frameContentSize = MEM_readLE32((const char *)src + ZSTD_FRAMEIDSIZE);
- zfhPtr->frameType = ZSTD_skippableFrame;
- return 0;
- }
- RETURN_ERROR(prefix_unknown, "");
- }
-
- /* ensure there is enough `srcSize` to fully read/decode frame header */
- { size_t const fhsize = ZSTD_frameHeaderSize_internal(src, srcSize, format);
- if (srcSize < fhsize) return fhsize;
- zfhPtr->headerSize = (U32)fhsize;
- }
-
- { BYTE const fhdByte = ip[minInputSize-1];
- size_t pos = minInputSize;
- U32 const dictIDSizeCode = fhdByte&3;
- U32 const checksumFlag = (fhdByte>>2)&1;
- U32 const singleSegment = (fhdByte>>5)&1;
- U32 const fcsID = fhdByte>>6;
- U64 windowSize = 0;
- U32 dictID = 0;
- U64 frameContentSize = ZSTD_CONTENTSIZE_UNKNOWN;
- RETURN_ERROR_IF((fhdByte & 0x08) != 0, frameParameter_unsupported,
- "reserved bits, must be zero");
-
- if (!singleSegment) {
- BYTE const wlByte = ip[pos++];
- U32 const windowLog = (wlByte >> 3) + ZSTD_WINDOWLOG_ABSOLUTEMIN;
- RETURN_ERROR_IF(windowLog > ZSTD_WINDOWLOG_MAX, frameParameter_windowTooLarge, "");
- windowSize = (1ULL << windowLog);
- windowSize += (windowSize >> 3) * (wlByte&7);
- }
- switch(dictIDSizeCode)
- {
- default: assert(0); /* impossible */
- case 0 : break;
- case 1 : dictID = ip[pos]; pos++; break;
- case 2 : dictID = MEM_readLE16(ip+pos); pos+=2; break;
- case 3 : dictID = MEM_readLE32(ip+pos); pos+=4; break;
- }
- switch(fcsID)
- {
- default: assert(0); /* impossible */
- case 0 : if (singleSegment) frameContentSize = ip[pos]; break;
- case 1 : frameContentSize = MEM_readLE16(ip+pos)+256; break;
- case 2 : frameContentSize = MEM_readLE32(ip+pos); break;
- case 3 : frameContentSize = MEM_readLE64(ip+pos); break;
- }
- if (singleSegment) windowSize = frameContentSize;
-
- zfhPtr->frameType = ZSTD_frame;
- zfhPtr->frameContentSize = frameContentSize;
- zfhPtr->windowSize = windowSize;
- zfhPtr->blockSizeMax = (unsigned) MIN(windowSize, ZSTD_BLOCKSIZE_MAX);
- zfhPtr->dictID = dictID;
- zfhPtr->checksumFlag = checksumFlag;
- }
- return 0;
-}
-
-/** ZSTD_getFrameHeader() :
- * decode Frame Header, or require larger `srcSize`.
- * note : this function does not consume input, it only reads it.
- * @return : 0, `zfhPtr` is correctly filled,
- * >0, `srcSize` is too small, value is wanted `srcSize` amount,
- * or an error code, which can be tested using ZSTD_isError() */
-size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize)
-{
- return ZSTD_getFrameHeader_advanced(zfhPtr, src, srcSize, ZSTD_f_zstd1);
-}
-
-
-/** ZSTD_getFrameContentSize() :
- * compatible with legacy mode
- * @return : decompressed size of the single frame pointed to be `src` if known, otherwise
- * - ZSTD_CONTENTSIZE_UNKNOWN if the size cannot be determined
- * - ZSTD_CONTENTSIZE_ERROR if an error occurred (e.g. invalid magic number, srcSize too small) */
-unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize)
-{
-#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
- if (ZSTD_isLegacy(src, srcSize)) {
- unsigned long long const ret = ZSTD_getDecompressedSize_legacy(src, srcSize);
- return ret == 0 ? ZSTD_CONTENTSIZE_UNKNOWN : ret;
- }
-#endif
- { ZSTD_frameHeader zfh;
- if (ZSTD_getFrameHeader(&zfh, src, srcSize) != 0)
- return ZSTD_CONTENTSIZE_ERROR;
- if (zfh.frameType == ZSTD_skippableFrame) {
- return 0;
- } else {
- return zfh.frameContentSize;
- } }
-}
-
-static size_t readSkippableFrameSize(void const* src, size_t srcSize)
-{
- size_t const skippableHeaderSize = ZSTD_SKIPPABLEHEADERSIZE;
- U32 sizeU32;
-
- RETURN_ERROR_IF(srcSize < ZSTD_SKIPPABLEHEADERSIZE, srcSize_wrong, "");
-
- sizeU32 = MEM_readLE32((BYTE const*)src + ZSTD_FRAMEIDSIZE);
- RETURN_ERROR_IF((U32)(sizeU32 + ZSTD_SKIPPABLEHEADERSIZE) < sizeU32,
- frameParameter_unsupported, "");
- {
- size_t const skippableSize = skippableHeaderSize + sizeU32;
- RETURN_ERROR_IF(skippableSize > srcSize, srcSize_wrong, "");
- return skippableSize;
- }
-}
-
-/** ZSTD_findDecompressedSize() :
- * compatible with legacy mode
- * `srcSize` must be the exact length of some number of ZSTD compressed and/or
- * skippable frames
- * @return : decompressed size of the frames contained */
-unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
-{
- unsigned long long totalDstSize = 0;
-
- while (srcSize >= ZSTD_startingInputLength(ZSTD_f_zstd1)) {
- U32 const magicNumber = MEM_readLE32(src);
-
- if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
- size_t const skippableSize = readSkippableFrameSize(src, srcSize);
- if (ZSTD_isError(skippableSize)) {
- return ZSTD_CONTENTSIZE_ERROR;
- }
- assert(skippableSize <= srcSize);
-
- src = (const BYTE *)src + skippableSize;
- srcSize -= skippableSize;
- continue;
- }
-
- { unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize);
- if (ret >= ZSTD_CONTENTSIZE_ERROR) return ret;
-
- /* check for overflow */
- if (totalDstSize + ret < totalDstSize) return ZSTD_CONTENTSIZE_ERROR;
- totalDstSize += ret;
- }
- { size_t const frameSrcSize = ZSTD_findFrameCompressedSize(src, srcSize);
- if (ZSTD_isError(frameSrcSize)) {
- return ZSTD_CONTENTSIZE_ERROR;
- }
-
- src = (const BYTE *)src + frameSrcSize;
- srcSize -= frameSrcSize;
- }
- } /* while (srcSize >= ZSTD_frameHeaderSize_prefix) */
-
- if (srcSize) return ZSTD_CONTENTSIZE_ERROR;
-
- return totalDstSize;
-}
-
-/** ZSTD_getDecompressedSize() :
- * compatible with legacy mode
- * @return : decompressed size if known, 0 otherwise
- note : 0 can mean any of the following :
- - frame content is empty
- - decompressed size field is not present in frame header
- - frame header unknown / not supported
- - frame header not complete (`srcSize` too small) */
-unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize)
-{
- unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize);
- ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_ERROR < ZSTD_CONTENTSIZE_UNKNOWN);
- return (ret >= ZSTD_CONTENTSIZE_ERROR) ? 0 : ret;
-}
-
-
-/** ZSTD_decodeFrameHeader() :
- * `headerSize` must be the size provided by ZSTD_frameHeaderSize().
- * @return : 0 if success, or an error code, which can be tested using ZSTD_isError() */
-static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t headerSize)
-{
- size_t const result = ZSTD_getFrameHeader_advanced(&(dctx->fParams), src, headerSize, dctx->format);
- if (ZSTD_isError(result)) return result; /* invalid header */
- RETURN_ERROR_IF(result>0, srcSize_wrong, "headerSize too small");
-#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
- /* Skip the dictID check in fuzzing mode, because it makes the search
- * harder.
- */
- RETURN_ERROR_IF(dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID),
- dictionary_wrong, "");
-#endif
- if (dctx->fParams.checksumFlag) XXH64_reset(&dctx->xxhState, 0);
- return 0;
-}
-
-static ZSTD_frameSizeInfo ZSTD_errorFrameSizeInfo(size_t ret)
-{
- ZSTD_frameSizeInfo frameSizeInfo;
- frameSizeInfo.compressedSize = ret;
- frameSizeInfo.decompressedBound = ZSTD_CONTENTSIZE_ERROR;
- return frameSizeInfo;
-}
-
-static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize)
-{
- ZSTD_frameSizeInfo frameSizeInfo;
- memset(&frameSizeInfo, 0, sizeof(ZSTD_frameSizeInfo));
-
-#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
- if (ZSTD_isLegacy(src, srcSize))
- return ZSTD_findFrameSizeInfoLegacy(src, srcSize);
-#endif
-
- if ((srcSize >= ZSTD_SKIPPABLEHEADERSIZE)
- && (MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
- frameSizeInfo.compressedSize = readSkippableFrameSize(src, srcSize);
- assert(ZSTD_isError(frameSizeInfo.compressedSize) ||
- frameSizeInfo.compressedSize <= srcSize);
- return frameSizeInfo;
- } else {
- const BYTE* ip = (const BYTE*)src;
- const BYTE* const ipstart = ip;
- size_t remainingSize = srcSize;
- size_t nbBlocks = 0;
- ZSTD_frameHeader zfh;
-
- /* Extract Frame Header */
- { size_t const ret = ZSTD_getFrameHeader(&zfh, src, srcSize);
- if (ZSTD_isError(ret))
- return ZSTD_errorFrameSizeInfo(ret);
- if (ret > 0)
- return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong));
- }
-
- ip += zfh.headerSize;
- remainingSize -= zfh.headerSize;
-
- /* Iterate over each block */
- while (1) {
- blockProperties_t blockProperties;
- size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSize, &blockProperties);
- if (ZSTD_isError(cBlockSize))
- return ZSTD_errorFrameSizeInfo(cBlockSize);
-
- if (ZSTD_blockHeaderSize + cBlockSize > remainingSize)
- return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong));
-
- ip += ZSTD_blockHeaderSize + cBlockSize;
- remainingSize -= ZSTD_blockHeaderSize + cBlockSize;
- nbBlocks++;
-
- if (blockProperties.lastBlock) break;
- }
-
- /* Final frame content checksum */
- if (zfh.checksumFlag) {
- if (remainingSize < 4)
- return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong));
- ip += 4;
- }
-
- frameSizeInfo.compressedSize = ip - ipstart;
- frameSizeInfo.decompressedBound = (zfh.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN)
- ? zfh.frameContentSize
- : nbBlocks * zfh.blockSizeMax;
- return frameSizeInfo;
- }
-}
-
-/** ZSTD_findFrameCompressedSize() :
- * compatible with legacy mode
- * `src` must point to the start of a ZSTD frame, ZSTD legacy frame, or skippable frame
- * `srcSize` must be at least as large as the frame contained
- * @return : the compressed size of the frame starting at `src` */
-size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize)
-{
- ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize);
- return frameSizeInfo.compressedSize;
-}
-
-/** ZSTD_decompressBound() :
- * compatible with legacy mode
- * `src` must point to the start of a ZSTD frame or a skippeable frame
- * `srcSize` must be at least as large as the frame contained
- * @return : the maximum decompressed size of the compressed source
- */
-unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize)
-{
- unsigned long long bound = 0;
- /* Iterate over each frame */
- while (srcSize > 0) {
- ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize);
- size_t const compressedSize = frameSizeInfo.compressedSize;
- unsigned long long const decompressedBound = frameSizeInfo.decompressedBound;
- if (ZSTD_isError(compressedSize) || decompressedBound == ZSTD_CONTENTSIZE_ERROR)
- return ZSTD_CONTENTSIZE_ERROR;
- assert(srcSize >= compressedSize);
- src = (const BYTE*)src + compressedSize;
- srcSize -= compressedSize;
- bound += decompressedBound;
- }
- return bound;
-}
-
-
-/*-*************************************************************
- * Frame decoding
- ***************************************************************/
-
-/** ZSTD_insertBlock() :
- * insert `src` block into `dctx` history. Useful to track uncompressed blocks. */
-size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize)
-{
- DEBUGLOG(5, "ZSTD_insertBlock: %u bytes", (unsigned)blockSize);
- ZSTD_checkContinuity(dctx, blockStart);
- dctx->previousDstEnd = (const char*)blockStart + blockSize;
- return blockSize;
-}
-
-
-static size_t ZSTD_copyRawBlock(void* dst, size_t dstCapacity,
- const void* src, size_t srcSize)
-{
- DEBUGLOG(5, "ZSTD_copyRawBlock");
- if (dst == NULL) {
- if (srcSize == 0) return 0;
- RETURN_ERROR(dstBuffer_null, "");
- }
- RETURN_ERROR_IF(srcSize > dstCapacity, dstSize_tooSmall, "");
- memcpy(dst, src, srcSize);
- return srcSize;
-}
-
-static size_t ZSTD_setRleBlock(void* dst, size_t dstCapacity,
- BYTE b,
- size_t regenSize)
-{
- if (dst == NULL) {
- if (regenSize == 0) return 0;
- RETURN_ERROR(dstBuffer_null, "");
- }
- RETURN_ERROR_IF(regenSize > dstCapacity, dstSize_tooSmall, "");
- memset(dst, b, regenSize);
- return regenSize;
-}
-
-
-/*! ZSTD_decompressFrame() :
- * @dctx must be properly initialized
- * will update *srcPtr and *srcSizePtr,
- * to make *srcPtr progress by one frame. */
-static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
- void* dst, size_t dstCapacity,
- const void** srcPtr, size_t *srcSizePtr)
-{
- const BYTE* ip = (const BYTE*)(*srcPtr);
- BYTE* const ostart = (BYTE* const)dst;
- BYTE* const oend = dstCapacity != 0 ? ostart + dstCapacity : ostart;
- BYTE* op = ostart;
- size_t remainingSrcSize = *srcSizePtr;
-
- DEBUGLOG(4, "ZSTD_decompressFrame (srcSize:%i)", (int)*srcSizePtr);
-
- /* check */
- RETURN_ERROR_IF(
- remainingSrcSize < ZSTD_FRAMEHEADERSIZE_MIN(dctx->format)+ZSTD_blockHeaderSize,
- srcSize_wrong, "");
-
- /* Frame Header */
- { size_t const frameHeaderSize = ZSTD_frameHeaderSize_internal(
- ip, ZSTD_FRAMEHEADERSIZE_PREFIX(dctx->format), dctx->format);
- if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize;
- RETURN_ERROR_IF(remainingSrcSize < frameHeaderSize+ZSTD_blockHeaderSize,
- srcSize_wrong, "");
- FORWARD_IF_ERROR( ZSTD_decodeFrameHeader(dctx, ip, frameHeaderSize) , "");
- ip += frameHeaderSize; remainingSrcSize -= frameHeaderSize;
- }
-
- /* Loop on each block */
- while (1) {
- size_t decodedSize;
- blockProperties_t blockProperties;
- size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSrcSize, &blockProperties);
- if (ZSTD_isError(cBlockSize)) return cBlockSize;
-
- ip += ZSTD_blockHeaderSize;
- remainingSrcSize -= ZSTD_blockHeaderSize;
- RETURN_ERROR_IF(cBlockSize > remainingSrcSize, srcSize_wrong, "");
-
- switch(blockProperties.blockType)
- {
- case bt_compressed:
- decodedSize = ZSTD_decompressBlock_internal(dctx, op, oend-op, ip, cBlockSize, /* frame */ 1);
- break;
- case bt_raw :
- decodedSize = ZSTD_copyRawBlock(op, oend-op, ip, cBlockSize);
- break;
- case bt_rle :
- decodedSize = ZSTD_setRleBlock(op, oend-op, *ip, blockProperties.origSize);
- break;
- case bt_reserved :
- default:
- RETURN_ERROR(corruption_detected, "invalid block type");
- }
-
- if (ZSTD_isError(decodedSize)) return decodedSize;
- if (dctx->fParams.checksumFlag)
- XXH64_update(&dctx->xxhState, op, decodedSize);
- if (decodedSize != 0)
- op += decodedSize;
- assert(ip != NULL);
- ip += cBlockSize;
- remainingSrcSize -= cBlockSize;
- if (blockProperties.lastBlock) break;
- }
-
- if (dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN) {
- RETURN_ERROR_IF((U64)(op-ostart) != dctx->fParams.frameContentSize,
- corruption_detected, "");
- }
- if (dctx->fParams.checksumFlag) { /* Frame content checksum verification */
- U32 const checkCalc = (U32)XXH64_digest(&dctx->xxhState);
- U32 checkRead;
- RETURN_ERROR_IF(remainingSrcSize<4, checksum_wrong, "");
- checkRead = MEM_readLE32(ip);
- RETURN_ERROR_IF(checkRead != checkCalc, checksum_wrong, "");
- ip += 4;
- remainingSrcSize -= 4;
- }
-
- /* Allow caller to get size read */
- *srcPtr = ip;
- *srcSizePtr = remainingSrcSize;
- return op-ostart;
-}
-
-static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- const void* dict, size_t dictSize,
- const ZSTD_DDict* ddict)
-{
- void* const dststart = dst;
- int moreThan1Frame = 0;
-
- DEBUGLOG(5, "ZSTD_decompressMultiFrame");
- assert(dict==NULL || ddict==NULL); /* either dict or ddict set, not both */
-
- if (ddict) {
- dict = ZSTD_DDict_dictContent(ddict);
- dictSize = ZSTD_DDict_dictSize(ddict);
- }
-
- while (srcSize >= ZSTD_startingInputLength(dctx->format)) {
-
-#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
- if (ZSTD_isLegacy(src, srcSize)) {
- size_t decodedSize;
- size_t const frameSize = ZSTD_findFrameCompressedSizeLegacy(src, srcSize);
- if (ZSTD_isError(frameSize)) return frameSize;
- RETURN_ERROR_IF(dctx->staticSize, memory_allocation,
- "legacy support is not compatible with static dctx");
-
- decodedSize = ZSTD_decompressLegacy(dst, dstCapacity, src, frameSize, dict, dictSize);
- if (ZSTD_isError(decodedSize)) return decodedSize;
-
- assert(decodedSize <=- dstCapacity);
- dst = (BYTE*)dst + decodedSize;
- dstCapacity -= decodedSize;
-
- src = (const BYTE*)src + frameSize;
- srcSize -= frameSize;
-
- continue;
- }
-#endif
-
- { U32 const magicNumber = MEM_readLE32(src);
- DEBUGLOG(4, "reading magic number %08X (expecting %08X)",
- (unsigned)magicNumber, ZSTD_MAGICNUMBER);
- if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
- size_t const skippableSize = readSkippableFrameSize(src, srcSize);
- FORWARD_IF_ERROR(skippableSize, "readSkippableFrameSize failed");
- assert(skippableSize <= srcSize);
-
- src = (const BYTE *)src + skippableSize;
- srcSize -= skippableSize;
- continue;
- } }
-
- if (ddict) {
- /* we were called from ZSTD_decompress_usingDDict */
- FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(dctx, ddict), "");
- } else {
- /* this will initialize correctly with no dict if dict == NULL, so
- * use this in all cases but ddict */
- FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDict(dctx, dict, dictSize), "");
- }
- ZSTD_checkContinuity(dctx, dst);
-
- { const size_t res = ZSTD_decompressFrame(dctx, dst, dstCapacity,
- &src, &srcSize);
- RETURN_ERROR_IF(
- (ZSTD_getErrorCode(res) == ZSTD_error_prefix_unknown)
- && (moreThan1Frame==1),
- srcSize_wrong,
- "at least one frame successfully completed, but following "
- "bytes are garbage: it's more likely to be a srcSize error, "
- "specifying more bytes than compressed size of frame(s). This "
- "error message replaces ERROR(prefix_unknown), which would be "
- "confusing, as the first header is actually correct. Note that "
- "one could be unlucky, it might be a corruption error instead, "
- "happening right at the place where we expect zstd magic "
- "bytes. But this is _much_ less likely than a srcSize field "
- "error.");
- if (ZSTD_isError(res)) return res;
- assert(res <= dstCapacity);
- if (res != 0)
- dst = (BYTE*)dst + res;
- dstCapacity -= res;
- }
- moreThan1Frame = 1;
- } /* while (srcSize >= ZSTD_frameHeaderSize_prefix) */
-
- RETURN_ERROR_IF(srcSize, srcSize_wrong, "input not entirely consumed");
-
- return (BYTE*)dst - (BYTE*)dststart;
-}
-
-size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- const void* dict, size_t dictSize)
-{
- return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, srcSize, dict, dictSize, NULL);
-}
-
-
-static ZSTD_DDict const* ZSTD_getDDict(ZSTD_DCtx* dctx)
-{
- switch (dctx->dictUses) {
- default:
- assert(0 /* Impossible */);
- /* fall-through */
- case ZSTD_dont_use:
- ZSTD_clearDict(dctx);
- return NULL;
- case ZSTD_use_indefinitely:
- return dctx->ddict;
- case ZSTD_use_once:
- dctx->dictUses = ZSTD_dont_use;
- return dctx->ddict;
- }
-}
-
-size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
-{
- return ZSTD_decompress_usingDDict(dctx, dst, dstCapacity, src, srcSize, ZSTD_getDDict(dctx));
-}
-
-
-size_t ZSTD_decompress(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
-{
-#if defined(ZSTD_HEAPMODE) && (ZSTD_HEAPMODE>=1)
- size_t regenSize;
- ZSTD_DCtx* const dctx = ZSTD_createDCtx();
- RETURN_ERROR_IF(dctx==NULL, memory_allocation, "NULL pointer!");
- regenSize = ZSTD_decompressDCtx(dctx, dst, dstCapacity, src, srcSize);
- ZSTD_freeDCtx(dctx);
- return regenSize;
-#else /* stack mode */
- ZSTD_DCtx dctx;
- ZSTD_initDCtx_internal(&dctx);
- return ZSTD_decompressDCtx(&dctx, dst, dstCapacity, src, srcSize);
-#endif
-}
-
-
-/*-**************************************
-* Advanced Streaming Decompression API
-* Bufferless and synchronous
-****************************************/
-size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx) { return dctx->expected; }
-
-/**
- * Similar to ZSTD_nextSrcSizeToDecompress(), but when when a block input can be streamed,
- * we allow taking a partial block as the input. Currently only raw uncompressed blocks can
- * be streamed.
- *
- * For blocks that can be streamed, this allows us to reduce the latency until we produce
- * output, and avoid copying the input.
- *
- * @param inputSize - The total amount of input that the caller currently has.
- */
-static size_t ZSTD_nextSrcSizeToDecompressWithInputSize(ZSTD_DCtx* dctx, size_t inputSize) {
- if (!(dctx->stage == ZSTDds_decompressBlock || dctx->stage == ZSTDds_decompressLastBlock))
- return dctx->expected;
- if (dctx->bType != bt_raw)
- return dctx->expected;
- return MIN(MAX(inputSize, 1), dctx->expected);
-}
-
-ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx) {
- switch(dctx->stage)
- {
- default: /* should not happen */
- assert(0);
- case ZSTDds_getFrameHeaderSize:
- case ZSTDds_decodeFrameHeader:
- return ZSTDnit_frameHeader;
- case ZSTDds_decodeBlockHeader:
- return ZSTDnit_blockHeader;
- case ZSTDds_decompressBlock:
- return ZSTDnit_block;
- case ZSTDds_decompressLastBlock:
- return ZSTDnit_lastBlock;
- case ZSTDds_checkChecksum:
- return ZSTDnit_checksum;
- case ZSTDds_decodeSkippableHeader:
- case ZSTDds_skipFrame:
- return ZSTDnit_skippableFrame;
- }
-}
-
-static int ZSTD_isSkipFrame(ZSTD_DCtx* dctx) { return dctx->stage == ZSTDds_skipFrame; }
-
-/** ZSTD_decompressContinue() :
- * srcSize : must be the exact nb of bytes expected (see ZSTD_nextSrcSizeToDecompress())
- * @return : nb of bytes generated into `dst` (necessarily <= `dstCapacity)
- * or an error code, which can be tested using ZSTD_isError() */
-size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
-{
- DEBUGLOG(5, "ZSTD_decompressContinue (srcSize:%u)", (unsigned)srcSize);
- /* Sanity check */
- RETURN_ERROR_IF(srcSize != ZSTD_nextSrcSizeToDecompressWithInputSize(dctx, srcSize), srcSize_wrong, "not allowed");
- if (dstCapacity) ZSTD_checkContinuity(dctx, dst);
-
- switch (dctx->stage)
- {
- case ZSTDds_getFrameHeaderSize :
- assert(src != NULL);
- if (dctx->format == ZSTD_f_zstd1) { /* allows header */
- assert(srcSize >= ZSTD_FRAMEIDSIZE); /* to read skippable magic number */
- if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */
- memcpy(dctx->headerBuffer, src, srcSize);
- dctx->expected = ZSTD_SKIPPABLEHEADERSIZE - srcSize; /* remaining to load to get full skippable frame header */
- dctx->stage = ZSTDds_decodeSkippableHeader;
- return 0;
- } }
- dctx->headerSize = ZSTD_frameHeaderSize_internal(src, srcSize, dctx->format);
- if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize;
- memcpy(dctx->headerBuffer, src, srcSize);
- dctx->expected = dctx->headerSize - srcSize;
- dctx->stage = ZSTDds_decodeFrameHeader;
- return 0;
-
- case ZSTDds_decodeFrameHeader:
- assert(src != NULL);
- memcpy(dctx->headerBuffer + (dctx->headerSize - srcSize), src, srcSize);
- FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize), "");
- dctx->expected = ZSTD_blockHeaderSize;
- dctx->stage = ZSTDds_decodeBlockHeader;
- return 0;
-
- case ZSTDds_decodeBlockHeader:
- { blockProperties_t bp;
- size_t const cBlockSize = ZSTD_getcBlockSize(src, ZSTD_blockHeaderSize, &bp);
- if (ZSTD_isError(cBlockSize)) return cBlockSize;
- RETURN_ERROR_IF(cBlockSize > dctx->fParams.blockSizeMax, corruption_detected, "Block Size Exceeds Maximum");
- dctx->expected = cBlockSize;
- dctx->bType = bp.blockType;
- dctx->rleSize = bp.origSize;
- if (cBlockSize) {
- dctx->stage = bp.lastBlock ? ZSTDds_decompressLastBlock : ZSTDds_decompressBlock;
- return 0;
- }
- /* empty block */
- if (bp.lastBlock) {
- if (dctx->fParams.checksumFlag) {
- dctx->expected = 4;
- dctx->stage = ZSTDds_checkChecksum;
- } else {
- dctx->expected = 0; /* end of frame */
- dctx->stage = ZSTDds_getFrameHeaderSize;
- }
- } else {
- dctx->expected = ZSTD_blockHeaderSize; /* jump to next header */
- dctx->stage = ZSTDds_decodeBlockHeader;
- }
- return 0;
- }
-
- case ZSTDds_decompressLastBlock:
- case ZSTDds_decompressBlock:
- DEBUGLOG(5, "ZSTD_decompressContinue: case ZSTDds_decompressBlock");
- { size_t rSize;
- switch(dctx->bType)
- {
- case bt_compressed:
- DEBUGLOG(5, "ZSTD_decompressContinue: case bt_compressed");
- rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 1);
- dctx->expected = 0; /* Streaming not supported */
- break;
- case bt_raw :
- assert(srcSize <= dctx->expected);
- rSize = ZSTD_copyRawBlock(dst, dstCapacity, src, srcSize);
- FORWARD_IF_ERROR(rSize, "ZSTD_copyRawBlock failed");
- assert(rSize == srcSize);
- dctx->expected -= rSize;
- break;
- case bt_rle :
- rSize = ZSTD_setRleBlock(dst, dstCapacity, *(const BYTE*)src, dctx->rleSize);
- dctx->expected = 0; /* Streaming not supported */
- break;
- case bt_reserved : /* should never happen */
- default:
- RETURN_ERROR(corruption_detected, "invalid block type");
- }
- FORWARD_IF_ERROR(rSize, "");
- RETURN_ERROR_IF(rSize > dctx->fParams.blockSizeMax, corruption_detected, "Decompressed Block Size Exceeds Maximum");
- DEBUGLOG(5, "ZSTD_decompressContinue: decoded size from block : %u", (unsigned)rSize);
- dctx->decodedSize += rSize;
- if (dctx->fParams.checksumFlag) XXH64_update(&dctx->xxhState, dst, rSize);
- dctx->previousDstEnd = (char*)dst + rSize;
-
- /* Stay on the same stage until we are finished streaming the block. */
- if (dctx->expected > 0) {
- return rSize;
- }
-
- if (dctx->stage == ZSTDds_decompressLastBlock) { /* end of frame */
- DEBUGLOG(4, "ZSTD_decompressContinue: decoded size from frame : %u", (unsigned)dctx->decodedSize);
- RETURN_ERROR_IF(
- dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN
- && dctx->decodedSize != dctx->fParams.frameContentSize,
- corruption_detected, "");
- if (dctx->fParams.checksumFlag) { /* another round for frame checksum */
- dctx->expected = 4;
- dctx->stage = ZSTDds_checkChecksum;
- } else {
- dctx->expected = 0; /* ends here */
- dctx->stage = ZSTDds_getFrameHeaderSize;
- }
- } else {
- dctx->stage = ZSTDds_decodeBlockHeader;
- dctx->expected = ZSTD_blockHeaderSize;
- }
- return rSize;
- }
-
- case ZSTDds_checkChecksum:
- assert(srcSize == 4); /* guaranteed by dctx->expected */
- { U32 const h32 = (U32)XXH64_digest(&dctx->xxhState);
- U32 const check32 = MEM_readLE32(src);
- DEBUGLOG(4, "ZSTD_decompressContinue: checksum : calculated %08X :: %08X read", (unsigned)h32, (unsigned)check32);
- RETURN_ERROR_IF(check32 != h32, checksum_wrong, "");
- dctx->expected = 0;
- dctx->stage = ZSTDds_getFrameHeaderSize;
- return 0;
- }
-
- case ZSTDds_decodeSkippableHeader:
- assert(src != NULL);
- assert(srcSize <= ZSTD_SKIPPABLEHEADERSIZE);
- memcpy(dctx->headerBuffer + (ZSTD_SKIPPABLEHEADERSIZE - srcSize), src, srcSize); /* complete skippable header */
- dctx->expected = MEM_readLE32(dctx->headerBuffer + ZSTD_FRAMEIDSIZE); /* note : dctx->expected can grow seriously large, beyond local buffer size */
- dctx->stage = ZSTDds_skipFrame;
- return 0;
-
- case ZSTDds_skipFrame:
- dctx->expected = 0;
- dctx->stage = ZSTDds_getFrameHeaderSize;
- return 0;
-
- default:
- assert(0); /* impossible */
- RETURN_ERROR(GENERIC, "impossible to reach"); /* some compiler require default to do something */
- }
-}
-
-
-static size_t ZSTD_refDictContent(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
-{
- dctx->dictEnd = dctx->previousDstEnd;
- dctx->virtualStart = (const char*)dict - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart));
- dctx->prefixStart = dict;
- dctx->previousDstEnd = (const char*)dict + dictSize;
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
- dctx->dictContentBeginForFuzzing = dctx->prefixStart;
- dctx->dictContentEndForFuzzing = dctx->previousDstEnd;
-#endif
- return 0;
-}
-
-/*! ZSTD_loadDEntropy() :
- * dict : must point at beginning of a valid zstd dictionary.
- * @return : size of entropy tables read */
-size_t
-ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy,
- const void* const dict, size_t const dictSize)
-{
- const BYTE* dictPtr = (const BYTE*)dict;
- const BYTE* const dictEnd = dictPtr + dictSize;
-
- RETURN_ERROR_IF(dictSize <= 8, dictionary_corrupted, "dict is too small");
- assert(MEM_readLE32(dict) == ZSTD_MAGIC_DICTIONARY); /* dict must be valid */
- dictPtr += 8; /* skip header = magic + dictID */
-
- ZSTD_STATIC_ASSERT(offsetof(ZSTD_entropyDTables_t, OFTable) == offsetof(ZSTD_entropyDTables_t, LLTable) + sizeof(entropy->LLTable));
- ZSTD_STATIC_ASSERT(offsetof(ZSTD_entropyDTables_t, MLTable) == offsetof(ZSTD_entropyDTables_t, OFTable) + sizeof(entropy->OFTable));
- ZSTD_STATIC_ASSERT(sizeof(entropy->LLTable) + sizeof(entropy->OFTable) + sizeof(entropy->MLTable) >= HUF_DECOMPRESS_WORKSPACE_SIZE);
- { void* const workspace = &entropy->LLTable; /* use fse tables as temporary workspace; implies fse tables are grouped together */
- size_t const workspaceSize = sizeof(entropy->LLTable) + sizeof(entropy->OFTable) + sizeof(entropy->MLTable);
-#ifdef HUF_FORCE_DECOMPRESS_X1
- /* in minimal huffman, we always use X1 variants */
- size_t const hSize = HUF_readDTableX1_wksp(entropy->hufTable,
- dictPtr, dictEnd - dictPtr,
- workspace, workspaceSize);
-#else
- size_t const hSize = HUF_readDTableX2_wksp(entropy->hufTable,
- dictPtr, dictEnd - dictPtr,
- workspace, workspaceSize);
-#endif
- RETURN_ERROR_IF(HUF_isError(hSize), dictionary_corrupted, "");
- dictPtr += hSize;
- }
-
- { short offcodeNCount[MaxOff+1];
- unsigned offcodeMaxValue = MaxOff, offcodeLog;
- size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
- RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted, "");
- RETURN_ERROR_IF(offcodeMaxValue > MaxOff, dictionary_corrupted, "");
- RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted, "");
- ZSTD_buildFSETable( entropy->OFTable,
- offcodeNCount, offcodeMaxValue,
- OF_base, OF_bits,
- offcodeLog);
- dictPtr += offcodeHeaderSize;
- }
-
- { short matchlengthNCount[MaxML+1];
- unsigned matchlengthMaxValue = MaxML, matchlengthLog;
- size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
- RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted, "");
- RETURN_ERROR_IF(matchlengthMaxValue > MaxML, dictionary_corrupted, "");
- RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted, "");
- ZSTD_buildFSETable( entropy->MLTable,
- matchlengthNCount, matchlengthMaxValue,
- ML_base, ML_bits,
- matchlengthLog);
- dictPtr += matchlengthHeaderSize;
- }
-
- { short litlengthNCount[MaxLL+1];
- unsigned litlengthMaxValue = MaxLL, litlengthLog;
- size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
- RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted, "");
- RETURN_ERROR_IF(litlengthMaxValue > MaxLL, dictionary_corrupted, "");
- RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted, "");
- ZSTD_buildFSETable( entropy->LLTable,
- litlengthNCount, litlengthMaxValue,
- LL_base, LL_bits,
- litlengthLog);
- dictPtr += litlengthHeaderSize;
- }
-
- RETURN_ERROR_IF(dictPtr+12 > dictEnd, dictionary_corrupted, "");
- { int i;
- size_t const dictContentSize = (size_t)(dictEnd - (dictPtr+12));
- for (i=0; i<3; i++) {
- U32 const rep = MEM_readLE32(dictPtr); dictPtr += 4;
- RETURN_ERROR_IF(rep==0 || rep > dictContentSize,
- dictionary_corrupted, "");
- entropy->rep[i] = rep;
- } }
-
- return dictPtr - (const BYTE*)dict;
-}
-
-static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
-{
- if (dictSize < 8) return ZSTD_refDictContent(dctx, dict, dictSize);
- { U32 const magic = MEM_readLE32(dict);
- if (magic != ZSTD_MAGIC_DICTIONARY) {
- return ZSTD_refDictContent(dctx, dict, dictSize); /* pure content mode */
- } }
- dctx->dictID = MEM_readLE32((const char*)dict + ZSTD_FRAMEIDSIZE);
-
- /* load entropy tables */
- { size_t const eSize = ZSTD_loadDEntropy(&dctx->entropy, dict, dictSize);
- RETURN_ERROR_IF(ZSTD_isError(eSize), dictionary_corrupted, "");
- dict = (const char*)dict + eSize;
- dictSize -= eSize;
- }
- dctx->litEntropy = dctx->fseEntropy = 1;
-
- /* reference dictionary content */
- return ZSTD_refDictContent(dctx, dict, dictSize);
-}
-
-size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx)
-{
- assert(dctx != NULL);
- dctx->expected = ZSTD_startingInputLength(dctx->format); /* dctx->format must be properly set */
- dctx->stage = ZSTDds_getFrameHeaderSize;
- dctx->decodedSize = 0;
- dctx->previousDstEnd = NULL;
- dctx->prefixStart = NULL;
- dctx->virtualStart = NULL;
- dctx->dictEnd = NULL;
- dctx->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */
- dctx->litEntropy = dctx->fseEntropy = 0;
- dctx->dictID = 0;
- dctx->bType = bt_reserved;
- ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue));
- memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */
- dctx->LLTptr = dctx->entropy.LLTable;
- dctx->MLTptr = dctx->entropy.MLTable;
- dctx->OFTptr = dctx->entropy.OFTable;
- dctx->HUFptr = dctx->entropy.hufTable;
- return 0;
-}
-
-size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
-{
- FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) , "");
- if (dict && dictSize)
- RETURN_ERROR_IF(
- ZSTD_isError(ZSTD_decompress_insertDictionary(dctx, dict, dictSize)),
- dictionary_corrupted, "");
- return 0;
-}
-
-
-/* ====== ZSTD_DDict ====== */
-
-size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)
-{
- DEBUGLOG(4, "ZSTD_decompressBegin_usingDDict");
- assert(dctx != NULL);
- if (ddict) {
- const char* const dictStart = (const char*)ZSTD_DDict_dictContent(ddict);
- size_t const dictSize = ZSTD_DDict_dictSize(ddict);
- const void* const dictEnd = dictStart + dictSize;
- dctx->ddictIsCold = (dctx->dictEnd != dictEnd);
- DEBUGLOG(4, "DDict is %s",
- dctx->ddictIsCold ? "~cold~" : "hot!");
- }
- FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) , "");
- if (ddict) { /* NULL ddict is equivalent to no dictionary */
- ZSTD_copyDDictParameters(dctx, ddict);
- }
- return 0;
-}
-
-/*! ZSTD_getDictID_fromDict() :
- * Provides the dictID stored within dictionary.
- * if @return == 0, the dictionary is not conformant with Zstandard specification.
- * It can still be loaded, but as a content-only dictionary. */
-unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize)
-{
- if (dictSize < 8) return 0;
- if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) return 0;
- return MEM_readLE32((const char*)dict + ZSTD_FRAMEIDSIZE);
-}
-
-/*! ZSTD_getDictID_fromFrame() :
- * Provides the dictID required to decompress frame stored within `src`.
- * If @return == 0, the dictID could not be decoded.
- * This could for one of the following reasons :
- * - The frame does not require a dictionary (most common case).
- * - The frame was built with dictID intentionally removed.
- * Needed dictionary is a hidden information.
- * Note : this use case also happens when using a non-conformant dictionary.
- * - `srcSize` is too small, and as a result, frame header could not be decoded.
- * Note : possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`.
- * - This is not a Zstandard frame.
- * When identifying the exact failure cause, it's possible to use
- * ZSTD_getFrameHeader(), which will provide a more precise error code. */
-unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize)
-{
- ZSTD_frameHeader zfp = { 0, 0, 0, ZSTD_frame, 0, 0, 0 };
- size_t const hError = ZSTD_getFrameHeader(&zfp, src, srcSize);
- if (ZSTD_isError(hError)) return 0;
- return zfp.dictID;
-}
-
-
-/*! ZSTD_decompress_usingDDict() :
-* Decompression using a pre-digested Dictionary
-* Use dictionary without significant overhead. */
-size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- const ZSTD_DDict* ddict)
-{
- /* pass content and size in case legacy frames are encountered */
- return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, srcSize,
- NULL, 0,
- ddict);
-}
-
-
-/*=====================================
-* Streaming decompression
-*====================================*/
-
-ZSTD_DStream* ZSTD_createDStream(void)
-{
- DEBUGLOG(3, "ZSTD_createDStream");
- return ZSTD_createDStream_advanced(ZSTD_defaultCMem);
-}
-
-ZSTD_DStream* ZSTD_initStaticDStream(void *workspace, size_t workspaceSize)
-{
- return ZSTD_initStaticDCtx(workspace, workspaceSize);
-}
-
-ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem)
-{
- return ZSTD_createDCtx_advanced(customMem);
-}
-
-size_t ZSTD_freeDStream(ZSTD_DStream* zds)
-{
- return ZSTD_freeDCtx(zds);
-}
-
-
-/* *** Initialization *** */
-
-size_t ZSTD_DStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize; }
-size_t ZSTD_DStreamOutSize(void) { return ZSTD_BLOCKSIZE_MAX; }
-
-size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx,
- const void* dict, size_t dictSize,
- ZSTD_dictLoadMethod_e dictLoadMethod,
- ZSTD_dictContentType_e dictContentType)
-{
- RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");
- ZSTD_clearDict(dctx);
- if (dict && dictSize != 0) {
- dctx->ddictLocal = ZSTD_createDDict_advanced(dict, dictSize, dictLoadMethod, dictContentType, dctx->customMem);
- RETURN_ERROR_IF(dctx->ddictLocal == NULL, memory_allocation, "NULL pointer!");
- dctx->ddict = dctx->ddictLocal;
- dctx->dictUses = ZSTD_use_indefinitely;
- }
- return 0;
-}
-
-size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
-{
- return ZSTD_DCtx_loadDictionary_advanced(dctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto);
-}
-
-size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
-{
- return ZSTD_DCtx_loadDictionary_advanced(dctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto);
-}
-
-size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType)
-{
- FORWARD_IF_ERROR(ZSTD_DCtx_loadDictionary_advanced(dctx, prefix, prefixSize, ZSTD_dlm_byRef, dictContentType), "");
- dctx->dictUses = ZSTD_use_once;
- return 0;
-}
-
-size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize)
-{
- return ZSTD_DCtx_refPrefix_advanced(dctx, prefix, prefixSize, ZSTD_dct_rawContent);
-}
-
-
-/* ZSTD_initDStream_usingDict() :
- * return : expected size, aka ZSTD_startingInputLength().
- * this function cannot fail */
-size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize)
-{
- DEBUGLOG(4, "ZSTD_initDStream_usingDict");
- FORWARD_IF_ERROR( ZSTD_DCtx_reset(zds, ZSTD_reset_session_only) , "");
- FORWARD_IF_ERROR( ZSTD_DCtx_loadDictionary(zds, dict, dictSize) , "");
- return ZSTD_startingInputLength(zds->format);
-}
-
-/* note : this variant can't fail */
-size_t ZSTD_initDStream(ZSTD_DStream* zds)
-{
- DEBUGLOG(4, "ZSTD_initDStream");
- return ZSTD_initDStream_usingDDict(zds, NULL);
-}
-
-/* ZSTD_initDStream_usingDDict() :
- * ddict will just be referenced, and must outlive decompression session
- * this function cannot fail */
-size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* dctx, const ZSTD_DDict* ddict)
-{
- FORWARD_IF_ERROR( ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only) , "");
- FORWARD_IF_ERROR( ZSTD_DCtx_refDDict(dctx, ddict) , "");
- return ZSTD_startingInputLength(dctx->format);
-}
-
-/* ZSTD_resetDStream() :
- * return : expected size, aka ZSTD_startingInputLength().
- * this function cannot fail */
-size_t ZSTD_resetDStream(ZSTD_DStream* dctx)
-{
- FORWARD_IF_ERROR(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only), "");
- return ZSTD_startingInputLength(dctx->format);
-}
-
-
-size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)
-{
- RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");
- ZSTD_clearDict(dctx);
- if (ddict) {
- dctx->ddict = ddict;
- dctx->dictUses = ZSTD_use_indefinitely;
- }
- return 0;
-}
-
-/* ZSTD_DCtx_setMaxWindowSize() :
- * note : no direct equivalence in ZSTD_DCtx_setParameter,
- * since this version sets windowSize, and the other sets windowLog */
-size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize)
-{
- ZSTD_bounds const bounds = ZSTD_dParam_getBounds(ZSTD_d_windowLogMax);
- size_t const min = (size_t)1 << bounds.lowerBound;
- size_t const max = (size_t)1 << bounds.upperBound;
- RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");
- RETURN_ERROR_IF(maxWindowSize < min, parameter_outOfBound, "");
- RETURN_ERROR_IF(maxWindowSize > max, parameter_outOfBound, "");
- dctx->maxWindowSize = maxWindowSize;
- return 0;
-}
-
-size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format)
-{
- return ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, format);
-}
-
-ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam)
-{
- ZSTD_bounds bounds = { 0, 0, 0 };
- switch(dParam) {
- case ZSTD_d_windowLogMax:
- bounds.lowerBound = ZSTD_WINDOWLOG_ABSOLUTEMIN;
- bounds.upperBound = ZSTD_WINDOWLOG_MAX;
- return bounds;
- case ZSTD_d_format:
- bounds.lowerBound = (int)ZSTD_f_zstd1;
- bounds.upperBound = (int)ZSTD_f_zstd1_magicless;
- ZSTD_STATIC_ASSERT(ZSTD_f_zstd1 < ZSTD_f_zstd1_magicless);
- return bounds;
- case ZSTD_d_stableOutBuffer:
- bounds.lowerBound = (int)ZSTD_obm_buffered;
- bounds.upperBound = (int)ZSTD_obm_stable;
- return bounds;
- default:;
- }
- bounds.error = ERROR(parameter_unsupported);
- return bounds;
-}
-
-/* ZSTD_dParam_withinBounds:
- * @return 1 if value is within dParam bounds,
- * 0 otherwise */
-static int ZSTD_dParam_withinBounds(ZSTD_dParameter dParam, int value)
-{
- ZSTD_bounds const bounds = ZSTD_dParam_getBounds(dParam);
- if (ZSTD_isError(bounds.error)) return 0;
- if (value < bounds.lowerBound) return 0;
- if (value > bounds.upperBound) return 0;
- return 1;
-}
-
-#define CHECK_DBOUNDS(p,v) { \
- RETURN_ERROR_IF(!ZSTD_dParam_withinBounds(p, v), parameter_outOfBound, ""); \
-}
-
-size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter dParam, int value)
-{
- RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");
- switch(dParam) {
- case ZSTD_d_windowLogMax:
- if (value == 0) value = ZSTD_WINDOWLOG_LIMIT_DEFAULT;
- CHECK_DBOUNDS(ZSTD_d_windowLogMax, value);
- dctx->maxWindowSize = ((size_t)1) << value;
- return 0;
- case ZSTD_d_format:
- CHECK_DBOUNDS(ZSTD_d_format, value);
- dctx->format = (ZSTD_format_e)value;
- return 0;
- case ZSTD_d_stableOutBuffer:
- CHECK_DBOUNDS(ZSTD_d_stableOutBuffer, value);
- dctx->outBufferMode = (ZSTD_outBufferMode_e)value;
- return 0;
- default:;
- }
- RETURN_ERROR(parameter_unsupported, "");
-}
-
-size_t ZSTD_DCtx_reset(ZSTD_DCtx* dctx, ZSTD_ResetDirective reset)
-{
- if ( (reset == ZSTD_reset_session_only)
- || (reset == ZSTD_reset_session_and_parameters) ) {
- dctx->streamStage = zdss_init;
- dctx->noForwardProgress = 0;
- }
- if ( (reset == ZSTD_reset_parameters)
- || (reset == ZSTD_reset_session_and_parameters) ) {
- RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");
- ZSTD_clearDict(dctx);
- dctx->format = ZSTD_f_zstd1;
- dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT;
- }
- return 0;
-}
-
-
-size_t ZSTD_sizeof_DStream(const ZSTD_DStream* dctx)
-{
- return ZSTD_sizeof_DCtx(dctx);
-}
-
-size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize)
-{
- size_t const blockSize = (size_t) MIN(windowSize, ZSTD_BLOCKSIZE_MAX);
- unsigned long long const neededRBSize = windowSize + blockSize + (WILDCOPY_OVERLENGTH * 2);
- unsigned long long const neededSize = MIN(frameContentSize, neededRBSize);
- size_t const minRBSize = (size_t) neededSize;
- RETURN_ERROR_IF((unsigned long long)minRBSize != neededSize,
- frameParameter_windowTooLarge, "");
- return minRBSize;
-}
-
-size_t ZSTD_estimateDStreamSize(size_t windowSize)
-{
- size_t const blockSize = MIN(windowSize, ZSTD_BLOCKSIZE_MAX);
- size_t const inBuffSize = blockSize; /* no block can be larger */
- size_t const outBuffSize = ZSTD_decodingBufferSize_min(windowSize, ZSTD_CONTENTSIZE_UNKNOWN);
- return ZSTD_estimateDCtxSize() + inBuffSize + outBuffSize;
-}
-
-size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize)
-{
- U32 const windowSizeMax = 1U << ZSTD_WINDOWLOG_MAX; /* note : should be user-selectable, but requires an additional parameter (or a dctx) */
- ZSTD_frameHeader zfh;
- size_t const err = ZSTD_getFrameHeader(&zfh, src, srcSize);
- if (ZSTD_isError(err)) return err;
- RETURN_ERROR_IF(err>0, srcSize_wrong, "");
- RETURN_ERROR_IF(zfh.windowSize > windowSizeMax,
- frameParameter_windowTooLarge, "");
- return ZSTD_estimateDStreamSize((size_t)zfh.windowSize);
-}
-
-
-/* ***** Decompression ***** */
-
-static int ZSTD_DCtx_isOverflow(ZSTD_DStream* zds, size_t const neededInBuffSize, size_t const neededOutBuffSize)
-{
- return (zds->inBuffSize + zds->outBuffSize) >= (neededInBuffSize + neededOutBuffSize) * ZSTD_WORKSPACETOOLARGE_FACTOR;
-}
-
-static void ZSTD_DCtx_updateOversizedDuration(ZSTD_DStream* zds, size_t const neededInBuffSize, size_t const neededOutBuffSize)
-{
- if (ZSTD_DCtx_isOverflow(zds, neededInBuffSize, neededOutBuffSize))
- zds->oversizedDuration++;
- else
- zds->oversizedDuration = 0;
-}
-
-static int ZSTD_DCtx_isOversizedTooLong(ZSTD_DStream* zds)
-{
- return zds->oversizedDuration >= ZSTD_WORKSPACETOOLARGE_MAXDURATION;
-}
-
-/* Checks that the output buffer hasn't changed if ZSTD_obm_stable is used. */
-static size_t ZSTD_checkOutBuffer(ZSTD_DStream const* zds, ZSTD_outBuffer const* output)
-{
- ZSTD_outBuffer const expect = zds->expectedOutBuffer;
- /* No requirement when ZSTD_obm_stable is not enabled. */
- if (zds->outBufferMode != ZSTD_obm_stable)
- return 0;
- /* Any buffer is allowed in zdss_init, this must be the same for every other call until
- * the context is reset.
- */
- if (zds->streamStage == zdss_init)
- return 0;
- /* The buffer must match our expectation exactly. */
- if (expect.dst == output->dst && expect.pos == output->pos && expect.size == output->size)
- return 0;
- RETURN_ERROR(dstBuffer_wrong, "ZSTD_obm_stable enabled but output differs!");
-}
-
-/* Calls ZSTD_decompressContinue() with the right parameters for ZSTD_decompressStream()
- * and updates the stage and the output buffer state. This call is extracted so it can be
- * used both when reading directly from the ZSTD_inBuffer, and in buffered input mode.
- * NOTE: You must break after calling this function since the streamStage is modified.
- */
-static size_t ZSTD_decompressContinueStream(
- ZSTD_DStream* zds, char** op, char* oend,
- void const* src, size_t srcSize) {
- int const isSkipFrame = ZSTD_isSkipFrame(zds);
- if (zds->outBufferMode == ZSTD_obm_buffered) {
- size_t const dstSize = isSkipFrame ? 0 : zds->outBuffSize - zds->outStart;
- size_t const decodedSize = ZSTD_decompressContinue(zds,
- zds->outBuff + zds->outStart, dstSize, src, srcSize);
- FORWARD_IF_ERROR(decodedSize, "");
- if (!decodedSize && !isSkipFrame) {
- zds->streamStage = zdss_read;
- } else {
- zds->outEnd = zds->outStart + decodedSize;
- zds->streamStage = zdss_flush;
- }
- } else {
- /* Write directly into the output buffer */
- size_t const dstSize = isSkipFrame ? 0 : oend - *op;
- size_t const decodedSize = ZSTD_decompressContinue(zds, *op, dstSize, src, srcSize);
- FORWARD_IF_ERROR(decodedSize, "");
- *op += decodedSize;
- /* Flushing is not needed. */
- zds->streamStage = zdss_read;
- assert(*op <= oend);
- assert(zds->outBufferMode == ZSTD_obm_stable);
- }
- return 0;
-}
-
-size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
-{
- const char* const src = (const char*)input->src;
- const char* const istart = input->pos != 0 ? src + input->pos : src;
- const char* const iend = input->size != 0 ? src + input->size : src;
- const char* ip = istart;
- char* const dst = (char*)output->dst;
- char* const ostart = output->pos != 0 ? dst + output->pos : dst;
- char* const oend = output->size != 0 ? dst + output->size : dst;
- char* op = ostart;
- U32 someMoreWork = 1;
-
- DEBUGLOG(5, "ZSTD_decompressStream");
- RETURN_ERROR_IF(
- input->pos > input->size,
- srcSize_wrong,
- "forbidden. in: pos: %u vs size: %u",
- (U32)input->pos, (U32)input->size);
- RETURN_ERROR_IF(
- output->pos > output->size,
- dstSize_tooSmall,
- "forbidden. out: pos: %u vs size: %u",
- (U32)output->pos, (U32)output->size);
- DEBUGLOG(5, "input size : %u", (U32)(input->size - input->pos));
- FORWARD_IF_ERROR(ZSTD_checkOutBuffer(zds, output), "");
-
- while (someMoreWork) {
- switch(zds->streamStage)
- {
- case zdss_init :
- DEBUGLOG(5, "stage zdss_init => transparent reset ");
- zds->streamStage = zdss_loadHeader;
- zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0;
- zds->legacyVersion = 0;
- zds->hostageByte = 0;
- zds->expectedOutBuffer = *output;
- /* fall-through */
-
- case zdss_loadHeader :
- DEBUGLOG(5, "stage zdss_loadHeader (srcSize : %u)", (U32)(iend - ip));
-#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
- if (zds->legacyVersion) {
- RETURN_ERROR_IF(zds->staticSize, memory_allocation,
- "legacy support is incompatible with static dctx");
- { size_t const hint = ZSTD_decompressLegacyStream(zds->legacyContext, zds->legacyVersion, output, input);
- if (hint==0) zds->streamStage = zdss_init;
- return hint;
- } }
-#endif
- { size_t const hSize = ZSTD_getFrameHeader_advanced(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format);
- DEBUGLOG(5, "header size : %u", (U32)hSize);
- if (ZSTD_isError(hSize)) {
-#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
- U32 const legacyVersion = ZSTD_isLegacy(istart, iend-istart);
- if (legacyVersion) {
- ZSTD_DDict const* const ddict = ZSTD_getDDict(zds);
- const void* const dict = ddict ? ZSTD_DDict_dictContent(ddict) : NULL;
- size_t const dictSize = ddict ? ZSTD_DDict_dictSize(ddict) : 0;
- DEBUGLOG(5, "ZSTD_decompressStream: detected legacy version v0.%u", legacyVersion);
- RETURN_ERROR_IF(zds->staticSize, memory_allocation,
- "legacy support is incompatible with static dctx");
- FORWARD_IF_ERROR(ZSTD_initLegacyStream(&zds->legacyContext,
- zds->previousLegacyVersion, legacyVersion,
- dict, dictSize), "");
- zds->legacyVersion = zds->previousLegacyVersion = legacyVersion;
- { size_t const hint = ZSTD_decompressLegacyStream(zds->legacyContext, legacyVersion, output, input);
- if (hint==0) zds->streamStage = zdss_init; /* or stay in stage zdss_loadHeader */
- return hint;
- } }
-#endif
- return hSize; /* error */
- }
- if (hSize != 0) { /* need more input */
- size_t const toLoad = hSize - zds->lhSize; /* if hSize!=0, hSize > zds->lhSize */
- size_t const remainingInput = (size_t)(iend-ip);
- assert(iend >= ip);
- if (toLoad > remainingInput) { /* not enough input to load full header */
- if (remainingInput > 0) {
- memcpy(zds->headerBuffer + zds->lhSize, ip, remainingInput);
- zds->lhSize += remainingInput;
- }
- input->pos = input->size;
- return (MAX((size_t)ZSTD_FRAMEHEADERSIZE_MIN(zds->format), hSize) - zds->lhSize) + ZSTD_blockHeaderSize; /* remaining header bytes + next block header */
- }
- assert(ip != NULL);
- memcpy(zds->headerBuffer + zds->lhSize, ip, toLoad); zds->lhSize = hSize; ip += toLoad;
- break;
- } }
-
- /* check for single-pass mode opportunity */
- if (zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN
- && zds->fParams.frameType != ZSTD_skippableFrame
- && (U64)(size_t)(oend-op) >= zds->fParams.frameContentSize) {
- size_t const cSize = ZSTD_findFrameCompressedSize(istart, iend-istart);
- if (cSize <= (size_t)(iend-istart)) {
- /* shortcut : using single-pass mode */
- size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, oend-op, istart, cSize, ZSTD_getDDict(zds));
- if (ZSTD_isError(decompressedSize)) return decompressedSize;
- DEBUGLOG(4, "shortcut to single-pass ZSTD_decompress_usingDDict()")
- ip = istart + cSize;
- op += decompressedSize;
- zds->expected = 0;
- zds->streamStage = zdss_init;
- someMoreWork = 0;
- break;
- } }
-
- /* Check output buffer is large enough for ZSTD_odm_stable. */
- if (zds->outBufferMode == ZSTD_obm_stable
- && zds->fParams.frameType != ZSTD_skippableFrame
- && zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN
- && (U64)(size_t)(oend-op) < zds->fParams.frameContentSize) {
- RETURN_ERROR(dstSize_tooSmall, "ZSTD_obm_stable passed but ZSTD_outBuffer is too small");
- }
-
- /* Consume header (see ZSTDds_decodeFrameHeader) */
- DEBUGLOG(4, "Consume header");
- FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(zds, ZSTD_getDDict(zds)), "");
-
- if ((MEM_readLE32(zds->headerBuffer) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */
- zds->expected = MEM_readLE32(zds->headerBuffer + ZSTD_FRAMEIDSIZE);
- zds->stage = ZSTDds_skipFrame;
- } else {
- FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(zds, zds->headerBuffer, zds->lhSize), "");
- zds->expected = ZSTD_blockHeaderSize;
- zds->stage = ZSTDds_decodeBlockHeader;
- }
-
- /* control buffer memory usage */
- DEBUGLOG(4, "Control max memory usage (%u KB <= max %u KB)",
- (U32)(zds->fParams.windowSize >>10),
- (U32)(zds->maxWindowSize >> 10) );
- zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN);
- RETURN_ERROR_IF(zds->fParams.windowSize > zds->maxWindowSize,
- frameParameter_windowTooLarge, "");
-
- /* Adapt buffer sizes to frame header instructions */
- { size_t const neededInBuffSize = MAX(zds->fParams.blockSizeMax, 4 /* frame checksum */);
- size_t const neededOutBuffSize = zds->outBufferMode == ZSTD_obm_buffered
- ? ZSTD_decodingBufferSize_min(zds->fParams.windowSize, zds->fParams.frameContentSize)
- : 0;
-
- ZSTD_DCtx_updateOversizedDuration(zds, neededInBuffSize, neededOutBuffSize);
-
- { int const tooSmall = (zds->inBuffSize < neededInBuffSize) || (zds->outBuffSize < neededOutBuffSize);
- int const tooLarge = ZSTD_DCtx_isOversizedTooLong(zds);
-
- if (tooSmall || tooLarge) {
- size_t const bufferSize = neededInBuffSize + neededOutBuffSize;
- DEBUGLOG(4, "inBuff : from %u to %u",
- (U32)zds->inBuffSize, (U32)neededInBuffSize);
- DEBUGLOG(4, "outBuff : from %u to %u",
- (U32)zds->outBuffSize, (U32)neededOutBuffSize);
- if (zds->staticSize) { /* static DCtx */
- DEBUGLOG(4, "staticSize : %u", (U32)zds->staticSize);
- assert(zds->staticSize >= sizeof(ZSTD_DCtx)); /* controlled at init */
- RETURN_ERROR_IF(
- bufferSize > zds->staticSize - sizeof(ZSTD_DCtx),
- memory_allocation, "");
- } else {
- ZSTD_free(zds->inBuff, zds->customMem);
- zds->inBuffSize = 0;
- zds->outBuffSize = 0;
- zds->inBuff = (char*)ZSTD_malloc(bufferSize, zds->customMem);
- RETURN_ERROR_IF(zds->inBuff == NULL, memory_allocation, "");
- }
- zds->inBuffSize = neededInBuffSize;
- zds->outBuff = zds->inBuff + zds->inBuffSize;
- zds->outBuffSize = neededOutBuffSize;
- } } }
- zds->streamStage = zdss_read;
- /* fall-through */
-
- case zdss_read:
- DEBUGLOG(5, "stage zdss_read");
- { size_t const neededInSize = ZSTD_nextSrcSizeToDecompressWithInputSize(zds, iend - ip);
- DEBUGLOG(5, "neededInSize = %u", (U32)neededInSize);
- if (neededInSize==0) { /* end of frame */
- zds->streamStage = zdss_init;
- someMoreWork = 0;
- break;
- }
- if ((size_t)(iend-ip) >= neededInSize) { /* decode directly from src */
- FORWARD_IF_ERROR(ZSTD_decompressContinueStream(zds, &op, oend, ip, neededInSize), "");
- ip += neededInSize;
- /* Function modifies the stage so we must break */
- break;
- } }
- if (ip==iend) { someMoreWork = 0; break; } /* no more input */
- zds->streamStage = zdss_load;
- /* fall-through */
-
- case zdss_load:
- { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds);
- size_t const toLoad = neededInSize - zds->inPos;
- int const isSkipFrame = ZSTD_isSkipFrame(zds);
- size_t loadedSize;
- /* At this point we shouldn't be decompressing a block that we can stream. */
- assert(neededInSize == ZSTD_nextSrcSizeToDecompressWithInputSize(zds, iend - ip));
- if (isSkipFrame) {
- loadedSize = MIN(toLoad, (size_t)(iend-ip));
- } else {
- RETURN_ERROR_IF(toLoad > zds->inBuffSize - zds->inPos,
- corruption_detected,
- "should never happen");
- loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, iend-ip);
- }
- ip += loadedSize;
- zds->inPos += loadedSize;
- if (loadedSize < toLoad) { someMoreWork = 0; break; } /* not enough input, wait for more */
-
- /* decode loaded input */
- zds->inPos = 0; /* input is consumed */
- FORWARD_IF_ERROR(ZSTD_decompressContinueStream(zds, &op, oend, zds->inBuff, neededInSize), "");
- /* Function modifies the stage so we must break */
- break;
- }
- case zdss_flush:
- { size_t const toFlushSize = zds->outEnd - zds->outStart;
- size_t const flushedSize = ZSTD_limitCopy(op, oend-op, zds->outBuff + zds->outStart, toFlushSize);
- op += flushedSize;
- zds->outStart += flushedSize;
- if (flushedSize == toFlushSize) { /* flush completed */
- zds->streamStage = zdss_read;
- if ( (zds->outBuffSize < zds->fParams.frameContentSize)
- && (zds->outStart + zds->fParams.blockSizeMax > zds->outBuffSize) ) {
- DEBUGLOG(5, "restart filling outBuff from beginning (left:%i, needed:%u)",
- (int)(zds->outBuffSize - zds->outStart),
- (U32)zds->fParams.blockSizeMax);
- zds->outStart = zds->outEnd = 0;
- }
- break;
- } }
- /* cannot complete flush */
- someMoreWork = 0;
- break;
-
- default:
- assert(0); /* impossible */
- RETURN_ERROR(GENERIC, "impossible to reach"); /* some compiler require default to do something */
- } }
-
- /* result */
- input->pos = (size_t)(ip - (const char*)(input->src));
- output->pos = (size_t)(op - (char*)(output->dst));
-
- /* Update the expected output buffer for ZSTD_obm_stable. */
- zds->expectedOutBuffer = *output;
-
- if ((ip==istart) && (op==ostart)) { /* no forward progress */
- zds->noForwardProgress ++;
- if (zds->noForwardProgress >= ZSTD_NO_FORWARD_PROGRESS_MAX) {
- RETURN_ERROR_IF(op==oend, dstSize_tooSmall, "");
- RETURN_ERROR_IF(ip==iend, srcSize_wrong, "");
- assert(0);
- }
- } else {
- zds->noForwardProgress = 0;
- }
- { size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zds);
- if (!nextSrcSizeHint) { /* frame fully decoded */
- if (zds->outEnd == zds->outStart) { /* output fully flushed */
- if (zds->hostageByte) {
- if (input->pos >= input->size) {
- /* can't release hostage (not present) */
- zds->streamStage = zdss_read;
- return 1;
- }
- input->pos++; /* release hostage */
- } /* zds->hostageByte */
- return 0;
- } /* zds->outEnd == zds->outStart */
- if (!zds->hostageByte) { /* output not fully flushed; keep last byte as hostage; will be released when all output is flushed */
- input->pos--; /* note : pos > 0, otherwise, impossible to finish reading last block */
- zds->hostageByte=1;
- }
- return 1;
- } /* nextSrcSizeHint==0 */
- nextSrcSizeHint += ZSTD_blockHeaderSize * (ZSTD_nextInputType(zds) == ZSTDnit_block); /* preload header of next block */
- assert(zds->inPos <= nextSrcSizeHint);
- nextSrcSizeHint -= zds->inPos; /* part already loaded*/
- return nextSrcSizeHint;
- }
-}
-
-size_t ZSTD_decompressStream_simpleArgs (
- ZSTD_DCtx* dctx,
- void* dst, size_t dstCapacity, size_t* dstPos,
- const void* src, size_t srcSize, size_t* srcPos)
-{
- ZSTD_outBuffer output = { dst, dstCapacity, *dstPos };
- ZSTD_inBuffer input = { src, srcSize, *srcPos };
- /* ZSTD_compress_generic() will check validity of dstPos and srcPos */
- size_t const cErr = ZSTD_decompressStream(dctx, &output, &input);
- *dstPos = output.pos;
- *srcPos = input.pos;
- return cErr;
-}
-/**** ended inlining decompress/zstd_decompress.c ****/
-/**** start inlining decompress/zstd_decompress_block.c ****/
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under both the BSD-style license (found in the
- * LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
- * You may select, at your option, one of the above-listed licenses.
- */
-
-/* zstd_decompress_block :
- * this module takes care of decompressing _compressed_ block */
-
-/*-*******************************************************
-* Dependencies
-*********************************************************/
-#include <string.h> /* memcpy, memmove, memset */
-/**** skipping file: ../common/compiler.h ****/
-/**** skipping file: ../common/cpu.h ****/
-/**** skipping file: ../common/mem.h ****/
-#define FSE_STATIC_LINKING_ONLY
-/**** skipping file: ../common/fse.h ****/
-#define HUF_STATIC_LINKING_ONLY
-/**** skipping file: ../common/huf.h ****/
-/**** skipping file: ../common/zstd_internal.h ****/
-/**** skipping file: zstd_decompress_internal.h ****/
-/**** skipping file: zstd_ddict.h ****/
-/**** skipping file: zstd_decompress_block.h ****/
-
-/*_*******************************************************
-* Macros
-**********************************************************/
-
-/* These two optional macros force the use one way or another of the two
- * ZSTD_decompressSequences implementations. You can't force in both directions
- * at the same time.
- */
-#if defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \
- defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG)
-#error "Cannot force the use of the short and the long ZSTD_decompressSequences variants!"
-#endif
-
-
-/*_*******************************************************
-* Memory operations
-**********************************************************/
-static void ZSTD_copy4(void* dst, const void* src) { memcpy(dst, src, 4); }
-
-
-/*-*************************************************************
- * Block decoding
- ***************************************************************/
-
-/*! ZSTD_getcBlockSize() :
- * Provides the size of compressed block from block header `src` */
-size_t ZSTD_getcBlockSize(const void* src, size_t srcSize,
- blockProperties_t* bpPtr)
-{
- RETURN_ERROR_IF(srcSize < ZSTD_blockHeaderSize, srcSize_wrong, "");
-
- { U32 const cBlockHeader = MEM_readLE24(src);
- U32 const cSize = cBlockHeader >> 3;
- bpPtr->lastBlock = cBlockHeader & 1;
- bpPtr->blockType = (blockType_e)((cBlockHeader >> 1) & 3);
- bpPtr->origSize = cSize; /* only useful for RLE */
- if (bpPtr->blockType == bt_rle) return 1;
- RETURN_ERROR_IF(bpPtr->blockType == bt_reserved, corruption_detected, "");
- return cSize;
- }
-}
-
-
-/* Hidden declaration for fullbench */
-size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
- const void* src, size_t srcSize);
-/*! ZSTD_decodeLiteralsBlock() :
- * @return : nb of bytes read from src (< srcSize )
- * note : symbol not declared but exposed for fullbench */
-size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
- const void* src, size_t srcSize) /* note : srcSize < BLOCKSIZE */
-{
- DEBUGLOG(5, "ZSTD_decodeLiteralsBlock");
- RETURN_ERROR_IF(srcSize < MIN_CBLOCK_SIZE, corruption_detected, "");
-
- { const BYTE* const istart = (const BYTE*) src;
- symbolEncodingType_e const litEncType = (symbolEncodingType_e)(istart[0] & 3);
-
- switch(litEncType)
- {
- case set_repeat:
- DEBUGLOG(5, "set_repeat flag : re-using stats from previous compressed literals block");
- RETURN_ERROR_IF(dctx->litEntropy==0, dictionary_corrupted, "");
- /* fall-through */
-
- case set_compressed:
- RETURN_ERROR_IF(srcSize < 5, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 3; here we need up to 5 for case 3");
- { size_t lhSize, litSize, litCSize;
- U32 singleStream=0;
- U32 const lhlCode = (istart[0] >> 2) & 3;
- U32 const lhc = MEM_readLE32(istart);
- size_t hufSuccess;
- switch(lhlCode)
- {
- case 0: case 1: default: /* note : default is impossible, since lhlCode into [0..3] */
- /* 2 - 2 - 10 - 10 */
- singleStream = !lhlCode;
- lhSize = 3;
- litSize = (lhc >> 4) & 0x3FF;
- litCSize = (lhc >> 14) & 0x3FF;
- break;
- case 2:
- /* 2 - 2 - 14 - 14 */
- lhSize = 4;
- litSize = (lhc >> 4) & 0x3FFF;
- litCSize = lhc >> 18;
- break;
- case 3:
- /* 2 - 2 - 18 - 18 */
- lhSize = 5;
- litSize = (lhc >> 4) & 0x3FFFF;
- litCSize = (lhc >> 22) + ((size_t)istart[4] << 10);
- break;
- }
- RETURN_ERROR_IF(litSize > ZSTD_BLOCKSIZE_MAX, corruption_detected, "");
- RETURN_ERROR_IF(litCSize + lhSize > srcSize, corruption_detected, "");
-
- /* prefetch huffman table if cold */
- if (dctx->ddictIsCold && (litSize > 768 /* heuristic */)) {
- PREFETCH_AREA(dctx->HUFptr, sizeof(dctx->entropy.hufTable));
- }
-
- if (litEncType==set_repeat) {
- if (singleStream) {
- hufSuccess = HUF_decompress1X_usingDTable_bmi2(
- dctx->litBuffer, litSize, istart+lhSize, litCSize,
- dctx->HUFptr, dctx->bmi2);
- } else {
- hufSuccess = HUF_decompress4X_usingDTable_bmi2(
- dctx->litBuffer, litSize, istart+lhSize, litCSize,
- dctx->HUFptr, dctx->bmi2);
- }
- } else {
- if (singleStream) {
-#if defined(HUF_FORCE_DECOMPRESS_X2)
- hufSuccess = HUF_decompress1X_DCtx_wksp(
- dctx->entropy.hufTable, dctx->litBuffer, litSize,
- istart+lhSize, litCSize, dctx->workspace,
- sizeof(dctx->workspace));
-#else
- hufSuccess = HUF_decompress1X1_DCtx_wksp_bmi2(
- dctx->entropy.hufTable, dctx->litBuffer, litSize,
- istart+lhSize, litCSize, dctx->workspace,
- sizeof(dctx->workspace), dctx->bmi2);
-#endif
- } else {
- hufSuccess = HUF_decompress4X_hufOnly_wksp_bmi2(
- dctx->entropy.hufTable, dctx->litBuffer, litSize,
- istart+lhSize, litCSize, dctx->workspace,
- sizeof(dctx->workspace), dctx->bmi2);
- }
- }
-
- RETURN_ERROR_IF(HUF_isError(hufSuccess), corruption_detected, "");
-
- dctx->litPtr = dctx->litBuffer;
- dctx->litSize = litSize;
- dctx->litEntropy = 1;
- if (litEncType==set_compressed) dctx->HUFptr = dctx->entropy.hufTable;
- memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH);
- return litCSize + lhSize;
- }
-
- case set_basic:
- { size_t litSize, lhSize;
- U32 const lhlCode = ((istart[0]) >> 2) & 3;
- switch(lhlCode)
- {
- case 0: case 2: default: /* note : default is impossible, since lhlCode into [0..3] */
- lhSize = 1;
- litSize = istart[0] >> 3;
- break;
- case 1:
- lhSize = 2;
- litSize = MEM_readLE16(istart) >> 4;
- break;
- case 3:
- lhSize = 3;
- litSize = MEM_readLE24(istart) >> 4;
- break;
- }
-
- if (lhSize+litSize+WILDCOPY_OVERLENGTH > srcSize) { /* risk reading beyond src buffer with wildcopy */
- RETURN_ERROR_IF(litSize+lhSize > srcSize, corruption_detected, "");
- memcpy(dctx->litBuffer, istart+lhSize, litSize);
- dctx->litPtr = dctx->litBuffer;
- dctx->litSize = litSize;
- memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH);
- return lhSize+litSize;
- }
- /* direct reference into compressed stream */
- dctx->litPtr = istart+lhSize;
- dctx->litSize = litSize;
- return lhSize+litSize;
- }
-
- case set_rle:
- { U32 const lhlCode = ((istart[0]) >> 2) & 3;
- size_t litSize, lhSize;
- switch(lhlCode)
- {
- case 0: case 2: default: /* note : default is impossible, since lhlCode into [0..3] */
- lhSize = 1;
- litSize = istart[0] >> 3;
- break;
- case 1:
- lhSize = 2;
- litSize = MEM_readLE16(istart) >> 4;
- break;
- case 3:
- lhSize = 3;
- litSize = MEM_readLE24(istart) >> 4;
- RETURN_ERROR_IF(srcSize<4, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 3; here we need lhSize+1 = 4");
- break;
- }
- RETURN_ERROR_IF(litSize > ZSTD_BLOCKSIZE_MAX, corruption_detected, "");
- memset(dctx->litBuffer, istart[lhSize], litSize + WILDCOPY_OVERLENGTH);
- dctx->litPtr = dctx->litBuffer;
- dctx->litSize = litSize;
- return lhSize+1;
- }
- default:
- RETURN_ERROR(corruption_detected, "impossible");
- }
- }
-}
-
-/* Default FSE distribution tables.
- * These are pre-calculated FSE decoding tables using default distributions as defined in specification :
- * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#default-distributions
- * They were generated programmatically with following method :
- * - start from default distributions, present in /lib/common/zstd_internal.h
- * - generate tables normally, using ZSTD_buildFSETable()
- * - printout the content of tables
- * - pretify output, report below, test with fuzzer to ensure it's correct */
-
-/* Default FSE distribution table for Literal Lengths */
-static const ZSTD_seqSymbol LL_defaultDTable[(1<<LL_DEFAULTNORMLOG)+1] = {
- { 1, 1, 1, LL_DEFAULTNORMLOG}, /* header : fastMode, tableLog */
- /* nextState, nbAddBits, nbBits, baseVal */
- { 0, 0, 4, 0}, { 16, 0, 4, 0},
- { 32, 0, 5, 1}, { 0, 0, 5, 3},
- { 0, 0, 5, 4}, { 0, 0, 5, 6},
- { 0, 0, 5, 7}, { 0, 0, 5, 9},
- { 0, 0, 5, 10}, { 0, 0, 5, 12},
- { 0, 0, 6, 14}, { 0, 1, 5, 16},
- { 0, 1, 5, 20}, { 0, 1, 5, 22},
- { 0, 2, 5, 28}, { 0, 3, 5, 32},
- { 0, 4, 5, 48}, { 32, 6, 5, 64},
- { 0, 7, 5, 128}, { 0, 8, 6, 256},
- { 0, 10, 6, 1024}, { 0, 12, 6, 4096},
- { 32, 0, 4, 0}, { 0, 0, 4, 1},
- { 0, 0, 5, 2}, { 32, 0, 5, 4},
- { 0, 0, 5, 5}, { 32, 0, 5, 7},
- { 0, 0, 5, 8}, { 32, 0, 5, 10},
- { 0, 0, 5, 11}, { 0, 0, 6, 13},
- { 32, 1, 5, 16}, { 0, 1, 5, 18},
- { 32, 1, 5, 22}, { 0, 2, 5, 24},
- { 32, 3, 5, 32}, { 0, 3, 5, 40},
- { 0, 6, 4, 64}, { 16, 6, 4, 64},
- { 32, 7, 5, 128}, { 0, 9, 6, 512},
- { 0, 11, 6, 2048}, { 48, 0, 4, 0},
- { 16, 0, 4, 1}, { 32, 0, 5, 2},
- { 32, 0, 5, 3}, { 32, 0, 5, 5},
- { 32, 0, 5, 6}, { 32, 0, 5, 8},
- { 32, 0, 5, 9}, { 32, 0, 5, 11},
- { 32, 0, 5, 12}, { 0, 0, 6, 15},
- { 32, 1, 5, 18}, { 32, 1, 5, 20},
- { 32, 2, 5, 24}, { 32, 2, 5, 28},
- { 32, 3, 5, 40}, { 32, 4, 5, 48},
- { 0, 16, 6,65536}, { 0, 15, 6,32768},
- { 0, 14, 6,16384}, { 0, 13, 6, 8192},
-}; /* LL_defaultDTable */
-
-/* Default FSE distribution table for Offset Codes */
-static const ZSTD_seqSymbol OF_defaultDTable[(1<<OF_DEFAULTNORMLOG)+1] = {
- { 1, 1, 1, OF_DEFAULTNORMLOG}, /* header : fastMode, tableLog */
- /* nextState, nbAddBits, nbBits, baseVal */
- { 0, 0, 5, 0}, { 0, 6, 4, 61},
- { 0, 9, 5, 509}, { 0, 15, 5,32765},
- { 0, 21, 5,2097149}, { 0, 3, 5, 5},
- { 0, 7, 4, 125}, { 0, 12, 5, 4093},
- { 0, 18, 5,262141}, { 0, 23, 5,8388605},
- { 0, 5, 5, 29}, { 0, 8, 4, 253},
- { 0, 14, 5,16381}, { 0, 20, 5,1048573},
- { 0, 2, 5, 1}, { 16, 7, 4, 125},
- { 0, 11, 5, 2045}, { 0, 17, 5,131069},
- { 0, 22, 5,4194301}, { 0, 4, 5, 13},
- { 16, 8, 4, 253}, { 0, 13, 5, 8189},
- { 0, 19, 5,524285}, { 0, 1, 5, 1},
- { 16, 6, 4, 61}, { 0, 10, 5, 1021},
- { 0, 16, 5,65533}, { 0, 28, 5,268435453},
- { 0, 27, 5,134217725}, { 0, 26, 5,67108861},
- { 0, 25, 5,33554429}, { 0, 24, 5,16777213},
-}; /* OF_defaultDTable */
-
-
-/* Default FSE distribution table for Match Lengths */
-static const ZSTD_seqSymbol ML_defaultDTable[(1<<ML_DEFAULTNORMLOG)+1] = {
- { 1, 1, 1, ML_DEFAULTNORMLOG}, /* header : fastMode, tableLog */
- /* nextState, nbAddBits, nbBits, baseVal */
- { 0, 0, 6, 3}, { 0, 0, 4, 4},
- { 32, 0, 5, 5}, { 0, 0, 5, 6},
- { 0, 0, 5, 8}, { 0, 0, 5, 9},
- { 0, 0, 5, 11}, { 0, 0, 6, 13},
- { 0, 0, 6, 16}, { 0, 0, 6, 19},
- { 0, 0, 6, 22}, { 0, 0, 6, 25},
- { 0, 0, 6, 28}, { 0, 0, 6, 31},
- { 0, 0, 6, 34}, { 0, 1, 6, 37},
- { 0, 1, 6, 41}, { 0, 2, 6, 47},
- { 0, 3, 6, 59}, { 0, 4, 6, 83},
- { 0, 7, 6, 131}, { 0, 9, 6, 515},
- { 16, 0, 4, 4}, { 0, 0, 4, 5},
- { 32, 0, 5, 6}, { 0, 0, 5, 7},
- { 32, 0, 5, 9}, { 0, 0, 5, 10},
- { 0, 0, 6, 12}, { 0, 0, 6, 15},
- { 0, 0, 6, 18}, { 0, 0, 6, 21},
- { 0, 0, 6, 24}, { 0, 0, 6, 27},
- { 0, 0, 6, 30}, { 0, 0, 6, 33},
- { 0, 1, 6, 35}, { 0, 1, 6, 39},
- { 0, 2, 6, 43}, { 0, 3, 6, 51},
- { 0, 4, 6, 67}, { 0, 5, 6, 99},
- { 0, 8, 6, 259}, { 32, 0, 4, 4},
- { 48, 0, 4, 4}, { 16, 0, 4, 5},
- { 32, 0, 5, 7}, { 32, 0, 5, 8},
- { 32, 0, 5, 10}, { 32, 0, 5, 11},
- { 0, 0, 6, 14}, { 0, 0, 6, 17},
- { 0, 0, 6, 20}, { 0, 0, 6, 23},
- { 0, 0, 6, 26}, { 0, 0, 6, 29},
- { 0, 0, 6, 32}, { 0, 16, 6,65539},
- { 0, 15, 6,32771}, { 0, 14, 6,16387},
- { 0, 13, 6, 8195}, { 0, 12, 6, 4099},
- { 0, 11, 6, 2051}, { 0, 10, 6, 1027},
-}; /* ML_defaultDTable */
-
-
-static void ZSTD_buildSeqTable_rle(ZSTD_seqSymbol* dt, U32 baseValue, U32 nbAddBits)
-{
- void* ptr = dt;
- ZSTD_seqSymbol_header* const DTableH = (ZSTD_seqSymbol_header*)ptr;
- ZSTD_seqSymbol* const cell = dt + 1;
-
- DTableH->tableLog = 0;
- DTableH->fastMode = 0;
-
- cell->nbBits = 0;
- cell->nextState = 0;
- assert(nbAddBits < 255);
- cell->nbAdditionalBits = (BYTE)nbAddBits;
- cell->baseValue = baseValue;
-}
-
-
-/* ZSTD_buildFSETable() :
- * generate FSE decoding table for one symbol (ll, ml or off)
- * cannot fail if input is valid =>
- * all inputs are presumed validated at this stage */
-void
-ZSTD_buildFSETable(ZSTD_seqSymbol* dt,
- const short* normalizedCounter, unsigned maxSymbolValue,
- const U32* baseValue, const U32* nbAdditionalBits,
- unsigned tableLog)
-{
- ZSTD_seqSymbol* const tableDecode = dt+1;
- U16 symbolNext[MaxSeq+1];
-
- U32 const maxSV1 = maxSymbolValue + 1;
- U32 const tableSize = 1 << tableLog;
- U32 highThreshold = tableSize-1;
-
- /* Sanity Checks */
- assert(maxSymbolValue <= MaxSeq);
- assert(tableLog <= MaxFSELog);
-
- /* Init, lay down lowprob symbols */
- { ZSTD_seqSymbol_header DTableH;
- DTableH.tableLog = tableLog;
- DTableH.fastMode = 1;
- { S16 const largeLimit= (S16)(1 << (tableLog-1));
- U32 s;
- for (s=0; s<maxSV1; s++) {
- if (normalizedCounter[s]==-1) {
- tableDecode[highThreshold--].baseValue = s;
- symbolNext[s] = 1;
- } else {
- if (normalizedCounter[s] >= largeLimit) DTableH.fastMode=0;
- assert(normalizedCounter[s]>=0);
- symbolNext[s] = (U16)normalizedCounter[s];
- } } }
- memcpy(dt, &DTableH, sizeof(DTableH));
- }
-
- /* Spread symbols */
- { U32 const tableMask = tableSize-1;
- U32 const step = FSE_TABLESTEP(tableSize);
- U32 s, position = 0;
- for (s=0; s<maxSV1; s++) {
- int i;
- for (i=0; i<normalizedCounter[s]; i++) {
- tableDecode[position].baseValue = s;
- position = (position + step) & tableMask;
- while (position > highThreshold) position = (position + step) & tableMask; /* lowprob area */
- } }
- assert(position == 0); /* position must reach all cells once, otherwise normalizedCounter is incorrect */
- }
-
- /* Build Decoding table */
- { U32 u;
- for (u=0; u<tableSize; u++) {
- U32 const symbol = tableDecode[u].baseValue;
- U32 const nextState = symbolNext[symbol]++;
- tableDecode[u].nbBits = (BYTE) (tableLog - BIT_highbit32(nextState) );
- tableDecode[u].nextState = (U16) ( (nextState << tableDecode[u].nbBits) - tableSize);
- assert(nbAdditionalBits[symbol] < 255);
- tableDecode[u].nbAdditionalBits = (BYTE)nbAdditionalBits[symbol];
- tableDecode[u].baseValue = baseValue[symbol];
- } }
-}
-
-
-/*! ZSTD_buildSeqTable() :
- * @return : nb bytes read from src,
- * or an error code if it fails */
-static size_t ZSTD_buildSeqTable(ZSTD_seqSymbol* DTableSpace, const ZSTD_seqSymbol** DTablePtr,
- symbolEncodingType_e type, unsigned max, U32 maxLog,
- const void* src, size_t srcSize,
- const U32* baseValue, const U32* nbAdditionalBits,
- const ZSTD_seqSymbol* defaultTable, U32 flagRepeatTable,
- int ddictIsCold, int nbSeq)
-{
- switch(type)
- {
- case set_rle :
- RETURN_ERROR_IF(!srcSize, srcSize_wrong, "");
- RETURN_ERROR_IF((*(const BYTE*)src) > max, corruption_detected, "");
- { U32 const symbol = *(const BYTE*)src;
- U32 const baseline = baseValue[symbol];
- U32 const nbBits = nbAdditionalBits[symbol];
- ZSTD_buildSeqTable_rle(DTableSpace, baseline, nbBits);
- }
- *DTablePtr = DTableSpace;
- return 1;
- case set_basic :
- *DTablePtr = defaultTable;
- return 0;
- case set_repeat:
- RETURN_ERROR_IF(!flagRepeatTable, corruption_detected, "");
- /* prefetch FSE table if used */
- if (ddictIsCold && (nbSeq > 24 /* heuristic */)) {
- const void* const pStart = *DTablePtr;
- size_t const pSize = sizeof(ZSTD_seqSymbol) * (SEQSYMBOL_TABLE_SIZE(maxLog));
- PREFETCH_AREA(pStart, pSize);
- }
- return 0;
- case set_compressed :
- { unsigned tableLog;
- S16 norm[MaxSeq+1];
- size_t const headerSize = FSE_readNCount(norm, &max, &tableLog, src, srcSize);
- RETURN_ERROR_IF(FSE_isError(headerSize), corruption_detected, "");
- RETURN_ERROR_IF(tableLog > maxLog, corruption_detected, "");
- ZSTD_buildFSETable(DTableSpace, norm, max, baseValue, nbAdditionalBits, tableLog);
- *DTablePtr = DTableSpace;
- return headerSize;
- }
- default :
- assert(0);
- RETURN_ERROR(GENERIC, "impossible");
- }
-}
-
-size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr,
- const void* src, size_t srcSize)
-{
- const BYTE* const istart = (const BYTE* const)src;
- const BYTE* const iend = istart + srcSize;
- const BYTE* ip = istart;
- int nbSeq;
- DEBUGLOG(5, "ZSTD_decodeSeqHeaders");
-
- /* check */
- RETURN_ERROR_IF(srcSize < MIN_SEQUENCES_SIZE, srcSize_wrong, "");
-
- /* SeqHead */
- nbSeq = *ip++;
- if (!nbSeq) {
- *nbSeqPtr=0;
- RETURN_ERROR_IF(srcSize != 1, srcSize_wrong, "");
- return 1;
- }
- if (nbSeq > 0x7F) {
- if (nbSeq == 0xFF) {
- RETURN_ERROR_IF(ip+2 > iend, srcSize_wrong, "");
- nbSeq = MEM_readLE16(ip) + LONGNBSEQ, ip+=2;
- } else {
- RETURN_ERROR_IF(ip >= iend, srcSize_wrong, "");
- nbSeq = ((nbSeq-0x80)<<8) + *ip++;
- }
- }
- *nbSeqPtr = nbSeq;
-
- /* FSE table descriptors */
- RETURN_ERROR_IF(ip+1 > iend, srcSize_wrong, ""); /* minimum possible size: 1 byte for symbol encoding types */
- { symbolEncodingType_e const LLtype = (symbolEncodingType_e)(*ip >> 6);
- symbolEncodingType_e const OFtype = (symbolEncodingType_e)((*ip >> 4) & 3);
- symbolEncodingType_e const MLtype = (symbolEncodingType_e)((*ip >> 2) & 3);
- ip++;
-
- /* Build DTables */
- { size_t const llhSize = ZSTD_buildSeqTable(dctx->entropy.LLTable, &dctx->LLTptr,
- LLtype, MaxLL, LLFSELog,
- ip, iend-ip,
- LL_base, LL_bits,
- LL_defaultDTable, dctx->fseEntropy,
- dctx->ddictIsCold, nbSeq);
- RETURN_ERROR_IF(ZSTD_isError(llhSize), corruption_detected, "ZSTD_buildSeqTable failed");
- ip += llhSize;
- }
-
- { size_t const ofhSize = ZSTD_buildSeqTable(dctx->entropy.OFTable, &dctx->OFTptr,
- OFtype, MaxOff, OffFSELog,
- ip, iend-ip,
- OF_base, OF_bits,
- OF_defaultDTable, dctx->fseEntropy,
- dctx->ddictIsCold, nbSeq);
- RETURN_ERROR_IF(ZSTD_isError(ofhSize), corruption_detected, "ZSTD_buildSeqTable failed");
- ip += ofhSize;
- }
-
- { size_t const mlhSize = ZSTD_buildSeqTable(dctx->entropy.MLTable, &dctx->MLTptr,
- MLtype, MaxML, MLFSELog,
- ip, iend-ip,
- ML_base, ML_bits,
- ML_defaultDTable, dctx->fseEntropy,
- dctx->ddictIsCold, nbSeq);
- RETURN_ERROR_IF(ZSTD_isError(mlhSize), corruption_detected, "ZSTD_buildSeqTable failed");
- ip += mlhSize;
- }
- }
-
- return ip-istart;
-}
-
-
-typedef struct {
- size_t litLength;
- size_t matchLength;
- size_t offset;
- const BYTE* match;
-} seq_t;
-
-typedef struct {
- size_t state;
- const ZSTD_seqSymbol* table;
-} ZSTD_fseState;
-
-typedef struct {
- BIT_DStream_t DStream;
- ZSTD_fseState stateLL;
- ZSTD_fseState stateOffb;
- ZSTD_fseState stateML;
- size_t prevOffset[ZSTD_REP_NUM];
- const BYTE* prefixStart;
- const BYTE* dictEnd;
- size_t pos;
-} seqState_t;
-
-/*! ZSTD_overlapCopy8() :
- * Copies 8 bytes from ip to op and updates op and ip where ip <= op.
- * If the offset is < 8 then the offset is spread to at least 8 bytes.
- *
- * Precondition: *ip <= *op
- * Postcondition: *op - *op >= 8
- */
-HINT_INLINE void ZSTD_overlapCopy8(BYTE** op, BYTE const** ip, size_t offset) {
- assert(*ip <= *op);
- if (offset < 8) {
- /* close range match, overlap */
- static const U32 dec32table[] = { 0, 1, 2, 1, 4, 4, 4, 4 }; /* added */
- static const int dec64table[] = { 8, 8, 8, 7, 8, 9,10,11 }; /* subtracted */
- int const sub2 = dec64table[offset];
- (*op)[0] = (*ip)[0];
- (*op)[1] = (*ip)[1];
- (*op)[2] = (*ip)[2];
- (*op)[3] = (*ip)[3];
- *ip += dec32table[offset];
- ZSTD_copy4(*op+4, *ip);
- *ip -= sub2;
- } else {
- ZSTD_copy8(*op, *ip);
- }
- *ip += 8;
- *op += 8;
- assert(*op - *ip >= 8);
-}
-
-/*! ZSTD_safecopy() :
- * Specialized version of memcpy() that is allowed to READ up to WILDCOPY_OVERLENGTH past the input buffer
- * and write up to 16 bytes past oend_w (op >= oend_w is allowed).
- * This function is only called in the uncommon case where the sequence is near the end of the block. It
- * should be fast for a single long sequence, but can be slow for several short sequences.
- *
- * @param ovtype controls the overlap detection
- * - ZSTD_no_overlap: The source and destination are guaranteed to be at least WILDCOPY_VECLEN bytes apart.
- * - ZSTD_overlap_src_before_dst: The src and dst may overlap and may be any distance apart.
- * The src buffer must be before the dst buffer.
- */
-static void ZSTD_safecopy(BYTE* op, BYTE* const oend_w, BYTE const* ip, ptrdiff_t length, ZSTD_overlap_e ovtype) {
- ptrdiff_t const diff = op - ip;
- BYTE* const oend = op + length;
-
- assert((ovtype == ZSTD_no_overlap && (diff <= -8 || diff >= 8 || op >= oend_w)) ||
- (ovtype == ZSTD_overlap_src_before_dst && diff >= 0));
-
- if (length < 8) {
- /* Handle short lengths. */
- while (op < oend) *op++ = *ip++;
- return;
- }
- if (ovtype == ZSTD_overlap_src_before_dst) {
- /* Copy 8 bytes and ensure the offset >= 8 when there can be overlap. */
- assert(length >= 8);
- ZSTD_overlapCopy8(&op, &ip, diff);
- assert(op - ip >= 8);
- assert(op <= oend);
- }
-
- if (oend <= oend_w) {
- /* No risk of overwrite. */
- ZSTD_wildcopy(op, ip, length, ovtype);
- return;
- }
- if (op <= oend_w) {
- /* Wildcopy until we get close to the end. */
- assert(oend > oend_w);
- ZSTD_wildcopy(op, ip, oend_w - op, ovtype);
- ip += oend_w - op;
- op = oend_w;
- }
- /* Handle the leftovers. */
- while (op < oend) *op++ = *ip++;
-}
-
-/* ZSTD_execSequenceEnd():
- * This version handles cases that are near the end of the output buffer. It requires
- * more careful checks to make sure there is no overflow. By separating out these hard
- * and unlikely cases, we can speed up the common cases.
- *
- * NOTE: This function needs to be fast for a single long sequence, but doesn't need
- * to be optimized for many small sequences, since those fall into ZSTD_execSequence().
- */
-FORCE_NOINLINE
-size_t ZSTD_execSequenceEnd(BYTE* op,
- BYTE* const oend, seq_t sequence,
- const BYTE** litPtr, const BYTE* const litLimit,
- const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd)
-{
- BYTE* const oLitEnd = op + sequence.litLength;
- size_t const sequenceLength = sequence.litLength + sequence.matchLength;
- const BYTE* const iLitEnd = *litPtr + sequence.litLength;
- const BYTE* match = oLitEnd - sequence.offset;
- BYTE* const oend_w = oend - WILDCOPY_OVERLENGTH;
-
- /* bounds checks : careful of address space overflow in 32-bit mode */
- RETURN_ERROR_IF(sequenceLength > (size_t)(oend - op), dstSize_tooSmall, "last match must fit within dstBuffer");
- RETURN_ERROR_IF(sequence.litLength > (size_t)(litLimit - *litPtr), corruption_detected, "try to read beyond literal buffer");
- assert(op < op + sequenceLength);
- assert(oLitEnd < op + sequenceLength);
-
- /* copy literals */
- ZSTD_safecopy(op, oend_w, *litPtr, sequence.litLength, ZSTD_no_overlap);
- op = oLitEnd;
- *litPtr = iLitEnd;
-
- /* copy Match */
- if (sequence.offset > (size_t)(oLitEnd - prefixStart)) {
- /* offset beyond prefix */
- RETURN_ERROR_IF(sequence.offset > (size_t)(oLitEnd - virtualStart), corruption_detected, "");
- match = dictEnd - (prefixStart-match);
- if (match + sequence.matchLength <= dictEnd) {
- memmove(oLitEnd, match, sequence.matchLength);
- return sequenceLength;
- }
- /* span extDict & currentPrefixSegment */
- { size_t const length1 = dictEnd - match;
- memmove(oLitEnd, match, length1);
- op = oLitEnd + length1;
- sequence.matchLength -= length1;
- match = prefixStart;
- } }
- ZSTD_safecopy(op, oend_w, match, sequence.matchLength, ZSTD_overlap_src_before_dst);
- return sequenceLength;
-}
-
-HINT_INLINE
-size_t ZSTD_execSequence(BYTE* op,
- BYTE* const oend, seq_t sequence,
- const BYTE** litPtr, const BYTE* const litLimit,
- const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd)
-{
- BYTE* const oLitEnd = op + sequence.litLength;
- size_t const sequenceLength = sequence.litLength + sequence.matchLength;
- BYTE* const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */
- BYTE* const oend_w = oend - WILDCOPY_OVERLENGTH; /* risk : address space underflow on oend=NULL */
- const BYTE* const iLitEnd = *litPtr + sequence.litLength;
- const BYTE* match = oLitEnd - sequence.offset;
-
- assert(op != NULL /* Precondition */);
- assert(oend_w < oend /* No underflow */);
- /* Handle edge cases in a slow path:
- * - Read beyond end of literals
- * - Match end is within WILDCOPY_OVERLIMIT of oend
- * - 32-bit mode and the match length overflows
- */
- if (UNLIKELY(
- iLitEnd > litLimit ||
- oMatchEnd > oend_w ||
- (MEM_32bits() && (size_t)(oend - op) < sequenceLength + WILDCOPY_OVERLENGTH)))
- return ZSTD_execSequenceEnd(op, oend, sequence, litPtr, litLimit, prefixStart, virtualStart, dictEnd);
-
- /* Assumptions (everything else goes into ZSTD_execSequenceEnd()) */
- assert(op <= oLitEnd /* No overflow */);
- assert(oLitEnd < oMatchEnd /* Non-zero match & no overflow */);
- assert(oMatchEnd <= oend /* No underflow */);
- assert(iLitEnd <= litLimit /* Literal length is in bounds */);
- assert(oLitEnd <= oend_w /* Can wildcopy literals */);
- assert(oMatchEnd <= oend_w /* Can wildcopy matches */);
-
- /* Copy Literals:
- * Split out litLength <= 16 since it is nearly always true. +1.6% on gcc-9.
- * We likely don't need the full 32-byte wildcopy.
- */
- assert(WILDCOPY_OVERLENGTH >= 16);
- ZSTD_copy16(op, (*litPtr));
- if (UNLIKELY(sequence.litLength > 16)) {
- ZSTD_wildcopy(op+16, (*litPtr)+16, sequence.litLength-16, ZSTD_no_overlap);
- }
- op = oLitEnd;
- *litPtr = iLitEnd; /* update for next sequence */
-
- /* Copy Match */
- if (sequence.offset > (size_t)(oLitEnd - prefixStart)) {
- /* offset beyond prefix -> go into extDict */
- RETURN_ERROR_IF(UNLIKELY(sequence.offset > (size_t)(oLitEnd - virtualStart)), corruption_detected, "");
- match = dictEnd + (match - prefixStart);
- if (match + sequence.matchLength <= dictEnd) {
- memmove(oLitEnd, match, sequence.matchLength);
- return sequenceLength;
- }
- /* span extDict & currentPrefixSegment */
- { size_t const length1 = dictEnd - match;
- memmove(oLitEnd, match, length1);
- op = oLitEnd + length1;
- sequence.matchLength -= length1;
- match = prefixStart;
- } }
- /* Match within prefix of 1 or more bytes */
- assert(op <= oMatchEnd);
- assert(oMatchEnd <= oend_w);
- assert(match >= prefixStart);
- assert(sequence.matchLength >= 1);
-
- /* Nearly all offsets are >= WILDCOPY_VECLEN bytes, which means we can use wildcopy
- * without overlap checking.
- */
- if (LIKELY(sequence.offset >= WILDCOPY_VECLEN)) {
- /* We bet on a full wildcopy for matches, since we expect matches to be
- * longer than literals (in general). In silesia, ~10% of matches are longer
- * than 16 bytes.
- */
- ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength, ZSTD_no_overlap);
- return sequenceLength;
- }
- assert(sequence.offset < WILDCOPY_VECLEN);
-
- /* Copy 8 bytes and spread the offset to be >= 8. */
- ZSTD_overlapCopy8(&op, &match, sequence.offset);
-
- /* If the match length is > 8 bytes, then continue with the wildcopy. */
- if (sequence.matchLength > 8) {
- assert(op < oMatchEnd);
- ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength-8, ZSTD_overlap_src_before_dst);
- }
- return sequenceLength;
-}
-
-static void
-ZSTD_initFseState(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, const ZSTD_seqSymbol* dt)
-{
- const void* ptr = dt;
- const ZSTD_seqSymbol_header* const DTableH = (const ZSTD_seqSymbol_header*)ptr;
- DStatePtr->state = BIT_readBits(bitD, DTableH->tableLog);
- DEBUGLOG(6, "ZSTD_initFseState : val=%u using %u bits",
- (U32)DStatePtr->state, DTableH->tableLog);
- BIT_reloadDStream(bitD);
- DStatePtr->table = dt + 1;
-}
-
-FORCE_INLINE_TEMPLATE void
-ZSTD_updateFseState(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD)
-{
- ZSTD_seqSymbol const DInfo = DStatePtr->table[DStatePtr->state];
- U32 const nbBits = DInfo.nbBits;
- size_t const lowBits = BIT_readBits(bitD, nbBits);
- DStatePtr->state = DInfo.nextState + lowBits;
-}
-
-FORCE_INLINE_TEMPLATE void
-ZSTD_updateFseStateWithDInfo(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, ZSTD_seqSymbol const DInfo)
-{
- U32 const nbBits = DInfo.nbBits;
- size_t const lowBits = BIT_readBits(bitD, nbBits);
- DStatePtr->state = DInfo.nextState + lowBits;
-}
-
-/* We need to add at most (ZSTD_WINDOWLOG_MAX_32 - 1) bits to read the maximum
- * offset bits. But we can only read at most (STREAM_ACCUMULATOR_MIN_32 - 1)
- * bits before reloading. This value is the maximum number of bytes we read
- * after reloading when we are decoding long offsets.
- */
-#define LONG_OFFSETS_MAX_EXTRA_BITS_32 \
- (ZSTD_WINDOWLOG_MAX_32 > STREAM_ACCUMULATOR_MIN_32 \
- ? ZSTD_WINDOWLOG_MAX_32 - STREAM_ACCUMULATOR_MIN_32 \
- : 0)
-
-typedef enum { ZSTD_lo_isRegularOffset, ZSTD_lo_isLongOffset=1 } ZSTD_longOffset_e;
-typedef enum { ZSTD_p_noPrefetch=0, ZSTD_p_prefetch=1 } ZSTD_prefetch_e;
-
-FORCE_INLINE_TEMPLATE seq_t
-ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets, const ZSTD_prefetch_e prefetch)
-{
- seq_t seq;
- ZSTD_seqSymbol const llDInfo = seqState->stateLL.table[seqState->stateLL.state];
- ZSTD_seqSymbol const mlDInfo = seqState->stateML.table[seqState->stateML.state];
- ZSTD_seqSymbol const ofDInfo = seqState->stateOffb.table[seqState->stateOffb.state];
- U32 const llBase = llDInfo.baseValue;
- U32 const mlBase = mlDInfo.baseValue;
- U32 const ofBase = ofDInfo.baseValue;
- BYTE const llBits = llDInfo.nbAdditionalBits;
- BYTE const mlBits = mlDInfo.nbAdditionalBits;
- BYTE const ofBits = ofDInfo.nbAdditionalBits;
- BYTE const totalBits = llBits+mlBits+ofBits;
-
- /* sequence */
- { size_t offset;
- if (ofBits > 1) {
- ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1);
- ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5);
- assert(ofBits <= MaxOff);
- if (MEM_32bits() && longOffsets && (ofBits >= STREAM_ACCUMULATOR_MIN_32)) {
- U32 const extraBits = ofBits - MIN(ofBits, 32 - seqState->DStream.bitsConsumed);
- offset = ofBase + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits);
- BIT_reloadDStream(&seqState->DStream);
- if (extraBits) offset += BIT_readBitsFast(&seqState->DStream, extraBits);
- assert(extraBits <= LONG_OFFSETS_MAX_EXTRA_BITS_32); /* to avoid another reload */
- } else {
- offset = ofBase + BIT_readBitsFast(&seqState->DStream, ofBits/*>0*/); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */
- if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream);
- }
- seqState->prevOffset[2] = seqState->prevOffset[1];
- seqState->prevOffset[1] = seqState->prevOffset[0];
- seqState->prevOffset[0] = offset;
- } else {
- U32 const ll0 = (llBase == 0);
- if (LIKELY((ofBits == 0))) {
- if (LIKELY(!ll0))
- offset = seqState->prevOffset[0];
- else {
- offset = seqState->prevOffset[1];
- seqState->prevOffset[1] = seqState->prevOffset[0];
- seqState->prevOffset[0] = offset;
- }
- } else {
- offset = ofBase + ll0 + BIT_readBitsFast(&seqState->DStream, 1);
- { size_t temp = (offset==3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset];
- temp += !temp; /* 0 is not valid; input is corrupted; force offset to 1 */
- if (offset != 1) seqState->prevOffset[2] = seqState->prevOffset[1];
- seqState->prevOffset[1] = seqState->prevOffset[0];
- seqState->prevOffset[0] = offset = temp;
- } } }
- seq.offset = offset;
- }
-
- seq.matchLength = mlBase;
- if (mlBits > 0)
- seq.matchLength += BIT_readBitsFast(&seqState->DStream, mlBits/*>0*/);
-
- if (MEM_32bits() && (mlBits+llBits >= STREAM_ACCUMULATOR_MIN_32-LONG_OFFSETS_MAX_EXTRA_BITS_32))
- BIT_reloadDStream(&seqState->DStream);
- if (MEM_64bits() && UNLIKELY(totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog)))
- BIT_reloadDStream(&seqState->DStream);
- /* Ensure there are enough bits to read the rest of data in 64-bit mode. */
- ZSTD_STATIC_ASSERT(16+LLFSELog+MLFSELog+OffFSELog < STREAM_ACCUMULATOR_MIN_64);
-
- seq.litLength = llBase;
- if (llBits > 0)
- seq.litLength += BIT_readBitsFast(&seqState->DStream, llBits/*>0*/);
-
- if (MEM_32bits())
- BIT_reloadDStream(&seqState->DStream);
-
- DEBUGLOG(6, "seq: litL=%u, matchL=%u, offset=%u",
- (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset);
-
- if (prefetch == ZSTD_p_prefetch) {
- size_t const pos = seqState->pos + seq.litLength;
- const BYTE* const matchBase = (seq.offset > pos) ? seqState->dictEnd : seqState->prefixStart;
- seq.match = matchBase + pos - seq.offset; /* note : this operation can overflow when seq.offset is really too large, which can only happen when input is corrupted.
- * No consequence though : no memory access will occur, offset is only used for prefetching */
- seqState->pos = pos + seq.matchLength;
- }
-
- /* ANS state update
- * gcc-9.0.0 does 2.5% worse with ZSTD_updateFseStateWithDInfo().
- * clang-9.2.0 does 7% worse with ZSTD_updateFseState().
- * Naturally it seems like ZSTD_updateFseStateWithDInfo() should be the
- * better option, so it is the default for other compilers. But, if you
- * measure that it is worse, please put up a pull request.
- */
- {
-#if defined(__GNUC__) && !defined(__clang__)
- const int kUseUpdateFseState = 1;
-#else
- const int kUseUpdateFseState = 0;
-#endif
- if (kUseUpdateFseState) {
- ZSTD_updateFseState(&seqState->stateLL, &seqState->DStream); /* <= 9 bits */
- ZSTD_updateFseState(&seqState->stateML, &seqState->DStream); /* <= 9 bits */
- if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */
- ZSTD_updateFseState(&seqState->stateOffb, &seqState->DStream); /* <= 8 bits */
- } else {
- ZSTD_updateFseStateWithDInfo(&seqState->stateLL, &seqState->DStream, llDInfo); /* <= 9 bits */
- ZSTD_updateFseStateWithDInfo(&seqState->stateML, &seqState->DStream, mlDInfo); /* <= 9 bits */
- if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */
- ZSTD_updateFseStateWithDInfo(&seqState->stateOffb, &seqState->DStream, ofDInfo); /* <= 8 bits */
- }
- }
-
- return seq;
-}
-
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
-static int ZSTD_dictionaryIsActive(ZSTD_DCtx const* dctx, BYTE const* prefixStart, BYTE const* oLitEnd)
-{
- size_t const windowSize = dctx->fParams.windowSize;
- /* No dictionary used. */
- if (dctx->dictContentEndForFuzzing == NULL) return 0;
- /* Dictionary is our prefix. */
- if (prefixStart == dctx->dictContentBeginForFuzzing) return 1;
- /* Dictionary is not our ext-dict. */
- if (dctx->dictEnd != dctx->dictContentEndForFuzzing) return 0;
- /* Dictionary is not within our window size. */
- if ((size_t)(oLitEnd - prefixStart) >= windowSize) return 0;
- /* Dictionary is active. */
- return 1;
-}
-
-MEM_STATIC void ZSTD_assertValidSequence(
- ZSTD_DCtx const* dctx,
- BYTE const* op, BYTE const* oend,
- seq_t const seq,
- BYTE const* prefixStart, BYTE const* virtualStart)
-{
- size_t const windowSize = dctx->fParams.windowSize;
- size_t const sequenceSize = seq.litLength + seq.matchLength;
- BYTE const* const oLitEnd = op + seq.litLength;
- DEBUGLOG(6, "Checking sequence: litL=%u matchL=%u offset=%u",
- (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset);
- assert(op <= oend);
- assert((size_t)(oend - op) >= sequenceSize);
- assert(sequenceSize <= ZSTD_BLOCKSIZE_MAX);
- if (ZSTD_dictionaryIsActive(dctx, prefixStart, oLitEnd)) {
- size_t const dictSize = (size_t)((char const*)dctx->dictContentEndForFuzzing - (char const*)dctx->dictContentBeginForFuzzing);
- /* Offset must be within the dictionary. */
- assert(seq.offset <= (size_t)(oLitEnd - virtualStart));
- assert(seq.offset <= windowSize + dictSize);
- } else {
- /* Offset must be within our window. */
- assert(seq.offset <= windowSize);
- }
-}
-#endif
-
-#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG
-FORCE_INLINE_TEMPLATE size_t
-DONT_VECTORIZE
-ZSTD_decompressSequences_body( ZSTD_DCtx* dctx,
- void* dst, size_t maxDstSize,
- const void* seqStart, size_t seqSize, int nbSeq,
- const ZSTD_longOffset_e isLongOffset,
- const int frame)
-{
- const BYTE* ip = (const BYTE*)seqStart;
- const BYTE* const iend = ip + seqSize;
- BYTE* const ostart = (BYTE* const)dst;
- BYTE* const oend = ostart + maxDstSize;
- BYTE* op = ostart;
- const BYTE* litPtr = dctx->litPtr;
- const BYTE* const litEnd = litPtr + dctx->litSize;
- const BYTE* const prefixStart = (const BYTE*) (dctx->prefixStart);
- const BYTE* const vBase = (const BYTE*) (dctx->virtualStart);
- const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd);
- DEBUGLOG(5, "ZSTD_decompressSequences_body");
- (void)frame;
-
- /* Regen sequences */
- if (nbSeq) {
- seqState_t seqState;
- size_t error = 0;
- dctx->fseEntropy = 1;
- { U32 i; for (i=0; i<ZSTD_REP_NUM; i++) seqState.prevOffset[i] = dctx->entropy.rep[i]; }
- RETURN_ERROR_IF(
- ERR_isError(BIT_initDStream(&seqState.DStream, ip, iend-ip)),
- corruption_detected, "");
- ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr);
- ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr);
- ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr);
- assert(dst != NULL);
-
- ZSTD_STATIC_ASSERT(
- BIT_DStream_unfinished < BIT_DStream_completed &&
- BIT_DStream_endOfBuffer < BIT_DStream_completed &&
- BIT_DStream_completed < BIT_DStream_overflow);
-
-#if defined(__GNUC__) && defined(__x86_64__)
- /* Align the decompression loop to 32 + 16 bytes.
- *
- * zstd compiled with gcc-9 on an Intel i9-9900k shows 10% decompression
- * speed swings based on the alignment of the decompression loop. This
- * performance swing is caused by parts of the decompression loop falling
- * out of the DSB. The entire decompression loop should fit in the DSB,
- * when it can't we get much worse performance. You can measure if you've
- * hit the good case or the bad case with this perf command for some
- * compressed file test.zst:
- *
- * perf stat -e cycles -e instructions -e idq.all_dsb_cycles_any_uops \
- * -e idq.all_mite_cycles_any_uops -- ./zstd -tq test.zst
- *
- * If you see most cycles served out of the MITE you've hit the bad case.
- * If you see most cycles served out of the DSB you've hit the good case.
- * If it is pretty even then you may be in an okay case.
- *
- * I've been able to reproduce this issue on the following CPUs:
- * - Kabylake: Macbook Pro (15-inch, 2019) 2.4 GHz Intel Core i9
- * Use Instruments->Counters to get DSB/MITE cycles.
- * I never got performance swings, but I was able to
- * go from the good case of mostly DSB to half of the
- * cycles served from MITE.
- * - Coffeelake: Intel i9-9900k
- *
- * I haven't been able to reproduce the instability or DSB misses on any
- * of the following CPUS:
- * - Haswell
- * - Broadwell: Intel(R) Xeon(R) CPU E5-2680 v4 @ 2.40GH
- * - Skylake
- *
- * If you are seeing performance stability this script can help test.
- * It tests on 4 commits in zstd where I saw performance change.
- *
- * https://gist.github.com/terrelln/9889fc06a423fd5ca6e99351564473f4
- */
- __asm__(".p2align 5");
- __asm__("nop");
- __asm__(".p2align 4");
-#endif
- for ( ; ; ) {
- seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset, ZSTD_p_noPrefetch);
- size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litEnd, prefixStart, vBase, dictEnd);
-#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE)
- assert(!ZSTD_isError(oneSeqSize));
- if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase);
-#endif
- DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize);
- BIT_reloadDStream(&(seqState.DStream));
- /* gcc and clang both don't like early returns in this loop.
- * gcc doesn't like early breaks either.
- * Instead save an error and report it at the end.
- * When there is an error, don't increment op, so we don't
- * overwrite.
- */
- if (UNLIKELY(ZSTD_isError(oneSeqSize))) error = oneSeqSize;
- else op += oneSeqSize;
- if (UNLIKELY(!--nbSeq)) break;
- }
-
- /* check if reached exact end */
- DEBUGLOG(5, "ZSTD_decompressSequences_body: after decode loop, remaining nbSeq : %i", nbSeq);
- if (ZSTD_isError(error)) return error;
- RETURN_ERROR_IF(nbSeq, corruption_detected, "");
- RETURN_ERROR_IF(BIT_reloadDStream(&seqState.DStream) < BIT_DStream_completed, corruption_detected, "");
- /* save reps for next block */
- { U32 i; for (i=0; i<ZSTD_REP_NUM; i++) dctx->entropy.rep[i] = (U32)(seqState.prevOffset[i]); }
- }
-
- /* last literal segment */
- { size_t const lastLLSize = litEnd - litPtr;
- RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, "");
- if (op != NULL) {
- memcpy(op, litPtr, lastLLSize);
- op += lastLLSize;
- }
- }
-
- return op-ostart;
-}
-
-static size_t
-ZSTD_decompressSequences_default(ZSTD_DCtx* dctx,
- void* dst, size_t maxDstSize,
- const void* seqStart, size_t seqSize, int nbSeq,
- const ZSTD_longOffset_e isLongOffset,
- const int frame)
-{
- return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
-}
-#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */
-
-#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT
-FORCE_INLINE_TEMPLATE size_t
-ZSTD_decompressSequencesLong_body(
- ZSTD_DCtx* dctx,
- void* dst, size_t maxDstSize,
- const void* seqStart, size_t seqSize, int nbSeq,
- const ZSTD_longOffset_e isLongOffset,
- const int frame)
-{
- const BYTE* ip = (const BYTE*)seqStart;
- const BYTE* const iend = ip + seqSize;
- BYTE* const ostart = (BYTE* const)dst;
- BYTE* const oend = ostart + maxDstSize;
- BYTE* op = ostart;
- const BYTE* litPtr = dctx->litPtr;
- const BYTE* const litEnd = litPtr + dctx->litSize;
- const BYTE* const prefixStart = (const BYTE*) (dctx->prefixStart);
- const BYTE* const dictStart = (const BYTE*) (dctx->virtualStart);
- const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd);
- (void)frame;
-
- /* Regen sequences */
- if (nbSeq) {
-#define STORED_SEQS 4
-#define STORED_SEQS_MASK (STORED_SEQS-1)
-#define ADVANCED_SEQS 4
- seq_t sequences[STORED_SEQS];
- int const seqAdvance = MIN(nbSeq, ADVANCED_SEQS);
- seqState_t seqState;
- int seqNb;
- dctx->fseEntropy = 1;
- { int i; for (i=0; i<ZSTD_REP_NUM; i++) seqState.prevOffset[i] = dctx->entropy.rep[i]; }
- seqState.prefixStart = prefixStart;
- seqState.pos = (size_t)(op-prefixStart);
- seqState.dictEnd = dictEnd;
- assert(dst != NULL);
- assert(iend >= ip);
- RETURN_ERROR_IF(
- ERR_isError(BIT_initDStream(&seqState.DStream, ip, iend-ip)),
- corruption_detected, "");
- ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr);
- ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr);
- ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr);
-
- /* prepare in advance */
- for (seqNb=0; (BIT_reloadDStream(&seqState.DStream) <= BIT_DStream_completed) && (seqNb<seqAdvance); seqNb++) {
- sequences[seqNb] = ZSTD_decodeSequence(&seqState, isLongOffset, ZSTD_p_prefetch);
- PREFETCH_L1(sequences[seqNb].match); PREFETCH_L1(sequences[seqNb].match + sequences[seqNb].matchLength - 1); /* note : it's safe to invoke PREFETCH() on any memory address, including invalid ones */
- }
- RETURN_ERROR_IF(seqNb<seqAdvance, corruption_detected, "");
-
- /* decode and decompress */
- for ( ; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && (seqNb<nbSeq) ; seqNb++) {
- seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset, ZSTD_p_prefetch);
- size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequences[(seqNb-ADVANCED_SEQS) & STORED_SEQS_MASK], &litPtr, litEnd, prefixStart, dictStart, dictEnd);
-#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE)
- assert(!ZSTD_isError(oneSeqSize));
- if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[(seqNb-ADVANCED_SEQS) & STORED_SEQS_MASK], prefixStart, dictStart);
-#endif
- if (ZSTD_isError(oneSeqSize)) return oneSeqSize;
- PREFETCH_L1(sequence.match); PREFETCH_L1(sequence.match + sequence.matchLength - 1); /* note : it's safe to invoke PREFETCH() on any memory address, including invalid ones */
- sequences[seqNb & STORED_SEQS_MASK] = sequence;
- op += oneSeqSize;
- }
- RETURN_ERROR_IF(seqNb<nbSeq, corruption_detected, "");
-
- /* finish queue */
- seqNb -= seqAdvance;
- for ( ; seqNb<nbSeq ; seqNb++) {
- size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequences[seqNb&STORED_SEQS_MASK], &litPtr, litEnd, prefixStart, dictStart, dictEnd);
-#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE)
- assert(!ZSTD_isError(oneSeqSize));
- if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[seqNb&STORED_SEQS_MASK], prefixStart, dictStart);
-#endif
- if (ZSTD_isError(oneSeqSize)) return oneSeqSize;
- op += oneSeqSize;
- }
-
- /* save reps for next block */
- { U32 i; for (i=0; i<ZSTD_REP_NUM; i++) dctx->entropy.rep[i] = (U32)(seqState.prevOffset[i]); }
- }
-
- /* last literal segment */
- { size_t const lastLLSize = litEnd - litPtr;
- RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, "");
- if (op != NULL) {
- memcpy(op, litPtr, lastLLSize);
- op += lastLLSize;
- }
- }
-
- return op-ostart;
-}
-
-static size_t
-ZSTD_decompressSequencesLong_default(ZSTD_DCtx* dctx,
- void* dst, size_t maxDstSize,
- const void* seqStart, size_t seqSize, int nbSeq,
- const ZSTD_longOffset_e isLongOffset,
- const int frame)
-{
- return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
-}
-#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */
-
-
-
-#if DYNAMIC_BMI2
-
-#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG
-static TARGET_ATTRIBUTE("bmi2") size_t
-DONT_VECTORIZE
-ZSTD_decompressSequences_bmi2(ZSTD_DCtx* dctx,
- void* dst, size_t maxDstSize,
- const void* seqStart, size_t seqSize, int nbSeq,
- const ZSTD_longOffset_e isLongOffset,
- const int frame)
-{
- return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
-}
-#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */
-
-#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT
-static TARGET_ATTRIBUTE("bmi2") size_t
-ZSTD_decompressSequencesLong_bmi2(ZSTD_DCtx* dctx,
- void* dst, size_t maxDstSize,
- const void* seqStart, size_t seqSize, int nbSeq,
- const ZSTD_longOffset_e isLongOffset,
- const int frame)
-{
- return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
-}
-#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */
-
-#endif /* DYNAMIC_BMI2 */
-
-typedef size_t (*ZSTD_decompressSequences_t)(
- ZSTD_DCtx* dctx,
- void* dst, size_t maxDstSize,
- const void* seqStart, size_t seqSize, int nbSeq,
- const ZSTD_longOffset_e isLongOffset,
- const int frame);
-
-#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG
-static size_t
-ZSTD_decompressSequences(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize,
- const void* seqStart, size_t seqSize, int nbSeq,
- const ZSTD_longOffset_e isLongOffset,
- const int frame)
-{
- DEBUGLOG(5, "ZSTD_decompressSequences");
-#if DYNAMIC_BMI2
- if (dctx->bmi2) {
- return ZSTD_decompressSequences_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
- }
-#endif
- return ZSTD_decompressSequences_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
-}
-#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */
-
-
-#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT
-/* ZSTD_decompressSequencesLong() :
- * decompression function triggered when a minimum share of offsets is considered "long",
- * aka out of cache.
- * note : "long" definition seems overloaded here, sometimes meaning "wider than bitstream register", and sometimes meaning "farther than memory cache distance".
- * This function will try to mitigate main memory latency through the use of prefetching */
-static size_t
-ZSTD_decompressSequencesLong(ZSTD_DCtx* dctx,
- void* dst, size_t maxDstSize,
- const void* seqStart, size_t seqSize, int nbSeq,
- const ZSTD_longOffset_e isLongOffset,
- const int frame)
-{
- DEBUGLOG(5, "ZSTD_decompressSequencesLong");
-#if DYNAMIC_BMI2
- if (dctx->bmi2) {
- return ZSTD_decompressSequencesLong_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
- }
-#endif
- return ZSTD_decompressSequencesLong_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
-}
-#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */
-
-
-
-#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \
- !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG)
-/* ZSTD_getLongOffsetsShare() :
- * condition : offTable must be valid
- * @return : "share" of long offsets (arbitrarily defined as > (1<<23))
- * compared to maximum possible of (1<<OffFSELog) */
-static unsigned
-ZSTD_getLongOffsetsShare(const ZSTD_seqSymbol* offTable)
-{
- const void* ptr = offTable;
- U32 const tableLog = ((const ZSTD_seqSymbol_header*)ptr)[0].tableLog;
- const ZSTD_seqSymbol* table = offTable + 1;
- U32 const max = 1 << tableLog;
- U32 u, total = 0;
- DEBUGLOG(5, "ZSTD_getLongOffsetsShare: (tableLog=%u)", tableLog);
-
- assert(max <= (1 << OffFSELog)); /* max not too large */
- for (u=0; u<max; u++) {
- if (table[u].nbAdditionalBits > 22) total += 1;
- }
-
- assert(tableLog <= OffFSELog);
- total <<= (OffFSELog - tableLog); /* scale to OffFSELog */
-
- return total;
-}
-#endif
-
-size_t
-ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize, const int frame)
-{ /* blockType == blockCompressed */
- const BYTE* ip = (const BYTE*)src;
- /* isLongOffset must be true if there are long offsets.
- * Offsets are long if they are larger than 2^STREAM_ACCUMULATOR_MIN.
- * We don't expect that to be the case in 64-bit mode.
- * In block mode, window size is not known, so we have to be conservative.
- * (note: but it could be evaluated from current-lowLimit)
- */
- ZSTD_longOffset_e const isLongOffset = (ZSTD_longOffset_e)(MEM_32bits() && (!frame || (dctx->fParams.windowSize > (1ULL << STREAM_ACCUMULATOR_MIN))));
- DEBUGLOG(5, "ZSTD_decompressBlock_internal (size : %u)", (U32)srcSize);
-
- RETURN_ERROR_IF(srcSize >= ZSTD_BLOCKSIZE_MAX, srcSize_wrong, "");
-
- /* Decode literals section */
- { size_t const litCSize = ZSTD_decodeLiteralsBlock(dctx, src, srcSize);
- DEBUGLOG(5, "ZSTD_decodeLiteralsBlock : %u", (U32)litCSize);
- if (ZSTD_isError(litCSize)) return litCSize;
- ip += litCSize;
- srcSize -= litCSize;
- }
-
- /* Build Decoding Tables */
- {
- /* These macros control at build-time which decompressor implementation
- * we use. If neither is defined, we do some inspection and dispatch at
- * runtime.
- */
-#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \
- !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG)
- int usePrefetchDecoder = dctx->ddictIsCold;
-#endif
- int nbSeq;
- size_t const seqHSize = ZSTD_decodeSeqHeaders(dctx, &nbSeq, ip, srcSize);
- if (ZSTD_isError(seqHSize)) return seqHSize;
- ip += seqHSize;
- srcSize -= seqHSize;
-
- RETURN_ERROR_IF(dst == NULL && nbSeq > 0, dstSize_tooSmall, "NULL not handled");
-
-#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \
- !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG)
- if ( !usePrefetchDecoder
- && (!frame || (dctx->fParams.windowSize > (1<<24)))
- && (nbSeq>ADVANCED_SEQS) ) { /* could probably use a larger nbSeq limit */
- U32 const shareLongOffsets = ZSTD_getLongOffsetsShare(dctx->OFTptr);
- U32 const minShare = MEM_64bits() ? 7 : 20; /* heuristic values, correspond to 2.73% and 7.81% */
- usePrefetchDecoder = (shareLongOffsets >= minShare);
- }
-#endif
-
- dctx->ddictIsCold = 0;
-
-#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \
- !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG)
- if (usePrefetchDecoder)
-#endif
-#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT
- return ZSTD_decompressSequencesLong(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset, frame);
-#endif
-
-#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG
- /* else */
- return ZSTD_decompressSequences(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset, frame);
-#endif
- }
-}
-
-
-void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst)
-{
- if (dst != dctx->previousDstEnd) { /* not contiguous */
- dctx->dictEnd = dctx->previousDstEnd;
- dctx->virtualStart = (const char*)dst - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart));
- dctx->prefixStart = dst;
- dctx->previousDstEnd = dst;
- }
-}
-
-
-size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize)
-{
- size_t dSize;
- ZSTD_checkContinuity(dctx, dst);
- dSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 0);
- dctx->previousDstEnd = (char*)dst + dSize;
- return dSize;
-}
-/**** ended inlining decompress/zstd_decompress_block.c ****/
diff --git a/sys/contrib/openzfs/module/zstd/lib/zstd.h b/sys/contrib/openzfs/module/zstd/lib/zstd.h
index b6772f8818a7..8c6fc6ae90e6 100644
--- a/sys/contrib/openzfs/module/zstd/lib/zstd.h
+++ b/sys/contrib/openzfs/module/zstd/lib/zstd.h
@@ -1,37 +1,12 @@
/*
- * BSD 3-Clause Clear License
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * 3. Neither the name of the copyright holder nor the names of its
- * contributors may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
*/
-
-/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. All rights reserved.
- */
-
#if defined (__cplusplus)
extern "C" {
#endif
diff --git a/sys/contrib/openzfs/module/zstd/zfs_zstd.c b/sys/contrib/openzfs/module/zstd/zfs_zstd.c
index 7b3eb52574df..7f042b5bcd6f 100644
--- a/sys/contrib/openzfs/module/zstd/zfs_zstd.c
+++ b/sys/contrib/openzfs/module/zstd/zfs_zstd.c
@@ -48,7 +48,7 @@
#define ZSTD_STATIC_LINKING_ONLY
#include "lib/zstd.h"
-#include "lib/zstd_errors.h"
+#include "lib/common/zstd_errors.h"
kstat_t *zstd_ksp = NULL;
@@ -207,11 +207,7 @@ static struct zstd_pool *zstd_mempool_dctx;
* and while ASAN does this, KASAN defines that and does not. So to avoid
* changing the external code, we do this.
*/
-#if defined(__has_feature)
-#if __has_feature(address_sanitizer)
-#define ADDRESS_SANITIZER 1
-#endif
-#elif defined(__SANITIZE_ADDRESS__)
+#if defined(ZFS_ASAN_ENABLED)
#define ADDRESS_SANITIZER 1
#endif
#if defined(_KERNEL) && defined(ADDRESS_SANITIZER)
diff --git a/sys/contrib/openzfs/rpm/generic/zfs-kmod.spec.in b/sys/contrib/openzfs/rpm/generic/zfs-kmod.spec.in
index 1692be1a72e6..53b1e1385159 100644
--- a/sys/contrib/openzfs/rpm/generic/zfs-kmod.spec.in
+++ b/sys/contrib/openzfs/rpm/generic/zfs-kmod.spec.in
@@ -140,7 +140,10 @@ for kernel_version in %{?kernel_versions}; do
--with-linux=%{ksrc} \
--with-linux-obj=%{kobj} \
%{debug} \
- %{debuginfo}
+ %{debuginfo} \
+ %{?kernel_cc} \
+ %{?kernel_ld} \
+ %{?kernel_llvm}
make %{?_smp_mflags}
cd ..
done
diff --git a/sys/contrib/openzfs/rpm/generic/zfs.spec.in b/sys/contrib/openzfs/rpm/generic/zfs.spec.in
index 9ee36b20491e..bdd77b43da6f 100644
--- a/sys/contrib/openzfs/rpm/generic/zfs.spec.in
+++ b/sys/contrib/openzfs/rpm/generic/zfs.spec.in
@@ -55,6 +55,7 @@
%bcond_with debug
%bcond_with debuginfo
%bcond_with asan
+%bcond_with ubsan
%bcond_with systemd
%bcond_with pam
%bcond_without pyzfs
@@ -117,10 +118,15 @@ BuildRequires: ncompress
BuildRequires: libtirpc-devel
%endif
+%if %{with pam}
+BuildRequires: pam-devel
+%endif
+
Requires: openssl
%if 0%{?_systemd}
BuildRequires: systemd
%endif
+
%endif
%if 0%{?_systemd}
@@ -339,6 +345,12 @@ image which is ZFS aware.
%define asan --disable-asan
%endif
+%if %{with ubsan}
+ %define ubsan --enable-ubsan
+%else
+ %define ubsan --disable-ubsan
+%endif
+
%if 0%{?_systemd}
%define systemd --enable-systemd --with-systemdunitdir=%{_unitdir} --with-systemdpresetdir=%{_presetdir} --with-systemdmodulesloaddir=%{_modulesloaddir} --with-systemdgeneratordir=%{_systemdgeneratordir} --disable-sysvinit
%define systemd_svcs zfs-import-cache.service zfs-import-scan.service zfs-mount.service zfs-share.service zfs-zed.service zfs.target zfs-import.target zfs-volume-wait.service zfs-volumes.target
@@ -374,6 +386,7 @@ image which is ZFS aware.
%{debug} \
%{debuginfo} \
%{asan} \
+ %{ubsan} \
%{systemd} \
%{pam} \
%{pyzfs}
@@ -527,7 +540,7 @@ systemctl --system daemon-reload >/dev/null || true
%{_datadir}/%{name}/*.sh
%files dracut
-%doc contrib/dracut/README.dracut.markdown
+%doc contrib/dracut/README.md
%{_dracutdir}/modules.d/*
%if %{with pyzfs}
@@ -541,7 +554,7 @@ systemctl --system daemon-reload >/dev/null || true
%if 0%{?_initramfs}
%files initramfs
-%doc contrib/initramfs/README.initramfs.markdown
+%doc contrib/initramfs/README.md
/usr/share/initramfs-tools/*
%else
# Since we're not building the initramfs package,
diff --git a/sys/contrib/openzfs/rpm/redhat/zfs-kmod.spec.in b/sys/contrib/openzfs/rpm/redhat/zfs-kmod.spec.in
index eb93aeeb2efe..7b74fdc51f43 100644
--- a/sys/contrib/openzfs/rpm/redhat/zfs-kmod.spec.in
+++ b/sys/contrib/openzfs/rpm/redhat/zfs-kmod.spec.in
@@ -69,7 +69,10 @@ fi
--with-linux=%{ksrc} \
--with-linux-obj=%{kobj} \
%{debug} \
- %{debuginfo}
+ %{debuginfo} \
+ %{?kernel_cc} \
+ %{?kernel_ld} \
+ %{?kernel_llvm}
make %{?_smp_mflags}
%install
diff --git a/sys/contrib/openzfs/scripts/Makefile.am b/sys/contrib/openzfs/scripts/Makefile.am
index a5107e6fc872..e2772cf1d605 100644
--- a/sys/contrib/openzfs/scripts/Makefile.am
+++ b/sys/contrib/openzfs/scripts/Makefile.am
@@ -18,7 +18,8 @@ EXTRA_SCRIPTS = \
make_gitrev.sh \
man-dates.sh \
paxcheck.sh \
- mancheck.sh
+ mancheck.sh \
+ zfs-tests-color.sh
EXTRA_DIST = \
cstyle.pl \
@@ -28,7 +29,6 @@ EXTRA_DIST = \
$(EXTRA_SCRIPTS)
SHELLCHECKSCRIPTS = $(EXTRA_SCRIPTS)
-SHELLCHECK_OPTS = --enable=all
define EXTRA_ENVIRONMENT
diff --git a/sys/contrib/openzfs/scripts/cstyle.pl b/sys/contrib/openzfs/scripts/cstyle.pl
index d19718ecf443..d4563cdc9f1a 100755
--- a/sys/contrib/openzfs/scripts/cstyle.pl
+++ b/sys/contrib/openzfs/scripts/cstyle.pl
@@ -140,7 +140,7 @@ my %old2posix = (
);
my $lint_re = qr/\/\*(?:
- ARGSUSED[0-9]*|NOTREACHED|LINTLIBRARY|VARARGS[0-9]*|
+ NOTREACHED|LINTLIBRARY|VARARGS[0-9]*|
CONSTCOND|CONSTANTCOND|CONSTANTCONDITION|EMPTY|
FALLTHRU|FALLTHROUGH|LINTED.*?|PRINTFLIKE[0-9]*|
PROTOLIB[0-9]*|SCANFLIKE[0-9]*|CSTYLED.*?
@@ -385,6 +385,9 @@ line: while (<$filehandle>) {
if (/[^ \t(]\/\*/ && !/\w\(\/\*.*\*\/\);/) {
err("comment preceded by non-blank");
}
+ if (/ARGSUSED/) {
+ err("ARGSUSED directive");
+ }
# is this the beginning or ending of a function?
# (not if "struct foo\n{\n")
diff --git a/sys/contrib/openzfs/scripts/dkms.mkconf b/sys/contrib/openzfs/scripts/dkms.mkconf
index ebe38e31916a..4090efa087f7 100755
--- a/sys/contrib/openzfs/scripts/dkms.mkconf
+++ b/sys/contrib/openzfs/scripts/dkms.mkconf
@@ -29,22 +29,14 @@ PRE_BUILD="configure
--prefix=/usr
--with-config=kernel
--with-linux=\$(
- case \`lsb_release -is\` in
- (Debian|Devuan)
- if [[ -e \${kernel_source_dir/%build/source} ]]
- then
- echo \${kernel_source_dir/%build/source}
- else
- # A kpkg exception for Proxmox 2.0
- echo \${kernel_source_dir}
- fi
- ;;
- (*)
- echo \${kernel_source_dir}
- ;;
- esac
+ if [ -e "\${kernel_source_dir/%build/source}" ]
+ then
+ echo "\${kernel_source_dir/%build/source}"
+ else
+ echo "\${kernel_source_dir}"
+ fi
)
- --with-linux-obj=\${kernel_source_dir}
+ --with-linux-obj="\${kernel_source_dir}"
\$(
[[ -n \"\${ICP_ROOT}\" ]] && \\
{
diff --git a/sys/contrib/openzfs/scripts/zfs-tests-color.sh b/sys/contrib/openzfs/scripts/zfs-tests-color.sh
new file mode 100755
index 000000000000..9098abb62d74
--- /dev/null
+++ b/sys/contrib/openzfs/scripts/zfs-tests-color.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+# A large mass of sed for coloring zfs-tests.sh output
+# Version 2, thanks to наб.
+# Just pipe zfs-tests.sh output into this, and watch.
+
+exec "$(command -v gsed || echo sed)" \
+ -e 's/\] \[PASS\]$/] [\x1b[92mPASS\x1b[0m]/' \
+ -e 's/\] \[FAIL\]$/] [\x1b[1;91mFAIL\x1b[0m]/' \
+ -e 's/\] \[KILLED\]$/] [\x1b[1;101mKILLED\x1b[0m]/' \
+ -e 's/\] \[SKIP\]$/] [\x1b[1mSKIP\x1b[0m]/' \
+ -e 's/\] \[RERAN\]$/] [\x1b[1;93mRERAN\x1b[0m]/' \
+ -e 's/^\(PASS\W\)/\x1b[92m\1\x1b[0m/' \
+ -e 's/^\(FAIL\W\)/\x1b[1;91m\1\x1b[0m/' \
+ -e 's/^\(KILLED\W\)/\x1b[1;101m\1\x1b[0m/' \
+ -e 's/^\(SKIP\W\)/\x1b[1m\1\x1b[0m/' \
+ -e 's/^\(RERAN\W\)/\x1b[1;93m\1\x1b[0m/' \
+ -e 's/^Tests with result\(.\+\)PASS\(.\+\)$/Tests with result\1\x1b[92mPASS\x1b[0m\2/' \
+ -e 's/^\(\W\+\)\(KILLED\)\(\W\)/\1\x1b[1;101m\2\x1b[0m\3/g' \
+ -e 's/^\(\W\+\)\(FAIL\)\(\W\)/\1\x1b[1;91m\2\x1b[0m\3/g' \
+ -e 's/^\(\W\+\)\(RERUN\)\(\W\)/\1\x1b[1;93m\2\x1b[0m\3/g' \
+ -e 's/^\(\W\+\)\(SKIP\)\(\W\)/\1\x1b[1m\2\x1b[0m\3/g' \
+ -e 's/expected \(PASS\))$/expected \x1b[92m\1\x1b[0m)/' \
+ -e 's/expected \(KILLED\))$/expected \x1b[1;101m\1\x1b[0m)/' \
+ -e 's/expected \(FAIL\))$/expected \x1b[1;91m\1\x1b[0m)/' \
+ -e 's/expected \(RERUN\))$/expected \x1b[1;93m\1\x1b[0m)/' \
+ -e 's/expected \(SKIP\))$/expected \x1b[1m\1\x1b[0m)/' \
+ -e 's/^Test\( ([[:alnum:] ]\+)\)\?: \(.\+\) (run as \(.\+\)) \[\([0-9]\+:[0-9]\+\)\] \[\(.\+\)\]$/\x1b[1mTest\1: \x1b[0m\2 (run as \x1b[1m\3\x1b[0m) [\x1b[1m\4\x1b[0m\] [\5\]/'
diff --git a/sys/contrib/openzfs/scripts/zfs-tests.sh b/sys/contrib/openzfs/scripts/zfs-tests.sh
index aaaf9ddfc25d..2477d0f91799 100755
--- a/sys/contrib/openzfs/scripts/zfs-tests.sh
+++ b/sys/contrib/openzfs/scripts/zfs-tests.sh
@@ -54,6 +54,7 @@ ZFS_DBGMSG="$STF_SUITE/callbacks/zfs_dbgmsg.ksh"
ZFS_DMESG="$STF_SUITE/callbacks/zfs_dmesg.ksh"
UNAME=$(uname -s)
RERUN=""
+KMEMLEAK=""
# Override some defaults if on FreeBSD
if [ "$UNAME" = "FreeBSD" ] ; then
@@ -148,7 +149,7 @@ trap cleanup EXIT
# be dangerous and should only be used in a dedicated test environment.
#
cleanup_all() {
- TEST_POOLS=$(sudo "$ZPOOL" list -H -o name | grep testpool)
+ TEST_POOLS=$(sudo env ASAN_OPTIONS=detect_leaks=false "$ZPOOL" list -H -o name | grep testpool)
if [ "$UNAME" = "FreeBSD" ] ; then
TEST_LOOPBACKS=$(sudo "${LOSETUP}" -l)
else
@@ -160,7 +161,7 @@ cleanup_all() {
msg "--- Cleanup ---"
msg "Removing pool(s): $(echo "${TEST_POOLS}" | tr '\n' ' ')"
for TEST_POOL in $TEST_POOLS; do
- sudo "$ZPOOL" destroy "${TEST_POOL}"
+ sudo env ASAN_OPTIONS=detect_leaks=false "$ZPOOL" destroy "${TEST_POOL}"
done
if [ "$UNAME" != "FreeBSD" ] ; then
@@ -329,6 +330,7 @@ OPTIONS:
-S Enable stack tracer (negative performance impact)
-c Only create and populate constrained path
-R Automatically rerun failing tests
+ -m Enable kmemleak reporting (Linux only)
-n NFSFILE Use the nfsfile to determine the NFS configuration
-I NUM Number of iterations
-d DIR Use DIR for files and loopback devices
@@ -355,7 +357,7 @@ $0 -x
EOF
}
-while getopts 'hvqxkfScRn:d:s:r:?t:T:u:I:' OPTION; do
+while getopts 'hvqxkfScRmn:d:s:r:?t:T:u:I:' OPTION; do
case $OPTION in
h)
usage
@@ -386,6 +388,9 @@ while getopts 'hvqxkfScRn:d:s:r:?t:T:u:I:' OPTION; do
R)
RERUN="yes"
;;
+ m)
+ KMEMLEAK="yes"
+ ;;
n)
nfsfile=$OPTARG
[ -f "$nfsfile" ] || fail "Cannot read file: $nfsfile"
@@ -554,7 +559,7 @@ fi
# space-delimited to newline-delimited.
#
if [ -z "${KEEP}" ]; then
- KEEP="$(sudo "$ZPOOL" list -H -o name)"
+ KEEP="$(sudo env ASAN_OPTIONS=detect_leaks=false "$ZPOOL" list -H -o name)"
if [ -z "${KEEP}" ]; then
KEEP="rpool"
fi
@@ -683,29 +688,37 @@ export __ZFS_POOL_EXCLUDE
export TESTFAIL_CALLBACKS
export PATH=$STF_PATH
-if [ "$UNAME" = "FreeBSD" ] ; then
- mkdir -p "$FILEDIR" || true
- RESULTS_FILE=$(mktemp -u "${FILEDIR}/zts-results.XXXXXX")
- REPORT_FILE=$(mktemp -u "${FILEDIR}/zts-report.XXXXXX")
-else
- RESULTS_FILE=$(mktemp -u -t zts-results.XXXXXX -p "$FILEDIR")
- REPORT_FILE=$(mktemp -u -t zts-report.XXXXXX -p "$FILEDIR")
-fi
+mktemp_file() {
+ if [ "$UNAME" = "FreeBSD" ]; then
+ mktemp -u "${FILEDIR}/$1.XXXXXX"
+ else
+ mktemp -ut "$1.XXXXXX" -p "$FILEDIR"
+ fi
+}
+mkdir -p "$FILEDIR" || :
+RESULTS_FILE=$(mktemp_file zts-results)
+REPORT_FILE=$(mktemp_file zts-report)
#
# Run all the tests as specified.
#
-msg "${TEST_RUNNER} ${QUIET:+-q}" \
+msg "${TEST_RUNNER}" \
+ "${QUIET:+-q}" \
+ "${KMEMLEAK:+-m}" \
"-c \"${RUNFILES}\"" \
"-T \"${TAGS}\"" \
"-i \"${STF_SUITE}\"" \
"-I \"${ITERATIONS}\""
-${TEST_RUNNER} ${QUIET:+-q} \
+{ ${TEST_RUNNER} \
+ ${QUIET:+-q} \
+ ${KMEMLEAK:+-m} \
-c "${RUNFILES}" \
-T "${TAGS}" \
-i "${STF_SUITE}" \
-I "${ITERATIONS}" \
- 2>&1 | tee "$RESULTS_FILE"
+ 2>&1; echo $? >"$REPORT_FILE"; } | tee "$RESULTS_FILE"
+read -r RUNRESULT <"$REPORT_FILE"
+
#
# Analyze the results.
#
@@ -714,19 +727,22 @@ RESULT=$?
if [ "$RESULT" -eq "2" ] && [ -n "$RERUN" ]; then
MAYBES="$($ZTS_REPORT --list-maybes)"
- TEMP_RESULTS_FILE=$(mktemp -u -t zts-results-tmp.XXXXX -p "$FILEDIR")
- TEST_LIST=$(mktemp -u -t test-list.XXXXX -p "$FILEDIR")
+ TEMP_RESULTS_FILE=$(mktemp_file zts-results-tmp)
+ TEST_LIST=$(mktemp_file test-list)
grep "^Test:.*\[FAIL\]" "$RESULTS_FILE" >"$TEMP_RESULTS_FILE"
for test_name in $MAYBES; do
grep "$test_name " "$TEMP_RESULTS_FILE" >>"$TEST_LIST"
done
- ${TEST_RUNNER} ${QUIET:+-q} \
+ { ${TEST_RUNNER} \
+ ${QUIET:+-q} \
+ ${KMEMLEAK:+-m} \
-c "${RUNFILES}" \
-T "${TAGS}" \
-i "${STF_SUITE}" \
-I "${ITERATIONS}" \
-l "${TEST_LIST}" \
- 2>&1 | tee "$RESULTS_FILE"
+ 2>&1; echo $? >"$REPORT_FILE"; } | tee "$RESULTS_FILE"
+ read -r RUNRESULT <"$REPORT_FILE"
#
# Analyze the results.
#
@@ -748,4 +764,4 @@ if [ -n "$SINGLETEST" ]; then
rm -f "$RUNFILES" >/dev/null 2>&1
fi
-exit "${RESULT}"
+[ "$RUNRESULT" -gt 3 ] && exit "$RUNRESULT" || exit "$RESULT"
diff --git a/sys/contrib/openzfs/scripts/zloop.sh b/sys/contrib/openzfs/scripts/zloop.sh
index 1a512657be69..dd89ff6fdf29 100755
--- a/sys/contrib/openzfs/scripts/zloop.sh
+++ b/sys/contrib/openzfs/scripts/zloop.sh
@@ -215,7 +215,8 @@ shift $((OPTIND - 1))
# enable core dumps
ulimit -c unlimited
-export ASAN_OPTIONS=abort_on_error=1:disable_coredump=0
+export ASAN_OPTIONS=abort_on_error=true:halt_on_error=true:allocator_may_return_null=true:disable_coredump=false:detect_stack_use_after_return=true
+export UBSAN_OPTIONS=abort_on_error=true:halt_on_error=true:print_stacktrace=true
if [[ -f "$(core_file)" ]]; then
echo -n "There's a core dump here you might want to look at first... "
diff --git a/sys/contrib/openzfs/tests/runfiles/common.run b/sys/contrib/openzfs/tests/runfiles/common.run
index 1c0042af1858..fdc2172b6a65 100644
--- a/sys/contrib/openzfs/tests/runfiles/common.run
+++ b/sys/contrib/openzfs/tests/runfiles/common.run
@@ -29,7 +29,7 @@ outputdir = /var/tmp/test_results
tags = ['functional']
[tests/functional/acl/off]
-tests = ['posixmode']
+tests = ['dosmode', 'posixmode']
tags = ['functional', 'acl']
[tests/functional/alloc_class]
@@ -236,7 +236,8 @@ tests = ['zfs_receive_001_pos', 'zfs_receive_002_pos', 'zfs_receive_003_pos',
'receive-o-x_props_aliases',
'zfs_receive_from_encrypted', 'zfs_receive_to_encrypted',
'zfs_receive_raw', 'zfs_receive_raw_incremental', 'zfs_receive_-e',
- 'zfs_receive_raw_-d', 'zfs_receive_from_zstd', 'zfs_receive_new_props']
+ 'zfs_receive_raw_-d', 'zfs_receive_from_zstd', 'zfs_receive_new_props',
+ 'zfs_receive_-wR-encrypted-mix']
tags = ['functional', 'cli_root', 'zfs_receive']
[tests/functional/cli_root/zfs_rename]
@@ -659,12 +660,6 @@ tags = ['functional', 'inuse']
tests = ['large_files_001_pos', 'large_files_002_pos']
tags = ['functional', 'large_files']
-[tests/functional/largest_pool]
-tests = ['largest_pool_001_pos']
-pre =
-post =
-tags = ['functional', 'largest_pool']
-
[tests/functional/limits]
tests = ['filesystem_count', 'filesystem_limit', 'snapshot_count',
'snapshot_limit']
@@ -699,7 +694,7 @@ tags = ['functional', 'nestedfs']
[tests/functional/no_space]
tests = ['enospc_001_pos', 'enospc_002_pos', 'enospc_003_pos',
- 'enospc_df']
+ 'enospc_df', 'enospc_rm']
tags = ['functional', 'no_space']
[tests/functional/nopwrite]
@@ -839,7 +834,8 @@ tests = ['recv_dedup', 'recv_dedup_encrypted_zvol', 'rsend_001_pos',
'send_freeobjects', 'send_realloc_files',
'send_realloc_encrypted_files', 'send_spill_block', 'send_holds',
'send_hole_birth', 'send_mixed_raw', 'send-wR_encrypted_zvol',
- 'send_partial_dataset', 'send_invalid', 'send_doall']
+ 'send_partial_dataset', 'send_invalid', 'send_doall',
+ 'send_raw_spill_block', 'send_raw_ashift']
tags = ['functional', 'rsend']
[tests/functional/scrub_mirror]
@@ -852,7 +848,7 @@ tests = ['slog_001_pos', 'slog_002_pos', 'slog_003_pos', 'slog_004_pos',
'slog_005_pos', 'slog_006_pos', 'slog_007_pos', 'slog_008_neg',
'slog_009_neg', 'slog_010_neg', 'slog_011_neg', 'slog_012_neg',
'slog_013_pos', 'slog_014_pos', 'slog_015_neg', 'slog_replay_fs_001',
- 'slog_replay_fs_002', 'slog_replay_volume']
+ 'slog_replay_fs_002', 'slog_replay_volume', 'slog_016_pos']
tags = ['functional', 'slog']
[tests/functional/snapshot]
@@ -880,7 +876,7 @@ tags = ['functional', 'stat']
[tests/functional/suid]
tests = ['suid_write_to_suid', 'suid_write_to_sgid', 'suid_write_to_suid_sgid',
- 'suid_write_to_none']
+ 'suid_write_to_none', 'suid_write_zil_replay']
tags = ['functional', 'suid']
[tests/functional/threadsappend]
@@ -923,7 +919,7 @@ tags = ['functional', 'write_dirs']
[tests/functional/xattr]
tests = ['xattr_001_pos', 'xattr_002_neg', 'xattr_003_neg', 'xattr_004_pos',
'xattr_005_pos', 'xattr_006_pos', 'xattr_007_neg',
- 'xattr_011_pos', 'xattr_012_pos', 'xattr_013_pos']
+ 'xattr_011_pos', 'xattr_012_pos', 'xattr_013_pos', 'xattr_compat']
tags = ['functional', 'xattr']
[tests/functional/zvol/zvol_ENOSPC]
diff --git a/sys/contrib/openzfs/tests/runfiles/freebsd.run b/sys/contrib/openzfs/tests/runfiles/freebsd.run
index 153b204b4932..c7ca1d769fc3 100644
--- a/sys/contrib/openzfs/tests/runfiles/freebsd.run
+++ b/sys/contrib/openzfs/tests/runfiles/freebsd.run
@@ -22,10 +22,6 @@ failsafe = callbacks/zfs_failsafe
outputdir = /var/tmp/test_results
tags = ['functional']
-[tests/functional/acl/off:FreeBSD]
-tests = ['dosmode']
-tags = ['functional', 'acl']
-
[tests/functional/cli_root/zfs_jail:FreeBSD]
tests = ['zfs_jail_001_pos']
tags = ['functional', 'cli_root', 'zfs_jail']
diff --git a/sys/contrib/openzfs/tests/runfiles/linux.run b/sys/contrib/openzfs/tests/runfiles/linux.run
index 58eefec319ea..8412a7ea5a95 100644
--- a/sys/contrib/openzfs/tests/runfiles/linux.run
+++ b/sys/contrib/openzfs/tests/runfiles/linux.run
@@ -109,6 +109,12 @@ tags = ['functional', 'features', 'large_dnode']
tests = ['libaio', 'io_uring']
tags = ['functional', 'io']
+[tests/functional/largest_pool:Linux]
+tests = ['largest_pool_001_pos']
+pre =
+post =
+tags = ['functional', 'largest_pool']
+
[tests/functional/mmap:Linux]
tests = ['mmap_libaio_001_pos']
tags = ['functional', 'mmap']
@@ -143,10 +149,20 @@ tests = ['projectid_001_pos', 'projectid_002_pos', 'projectid_003_pos',
'projecttree_001_pos', 'projecttree_002_pos', 'projecttree_003_neg']
tags = ['functional', 'projectquota']
+[tests/functional/dos_attributes:Linux]
+tests = ['read_dos_attrs_001', 'write_dos_attrs_001']
+tags = ['functional', 'dos_attributes']
+
[tests/functional/rsend:Linux]
tests = ['send_realloc_dnode_size', 'send_encrypted_files']
tags = ['functional', 'rsend']
+[tests/functional/simd:Linux]
+pre =
+post =
+tests = ['simd_supported']
+tags = ['functional', 'simd']
+
[tests/functional/snapshot:Linux]
tests = ['snapshot_015_pos', 'snapshot_016_pos']
tags = ['functional', 'snapshot']
diff --git a/sys/contrib/openzfs/tests/runfiles/sanity.run b/sys/contrib/openzfs/tests/runfiles/sanity.run
index 8057d8148c93..383308bb59ff 100644
--- a/sys/contrib/openzfs/tests/runfiles/sanity.run
+++ b/sys/contrib/openzfs/tests/runfiles/sanity.run
@@ -602,7 +602,7 @@ tags = ['functional', 'vdev_zaps']
[tests/functional/xattr]
tests = ['xattr_001_pos', 'xattr_002_neg', 'xattr_003_neg', 'xattr_004_pos',
'xattr_005_pos', 'xattr_006_pos', 'xattr_007_neg',
- 'xattr_011_pos', 'xattr_013_pos']
+ 'xattr_011_pos', 'xattr_013_pos', 'xattr_compat']
tags = ['functional', 'xattr']
[tests/functional/zvol/zvol_ENOSPC]
diff --git a/sys/contrib/openzfs/tests/test-runner/bin/test-runner.py.in b/sys/contrib/openzfs/tests/test-runner/bin/test-runner.py.in
index 3c0b82a311bb..c644745b4390 100755
--- a/sys/contrib/openzfs/tests/test-runner/bin/test-runner.py.in
+++ b/sys/contrib/openzfs/tests/test-runner/bin/test-runner.py.in
@@ -31,11 +31,13 @@ from pwd import getpwuid
from select import select
from subprocess import PIPE
from subprocess import Popen
+from subprocess import check_output
from threading import Timer
from time import time, CLOCK_MONOTONIC
BASEDIR = '/var/tmp/test_results'
TESTDIR = '/usr/share/zfs/'
+KMEMLEAK_FILE = '/sys/kernel/debug/kmemleak'
KILL = 'kill'
TRUE = 'true'
SUDO = 'sudo'
@@ -75,6 +77,7 @@ class Result(object):
self.runtime = ''
self.stdout = []
self.stderr = []
+ self.kmemleak = ''
self.result = ''
def done(self, proc, killed, reran):
@@ -90,6 +93,9 @@ class Result(object):
if killed:
self.result = 'KILLED'
Result.runresults['KILLED'] += 1
+ elif len(self.kmemleak) > 0:
+ self.result = 'FAIL'
+ Result.runresults['FAIL'] += 1
elif self.returncode == 0:
self.result = 'PASS'
Result.runresults['PASS'] += 1
@@ -250,7 +256,7 @@ User: %s
return out.lines, err.lines
- def run(self, dryrun):
+ def run(self, dryrun, kmemleak):
"""
This is the main function that runs each individual test.
Determine whether or not the command requires sudo, and modify it
@@ -270,6 +276,11 @@ User: %s
fail('%s' % e)
self.result.starttime = monotonic_time()
+
+ if kmemleak:
+ cmd = f'echo clear | {SUDO} tee {KMEMLEAK_FILE}'
+ check_output(cmd, shell=True)
+
proc = Popen(privcmd, stdout=PIPE, stderr=PIPE)
# Allow a special timeout value of 0 to mean infinity
if int(self.timeout) == 0:
@@ -279,6 +290,12 @@ User: %s
try:
t.start()
self.result.stdout, self.result.stderr = self.collect_output(proc)
+
+ if kmemleak:
+ cmd = f'echo scan | {SUDO} tee {KMEMLEAK_FILE}'
+ check_output(cmd, shell=True)
+ cmd = f'{SUDO} cat {KMEMLEAK_FILE}'
+ self.result.kmemleak = check_output(cmd, shell=True)
except KeyboardInterrupt:
self.kill_cmd(proc, True)
fail('\nRun terminated at user request.')
@@ -355,6 +372,9 @@ User: %s
with open(os.path.join(self.outputdir, 'merged'), 'wb') as merged:
for _, line in lines:
os.write(merged.fileno(), b'%s\n' % line)
+ if len(self.result.kmemleak):
+ with open(os.path.join(self.outputdir, 'kmemleak'), 'wb') as kmem:
+ kmem.write(self.result.kmemleak)
class Test(Cmd):
@@ -439,14 +459,14 @@ Tags: %s
cont = True
if len(pretest.pathname):
- pretest.run(options.dryrun)
+ pretest.run(options.dryrun, False)
cont = pretest.result.result == 'PASS'
pretest.log(options)
if cont:
- test.run(options.dryrun)
+ test.run(options.dryrun, options.kmemleak)
if test.result.result == 'KILLED' and len(failsafe.pathname):
- failsafe.run(options.dryrun)
+ failsafe.run(options.dryrun, False)
failsafe.log(options, suppress_console=True)
else:
test.skip()
@@ -454,7 +474,7 @@ Tags: %s
test.log(options)
if len(posttest.pathname):
- posttest.run(options.dryrun)
+ posttest.run(options.dryrun, False)
posttest.log(options)
@@ -557,7 +577,7 @@ Tags: %s
cont = True
if len(pretest.pathname):
- pretest.run(options.dryrun)
+ pretest.run(options.dryrun, False)
cont = pretest.result.result == 'PASS'
pretest.log(options)
@@ -570,9 +590,9 @@ Tags: %s
failsafe = Cmd(self.failsafe, outputdir=odir, timeout=self.timeout,
user=self.failsafe_user, identifier=self.identifier)
if cont:
- test.run(options.dryrun)
+ test.run(options.dryrun, options.kmemleak)
if test.result.result == 'KILLED' and len(failsafe.pathname):
- failsafe.run(options.dryrun)
+ failsafe.run(options.dryrun, False)
failsafe.log(options, suppress_console=True)
else:
test.skip()
@@ -580,7 +600,7 @@ Tags: %s
test.log(options)
if len(posttest.pathname):
- posttest.run(options.dryrun)
+ posttest.run(options.dryrun, False)
posttest.log(options)
@@ -845,6 +865,11 @@ class TestRun(object):
else:
write_log('Could not make a symlink to directory %s\n' %
self.outputdir, LOG_ERR)
+
+ if options.kmemleak:
+ cmd = f'echo scan=0 | {SUDO} tee {KMEMLEAK_FILE}'
+ check_output(cmd, shell=True)
+
iteration = 0
while iteration < options.iterations:
for test in sorted(self.tests.keys()):
@@ -990,6 +1015,14 @@ def fail(retstr, ret=1):
exit(ret)
+def kmemleak_cb(option, opt_str, value, parser):
+ if not os.path.exists(KMEMLEAK_FILE):
+ fail(f"File '{KMEMLEAK_FILE}' doesn't exist. " +
+ "Enable CONFIG_DEBUG_KMEMLEAK in kernel configuration.")
+
+ setattr(parser.values, option.dest, True)
+
+
def options_cb(option, opt_str, value, parser):
path_options = ['outputdir', 'template', 'testdir', 'logfile']
@@ -1027,6 +1060,9 @@ def parse_args():
parser.add_option('-i', action='callback', callback=options_cb,
default=TESTDIR, dest='testdir', type='string',
metavar='testdir', help='Specify a test directory.')
+ parser.add_option('-m', action='callback', callback=kmemleak_cb,
+ default=False, dest='kmemleak',
+ help='Enable kmemleak reporting (Linux only)')
parser.add_option('-p', action='callback', callback=options_cb,
default='', dest='pre', metavar='script',
type='string', help='Specify a pre script.')
diff --git a/sys/contrib/openzfs/tests/test-runner/bin/zts-report.py.in b/sys/contrib/openzfs/tests/test-runner/bin/zts-report.py.in
index 9f00ec11b437..560f7dce6814 100755
--- a/sys/contrib/openzfs/tests/test-runner/bin/zts-report.py.in
+++ b/sys/contrib/openzfs/tests/test-runner/bin/zts-report.py.in
@@ -181,6 +181,8 @@ known = {
if sys.platform.startswith('freebsd'):
known.update({
+ 'cli_root/zfs_receive/receive-o-x_props_override':
+ ['FAIL', known_reason],
'cli_root/zpool_wait/zpool_wait_trim_basic': ['SKIP', trim_reason],
'cli_root/zpool_wait/zpool_wait_trim_cancel': ['SKIP', trim_reason],
'cli_root/zpool_wait/zpool_wait_trim_flag': ['SKIP', trim_reason],
@@ -222,8 +224,6 @@ maybe = {
'cli_root/zfs_unshare/setup': ['SKIP', share_reason],
'cli_root/zpool_add/zpool_add_004_pos': ['FAIL', known_reason],
'cli_root/zpool_destroy/zpool_destroy_001_pos': ['SKIP', '6145'],
- 'cli_root/zpool_import/import_rewind_config_changed':
- ['FAIL', rewind_reason],
'cli_root/zpool_import/zpool_import_missing_003_pos': ['SKIP', '6839'],
'cli_root/zpool_initialize/zpool_initialize_import_export':
['FAIL', '11948'],
@@ -242,7 +242,6 @@ maybe = {
'largest_pool/largest_pool_001_pos': ['FAIL', known_reason],
'mmp/mmp_on_uberblocks': ['FAIL', known_reason],
'pyzfs/pyzfs_unittest': ['SKIP', python_deps_reason],
- 'no_space/enospc_002_pos': ['FAIL', enospc_reason],
'pool_checkpoint/checkpoint_discard_busy': ['FAIL', '11946'],
'projectquota/setup': ['SKIP', exec_reason],
'redundancy/redundancy_004_neg': ['FAIL', '7290'],
@@ -260,7 +259,6 @@ maybe = {
'upgrade/upgrade_projectquota_001_pos': ['SKIP', project_id_reason],
'user_namespace/setup': ['SKIP', user_ns_reason],
'userquota/setup': ['SKIP', exec_reason],
- 'vdev_zaps/vdev_zaps_004_pos': ['FAIL', '6935'],
'zvol/zvol_ENOSPC/zvol_ENOSPC_001_pos': ['FAIL', '5848'],
'pam/setup': ['SKIP', "pamtester might be not available"],
}
@@ -269,8 +267,6 @@ if sys.platform.startswith('freebsd'):
maybe.update({
'cli_root/zfs_copies/zfs_copies_002_pos': ['FAIL', known_reason],
'cli_root/zfs_inherit/zfs_inherit_001_neg': ['FAIL', known_reason],
- 'cli_root/zfs_receive/receive-o-x_props_override':
- ['FAIL', known_reason],
'cli_root/zfs_share/zfs_share_011_pos': ['FAIL', known_reason],
'cli_root/zfs_share/zfs_share_concurrent_shares':
['FAIL', known_reason],
@@ -284,8 +280,6 @@ if sys.platform.startswith('freebsd'):
elif sys.platform.startswith('linux'):
maybe.update({
'cli_root/zfs_rename/zfs_rename_002_pos': ['FAIL', known_reason],
- 'cli_root/zpool_expand/zpool_expand_001_pos': ['FAIL', known_reason],
- 'cli_root/zpool_expand/zpool_expand_005_pos': ['FAIL', known_reason],
'cli_root/zpool_reopen/zpool_reopen_003_pos': ['FAIL', known_reason],
'fault/auto_spare_shared': ['FAIL', '11889'],
'io/io_uring': ['SKIP', 'io_uring support required'],
diff --git a/sys/contrib/openzfs/tests/test-runner/man/test-runner.1 b/sys/contrib/openzfs/tests/test-runner/man/test-runner.1
index f7cbcbc5b9e9..b823aaa3e1a0 100644
--- a/sys/contrib/openzfs/tests/test-runner/man/test-runner.1
+++ b/sys/contrib/openzfs/tests/test-runner/man/test-runner.1
@@ -210,6 +210,8 @@ to be consumed by the run command.
.It Fl d
Dry run mode.
Execute no tests, but print a description of each test that would have been run.
+.It Fl m
+Enable kmemleak reporting (Linux only)
.It Fl g
Create test groups from any directories found while searching for tests.
.It Fl o Ar outputdir
diff --git a/sys/contrib/openzfs/tests/zfs-tests/cmd/Makefile.am b/sys/contrib/openzfs/tests/zfs-tests/cmd/Makefile.am
index 2470397a90a3..88d8c8cf08b2 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/cmd/Makefile.am
+++ b/sys/contrib/openzfs/tests/zfs-tests/cmd/Makefile.am
@@ -34,6 +34,8 @@ if BUILD_LINUX
SUBDIRS += \
getversion \
randfree_file \
+ read_dos_attributes \
user_ns_exec \
+ write_dos_attributes \
xattrtest
endif
diff --git a/sys/contrib/openzfs/tests/zfs-tests/cmd/draid/draid.c b/sys/contrib/openzfs/tests/zfs-tests/cmd/draid/draid.c
index 57261348b3cd..e12ab84fce59 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/cmd/draid/draid.c
+++ b/sys/contrib/openzfs/tests/zfs-tests/cmd/draid/draid.c
@@ -181,7 +181,7 @@ write_map(const char *filename, nvlist_t *allcfgs)
* no locking, it only guarantees the packed nvlist on disk
* is updated atomically and is internally consistent.
*/
- char *tmpname = calloc(MAXPATHLEN, 1);
+ char *tmpname = calloc(1, MAXPATHLEN);
if (tmpname == NULL) {
free(buf);
return (ENOMEM);
diff --git a/sys/contrib/openzfs/tests/zfs-tests/cmd/mkbusy/mkbusy.c b/sys/contrib/openzfs/tests/zfs-tests/cmd/mkbusy/mkbusy.c
index e1cbd95cd118..c32f1ecdc3b9 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/cmd/mkbusy/mkbusy.c
+++ b/sys/contrib/openzfs/tests/zfs-tests/cmd/mkbusy/mkbusy.c
@@ -31,14 +31,14 @@
#include <string.h>
-static __attribute__((noreturn)) void
+static _Noreturn void
usage(char *progname)
{
(void) fprintf(stderr, "Usage: %s <dirname|filename>\n", progname);
exit(1);
}
-static __attribute__((noreturn)) void
+static _Noreturn void
fail(char *err)
{
perror(err);
@@ -136,7 +136,7 @@ main(int argc, char *argv[])
switch (sbuf.st_mode & S_IFMT) {
case S_IFDIR:
isdir = B_TRUE;
- fallthrough;
+ zfs_fallthrough;
case S_IFLNK:
case S_IFCHR:
case S_IFBLK:
diff --git a/sys/contrib/openzfs/tests/zfs-tests/cmd/mkfile/mkfile.c b/sys/contrib/openzfs/tests/zfs-tests/cmd/mkfile/mkfile.c
index 673cbf9e0069..f59a01efaca2 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/cmd/mkfile/mkfile.c
+++ b/sys/contrib/openzfs/tests/zfs-tests/cmd/mkfile/mkfile.c
@@ -44,7 +44,7 @@
#define FILE_MODE (S_ISVTX + S_IRUSR + S_IWUSR)
-static void usage(void) __attribute__((noreturn));
+static _Noreturn void usage(void);
int
main(int argc, char **argv)
diff --git a/sys/contrib/openzfs/tests/zfs-tests/cmd/read_dos_attributes/.gitignore b/sys/contrib/openzfs/tests/zfs-tests/cmd/read_dos_attributes/.gitignore
new file mode 100644
index 000000000000..52584e4a738b
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/cmd/read_dos_attributes/.gitignore
@@ -0,0 +1 @@
+/read_dos_attributes
diff --git a/sys/contrib/openzfs/tests/zfs-tests/cmd/read_dos_attributes/Makefile.am b/sys/contrib/openzfs/tests/zfs-tests/cmd/read_dos_attributes/Makefile.am
new file mode 100644
index 000000000000..69412f05f650
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/cmd/read_dos_attributes/Makefile.am
@@ -0,0 +1,6 @@
+include $(top_srcdir)/config/Rules.am
+
+pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin
+
+pkgexec_PROGRAMS = read_dos_attributes
+read_dos_attributes_SOURCES = read_dos_attributes.c
diff --git a/sys/contrib/openzfs/tests/zfs-tests/cmd/read_dos_attributes/read_dos_attributes.c b/sys/contrib/openzfs/tests/zfs-tests/cmd/read_dos_attributes/read_dos_attributes.c
new file mode 100644
index 000000000000..ed0906c36a6f
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/cmd/read_dos_attributes/read_dos_attributes.c
@@ -0,0 +1,167 @@
+/*
+ * 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.
+ */
+
+/*
+ * Copyright 2022 iXsystems, Inc.
+ */
+
+/*
+ * FreeBSD allows to update and retreive additional file level attributes.
+ * For Linux, two IOCTLs have been added to update and retrieve additional
+ * level attributes.
+ *
+ * This application reads additional file level attributes on a given
+ * file and prints FreeBSD keywords that map to respective attributes.
+ *
+ * Usage: 'read_dos_attributes filepath'
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <err.h>
+#include <sys/fs/zfs.h>
+#include <string.h>
+
+#define SU_ARCH_SHORT "arch"
+#define SU_ARCH_FULL "archived"
+#define SU_NODUMP "nodump"
+#define SU_APPEND_SHORT "sappnd"
+#define SU_APPEND_FULL "sappend"
+#define SU_IMMUTABLE "schg"
+#define SU_IMMUTABLE_SHORT "schange"
+#define SU_IMMUTABLE_FULL "simmutable"
+#define SU_UNLINK_SHORT "sunlnk"
+#define SU_UNLINK_FULL "sunlink"
+#define U_APPEND_SHORT "uappnd"
+#define U_APPEND_FULL "uappend"
+#define U_ARCH_SHORT "uarch"
+#define U_ARCH_FULL "uarchive"
+#define U_IMMUTABLE "uchg"
+#define U_IMMUTABLE_SHORT "uchange"
+#define U_IMMUTABLE_FULL "uimmutable"
+#define U_HIDDEN_SHORT "hidden"
+#define U_HIDDEN_FULL "uhidden"
+#define U_OFFLINE_SHORT "offline"
+#define U_OFFLINE_FULL "uoffline"
+#define U_RDONLY "rdonly"
+#define U_RDONLY_SHORT "urdonly"
+#define U_RDONLY_FULL "readonly"
+#define U_SPARSE_SHORT "sparse"
+#define U_SPARSE_FULL "usparse"
+#define U_SYSTEM_SHORT "system"
+#define U_SYSTEM_FULL "usystem"
+#define U_REPARSE_SHORT "reparse"
+#define U_REPARSE_FULL "ureparse"
+#define U_UNLINK_SHORT "uunlnk"
+#define U_UNLINK_FULL "uunlink"
+#define UNSET_NODUMP "dump"
+
+#define NO_ATTRIBUTE "-"
+
+#define SEPARATOR ","
+
+#define BUFFER_SIZE 0x200
+
+void attribute_to_str(uint64_t attributes, char *buff);
+
+void
+attribute_to_str(uint64_t attributes, char *buff)
+{
+ if (attributes & ZFS_ARCHIVE) {
+ strcat(buff, U_ARCH_SHORT);
+ strcat(buff, SEPARATOR);
+ }
+
+ if (attributes & ZFS_APPENDONLY) {
+ strcat(buff, U_APPEND_SHORT);
+ strcat(buff, SEPARATOR);
+ }
+
+ if (attributes & ZFS_IMMUTABLE) {
+ strcat(buff, U_IMMUTABLE_FULL);
+ strcat(buff, SEPARATOR);
+ }
+
+ if (attributes & ZFS_NOUNLINK) {
+ strcat(buff, U_UNLINK_SHORT);
+ strcat(buff, SEPARATOR);
+ }
+
+ if (attributes & ZFS_NODUMP) {
+ strcat(buff, SU_NODUMP);
+ strcat(buff, SEPARATOR);
+ }
+
+ if (attributes & ZFS_HIDDEN) {
+ strcat(buff, U_HIDDEN_SHORT);
+ strcat(buff, SEPARATOR);
+ }
+
+ if (attributes & ZFS_OFFLINE) {
+ strcat(buff, U_OFFLINE_SHORT);
+ strcat(buff, SEPARATOR);
+ }
+
+ if (attributes & ZFS_READONLY) {
+ strcat(buff, U_RDONLY);
+ strcat(buff, SEPARATOR);
+ }
+
+ if (attributes & ZFS_SPARSE) {
+ strcat(buff, U_SPARSE_SHORT);
+ strcat(buff, SEPARATOR);
+ }
+
+ if (attributes & ZFS_SYSTEM) {
+ strcat(buff, U_SYSTEM_SHORT);
+ strcat(buff, SEPARATOR);
+ }
+
+ if (attributes & ZFS_REPARSE) {
+ strcat(buff, U_REPARSE_SHORT);
+ strcat(buff, SEPARATOR);
+ }
+
+ if (buff[0] == '\0')
+ strcat(buff, NO_ATTRIBUTE);
+ else
+ buff[strlen(buff) - 1] = '\0';
+}
+
+int
+main(int argc, const char * const argv[])
+{
+ if (argc != 2)
+ errx(EXIT_FAILURE, "Usage: %s filepath", argv[0]);
+
+ int fd = open(argv[1], O_RDWR | O_APPEND);
+ if (fd < 0)
+ err(EXIT_FAILURE, "Failed to open %s", argv[1]);
+
+ uint64_t dosflags = 0;
+ if (ioctl(fd, ZFS_IOC_GETDOSFLAGS, &dosflags) == -1)
+ err(EXIT_FAILURE, "ZFS_IOC_GETDOSFLAGS failed");
+
+ (void) close(fd);
+
+ char buffer[BUFFER_SIZE];
+ memset(buffer, 0, BUFFER_SIZE);
+
+ (void) attribute_to_str(dosflags, buffer);
+
+ (void) printf("%s\n", buffer);
+
+ return (EXIT_SUCCESS);
+}
diff --git a/sys/contrib/openzfs/tests/zfs-tests/cmd/write_dos_attributes/.gitignore b/sys/contrib/openzfs/tests/zfs-tests/cmd/write_dos_attributes/.gitignore
new file mode 100644
index 000000000000..f3949ac82822
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/cmd/write_dos_attributes/.gitignore
@@ -0,0 +1 @@
+/write_dos_attributes
diff --git a/sys/contrib/openzfs/tests/zfs-tests/cmd/write_dos_attributes/Makefile.am b/sys/contrib/openzfs/tests/zfs-tests/cmd/write_dos_attributes/Makefile.am
new file mode 100644
index 000000000000..c297fd49e0e9
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/cmd/write_dos_attributes/Makefile.am
@@ -0,0 +1,6 @@
+include $(top_srcdir)/config/Rules.am
+
+pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin
+
+pkgexec_PROGRAMS = write_dos_attributes
+write_dos_attributes_SOURCES = write_dos_attributes.c
diff --git a/sys/contrib/openzfs/tests/zfs-tests/cmd/write_dos_attributes/write_dos_attributes.c b/sys/contrib/openzfs/tests/zfs-tests/cmd/write_dos_attributes/write_dos_attributes.c
new file mode 100644
index 000000000000..c373d3b15318
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/cmd/write_dos_attributes/write_dos_attributes.c
@@ -0,0 +1,201 @@
+/*
+ * 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.
+ */
+
+/*
+ * Copyright 2022 iXsystems, Inc.
+ */
+
+/*
+ * FreeBSD allows to update and retreive additional file level attributes.
+ * For Linux, two IOCTLs have been added to update and retrieve additional
+ * level attributes.
+ *
+ * This application updates additional file level attributes on a given
+ * file. FreeBSD keywords can be used to specify the flag.
+ *
+ * Usage: 'write_dos_attributes flag filepath'
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <err.h>
+#include <sys/fs/zfs.h>
+#include <string.h>
+#include <ctype.h>
+
+#define SU_ARCH_SHORT "arch"
+#define SU_ARCH_FULL "archived"
+#define SU_NODUMP "nodump"
+#define SU_APPEND_SHORT "sappnd"
+#define SU_APPEND_FULL "sappend"
+#define SU_IMMUTABLE "schg"
+#define SU_IMMUTABLE_SHORT "schange"
+#define SU_IMMUTABLE_FULL "simmutable"
+#define SU_UNLINK_SHORT "sunlnk"
+#define SU_UNLINK_FULL "sunlink"
+#define U_APPEND_SHORT "uappnd"
+#define U_APPEND_FULL "uappend"
+#define U_ARCH_SHORT "uarch"
+#define U_ARCH_FULL "uarchive"
+#define U_IMMUTABLE "uchg"
+#define U_IMMUTABLE_SHORT "uchange"
+#define U_IMMUTABLE_FULL "uimmutable"
+#define U_HIDDEN_SHORT "hidden"
+#define U_HIDDEN_FULL "uhidden"
+#define U_OFFLINE_SHORT "offline"
+#define U_OFFLINE_FULL "uoffline"
+#define U_RDONLY "rdonly"
+#define U_RDONLY_SHORT "urdonly"
+#define U_RDONLY_FULL "readonly"
+#define U_SPARSE_SHORT "sparse"
+#define U_SPARSE_FULL "usparse"
+#define U_SYSTEM_SHORT "system"
+#define U_SYSTEM_FULL "usystem"
+#define U_REPARSE_SHORT "reparse"
+#define U_REPARSE_FULL "ureparse"
+#define U_UNLINK_SHORT "uunlnk"
+#define U_UNLINK_FULL "uunlink"
+#define UNSET_NODUMP "dump"
+
+#define IS_NO(s) (s[0] == 'n' && s[1] == 'o')
+
+uint64_t str_to_attribute(char *str);
+
+uint64_t
+str_to_attribute(char *str)
+{
+ if ((strcmp(str, SU_ARCH_SHORT) == 0) ||
+ (strcmp(str, SU_ARCH_FULL) == 0) ||
+ (strcmp(str, U_ARCH_SHORT) == 0) ||
+ (strcmp(str, U_ARCH_FULL) == 0))
+ return (ZFS_ARCHIVE);
+
+ else if ((strcmp(str, SU_APPEND_SHORT) == 0) ||
+ (strcmp(str, SU_APPEND_FULL) == 0) ||
+ (strcmp(str, U_APPEND_SHORT) == 0) ||
+ (strcmp(str, U_APPEND_FULL) == 0))
+ return (ZFS_APPENDONLY);
+
+ else if ((strcmp(str, SU_IMMUTABLE) == 0) ||
+ (strcmp(str, SU_IMMUTABLE_SHORT) == 0) ||
+ (strcmp(str, SU_IMMUTABLE_FULL) == 0))
+ return (ZFS_IMMUTABLE);
+
+ else if ((strcmp(str, SU_UNLINK_SHORT) == 0) ||
+ (strcmp(str, SU_UNLINK_FULL) == 0) ||
+ (strcmp(str, U_UNLINK_SHORT) == 0) ||
+ (strcmp(str, SU_UNLINK_FULL) == 0))
+ return (ZFS_NOUNLINK);
+
+ else if ((strcmp(str, U_HIDDEN_SHORT) == 0) ||
+ (strcmp(str, U_HIDDEN_FULL) == 0))
+ return (ZFS_HIDDEN);
+
+ else if ((strcmp(str, U_OFFLINE_SHORT) == 0) ||
+ (strcmp(str, U_OFFLINE_FULL) == 0))
+ return (ZFS_OFFLINE);
+
+ else if ((strcmp(str, U_RDONLY) == 0) ||
+ (strcmp(str, U_RDONLY_SHORT) == 0) ||
+ (strcmp(str, U_RDONLY_FULL) == 0))
+ return (ZFS_READONLY);
+
+ else if ((strcmp(str, U_SPARSE_SHORT) == 0) ||
+ (strcmp(str, U_SPARSE_FULL) == 0))
+ return (ZFS_SPARSE);
+
+ else if ((strcmp(str, U_SYSTEM_SHORT) == 0) ||
+ (strcmp(str, U_SYSTEM_FULL) == 0))
+ return (ZFS_SYSTEM);
+
+ else if ((strcmp(str, U_REPARSE_SHORT) == 0) ||
+ (strcmp(str, U_REPARSE_FULL) == 0))
+ return (ZFS_REPARSE);
+
+ return (-1);
+}
+
+int
+main(int argc, const char * const argv[])
+{
+ if (argc != 3)
+ errx(EXIT_FAILURE, "Usage: %s flag filepath", argv[0]);
+
+ uint8_t unset, unset_all;
+ uint64_t attribute, dosflags;
+ char *flag = strdup(argv[1]);
+ unset = unset_all = 0;
+ attribute = dosflags = 0;
+
+ // convert the flag to lower case
+ for (int i = 0; i < strlen(argv[1]); ++i)
+ flag[i] = tolower((unsigned char) flag[i]);
+
+ // check if flag starts with 'no'
+ if (IS_NO(flag)) {
+ if (strcmp(flag, SU_NODUMP) == 0) {
+ attribute = ZFS_NODUMP;
+ } else {
+ attribute = str_to_attribute(flag + 2);
+ unset = 1;
+ }
+ }
+ // check if '0' was passed
+ else if (strcmp(flag, "0") == 0) {
+ unset_all = 1;
+ }
+ // check if the flag is 'dump'
+ else if (strcmp(flag, UNSET_NODUMP) == 0) {
+ attribute = ZFS_NODUMP;
+ unset = 1;
+ } else {
+ attribute = str_to_attribute(flag);
+ }
+
+ if (attribute == -1)
+ errx(EXIT_FAILURE, "Invalid Flag %s", argv[1]);
+
+ int fd = open(argv[2], O_RDWR | O_APPEND);
+ if (fd < 0)
+ err(EXIT_FAILURE, "Failed to open %s", argv[2]);
+
+ if (ioctl(fd, ZFS_IOC_GETDOSFLAGS, &dosflags) == -1)
+ err(EXIT_FAILURE, "ZFS_IOC_GETDOSFLAGS failed");
+
+ if (unset == 0 && attribute != 0)
+ attribute |= dosflags;
+ else if (unset == 1 && attribute != 0)
+ attribute = dosflags & (~attribute);
+ else if (unset_all == 1)
+ attribute = 0;
+
+ // set the attribute/s
+ if (ioctl(fd, ZFS_IOC_SETDOSFLAGS, &attribute) == -1)
+ err(EXIT_FAILURE, "ZFS_IOC_SETDOSFLAGS failed");
+
+ // get the attributes to confirm
+ dosflags = -1;
+ if (ioctl(fd, ZFS_IOC_GETDOSFLAGS, &dosflags) == -1)
+ err(EXIT_FAILURE, "ZFS_IOC_GETDOSFLAGS failed");
+
+ (void) close(fd);
+
+ if (dosflags != attribute)
+ errx(EXIT_FAILURE, "Could not set %s attribute", argv[1]);
+
+ (void) printf("New Dos Flags: 0x%llx\n", (u_longlong_t)dosflags);
+
+ return (EXIT_SUCCESS);
+}
diff --git a/sys/contrib/openzfs/tests/zfs-tests/include/commands.cfg b/sys/contrib/openzfs/tests/zfs-tests/include/commands.cfg
index ca7628855d66..b247a67ff669 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/include/commands.cfg
+++ b/sys/contrib/openzfs/tests/zfs-tests/include/commands.cfg
@@ -51,6 +51,7 @@ export SYSTEM_FILES_COMMON='arp
iostat
kill
ksh
+ ldd
ln
logname
ls
@@ -76,6 +77,7 @@ export SYSTEM_FILES_COMMON='arp
readlink
rm
rmdir
+ rsync
scp
script
sed
@@ -109,8 +111,7 @@ export SYSTEM_FILES_COMMON='arp
vmstat
wait
wc
- which
- xargs'
+ which'
export SYSTEM_FILES_FREEBSD='chflags
compress
@@ -214,10 +215,12 @@ export ZFSTEST_FILES='badsend
randfree_file
randwritecomp
readmmap
+ read_dos_attributes
rename_dir
rm_lnkcnt_zero_file
send_doall
threadsappend
user_ns_exec
+ write_dos_attributes
xattrtest
stride_dd'
diff --git a/sys/contrib/openzfs/tests/zfs-tests/include/default.cfg.in b/sys/contrib/openzfs/tests/zfs-tests/include/default.cfg.in
index 1a9cc5a2bb62..cf382cfe994c 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/include/default.cfg.in
+++ b/sys/contrib/openzfs/tests/zfs-tests/include/default.cfg.in
@@ -155,6 +155,21 @@ done
export MAX_PARTITIONS=8
+if [ "@ASAN_ENABLED@" = "yes" ]; then
+ export ASAN_OPTIONS=abort_on_error=true:halt_on_error=true:allocator_may_return_null=true:disable_coredump=false:detect_stack_use_after_return=true
+
+ # TODO
+ # disable memory leaks detection
+ # there are quite many of them and they are not as
+ # destructive to CLI programs as they are to daemons
+ export ASAN_OPTIONS="$ASAN_OPTIONS:detect_leaks=false"
+fi
+
+if [ "@UBSAN_ENABLED@" = "yes" ]; then
+ export UBSAN_OPTIONS=abort_on_error=true:halt_on_error=true:print_stacktrace=true
+fi
+
+
case $(uname -o) in
GNU/Linux)
unpack_opts="--sparse -xf"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/include/libtest.shlib b/sys/contrib/openzfs/tests/zfs-tests/include/libtest.shlib
index 24010d9f3732..3c0cd04c5e0f 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/include/libtest.shlib
+++ b/sys/contrib/openzfs/tests/zfs-tests/include/libtest.shlib
@@ -448,7 +448,7 @@ function create_recv_clone
datasetexists $recvfs && log_fail "Recv filesystem must not exist."
datasetexists $sendfs && log_fail "Send filesystem must not exist."
- log_must zfs create -o mountpoint="$mountpoint" $sendfs
+ log_must zfs create -o compression=off -o mountpoint="$mountpoint" $sendfs
log_must zfs snapshot $snap
log_must eval "zfs send $snap | zfs recv -u $recvfs"
log_must mkfile 1m "$mountpoint/data"
@@ -545,11 +545,18 @@ function destroy_mirrors
log_pass
}
+function default_raidz_setup
+{
+ default_raidz_setup_noexit "$*"
+
+ log_pass
+}
+
#
# Given a minimum of two disks, set up a storage pool and dataset for the raid-z
# $1 the list of disks
#
-function default_raidz_setup
+function default_raidz_setup_noexit
{
typeset disklist="$*"
disks=(${disklist[*]})
@@ -562,8 +569,6 @@ function default_raidz_setup
log_must zpool create -f $TESTPOOL raidz $disklist
log_must zfs create $TESTPOOL/$TESTFS
log_must zfs set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
-
- log_pass
}
#
@@ -2141,7 +2146,7 @@ function get_disklist # pool
disklist=$(zpool iostat -v $1 | nawk '(NR >4) {print $1}' | \
grep -v "\-\-\-\-\-" | \
- egrep -v -e "^(mirror|raidz[1-3]|spare|log|cache|special|dedup)$")
+ egrep -v -e "^(mirror|raidz[1-3]|draid[1-3]|spare|log|cache|special|dedup)|\-[0-9]$")
echo $disklist
}
@@ -3567,17 +3572,19 @@ function wait_replacing #pool
done
}
-#
# Wait for a pool to be scrubbed
#
# $1 pool name
+# $2 timeout
#
-function wait_scrubbed
+function wait_scrubbed #pool timeout
{
- typeset pool=${1:-$TESTPOOL}
- while ! is_pool_scrubbed $pool ; do
- sleep 1
- done
+ typeset timeout=${2:-300}
+ typeset pool=${1:-$TESTPOOL}
+ for (( timer = 0; timer < $timeout; timer++ )); do
+ is_pool_scrubbed $pool && break;
+ sleep 1;
+ done
}
# Backup the zed.rc in our test directory so that we can edit it for our test.
@@ -3672,6 +3679,21 @@ function zed_cleanup
}
#
+# Check if ZED is currently running; if so, returns PIDs
+#
+function zed_check
+{
+ if ! is_linux; then
+ return
+ fi
+ zedpids="$(pgrep -x zed)"
+# ret1=$?
+ zedpids2="$(pgrep -x lt-zed)"
+# ret2=$?
+ echo ${zedpids} ${zedpids2}
+}
+
+#
# Check if ZED is currently running, if not start ZED.
#
function zed_start
@@ -3686,9 +3708,14 @@ function zed_start
fi
# Verify the ZED is not already running.
- pgrep -x zed > /dev/null
- if (($? == 0)); then
- log_note "ZED already running"
+ zedpids=$(zed_check)
+ if [ -n "$zedpids" ]; then
+ # We never, ever, really want it to just keep going if zed
+ # is already running - usually this implies our test cases
+ # will break very strangely because whatever we wanted to
+ # configure zed for won't be listening to our changes in the
+ # tmpdir
+ log_fail "ZED already running - ${zedpids}"
else
log_note "Starting ZED"
# run ZED in the background and redirect foreground logging
@@ -3707,13 +3734,13 @@ function zed_start
function zed_stop
{
if ! is_linux; then
- return
+ return ""
fi
log_note "Stopping ZED"
while true; do
- zedpids="$(pgrep -x zed)"
- [ "$?" -ne 0 ] && break
+ zedpids=$(zed_check)
+ [ ! -n "$zedpids" ] && break
log_must kill $zedpids
sleep 1
@@ -4303,3 +4330,86 @@ function wait_for_children #children
done
return $rv
}
+
+#
+# Compare two directory trees recursively in a manner similar to diff(1), but
+# using rsync. If there are any discrepancies, a summary of the differences are
+# output and a non-zero error is returned.
+#
+# If you're comparing a directory after a ZIL replay, you should set
+# LIBTEST_DIFF_ZIL_REPLAY=1 or use replay_directory_diff which will cause
+# directory_diff to ignore mtime changes (the ZIL replay won't fix up mtime
+# information).
+#
+function directory_diff # dir_a dir_b
+{
+ dir_a="$1"
+ dir_b="$2"
+ zil_replay="${LIBTEST_DIFF_ZIL_REPLAY:-0}"
+
+ # If one of the directories doesn't exist, return 2. This is to match the
+ # semantics of diff.
+ if ! [ -d "$dir_a" -a -d "$dir_b" ]; then
+ return 2
+ fi
+
+ # Run rsync with --dry-run --itemize-changes to get something akin to diff
+ # output, but rsync is far more thorough in detecting differences (diff
+ # doesn't compare file metadata, and cannot handle special files).
+ #
+ # Also make sure to filter out non-user.* xattrs when comparing. On
+ # SELinux-enabled systems the copied tree will probably have different
+ # SELinux labels.
+ args=("-nicaAHX" '--filter=-x! user.*' "--delete")
+
+ # NOTE: Quite a few rsync builds do not support --crtimes which would be
+ # necessary to verify that creation times are being maintained properly.
+ # Unfortunately because of this we cannot use it unconditionally but we can
+ # check if this rsync build supports it and use it then. This check is
+ # based on the same check in the rsync test suite (testsuite/crtimes.test).
+ #
+ # We check ctimes even with zil_replay=1 because the ZIL does store
+ # creation times and we should make sure they match (if the creation times
+ # do not match there is a "c" entry in one of the columns).
+ if ( rsync --version | grep -q "[, ] crtimes" >/dev/null ); then
+ args+=("--crtimes")
+ else
+ echo "NOTE: This rsync package does not support --crtimes (-N)."
+ fi
+
+ # If we are testing a ZIL replay, we need to ignore timestamp changes.
+ # Unfortunately --no-times doesn't do what we want -- it will still tell
+ # you if the timestamps don't match but rsync will set the timestamps to
+ # the current time (leading to an itemised change entry). It's simpler to
+ # just filter out those lines.
+ if [ "$zil_replay" -eq 0 ]; then
+ filter=("cat")
+ else
+ # Different rsync versions have different numbers of columns. So just
+ # require that aside from the first two, all other columns must be
+ # blank (literal ".") or a timestamp field ("[tT]").
+ filter=("grep" "-v" '^\..[.Tt]\+ ')
+ fi
+
+ diff="$(rsync "${args[@]}" "$dir_a/" "$dir_b/" | "${filter[@]}")"
+ rv=0
+ if [ -n "$diff" ]; then
+ echo "$diff"
+ rv=1
+ fi
+ return $rv
+}
+
+#
+# Compare two directory trees recursively, without checking whether the mtimes
+# match (creation times will be checked if the available rsync binary supports
+# it). This is necessary for ZIL replay checks (because the ZIL does not
+# contain mtimes and thus after a ZIL replay, mtimes won't match).
+#
+# This is shorthand for LIBTEST_DIFF_ZIL_REPLAY=1 directory_diff <...>.
+#
+function replay_directory_diff # dir_a dir_b
+{
+ LIBTEST_DIFF_ZIL_REPLAY=1 directory_diff "$@"
+ return $?
+}
diff --git a/sys/contrib/openzfs/tests/zfs-tests/include/tunables.cfg b/sys/contrib/openzfs/tests/zfs-tests/include/tunables.cfg
index fff43e469165..d3838cb7c8ed 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/include/tunables.cfg
+++ b/sys/contrib/openzfs/tests/zfs-tests/include/tunables.cfg
@@ -87,9 +87,11 @@ VDEV_VALIDATE_SKIP vdev.validate_skip vdev_validate_skip
VOL_INHIBIT_DEV UNSUPPORTED zvol_inhibit_dev
VOL_MODE vol.mode zvol_volmode
VOL_RECURSIVE vol.recursive UNSUPPORTED
+XATTR_COMPAT xattr_compat zfs_xattr_compat
ZEVENT_LEN_MAX zevent.len_max zfs_zevent_len_max
ZEVENT_RETAIN_MAX zevent.retain_max zfs_zevent_retain_max
ZIO_SLOW_IO_MS zio.slow_io_ms zio_slow_io_ms
+ZIL_SAXATTR zil_saxattr zfs_zil_saxattr
%%%%
while read name FreeBSD Linux; do
eval "export ${name}=\$${UNAME}"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/Makefile.am b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/Makefile.am
index 1412e3d8132e..9164650e3419 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/Makefile.am
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/Makefile.am
@@ -21,6 +21,7 @@ SUBDIRS = \
deadman \
delegate \
devices \
+ dos_attributes \
events \
exec \
fallocate \
@@ -89,5 +90,6 @@ SUBDIRS = \
if BUILD_LINUX
SUBDIRS += \
+ simd \
tmpfile
endif
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/acl/off/Makefile.am b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/acl/off/Makefile.am
index 36aa13dd03fd..ae6a9c69d934 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/acl/off/Makefile.am
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/acl/off/Makefile.am
@@ -10,7 +10,5 @@ dist_pkgdata_SCRIPTS = \
pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/acl/off
-if BUILD_FREEBSD
pkgexec_PROGRAMS = dosmode_readonly_write
dosmode_readonly_write_SOURCES = dosmode_readonly_write.c
-endif
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/acl/off/dosmode.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/acl/off/dosmode.ksh
index e232dfd525c6..585aa025390c 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/acl/off/dosmode.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/acl/off/dosmode.ksh
@@ -31,8 +31,6 @@
# DESCRIPTION:
# Verify that DOS mode flags function correctly.
#
-# These flags are not currently exposed on Linux, so the test is
-# only useful on FreeBSD.
#
# STRATEGY:
# 1. ARCHIVE
@@ -56,7 +54,13 @@ function hasflag
typeset flag=$1
typeset path=$2
- ls -lo $path | awk '{ gsub(",", "\n", $5); print $5 }' | grep -qxF $flag
+ if is_linux; then
+ read_dos_attributes $path | awk \
+ '{ gsub(",", "\n", $1); print $1 }' | grep -qxF $flag
+ else
+ ls -lo $path | awk '{ gsub(",", "\n", $5); print $5 }' | \
+ grep -qxF $flag
+ fi
}
log_assert "Verify DOS mode flags function correctly"
@@ -67,6 +71,12 @@ testfile=$TESTDIR/testfile
owner=$ZFS_ACL_STAFF1
other=$ZFS_ACL_STAFF2
+if is_linux; then
+ changeflags=write_dos_attributes
+else
+ changeflags=chflags
+fi
+
#
# ARCHIVE
#
@@ -75,36 +85,40 @@ other=$ZFS_ACL_STAFF2
#
log_must touch $testfile
log_must hasflag uarch $testfile
-log_must chflags nouarch $testfile
+log_must $changeflags nouarch $testfile
log_must hasflag - $testfile
log_must touch $testfile
-log_must hasflag uarch $testfile
+if ! is_linux; then
+ log_must hasflag uarch $testfile
+fi
log_must rm $testfile
log_must user_run $owner touch $testfile
log_must hasflag uarch $testfile
-log_must user_run $owner chflags nouarch $testfile
-log_mustnot user_run $other chflags uarch $testfile
+log_must user_run $owner $changeflags nouarch $testfile
+log_mustnot user_run $other $changeflags uarch $testfile
log_must hasflag - $testfile
log_must user_run $owner touch $testfile
-log_mustnot user_run $other chflags nouarch $testfile
-log_must hasflag uarch $testfile
+log_mustnot user_run $other $changeflags nouarch $testfile
+if ! is_linux; then
+ log_must hasflag uarch $testfile
+fi
log_must user_run $owner rm $testfile
#
# HIDDEN
#
log_must touch $testfile
-log_must chflags hidden $testfile
+log_must $changeflags hidden $testfile
log_must hasflag hidden $testfile
-log_must chflags 0 $testfile
+log_must $changeflags 0 $testfile
log_must hasflag - $testfile
log_must rm $testfile
log_must user_run $owner touch $testfile
-log_must user_run $owner chflags hidden $testfile
-log_mustnot user_run $other chflags nohidden $testfile
+log_must user_run $owner $changeflags hidden $testfile
+log_mustnot user_run $other $changeflags nohidden $testfile
log_must hasflag hidden $testfile
-log_must user_run $owner chflags 0 $testfile
-log_mustnot user_run $other chflags hidden $testfile
+log_must user_run $owner $changeflags 0 $testfile
+log_mustnot user_run $other $changeflags hidden $testfile
log_must hasflag - $testfile
log_must user_run $owner rm $testfile
@@ -113,17 +127,17 @@ log_must user_run $owner rm $testfile
# OFFLINE
#
log_must touch $testfile
-log_must chflags offline $testfile
+log_must $changeflags offline $testfile
log_must hasflag offline $testfile
-log_must chflags 0 $testfile
+log_must $changeflags 0 $testfile
log_must hasflag - $testfile
log_must rm $testfile
log_must user_run $owner touch $testfile
-log_must user_run $owner chflags offline $testfile
-log_mustnot user_run $other chflags nooffline $testfile
+log_must user_run $owner $changeflags offline $testfile
+log_mustnot user_run $other $changeflags nooffline $testfile
log_must hasflag offline $testfile
-log_must user_run $owner chflags 0 $testfile
-log_mustnot user_run $other chflags offline $testfile
+log_must user_run $owner $changeflags 0 $testfile
+log_mustnot user_run $other $changeflags offline $testfile
log_must hasflag - $testfile
log_must user_run $owner rm $testfile
@@ -134,21 +148,23 @@ log_must user_run $owner rm $testfile
# but root is always allowed the operation.
#
log_must touch $testfile
-log_must chflags rdonly $testfile
+log_must $changeflags rdonly $testfile
log_must hasflag rdonly $testfile
log_must eval "echo 'root write allowed' >> $testfile"
log_must cat $testfile
-log_must chflags 0 $testfile
-log_must hasflag - $tesfile
+log_must $changeflags 0 $testfile
+log_must hasflag - $testfile
log_must rm $testfile
# It is required to still be able to write to an fd that was opened RW before
# READONLY is set. We have a special test program for that.
log_must user_run $owner touch $testfile
-log_mustnot user_run $other chflags rdonly $testfile
+log_mustnot user_run $other $changeflags rdonly $testfile
log_must user_run $owner $tests_base/dosmode_readonly_write $testfile
-log_mustnot user_run $other chflags nordonly $testfile
+log_mustnot user_run $other $changeflags nordonly $testfile
log_must hasflag rdonly $testfile
-log_mustnot user_run $owner "echo 'user write forbidden' >> $testfile"
+if ! is_linux; then
+ log_mustnot user_run $owner "echo 'user write forbidden' >> $testfile"
+fi
log_must eval "echo 'root write allowed' >> $testfile"
# We are still allowed to read and remove the file when READONLY is set.
log_must user_run $owner cat $testfile
@@ -157,24 +173,23 @@ log_must user_run $owner rm $testfile
#
# REPARSE
#
-# FIXME: does not work, not sure if broken or testing wrong
-#
+# not allowed to be changed
#
# SPARSE
#
log_must truncate -s 1m $testfile
-log_must chflags sparse $testfile
+log_must $changeflags sparse $testfile
log_must hasflag sparse $testfile
-log_must chflags 0 $testfile
+log_must $changeflags 0 $testfile
log_must hasflag - $testfile
log_must rm $testfile
log_must user_run $owner truncate -s 1m $testfile
-log_must user_run $owner chflags sparse $testfile
-log_mustnot user_run $other chflags nosparse $testfile
+log_must user_run $owner $changeflags sparse $testfile
+log_mustnot user_run $other $changeflags nosparse $testfile
log_must hasflag sparse $testfile
-log_must user_run $owner chflags 0 $testfile
-log_mustnot user_run $other chflags sparse $testfile
+log_must user_run $owner $changeflags 0 $testfile
+log_mustnot user_run $other $changeflags sparse $testfile
log_must hasflag - $testfile
log_must user_run $owner rm $testfile
@@ -182,17 +197,17 @@ log_must user_run $owner rm $testfile
# SYSTEM
#
log_must touch $testfile
-log_must chflags system $testfile
+log_must $changeflags system $testfile
log_must hasflag system $testfile
-log_must chflags 0 $testfile
+log_must $changeflags 0 $testfile
log_must hasflag - $testfile
log_must rm $testfile
log_must user_run $owner touch $testfile
-log_must user_run $owner chflags system $testfile
-log_mustnot user_run $other chflags nosystem $testfile
+log_must user_run $owner $changeflags system $testfile
+log_mustnot user_run $other $changeflags nosystem $testfile
log_must hasflag system $testfile
-log_must user_run $owner chflags 0 $testfile
-log_mustnot user_run $other chflags system $testfile
+log_must user_run $owner $changeflags 0 $testfile
+log_mustnot user_run $other $changeflags system $testfile
log_must hasflag - $testfile
log_must user_run $owner rm $testfile
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/acl/off/dosmode_readonly_write.c b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/acl/off/dosmode_readonly_write.c
index 372c3f7f64de..0441d1c7b472 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/acl/off/dosmode_readonly_write.c
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/acl/off/dosmode_readonly_write.c
@@ -36,6 +36,11 @@
#include <string.h>
#include <unistd.h>
+#ifdef __linux__
+#include <stdint.h>
+#include <sys/fs/zfs.h>
+#endif
+
int
main(int argc, const char *argv[])
{
@@ -51,8 +56,14 @@ main(int argc, const char *argv[])
fd = open(path, O_CREAT|O_RDWR, 0777);
if (fd == -1)
err(EXIT_FAILURE, "%s: open failed", path);
+#ifdef __linux__
+ uint64_t dosflags = ZFS_READONLY;
+ if (ioctl(fd, ZFS_IOC_SETDOSFLAGS, &dosflags) == -1)
+ err(EXIT_FAILURE, "%s: ZFS_IOC_SETDOSFLAGS failed", path);
+#else
if (chflags(path, UF_READONLY) == -1)
err(EXIT_FAILURE, "%s: chflags failed", path);
+#endif
if (write(fd, buf, strlen(buf)) == -1)
err(EXIT_FAILURE, "%s: write failed", path);
if (close(fd) == -1)
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/alloc_class/alloc_class_012_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/alloc_class/alloc_class_012_pos.ksh
index 2bce471a7f30..0b1c18bafdaf 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/alloc_class/alloc_class_012_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/alloc_class/alloc_class_012_pos.ksh
@@ -33,7 +33,8 @@ function file_in_special_vdev # <dataset> <inode>
{
typeset dataset="$1"
typeset inum="$2"
- typeset num_normal=$(echo $ZPOOL_DISKS | wc -w | xargs)
+ typeset num_normal=$(echo $ZPOOL_DISKS | wc -w)
+ num_normal=${num_normal##* }
zdb -dddddd $dataset $inum | awk -v d=$num_normal '{
# find DVAs from string "offset level dva" only for L0 (data) blocks
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/alloc_class/alloc_class_013_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/alloc_class/alloc_class_013_pos.ksh
index 7a0eb53436a1..624cab88af0c 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/alloc_class/alloc_class_013_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/alloc_class/alloc_class_013_pos.ksh
@@ -41,8 +41,8 @@ log_must display_status "$TESTPOOL"
#
log_must zfs create -o dedup=on -V 2G $TESTPOOL/$TESTVOL
-
-log_must eval "new_fs $ZVOL_DEVDIR/$TESTPOOL/$TESTVOL >/dev/null 2>&1"
+block_device_wait "$ZVOL_DEVDIR/$TESTPOOL/$TESTVOL"
+log_must eval "new_fs $ZVOL_DEVDIR/$TESTPOOL/$TESTVOL >/dev/null"
sync_pool
log_must zpool list -v $TESTPOOL
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zdb/zdb_object_range_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zdb/zdb_object_range_pos.ksh
index 61c031a0ce5b..1e63ac7d2f4e 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zdb/zdb_object_range_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zdb/zdb_object_range_pos.ksh
@@ -142,8 +142,8 @@ log_must test "\n$actual\n" == "\n$expected\n"
# Specifying individual object IDs works
objects="$start1 $end1 $start2 $end2"
expected="$objects"
-actual=$(get_object_list $TESTPOOL/$TESTFS $objects | awk '{print $1}' | xargs)
-log_must test "$actual" == "$expected"
+actual=$(get_object_list $TESTPOOL/$TESTFS $objects | awk '{print $1}' | tr '\n' ' ')
+log_must test "${actual% }" == "$expected"
# Get all objects in the meta-objset to test m (spacemap) and z (zap) flags
all_mos_objects=$(get_object_list $TESTPOOL 0:-1)
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zdb/zdb_objset_id.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zdb/zdb_objset_id.ksh
index 27d3d61fbbad..accb125280f0 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zdb/zdb_objset_id.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zdb/zdb_objset_id.ksh
@@ -54,6 +54,8 @@ write_count=8
blksize=131072
verify_runnable "global"
verify_disk_count "$DISKS" 2
+hex_ds=$TESTPOOL/0x400000
+num_ds=$TESTPOOL/100000
default_mirror_setup_noexit $DISKS
file_write -o create -w -f $init_data -b $blksize -c $write_count
@@ -111,23 +113,23 @@ if is_linux; then
"zdb -dddddd $TESTPOOL/$objset_hex failed $reason"
fi
-log_must zfs create $TESTPOOL/0x400
-log_must zfs create $TESTPOOL/100
-output=$(zdb -d $TESTPOOL/0x400)
+log_must zfs create $hex_ds
+log_must zfs create $num_ds
+output=$(zdb -d $hex_ds)
reason="($TESTPOOL/0x400 not in zdb output)"
-echo $output |grep "$TESTPOOL/0x400" > /dev/null
+echo $output |grep "$hex_ds" > /dev/null
(( $? != 0 )) && log_fail \
- "zdb -d $TESTPOOL/0x400 failed $reason"
-output=$(zdb -d $TESTPOOL/100)
-reason="($TESTPOOL/100 not in zdb output)"
-echo $output |grep "$TESTPOOL/100" > /dev/null
+ "zdb -d $hex_ds failed $reason"
+output=$(zdb -d $num_ds)
+reason="($num_ds not in zdb output)"
+echo $output |grep "$num_ds" > /dev/null
(( $? != 0 )) && log_fail \
- "zdb -d $TESTPOOL/100 failed $reason"
+ "zdb -d $num_ds failed $reason"
-# force numeric interpretation, should fail
-log_mustnot zdb -N $TESTPOOL/0x400
-log_mustnot zdb -N $TESTPOOL/100
-log_mustnot zdb -Nd $TESTPOOL/0x400
-log_mustnot zdb -Nd $TESTPOOL/100
+# force numeric interpretation, expect fail
+log_mustnot zdb -N $hex_ds
+log_mustnot zdb -N $num_ds
+log_mustnot zdb -Nd $hex_ds
+log_mustnot zdb -Nd $num_ds
log_pass "zdb -d <pool>/<objset ID> generates the correct names."
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs/zfs_002_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs/zfs_002_pos.ksh
index 1290d888a947..51a7ce1d96d7 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs/zfs_002_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs/zfs_002_pos.ksh
@@ -97,7 +97,6 @@ if is_linux; then
ulimit -c unlimited
echo "$corefile" >/proc/sys/kernel/core_pattern
echo 0 >/proc/sys/kernel/core_uses_pid
- export ASAN_OPTIONS="abort_on_error=1:disable_coredump=0"
elif is_freebsd; then
ulimit -c unlimited
savedcorefile=$(sysctl -n kern.corefile)
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/zfs_copies_002_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/zfs_copies_002_pos.ksh
index 5774fb873f33..61d7aa28d27c 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/zfs_copies_002_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/zfs_copies_002_pos.ksh
@@ -59,7 +59,7 @@ log_assert "Verify that the space used by multiple copies is charged correctly."
log_onexit cleanup
for val in 1 2 3; do
- log_must zfs create -o copies=$val $TESTPOOL/fs_$val
+ log_must zfs create -o compression=off -o copies=$val $TESTPOOL/fs_$val
log_must mkfile $FILESIZE /$TESTPOOL/fs_$val/$FILE
done
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/setup.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/setup.ksh
index 6a9af3bc28c3..f4288f715b22 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/setup.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/setup.ksh
@@ -29,4 +29,6 @@
DISK=${DISKS%% *}
-default_setup $DISK
+default_setup_noexit $DISK
+log_must zfs set compression=off $TESTPOOL/$TESTFS
+log_pass
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_clone_livelist_condense_and_disable.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_clone_livelist_condense_and_disable.ksh
index 2f328ceac4ae..b9d6ad1e5dcf 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_clone_livelist_condense_and_disable.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_clone_livelist_condense_and_disable.ksh
@@ -39,6 +39,7 @@ function cleanup
set_tunable64 LIVELIST_MAX_ENTRIES $ORIGINAL_MAX
# reset the minimum percent shared to 75
set_tunable32 LIVELIST_MIN_PERCENT_SHARED $ORIGINAL_MIN
+ log_must zfs inherit compression $TESTPOOL
}
function check_ll_len
@@ -116,6 +117,11 @@ ORIGINAL_MAX=$(get_tunable LIVELIST_MAX_ENTRIES)
ORIGINAL_MIN=$(get_tunable LIVELIST_MIN_PERCENT_SHARED)
log_onexit cleanup
+# You might think that setting compression=off for $TESTFS1 would be
+# sufficient. You would be mistaken.
+# You need compression=off for whatever the parent of $TESTFS1 is,
+# and $TESTFS1.
+log_must zfs set compression=off $TESTPOOL
log_must zfs create $TESTPOOL/$TESTFS1
log_must mkfile 5m /$TESTPOOL/$TESTFS1/atestfile
log_must zfs snapshot $TESTPOOL/$TESTFS1@snap
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_clone_livelist_condense_races.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_clone_livelist_condense_races.ksh
index d83280e32dea..cf248bb87f94 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_clone_livelist_condense_races.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_clone_livelist_condense_races.ksh
@@ -42,6 +42,7 @@ function cleanup
# reset the condense tests to 0
set_tunable32 LIVELIST_CONDENSE_ZTHR_PAUSE 0
set_tunable32 LIVELIST_CONDENSE_SYNC_PAUSE 0
+ log_must zfs inherit compression $TESTPOOL
}
function delete_race
@@ -93,6 +94,11 @@ ORIGINAL_MAX=$(get_tunable LIVELIST_MAX_ENTRIES)
log_onexit cleanup
+# You might think that setting compression=off for $TESTFS1 would be
+# sufficient. You would be mistaken.
+# You need compression=off for whatever the parent of $TESTFS1 is,
+# and $TESTFS1.
+log_must zfs set compression=off $TESTPOOL
log_must zfs create $TESTPOOL/$TESTFS1
log_must mkfile 100m /$TESTPOOL/$TESTFS1/atestfile
sync_pool $TESTPOOL
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_clone_livelist_dedup.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_clone_livelist_dedup.ksh
index 00583402db89..9632cf01b3b6 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_clone_livelist_dedup.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_clone_livelist_dedup.ksh
@@ -80,9 +80,16 @@ function test_dedup
ORIGINAL_MIN_SHARED=$(get_tunable LIVELIST_MIN_PERCENT_SHARED)
log_onexit cleanup
+# You might think that setting compression=off for $TESTFS1 would be
+# sufficient. You would be mistaken.
+# You need compression=off for whatever the parent of $TESTFS1 is,
+# and $TESTFS1.
+log_must zfs set compression=off $TESTPOOL
log_must zfs create $TESTPOOL/$TESTFS1
log_must mkfile 5m /$TESTPOOL/$TESTFS1/atestfile
log_must zfs snapshot $TESTPOOL/$TESTFS1@snap
test_dedup
+log_must zfs inherit compression $TESTPOOL
+
log_pass "Clone's livelist processes dedup blocks as expected."
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_clone_livelist.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_clone_livelist.ksh
index 9165b03a1647..54d6096890b3 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_clone_livelist.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_clone_livelist.ksh
@@ -42,6 +42,7 @@ function cleanup
datasetexists $TESTPOOL/$TESTFS1 && destroy_dataset $TESTPOOL/$TESTFS1 -R
# reset the livelist sublist size to its original value
set_tunable64 LIVELIST_MAX_ENTRIES $ORIGINAL_MAX
+ log_must zfs inherit compression $TESTPOOL
}
function clone_write_file
@@ -146,6 +147,11 @@ function test_clone_clone_promote
ORIGINAL_MAX=$(get_tunable LIVELIST_MAX_ENTRIES)
log_onexit cleanup
+# You might think that setting compression=off for $TESTFS1 would be
+# sufficient. You would be mistaken.
+# You need compression=off for whatever the parent of $TESTFS1 is,
+# and $TESTFS1.
+log_must zfs set compression=off $TESTPOOL
log_must zfs create $TESTPOOL/$TESTFS1
log_must mkfile 20m /$TESTPOOL/$TESTFS1/atestfile
log_must zfs snapshot $TESTPOOL/$TESTFS1@snap
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_dev_removal_condense.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_dev_removal_condense.ksh
index b4f2740c7aa2..fa5ebb6cce98 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_dev_removal_condense.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_dev_removal_condense.ksh
@@ -53,7 +53,7 @@ VIRTUAL_DISK2=$TEST_BASE_DIR/disk2
log_must truncate -s $(($MINVDEVSIZE * 8)) $VIRTUAL_DISK1
log_must truncate -s $(($MINVDEVSIZE * 16)) $VIRTUAL_DISK2
-log_must zpool create $TESTPOOL2 $VIRTUAL_DISK1
+log_must zpool create -O compression=off $TESTPOOL2 $VIRTUAL_DISK1
log_must poolexists $TESTPOOL2
log_must zfs create $TESTPOOL2/$TESTFS
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/Makefile.am b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/Makefile.am
index aa23c71bdb0c..cf9490de4e81 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/Makefile.am
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/Makefile.am
@@ -27,7 +27,8 @@ dist_pkgdata_SCRIPTS = \
zfs_receive_raw.ksh \
zfs_receive_raw_incremental.ksh \
zfs_receive_raw_-d.ksh \
- zfs_receive_-e.ksh
+ zfs_receive_-e.ksh \
+ zfs_receive_-wR-encrypted-mix.ksh
dist_pkgdata_DATA = \
zstd_test_data.txt
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/receive-o-x_props_aliases.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/receive-o-x_props_aliases.ksh
index d4b0aa2341fc..6e5b48ffe272 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/receive-o-x_props_aliases.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/receive-o-x_props_aliases.ksh
@@ -129,7 +129,7 @@ log_must eval "check_prop_inherit $destsub copies $dest"
log_must eval "check_prop_inherit $destsub atime $dest"
log_must eval "check_prop_inherit $destsub checksum $dest"
log_must eval "check_prop_source $destsub quota 0 default"
-log_must eval "check_prop_source $destsub compression off default"
+log_must eval "check_prop_source $destsub compression on default"
# Cleanup
log_must zfs destroy -r -f $orig
log_must zfs destroy -r -f $dest
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/receive-o-x_props_override.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/receive-o-x_props_override.ksh
index 2d3c15c62fc9..44fe60463b2f 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/receive-o-x_props_override.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/receive-o-x_props_override.ksh
@@ -135,7 +135,7 @@ log_must eval "check_prop_inherit $destsub atime $dest"
log_must eval "check_prop_inherit $destsub checksum $dest"
log_must eval "check_prop_inherit $destsub '$userprop:dest2' $dest"
log_must eval "check_prop_source $destsub quota 0 default"
-log_must eval "check_prop_source $destsub compression off default"
+log_must eval "check_prop_source $destsub compression on default"
log_must eval "check_prop_missing $dest '$userprop:orig'"
log_must eval "check_prop_missing $destsub '$userprop:orig'"
log_must eval "check_prop_source " \
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_-wR-encrypted-mix.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_-wR-encrypted-mix.ksh
new file mode 100755
index 000000000000..6e27130e0248
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_-wR-encrypted-mix.ksh
@@ -0,0 +1,75 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or 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) 2022 by Attila Fülöp <attila@fueloep.org>
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# ZFS should receive a raw send of a mix of unencrypted and encrypted
+# child datasets
+#
+# The layout of the datasets is: enc/unenc/enc/unenc
+#
+# STRATEGY:
+# 1. Create the dataset hierarchy
+# 2. Snapshot the dataset hierarchy
+# 3. Send -Rw the dataset hierarchy and receive into a top-level dataset
+# 4. Check the encryption property of the received datasets
+
+verify_runnable "both"
+
+function cleanup
+{
+ datasetexists "$TESTPOOL/$TESTFS1" && \
+ destroy_dataset "$TESTPOOL/$TESTFS1" -r
+
+ datasetexists "$TESTPOOL/$TESTFS2" && \
+ destroy_dataset "$TESTPOOL/$TESTFS2" -r
+}
+
+log_onexit cleanup
+
+log_assert "ZFS should receive a mix of un/encrypted childs"
+
+typeset src="$TESTPOOL/$TESTFS1"
+typeset dst="$TESTPOOL/$TESTFS2"
+typeset snap="snap"
+
+echo "password" | \
+ create_dataset "$src" -o encryption=on -o keyformat=passphrase
+create_dataset "$src/u" "-o encryption=off"
+echo "password" | \
+ create_dataset "$src/u/e" -o encryption=on -o keyformat=passphrase
+create_dataset "$src/u/e/u" -o encryption=off
+
+log_must zfs snapshot -r "$src@$snap"
+log_must eval "zfs send -Rw $src@$snap | zfs receive -u $dst"
+log_must test "$(get_prop 'encryption' $dst)" != "off"
+log_must test "$(get_prop 'encryption' $dst/u)" == "off"
+log_must test "$(get_prop 'encryption' $dst/u/e)" != "off"
+log_must test "$(get_prop 'encryption' $dst/u/e/u)" == "off"
+
+log_pass "ZFS can receive a mix of un/encrypted childs"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_010_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_010_pos.ksh
index 84485977aa23..47e23e6ebca7 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_010_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_010_pos.ksh
@@ -166,12 +166,12 @@ log_must zfs destroy -fr $rfs
cat $TESTDIR/zr010p | log_must zfs receive -o origin=$fs2@s1 $rfs
mntpnt_old=$(get_prop mountpoint $fs)
mntpnt_new=$(get_prop mountpoint $rfs)
-log_must diff -r $mntpnt_old $mntpnt_new
+log_must directory_diff $mntpnt_old $mntpnt_new
log_must zfs destroy -r $rfs
cat $TESTDIR/zr010p2 | log_must zfs receive -o origin=$fs@s1 $rfs
mntpnt_old=$(get_prop mountpoint $fs2)
mntpnt_new=$(get_prop mountpoint $rfs)
-log_must diff -r $mntpnt_old $mntpnt_new
+log_must directory_diff $mntpnt_old $mntpnt_new
log_pass "zfs receive of full send as clone works"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_to_encrypted.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_to_encrypted.ksh
index 526497401f28..5d76c220fc45 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_to_encrypted.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_to_encrypted.ksh
@@ -59,19 +59,29 @@ log_must eval "echo $passphrase | zfs create -o encryption=on" \
log_note "Verifying ZFS will receive to an encrypted child"
log_must eval "zfs send $snap | zfs receive $TESTPOOL/$TESTFS1/c1"
+log_must test "$(get_prop 'encryption' $TESTPOOL/$TESTFS1/c1)" != "off"
-log_note "Verifying 'send -p' will receive to an encrypted child"
+# Unload the key, the following tests won't require it and we will test
+# the receive checks as well.
+log_must zfs unmount $TESTPOOL/$TESTFS1
+log_must zfs unload-key $TESTPOOL/$TESTFS1
+
+log_note "Verifying 'send -p' will receive to an unencrypted child"
log_must eval "zfs send -p $snap | zfs receive $TESTPOOL/$TESTFS1/c2"
log_must test "$(get_prop 'encryption' $TESTPOOL/$TESTFS1/c2)" == "off"
-log_note "Verifying 'send -R' will receive to an encrypted child"
+# For completeness add the property override case.
+log_note "Verifying recv -o encyption=off' will receive to an unencrypted child"
+log_must eval "zfs send $snap | \
+ zfs receive -o encryption=off $TESTPOOL/$TESTFS1/c2o"
+log_must test "$(get_prop 'encryption' $TESTPOOL/$TESTFS1/c2o)" == "off"
+
+log_note "Verifying 'send -R' will receive to an unencrypted child"
log_must eval "zfs send -R $snap | zfs receive $TESTPOOL/$TESTFS1/c3"
log_must test "$(get_prop 'encryption' $TESTPOOL/$TESTFS1/c3)" == "off"
log_note "Verifying ZFS will not receive to an encrypted child when the" \
"parent key is unloaded"
-log_must zfs unmount $TESTPOOL/$TESTFS1
-log_must zfs unload-key $TESTPOOL/$TESTFS1
log_mustnot eval "zfs send $snap | zfs receive $TESTPOOL/$TESTFS1/c4"
log_pass "ZFS can receive encrypted filesystems into child dataset"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/setup.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/setup.ksh
index 60acbe07acbe..788e093fb2ca 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/setup.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/setup.ksh
@@ -42,7 +42,8 @@ if [[ -d $TESTDIR2 ]]; then
log_unresolved Could not remove $TESTDIR2
fi
fi
-log_must zfs create $TESTPOOL/$DATAFS
+log_must zfs set compression=off $TESTPOOL/$TESTFS
+log_must zfs create -o compression=off $TESTPOOL/$DATAFS
log_must zfs set mountpoint=$TESTDIR2 $TESTPOOL/$DATAFS
log_must eval "dd if=$IF of=$OF bs=$BS count=$CNT >/dev/null 2>&1"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send-b.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send-b.ksh
index f019c2215ecd..7e841c10ceac 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send-b.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send-b.ksh
@@ -58,13 +58,13 @@ log_must zfs set "org.openzfs:snapprop=val" "$SENDFS@s1"
# 2. Verify command line options interact with '-b' correctly
typeset opts=("" "p" "Rp" "cew" "nv" "D" "DLPRcenpvw")
for opt in ${opts[@]}; do
- log_must eval "zfs send -b$opt $SENDFS@s1 >$TEST_BASE_DIR/devnull"
- log_must eval "zfs send -b$opt -i $SENDFS@s1 $SENDFS@s2 >$TEST_BASE_DIR/devnull"
- log_must eval "zfs send -b$opt -I $SENDFS@s1 $SENDFS@s2 >$TEST_BASE_DIR/devnull"
+ log_must eval "zfs send -b$opt $SENDFS@s1 > /dev/null"
+ log_must eval "zfs send -b$opt -i $SENDFS@s1 $SENDFS@s2 > /dev/null"
+ log_must eval "zfs send -b$opt -I $SENDFS@s1 $SENDFS@s2 > /dev/null"
done
for opt in ${opts[@]}; do
- log_mustnot eval "zfs send -b$opt $SENDFS >$TEST_BASE_DIR/devnull"
- log_mustnot eval "zfs send -b$opt $SENDFS#bm >$TEST_BASE_DIR/devnull"
+ log_mustnot eval "zfs send -b$opt $SENDFS > /dev/null"
+ log_mustnot eval "zfs send -b$opt $SENDFS#bm > /dev/null"
done
# Do 3..6 in a loop to verify various combination of "zfs send" options
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_003_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_003_pos.ksh
index caa84886fa12..b04c9d3b240c 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_003_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_003_pos.ksh
@@ -61,7 +61,7 @@ log_must zfs snapshot $snap2
typeset -i i=0
while (( i < ${#args[*]} )); do
- log_must eval "zfs send -i ${args[i]} >$TEST_BASE_DIR/devnull"
+ log_must eval "zfs send -i ${args[i]} > /dev/null"
(( i += 1 ))
done
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_004_neg.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_004_neg.ksh
index af10e3a11faf..66a3da69f74b 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_004_neg.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_004_neg.ksh
@@ -95,7 +95,7 @@ log_must zfs snapshot $snap3
typeset -i i=0
while (( i < ${#badargs[*]} ))
do
- log_mustnot eval "zfs send ${badargs[i]} >$TEST_BASE_DIR/devnull"
+ log_mustnot eval "zfs send ${badargs[i]} > /dev/null"
(( i = i + 1 ))
done
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_005_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_005_pos.ksh
index c4ab7a6212bc..de8b28534fe1 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_005_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_005_pos.ksh
@@ -61,6 +61,6 @@ log_must zfs snapshot -r $TESTPOOL@snap
log_must zpool export $TESTPOOL
log_must zpool import -o readonly=on $TESTPOOL
-log_must eval "zfs send -R $TESTPOOL@snap >$TEST_BASE_DIR/devnull"
+log_must eval "zfs send -R $TESTPOOL@snap > /dev/null"
log_pass "'zfs send -R' can send from read-only pools"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_007_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_007_pos.ksh
index 675afa72f5af..306fabc8cef4 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_007_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_007_pos.ksh
@@ -83,7 +83,7 @@ test_pool ()
cat $streamfile | log_must zfs receive $POOL/recvfs
recv_mntpnt=$(get_prop mountpoint "$POOL/recvfs")
- log_must diff -r $mntpnt $recv_mntpnt
+ log_must directory_diff $mntpnt $recv_mntpnt
log_must zfs destroy -rf $POOL/fs
log_must zfs destroy -rf $POOL/recvfs
}
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_encrypted.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_encrypted.ksh
index a4c332d47dfc..b0f10028f472 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_encrypted.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_encrypted.ksh
@@ -62,15 +62,15 @@ log_must eval "echo $passphrase1 | zfs create -o encryption=on" \
log_must zfs snapshot -r $snap
-log_must eval "zfs send $snap >$TEST_BASE_DIR/devnull"
-log_mustnot eval "zfs send -p $snap >$TEST_BASE_DIR/devnull"
-log_mustnot eval "zfs send -R $snap >$TEST_BASE_DIR/devnull"
+log_must eval "zfs send $snap > /dev/null"
+log_mustnot eval "zfs send -p $snap > /dev/null"
+log_mustnot eval "zfs send -R $snap > /dev/null"
log_must zfs unmount $TESTPOOL/$TESTFS1
log_must zfs unload-key $TESTPOOL/$TESTFS1
-log_mustnot eval "zfs send $snap >$TEST_BASE_DIR/devnull"
-log_must eval "zfs send $TESTPOOL/$TESTFS1/child@snap >$TEST_BASE_DIR/devnull"
+log_mustnot eval "zfs send $snap > /dev/null"
+log_must eval "zfs send $TESTPOOL/$TESTFS1/child@snap > /dev/null"
log_pass "ZFS performs unencrypted sends of encrypted datasets, unless the" \
"'-p' or '-R' options are specified"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_encrypted_unloaded.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_encrypted_unloaded.ksh
index f268f7b38d4d..bf9a2be8db53 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_encrypted_unloaded.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_encrypted_unloaded.ksh
@@ -53,7 +53,7 @@ log_must eval "echo $passphrase | zfs create -o encryption=on" \
log_must zfs snapshot $snap
log_must zfs unmount $TESTPOOL/$TESTFS1
log_must zfs unload-key $TESTPOOL/$TESTFS1
-log_mustnot eval "zfs send $snap >$TEST_BASE_DIR/devnull"
+log_mustnot eval "zfs send $snap > /dev/null"
log_pass "ZFS does not perform unencrypted sends from encrypted datasets" \
"with unloaded keys."
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_raw.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_raw.ksh
index 03c2e78673d8..b221d8280df2 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_raw.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_raw.ksh
@@ -57,21 +57,21 @@ log_must eval "echo $passphrase | zfs create -o encryption=on" \
log_must zfs snapshot $snap
log_must zfs snapshot $snap1
-log_must eval "zfs send -w $snap >$TEST_BASE_DIR/devnull"
-log_must eval "zfs send -w $snap1 >$TEST_BASE_DIR/devnull"
+log_must eval "zfs send -w $snap > /dev/null"
+log_must eval "zfs send -w $snap1 > /dev/null"
log_note "Verify ZFS can perform raw sends with properties"
-log_must eval "zfs send -wp $snap >$TEST_BASE_DIR/devnull"
-log_must eval "zfs send -wp $snap1 >$TEST_BASE_DIR/devnull"
+log_must eval "zfs send -wp $snap > /dev/null"
+log_must eval "zfs send -wp $snap1 > /dev/null"
log_note "Verify ZFS can perform raw replication sends"
-log_must eval "zfs send -wR $snap >$TEST_BASE_DIR/devnull"
-log_must eval "zfs send -wR $snap1 >$TEST_BASE_DIR/devnull"
+log_must eval "zfs send -wR $snap > /dev/null"
+log_must eval "zfs send -wR $snap1 > /dev/null"
log_note "Verify ZFS can perform a raw send of an encrypted datasets with" \
"its key unloaded"
log_must zfs unmount $TESTPOOL/$TESTFS1
log_must zfs unload-key $TESTPOOL/$TESTFS1
-log_must eval "zfs send -w $snap1 >$TEST_BASE_DIR/devnull"
+log_must eval "zfs send -w $snap1 > /dev/null"
log_pass "ZFS performs raw sends of datasets"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_skip_missing.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_skip_missing.ksh
index 2e12d2534412..17b191a36173 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_skip_missing.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_skip_missing.ksh
@@ -49,7 +49,6 @@ function cleanup
datasetexists $PARENT && destroy_dataset $PARENT -rf
[[ -e $WARNF ]] && log_must rm -f $WARNF
- rm -f $TEST_BASE_DIR/devnull
}
log_assert "Verify 'zfs send -Rs' works as expected."
@@ -66,12 +65,12 @@ log_note "Verify 'zfs send -R' fails to generate replication stream"\
log_must zfs create $PARENT
log_must zfs create $CHILD
log_must zfs snapshot $SNAP
-log_mustnot eval "zfs send -R $SNAP >$TEST_BASE_DIR/devnull"
+log_mustnot eval "zfs send -R $SNAP > /dev/null"
log_note "Verify 'zfs send -Rs' warns about missing snapshots, "\
"but still succeeds"
-log_must eval "zfs send -Rs $SNAP 2> $WARNF >$TEST_BASE_DIR/devnull"
+log_must eval "zfs send -Rs $SNAP 2> $WARNF > /dev/null"
log_must eval "[[ -s $WARNF ]]"
log_pass "Verify 'zfs send -Rs' works as expected."
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_009_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_009_pos.ksh
index 6fedba9e5b27..4ff539a377d4 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_009_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_009_pos.ksh
@@ -93,11 +93,8 @@ for i in 1 2 3; do
done
log_note "verify snapshot contents"
for ds in $datasets; do
- diff -q -r /$ds /$ds/.zfs/snapshot/snap > /dev/null 2>&1
- if [[ $? -eq 1 ]]; then
- log_fail "snapshot contents are different from" \
- "the filesystem"
- fi
+ [ -d "/$ds/.zfs/snapshot/snap" ] && \
+ log_must directory_diff /$ds /$ds/.zfs/snapshot/snap
done
# We subtract 3 + 7 + 7 + 1 = 18 for three slashes (/), strlen("TESTFSA") == 7,
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool/zpool_002_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool/zpool_002_pos.ksh
index caf8a9a2d0ee..e4ffa2a6c028 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool/zpool_002_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool/zpool_002_pos.ksh
@@ -95,7 +95,6 @@ elif is_freebsd; then
fi
ulimit -c unlimited
-export ASAN_OPTIONS="abort_on_error=1:disable_coredump=0"
export ZFS_ABORT=yes
for subcmd in "${cmds[@]}" "${badparams[@]}"; do
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool/zpool_003_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool/zpool_003_pos.ksh
index 71d73c0f80e5..6f15c09a5229 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool/zpool_003_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool/zpool_003_pos.ksh
@@ -89,7 +89,6 @@ elif is_freebsd; then
fi
ulimit -c unlimited
-export ASAN_OPTIONS="abort_on_error=1:disable_coredump=0"
export ZFS_ABORT=yes
zpool >/dev/null 2>&1
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add.kshlib b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add.kshlib
index a7a1fb330241..c64b4a35aa03 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add.kshlib
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add.kshlib
@@ -36,28 +36,13 @@
#
function find_vfstab_dev
{
- typeset vfstabdev
- typeset vfstabdevs=""
- typeset line
-
if is_illumos; then
vfstab="/etc/vfstab"
- tmpfile="$TEST_BASE_DIR/vfstab.tmp"
else
vfstab="/etc/fstab"
- tmpfile="$TEST_BASE_DIR/fstab.tmp"
fi
- cat $vfstab | grep "^${DEV_DSKDIR}" >$tmpfile
- while read -r line
- do
- vfstabdev=`echo "$line" | awk '{print $1}'`
- vfstabdev=${vfstabdev%%:}
- vfstabdevs="$vfstabdev $vfstabdevs"
- done <$tmpfile
-
- rm -f $tmpfile
- echo $vfstabdevs
+ awk -v pat="^${DEV_DSKDIR}" '$0 ~ pat {sub(/:$/, "", $1); print $1}' $vfstab
}
#
@@ -72,7 +57,7 @@ function find_mnttab_dev
if is_freebsd; then
# FreeBSD doesn't have a mnttab file.
mount -p | awk -v dir="^${DEV_DSKDIR}" \
- '$1 ~ dir { print $1 }' | xargs
+ '$1 ~ dir { print $1 }'
return 0
elif is_linux; then
typeset mnttab="/etc/mtab"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create.shlib b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create.shlib
index c98e49518712..005cf979befa 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create.shlib
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create.shlib
@@ -69,28 +69,13 @@ function create_blockfile
#
function find_vfstab_dev
{
- typeset vfstabdev
- typeset vfstabdevs=""
- typeset line
-
if is_illumos; then
vfstab="/etc/vfstab"
- tmpfile="$TEST_BASE_DIR/vfstab.tmp"
else
vfstab="/etc/fstab"
- tmpfile="$TEST_BASE_DIR/fstab.tmp"
fi
- cat $vfstab | grep "^${DEV_DSKDIR}" >$tmpfile
- while read -r line
- do
- vfstabdev=`echo "$line" | awk '{print $1}'`
- vfstabdev=${vfstabdev%%:}
- vfstabdevs="$vfstabdev $vfstabdevs"
- done <$tmpfile
-
- rm -f $tmpfile
- echo $vfstabdevs
+ awk -v pat="^${DEV_DSKDIR}" '$0 ~ pat {sub(/:$/, "", $1); print $1}' $vfstab
}
#
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_events/zpool_events_clear.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_events/zpool_events_clear.ksh
index 054d39be3fe9..1df8ff441623 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_events/zpool_events_clear.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_events/zpool_events_clear.ksh
@@ -43,7 +43,8 @@ for i in `seq 1 $EVENTS_NUM`; do
done
# wait a bit to allow the kernel module to process new events
zpool_events_settle
-EVENTS_NUM=$(zpool events -H | wc -l | xargs)
+EVENTS_NUM=$(zpool events -H | wc -l)
+EVENTS_NUM=${EVENTS_NUM##* }
# 3. Verify 'zpool events -c' successfully clear new events
CLEAR_OUTPUT=$(zpool events -c)
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_expand/zpool_expand_001_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_expand/zpool_expand_001_pos.ksh
index 922e35125e4a..6bbd46289f7c 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_expand/zpool_expand_001_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_expand/zpool_expand_001_pos.ksh
@@ -72,7 +72,7 @@ log_onexit cleanup
log_assert "zpool can be autoexpanded after set autoexpand=on on vdev expansion"
-for type in " " mirror raidz draid; do
+for type in " " mirror raidz draid:1s; do
log_note "Setting up loopback, scsi_debug, and file vdevs"
log_must truncate -s $org_size $FILE_LO
DEV1=$(losetup -f)
@@ -144,7 +144,7 @@ for type in " " mirror raidz draid; do
if [[ $? -ne 0 ]] ; then
log_fail "pool $TESTPOOL1 has not expanded"
fi
- elif [[ $type == "draid" ]]; then
+ elif [[ $type == "draid:1s" ]]; then
typeset expansion_size=$((2*($exp_size-$org_size)))
zpool history -il $TESTPOOL1 | \
grep "pool '$TESTPOOL1' size:" | \
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get.cfg b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get.cfg
index accbf69cf9c8..fac96e26e460 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get.cfg
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get.cfg
@@ -97,5 +97,6 @@ if is_linux || is_freebsd; then
"feature@bookmark_v2"
"feature@livelist"
"feature@zstd_compress"
+ "feature@zilsaxattr"
)
fi \ No newline at end of file
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/import_devices_missing.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/import_devices_missing.ksh
index 53828c912ca3..af6ac8d78e4e 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/import_devices_missing.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/import_devices_missing.ksh
@@ -68,7 +68,7 @@ function test_devices_missing
log_must generate_data $TESTPOOL1 $MD5FILE2 "second"
- log_must zpool export $TESTPOOL1
+ log_must_busy zpool export $TESTPOOL1
log_must mv $missingvdevs $BACKUP_DEVICE_DIR
@@ -85,7 +85,7 @@ function test_devices_missing
"get suspended."
verify_data_md5sums $MD5FILE >/dev/null 2>&1
- log_must zpool export $TESTPOOL1
+ log_must_busy zpool export $TESTPOOL1
typeset newpaths=$(echo "$missingvdevs" | \
sed "s:$DEVICE_DIR:$BACKUP_DEVICE_DIR:g")
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/import_rewind_config_changed.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/import_rewind_config_changed.ksh
index 3ac8c104f1ca..d79c757d2406 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/import_rewind_config_changed.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/import_rewind_config_changed.ksh
@@ -61,6 +61,7 @@ function test_common
typeset detachvdev="${4:-}"
typeset removevdev="${5:-}"
typeset finalpool="${6:-}"
+ typeset retval=1
typeset poolcheck="$poolcreate"
@@ -120,19 +121,30 @@ function test_common
# while having a checkpoint, we take it after the
# operation that changes the config.
#
+ # However, it is possible the MOS data was overwritten
+ # in which case the pool will either be unimportable, or
+ # may have been rewound prior to the data being written.
+ # In which case an error is returned and test_common()
+ # is retried by the caller to minimize false positives.
+ #
log_must zpool checkpoint $TESTPOOL1
log_must overwrite_data $TESTPOOL1 ""
log_must zpool export $TESTPOOL1
- log_must zpool import -d $DEVICE_DIR -T $txg $TESTPOOL1
- log_must check_pool_config $TESTPOOL1 "$poolcheck"
+ zpool import -d $DEVICE_DIR -T $txg $TESTPOOL1
+ if (( $? == 0 )); then
+ verify_data_md5sums $MD5FILE
+ if (( $? == 0 )); then
+ retval=0
+ fi
- log_must verify_data_md5sums $MD5FILE
+ log_must check_pool_config $TESTPOOL1 "$poolcheck"
+ log_must zpool destroy $TESTPOOL1
+ fi
# Cleanup
- log_must zpool destroy $TESTPOOL1
if [[ -n $pathstochange ]]; then
for dev in $pathstochange; do
log_must mv "${dev}_new" $dev
@@ -143,6 +155,7 @@ function test_common
log_must zpool destroy $TESTPOOL2
log_note ""
+ return $retval
}
function test_add_vdevs
@@ -152,7 +165,12 @@ function test_add_vdevs
log_note "$0: pool '$poolcreate', add $addvdevs."
- test_common "$poolcreate" "$addvdevs"
+ for retry in $(seq 1 5); do
+ test_common "$poolcreate" "$addvdevs" && return
+ log_note "Retry $retry / 5 for test_add_vdevs()"
+ done
+
+ log_fail "Exhausted all 5 retries for test_add_vdevs()"
}
function test_attach_vdev
@@ -163,7 +181,12 @@ function test_attach_vdev
log_note "$0: pool '$poolcreate', attach $attachvdev to $attachto."
- test_common "$poolcreate" "" "$attachto $attachvdev"
+ for retry in $(seq 1 5); do
+ test_common "$poolcreate" "" "$attachto $attachvdev" && return
+ log_note "Retry $retry / 5 for test_attach_vdev()"
+ done
+
+ log_fail "Exhausted all 5 retries for test_attach_vdev()"
}
function test_detach_vdev
@@ -173,7 +196,12 @@ function test_detach_vdev
log_note "$0: pool '$poolcreate', detach $detachvdev."
- test_common "$poolcreate" "" "" "$detachvdev"
+ for retry in $(seq 1 5); do
+ test_common "$poolcreate" "" "" "$detachvdev" && return
+ log_note "Retry $retry / 5 for test_detach_vdev()"
+ done
+
+ log_fail "Exhausted all 5 retries for test_detach_vdev()"
}
function test_attach_detach_vdev
@@ -186,7 +214,13 @@ function test_attach_detach_vdev
log_note "$0: pool '$poolcreate', attach $attachvdev to $attachto," \
"then detach $detachvdev."
- test_common "$poolcreate" "" "$attachto $attachvdev" "$detachvdev"
+ for retry in $(seq 1 5); do
+ test_common "$poolcreate" "" "$attachto $attachvdev" \
+ "$detachvdev" && return
+ log_note "Retry $retry / 5 for test_attach_detach_vdev()"
+ done
+
+ log_fail "Exhausted all 5 retries for test_attach_detach_vdev()"
}
function test_remove_vdev
@@ -197,7 +231,13 @@ function test_remove_vdev
log_note "$0: pool '$poolcreate', remove $removevdev."
- test_common "$poolcreate" "" "" "" "$removevdev" "$finalpool"
+ for retry in $(seq 1 5); do
+ test_common "$poolcreate" "" "" "" "$removevdev" \
+ "$finalpool" && return
+ log_note "Retry $retry / 5 for test_remove_vdev()"
+ done
+
+ log_fail "Exhausted all 5 retries for test_remove_vdev()"
}
# Record txg history
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_errata4.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_errata4.ksh
index a0f063a8dc83..a199c2a7fb9d 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_errata4.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_errata4.ksh
@@ -122,7 +122,7 @@ block_device_wait
old_mntpnt=$(get_prop mountpoint $POOL_NAME/testfs)
new_mntpnt=$(get_prop mountpoint $POOL_NAME/fixed/testfs)
-log_must diff -r "$old_mntpnt" "$new_mntpnt"
+log_must directory_diff "$old_mntpnt" "$new_mntpnt"
log_must diff /dev/zvol/$POOL_NAME/testvol /dev/zvol/$POOL_NAME/fixed/testvol
log_must has_ivset_guid $POOL_NAME/fixed/testfs@snap1
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_trim/zpool_trim_partial.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_trim/zpool_trim_partial.ksh
index f3b3b0f272a7..bdbf3db53336 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_trim/zpool_trim_partial.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_trim/zpool_trim_partial.ksh
@@ -64,7 +64,7 @@ log_must set_tunable64 TRIM_EXTENT_BYTES_MIN 4096
log_must mkdir "$TESTDIR"
log_must truncate -s $LARGESIZE "$LARGEFILE"
-log_must zpool create $TESTPOOL "$LARGEFILE"
+log_must zpool create -O compression=off $TESTPOOL "$LARGEFILE"
log_must mkfile $(( floor(LARGESIZE * 0.80) )) /$TESTPOOL/file
sync_all_pools
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_trim/zpool_trim_start_and_cancel_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_trim/zpool_trim_start_and_cancel_pos.ksh
index fbb0c291046c..a60e12e1481e 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_trim/zpool_trim_start_and_cancel_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_trim/zpool_trim_start_and_cancel_pos.ksh
@@ -35,7 +35,7 @@
DISK1=${DISKS%% *}
log_must zpool create -f $TESTPOOL $DISK1
-log_must zpool trim $TESTPOOL
+log_must zpool trim -r 1 "$TESTPOOL"
[[ -z "$(trim_progress $TESTPOOL $DISK1)" ]] && \
log_fail "TRIM did not start"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/deadman/deadman_ratelimit.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/deadman/deadman_ratelimit.ksh
index 469117a56cc0..7c8fb08b7e01 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/deadman/deadman_ratelimit.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/deadman/deadman_ratelimit.ksh
@@ -64,7 +64,7 @@ log_must file_write -b 1048576 -c 8 -o create -d 0 -f $mntpnt/file
log_must zpool export $TESTPOOL
log_must zpool import $TESTPOOL
log_must zinject -d $DISK1 -D 5:1 $TESTPOOL
-log_must dd if=$mntpnt/file of=$TEST_BASE_DIR/devnull oflag=sync
+log_must dd if=$mntpnt/file of=/dev/null oflag=sync
events=$(zpool events $TESTPOOL | grep -c ereport.fs.zfs.deadman)
log_note "events=$events"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/dos_attributes/Makefile.am b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/dos_attributes/Makefile.am
new file mode 100644
index 000000000000..436bcdb1f31e
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/dos_attributes/Makefile.am
@@ -0,0 +1,8 @@
+include $(top_srcdir)/config/Rules.am
+
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/dos_attributes
+dist_pkgdata_SCRIPTS = \
+ cleanup.ksh \
+ read_dos_attrs_001.ksh \
+ write_dos_attrs_001.ksh \
+ setup.ksh
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/dos_attributes/cleanup.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/dos_attributes/cleanup.ksh
new file mode 100755
index 000000000000..3166bd6ec16e
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/dos_attributes/cleanup.ksh
@@ -0,0 +1,34 @@
+#!/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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/dos_attributes/read_dos_attrs_001.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/dos_attributes/read_dos_attrs_001.ksh
new file mode 100755
index 000000000000..c36c0183315e
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/dos_attributes/read_dos_attrs_001.ksh
@@ -0,0 +1,60 @@
+#!/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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013, 2016 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#
+# Read additional file level attributes stored in upper half of z_pflags
+#
+# STARTEGY:
+# 1) Create a file
+# 2) Execute read_dos_attributes on the file we created
+# 3) Verify that read_dos_attributes exited successfully
+#
+
+verify_runnable "global"
+
+FILETOTEST="$TESTDIR/test_read_dos_attrs.txt"
+
+function cleanup
+{
+ rm -f $FILETOTEST
+}
+
+log_onexit cleanup
+
+log_must chmod 777 $TESTDIR
+log_must eval "echo 'This is a test file.' > $FILETOTEST"
+log_must read_dos_attributes $FILETOTEST
+
+log_pass "reading DOS attributes succeeded."
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/dos_attributes/setup.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/dos_attributes/setup.ksh
new file mode 100755
index 000000000000..fc5cec3063a6
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/dos_attributes/setup.ksh
@@ -0,0 +1,35 @@
+#!/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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+default_setup $DISK
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/dos_attributes/write_dos_attrs_001.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/dos_attributes/write_dos_attrs_001.ksh
new file mode 100755
index 000000000000..9d66cd357599
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/dos_attributes/write_dos_attrs_001.ksh
@@ -0,0 +1,61 @@
+#!/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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013, 2016 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#
+# Write additional file level attributes stored in upper half of z_pflags
+#
+# STARTEGY:
+# 1) Create a file
+# 2) Execute write_dos_attributes on the file we created
+# 3) Verify that write_dos_attributes exited successfully
+#
+
+verify_runnable "global"
+
+FILETOTEST="$TESTDIR/test_write_dos_attrs.txt"
+
+function cleanup
+{
+ rm -f $FILETOTEST
+}
+
+log_onexit cleanup
+
+log_must chmod 777 $TESTDIR
+log_must eval "echo 'This is a test file.' > $FILETOTEST"
+log_must write_dos_attributes offline $FILETOTEST
+log_must write_dos_attributes nooffline $FILETOTEST
+
+log_pass "writing DOS attributes succeeded."
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/events/cleanup.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/events/cleanup.ksh
index 699bc2823343..72570d9288fd 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/events/cleanup.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/events/cleanup.ksh
@@ -28,4 +28,6 @@
zed_cleanup all-debug.sh all-syslog.sh all-dumpfds
+zed_stop
+
default_cleanup
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/events/events_002_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/events/events_002_pos.ksh
index af2be33dbc73..9407656b6e6b 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/events/events_002_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/events/events_002_pos.ksh
@@ -62,7 +62,7 @@ log_must truncate -s $MINVDEVSIZE $VDEV1 $VDEV2
# 1. Create a pool and generate some events.
log_must truncate -s 0 $ZED_DEBUG_LOG
log_must zpool events -c
-log_must zpool create $MPOOL mirror $VDEV1 $VDEV2
+log_must zpool create -O compression=off $MPOOL mirror $VDEV1 $VDEV2
# 2. Start the ZED and verify it handles missed events.
log_must zed_start
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/events/zed_fd_spill.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/events/zed_fd_spill.ksh
index 8736a7fdf7e6..4ae136d0f36c 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/events/zed_fd_spill.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/events/zed_fd_spill.ksh
@@ -47,8 +47,14 @@ log_onexit cleanup
logdir="$(mktemp -d)"
log_must ln -s "$logdir" /tmp/zts-zed_fd_spill-logdir
+
self="$(readlink -f "$0")"
-log_must ln -s "${self%/*}/zed_fd_spill-zedlet" "${ZEDLET_DIR}/all-dumpfds"
+zedlet="${self%/*}/zed_fd_spill-zedlet"
+log_must ln -s $zedlet "${ZEDLET_DIR}/all-dumpfds"
+
+# zed will cry foul and refuse to run it if this isn't true
+sudo chown root $zedlet
+sudo chmod 700 $zedlet
log_must zpool events -c
log_must zed_stop
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/fault/decrypt_fault.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/fault/decrypt_fault.ksh
index d81c4b2bd2f2..a4cf06144e58 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/fault/decrypt_fault.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/fault/decrypt_fault.ksh
@@ -40,6 +40,7 @@ function cleanup
log_onexit cleanup
default_mirror_setup_noexit $DISK1 $DISK2
+log_must zfs set compression=off $TESTPOOL
log_must eval "echo 'password' | zfs create -o encryption=on \
-o keyformat=passphrase -o keylocation=prompt $TESTPOOL/fs"
mntpt=$(get_prop mountpoint $TESTPOOL/fs)
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/features/large_dnode/large_dnode_005_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/features/large_dnode/large_dnode_005_pos.ksh
index 2be98942634f..03e2db4b8082 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/features/large_dnode/large_dnode_005_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/features/large_dnode/large_dnode_005_pos.ksh
@@ -68,7 +68,7 @@ if [[ "$dnsize" != "1K" ]]; then
fi
log_must eval "zfs recv -F $TEST_RECV_FS < $TEST_STREAMINCR"
-log_must diff -r /$TEST_SEND_FS /$TEST_RECV_FS
+log_must directory_diff /$TEST_SEND_FS /$TEST_RECV_FS
log_must zfs umount $TEST_SEND_FS
log_must zfs umount $TEST_RECV_FS
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/history/history_006_neg.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/history/history_006_neg.ksh
index c3a5e092d02d..19b7114faf5b 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/history/history_006_neg.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/history/history_006_neg.ksh
@@ -75,9 +75,7 @@ if ! is_linux; then
log_must zfs share $fs
log_must zfs unshare $fs
fi
-# https://github.com/openzfs/zfs/issues/11445
-set -o pipefail
-log_must zfs send -i $snap1 $snap2 | cat > /dev/null
+log_must zfs send -i $snap1 $snap2 > /dev/null
log_must zfs holds $snap1
log_must eval "zpool history $TESTPOOL > $NEW_HISTORY"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/inheritance/inherit_001_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/inheritance/inherit_001_pos.ksh
index 7c5b81287736..95dc7359f278 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/inheritance/inherit_001_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/inheritance/inherit_001_pos.ksh
@@ -388,12 +388,12 @@ set -A prop "checksum" "" \
# above must have a corresponding entry in the two arrays below.
#
-set -A def_val "on" "off" "on" \
+set -A def_val "on" "on" "on" \
"off" "" \
"hidden" \
"off"
-set -A local_val "off" "on" "off" \
+set -A local_val "off" "off" "off" \
"on" "" \
"visible" \
"off"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/mv_files/mv_files_001_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/mv_files/mv_files_001_pos.ksh
index 4ea5e3db3889..c49b19c6c3a3 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/mv_files/mv_files_001_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/mv_files/mv_files_001_pos.ksh
@@ -53,7 +53,6 @@ verify_runnable "global"
function cleanup
{
- PIDS=""
rm -f $OLDDIR/* >/dev/null 2>&1
rm -f $NEWDIR_IN_FS/* >/dev/null 2>&1
}
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/mv_files/mv_files_002_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/mv_files/mv_files_002_pos.ksh
index 283770d4a4bf..fdadac32d59b 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/mv_files/mv_files_002_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/mv_files/mv_files_002_pos.ksh
@@ -54,7 +54,6 @@ verify_runnable "global"
function cleanup
{
- PIDS=""
rm -f $OLDDIR/* >/dev/null 2>&1
rm -f $NEWDIR_ACROSS_FS/* >/dev/null 2>&1
}
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/mv_files/mv_files_common.kshlib b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/mv_files/mv_files_common.kshlib
index 6b925501b088..3ddd8f113a3b 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/mv_files/mv_files_common.kshlib
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/mv_files/mv_files_common.kshlib
@@ -30,55 +30,6 @@
. $STF_SUITE/tests/functional/mv_files/mv_files.cfg
-#
-# Determine whether this version of the ksh being
-# executed has a bug where the limit of background
-# processes of 25.
-#
-function check_bg_procs_limit_num
-{
-echo "#!/bin/ksh" > $TEST_BASE_DIR/exitsZero.ksh
-echo "exit 0" >> $TEST_BASE_DIR/exitsZero.ksh
-chmod 777 $TEST_BASE_DIR/exitsZero.ksh
-
-cat <<EOF > $TEST_BASE_DIR/testbackgprocs.ksh
-#!/bin/ksh
-#
-# exitsZero.ksh is a one line script
-# that exit with status of "0"
-#
-
-PIDS=""
-typeset -i i=1
-while [ \$i -le 50 ]
-do
- $TEST_BASE_DIR/exitsZero.ksh &
- PIDS="\$PIDS \$!"
- (( i = i + 1 ))
-done
-
-sleep 1
-
-for pid in \$PIDS
-do
- wait \$pid
- (( \$? == 127 )) && exit 1
-done
-exit 0
-EOF
-
-ksh $TEST_BASE_DIR/testbackgprocs.ksh
-if [[ $? -eq 1 ]]; then
-#
-# Current ksh being executed has a limit
-# of 25 background processes.
-#
- return 1
-else
- return 0
-fi
-}
-
function init_setup
{
@@ -152,8 +103,7 @@ function generate_files
#
function mv_files
{
- find $1 -type f -print | xargs -I "{}" \
- mv {} $2 > /dev/null 2>&1
+ find $1 -type f -exec mv {} $2 \; > /dev/null 2>&1
}
#
@@ -165,8 +115,7 @@ function mv_files
function count_files
{
typeset -i file_num
- file_num=`find $1 -type f -print | \
- wc -l`
+ file_num=$(find $1 -type f -print | wc -l | tr -d ' ')
(( file_num != $2 )) && \
log_fail "The file number of target directory"\
"$2 is not equal to that of the source "\
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/mv_files/setup.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/mv_files/setup.ksh
index e4e97b16d5d4..d459c51e4e57 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/mv_files/setup.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/mv_files/setup.ksh
@@ -34,13 +34,25 @@
verify_runnable "global"
-check_bg_procs_limit_num
-if [[ $? -ne 0 ]]; then
+#
+# Determine whether this version of the ksh being
+# executed has a bug where the limit of background
+# processes of 25.
+#
+(
+ pids=
+ for _ in $(seq 50); do
+ : &
+ pids="$pids $!"
+ done
+
+ for pid in $pids; do
+ wait $pid || exit
+ done
+) || {
log_note "ksh background process limit number is 25"
- export GANGPIDS=25
-fi
-
-export PIDS=""
+ GANGPIDS=25
+}
init_setup $DISK
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/no_space/Makefile.am b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/no_space/Makefile.am
index c2e42bc2ada4..31584fb17583 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/no_space/Makefile.am
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/no_space/Makefile.am
@@ -5,7 +5,8 @@ dist_pkgdata_SCRIPTS = \
enospc_001_pos.ksh \
enospc_002_pos.ksh \
enospc_003_pos.ksh \
- enospc_df.ksh
+ enospc_df.ksh \
+ enospc_rm.ksh
dist_pkgdata_DATA = \
enospc.cfg
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/no_space/enospc_002_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/no_space/enospc_002_pos.ksh
index 081157cdc719..2fb3fb46c44c 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/no_space/enospc_002_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/no_space/enospc_002_pos.ksh
@@ -61,9 +61,6 @@ done
log_mustnot_expect space zfs create $TESTPOOL/$TESTFS/subfs
log_mustnot_expect space zfs clone $TESTPOOL/$TESTFS@snap $TESTPOOL/clone
-log_mustnot_expect space zfs snapshot $TESTPOOL/$TESTFS@snap2
-log_mustnot_expect space zfs bookmark \
- $TESTPOOL/$TESTFS@snap $TESTPOOL/$TESTFS#bookmark
log_must zfs send $TESTPOOL/$TESTFS@snap > $TEST_BASE_DIR/stream.$$
log_mustnot_expect space zfs receive $TESTPOOL/$TESTFS/recvd < $TEST_BASE_DIR/stream.$$
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/no_space/enospc_rm.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/no_space/enospc_rm.ksh
new file mode 100755
index 000000000000..065abc75977e
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/no_space/enospc_rm.ksh
@@ -0,0 +1,60 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# 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.
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2014, 2016 by Delphix. All rights reserved.
+# Copyright (c) 2022 by Lawrence Livermore National Security, LLC.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/no_space/enospc.cfg
+
+#
+# DESCRIPTION:
+# After filling a filesystem, verify the contents can be removed
+# without encountering an ENOSPC error.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+ destroy_pool $TESTPOOL
+ log_must rm -f $all_vdevs
+}
+
+log_onexit cleanup
+
+log_assert "Files can be removed from full file system."
+
+all_vdevs=$(echo $TEST_BASE_DIR/file.{01..12})
+
+log_must truncate -s $MINVDEVSIZE $all_vdevs
+
+log_must zpool create -f $TESTPOOL draid2:8d:2s $all_vdevs
+log_must zfs create $TESTPOOL/$TESTFS
+log_must zfs set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+log_must zfs set compression=off $TESTPOOL/$TESTFS
+
+log_note "Writing files until ENOSPC."
+log_mustnot_expect "No space left on device" fio --name=test \
+ --fallocate=none --rw=write --bs=1M --size=1G --numjobs=4 \
+ --sync=1 --directory=$TESTDIR/ --group_reporting
+
+log_must rm $TESTDIR/test.*
+log_must test -z "$(ls -A $TESTDIR)"
+
+log_pass "All files removed without error"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/online_offline/setup.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/online_offline/setup.ksh
index 4132392d80a9..b1fb6a123897 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/online_offline/setup.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/online_offline/setup.ksh
@@ -43,5 +43,3 @@ case $index in
default_raidz_setup $DISKS
;;
esac
-
-log_pass
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/pam/pam_basic.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/pam/pam_basic.ksh
index f146a6e5f157..eab819ab8d24 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/pam/pam_basic.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/pam/pam_basic.ksh
@@ -22,6 +22,10 @@
. $STF_SUITE/tests/functional/pam/utilities.kshlib
+if [ -n "$ASAN_OPTIONS" ]; then
+ export LD_PRELOAD=$(ldd "$(command -v zfs)" | awk '/libasan\.so/ {print $3}')
+fi
+
log_mustnot ismounted "$TESTPOOL/pam/${username}"
keystatus unavailable
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/pam/pam_nounmount.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/pam/pam_nounmount.ksh
index eb9976f2f776..29ce437b40ee 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/pam/pam_nounmount.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/pam/pam_nounmount.ksh
@@ -22,6 +22,10 @@
. $STF_SUITE/tests/functional/pam/utilities.kshlib
+if [ -n "$ASAN_OPTIONS" ]; then
+ export LD_PRELOAD=$(ldd "$(command -v zfs)" | awk '/libasan\.so/ {print $3}')
+fi
+
log_mustnot ismounted "$TESTPOOL/pam/${username}"
keystatus unavailable
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/pam/pam_short_password.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/pam/pam_short_password.ksh
index 1f72c9468a46..100f279fffed 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/pam/pam_short_password.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/pam/pam_short_password.ksh
@@ -27,6 +27,10 @@
. $STF_SUITE/tests/functional/pam/utilities.kshlib
+if [ -n "$ASAN_OPTIONS" ]; then
+ export LD_PRELOAD=$(ldd "$(command -v zfs)" | awk '/libasan\.so/ {print $3}')
+fi
+
if [[ -z pamservice ]]; then
pamservice=pam_zfs_key_test
fi
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/pool_checkpoint/checkpoint_ro_rewind.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/pool_checkpoint/checkpoint_ro_rewind.ksh
index fd7416612b7c..f326bf0c25d2 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/pool_checkpoint/checkpoint_ro_rewind.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/pool_checkpoint/checkpoint_ro_rewind.ksh
@@ -44,12 +44,12 @@ populate_test_pool
log_must zpool checkpoint $TESTPOOL
test_change_state_after_checkpoint
-log_must zpool export $TESTPOOL
+log_must_busy zpool export $TESTPOOL
log_must zpool import -o readonly=on --rewind-to-checkpoint $TESTPOOL
test_verify_pre_checkpoint_state "ro-check"
-log_must zpool export $TESTPOOL
+log_must_busy zpool export $TESTPOOL
log_must zpool import $TESTPOOL
test_verify_post_checkpoint_state
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projecttree_002_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projecttree_002_pos.ksh
index d61019242703..9942a88cb347 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projecttree_002_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projecttree_002_pos.ksh
@@ -109,8 +109,7 @@ log_must eval "zfs project -cr $PRJDIR/a1/a2 | grep a3 | grep 'not set'"
log_must eval "zfs project -cr $PRJDIR/a1/a2 | grep d4 | grep 'not set'"
log_must eval "zfs project $PRJDIR/a1/a2/a3/d4 | grep '0 \-'"
-log_must eval \
- "zfs project -cr -0 $PRJDIR/a1/a2 | xargs -0 zfs project -s -p $PRJID2"
+log_must eval "zfs project -s -p $PRJID2 $(zfs project -cr0 $PRJDIR/a1/a2 | tr '\0' '\t')"
log_mustnot eval "zfs project -cr $PRJDIR/a1/a2 | grep a3 | grep 'not set'"
log_mustnot eval "zfs project -cr $PRJDIR/a1/a2 | grep d4 | grep 'not set'"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/setup.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/setup.ksh
index c81b300e5e96..88906d91cdbb 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/setup.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/setup.ksh
@@ -53,4 +53,6 @@ fi
DISK=${DISKS%% *}
default_setup_noexit $DISK
+zfs set compression=off $TESTPOOL
+
log_pass
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/pyzfs/pyzfs_unittest.ksh.in b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/pyzfs/pyzfs_unittest.ksh.in
index 1f58d8116b68..84e20e2e7eba 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/pyzfs/pyzfs_unittest.ksh.in
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/pyzfs/pyzfs_unittest.ksh.in
@@ -16,6 +16,10 @@
. $STF_SUITE/include/libtest.shlib
+if [ -n "$ASAN_OPTIONS" ]; then
+ export LD_PRELOAD=$(ldd "$(command -v zfs)" | awk '/libasan\.so/ {print $3}')
+fi
+
#
# DESCRIPTION:
# Verify the libzfs_core Python test suite can be run successfully
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/quota/setup.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/quota/setup.ksh
index 677cb12d79ac..99a4cb3493ae 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/quota/setup.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/quota/setup.ksh
@@ -33,4 +33,6 @@
DISK=${DISKS%% *}
-default_container_setup $DISK
+default_setup_noexit $DISK "true"
+log_must zfs set compression=off $TESTPOOL
+log_pass
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redacted_send/redacted_incrementals.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redacted_send/redacted_incrementals.ksh
index 1d2ed3a687be..18ea5d68fcf8 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redacted_send/redacted_incrementals.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redacted_send/redacted_incrementals.ksh
@@ -51,10 +51,10 @@ log_must eval "zfs receive $POOL2/rfs <$stream"
# Verify receipt of normal incrementals to redaction list members.
log_must eval "zfs send -i $sendfs@snap0 $POOL/stride3@snap >$stream"
log_must eval "zfs recv $POOL2/rstride3 <$stream"
-log_must diff -r /$POOL/stride3 /$POOL2/rstride3
+log_must directory_diff /$POOL/stride3 /$POOL2/rstride3
log_must eval "zfs send -i $sendfs@snap0 $POOL/stride5@snap >$stream"
log_must eval "zfs recv $POOL2/rstride5 <$stream"
-log_must diff -r /$POOL/stride5 /$POOL2/rstride5
+log_must directory_diff /$POOL/stride5 /$POOL2/rstride5
# But not a normal child that we weren't redacted with respect to.
log_must eval "zfs send -i $sendfs@snap0 $POOL/hole@snap >$stream"
@@ -73,7 +73,7 @@ log_must mount_redacted -f $POOL2/rint
# Verify we can receive grandchildren on the child.
log_must eval "zfs send -i $POOL/int@snap $POOL/rm@snap >$stream"
log_must eval "zfs receive $POOL2/rrm <$stream"
-log_must diff -r /$POOL/rm /$POOL2/rrm
+log_must directory_diff /$POOL/rm /$POOL2/rrm
# But not a grandchild that the received child wasn't redacted with respect to.
log_must eval "zfs send -i $POOL/int@snap $POOL/write@snap >$stream"
@@ -92,13 +92,13 @@ log_mustnot zfs redact $POOL/int@snap book6 $POOL/hole@snap
# Verify we can receive a full clone of the grandchild on the child.
log_must eval "zfs send $POOL/write@snap >$stream"
log_must eval "zfs recv -o origin=$POOL2/rint@snap $POOL2/rwrite <$stream"
-log_must diff -r /$POOL/write /$POOL2/rwrite
+log_must directory_diff /$POOL/write /$POOL2/rwrite
# Along with other origins.
log_must eval "zfs recv -o origin=$POOL2/rfs@snap0 $POOL2/rwrite1 <$stream"
-log_must diff -r /$POOL/write /$POOL2/rwrite1
+log_must directory_diff /$POOL/write /$POOL2/rwrite1
log_must eval "zfs recv -o origin=$POOL2@init $POOL2/rwrite2 <$stream"
-log_must diff -r /$POOL/write /$POOL2/rwrite2
+log_must directory_diff /$POOL/write /$POOL2/rwrite2
log_must zfs destroy -R $POOL2/rwrite2
log_must zfs destroy -R $POOL2/rfs
@@ -140,7 +140,7 @@ unmount_redacted $POOL2/rfs
# sending from the bookmark.
log_must eval "zfs send -i $sendfs#book7 $POOL/hole1@snap >$stream"
log_must eval "zfs recv $POOL2/rhole1 <$stream"
-log_must diff -r /$POOL/hole1 /$POOL2/rhole1
+log_must directory_diff /$POOL/hole1 /$POOL2/rhole1
# Verify we can receive an intermediate clone redacted with respect to a
# non-subset if we send from the bookmark.
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redacted_send/redacted_largeblocks.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redacted_send/redacted_largeblocks.ksh
index caccdd360061..ef85bb31dcea 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redacted_send/redacted_largeblocks.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redacted_send/redacted_largeblocks.ksh
@@ -58,6 +58,6 @@ unmount_redacted $recvfs
log_must eval "zfs send -L -i $sendfs@snap $clone@snap1 >$stream"
log_must stream_has_features $stream large_blocks
log_must eval "zfs recv $recvfs/new <$stream"
-log_must diff -r $clone_mnt $recv_mnt/new
+log_must directory_diff $clone_mnt $recv_mnt/new
log_pass "Large blocks and redacted send work correctly together."
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redacted_send/redacted_negative.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redacted_send/redacted_negative.ksh
index e591cca0bbde..ea5e08c3cb86 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redacted_send/redacted_negative.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redacted_send/redacted_negative.ksh
@@ -45,11 +45,11 @@ log_must zfs snapshot $clone2@snap
# Incompatible flags
log_must zfs redact $sendfs@snap2 book $clone1@snap
-log_mustnot eval "zfs send -R --redact book $sendfs@snap2 >$TEST_BASE_DIR/devnull"
+log_mustnot eval "zfs send -R --redact book $sendfs@snap2 > /dev/null"
typeset arg
for arg in "$sendfs" "$clone1#book"; do
- log_mustnot eval "zfs send --redact book $arg >$TEST_BASE_DIR/devnull"
+ log_mustnot eval "zfs send --redact book $arg > /dev/null"
done
# Bad redaction list arguments
@@ -58,7 +58,7 @@ log_mustnot zfs redact $sendfs@snap1 book
log_mustnot zfs redact $sendfs#book1 book4 $clone1
log_mustnot zfs redact $sendfs@snap1 book snap2 snap3
log_mustnot zfs redact $sendfs@snap1 book @snap2 @snap3
-log_mustnot eval "zfs send --redact $sendfs#book $sendfs@snap >$TEST_BASE_DIR/devnull"
+log_mustnot eval "zfs send --redact $sendfs#book $sendfs@snap > /dev/null"
# Redaction snapshots not a descendant of tosnap
log_mustnot zfs redact $sendfs@snap2 book $sendfs@snap2
@@ -66,7 +66,7 @@ log_must zfs redact $sendfs@snap2 book2 $clone1@snap $clone2@snap
log_must eval "zfs send --redact book2 $sendfs@snap2 >$stream"
log_must zfs redact $sendfs@snap2 book3 $clone1@snap $clone2@snap
log_must eval "zfs send -i $sendfs@snap1 --redact book3 $sendfs@snap2 \
- >$TEST_BASE_DIR/devnull"
+ > /dev/null"
log_mustnot zfs redact $sendfs@snap3 $sendfs@snap3 $clone1@snap
# Full redacted sends of redacted datasets are not allowed.
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redacted_send/redacted_resume.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redacted_send/redacted_resume.ksh
index 4ab04a0e5730..8118ea59ec8b 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redacted_send/redacted_resume.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redacted_send/redacted_resume.ksh
@@ -81,7 +81,7 @@ log_must eval "zfs send --redact book1 $sendfs@snap >$stream"
dd if=$stream bs=64k count=1 | log_mustnot zfs receive -s $recvfs
[[ "-" = $(get_prop receive_resume_token $recvfs) ]] && \
log_fail "Receive token not found."
-log_mustnot eval "zfs send --saved --redact book1 $recvfs >$TEST_BASE_DIR/devnull"
+log_mustnot eval "zfs send --saved --redact book1 $recvfs > /dev/null"
log_must zfs recv -A $recvfs
log_must datasetnonexists $recvfs
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redundancy/redundancy.kshlib b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redundancy/redundancy.kshlib
index baee8269b1e1..55816b451612 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redundancy/redundancy.kshlib
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redundancy/redundancy.kshlib
@@ -139,7 +139,7 @@ function setup_test_env
log_must truncate -s $MINVDEVSIZE $vdevs
- log_must zpool create -f -m $TESTDIR $pool $keyword $vdevs
+ log_must zpool create -O compression=off -f -m $TESTDIR $pool $keyword $vdevs
log_note "Filling up the filesystem ..."
typeset -i ret=0
@@ -243,7 +243,7 @@ function get_vdevs #pool cnt
typeset -i cnt=$2
typeset all_devs=$(zpool iostat -v $pool | awk '{print $1}'| \
- egrep -v "^pool$|^capacity$|^mirror$|^raidz1$|^raidz2$|^raidz3$|^draid1.*|^draid2.*|^draid3.*|---" | \
+ egrep -v "^pool$|^capacity$|^mirror\-[0-9]$|^raidz[1-3]\-[0-9]$|^draid[1-3].*\-[0-9]$|---" | \
egrep -v "/old$|^$pool$")
typeset -i i=0
typeset vdevs
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redundancy/redundancy_draid.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redundancy/redundancy_draid.ksh
index 8015e682c892..b2721707cb75 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redundancy/redundancy_draid.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redundancy/redundancy_draid.ksh
@@ -219,7 +219,7 @@ for nparity in 1 2 3; do
raid=draid$nparity
dir=$TEST_BASE_DIR
- log_must zpool create -f -o cachefile=none $TESTPOOL $raid ${disks[@]}
+ log_must zpool create -O compression=off -f -o cachefile=none $TESTPOOL $raid ${disks[@]}
log_must zfs set primarycache=metadata $TESTPOOL
log_must zfs create $TESTPOOL/fs
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redundancy/redundancy_draid_damaged.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redundancy/redundancy_draid_damaged.ksh
index 6796cc78a1bd..9b3be9f4e3f7 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redundancy/redundancy_draid_damaged.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redundancy/redundancy_draid_damaged.ksh
@@ -85,7 +85,9 @@ function test_sequential_resilver # <pool> <parity> <dir>
for (( i=0; i<$nparity; i=i+1 )); do
spare=draid${nparity}-0-$i
- log_must zpool replace -fsw $pool $dir/dev-$i $spare
+ zpool status $pool
+ zpool replace -fsw $pool $dir/dev-$i $spare
+ zpool status $pool
done
log_must zpool scrub -w $pool
@@ -128,7 +130,7 @@ for nparity in 1 2 3; do
raid=draid${nparity}:${nparity}s
dir=$TEST_BASE_DIR
- log_must zpool create -f -o cachefile=none $TESTPOOL $raid ${disks[@]}
+ log_must zpool create -O compression=off -f -o cachefile=none $TESTPOOL $raid ${disks[@]}
log_must zfs set primarycache=metadata $TESTPOOL
log_must zfs create $TESTPOOL/fs
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redundancy/redundancy_raidz.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redundancy/redundancy_raidz.ksh
index d73688391624..7351cfaae5ed 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redundancy/redundancy_raidz.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redundancy/redundancy_raidz.ksh
@@ -219,7 +219,7 @@ for nparity in 1 2 3; do
raid=raidz$nparity
dir=$TEST_BASE_DIR
- log_must zpool create -f -o cachefile=none $TESTPOOL $raid ${disks[@]}
+ log_must zpool create -O compression=off -f -o cachefile=none $TESTPOOL $raid ${disks[@]}
log_must zfs set primarycache=metadata $TESTPOOL
log_must zfs create $TESTPOOL/fs
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/refquota/setup.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/refquota/setup.ksh
index a34453bd3892..48bd314cd2dc 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/refquota/setup.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/refquota/setup.ksh
@@ -33,4 +33,6 @@
verify_runnable "both"
DISK=${DISKS%% *}
-default_setup $DISK
+default_setup_noexit $DISK
+log_must zfs set compression=off $TESTPOOL
+log_pass
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/refreserv/refreserv_raidz.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/refreserv/refreserv_raidz.ksh
index 056c7916d990..0c8de79b3f9f 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/refreserv/refreserv_raidz.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/refreserv/refreserv_raidz.ksh
@@ -98,7 +98,7 @@ for parity in 1 2 3; do
continue
fi
- log_must zpool create "$TESTPOOL" "$raid" "${disks[@]}"
+ log_must zpool create -O compression=off "$TESTPOOL" "$raid" "${disks[@]}"
for bits in "${allshifts[@]}"; do
vbs=$((1 << bits))
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/refreserv/setup.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/refreserv/setup.ksh
index a34453bd3892..48bd314cd2dc 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/refreserv/setup.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/refreserv/setup.ksh
@@ -33,4 +33,6 @@
verify_runnable "both"
DISK=${DISKS%% *}
-default_setup $DISK
+default_setup_noexit $DISK
+log_must zfs set compression=off $TESTPOOL
+log_pass
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/removal/removal_with_errors.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/removal/removal_with_errors.ksh
index 9d5143ef8b17..be7364eb2b0d 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/removal/removal_with_errors.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/removal/removal_with_errors.ksh
@@ -78,6 +78,7 @@ function wait_for_removing_cancel
default_setup_noexit "mirror $DISK0 $DISK1 mirror $DISK2 $DISK3"
log_onexit cleanup
+log_must zfs set compression=off $TESTPOOL
FILE_CONTENTS="Leeloo Dallas mul-ti-pass."
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/removal/removal_with_export.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/removal/removal_with_export.ksh
index f76f76d34f5b..098a52cb9f9a 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/removal/removal_with_export.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/removal/removal_with_export.ksh
@@ -22,6 +22,7 @@
. $STF_SUITE/tests/functional/removal/removal.kshlib
default_setup_noexit "$DISKS"
+log_must zfs set compression=off $TESTPOOL
log_onexit default_cleanup_noexit
function callback
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/removal/removal_with_send.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/removal/removal_with_send.ksh
index a08247838105..735578104740 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/removal/removal_with_send.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/removal/removal_with_send.ksh
@@ -28,7 +28,7 @@ function callback
{
create_snapshot $TESTPOOL/$TESTFS $TESTSNAP
log_must ksh -c \
- "zfs send $TESTPOOL/$TESTFS@$TESTSNAP >$TEST_BASE_DIR/devnull"
+ "zfs send $TESTPOOL/$TESTFS@$TESTSNAP > /dev/null"
return 0
}
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/replacement/setup.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/replacement/setup.ksh
index 4132392d80a9..b1fb6a123897 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/replacement/setup.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/replacement/setup.ksh
@@ -43,5 +43,3 @@ case $index in
default_raidz_setup $DISKS
;;
esac
-
-log_pass
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/reservation/setup.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/reservation/setup.ksh
index c39034783555..731aa6a30680 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/reservation/setup.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/reservation/setup.ksh
@@ -32,4 +32,5 @@
. $STF_SUITE/include/libtest.shlib
default_setup_noexit ${DISKS%% *}
+log_must zfs set compression=off $TESTPOOL
log_pass
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/Makefile.am b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/Makefile.am
index 94bdd2674517..b8eb54f64c3e 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/Makefile.am
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/Makefile.am
@@ -49,6 +49,8 @@ dist_pkgdata_SCRIPTS = \
send_realloc_files.ksh \
send_realloc_encrypted_files.ksh \
send_spill_block.ksh \
+ send_raw_spill_block.ksh \
+ send_raw_ashift.ksh \
send_holds.ksh \
send_hole_birth.ksh \
send_invalid.ksh \
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/recv_dedup.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/recv_dedup.ksh
index e6e282a1c6f8..ba23c4f6aa3c 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/recv_dedup.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/recv_dedup.ksh
@@ -48,6 +48,7 @@ log_must eval "zstream redup $sendfile | zfs recv -d $TESTPOOL/recv"
log_must mkdir /$TESTPOOL/tar
log_must tar --directory /$TESTPOOL/tar -xzf $tarfile
-log_must diff -r /$TESTPOOL/tar /$TESTPOOL/recv
+# The recv'd filesystem is called "/fs", so only compare that subdirectory.
+log_must directory_diff /$TESTPOOL/tar/fs /$TESTPOOL/recv/fs
log_pass "zfs can receive dedup send streams with 'zstream redup'"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/rsend.kshlib b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/rsend.kshlib
index 516d41263294..2c8085f226b0 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/rsend.kshlib
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/rsend.kshlib
@@ -212,7 +212,7 @@ function cmp_ds_cont
srcdir=$(get_prop mountpoint $src_fs)
dstdir=$(get_prop mountpoint $dst_fs)
- diff -r $srcdir $dstdir > /dev/null 2>&1
+ replay_directory_diff $srcdir $dstdir
return $?
}
@@ -627,12 +627,12 @@ function file_check
if [[ -d /$recvfs/.zfs/snapshot/a && -d \
/$sendfs/.zfs/snapshot/a ]]; then
- diff -r /$recvfs/.zfs/snapshot/a /$sendfs/.zfs/snapshot/a
+ directory_diff /$recvfs/.zfs/snapshot/a /$sendfs/.zfs/snapshot/a
[[ $? -eq 0 ]] || log_fail "Differences found in snap a"
fi
if [[ -d /$recvfs/.zfs/snapshot/b && -d \
/$sendfs/.zfs/snapshot/b ]]; then
- diff -r /$recvfs/.zfs/snapshot/b /$sendfs/.zfs/snapshot/b
+ directory_diff /$recvfs/.zfs/snapshot/b /$sendfs/.zfs/snapshot/b
[[ $? -eq 0 ]] || log_fail "Differences found in snap b"
fi
}
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/rsend_009_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/rsend_009_pos.ksh
index 7d858d92d511..5712cb513401 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/rsend_009_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/rsend_009_pos.ksh
@@ -60,8 +60,8 @@ log_onexit cleanup
log_must mkfile $MINVDEVSIZE $TESTDIR/bfile
log_must mkfile $SPA_MINDEVSIZE $TESTDIR/sfile
-log_must zpool create bpool $TESTDIR/bfile
-log_must zpool create spool $TESTDIR/sfile
+log_must zpool create -O compression=off bpool $TESTDIR/bfile
+log_must zpool create -O compression=off spool $TESTDIR/sfile
#
# Test out of space on sub-filesystem
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/rsend_016_neg.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/rsend_016_neg.ksh
index 26573bfb594d..2741cd20ae0a 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/rsend_016_neg.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/rsend_016_neg.ksh
@@ -30,16 +30,9 @@
verify_runnable "both"
-function cleanup
-{
- rm -f $TEST_BASE_DIR/devnull
-}
-
-log_onexit cleanup
-
-log_mustnot eval "zfs send -i \#bla $POOl/$FS@final > $TEST_BASE_DIR/devnull"
+log_mustnot eval "zfs send -i \#bla $POOl/$FS@final > /dev/null"
log_must eval "zfs send -R -i snapA $POOL/vol@snapA 2>&1 " \
- "> $TEST_BASE_DIR/devnull | grep -q WARNING"
+ "> /dev/null | grep -q WARNING"
log_pass "Ensure that error conditions cause appropriate failures."
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/send_invalid.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/send_invalid.ksh
index 2ce7ee4a082f..ab3b1d73f850 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/send_invalid.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/send_invalid.ksh
@@ -44,7 +44,7 @@ log_must zfs snap $testfs@snap0
log_must zfs snap $testfs@snap1
# Test bad send with the CLI
-log_mustnot eval "zfs send -i $testfs@snap1 $testfs@snap0 >$TEST_BASE_DIR/devnull"
+log_mustnot eval "zfs send -i $testfs@snap1 $testfs@snap0 > /dev/null"
# Test bad send with libzfs/libzfs_core
log_must badsend $testfs@snap0 $testfs@snap1
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/send_partial_dataset.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/send_partial_dataset.ksh
index c390327a5b57..c36b0c7c3ece 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/send_partial_dataset.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/send_partial_dataset.ksh
@@ -46,7 +46,7 @@ function cleanup
}
log_onexit cleanup
-log_must zfs create $POOL/testfs2
+log_must zfs create -o compression=off $POOL/testfs2
log_must zfs create $POOL/stream
mntpnt=$(get_prop mountpoint $POOL/testfs2)
@@ -103,7 +103,7 @@ set -A badargs \
while (( i < ${#badargs[*]} ))
do
- log_mustnot eval "zfs send --saved ${badargs[i]} >$TEST_BASE_DIR/devnull"
+ log_mustnot eval "zfs send --saved ${badargs[i]} > /dev/null"
(( i = i + 1 ))
done
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/send_raw_ashift.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/send_raw_ashift.ksh
new file mode 100755
index 000000000000..3cea334495d9
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/send_raw_ashift.ksh
@@ -0,0 +1,193 @@
+#!/bin/ksh
+
+#
+# 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.
+#
+
+#
+# Copyright (c) 2019, Lawrence Livermore National Security, LLC.
+# Copyright (c) 2021, George Amanakis. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/include/properties.shlib
+. $STF_SUITE/tests/functional/rsend/rsend.kshlib
+
+#
+# Description:
+# Verify encrypted raw sending to pools with greater ashift succeeds.
+#
+# Strategy:
+# 1) Create a set of files each containing some file data in an
+# encrypted filesystem.
+# 2) Snapshot and raw send these files to a pool with greater ashift
+# 3) Verify that all the xattrs (and thus the spill block) were
+# preserved when receiving the incremental stream.
+# 4) Repeat the test for a non-encrypted filesystem using raw send
+#
+
+verify_runnable "both"
+
+log_assert "Verify raw sending to pools with greater ashift succeeds"
+
+function cleanup
+{
+ rm -f $BACKDIR/fs@*
+ poolexists pool9 && destroy_pool pool9
+ poolexists pool12 && destroy_pool pool12
+ log_must rm -f $TESTDIR/vdev_a $TESTDIR/vdev_b
+}
+
+function xattr_test
+{
+ log_must zfs set xattr=sa pool9/$1
+ log_must zfs set dnodesize=legacy pool9/$1
+ log_must zfs set recordsize=128k pool9/$1
+ rand_set_prop pool9/$1 compression "${compress_prop_vals[@]}"
+
+ # Create 40 files each with a spill block containing xattrs. Each file
+ # will be modified in a different way to validate the incremental receive.
+ for i in {1..40}; do
+ file="/pool9/$1/file$i"
+
+ log_must mkfile 16384 $file
+ for j in {1..20}; do
+ log_must set_xattr "testattr$j" "$attrvalue" $file
+ done
+ done
+
+ # Snapshot the pool and send it to the new dataset.
+ log_must zfs snapshot pool9/$1@snap1
+ log_must eval "zfs send -w pool9/$1@snap1 >$BACKDIR/$1@snap1"
+ log_must eval "zfs recv pool12/$1 < $BACKDIR/$1@snap1"
+
+ #
+ # Modify file[1-6]'s contents but not the spill blocks.
+ #
+ # file1 - Increase record size; single block
+ # file2 - Increase record size; multiple blocks
+ # file3 - Truncate file to zero size; single block
+ # file4 - Truncate file to smaller size; single block
+ # file5 - Truncate file to much larger size; add holes
+ # file6 - Truncate file to embedded size; embedded data
+ #
+ log_must mkfile 32768 /pool9/$1/file1
+ log_must mkfile 1048576 /pool9/$1/file2
+ log_must truncate -s 0 /pool9/$1/file3
+ log_must truncate -s 8192 /pool9/$1/file4
+ log_must truncate -s 1073741824 /pool9/$1/file5
+ log_must truncate -s 50 /pool9/$1/file6
+
+ #
+ # Modify file[11-16]'s contents and their spill blocks.
+ #
+ # file11 - Increase record size; single block
+ # file12 - Increase record size; multiple blocks
+ # file13 - Truncate file to zero size; single block
+ # file14 - Truncate file to smaller size; single block
+ # file15 - Truncate file to much larger size; add holes
+ # file16 - Truncate file to embedded size; embedded data
+ #
+ log_must mkfile 32768 /pool9/$1/file11
+ log_must mkfile 1048576 /pool9/$1/file12
+ log_must truncate -s 0 /pool9/$1/file13
+ log_must truncate -s 8192 /pool9/$1/file14
+ log_must truncate -s 1073741824 /pool9/$1/file15
+ log_must truncate -s 50 /pool9/$1/file16
+
+ for i in {11..20}; do
+ log_must rm_xattr testattr1 /pool9/$1/file$i
+ done
+
+ #
+ # Modify file[21-26]'s contents and remove their spill blocks.
+ #
+ # file21 - Increase record size; single block
+ # file22 - Increase record size; multiple blocks
+ # file23 - Truncate file to zero size; single block
+ # file24 - Truncate file to smaller size; single block
+ # file25 - Truncate file to much larger size; add holes
+ # file26 - Truncate file to embedded size; embedded data
+ #
+ log_must mkfile 32768 /pool9/$1/file21
+ log_must mkfile 1048576 /pool9/$1/file22
+ log_must truncate -s 0 /pool9/$1/file23
+ log_must truncate -s 8192 /pool9/$1/file24
+ log_must truncate -s 1073741824 /pool9/$1/file25
+ log_must truncate -s 50 /pool9/$1/file26
+
+ for i in {21..30}; do
+ for j in {1..20}; do
+ log_must rm_xattr testattr$j /pool9/$1/file$i
+ done
+ done
+
+ #
+ # Modify file[31-40]'s spill blocks but not the file contents.
+ #
+ for i in {31..40}; do
+ file="/pool9/$1/file$i"
+ log_must rm_xattr testattr$(((RANDOM % 20) + 1)) $file
+ log_must set_xattr testattr$(((RANDOM % 20) + 1)) "$attrvalue" $file
+ done
+
+ # Snapshot the pool and send the incremental snapshot.
+ log_must zfs snapshot pool9/$1@snap2
+ log_must eval "zfs send -w -i pool9/$1@snap1 pool9/$1@snap2 >$BACKDIR/$1@snap2"
+ log_must eval "zfs recv pool12/$1 < $BACKDIR/$1@snap2"
+}
+
+attrvalue="abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
+
+log_onexit cleanup
+
+# Create pools
+truncate -s $MINVDEVSIZE $TESTDIR/vdev_a
+truncate -s $MINVDEVSIZE $TESTDIR/vdev_b
+log_must zpool create -f -o ashift=9 pool9 $TESTDIR/vdev_a
+log_must zpool create -f -o ashift=12 pool12 $TESTDIR/vdev_b
+
+# Create encrypted fs
+log_must eval "echo 'password' | zfs create -o encryption=on" \
+ "-o keyformat=passphrase -o keylocation=prompt " \
+ "pool9/encfs"
+
+# Run xattr tests for encrypted fs
+xattr_test encfs
+
+# Calculate the expected recursive checksum for source encrypted fs
+expected_cksum=$(recursive_cksum /pool9/encfs)
+
+# Mount target encrypted fs
+log_must eval "echo 'password' | zfs load-key pool12/encfs"
+log_must zfs mount pool12/encfs
+
+# Validate the received copy using the received recursive checksum
+actual_cksum=$(recursive_cksum /pool12/encfs)
+if [[ "$expected_cksum" != "$actual_cksum" ]]; then
+ log_fail "Checksums differ ($expected_cksum != $actual_cksum)"
+fi
+
+# Perform the same test but without encryption (send -w)
+log_must zfs create pool9/fs
+
+# Run xattr tests for non-encrypted fs
+xattr_test fs
+
+# Calculate the expected recursive checksum for source non-encrypted fs
+expected_cksum=$(recursive_cksum /pool9/fs)
+
+# Validate the received copy using the received recursive checksum
+actual_cksum=$(recursive_cksum /pool12/fs)
+if [[ "$expected_cksum" != "$actual_cksum" ]]; then
+ log_fail "Checksums differ ($expected_cksum != $actual_cksum)"
+fi
+
+log_pass "Verify raw sending to pools with greater ashift succeeds"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/send_raw_spill_block.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/send_raw_spill_block.ksh
new file mode 100755
index 000000000000..8d7451ae62e2
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/rsend/send_raw_spill_block.ksh
@@ -0,0 +1,161 @@
+#!/bin/ksh
+
+#
+# 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.
+#
+
+#
+# Copyright (c) 2019, Lawrence Livermore National Security, LLC.
+# Copyright (c) 2021, George Amanakis. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/rsend/rsend.kshlib
+
+#
+# Description:
+# Verify spill blocks are correctly preserved in raw sends.
+#
+# Strategy:
+# 1) Create a set of files each containing some file data in an
+# encrypted filesystem.
+# 2) Add enough xattrs to the file to require a spill block.
+# 3) Snapshot and raw send these files to a new dataset.
+# 4) Modify the files and spill blocks in a variety of ways.
+# 5) Send the changes using an raw incremental send stream.
+# 6) Verify that all the xattrs (and thus the spill block) were
+# preserved when receiving the incremental stream.
+#
+
+verify_runnable "both"
+
+log_assert "Verify spill blocks are correctly preserved in raw sends"
+
+function cleanup
+{
+ rm -f $BACKDIR/fs@*
+ destroy_dataset $POOL/fs "-rR"
+ destroy_dataset $POOL/newfs "-rR"
+}
+
+attrvalue="abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
+
+log_onexit cleanup
+
+log_must eval "echo 'password' | zfs create -o encryption=on" \
+ "-o keyformat=passphrase -o keylocation=prompt " \
+ "$POOL/fs"
+log_must zfs set xattr=sa $POOL/fs
+log_must zfs set dnodesize=legacy $POOL/fs
+log_must zfs set recordsize=128k $POOL/fs
+
+# Create 40 files each with a spill block containing xattrs. Each file
+# will be modified in a different way to validate the incremental receive.
+for i in {1..40}; do
+ file="/$POOL/fs/file$i"
+
+ log_must mkfile 16384 $file
+ for j in {1..20}; do
+ log_must set_xattr "testattr$j" "$attrvalue" $file
+ done
+done
+
+# Snapshot the pool and send it to the new dataset.
+log_must zfs snapshot $POOL/fs@snap1
+log_must eval "zfs send -w $POOL/fs@snap1 >$BACKDIR/fs@snap1"
+log_must eval "zfs recv $POOL/newfs < $BACKDIR/fs@snap1"
+
+#
+# Modify file[1-6]'s contents but not the spill blocks.
+#
+# file1 - Increase record size; single block
+# file2 - Increase record size; multiple blocks
+# file3 - Truncate file to zero size; single block
+# file4 - Truncate file to smaller size; single block
+# file5 - Truncate file to much larger size; add holes
+# file6 - Truncate file to embedded size; embedded data
+#
+log_must mkfile 32768 /$POOL/fs/file1
+log_must mkfile 1048576 /$POOL/fs/file2
+log_must truncate -s 0 /$POOL/fs/file3
+log_must truncate -s 8192 /$POOL/fs/file4
+log_must truncate -s 1073741824 /$POOL/fs/file5
+log_must truncate -s 50 /$POOL/fs/file6
+
+#
+# Modify file[11-16]'s contents and their spill blocks.
+#
+# file11 - Increase record size; single block
+# file12 - Increase record size; multiple blocks
+# file13 - Truncate file to zero size; single block
+# file14 - Truncate file to smaller size; single block
+# file15 - Truncate file to much larger size; add holes
+# file16 - Truncate file to embedded size; embedded data
+#
+log_must mkfile 32768 /$POOL/fs/file11
+log_must mkfile 1048576 /$POOL/fs/file12
+log_must truncate -s 0 /$POOL/fs/file13
+log_must truncate -s 8192 /$POOL/fs/file14
+log_must truncate -s 1073741824 /$POOL/fs/file15
+log_must truncate -s 50 /$POOL/fs/file16
+
+for i in {11..20}; do
+ log_must rm_xattr testattr1 /$POOL/fs/file$i
+done
+
+#
+# Modify file[21-26]'s contents and remove their spill blocks.
+#
+# file21 - Increase record size; single block
+# file22 - Increase record size; multiple blocks
+# file23 - Truncate file to zero size; single block
+# file24 - Truncate file to smaller size; single block
+# file25 - Truncate file to much larger size; add holes
+# file26 - Truncate file to embedded size; embedded data
+#
+log_must mkfile 32768 /$POOL/fs/file21
+log_must mkfile 1048576 /$POOL/fs/file22
+log_must truncate -s 0 /$POOL/fs/file23
+log_must truncate -s 8192 /$POOL/fs/file24
+log_must truncate -s 1073741824 /$POOL/fs/file25
+log_must truncate -s 50 /$POOL/fs/file26
+
+for i in {21..30}; do
+ for j in {1..20}; do
+ log_must rm_xattr testattr$j /$POOL/fs/file$i
+ done
+done
+
+#
+# Modify file[31-40]'s spill blocks but not the file contents.
+#
+for i in {31..40}; do
+ file="/$POOL/fs/file$i"
+ log_must rm_xattr testattr$(((RANDOM % 20) + 1)) $file
+ log_must set_xattr testattr$(((RANDOM % 20) + 1)) "$attrvalue" $file
+done
+
+# Calculate the expected recursive checksum for the source.
+expected_cksum=$(recursive_cksum /$POOL/fs)
+
+# Snapshot the pool and send the incremental snapshot.
+log_must zfs snapshot $POOL/fs@snap2
+log_must eval "zfs send -w -i $POOL/fs@snap1 $POOL/fs@snap2 >$BACKDIR/fs@snap2"
+log_must eval "zfs recv $POOL/newfs < $BACKDIR/fs@snap2"
+log_must eval "echo 'password' | zfs load-key $POOL/newfs"
+log_must zfs mount $POOL/newfs
+
+# Validate the received copy using the received recursive checksum.
+actual_cksum=$(recursive_cksum /$POOL/newfs)
+if [[ "$expected_cksum" != "$actual_cksum" ]]; then
+ log_fail "Checksums differ ($expected_cksum != $actual_cksum)"
+fi
+
+log_pass "Verify spill blocks are correctly preserved in raw sends"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/simd/Makefile.am b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/simd/Makefile.am
new file mode 100644
index 000000000000..bfc28868024a
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/simd/Makefile.am
@@ -0,0 +1,2 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/simd
+dist_pkgdata_SCRIPTS = simd_supported.ksh
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/simd/simd_supported.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/simd/simd_supported.ksh
new file mode 100755
index 000000000000..d88bc582bf08
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/simd/simd_supported.ksh
@@ -0,0 +1,58 @@
+#!/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) 2022 by Attila Fülöp <attila@fueloep.org>
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Make sure we have SIMD support, so it will not go away without notice
+#
+# STRATEGY:
+# 1. Test if we are running on a Linux x86 system with SSE support
+# 2. If so, check if the zfs_fletcher_4_impl module parameter contains
+# a sse implementation
+# 3. If not fail the test, otherwise pass it
+
+log_note "Testing if we support SIMD instructions (Linux x86 only)"
+
+if !is_linux; then
+ log_unsupported "Not a Linux System"
+fi
+
+case "$(uname -m)" in
+i386|i686|x86_64)
+ typeset -R modparam="/sys/module/zcommon/parameters/zfs_fletcher_4_impl"
+ if cat /proc/cpuinfo | awk '/^flags/ {print; exit;}' | grep -q sse; then
+ log_must grep -q sse "$modparam"
+ log_pass "SIMD instructions supported"
+ else
+ log_unsupported "No FPU present"
+ fi
+ ;;
+*)
+ log_unsupported "Not a x86 CPU"
+ ;;
+esac
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/slog/Makefile.am b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/slog/Makefile.am
index 33e3a6d3a496..92c3fd6c8e75 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/slog/Makefile.am
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/slog/Makefile.am
@@ -19,7 +19,8 @@ dist_pkgdata_SCRIPTS = \
slog_015_neg.ksh \
slog_replay_fs_001.ksh \
slog_replay_fs_002.ksh \
- slog_replay_volume.ksh
+ slog_replay_volume.ksh \
+ slog_016_pos.ksh
dist_pkgdata_DATA = \
slog.cfg \
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/slog/slog_016_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/slog/slog_016_pos.ksh
new file mode 100755
index 000000000000..75f78c800a7c
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/slog/slog_016_pos.ksh
@@ -0,0 +1,157 @@
+#!/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) 2021 by Nutanix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/slog/slog.kshlib
+
+#
+# DESCRIPTION:
+# Verify saxattr logging in to ZIL works
+#
+# STRATEGY:
+# 1. Create an empty file system (TESTFS)
+# 2. Freeze TESTFS
+# 3. Create Xattrs.
+# 4. Unmount filesystem
+# <at this stage TESTFS is empty again and unfrozen, and the
+# intent log contains a complete set of deltas to replay it>
+# 5. Remount TESTFS <which replays the intent log>
+# 6. Check xattrs.
+#
+
+verify_runnable "global"
+
+function cleanup_testenv
+{
+ cleanup
+ log_must set_tunable32 ZIL_SAXATTR $orig_zil_saxattr
+}
+
+log_assert "Verify saxattr logging in to ZIL works"
+
+orig_zil_saxattr=$(get_tunable ZIL_SAXATTR)
+
+log_onexit cleanup_testenv
+log_must setup
+
+NFILES=10
+function validate_zil_saxattr
+{
+ saxattrzil=$1
+ if [ "$2" == "disabled" ]; then
+ zilsaxattr_feature_disabled=1
+ zpoolcreateflags="-ofeature@zilsaxattr=disabled"
+ else
+ zilsaxattr_feature_disabled=0
+ zpoolcreateflags=""
+ fi
+
+ log_must set_tunable32 ZIL_SAXATTR $saxattrzil
+
+ #
+ # 1. Create an empty file system (TESTFS)
+ #
+ log_must zpool create $zpoolcreateflags $TESTPOOL $VDEV log mirror $LDEV
+ log_must zfs set compression=on $TESTPOOL
+ log_must zfs create -o xattr=sa $TESTPOOL/$TESTFS
+ log_must mkdir -p $TESTDIR
+
+ #
+ # This dd command works around an issue where ZIL records aren't created
+ # after freezing the pool unless a ZIL header already exists. Create a
+ # file synchronously to force ZFS to write one out.
+ #
+ log_must dd if=/dev/zero of=/$TESTPOOL/$TESTFS/sync \
+ conv=fdatasync,fsync bs=1 count=1
+
+ #
+ # 2. Freeze TESTFS
+ #
+ log_must zpool freeze $TESTPOOL
+
+ rm /$TESTPOOL/$TESTFS/sync
+ #
+ # 3. Create xattrs
+ #
+ for i in $(seq $NFILES); do
+ log_must mkdir /$TESTPOOL/$TESTFS/xattr.d.$i
+ log_must set_xattr test test /$TESTPOOL/$TESTFS/xattr.d.$i
+
+ log_must touch /$TESTPOOL/$TESTFS/xattr.f.$i
+ log_must set_xattr test test /$TESTPOOL/$TESTFS/xattr.f.$i
+ done
+
+ #
+ # 4. Unmount filesystem and export the pool
+ #
+ # At this stage TESTFS is empty again and unfrozen, and the
+ # intent log contains a complete set of deltas to replay it.
+ #
+ log_must zfs unmount /$TESTPOOL/$TESTFS
+
+ log_note "Verify transactions to replay:"
+ log_must zdb -iv $TESTPOOL/$TESTFS
+
+ log_must zpool export $TESTPOOL
+
+ #
+ # 5. Remount TESTFS <which replays the intent log>
+ #
+ # Import the pool to unfreeze it and claim log blocks. It has to be
+ # `zpool import -f` because we can't write a frozen pool's labels!
+ #
+ log_must zpool import -f -d $VDIR $TESTPOOL
+
+ #
+ # 6. Verify Xattr
+ # If zilsaxattr_feature_disabled=1 or saxattrzil=0, then xattr=sa
+ # logging in ZIL is not enabled, So, xattrs would be lost.
+ # If zilsaxattr_feature_disabled=0 and saxattrzil=1, then xattr=sa
+ # logging in ZIL is enabled, So, xattrs shouldn't be lost.
+ #
+ for i in $(seq $NFILES); do
+ if [ $zilsaxattr_feature_disabled -eq 1 -o \
+ $saxattrzil -eq 0 ]; then
+ log_mustnot get_xattr test /$TESTPOOL/$TESTFS/xattr.d.$i
+ log_mustnot get_xattr test /$TESTPOOL/$TESTFS/xattr.f.$i
+ else
+ log_must get_xattr test /$TESTPOOL/$TESTFS/xattr.d.$i
+ log_must get_xattr test /$TESTPOOL/$TESTFS/xattr.f.$i
+ fi
+ done
+
+ cleanup
+ log_must setup
+}
+
+
+#Validate zilsaxattr feature enabled.
+validate_zil_saxattr 0
+validate_zil_saxattr 1
+#Validate zilsaxattr feature disabled.
+validate_zil_saxattr 0 disabled
+validate_zil_saxattr 1 disabled
+
+log_pass "Verify saxattr logging in to ZIL works"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/slog/slog_replay_fs_001.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/slog/slog_replay_fs_001.ksh
index 0b78a099f0b9..0b78a9645a60 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/slog/slog_replay_fs_001.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/slog/slog_replay_fs_001.ksh
@@ -178,8 +178,8 @@ log_must rm /$TESTPOOL/$TESTFS/link_and_unlink.link
#
# 4. Copy TESTFS to temporary location (TESTDIR/copy)
#
-log_must mkdir -p $TESTDIR/copy
-log_must cp -a /$TESTPOOL/$TESTFS/* $TESTDIR/copy/
+log_must mkdir -p $TESTDIR
+log_must rsync -aHAX /$TESTPOOL/$TESTFS/ $TESTDIR/copy
#
# 5. Unmount filesystem and export the pool
@@ -213,7 +213,7 @@ log_must ls_xattr /$TESTPOOL/$TESTFS/xattr.dir
log_must ls_xattr /$TESTPOOL/$TESTFS/xattr.file
log_note "Verify working set diff:"
-log_must diff -r /$TESTPOOL/$TESTFS $TESTDIR/copy
+log_must replay_directory_diff $TESTDIR/copy /$TESTPOOL/$TESTFS
log_note "Verify file checksum:"
typeset checksum1=$(sha256digest /$TESTPOOL/$TESTFS/payload)
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/slog/slog_replay_fs_002.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/slog/slog_replay_fs_002.ksh
index 3c3ccdf4ad23..50ccc6089322 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/slog/slog_replay_fs_002.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/slog/slog_replay_fs_002.ksh
@@ -98,8 +98,8 @@ log_must eval 'for i in $(seq $NFILES); do zfs set dnodesize=${dnsize[$RANDOM %
#
# 4. Copy TESTFS to temporary location (TESTDIR/copy)
#
-log_must mkdir -p $TESTDIR/copy
-log_must cp -a /$TESTPOOL/$TESTFS/* $TESTDIR/copy/
+log_must mkdir -p $TESTDIR
+log_must rsync -aHAX /$TESTPOOL/$TESTFS/ $TESTDIR/copy
#
# 5. Unmount filesystem and export the pool
@@ -132,6 +132,6 @@ log_note "Verify number of files"
log_must test "$(ls /$TESTPOOL/$TESTFS/dir0 | wc -l)" -eq $NFILES
log_note "Verify working set diff:"
-log_must diff -r /$TESTPOOL/$TESTFS $TESTDIR/copy
+log_must replay_directory_diff $TESTDIR/copy /$TESTPOOL/$TESTFS
log_pass "Replay of intent log succeeds."
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/snapshot/snapshot_002_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/snapshot/snapshot_002_pos.ksh
index 124a7db9c6e6..42fbbd9a7a2b 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/snapshot/snapshot_002_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/snapshot/snapshot_002_pos.ksh
@@ -55,24 +55,28 @@ function cleanup
cd $CWD || log_fail "Could not cd $CWD"
fi
- snapexists $SNAPFS
- if [[ $? -eq 0 ]]; then
- log_must zfs destroy $SNAPFS
- fi
+ snapexists $SNAPFS
+ if [[ $? -eq 0 ]]; then
+ log_must zfs destroy $SNAPFS
+ fi
- if [[ -e $SNAPDIR ]]; then
- log_must rm -rf $SNAPDIR > /dev/null 2>&1
- fi
+ if [[ -e $SNAPDIR ]]; then
+ log_must rm -rf $SNAPDIR > /dev/null 2>&1
+ fi
- if [[ -e $TESTDIR ]]; then
- log_must rm -rf $TESTDIR/* > /dev/null 2>&1
- fi
+ if [[ -e $TESTDIR ]]; then
+ log_must rm -rf $TESTDIR/* > /dev/null 2>&1
+ fi
+ if [[ -d "$SNAPSHOT_TARDIR" ]]; then
+ log_must rm -rf $SNAPSHOT_TARDIR > /dev/null 2>&1
+ fi
}
log_assert "Verify an archive of a file system is identical to " \
"an archive of its snapshot."
+SNAPSHOT_TARDIR="$(mktemp -d /tmp/zfstests_snapshot_002.XXXXXX)"
log_onexit cleanup
typeset -i COUNT=21
@@ -87,14 +91,13 @@ typeset i=1
while [ $i -lt $COUNT ]; do
log_must file_write -o $OP -f $TESTDIR/file$i \
-b $BLOCKSZ -c $NUM_WRITES -d $DATA
-
(( i = i + 1 ))
done
log_note "Create a tarball from $TESTDIR contents..."
CWD=$PWD
cd $TESTDIR || log_fail "Could not cd $TESTDIR"
-log_must tar cf $TESTDIR/tarball.original.tar file*
+log_must tar cf $SNAPSHOT_TARDIR/original.tar .
cd $CWD || log_fail "Could not cd $CWD"
log_note "Create a snapshot and mount it..."
@@ -106,7 +109,7 @@ log_must rm -f $TESTDIR/file* > /dev/null 2>&1
log_note "Create tarball of snapshot..."
CWD=$PWD
cd $SNAPDIR || log_fail "Could not cd $SNAPDIR"
-log_must tar cf $TESTDIR/tarball.snapshot.tar file*
+log_must tar cf $SNAPSHOT_TARDIR/snapshot.tar .
cd $CWD || log_fail "Could not cd $CWD"
log_must mkdir $TESTDIR/original
@@ -114,16 +117,12 @@ log_must mkdir $TESTDIR/snapshot
CWD=$PWD
cd $TESTDIR/original || log_fail "Could not cd $TESTDIR/original"
-log_must tar xf $TESTDIR/tarball.original.tar
+log_must tar xf $SNAPSHOT_TARDIR/original.tar
cd $TESTDIR/snapshot || log_fail "Could not cd $TESTDIR/snapshot"
-log_must tar xf $TESTDIR/tarball.snapshot.tar
+log_must tar xf $SNAPSHOT_TARDIR/snapshot.tar
cd $CWD || log_fail "Could not cd $CWD"
-diff -q -r $TESTDIR/original $TESTDIR/snapshot > /dev/null 2>&1
-if [[ $? -eq 1 ]]; then
- log_fail "Directory structures differ."
-fi
-
+log_must directory_diff $TESTDIR/original $TESTDIR/snapshot
log_pass "Directory structures match."
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/snapshot/snapshot_006_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/snapshot/snapshot_006_pos.ksh
index 68a616c02a6c..d2a304670981 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/snapshot/snapshot_006_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/snapshot/snapshot_006_pos.ksh
@@ -54,24 +54,28 @@ function cleanup
cd $CWD || log_fail "Could not cd $CWD"
fi
- snapexists $SNAPCTR
- if [[ $? -eq 0 ]]; then
- log_must zfs destroy $SNAPCTR
- fi
+ snapexists $SNAPCTR
+ if [[ $? -eq 0 ]]; then
+ log_must zfs destroy $SNAPCTR
+ fi
- if [[ -e $SNAPDIR1 ]]; then
- log_must rm -rf $SNAPDIR1 > /dev/null 2>&1
- fi
+ if [[ -e $SNAPDIR1 ]]; then
+ log_must rm -rf $SNAPDIR1 > /dev/null 2>&1
+ fi
- if [[ -e $TESTDIR1 ]]; then
- log_must rm -rf $TESTDIR1/* > /dev/null 2>&1
- fi
+ if [[ -e $TESTDIR1 ]]; then
+ log_must rm -rf $TESTDIR1/* > /dev/null 2>&1
+ fi
+ if [[ -d "$SNAPSHOT_TARDIR" ]]; then
+ log_must rm -rf $SNAPSHOT_TARDIR > /dev/null 2>&1
+ fi
}
log_assert "Verify that an archive of a dataset is identical to " \
"an archive of the dataset's snapshot."
+SNAPSHOT_TARDIR="$(mktemp -d /tmp/zfstests_snapshot_006.XXXXXX)"
log_onexit cleanup
typeset -i COUNT=21
@@ -85,14 +89,13 @@ typeset i=1
while [ $i -lt $COUNT ]; do
log_must file_write -o $OP -f $TESTDIR1/file$i \
-b $BLOCKSZ -c $NUM_WRITES -d $DATA
-
(( i = i + 1 ))
done
log_note "Create a tarball from $TESTDIR1 contents..."
CWD=$PWD
cd $TESTDIR1 || log_fail "Could not cd $TESTDIR1"
-log_must tar cf $TESTDIR1/tarball.original.tar file*
+log_must tar cf $SNAPSHOT_TARDIR/original.tar .
cd $CWD || log_fail "Could not cd $CWD"
log_note "Create a snapshot and mount it..."
@@ -104,7 +107,7 @@ log_must rm -f $TESTDIR1/file* > /dev/null 2>&1
log_note "Create tarball of snapshot..."
CWD=$PWD
cd $SNAPDIR1 || log_fail "Could not cd $SNAPDIR1"
-log_must tar cf $TESTDIR1/tarball.snapshot.tar file*
+log_must tar cf $SNAPSHOT_TARDIR/snapshot.tar .
cd $CWD || log_fail "Could not cd $CWD"
log_must mkdir $TESTDIR1/original
@@ -112,16 +115,12 @@ log_must mkdir $TESTDIR1/snapshot
CWD=$PWD
cd $TESTDIR1/original || log_fail "Could not cd $TESTDIR1/original"
-log_must tar xf $TESTDIR1/tarball.original.tar
+log_must tar xf $SNAPSHOT_TARDIR/original.tar
cd $TESTDIR1/snapshot || log_fail "Could not cd $TESTDIR1/snapshot"
-log_must tar xf $TESTDIR1/tarball.snapshot.tar
+log_must tar xf $SNAPSHOT_TARDIR/snapshot.tar
cd $CWD || log_fail "Could not cd $CWD"
-diff -q -r $TESTDIR1/original $TESTDIR1/snapshot > /dev/null 2>&1
-if [[ $? -eq 1 ]]; then
- log_fail "Directory structures differ."
-fi
-
+log_must directory_diff $TESTDIR1/original $TESTDIR1/snapshot
log_pass "Directory structures match."
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/snapshot/snapshot_014_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/snapshot/snapshot_014_pos.ksh
index d48d404b6d14..384377c7f64b 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/snapshot/snapshot_014_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/snapshot/snapshot_014_pos.ksh
@@ -56,11 +56,14 @@ function cleanup
datasetexists $TESTPOOL/$TESTCTR/$TESTFS1 && \
log_must zfs set quota=none $TESTPOOL/$TESTCTR/$TESTFS1
+ zfs inherit compression $TESTPOOL
}
log_assert "Verify creating/destroying snapshots do things clean"
log_onexit cleanup
+log_must zfs set compression=off $TESTPOOL
+
log_must zfs set quota=$FSQUOTA $TESTPOOL/$TESTCTR/$TESTFS1
log_must mkfile $FILESIZE $TESTDIR1/$TESTFILE
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/Makefile.am b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/Makefile.am
index 594d2b77ca8e..0145c1205fb3 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/Makefile.am
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/Makefile.am
@@ -7,6 +7,7 @@ dist_pkgdata_SCRIPTS = \
suid_write_to_sgid.ksh \
suid_write_to_suid_sgid.ksh \
suid_write_to_none.ksh \
+ suid_write_zil_replay.ksh \
cleanup.ksh \
setup.ksh
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/suid_write_to_file.c b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/suid_write_to_file.c
index 571dc553bec2..f3febb903b59 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/suid_write_to_file.c
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/suid_write_to_file.c
@@ -29,86 +29,16 @@
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
-
-static void
-test_stat_mode(mode_t extra)
-{
- struct stat st;
- int i, fd;
- char fpath[1024];
- char *penv[] = {"TESTDIR", "TESTFILE0"};
- char buf[] = "test";
- mode_t res;
- mode_t mode = 0777 | extra;
-
- /*
- * Get the environment variable values.
- */
- for (i = 0; i < sizeof (penv) / sizeof (char *); i++) {
- if ((penv[i] = getenv(penv[i])) == NULL) {
- fprintf(stderr, "getenv(penv[%d])\n", i);
- exit(1);
- }
- }
-
- umask(0);
- if (stat(penv[0], &st) == -1 && mkdir(penv[0], mode) == -1) {
- perror("mkdir");
- exit(2);
- }
-
- snprintf(fpath, sizeof (fpath), "%s/%s", penv[0], penv[1]);
- unlink(fpath);
- if (stat(fpath, &st) == 0) {
- fprintf(stderr, "%s exists\n", fpath);
- exit(3);
- }
-
- fd = creat(fpath, mode);
- if (fd == -1) {
- perror("creat");
- exit(4);
- }
- close(fd);
-
- if (setuid(65534) == -1) {
- perror("setuid");
- exit(5);
- }
-
- fd = open(fpath, O_RDWR);
- if (fd == -1) {
- perror("open");
- exit(6);
- }
-
- if (write(fd, buf, sizeof (buf)) == -1) {
- perror("write");
- exit(7);
- }
- close(fd);
-
- if (stat(fpath, &st) == -1) {
- perror("stat");
- exit(8);
- }
- unlink(fpath);
-
- /* Verify SUID/SGID are dropped */
- res = st.st_mode & (0777 | S_ISUID | S_ISGID);
- if (res != (mode & 0777)) {
- fprintf(stderr, "stat(2) %o\n", res);
- exit(9);
- }
-}
+#include <stdbool.h>
int
main(int argc, char *argv[])
{
- const char *name;
+ const char *name, *phase;
mode_t extra;
+ struct stat st;
- if (argc < 2) {
+ if (argc < 3) {
fprintf(stderr, "Invalid argc\n");
exit(1);
}
@@ -127,7 +57,77 @@ main(int argc, char *argv[])
exit(1);
}
- test_stat_mode(extra);
+ const char *testdir = getenv("TESTDIR");
+ if (!testdir) {
+ fprintf(stderr, "getenv(TESTDIR)\n");
+ exit(1);
+ }
+
+ umask(0);
+ if (stat(testdir, &st) == -1 && mkdir(testdir, 0777) == -1) {
+ perror("mkdir");
+ exit(2);
+ }
+
+ char fpath[1024];
+ snprintf(fpath, sizeof (fpath), "%s/%s", testdir, name);
+
+
+ phase = argv[2];
+ if (strcmp(phase, "PRECRASH") == 0) {
+
+ /* clean up last run */
+ unlink(fpath);
+ if (stat(fpath, &st) == 0) {
+ fprintf(stderr, "%s exists\n", fpath);
+ exit(3);
+ }
+
+ int fd;
+
+ fd = creat(fpath, 0777 | extra);
+ if (fd == -1) {
+ perror("creat");
+ exit(4);
+ }
+ close(fd);
+
+ if (setuid(65534) == -1) {
+ perror("setuid");
+ exit(5);
+ }
+
+ fd = open(fpath, O_RDWR);
+ if (fd == -1) {
+ perror("open");
+ exit(6);
+ }
+
+ const char buf[] = "test";
+ if (write(fd, buf, sizeof (buf)) == -1) {
+ perror("write");
+ exit(7);
+ }
+ close(fd);
+
+ } else if (strcmp(phase, "REPLAY") == 0) {
+ /* created in PRECRASH run */
+ } else {
+ fprintf(stderr, "Invalid phase %s\n", phase);
+ exit(1);
+ }
+
+ if (stat(fpath, &st) == -1) {
+ perror("stat");
+ exit(8);
+ }
+
+ /* Verify SUID/SGID are dropped */
+ mode_t res = st.st_mode & (0777 | S_ISUID | S_ISGID);
+ if (res != 0777) {
+ fprintf(stderr, "stat(2) %o\n", res);
+ exit(9);
+ }
return (0);
}
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/suid_write_to_none.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/suid_write_to_none.ksh
index dd01978619f9..470350f960cf 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/suid_write_to_none.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/suid_write_to_none.ksh
@@ -47,6 +47,6 @@ function cleanup
log_onexit cleanup
log_note "Verify write(2) to regular file by non-owner"
-log_must $STF_SUITE/tests/functional/suid/suid_write_to_file "NONE"
+log_must $STF_SUITE/tests/functional/suid/suid_write_to_file "NONE" "PRECRASH"
log_pass "Verify write(2) to regular file by non-owner passed"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/suid_write_to_sgid.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/suid_write_to_sgid.ksh
index 49ae2bd1b31e..3c95a402658e 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/suid_write_to_sgid.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/suid_write_to_sgid.ksh
@@ -47,6 +47,6 @@ function cleanup
log_onexit cleanup
log_note "Verify write(2) to SGID file by non-owner"
-log_must $STF_SUITE/tests/functional/suid/suid_write_to_file "SGID"
+log_must $STF_SUITE/tests/functional/suid/suid_write_to_file "SGID" "PRECRASH"
log_pass "Verify write(2) to SGID file by non-owner passed"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/suid_write_to_suid.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/suid_write_to_suid.ksh
index 3983aad2e51d..4183cbeefc20 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/suid_write_to_suid.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/suid_write_to_suid.ksh
@@ -47,6 +47,6 @@ function cleanup
log_onexit cleanup
log_note "Verify write(2) to SUID file by non-owner"
-log_must $STF_SUITE/tests/functional/suid/suid_write_to_file "SUID"
+log_must $STF_SUITE/tests/functional/suid/suid_write_to_file "SUID" "PRECRASH"
log_pass "Verify write(2) to SUID file by non-owner passed"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/suid_write_to_suid_sgid.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/suid_write_to_suid_sgid.ksh
index a058c7e7d4bc..f7a08a55fc4b 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/suid_write_to_suid_sgid.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/suid_write_to_suid_sgid.ksh
@@ -47,6 +47,6 @@ function cleanup
log_onexit cleanup
log_note "Verify write(2) to SUID/SGID file by non-owner"
-log_must $STF_SUITE/tests/functional/suid/suid_write_to_file "SUID_SGID"
+log_must $STF_SUITE/tests/functional/suid/suid_write_to_file "SUID_SGID" "PRECRASH"
log_pass "Verify write(2) to SUID/SGID file by non-owner passed"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/suid_write_zil_replay.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/suid_write_zil_replay.ksh
new file mode 100755
index 000000000000..81f431f6b68b
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/suid/suid_write_zil_replay.ksh
@@ -0,0 +1,99 @@
+#!/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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/tests/functional/slog/slog.kshlib
+
+verify_runnable "global"
+
+function cleanup_fs
+{
+ cleanup
+}
+
+log_assert "Verify ZIL replay results in correct SUID/SGID bits for unprivileged write to SUID/SGID files"
+log_onexit cleanup_fs
+log_must setup
+
+#
+# 1. Create a file system (TESTFS)
+#
+log_must zpool destroy "$TESTPOOL"
+log_must zpool create $TESTPOOL $VDEV log mirror $LDEV
+log_must zfs set compression=on $TESTPOOL
+log_must zfs create -o mountpoint="$TESTDIR" $TESTPOOL/$TESTFS
+
+# Make all the writes from suid_write_to_file.c sync
+log_must zfs set sync=always "$TESTPOOL/$TESTFS"
+
+#
+# This dd command works around an issue where ZIL records aren't created
+# after freezing the pool unless a ZIL header already exists. Create a file
+# synchronously to force ZFS to write one out.
+#
+log_must dd if=/dev/zero of=$TESTDIR/sync \
+ conv=fdatasync,fsync bs=1 count=1
+
+#
+# 2. Freeze TESTFS
+#
+log_must zpool freeze $TESTPOOL
+
+#
+# 3. Unprivileged write to a setuid file
+#
+log_must $STF_SUITE/tests/functional/suid/suid_write_to_file "NONE" "PRECRASH"
+log_must $STF_SUITE/tests/functional/suid/suid_write_to_file "SUID" "PRECRASH"
+log_must $STF_SUITE/tests/functional/suid/suid_write_to_file "SGID" "PRECRASH"
+log_must $STF_SUITE/tests/functional/suid/suid_write_to_file "SUID_SGID" "PRECRASH"
+
+#
+# 4. Unmount filesystem and export the pool
+#
+# At this stage TESTFS is empty again and frozen, the intent log contains
+# a complete set of deltas to replay.
+#
+log_must zfs unmount $TESTPOOL/$TESTFS
+
+log_note "List transactions to replay:"
+log_must zdb -iv $TESTPOOL/$TESTFS
+
+log_must zpool export $TESTPOOL
+
+#
+# 5. Remount TESTFS <which replays the intent log>
+#
+# Import the pool to unfreeze it and claim log blocks. It has to be
+# `zpool import -f` because we can't write a frozen pool's labels!
+#
+log_must zpool import -f -d $VDIR $TESTPOOL
+
+log_must $STF_SUITE/tests/functional/suid/suid_write_to_file "NONE" "REPLAY"
+log_must $STF_SUITE/tests/functional/suid/suid_write_to_file "SUID" "REPLAY"
+log_must $STF_SUITE/tests/functional/suid/suid_write_to_file "SGID" "REPLAY"
+log_must $STF_SUITE/tests/functional/suid/suid_write_to_file "SUID_SGID" "REPLAY"
+
+log_pass
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/tmpfile/tmpfile_002_pos.c b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/tmpfile/tmpfile_002_pos.c
index 55d939abd23b..39a72c22ab84 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/tmpfile/tmpfile_002_pos.c
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/tmpfile/tmpfile_002_pos.c
@@ -58,7 +58,7 @@ main(void)
exit(3);
}
- if ((ret = system("sudo zpool freeze $TESTPOOL"))) {
+ if ((ret = system("sudo -E zpool freeze $TESTPOOL"))) {
if (ret == -1)
perror("system \"zpool freeze\"");
else
@@ -69,7 +69,7 @@ main(void)
close(fd);
- if ((ret = system("sudo zpool export $TESTPOOL"))) {
+ if ((ret = system("sudo -E zpool export $TESTPOOL"))) {
if (ret == -1)
perror("system \"zpool export\"");
else
@@ -78,7 +78,7 @@ main(void)
exit(4);
}
- if ((ret = system("sudo zpool import $TESTPOOL"))) {
+ if ((ret = system("sudo -E zpool import $TESTPOOL"))) {
if (ret == -1)
perror("system \"zpool import\"");
else
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/userquota/setup.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/userquota/setup.ksh
index d4b3cdcaba92..2c609c9eb5e2 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/userquota/setup.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/userquota/setup.ksh
@@ -53,4 +53,6 @@ if [ $? -ne 0 ]; then
fi
DISK=${DISKS%% *}
-default_setup $DISK
+default_setup_noexit $DISK
+log_must zfs set compression=off $TESTPOOL
+log_pass
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/userquota/userspace_send_encrypted.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/userquota/userspace_send_encrypted.ksh
index e9ef0c4262e7..a9ff05174773 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/userquota/userspace_send_encrypted.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/userquota/userspace_send_encrypted.ksh
@@ -52,7 +52,7 @@ log_assert "Sending raw encrypted datasets back to the source dataset succeeds."
# Setup pool and create source
truncate -s 200m $FILEDEV
-log_must zpool create -o feature@encryption=enabled $POOLNAME \
+log_must zpool create -O compression=off -o feature@encryption=enabled $POOLNAME \
$FILEDEV
log_must eval "echo 'password' | zfs create -o encryption=on" \
"-o keyformat=passphrase -o keylocation=prompt " \
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_004_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_004_pos.ksh
index a84de6577704..b7468e4c331b 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_004_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_004_pos.ksh
@@ -50,6 +50,7 @@ assert_zap_common $TESTPOOL $DISK "top" $orig_top
disk2=$(echo $DISKS | awk '{print $2}')
log_must zpool attach $TESTPOOL $DISK $disk2
+log_must zpool wait -t resilver $TESTPOOL
log_must zdb -PC $TESTPOOL > $conf
# Ensure top-level ZAP was transferred successfully.
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/write_dirs/setup.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/write_dirs/setup.ksh
index a14eab27e958..c89cb8678c6a 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/write_dirs/setup.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/write_dirs/setup.ksh
@@ -35,4 +35,6 @@ verify_runnable "global"
DISK=$TEST_BASE_DIR/disk0
truncate -s 2G $DISK
-default_setup $DISK
+default_setup_noexit $DISK
+log_must zfs set compression=off $TESTPOOL
+log_pass
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/xattr/Makefile.am b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/xattr/Makefile.am
index 17001885f1ca..0cbd799aac85 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/xattr/Makefile.am
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/xattr/Makefile.am
@@ -14,7 +14,8 @@ dist_pkgdata_SCRIPTS = \
xattr_010_neg.ksh \
xattr_011_pos.ksh \
xattr_012_pos.ksh \
- xattr_013_pos.ksh
+ xattr_013_pos.ksh \
+ xattr_compat.ksh
dist_pkgdata_DATA = \
xattr_common.kshlib \
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/xattr/setup.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/xattr/setup.ksh
index d9228c426577..7ad36a714365 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/xattr/setup.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/xattr/setup.ksh
@@ -52,4 +52,6 @@ echo $ZFS_USER > $TEST_BASE_DIR/zfs-xattr-test-user.txt
echo $USES_NIS > $TEST_BASE_DIR/zfs-xattr-test-nis.txt
DISK=${DISKS%% *}
-default_setup $DISK
+default_setup_noexit $DISK
+log_must zfs set compression=off $TESTPOOL
+log_pass "Setup complete"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/xattr/xattr_compat.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/xattr/xattr_compat.ksh
new file mode 100755
index 000000000000..2f74ffe358b8
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/xattr/xattr_compat.ksh
@@ -0,0 +1,92 @@
+#!/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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright 2022 iXsystems, Inc.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# The zfs_xattr_compat tunable and fallback works as expected.
+#
+# STRATEGY:
+# For both of xattr=sa and xattr=dir:
+# 1. Create a filesystem with the native zfs_xattr_compat
+# 2. Create a file on the filesystem and add some xattrs to it
+# 3. Change the zfs_xattr_compat to the alternative setting
+# 4. Verify that the xattrs can still be accessed and modified
+# 5. Change zfs_xattr_compat back to the native setting
+# 6. Verify that the xattrs can still be accessed and modified
+#
+
+function cleanup {
+ rm -f $TESTFILE $TMPFILE
+ zfs set xattr=sa $TESTPOOL/$TESTFS
+ set_tunable32 XATTR_COMPAT $NATIVE_XATTR_COMPAT
+}
+
+log_assert "The zfs_xattr_compat tunable and fallback works as expected"
+log_onexit cleanup
+
+TESTFILE=$TESTDIR/testfile.$$
+TMPFILE=$TEST_BASE_DIR/tmpfile.$$
+NATIVE_XATTR_COMPAT=$(get_tunable XATTR_COMPAT)
+ALTERNATIVE_XATTR_COMPAT=$((1 - NATIVE_XATTR_COMPAT))
+
+for x in sa dir; do
+ log_must zfs set xattr=$x $TESTPOOL/$TESTFS
+ log_must touch $TESTFILE
+ log_must set_xattr testattr1 value1 $TESTFILE
+ log_must set_xattr testattr2 value2 $TESTFILE
+ log_must set_xattr testattr3 value3 $TESTFILE
+ log_must ls_xattr $TESTFILE
+
+ log_must set_tunable32 XATTR_COMPAT $ALTERNATIVE_XATTR_COMPAT
+ log_must ls_xattr $TESTFILE
+ log_must eval "get_xattr testattr1 $TESTFILE > $TMPFILE"
+ log_must test $(<$TMPFILE) = value1
+ log_must set_xattr testattr2 newvalue2 $TESTFILE
+ log_must rm_xattr testattr3 $TESTFILE
+ log_must set_xattr testattr4 value4 $TESTFILE
+ log_must ls_xattr $TESTFILE
+
+ log_must set_tunable32 XATTR_COMPAT $NATIVE_XATTR_COMPAT
+ log_must ls_xattr $TESTFILE
+ log_must eval "get_xattr testattr1 $TESTFILE > $TMPFILE"
+ log_must test $(<$TMPFILE) = value1
+ log_must eval "get_xattr testattr2 $TESTFILE > $TMPFILE"
+ log_must test $(<$TMPFILE) = newvalue2
+ log_mustnot get_xattr testattr3 $TESTFILE
+ log_must set_xattr testattr3 value3 $TESTFILE
+ log_must eval "get_xattr testattr4 $TESTFILE > $TMPFILE"
+ log_must test $(<$TMPFILE) = value4
+ log_must ls_xattr $TESTFILE
+
+ log_must rm $TESTFILE
+done
+
+log_pass "The zfs_xattr_compat tunable and fallback works as expected"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_volmode.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_volmode.ksh
index 264ec131ad6b..af808dc30764 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_volmode.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_volmode.ksh
@@ -43,8 +43,6 @@
# 7. Verify "volmode" behaves correctly at import time
# 8. Verify "volmode" behaves accordingly to zvol_inhibit_dev (Linux only)
#
-# NOTE: changing volmode may need to remove minors, which could be open, so call
-# block_device_wait() before we "zfs set volmode=<value>".
verify_runnable "global"
@@ -93,6 +91,21 @@ function test_io # dev
log_must dd if=/dev/zero of=$dev count=1
}
+#
+# Changing volmode may need to remove minors, which could be open, so call
+# udev_wait() before we "zfs set volmode=<value>". This ensures no udev
+# process has the zvol open (i.e. blkid) and the zvol_remove_minor_impl()
+# function won't skip removing the in use device.
+#
+function set_volmode # value ds
+{
+ typeset value="$1"
+ typeset ds="$2"
+
+ is_linux && udev_wait
+ log_must zfs set volmode="$value" "$ds"
+}
+
log_assert "Verify that ZFS volume property 'volmode' works as intended"
log_onexit cleanup
@@ -119,7 +132,7 @@ do
done
# 2. Verify "volmode=none" hides ZVOL device nodes
-log_must zfs set volmode=none $ZVOL
+set_volmode none $ZVOL
blockdev_missing $ZDEV
log_must_busy zfs destroy $ZVOL
blockdev_missing $ZDEV
@@ -127,12 +140,12 @@ blockdev_missing $ZDEV
# 3. Verify "volmode=full" exposes a fully functional device
log_must zfs create -V $VOLSIZE -s $ZVOL
blockdev_exists $ZDEV
-log_must zfs set volmode=full $ZVOL
+set_volmode full $ZVOL
blockdev_exists $ZDEV
test_io $ZDEV
log_must verify_partition $ZDEV
# 3.1 Verify "volmode=geom" is an alias for "volmode=full"
-log_must zfs set volmode=geom $ZVOL
+set_volmode geom $ZVOL
blockdev_exists $ZDEV
if [[ "$(get_prop 'volmode' $ZVOL)" != "full" ]]; then
log_fail " Volmode value 'geom' is not an alias for 'full'"
@@ -143,7 +156,7 @@ blockdev_missing $ZDEV
# 4. Verify "volmode=dev" hides partition info on the device
log_must zfs create -V $VOLSIZE -s $ZVOL
blockdev_exists $ZDEV
-log_must zfs set volmode=dev $ZVOL
+set_volmode dev $ZVOL
blockdev_exists $ZDEV
test_io $ZDEV
log_mustnot verify_partition $ZDEV
@@ -155,7 +168,7 @@ blockdev_missing $ZDEV
sysctl_volmode 1
log_must zfs create -V $VOLSIZE -s $ZVOL
blockdev_exists $ZDEV
-log_must zfs set volmode=default $ZVOL
+set_volmode default $ZVOL
blockdev_exists $ZDEV
log_must verify_partition $ZDEV
log_must_busy zfs destroy $ZVOL
@@ -164,7 +177,7 @@ blockdev_missing $ZDEV
sysctl_volmode 2
log_must zfs create -V $VOLSIZE -s $ZVOL
blockdev_exists $ZDEV
-log_must zfs set volmode=default $ZVOL
+set_volmode default $ZVOL
blockdev_exists $ZDEV
log_mustnot verify_partition $ZDEV
log_must_busy zfs destroy $ZVOL
@@ -173,33 +186,33 @@ blockdev_missing $ZDEV
sysctl_volmode 3
log_must zfs create -V $VOLSIZE -s $ZVOL
blockdev_missing $ZDEV
-log_must zfs set volmode=default $ZVOL
+set_volmode default $ZVOL
blockdev_missing $ZDEV
# 6. Verify "volmode" property is inherited correctly
log_must zfs inherit volmode $ZVOL
blockdev_missing $ZDEV
# 6.1 Check volmode=full case
-log_must zfs set volmode=full $TESTPOOL
+set_volmode full $TESTPOOL
verify_inherited 'volmode' 'full' $ZVOL $TESTPOOL
blockdev_exists $ZDEV
# 6.2 Check volmode=none case
-log_must zfs set volmode=none $TESTPOOL
+set_volmode none $TESTPOOL
verify_inherited 'volmode' 'none' $ZVOL $TESTPOOL
blockdev_missing $ZDEV
# 6.3 Check volmode=dev case
-log_must zfs set volmode=dev $TESTPOOL
+set_volmode dev $TESTPOOL
verify_inherited 'volmode' 'dev' $ZVOL $TESTPOOL
blockdev_exists $ZDEV
# 6.4 Check volmode=default case
sysctl_volmode 1
-log_must zfs set volmode=default $TESTPOOL
+set_volmode default $TESTPOOL
verify_inherited 'volmode' 'default' $ZVOL $TESTPOOL
blockdev_exists $ZDEV
# 6.5 Check inheritance on multiple levels
log_must zfs inherit volmode $SUBZVOL
-log_must zfs set volmode=none $VOLFS
-log_must zfs set volmode=full $TESTPOOL
+set_volmode none $VOLFS
+set_volmode full $TESTPOOL
verify_inherited 'volmode' 'none' $SUBZVOL $VOLFS
blockdev_missing $SUBZDEV
blockdev_exists $ZDEV
@@ -223,7 +236,7 @@ if is_linux; then
sysctl_volmode 1
log_must zfs create -V $VOLSIZE -s $ZVOL
blockdev_missing $ZDEV
- log_must zfs set volmode=full $ZVOL
+ set_volmode full $ZVOL
blockdev_missing $ZDEV
log_must_busy zfs destroy $ZVOL
blockdev_missing $ZDEV
@@ -231,7 +244,7 @@ if is_linux; then
sysctl_volmode 2
log_must zfs create -V $VOLSIZE -s $ZVOL
blockdev_missing $ZDEV
- log_must zfs set volmode=dev $ZVOL
+ set_volmode dev $ZVOL
blockdev_missing $ZDEV
log_must_busy zfs destroy $ZVOL
blockdev_missing $ZDEV
@@ -239,7 +252,7 @@ if is_linux; then
sysctl_volmode 3
log_must zfs create -V $VOLSIZE -s $ZVOL
blockdev_missing $ZDEV
- log_must zfs set volmode=none $ZVOL
+ set_volmode none $ZVOL
blockdev_missing $ZDEV
fi
diff --git a/sys/modules/zfs/Makefile b/sys/modules/zfs/Makefile
index d27e631b85fe..4d82554dae04 100644
--- a/sys/modules/zfs/Makefile
+++ b/sys/modules/zfs/Makefile
@@ -15,7 +15,9 @@ KMOD= zfs
${SRCDIR}/zcommon \
${SRCDIR}/zfs \
${SRCDIR}/zstd \
- ${SRCDIR}/zstd/lib
+ ${SRCDIR}/zstd/lib/common \
+ ${SRCDIR}/zstd/lib/compress \
+ ${SRCDIR}/zstd/lib/decompress
CFLAGS+= -I${INCDIR}
@@ -283,7 +285,28 @@ SRCS+= abd.c \
zvol.c
SRCS+= zfs_zstd.c \
- zstd.c
+ entropy_common.c \
+ error_private.c \
+ fse_compress.c \
+ fse_decompress.c \
+ hist.c \
+ huf_compress.c \
+ huf_decompress.c \
+ pool.c \
+ xxhash.c \
+ zstd_common.c \
+ zstd_compress.c \
+ zstd_compress_literals.c \
+ zstd_compress_sequences.c \
+ zstd_compress_superblock.c \
+ zstd_ddict.c \
+ zstd_decompress.c \
+ zstd_decompress_block.c \
+ zstd_double_fast.c \
+ zstd_fast.c \
+ zstd_lazy.c \
+ zstd_ldm.c \
+ zstd_opt.c
.include <bsd.kmod.mk>
@@ -342,8 +365,79 @@ CFLAGS.zil.c= -Wno-cast-qual
CFLAGS.zio.c= -Wno-cast-qual
CFLAGS.zrlock.c= -Wno-cast-qual
CFLAGS.zfs_zstd.c= -Wno-cast-qual -Wno-pointer-arith
+
CFLAGS.zstd.c= -U__BMI__ -fno-tree-vectorize
+CFLAGS.entropy_common.c= -U__BMI__ -fno-tree-vectorize
+CFLAGS.error_private.c= -U__BMI__ -fno-tree-vectorize
+CFLAGS.fse_compress.c= -U__BMI__ -fno-tree-vectorize
+CFLAGS.fse_decompress.c= -U__BMI__ -fno-tree-vectorize
+CFLAGS.hist.c= -U__BMI__ -fno-tree-vectorize
+CFLAGS.huf_compress.c= -U__BMI__ -fno-tree-vectorize
+CFLAGS.huf_decompress.c= -U__BMI__ -fno-tree-vectorize
+CFLAGS.pool.c= -U__BMI__ -fno-tree-vectorize
+CFLAGS.xxhash.c= -U__BMI__ -fno-tree-vectorize
+CFLAGS.zstd_common.c= -U__BMI__ -fno-tree-vectorize
+CFLAGS.std_compress.c= -U__BMI__ -fno-tree-vectorize
+CFLAGS.zstd_compress_literals.c= -U__BMI__ -fno-tree-vectorize
+CFLAGS.zstd_compress_sequences.c= -U__BMI__ -fno-tree-vectorize
+CFLAGS.zstd_compress_superblock.c= -U__BMI__ -fno-tree-vectorize
+CFLAGS.zstd_ddict.c= -U__BMI__ -fno-tree-vectorize
+CFLAGS.zstd_decompress.c= -U__BMI__ -fno-tree-vectorize
+CFLAGS.zstd_decompress_block.c= -U__BMI__ -fno-tree-vectorize
+CFLAGS.zstd_double_fast.c= -U__BMI__ -fno-tree-vectorize
+CFLAGS.zstd_fast.c= -U__BMI__ -fno-tree-vectorize
+CFLAGS.zstd_lazy.c= -U__BMI__ -fno-tree-vectorize
+CFLAGS.zstd_ldm.c= -U__BMI__ -fno-tree-vectorize
+CFLAGS.zstd_opt.c= -U__BMI__ -fno-tree-vectorize
+
.if ${MACHINE_CPUARCH} == "aarch64"
-CFLAGS.zstd.c+= -include ${SRCDIR}/zstd/include/aarch64_compat.h
+__ZFS_ZSTD_AARCH64_FLAGS= -include ${SRCDIR}/zstd/include/aarch64_compat.h
+CFLAGS.zstd.c+= ${__ZFS_ZSTD_AARCH64_FLAGS}
+CFLAGS.entropy_common.c+= ${__ZFS_ZSTD_AARCH64_FLAGS}
+CFLAGS.error_private.c+= ${__ZFS_ZSTD_AARCH64_FLAGS}
+CFLAGS.fse_compress.c+= ${__ZFS_ZSTD_AARCH64_FLAGS}
+CFLAGS.fse_decompress.c+= ${__ZFS_ZSTD_AARCH64_FLAGS}
+CFLAGS.hist.c+= ${__ZFS_ZSTD_AARCH64_FLAGS}
+CFLAGS.huf_compress.c+= ${__ZFS_ZSTD_AARCH64_FLAGS}
+CFLAGS.huf_decompress.c+= ${__ZFS_ZSTD_AARCH64_FLAGS}
+CFLAGS.pool.c+= ${__ZFS_ZSTD_AARCH64_FLAGS}
+CFLAGS.xxhash.c+= ${__ZFS_ZSTD_AARCH64_FLAGS}
+CFLAGS.zstd_common.c+= ${__ZFS_ZSTD_AARCH64_FLAGS}
+CFLAGS.zstd_compress.c+= ${__ZFS_ZSTD_AARCH64_FLAGS}
+CFLAGS.zstd_compress_literals.c+= ${__ZFS_ZSTD_AARCH64_FLAGS}
+CFLAGS.zstd_compress_sequences.c+= ${__ZFS_ZSTD_AARCH64_FLAGS}
+CFLAGS.zstd_compress_superblock.c+= ${__ZFS_ZSTD_AARCH64_FLAGS}
+CFLAGS.zstd_ddict.c+= ${__ZFS_ZSTD_AARCH64_FLAGS}
+CFLAGS.zstd_decompress.c+= ${__ZFS_ZSTD_AARCH64_FLAGS}
+CFLAGS.zstd_decompress_block.c+= ${__ZFS_ZSTD_AARCH64_FLAGS}
+CFLAGS.zstd_double_fast.c+= ${__ZFS_ZSTD_AARCH64_FLAGS}
+CFLAGS.zstd_fast.c+= ${__ZFS_ZSTD_AARCH64_FLAGS}
+CFLAGS.zstd_lazy.c+= ${__ZFS_ZSTD_AARCH64_FLAGS}
+CFLAGS.zstd_ldm.c+= ${__ZFS_ZSTD_AARCH64_FLAGS}
+CFLAGS.zstd_opt.c+= ${__ZFS_ZSTD_AARCH64_FLAGS}
+
.endif
CFLAGS.zstd.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.entropy_common.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.error_private.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.fse_compress.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.fse_decompress.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.hist.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.huf_compress.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.huf_decompress.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.pool.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.xxhash.c+= -include ${SRCTOP}/sys/sys/_null.h
+CFLAGS.xxhash.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_common.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_compress.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_compress_literals.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_compress_sequences.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_compress_superblock.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_ddict.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_decompress.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_decompress_block.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_double_fast.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_fast.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_lazy.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_ldm.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
+CFLAGS.zstd_opt.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}