mirror of
https://github.com/freebsd/freebsd-src.git
synced 2024-11-30 04:22:44 +00:00
zfs: merge openzfs/zfs@1c9a4c8cb
Some checks are pending
Cross-build Kernel / ${{ matrix.target_arch }} ${{ matrix.os }} (${{ matrix.compiler }}) (clang-14, /usr/lib/llvm-14/bin, ubuntu-22.04, bmake libarchive-dev clang-14 lld-14, amd64, amd64) (push) Waiting to run
Cross-build Kernel / ${{ matrix.target_arch }} ${{ matrix.os }} (${{ matrix.compiler }}) (clang-14, /usr/lib/llvm-14/bin, ubuntu-22.04, bmake libarchive-dev clang-14 lld-14, arm64, aarch64) (push) Waiting to run
Cross-build Kernel / ${{ matrix.target_arch }} ${{ matrix.os }} (${{ matrix.compiler }}) (clang-18, /opt/homebrew/opt/llvm@18/bin, macos-latest, bmake libarchive llvm@18, amd64, amd64) (push) Waiting to run
Cross-build Kernel / ${{ matrix.target_arch }} ${{ matrix.os }} (${{ matrix.compiler }}) (clang-18, /opt/homebrew/opt/llvm@18/bin, macos-latest, bmake libarchive llvm@18, arm64, aarch64) (push) Waiting to run
Cross-build Kernel / ${{ matrix.target_arch }} ${{ matrix.os }} (${{ matrix.compiler }}) (clang-18, /usr/lib/llvm-18/bin, ubuntu-24.04, bmake libarchive-dev clang-18 lld-18, amd64, amd64) (push) Waiting to run
Cross-build Kernel / ${{ matrix.target_arch }} ${{ matrix.os }} (${{ matrix.compiler }}) (clang-18, /usr/lib/llvm-18/bin, ubuntu-24.04, bmake libarchive-dev clang-18 lld-18, arm64, aarch64) (push) Waiting to run
Some checks are pending
Cross-build Kernel / ${{ matrix.target_arch }} ${{ matrix.os }} (${{ matrix.compiler }}) (clang-14, /usr/lib/llvm-14/bin, ubuntu-22.04, bmake libarchive-dev clang-14 lld-14, amd64, amd64) (push) Waiting to run
Cross-build Kernel / ${{ matrix.target_arch }} ${{ matrix.os }} (${{ matrix.compiler }}) (clang-14, /usr/lib/llvm-14/bin, ubuntu-22.04, bmake libarchive-dev clang-14 lld-14, arm64, aarch64) (push) Waiting to run
Cross-build Kernel / ${{ matrix.target_arch }} ${{ matrix.os }} (${{ matrix.compiler }}) (clang-18, /opt/homebrew/opt/llvm@18/bin, macos-latest, bmake libarchive llvm@18, amd64, amd64) (push) Waiting to run
Cross-build Kernel / ${{ matrix.target_arch }} ${{ matrix.os }} (${{ matrix.compiler }}) (clang-18, /opt/homebrew/opt/llvm@18/bin, macos-latest, bmake libarchive llvm@18, arm64, aarch64) (push) Waiting to run
Cross-build Kernel / ${{ matrix.target_arch }} ${{ matrix.os }} (${{ matrix.compiler }}) (clang-18, /usr/lib/llvm-18/bin, ubuntu-24.04, bmake libarchive-dev clang-18 lld-18, amd64, amd64) (push) Waiting to run
Cross-build Kernel / ${{ matrix.target_arch }} ${{ matrix.os }} (${{ matrix.compiler }}) (clang-18, /usr/lib/llvm-18/bin, ubuntu-24.04, bmake libarchive-dev clang-18 lld-18, arm64, aarch64) (push) Waiting to run
Notable upstream pull request merges: #16244acb6e71ed
Added output to `zpool online` and `offline` #1668494a03dd1e
Pack dmu_buf_impl_t by 16 bytes #166906187b1943
On the first vdev open ignore impossible ashift hints #16692673efbbf5
zdb: add extra -T flag to show histograms of BRT refcounts #166932bf152021
Fix gcc uninitialized warning in FreeBSD zio_crypt.c #16694b16e09619
Reduce dirty records memory usage #167015945676bc
ZFS send should use spill block prefetched from send_reader_thread #167341c9a4c8cb
Fix user properties output for zpool list Obtained from: OpenZFS OpenZFS commit:1c9a4c8cb4
This commit is contained in:
commit
5c65a0a916
@ -248,7 +248,7 @@ LUA_C = \
|
||||
lvm.c \
|
||||
lzio.c
|
||||
|
||||
UNICODE_C = u8_textprep.c uconv.c
|
||||
UNICODE_C = u8_textprep.c
|
||||
|
||||
SRCS+= ${USER_C} ${KERNEL_C} ${LUA_C} ${UNICODE_C} ${ARCH_C}
|
||||
|
||||
|
@ -225,7 +225,6 @@ contrib/openzfs/module/os/freebsd/zfs/zio_crypt.c optional zfs compile-with "${
|
||||
contrib/openzfs/module/os/freebsd/zfs/zvol_os.c optional zfs compile-with "${ZFS_C}"
|
||||
|
||||
#zfs unicode support
|
||||
contrib/openzfs/module/unicode/uconv.c optional zfs compile-with "${ZFS_C}"
|
||||
contrib/openzfs/module/unicode/u8_textprep.c optional zfs compile-with "${ZFS_C}"
|
||||
|
||||
#zfs checksums / zcommon
|
||||
|
49
sys/contrib/openzfs/.github/workflows/labels.yml
vendored
Normal file
49
sys/contrib/openzfs/.github/workflows/labels.yml
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
name: labels
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [ opened, synchronize, reopened, converted_to_draft, ready_for_review ]
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
open:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.action == 'opened' && github.event.pull_request.draft }}
|
||||
steps:
|
||||
- env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
ISSUE: ${{ github.event.pull_request.html_url }}
|
||||
run: |
|
||||
gh pr edit $ISSUE --add-label "Status: Work in Progress"
|
||||
|
||||
push:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.action == 'synchronize' || github.event.action == 'reopened' }}
|
||||
steps:
|
||||
- env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
ISSUE: ${{ github.event.pull_request.html_url }}
|
||||
run: |
|
||||
gh pr edit $ISSUE --remove-label "Status: Accepted,Status: Inactive,Status: Revision Needed,Status: Stale"
|
||||
|
||||
draft:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.action == 'converted_to_draft' }}
|
||||
steps:
|
||||
- env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
ISSUE: ${{ github.event.pull_request.html_url }}
|
||||
run: |
|
||||
gh pr edit $ISSUE --remove-label "Status: Accepted,Status: Code Review Needed,Status: Inactive,Status: Revision Needed,Status: Stale" --add-label "Status: Work in Progress"
|
||||
|
||||
rfr:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.action == 'ready_for_review' }}
|
||||
steps:
|
||||
- env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
ISSUE: ${{ github.event.pull_request.html_url }}
|
||||
run: |
|
||||
gh pr edit $ISSUE --remove-label "Status: Accepted,Status: Inactive,Status: Revision Needed,Status: Stale,Status: Work in Progress" --add-label "Status: Code Review Needed"
|
@ -52,16 +52,16 @@ case "$OS" in
|
||||
OSNAME="Debian 12"
|
||||
URL="https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-generic-amd64.qcow2"
|
||||
;;
|
||||
fedora39)
|
||||
OSNAME="Fedora 39"
|
||||
OSv="fedora39"
|
||||
URL="https://download.fedoraproject.org/pub/fedora/linux/releases/39/Cloud/x86_64/images/Fedora-Cloud-Base-39-1.5.x86_64.qcow2"
|
||||
;;
|
||||
fedora40)
|
||||
OSNAME="Fedora 40"
|
||||
OSv="fedora39"
|
||||
OSv="fedora-unknown"
|
||||
URL="https://download.fedoraproject.org/pub/fedora/linux/releases/40/Cloud/x86_64/images/Fedora-Cloud-Base-Generic.x86_64-40-1.14.qcow2"
|
||||
;;
|
||||
fedora41)
|
||||
OSNAME="Fedora 41"
|
||||
OSv="fedora-unknown"
|
||||
URL="https://download.fedoraproject.org/pub/fedora/linux/releases/41/Cloud/x86_64/images/Fedora-Cloud-Base-Generic-41-1.4.x86_64.qcow2"
|
||||
;;
|
||||
freebsd13-3r)
|
||||
OSNAME="FreeBSD 13.3-RELEASE"
|
||||
OSv="freebsd13.0"
|
||||
|
@ -13,10 +13,10 @@ function archlinux() {
|
||||
echo "##[endgroup]"
|
||||
|
||||
echo "##[group]Install Development Tools"
|
||||
sudo pacman -Sy --noconfirm base-devel bc cpio dhclient dkms fakeroot \
|
||||
fio gdb inetutils jq less linux linux-headers lsscsi nfs-utils parted \
|
||||
pax perf python-packaging python-setuptools qemu-guest-agent ksh samba \
|
||||
sysstat rng-tools rsync wget xxhash
|
||||
sudo pacman -Sy --noconfirm base-devel bc cpio cryptsetup dhclient dkms \
|
||||
fakeroot fio gdb inetutils jq less linux linux-headers lsscsi nfs-utils \
|
||||
parted pax perf python-packaging python-setuptools qemu-guest-agent ksh \
|
||||
samba sysstat rng-tools rsync wget xxhash
|
||||
echo "##[endgroup]"
|
||||
}
|
||||
|
||||
@ -30,11 +30,11 @@ function debian() {
|
||||
|
||||
echo "##[group]Install Development Tools"
|
||||
sudo apt-get install -y \
|
||||
acl alien attr autoconf bc cpio curl dbench dh-python dkms fakeroot \
|
||||
fio gdb gdebi git ksh lcov isc-dhcp-client jq 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 \
|
||||
libtool-bin libudev-dev libunwind-dev linux-headers-$(uname -r) \
|
||||
acl alien attr autoconf bc cpio cryptsetup curl dbench dh-python dkms \
|
||||
fakeroot fio gdb gdebi git ksh lcov isc-dhcp-client jq 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 libtool-bin libudev-dev libunwind-dev linux-headers-$(uname -r) \
|
||||
lsscsi nfs-kernel-server pamtester parted python3 python3-all-dev \
|
||||
python3-cffi python3-dev python3-distlib python3-packaging \
|
||||
python3-setuptools python3-sphinx qemu-guest-agent rng-tools rpm2cpio \
|
||||
@ -66,16 +66,23 @@ function rhel() {
|
||||
echo "##[endgroup]"
|
||||
|
||||
echo "##[group]Install Development Tools"
|
||||
sudo dnf group install -y "Development Tools"
|
||||
|
||||
# Alma wants "Development Tools", Fedora 41 wants "development-tools"
|
||||
if ! sudo dnf group install -y "Development Tools" ; then
|
||||
echo "Trying 'development-tools' instead of 'Development Tools'"
|
||||
sudo dnf group install -y development-tools
|
||||
fi
|
||||
|
||||
sudo dnf install -y \
|
||||
acl attr bc bzip2 curl dbench dkms elfutils-libelf-devel fio gdb git \
|
||||
jq kernel-rpm-macros ksh libacl-devel libaio-devel libargon2-devel \
|
||||
libattr-devel libblkid-devel libcurl-devel libffi-devel ncompress \
|
||||
libselinux-devel libtirpc-devel libtool libudev-devel libuuid-devel \
|
||||
lsscsi mdadm nfs-utils openssl-devel pam-devel pamtester parted perf \
|
||||
python3 python3-cffi python3-devel python3-packaging kernel-devel \
|
||||
python3-setuptools qemu-guest-agent rng-tools rpcgen rpm-build rsync \
|
||||
samba sysstat systemd watchdog wget xfsprogs-devel xxhash zlib-devel
|
||||
acl attr bc bzip2 cryptsetup curl dbench dkms elfutils-libelf-devel fio \
|
||||
gdb git jq kernel-rpm-macros ksh libacl-devel libaio-devel \
|
||||
libargon2-devel libattr-devel libblkid-devel libcurl-devel libffi-devel \
|
||||
ncompress libselinux-devel libtirpc-devel libtool libudev-devel \
|
||||
libuuid-devel lsscsi mdadm nfs-utils openssl-devel pam-devel pamtester \
|
||||
parted perf python3 python3-cffi python3-devel python3-packaging \
|
||||
kernel-devel python3-setuptools qemu-guest-agent rng-tools rpcgen \
|
||||
rpm-build rsync samba sysstat systemd watchdog wget xfsprogs-devel xxhash \
|
||||
zlib-devel
|
||||
echo "##[endgroup]"
|
||||
}
|
||||
|
||||
@ -111,6 +118,7 @@ case "$1" in
|
||||
archlinux
|
||||
;;
|
||||
debian*)
|
||||
echo 'debconf debconf/frontend select Noninteractive' | sudo debconf-set-selections
|
||||
debian
|
||||
echo "##[group]Install Debian specific"
|
||||
sudo apt-get install -yq linux-perf dh-sequence-dkms
|
||||
|
@ -83,7 +83,7 @@ function rpm_build_and_install() {
|
||||
echo "##[endgroup]"
|
||||
|
||||
echo "##[group]Install"
|
||||
run sudo dnf -y --skip-broken localinstall $(ls *.rpm | grep -v src.rpm)
|
||||
run sudo dnf -y --nobest install $(ls *.rpm | grep -v src.rpm)
|
||||
echo "##[endgroup]"
|
||||
|
||||
}
|
||||
|
@ -22,8 +22,8 @@ jobs:
|
||||
- name: Generate OS config and CI type
|
||||
id: os
|
||||
run: |
|
||||
FULL_OS='["almalinux8", "almalinux9", "centos-stream9", "debian11", "debian12", "fedora39", "fedora40", "freebsd13-4r", "freebsd14-0r", "freebsd14-1s", "ubuntu20", "ubuntu22", "ubuntu24"]'
|
||||
QUICK_OS='["almalinux8", "almalinux9", "debian12", "fedora40", "freebsd13-3r", "freebsd14-1r", "ubuntu24"]'
|
||||
FULL_OS='["almalinux8", "almalinux9", "centos-stream9", "debian11", "debian12", "fedora40", "fedora41", "freebsd13-4r", "freebsd14-0r", "freebsd14-1s", "ubuntu20", "ubuntu22", "ubuntu24"]'
|
||||
QUICK_OS='["almalinux8", "almalinux9", "debian12", "fedora41", "freebsd13-3r", "freebsd14-1r", "ubuntu24"]'
|
||||
# determine CI type when running on PR
|
||||
ci_type="full"
|
||||
if ${{ github.event_name == 'pull_request' }}; then
|
||||
@ -46,7 +46,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# rhl: almalinux8, almalinux9, centos-stream9, fedora39, fedora40
|
||||
# rhl: almalinux8, almalinux9, centos-stream9, fedora40, fedora41
|
||||
# debian: debian11, debian12, ubuntu20, ubuntu22, ubuntu24
|
||||
# misc: archlinux, tumbleweed
|
||||
# FreeBSD Release: freebsd13-3r, freebsd13-4r, freebsd14-0r, freebsd14-1r
|
||||
|
@ -2152,7 +2152,12 @@ dump_brt(spa_t *spa)
|
||||
if (dump_opt['T'] < 3)
|
||||
return;
|
||||
|
||||
/* -TTT shows a per-vdev histograms; -TTTT shows all entries */
|
||||
boolean_t do_histo = dump_opt['T'] == 3;
|
||||
|
||||
char dva[64];
|
||||
|
||||
if (!do_histo)
|
||||
printf("\n%-16s %-10s\n", "DVA", "REFCNT");
|
||||
|
||||
for (uint64_t vdevid = 0; vdevid < brt->brt_nvdevs; vdevid++) {
|
||||
@ -2160,6 +2165,8 @@ dump_brt(spa_t *spa)
|
||||
if (brtvd == NULL || !brtvd->bv_initiated)
|
||||
continue;
|
||||
|
||||
uint64_t counts[64] = {};
|
||||
|
||||
zap_cursor_t zc;
|
||||
zap_attribute_t *za = zap_attribute_alloc();
|
||||
for (zap_cursor_init(&zc, brt->brt_mos, brtvd->bv_mos_entries);
|
||||
@ -2172,14 +2179,26 @@ dump_brt(spa_t *spa)
|
||||
za->za_integer_length, za->za_num_integers,
|
||||
&refcnt));
|
||||
|
||||
uint64_t offset = *(const uint64_t *)za->za_name;
|
||||
if (do_histo)
|
||||
counts[highbit64(refcnt)]++;
|
||||
else {
|
||||
uint64_t offset =
|
||||
*(const uint64_t *)za->za_name;
|
||||
|
||||
snprintf(dva, sizeof (dva), "%" PRIu64 ":%llx", vdevid,
|
||||
(u_longlong_t)offset);
|
||||
printf("%-16s %-10llu\n", dva, (u_longlong_t)refcnt);
|
||||
snprintf(dva, sizeof (dva), "%" PRIu64 ":%llx",
|
||||
vdevid, (u_longlong_t)offset);
|
||||
printf("%-16s %-10llu\n", dva,
|
||||
(u_longlong_t)refcnt);
|
||||
}
|
||||
}
|
||||
zap_cursor_fini(&zc);
|
||||
zap_attribute_free(za);
|
||||
|
||||
if (do_histo) {
|
||||
printf("\nBRT: vdev %" PRIu64
|
||||
": DVAs with 2^n refcnts:\n", vdevid);
|
||||
dump_histogram(counts, 64, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,7 +139,8 @@ dev_event_nvlist(struct udev_device *dev)
|
||||
* is /dev/sda.
|
||||
*/
|
||||
struct udev_device *parent_dev = udev_device_get_parent(dev);
|
||||
if ((value = udev_device_get_sysattr_value(parent_dev, "size"))
|
||||
if (parent_dev != NULL &&
|
||||
(value = udev_device_get_sysattr_value(parent_dev, "size"))
|
||||
!= NULL) {
|
||||
uint64_t numval = DEV_BSIZE;
|
||||
|
||||
|
@ -3761,8 +3761,13 @@ collect_dataset(zfs_handle_t *zhp, list_cbdata_t *cb)
|
||||
if (cb->cb_json) {
|
||||
if (pl->pl_prop == ZFS_PROP_NAME)
|
||||
continue;
|
||||
const char *prop_name;
|
||||
if (pl->pl_prop != ZPROP_USERPROP)
|
||||
prop_name = zfs_prop_to_name(pl->pl_prop);
|
||||
else
|
||||
prop_name = pl->pl_user_prop;
|
||||
if (zprop_nvlist_one_property(
|
||||
zfs_prop_to_name(pl->pl_prop), propstr,
|
||||
prop_name, propstr,
|
||||
sourcetype, source, NULL, props,
|
||||
cb->cb_json_as_int) != 0)
|
||||
nomem();
|
||||
|
@ -6882,8 +6882,13 @@ collect_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
|
||||
if (cb->cb_json) {
|
||||
if (pl->pl_prop == ZPOOL_PROP_NAME)
|
||||
continue;
|
||||
const char *prop_name;
|
||||
if (pl->pl_prop != ZPROP_USERPROP)
|
||||
prop_name = zpool_prop_to_name(pl->pl_prop);
|
||||
else
|
||||
prop_name = pl->pl_user_prop;
|
||||
(void) zprop_nvlist_one_property(
|
||||
zpool_prop_to_name(pl->pl_prop), propstr,
|
||||
prop_name, propstr,
|
||||
sourcetype, NULL, NULL, props, cb->cb_json_as_int);
|
||||
} else {
|
||||
/*
|
||||
@ -7966,8 +7971,11 @@ zpool_do_online(int argc, char **argv)
|
||||
|
||||
poolname = argv[0];
|
||||
|
||||
if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
|
||||
if ((zhp = zpool_open(g_zfs, poolname)) == NULL) {
|
||||
(void) fprintf(stderr, gettext("failed to open pool "
|
||||
"\"%s\""), poolname);
|
||||
return (1);
|
||||
}
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
vdev_state_t oldstate;
|
||||
@ -7988,12 +7996,15 @@ zpool_do_online(int argc, char **argv)
|
||||
&l2cache, NULL);
|
||||
if (tgt == NULL) {
|
||||
ret = 1;
|
||||
(void) fprintf(stderr, gettext("couldn't find device "
|
||||
"\"%s\" in pool \"%s\"\n"), argv[i], poolname);
|
||||
continue;
|
||||
}
|
||||
uint_t vsc;
|
||||
oldstate = ((vdev_stat_t *)fnvlist_lookup_uint64_array(tgt,
|
||||
ZPOOL_CONFIG_VDEV_STATS, &vsc))->vs_state;
|
||||
if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) {
|
||||
if ((rc = zpool_vdev_online(zhp, argv[i], flags,
|
||||
&newstate)) == 0) {
|
||||
if (newstate != VDEV_STATE_HEALTHY) {
|
||||
(void) printf(gettext("warning: device '%s' "
|
||||
"onlined, but remains in faulted state\n"),
|
||||
@ -8019,6 +8030,9 @@ zpool_do_online(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
(void) fprintf(stderr, gettext("Failed to online "
|
||||
"\"%s\" in pool \"%s\": %d\n"),
|
||||
argv[i], poolname, rc);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
@ -8103,8 +8117,11 @@ zpool_do_offline(int argc, char **argv)
|
||||
|
||||
poolname = argv[0];
|
||||
|
||||
if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
|
||||
if ((zhp = zpool_open(g_zfs, poolname)) == NULL) {
|
||||
(void) fprintf(stderr, gettext("failed to open pool "
|
||||
"\"%s\""), poolname);
|
||||
return (1);
|
||||
}
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
uint64_t guid = zpool_vdev_path_to_guid(zhp, argv[i]);
|
||||
|
@ -17,14 +17,21 @@ AC_DEFUN([ZFS_AC_KERNEL_KTHREAD_COMPLETE_AND_EXIT], [
|
||||
|
||||
AC_DEFUN([ZFS_AC_KERNEL_KTHREAD_DEQUEUE_SIGNAL], [
|
||||
dnl #
|
||||
dnl # 5.17 API: enum pid_type * as new 4th dequeue_signal() argument,
|
||||
dnl # 5768d8906bc23d512b1a736c1e198aa833a6daa4 ("signal: Requeue signals in the appropriate queue")
|
||||
dnl # prehistory:
|
||||
dnl # int dequeue_signal(struct task_struct *task, sigset_t *mask,
|
||||
dnl # siginfo_t *info)
|
||||
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 # 4.20: kernel_siginfo_t introduced, replaces siginfo_t
|
||||
dnl # int dequeue_signal(struct task_struct *task, sigset_t *mask,
|
||||
dnl kernel_siginfo_t *info)
|
||||
dnl #
|
||||
dnl # 6.12 API: first arg struct_task* removed
|
||||
dnl # int dequeue_signal(sigset_t *mask, kernel_siginfo_t *info, enum pid_type *type);
|
||||
dnl # 5.17: enum pid_type introduced as 4th arg
|
||||
dnl # int dequeue_signal(struct task_struct *task, sigset_t *mask,
|
||||
dnl # kernel_siginfo_t *info, enum pid_type *type)
|
||||
dnl #
|
||||
dnl # 6.12: first arg struct_task* removed
|
||||
dnl # int dequeue_signal(sigset_t *mask, kernel_siginfo_t *info,
|
||||
dnl # enum pid_type *type)
|
||||
dnl #
|
||||
AC_MSG_CHECKING([whether dequeue_signal() takes 4 arguments])
|
||||
ZFS_LINUX_TEST_RESULT([kthread_dequeue_signal_4arg], [
|
||||
@ -33,11 +40,11 @@ AC_DEFUN([ZFS_AC_KERNEL_KTHREAD_DEQUEUE_SIGNAL], [
|
||||
[dequeue_signal() takes 4 arguments])
|
||||
], [
|
||||
AC_MSG_RESULT(no)
|
||||
AC_MSG_CHECKING([whether dequeue_signal() a task argument])
|
||||
ZFS_LINUX_TEST_RESULT([kthread_dequeue_signal_3arg_task], [
|
||||
AC_MSG_CHECKING([whether 3-arg dequeue_signal() takes a type argument])
|
||||
ZFS_LINUX_TEST_RESULT([kthread_dequeue_signal_3arg_type], [
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_DEQUEUE_SIGNAL_3ARG_TASK, 1,
|
||||
[dequeue_signal() takes a task argument])
|
||||
AC_DEFINE(HAVE_DEQUEUE_SIGNAL_3ARG_TYPE, 1,
|
||||
[3-arg dequeue_signal() takes a type argument])
|
||||
], [
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
@ -56,17 +63,6 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_KTHREAD_COMPLETE_AND_EXIT], [
|
||||
])
|
||||
|
||||
AC_DEFUN([ZFS_AC_KERNEL_SRC_KTHREAD_DEQUEUE_SIGNAL], [
|
||||
ZFS_LINUX_TEST_SRC([kthread_dequeue_signal_3arg_task], [
|
||||
#include <linux/sched/signal.h>
|
||||
], [
|
||||
struct task_struct *task = NULL;
|
||||
sigset_t *mask = NULL;
|
||||
kernel_siginfo_t *info = NULL;
|
||||
int error __attribute__ ((unused));
|
||||
|
||||
error = dequeue_signal(task, mask, info);
|
||||
])
|
||||
|
||||
ZFS_LINUX_TEST_SRC([kthread_dequeue_signal_4arg], [
|
||||
#include <linux/sched/signal.h>
|
||||
], [
|
||||
@ -78,6 +74,17 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_KTHREAD_DEQUEUE_SIGNAL], [
|
||||
|
||||
error = dequeue_signal(task, mask, info, type);
|
||||
])
|
||||
|
||||
ZFS_LINUX_TEST_SRC([kthread_dequeue_signal_3arg_type], [
|
||||
#include <linux/sched/signal.h>
|
||||
], [
|
||||
sigset_t *mask = NULL;
|
||||
kernel_siginfo_t *info = NULL;
|
||||
enum pid_type *type = NULL;
|
||||
int error __attribute__ ((unused));
|
||||
|
||||
error = dequeue_signal(mask, info, type);
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([ZFS_AC_KERNEL_KTHREAD], [
|
||||
|
@ -1,33 +0,0 @@
|
||||
dnl #
|
||||
dnl # Linux 5.18 uses invalidate_folio in lieu of invalidate_page
|
||||
dnl #
|
||||
AC_DEFUN([ZFS_AC_KERNEL_SRC_VFS_INVALIDATE_FOLIO], [
|
||||
ZFS_LINUX_TEST_SRC([vfs_has_invalidate_folio], [
|
||||
#include <linux/fs.h>
|
||||
|
||||
static void
|
||||
test_invalidate_folio(struct folio *folio, size_t offset,
|
||||
size_t len) {
|
||||
(void) folio; (void) offset; (void) len;
|
||||
return;
|
||||
}
|
||||
|
||||
static const struct address_space_operations
|
||||
aops __attribute__ ((unused)) = {
|
||||
.invalidate_folio = test_invalidate_folio,
|
||||
};
|
||||
],[])
|
||||
])
|
||||
|
||||
AC_DEFUN([ZFS_AC_KERNEL_VFS_INVALIDATE_FOLIO], [
|
||||
dnl #
|
||||
dnl # Linux 5.18 uses invalidate_folio in lieu of invalidate_page
|
||||
dnl #
|
||||
AC_MSG_CHECKING([whether invalidate_folio exists])
|
||||
ZFS_LINUX_TEST_RESULT([vfs_has_invalidate_folio], [
|
||||
AC_MSG_RESULT([yes])
|
||||
AC_DEFINE(HAVE_VFS_INVALIDATE_FOLIO, 1, [invalidate_folio exists])
|
||||
],[
|
||||
AC_MSG_RESULT([no])
|
||||
])
|
||||
])
|
27
sys/contrib/openzfs/config/kernel-vfs-migrate_folio.m4
Normal file
27
sys/contrib/openzfs/config/kernel-vfs-migrate_folio.m4
Normal file
@ -0,0 +1,27 @@
|
||||
dnl #
|
||||
dnl # Linux 6.0 uses migrate_folio in lieu of migrate_page
|
||||
dnl #
|
||||
AC_DEFUN([ZFS_AC_KERNEL_SRC_VFS_MIGRATE_FOLIO], [
|
||||
ZFS_LINUX_TEST_SRC([vfs_has_migrate_folio], [
|
||||
#include <linux/fs.h>
|
||||
#include <linux/migrate.h>
|
||||
|
||||
static const struct address_space_operations
|
||||
aops __attribute__ ((unused)) = {
|
||||
.migrate_folio = migrate_folio,
|
||||
};
|
||||
],[])
|
||||
])
|
||||
|
||||
AC_DEFUN([ZFS_AC_KERNEL_VFS_MIGRATE_FOLIO], [
|
||||
dnl #
|
||||
dnl # Linux 6.0 uses migrate_folio in lieu of migrate_page
|
||||
dnl #
|
||||
AC_MSG_CHECKING([whether migrate_folio exists])
|
||||
ZFS_LINUX_TEST_RESULT([vfs_has_migrate_folio], [
|
||||
AC_MSG_RESULT([yes])
|
||||
AC_DEFINE(HAVE_VFS_MIGRATE_FOLIO, 1, [migrate_folio exists])
|
||||
],[
|
||||
AC_MSG_RESULT([no])
|
||||
])
|
||||
])
|
@ -1,32 +0,0 @@
|
||||
dnl #
|
||||
dnl # Linux 5.19 uses release_folio in lieu of releasepage
|
||||
dnl #
|
||||
AC_DEFUN([ZFS_AC_KERNEL_SRC_VFS_RELEASE_FOLIO], [
|
||||
ZFS_LINUX_TEST_SRC([vfs_has_release_folio], [
|
||||
#include <linux/fs.h>
|
||||
|
||||
static bool
|
||||
test_release_folio(struct folio *folio, gfp_t gfp) {
|
||||
(void) folio; (void) gfp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static const struct address_space_operations
|
||||
aops __attribute__ ((unused)) = {
|
||||
.release_folio = test_release_folio,
|
||||
};
|
||||
],[])
|
||||
])
|
||||
|
||||
AC_DEFUN([ZFS_AC_KERNEL_VFS_RELEASE_FOLIO], [
|
||||
dnl #
|
||||
dnl # Linux 5.19 uses release_folio in lieu of releasepage
|
||||
dnl #
|
||||
AC_MSG_CHECKING([whether release_folio exists])
|
||||
ZFS_LINUX_TEST_RESULT([vfs_has_release_folio], [
|
||||
AC_MSG_RESULT([yes])
|
||||
AC_DEFINE(HAVE_VFS_RELEASE_FOLIO, 1, [release_folio exists])
|
||||
],[
|
||||
AC_MSG_RESULT([no])
|
||||
])
|
||||
])
|
@ -77,8 +77,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
|
||||
ZFS_AC_KERNEL_SRC_SGET
|
||||
ZFS_AC_KERNEL_SRC_VFS_FILEMAP_DIRTY_FOLIO
|
||||
ZFS_AC_KERNEL_SRC_VFS_READ_FOLIO
|
||||
ZFS_AC_KERNEL_SRC_VFS_RELEASE_FOLIO
|
||||
ZFS_AC_KERNEL_SRC_VFS_INVALIDATE_FOLIO
|
||||
ZFS_AC_KERNEL_SRC_VFS_MIGRATE_FOLIO
|
||||
ZFS_AC_KERNEL_SRC_VFS_FSYNC_2ARGS
|
||||
ZFS_AC_KERNEL_SRC_VFS_DIRECT_IO
|
||||
ZFS_AC_KERNEL_SRC_VFS_READPAGES
|
||||
@ -189,8 +188,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
|
||||
ZFS_AC_KERNEL_SGET
|
||||
ZFS_AC_KERNEL_VFS_FILEMAP_DIRTY_FOLIO
|
||||
ZFS_AC_KERNEL_VFS_READ_FOLIO
|
||||
ZFS_AC_KERNEL_VFS_RELEASE_FOLIO
|
||||
ZFS_AC_KERNEL_VFS_INVALIDATE_FOLIO
|
||||
ZFS_AC_KERNEL_VFS_MIGRATE_FOLIO
|
||||
ZFS_AC_KERNEL_VFS_FSYNC_2ARGS
|
||||
ZFS_AC_KERNEL_VFS_DIRECT_IO
|
||||
ZFS_AC_KERNEL_VFS_READPAGES
|
||||
|
@ -42,7 +42,7 @@
|
||||
#define TS_ZOMB EXIT_ZOMBIE
|
||||
#define TS_STOPPED TASK_STOPPED
|
||||
|
||||
typedef void (*thread_func_t)(void *);
|
||||
typedef void (*thread_func_t)(void *) __attribute__((noreturn));
|
||||
|
||||
#define thread_create_named(name, stk, stksize, func, arg, len, \
|
||||
pp, state, pri) \
|
||||
|
@ -171,7 +171,6 @@ typedef struct dbuf_dirty_record {
|
||||
* gets COW'd in a subsequent transaction group.
|
||||
*/
|
||||
arc_buf_t *dr_data;
|
||||
blkptr_t dr_overridden_by;
|
||||
override_states_t dr_override_state;
|
||||
uint8_t dr_copies;
|
||||
boolean_t dr_nopwrite;
|
||||
@ -179,14 +178,21 @@ typedef struct dbuf_dirty_record {
|
||||
boolean_t dr_diowrite;
|
||||
boolean_t dr_has_raw_params;
|
||||
|
||||
/* Override and raw params are mutually exclusive. */
|
||||
union {
|
||||
blkptr_t dr_overridden_by;
|
||||
struct {
|
||||
/*
|
||||
* If dr_has_raw_params is set, the following crypt
|
||||
* params will be set on the BP that's written.
|
||||
* If dr_has_raw_params is set, the
|
||||
* following crypt params will be set
|
||||
* on the BP that's written.
|
||||
*/
|
||||
boolean_t dr_byteorder;
|
||||
uint8_t dr_salt[ZIO_DATA_SALT_LEN];
|
||||
uint8_t dr_iv[ZIO_DATA_IV_LEN];
|
||||
uint8_t dr_mac[ZIO_DATA_MAC_LEN];
|
||||
};
|
||||
};
|
||||
} dl;
|
||||
struct dirty_lightweight_leaf {
|
||||
/*
|
||||
@ -264,6 +270,27 @@ typedef struct dmu_buf_impl {
|
||||
*/
|
||||
uint8_t db_level;
|
||||
|
||||
/* This block was freed while a read or write was active. */
|
||||
uint8_t db_freed_in_flight;
|
||||
|
||||
/*
|
||||
* Evict user data as soon as the dirty and reference counts are equal.
|
||||
*/
|
||||
uint8_t db_user_immediate_evict;
|
||||
|
||||
/*
|
||||
* dnode_evict_dbufs() or dnode_evict_bonus() tried to evict this dbuf,
|
||||
* but couldn't due to outstanding references. Evict once the refcount
|
||||
* drops to 0.
|
||||
*/
|
||||
uint8_t db_pending_evict;
|
||||
|
||||
/* Number of TXGs in which this buffer is dirty. */
|
||||
uint8_t db_dirtycnt;
|
||||
|
||||
/* The buffer was partially read. More reads may follow. */
|
||||
uint8_t db_partial_read;
|
||||
|
||||
/*
|
||||
* Protects db_buf's contents if they contain an indirect block or data
|
||||
* block of the meta-dnode. We use this lock to protect the structure of
|
||||
@ -288,6 +315,9 @@ typedef struct dmu_buf_impl {
|
||||
*/
|
||||
dbuf_states_t db_state;
|
||||
|
||||
/* In which dbuf cache this dbuf is, if any. */
|
||||
dbuf_cached_state_t db_caching_status;
|
||||
|
||||
/*
|
||||
* Refcount accessed by dmu_buf_{hold,rele}.
|
||||
* If nonzero, the buffer can't be destroyed.
|
||||
@ -304,39 +334,10 @@ typedef struct dmu_buf_impl {
|
||||
/* Link in dbuf_cache or dbuf_metadata_cache */
|
||||
multilist_node_t db_cache_link;
|
||||
|
||||
/* Tells us which dbuf cache this dbuf is in, if any */
|
||||
dbuf_cached_state_t db_caching_status;
|
||||
|
||||
uint64_t db_hash;
|
||||
|
||||
/* Data which is unique to data (leaf) blocks: */
|
||||
|
||||
/* User callback information. */
|
||||
dmu_buf_user_t *db_user;
|
||||
|
||||
/*
|
||||
* Evict user data as soon as the dirty and reference
|
||||
* counts are equal.
|
||||
*/
|
||||
uint8_t db_user_immediate_evict;
|
||||
|
||||
/*
|
||||
* This block was freed while a read or write was
|
||||
* active.
|
||||
*/
|
||||
uint8_t db_freed_in_flight;
|
||||
|
||||
/*
|
||||
* dnode_evict_dbufs() or dnode_evict_bonus() tried to
|
||||
* evict this dbuf, but couldn't due to outstanding
|
||||
* references. Evict once the refcount drops to 0.
|
||||
*/
|
||||
uint8_t db_pending_evict;
|
||||
|
||||
uint8_t db_dirtycnt;
|
||||
|
||||
/* The buffer was partially read. More reads may follow. */
|
||||
uint8_t db_partial_read;
|
||||
} dmu_buf_impl_t;
|
||||
|
||||
#define DBUF_HASH_MUTEX(h, idx) \
|
||||
@ -351,6 +352,8 @@ typedef struct dbuf_hash_table {
|
||||
|
||||
typedef void (*dbuf_prefetch_fn)(void *, uint64_t, uint64_t, boolean_t);
|
||||
|
||||
extern kmem_cache_t *dbuf_dirty_kmem_cache;
|
||||
|
||||
uint64_t dbuf_whichblock(const struct dnode *di, const int64_t level,
|
||||
const uint64_t offset);
|
||||
|
||||
|
@ -36,28 +36,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Unicode encoding conversion functions and their macros.
|
||||
*/
|
||||
#define UCONV_IN_BIG_ENDIAN 0x0001
|
||||
#define UCONV_OUT_BIG_ENDIAN 0x0002
|
||||
#define UCONV_IN_SYSTEM_ENDIAN 0x0004
|
||||
#define UCONV_OUT_SYSTEM_ENDIAN 0x0008
|
||||
#define UCONV_IN_LITTLE_ENDIAN 0x0010
|
||||
#define UCONV_OUT_LITTLE_ENDIAN 0x0020
|
||||
#define UCONV_IGNORE_NULL 0x0040
|
||||
#define UCONV_IN_ACCEPT_BOM 0x0080
|
||||
#define UCONV_OUT_EMIT_BOM 0x0100
|
||||
|
||||
extern int uconv_u16tou32(const uint16_t *, size_t *, uint32_t *, size_t *,
|
||||
int);
|
||||
extern int uconv_u16tou8(const uint16_t *, size_t *, uchar_t *, size_t *, int);
|
||||
extern int uconv_u32tou16(const uint32_t *, size_t *, uint16_t *, size_t *,
|
||||
int);
|
||||
extern int uconv_u32tou8(const uint32_t *, size_t *, uchar_t *, size_t *, int);
|
||||
extern int uconv_u8tou16(const uchar_t *, size_t *, uint16_t *, size_t *, int);
|
||||
extern int uconv_u8tou32(const uchar_t *, size_t *, uint32_t *, size_t *, int);
|
||||
|
||||
/*
|
||||
* UTF-8 text preparation functions and their macros.
|
||||
*
|
||||
@ -67,7 +45,9 @@ extern int uconv_u8tou32(const uchar_t *, size_t *, uint32_t *, size_t *, int);
|
||||
*/
|
||||
#define U8_STRCMP_CS (0x00000001)
|
||||
#define U8_STRCMP_CI_UPPER (0x00000002)
|
||||
#if 0
|
||||
#define U8_STRCMP_CI_LOWER (0x00000004)
|
||||
#endif
|
||||
|
||||
#define U8_CANON_DECOMP (0x00000010)
|
||||
#define U8_COMPAT_DECOMP (0x00000020)
|
||||
@ -79,7 +59,9 @@ extern int uconv_u8tou32(const uchar_t *, size_t *, uint32_t *, size_t *, int);
|
||||
#define U8_STRCMP_NFKC (U8_COMPAT_DECOMP | U8_CANON_COMP)
|
||||
|
||||
#define U8_TEXTPREP_TOUPPER (U8_STRCMP_CI_UPPER)
|
||||
#ifdef U8_STRCMP_CI_LOWER
|
||||
#define U8_TEXTPREP_TOLOWER (U8_STRCMP_CI_LOWER)
|
||||
#endif
|
||||
|
||||
#define U8_TEXTPREP_NFD (U8_STRCMP_NFD)
|
||||
#define U8_TEXTPREP_NFC (U8_STRCMP_NFC)
|
||||
@ -90,8 +72,12 @@ extern int uconv_u8tou32(const uchar_t *, size_t *, uint32_t *, size_t *, int);
|
||||
#define U8_TEXTPREP_IGNORE_INVALID (0x00020000)
|
||||
#define U8_TEXTPREP_NOWAIT (0x00040000)
|
||||
|
||||
#if 0
|
||||
#define U8_UNICODE_320 (0)
|
||||
#define U8_UNICODE_500 (1)
|
||||
#else
|
||||
#define U8_UNICODE_500 (0)
|
||||
#endif
|
||||
#define U8_UNICODE_LATEST (U8_UNICODE_500)
|
||||
|
||||
#define U8_VALIDATE_ENTIRE (0x00100000)
|
||||
|
@ -146,7 +146,8 @@ typedef struct {
|
||||
* The common b1_tbl for combining class, decompositions, tolower, and
|
||||
* toupper case conversion mappings.
|
||||
*/
|
||||
static const uchar_t u8_common_b1_tbl[2][256] = {
|
||||
static const uchar_t u8_common_b1_tbl[U8_UNICODE_LATEST + 1][256] = {
|
||||
#ifdef U8_UNICODE_320
|
||||
{
|
||||
0, N_, N_, N_, N_, N_, N_, N_,
|
||||
N_, N_, N_, N_, N_, N_, N_, N_,
|
||||
@ -181,6 +182,7 @@ static const uchar_t u8_common_b1_tbl[2][256] = {
|
||||
1, N_, N_, N_, N_, N_, N_, N_,
|
||||
N_, N_, N_, N_, N_, N_, N_, N_,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
0, N_, N_, N_, N_, N_, N_, N_,
|
||||
N_, N_, N_, N_, N_, N_, N_, N_,
|
||||
@ -217,7 +219,9 @@ static const uchar_t u8_common_b1_tbl[2][256] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const uchar_t u8_combining_class_b2_tbl[2][2][256] = {
|
||||
static const uchar_t u8_combining_class_b2_tbl[U8_UNICODE_LATEST + 1][2][256] =
|
||||
{
|
||||
#ifdef U8_UNICODE_320
|
||||
{
|
||||
{
|
||||
0, N_, N_, N_, N_, N_, N_, N_,
|
||||
@ -289,6 +293,7 @@ static const uchar_t u8_combining_class_b2_tbl[2][2][256] = {
|
||||
},
|
||||
|
||||
},
|
||||
#endif
|
||||
{
|
||||
{
|
||||
0, N_, N_, N_, N_, N_, N_, N_,
|
||||
@ -363,7 +368,9 @@ static const uchar_t u8_combining_class_b2_tbl[2][2][256] = {
|
||||
|
||||
};
|
||||
|
||||
static const uchar_t u8_combining_class_b3_tbl[2][9][256] = {
|
||||
static const uchar_t u8_combining_class_b3_tbl[U8_UNICODE_LATEST + 1][9][256] =
|
||||
{
|
||||
#ifdef U8_UNICODE_320
|
||||
{
|
||||
{ /* Third byte table 0. */
|
||||
N_, N_, N_, N_, N_, N_, N_, N_,
|
||||
@ -672,6 +679,7 @@ static const uchar_t u8_combining_class_b3_tbl[2][9][256] = {
|
||||
N_, N_, N_, N_, N_, N_, N_, N_,
|
||||
},
|
||||
},
|
||||
#endif
|
||||
{
|
||||
{ /* Third byte table 0. */
|
||||
N_, N_, N_, N_, N_, N_, N_, N_,
|
||||
@ -986,7 +994,9 @@ static const uchar_t u8_combining_class_b3_tbl[2][9][256] = {
|
||||
* Unlike other b4_tbl, the b4_tbl for combining class data has
|
||||
* the combining class values not indices to the final tables.
|
||||
*/
|
||||
static const uchar_t u8_combining_class_b4_tbl[2][55][256] = {
|
||||
static const uchar_t u8_combining_class_b4_tbl[U8_UNICODE_LATEST + 1][55][256] =
|
||||
{
|
||||
#ifdef U8_UNICODE_320
|
||||
{
|
||||
{ /* Fourth byte table 0. */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
@ -2859,6 +2869,7 @@ static const uchar_t u8_combining_class_b4_tbl[2][55][256] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
},
|
||||
},
|
||||
#endif
|
||||
{
|
||||
{ /* Fourth byte table 0. */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
@ -4733,7 +4744,8 @@ static const uchar_t u8_combining_class_b4_tbl[2][55][256] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const uchar_t u8_composition_b1_tbl[2][256] = {
|
||||
static const uchar_t u8_composition_b1_tbl[U8_UNICODE_LATEST + 1][256] = {
|
||||
#ifdef U8_UNICODE_320
|
||||
{
|
||||
0, N_, N_, N_, N_, N_, N_, N_,
|
||||
N_, N_, N_, N_, N_, N_, N_, N_,
|
||||
@ -4768,6 +4780,7 @@ static const uchar_t u8_composition_b1_tbl[2][256] = {
|
||||
N_, N_, N_, N_, N_, N_, N_, N_,
|
||||
N_, N_, N_, N_, N_, N_, N_, N_,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
0, N_, N_, N_, N_, N_, N_, N_,
|
||||
N_, N_, N_, N_, N_, N_, N_, N_,
|
||||
@ -4804,7 +4817,8 @@ static const uchar_t u8_composition_b1_tbl[2][256] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const uchar_t u8_composition_b2_tbl[2][1][256] = {
|
||||
static const uchar_t u8_composition_b2_tbl[U8_UNICODE_LATEST + 1][1][256] = {
|
||||
#ifdef U8_UNICODE_320
|
||||
{
|
||||
{
|
||||
0, N_, N_, N_, N_, N_, N_, N_,
|
||||
@ -4842,6 +4856,7 @@ static const uchar_t u8_composition_b2_tbl[2][1][256] = {
|
||||
},
|
||||
|
||||
},
|
||||
#endif
|
||||
{
|
||||
{
|
||||
0, N_, N_, N_, N_, N_, N_, N_,
|
||||
@ -4882,7 +4897,10 @@ static const uchar_t u8_composition_b2_tbl[2][1][256] = {
|
||||
|
||||
};
|
||||
|
||||
static const u8_displacement_t u8_composition_b3_tbl[2][5][256] = {
|
||||
static const u8_displacement_t u8_composition_b3_tbl[
|
||||
U8_UNICODE_LATEST + 1][5][256] =
|
||||
{
|
||||
#ifdef U8_UNICODE_320
|
||||
{
|
||||
{ /* Third byte table 0. */
|
||||
{ 0x8000, 0 }, { N_, 0 }, { N_, 0 },
|
||||
@ -5325,6 +5343,7 @@ static const u8_displacement_t u8_composition_b3_tbl[2][5][256] = {
|
||||
{ N_, 0 },
|
||||
},
|
||||
},
|
||||
#endif
|
||||
{
|
||||
{ /* Third byte table 0. */
|
||||
{ 0x8000, 0 }, { N_, 0 }, { N_, 0 },
|
||||
@ -5769,7 +5788,8 @@ static const u8_displacement_t u8_composition_b3_tbl[2][5][256] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const uchar_t u8_composition_b4_tbl[2][41][257] = {
|
||||
static const uchar_t u8_composition_b4_tbl[U8_UNICODE_LATEST + 1][41][257] = {
|
||||
#ifdef U8_UNICODE_320
|
||||
{
|
||||
{ /* Fourth byte table 0. */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
@ -7207,6 +7227,7 @@ static const uchar_t u8_composition_b4_tbl[2][41][257] = {
|
||||
0,
|
||||
},
|
||||
},
|
||||
#endif
|
||||
{
|
||||
{ /* Fourth byte table 0. */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
@ -8646,7 +8667,10 @@ static const uchar_t u8_composition_b4_tbl[2][41][257] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const uint16_t u8_composition_b4_16bit_tbl[2][5][257] = {
|
||||
static const uint16_t u8_composition_b4_16bit_tbl[
|
||||
U8_UNICODE_LATEST + 1][5][257] =
|
||||
{
|
||||
#ifdef U8_UNICODE_320
|
||||
{
|
||||
{ /* Fourth byte 16-bit table 0. */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
@ -8824,6 +8848,7 @@ static const uint16_t u8_composition_b4_16bit_tbl[2][5][257] = {
|
||||
362,
|
||||
},
|
||||
},
|
||||
#endif
|
||||
{
|
||||
{ /* Fourth byte 16-bit table 0. */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
@ -9003,7 +9028,8 @@ static const uint16_t u8_composition_b4_16bit_tbl[2][5][257] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const uchar_t u8_composition_final_tbl[2][6623] = {
|
||||
static const uchar_t u8_composition_final_tbl[U8_UNICODE_LATEST + 1][6623] = {
|
||||
#ifdef U8_UNICODE_320
|
||||
{
|
||||
0x01, 0xCC, 0xB8, FIL_, 0xE2, 0x89, 0xAE, FIL_,
|
||||
0x01, 0xCC, 0xB8, FIL_, 0xE2, 0x89, 0xA0, FIL_,
|
||||
@ -9834,6 +9860,7 @@ static const uchar_t u8_composition_final_tbl[2][6623] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
0x01, 0xCC, 0xB8, FIL_, 0xE2, 0x89, 0xAE, FIL_,
|
||||
0x01, 0xCC, 0xB8, FIL_, 0xE2, 0x89, 0xA0, FIL_,
|
||||
@ -10666,7 +10693,8 @@ static const uchar_t u8_composition_final_tbl[2][6623] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const uchar_t u8_decomp_b2_tbl[2][2][256] = {
|
||||
static const uchar_t u8_decomp_b2_tbl[U8_UNICODE_LATEST + 1][2][256] = {
|
||||
#ifdef U8_UNICODE_320
|
||||
{
|
||||
{
|
||||
0, N_, N_, N_, N_, N_, N_, N_,
|
||||
@ -10738,6 +10766,7 @@ static const uchar_t u8_decomp_b2_tbl[2][2][256] = {
|
||||
},
|
||||
|
||||
},
|
||||
#endif
|
||||
{
|
||||
{
|
||||
0, N_, N_, N_, N_, N_, N_, N_,
|
||||
@ -10812,7 +10841,9 @@ static const uchar_t u8_decomp_b2_tbl[2][2][256] = {
|
||||
|
||||
};
|
||||
|
||||
static const u8_displacement_t u8_decomp_b3_tbl[2][8][256] = {
|
||||
static const u8_displacement_t u8_decomp_b3_tbl[U8_UNICODE_LATEST + 1][8][256] =
|
||||
{
|
||||
#ifdef U8_UNICODE_320
|
||||
{
|
||||
{ /* Third byte table 0. */
|
||||
{ N_, 0 }, { N_, 0 }, { N_, 0 },
|
||||
@ -11519,6 +11550,7 @@ static const u8_displacement_t u8_decomp_b3_tbl[2][8][256] = {
|
||||
{ N_, 0 },
|
||||
},
|
||||
},
|
||||
#endif
|
||||
{
|
||||
{ /* Third byte table 0. */
|
||||
{ N_, 0 }, { N_, 0 }, { N_, 0 },
|
||||
@ -12227,7 +12259,8 @@ static const u8_displacement_t u8_decomp_b3_tbl[2][8][256] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const uchar_t u8_decomp_b4_tbl[2][118][257] = {
|
||||
static const uchar_t u8_decomp_b4_tbl[U8_UNICODE_LATEST + 1][118][257] = {
|
||||
#ifdef U8_UNICODE_320
|
||||
{
|
||||
{ /* Fourth byte table 0. */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
@ -16360,6 +16393,7 @@ static const uchar_t u8_decomp_b4_tbl[2][118][257] = {
|
||||
0,
|
||||
},
|
||||
},
|
||||
#endif
|
||||
{
|
||||
{ /* Fourth byte table 0. */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
@ -20494,7 +20528,8 @@ static const uchar_t u8_decomp_b4_tbl[2][118][257] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const uint16_t u8_decomp_b4_16bit_tbl[2][30][257] = {
|
||||
static const uint16_t u8_decomp_b4_16bit_tbl[U8_UNICODE_LATEST + 1][30][257] = {
|
||||
#ifdef U8_UNICODE_320
|
||||
{
|
||||
{ /* Fourth byte 16-bit table 0. */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
@ -21547,6 +21582,7 @@ static const uint16_t u8_decomp_b4_16bit_tbl[2][30][257] = {
|
||||
0,
|
||||
},
|
||||
},
|
||||
#endif
|
||||
{
|
||||
{ /* Fourth byte 16-bit table 0. */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
@ -22601,7 +22637,8 @@ static const uint16_t u8_decomp_b4_16bit_tbl[2][30][257] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const uchar_t u8_decomp_final_tbl[2][19370] = {
|
||||
static const uchar_t u8_decomp_final_tbl[U8_UNICODE_LATEST + 1][19370] = {
|
||||
#ifdef U8_UNICODE_320
|
||||
{
|
||||
0x20, 0x20, 0xCC, 0x88, 0x61, 0x20, 0xCC, 0x84,
|
||||
0x32, 0x33, 0x20, 0xCC, 0x81, 0xCE, 0xBC, 0x20,
|
||||
@ -25026,6 +25063,7 @@ static const uchar_t u8_decomp_final_tbl[2][19370] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
0x20, 0x20, 0xCC, 0x88, 0x61, 0x20, 0xCC, 0x84,
|
||||
0x32, 0x33, 0x20, 0xCC, 0x81, 0xCE, 0xBC, 0x20,
|
||||
@ -27452,7 +27490,8 @@ static const uchar_t u8_decomp_final_tbl[2][19370] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const uchar_t u8_case_common_b2_tbl[2][2][256] = {
|
||||
static const uchar_t u8_case_common_b2_tbl[U8_UNICODE_LATEST + 1][2][256] = {
|
||||
#ifdef U8_UNICODE_320
|
||||
{
|
||||
{
|
||||
0, N_, N_, N_, N_, N_, N_, N_,
|
||||
@ -27524,6 +27563,7 @@ static const uchar_t u8_case_common_b2_tbl[2][2][256] = {
|
||||
},
|
||||
|
||||
},
|
||||
#endif
|
||||
{
|
||||
{
|
||||
0, N_, N_, N_, N_, N_, N_, N_,
|
||||
@ -27598,7 +27638,11 @@ static const uchar_t u8_case_common_b2_tbl[2][2][256] = {
|
||||
|
||||
};
|
||||
|
||||
static const u8_displacement_t u8_tolower_b3_tbl[2][5][256] = {
|
||||
#ifdef U8_STRCMP_CI_LOWER
|
||||
static const u8_displacement_t u8_tolower_b3_tbl[
|
||||
U8_UNICODE_LATEST + 1][5][256] =
|
||||
{
|
||||
#ifdef U8_UNICODE_320
|
||||
{
|
||||
{ /* Third byte table 0. */
|
||||
{ N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
|
||||
@ -27931,6 +27975,7 @@ static const u8_displacement_t u8_tolower_b3_tbl[2][5][256] = {
|
||||
{ N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
|
||||
},
|
||||
},
|
||||
#endif
|
||||
{
|
||||
{ /* Third byte table 0. */
|
||||
{ N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
|
||||
@ -28265,7 +28310,8 @@ static const u8_displacement_t u8_tolower_b3_tbl[2][5][256] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const uchar_t u8_tolower_b4_tbl[2][36][257] = {
|
||||
static const uchar_t u8_tolower_b4_tbl[U8_UNICODE_LATEST + 1][36][257] = {
|
||||
#ifdef U8_UNICODE_320
|
||||
{
|
||||
{ /* Fourth byte table 0. */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
@ -29528,6 +29574,7 @@ static const uchar_t u8_tolower_b4_tbl[2][36][257] = {
|
||||
0,
|
||||
},
|
||||
},
|
||||
#endif
|
||||
{
|
||||
{ /* Fourth byte table 0. */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
@ -30792,7 +30839,8 @@ static const uchar_t u8_tolower_b4_tbl[2][36][257] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const uchar_t u8_tolower_final_tbl[2][2299] = {
|
||||
static const uchar_t u8_tolower_final_tbl[U8_UNICODE_LATEST + 1][2299] = {
|
||||
#ifdef U8_UNICODE_320
|
||||
{
|
||||
0xC3, 0xA0, 0xC3, 0xA1, 0xC3, 0xA2, 0xC3, 0xA3,
|
||||
0xC3, 0xA4, 0xC3, 0xA5, 0xC3, 0xA6, 0xC3, 0xA7,
|
||||
@ -31083,6 +31131,7 @@ static const uchar_t u8_tolower_final_tbl[2][2299] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
0xC3, 0xA0, 0xC3, 0xA1, 0xC3, 0xA2, 0xC3, 0xA3,
|
||||
0xC3, 0xA4, 0xC3, 0xA5, 0xC3, 0xA6, 0xC3, 0xA7,
|
||||
@ -31374,8 +31423,12 @@ static const uchar_t u8_tolower_final_tbl[2][2299] = {
|
||||
0x90, 0x91, 0x8F,
|
||||
},
|
||||
};
|
||||
#endif
|
||||
|
||||
static const u8_displacement_t u8_toupper_b3_tbl[2][5][256] = {
|
||||
static const u8_displacement_t u8_toupper_b3_tbl[
|
||||
U8_UNICODE_LATEST + 1][5][256] =
|
||||
{
|
||||
#ifdef U8_UNICODE_320
|
||||
{
|
||||
{ /* Third byte table 0. */
|
||||
{ N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
|
||||
@ -31708,6 +31761,7 @@ static const u8_displacement_t u8_toupper_b3_tbl[2][5][256] = {
|
||||
{ N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
|
||||
},
|
||||
},
|
||||
#endif
|
||||
{
|
||||
{ /* Third byte table 0. */
|
||||
{ N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
|
||||
@ -32042,7 +32096,8 @@ static const u8_displacement_t u8_toupper_b3_tbl[2][5][256] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const uchar_t u8_toupper_b4_tbl[2][39][257] = {
|
||||
static const uchar_t u8_toupper_b4_tbl[U8_UNICODE_LATEST + 1][39][257] = {
|
||||
#ifdef U8_UNICODE_320
|
||||
{
|
||||
{ /* Fourth byte table 0. */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
@ -33410,6 +33465,7 @@ static const uchar_t u8_toupper_b4_tbl[2][39][257] = {
|
||||
0,
|
||||
},
|
||||
},
|
||||
#endif
|
||||
{
|
||||
{ /* Fourth byte table 0. */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
@ -34779,7 +34835,8 @@ static const uchar_t u8_toupper_b4_tbl[2][39][257] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const uchar_t u8_toupper_final_tbl[2][2318] = {
|
||||
static const uchar_t u8_toupper_final_tbl[U8_UNICODE_LATEST + 1][2318] = {
|
||||
#ifdef U8_UNICODE_320
|
||||
{
|
||||
0xCE, 0x9C, 0xC3, 0x80, 0xC3, 0x81, 0xC3, 0x82,
|
||||
0xC3, 0x83, 0xC3, 0x84, 0xC3, 0x85, 0xC3, 0x86,
|
||||
@ -35072,6 +35129,7 @@ static const uchar_t u8_toupper_final_tbl[2][2318] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
0xCE, 0x9C, 0xC3, 0x80, 0xC3, 0x81, 0xC3, 0x82,
|
||||
0xC3, 0x83, 0xC3, 0x84, 0xC3, 0x85, 0xC3, 0x86,
|
||||
|
@ -3,5 +3,4 @@ libunicode_la_CFLAGS = $(AM_CFLAGS) $(KERNEL_CFLAGS) $(LIBRARY_CFLAGS)
|
||||
noinst_LTLIBRARIES += libunicode.la
|
||||
|
||||
nodist_libunicode_la_SOURCES = \
|
||||
module/unicode/u8_textprep.c \
|
||||
module/unicode/uconv.c
|
||||
module/unicode/u8_textprep.c
|
||||
|
@ -471,13 +471,15 @@ int
|
||||
zpool_get_userprop(zpool_handle_t *zhp, const char *propname, char *buf,
|
||||
size_t len, zprop_source_t *srctype)
|
||||
{
|
||||
nvlist_t *nv, *nvl;
|
||||
nvlist_t *nv;
|
||||
uint64_t ival;
|
||||
const char *value;
|
||||
zprop_source_t source = ZPROP_SRC_LOCAL;
|
||||
|
||||
nvl = zhp->zpool_props;
|
||||
if (nvlist_lookup_nvlist(nvl, propname, &nv) == 0) {
|
||||
if (zhp->zpool_props == NULL)
|
||||
zpool_get_all_props(zhp);
|
||||
|
||||
if (nvlist_lookup_nvlist(zhp->zpool_props, propname, &nv) == 0) {
|
||||
if (nvlist_lookup_uint64(nv, ZPROP_SOURCE, &ival) == 0)
|
||||
source = ival;
|
||||
verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0);
|
||||
|
@ -18,7 +18,7 @@
|
||||
.\"
|
||||
.\" Copyright (c) 2024, Klara, Inc.
|
||||
.\"
|
||||
.Dd October 2, 2024
|
||||
.Dd November 1, 2024
|
||||
.Dt ZFS 4
|
||||
.Os
|
||||
.
|
||||
@ -1333,9 +1333,10 @@ results in vector instructions
|
||||
from the respective CPU instruction set being used.
|
||||
.
|
||||
.It Sy zfs_bclone_enabled Ns = Ns Sy 1 Ns | Ns 0 Pq int
|
||||
Enable the experimental block cloning feature.
|
||||
Enables access to the block cloning feature.
|
||||
If this setting is 0, then even if feature@block_cloning is enabled,
|
||||
attempts to clone blocks will act as though the feature is disabled.
|
||||
using functions and system calls that attempt to clone blocks will act as
|
||||
though the feature is disabled.
|
||||
.
|
||||
.It Sy zfs_bclone_wait_dirty Ns = Ns Sy 0 Ns | Ns 1 Pq int
|
||||
When set to 1 the FICLONE and FICLONERANGE ioctls wait for dirty data to be
|
||||
|
@ -14,7 +14,7 @@
|
||||
.\" Copyright (c) 2017 Lawrence Livermore National Security, LLC.
|
||||
.\" Copyright (c) 2017 Intel Corporation.
|
||||
.\"
|
||||
.Dd November 18, 2023
|
||||
.Dd October 27, 2024
|
||||
.Dt ZDB 8
|
||||
.Os
|
||||
.
|
||||
@ -408,6 +408,8 @@ blocks cloned, the space saving as a result of cloning, and the saving ratio.
|
||||
.It Fl TT
|
||||
Display the per-vdev BRT statistics, including total references.
|
||||
.It Fl TTT
|
||||
Display histograms of per-vdev BRT refcounts.
|
||||
.It Fl TTTT
|
||||
Dump the contents of the block reference tables.
|
||||
.It Fl u , -uberblock
|
||||
Display the current uberblock.
|
||||
|
@ -224,8 +224,7 @@ zfs-objs += $(addprefix nvpair/,$(NVPAIR_OBJS))
|
||||
|
||||
|
||||
UNICODE_OBJS := \
|
||||
u8_textprep.o \
|
||||
uconv.o
|
||||
u8_textprep.o
|
||||
|
||||
zfs-objs += $(addprefix unicode/,$(UNICODE_OBJS))
|
||||
|
||||
|
@ -217,8 +217,7 @@ SRCS+= abd_os.c \
|
||||
zvol_os.c
|
||||
|
||||
#unicode
|
||||
SRCS+= u8_textprep.c \
|
||||
uconv.c
|
||||
SRCS+= u8_textprep.c
|
||||
|
||||
#zcommon
|
||||
SRCS+= cityhash.c \
|
||||
|
@ -171,11 +171,11 @@ issig(void)
|
||||
#if defined(HAVE_DEQUEUE_SIGNAL_4ARG)
|
||||
enum pid_type __type;
|
||||
if (dequeue_signal(current, &set, &__info, &__type) != 0) {
|
||||
#elif defined(HAVE_DEQUEUE_SIGNAL_3ARG_TASK)
|
||||
if (dequeue_signal(current, &set, &__info) != 0) {
|
||||
#else
|
||||
#elif defined(HAVE_DEQUEUE_SIGNAL_3ARG_TYPE)
|
||||
enum pid_type __type;
|
||||
if (dequeue_signal(&set, &__info, &__type) != 0) {
|
||||
#else
|
||||
if (dequeue_signal(current, &set, &__info) != 0) {
|
||||
#endif
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
kernel_signal_stop();
|
||||
|
@ -701,6 +701,8 @@ abd_free_linear_page(abd_t *abd)
|
||||
/* When backed by user page unmap it */
|
||||
if (abd_is_from_pages(abd))
|
||||
zfs_kunmap(sg_page(sg));
|
||||
else
|
||||
abd_update_scatter_stats(abd, ABDSTAT_DECR);
|
||||
|
||||
abd->abd_flags &= ~ABD_FLAG_LINEAR;
|
||||
abd->abd_flags &= ~ABD_FLAG_LINEAR_PAGE;
|
||||
|
@ -801,24 +801,13 @@ vbio_completion(struct bio *bio)
|
||||
bio_put(bio);
|
||||
|
||||
/*
|
||||
* If we copied the ABD before issuing it, clean up and return the copy
|
||||
* to the ADB, with changes if appropriate.
|
||||
* We're likely in an interrupt context so we can't do ABD/memory work
|
||||
* here; instead we stash vbio on the zio and take care of it in the
|
||||
* done callback.
|
||||
*/
|
||||
if (vbio->vbio_abd != NULL) {
|
||||
void *buf = abd_to_buf(vbio->vbio_abd);
|
||||
abd_free(vbio->vbio_abd);
|
||||
vbio->vbio_abd = NULL;
|
||||
ASSERT3P(zio->io_bio, ==, NULL);
|
||||
zio->io_bio = vbio;
|
||||
|
||||
if (zio->io_type == ZIO_TYPE_READ)
|
||||
abd_return_buf_copy(zio->io_abd, buf, zio->io_size);
|
||||
else
|
||||
abd_return_buf(zio->io_abd, buf, zio->io_size);
|
||||
}
|
||||
|
||||
/* Final cleanup */
|
||||
kmem_free(vbio, sizeof (vbio_t));
|
||||
|
||||
/* All done, submit for processing */
|
||||
zio_delay_interrupt(zio);
|
||||
}
|
||||
|
||||
@ -834,38 +823,61 @@ vbio_completion(struct bio *bio)
|
||||
* NOTE: if you change this function, change the copy in
|
||||
* tests/zfs-tests/tests/functional/vdev_disk/page_alignment.c, and add test
|
||||
* data there to validate the change you're making.
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
uint_t bmask;
|
||||
uint_t npages;
|
||||
uint_t end;
|
||||
} vdev_disk_check_pages_t;
|
||||
size_t blocksize;
|
||||
int seen_first;
|
||||
int seen_last;
|
||||
} vdev_disk_check_alignment_t;
|
||||
|
||||
static int
|
||||
vdev_disk_check_pages_cb(struct page *page, size_t off, size_t len, void *priv)
|
||||
vdev_disk_check_alignment_cb(struct page *page, size_t off, size_t len,
|
||||
void *priv)
|
||||
{
|
||||
(void) page;
|
||||
vdev_disk_check_pages_t *s = priv;
|
||||
vdev_disk_check_alignment_t *s = priv;
|
||||
|
||||
/*
|
||||
* If we didn't finish on a block size boundary last time, then there
|
||||
* would be a gap if we tried to use this ABD as-is, so abort.
|
||||
* The cardinal rule: a single on-disk block must never cross an
|
||||
* physical (order-0) page boundary, as the kernel expects to be able
|
||||
* to split at both LBS and page boundaries.
|
||||
*
|
||||
* This implies various alignment rules for the blocks in this
|
||||
* (possibly compound) page, which we can check for.
|
||||
*/
|
||||
if (s->end != 0)
|
||||
|
||||
/*
|
||||
* If the previous page did not end on a page boundary, then we
|
||||
* can't proceed without creating a hole.
|
||||
*/
|
||||
if (s->seen_last)
|
||||
return (1);
|
||||
|
||||
/* This page must contain only whole LBS-sized blocks. */
|
||||
if (!IS_P2ALIGNED(len, s->blocksize))
|
||||
return (1);
|
||||
|
||||
/*
|
||||
* Note if we're taking less than a full block, so we can check it
|
||||
* above on the next call.
|
||||
* If this is not the first page in the ABD, then the data must start
|
||||
* on a page-aligned boundary (so the kernel can split on page
|
||||
* boundaries without having to deal with a hole). If it is, then
|
||||
* it can start on LBS-alignment.
|
||||
*/
|
||||
s->end = (off+len) & s->bmask;
|
||||
|
||||
/* All blocks after the first must start on a block size boundary. */
|
||||
if (s->npages != 0 && (off & s->bmask) != 0)
|
||||
if (s->seen_first) {
|
||||
if (!IS_P2ALIGNED(off, PAGESIZE))
|
||||
return (1);
|
||||
} else {
|
||||
if (!IS_P2ALIGNED(off, s->blocksize))
|
||||
return (1);
|
||||
s->seen_first = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this data does not end on a page-aligned boundary, then this
|
||||
* must be the last page in the ABD, for the same reason.
|
||||
*/
|
||||
s->seen_last = !IS_P2ALIGNED(off+len, PAGESIZE);
|
||||
|
||||
s->npages++;
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -874,15 +886,14 @@ vdev_disk_check_pages_cb(struct page *page, size_t off, size_t len, void *priv)
|
||||
* the number of pages, or 0 if it can't be submitted like this.
|
||||
*/
|
||||
static boolean_t
|
||||
vdev_disk_check_pages(abd_t *abd, uint64_t size, struct block_device *bdev)
|
||||
vdev_disk_check_alignment(abd_t *abd, uint64_t size, struct block_device *bdev)
|
||||
{
|
||||
vdev_disk_check_pages_t s = {
|
||||
.bmask = bdev_logical_block_size(bdev)-1,
|
||||
.npages = 0,
|
||||
.end = 0,
|
||||
vdev_disk_check_alignment_t s = {
|
||||
.blocksize = bdev_logical_block_size(bdev),
|
||||
};
|
||||
|
||||
if (abd_iterate_page_func(abd, 0, size, vdev_disk_check_pages_cb, &s))
|
||||
if (abd_iterate_page_func(abd, 0, size,
|
||||
vdev_disk_check_alignment_cb, &s))
|
||||
return (B_FALSE);
|
||||
|
||||
return (B_TRUE);
|
||||
@ -916,37 +927,32 @@ vdev_disk_io_rw(zio_t *zio)
|
||||
|
||||
/*
|
||||
* Check alignment of the incoming ABD. If any part of it would require
|
||||
* submitting a page that is not aligned to the logical block size,
|
||||
* then we take a copy into a linear buffer and submit that instead.
|
||||
* This should be impossible on a 512b LBS, and fairly rare on 4K,
|
||||
* usually requiring abnormally-small data blocks (eg gang blocks)
|
||||
* mixed into the same ABD as larger ones (eg aggregated).
|
||||
* submitting a page that is not aligned to both the logical block size
|
||||
* and the page size, then we take a copy into a new memory region with
|
||||
* correct alignment. This should be impossible on a 512b LBS. On
|
||||
* larger blocks, this can happen at least when a small number of
|
||||
* blocks (usually 1) are allocated from a shared slab, or when
|
||||
* abnormally-small data regions (eg gang headers) are mixed into the
|
||||
* same ABD as larger allocations (eg aggregations).
|
||||
*/
|
||||
abd_t *abd = zio->io_abd;
|
||||
if (!vdev_disk_check_pages(abd, zio->io_size, bdev)) {
|
||||
void *buf;
|
||||
if (zio->io_type == ZIO_TYPE_READ)
|
||||
buf = abd_borrow_buf(zio->io_abd, zio->io_size);
|
||||
else
|
||||
buf = abd_borrow_buf_copy(zio->io_abd, zio->io_size);
|
||||
if (!vdev_disk_check_alignment(abd, zio->io_size, bdev)) {
|
||||
/* Allocate a new memory region with guaranteed alignment */
|
||||
abd = abd_alloc_for_io(zio->io_size,
|
||||
zio->io_abd->abd_flags & ABD_FLAG_META);
|
||||
|
||||
/* If we're writing copy our data into it */
|
||||
if (zio->io_type == ZIO_TYPE_WRITE)
|
||||
abd_copy(abd, zio->io_abd, zio->io_size);
|
||||
|
||||
/*
|
||||
* Wrap the copy in an abd_t, so we can use the same iterators
|
||||
* to count and fill the vbio later.
|
||||
*/
|
||||
abd = abd_get_from_buf(buf, zio->io_size);
|
||||
|
||||
/*
|
||||
* False here would mean the borrowed copy has an invalid
|
||||
* alignment too, which would mean we've somehow been passed a
|
||||
* linear ABD with an interior page that has a non-zero offset
|
||||
* or a size not a multiple of PAGE_SIZE. This is not possible.
|
||||
* It would mean either zio_buf_alloc() or its underlying
|
||||
* allocators have done something extremely strange, or our
|
||||
* math in vdev_disk_check_pages() is wrong. In either case,
|
||||
* False here would mean the new allocation has an invalid
|
||||
* alignment too, which would mean that abd_alloc() is not
|
||||
* guaranteeing this, or our logic in
|
||||
* vdev_disk_check_alignment() is wrong. In either case,
|
||||
* something in seriously wrong and its not safe to continue.
|
||||
*/
|
||||
VERIFY(vdev_disk_check_pages(abd, zio->io_size, bdev));
|
||||
VERIFY(vdev_disk_check_alignment(abd, zio->io_size, bdev));
|
||||
}
|
||||
|
||||
/* Allocate vbio, with a pointer to the borrowed ABD if necessary */
|
||||
@ -1437,6 +1443,28 @@ vdev_disk_io_start(zio_t *zio)
|
||||
static void
|
||||
vdev_disk_io_done(zio_t *zio)
|
||||
{
|
||||
/* If this was a read or write, we need to clean up the vbio */
|
||||
if (zio->io_bio != NULL) {
|
||||
vbio_t *vbio = zio->io_bio;
|
||||
zio->io_bio = NULL;
|
||||
|
||||
/*
|
||||
* If we copied the ABD before issuing it, clean up and return
|
||||
* the copy to the ADB, with changes if appropriate.
|
||||
*/
|
||||
if (vbio->vbio_abd != NULL) {
|
||||
if (zio->io_type == ZIO_TYPE_READ)
|
||||
abd_copy(zio->io_abd, vbio->vbio_abd,
|
||||
zio->io_size);
|
||||
|
||||
abd_free(vbio->vbio_abd);
|
||||
vbio->vbio_abd = NULL;
|
||||
}
|
||||
|
||||
/* Final cleanup */
|
||||
kmem_free(vbio, sizeof (vbio_t));
|
||||
}
|
||||
|
||||
/*
|
||||
* If the device returned EIO, we revalidate the media. If it is
|
||||
* determined the media has changed this triggers the asynchronous
|
||||
|
@ -33,11 +33,13 @@
|
||||
#include <sys/fs/zfs.h>
|
||||
#include <sys/fm/fs/zfs.h>
|
||||
#include <sys/abd.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/zfs_file.h>
|
||||
#ifdef _KERNEL
|
||||
#include <linux/falloc.h>
|
||||
#include <sys/fcntl.h>
|
||||
#else
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
/*
|
||||
* Virtual device vector for files.
|
||||
|
@ -260,15 +260,6 @@ update_pages(znode_t *zp, int64_t start, int len, objset_t *os)
|
||||
} else {
|
||||
ClearPageError(pp);
|
||||
SetPageUptodate(pp);
|
||||
if (!PagePrivate(pp)) {
|
||||
/*
|
||||
* Set private bit so page migration
|
||||
* will wait for us to finish writeback
|
||||
* before calling migrate_folio().
|
||||
*/
|
||||
SetPagePrivate(pp);
|
||||
get_page(pp);
|
||||
}
|
||||
|
||||
if (mapping_writably_mapped(mp))
|
||||
flush_dcache_page(pp);
|
||||
@ -4090,14 +4081,6 @@ zfs_fillpage(struct inode *ip, struct page *pp)
|
||||
} else {
|
||||
ClearPageError(pp);
|
||||
SetPageUptodate(pp);
|
||||
if (!PagePrivate(pp)) {
|
||||
/*
|
||||
* Set private bit so page migration will wait for us to
|
||||
* finish writeback before calling migrate_folio().
|
||||
*/
|
||||
SetPagePrivate(pp);
|
||||
get_page(pp);
|
||||
}
|
||||
}
|
||||
|
||||
return (error);
|
||||
|
@ -1577,14 +1577,6 @@ zfs_zero_partial_page(znode_t *zp, uint64_t start, uint64_t len)
|
||||
mark_page_accessed(pp);
|
||||
SetPageUptodate(pp);
|
||||
ClearPageError(pp);
|
||||
if (!PagePrivate(pp)) {
|
||||
/*
|
||||
* Set private bit so page migration will wait for us to
|
||||
* finish writeback before calling migrate_folio().
|
||||
*/
|
||||
SetPagePrivate(pp);
|
||||
get_page(pp);
|
||||
}
|
||||
unlock_page(pp);
|
||||
put_page(pp);
|
||||
}
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <linux/compat.h>
|
||||
#endif
|
||||
#include <linux/fs.h>
|
||||
#include <linux/migrate.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/dmu_objset.h>
|
||||
#include <sys/zfs_znode.h>
|
||||
@ -607,42 +608,6 @@ zpl_writepage(struct page *pp, struct writeback_control *wbc)
|
||||
return (zpl_putpage(pp, wbc, &for_sync));
|
||||
}
|
||||
|
||||
static int
|
||||
zpl_releasepage(struct page *pp, gfp_t gfp)
|
||||
{
|
||||
if (PagePrivate(pp)) {
|
||||
ClearPagePrivate(pp);
|
||||
put_page(pp);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
#ifdef HAVE_VFS_RELEASE_FOLIO
|
||||
static bool
|
||||
zpl_release_folio(struct folio *folio, gfp_t gfp)
|
||||
{
|
||||
return (zpl_releasepage(&folio->page, gfp));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_VFS_INVALIDATE_FOLIO
|
||||
static void
|
||||
zpl_invalidate_folio(struct folio *folio, size_t offset, size_t len)
|
||||
{
|
||||
if ((offset == 0) && (len == PAGE_SIZE)) {
|
||||
zpl_releasepage(&folio->page, 0);
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void
|
||||
zpl_invalidatepage(struct page *pp, unsigned int offset, unsigned int len)
|
||||
{
|
||||
if ((offset == 0) && (len == PAGE_SIZE)) {
|
||||
zpl_releasepage(pp, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The flag combination which matches the behavior of zfs_space() is
|
||||
* FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE. The FALLOC_FL_PUNCH_HOLE
|
||||
@ -1126,15 +1091,10 @@ const struct address_space_operations zpl_address_space_operations = {
|
||||
#ifdef HAVE_VFS_FILEMAP_DIRTY_FOLIO
|
||||
.dirty_folio = filemap_dirty_folio,
|
||||
#endif
|
||||
#ifdef HAVE_VFS_RELEASE_FOLIO
|
||||
.release_folio = zpl_release_folio,
|
||||
#ifdef HAVE_VFS_MIGRATE_FOLIO
|
||||
.migrate_folio = migrate_folio,
|
||||
#else
|
||||
.releasepage = zpl_releasepage,
|
||||
#endif
|
||||
#ifdef HAVE_VFS_INVALIDATE_FOLIO
|
||||
.invalidate_folio = zpl_invalidate_folio,
|
||||
#else
|
||||
.invalidatepage = zpl_invalidatepage,
|
||||
.migratepage = migrate_page,
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -527,6 +527,7 @@ do_case_conv(int uv, uchar_t *u8s, uchar_t *s, int sz, boolean_t is_it_toupper)
|
||||
for (i = 0; start_id < end_id; start_id++)
|
||||
u8s[i++] = u8_toupper_final_tbl[uv][b3_base + start_id];
|
||||
} else {
|
||||
#ifdef U8_STRCMP_CI_LOWER
|
||||
b3_tbl = u8_tolower_b3_tbl[uv][b2][b3].tbl_id;
|
||||
if (b3_tbl == U8_TBL_ELEMENT_NOT_DEF)
|
||||
return ((size_t)sz);
|
||||
@ -541,6 +542,9 @@ do_case_conv(int uv, uchar_t *u8s, uchar_t *s, int sz, boolean_t is_it_toupper)
|
||||
|
||||
for (i = 0; start_id < end_id; start_id++)
|
||||
u8s[i++] = u8_tolower_final_tbl[uv][b3_base + start_id];
|
||||
#else
|
||||
__builtin_unreachable();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1753,7 +1757,11 @@ do_norm_compare(size_t uv, uchar_t *s1, uchar_t *s2, size_t n1, size_t n2,
|
||||
s2last = s2 + n2;
|
||||
|
||||
is_it_toupper = flag & U8_TEXTPREP_TOUPPER;
|
||||
#ifdef U8_STRCMP_CI_LOWER
|
||||
is_it_tolower = flag & U8_TEXTPREP_TOLOWER;
|
||||
#else
|
||||
is_it_tolower = 0;
|
||||
#endif
|
||||
canonical_decomposition = flag & U8_CANON_DECOMP;
|
||||
compatibility_decomposition = flag & U8_COMPAT_DECOMP;
|
||||
canonical_composition = flag & U8_CANON_COMP;
|
||||
@ -1870,12 +1878,22 @@ u8_strcmp(const char *s1, const char *s2, size_t n, int flag, size_t uv,
|
||||
if (flag == 0) {
|
||||
flag = U8_STRCMP_CS;
|
||||
} else {
|
||||
f = flag & (U8_STRCMP_CS | U8_STRCMP_CI_UPPER |
|
||||
U8_STRCMP_CI_LOWER);
|
||||
#ifdef U8_STRCMP_CI_LOWER
|
||||
f = flag & (U8_STRCMP_CS | U8_STRCMP_CI_UPPER
|
||||
| U8_STRCMP_CI_LOWER);
|
||||
#else
|
||||
f = flag & (U8_STRCMP_CS | U8_STRCMP_CI_UPPER);
|
||||
#endif
|
||||
if (f == 0) {
|
||||
flag |= U8_STRCMP_CS;
|
||||
} else if (f != U8_STRCMP_CS && f != U8_STRCMP_CI_UPPER &&
|
||||
f != U8_STRCMP_CI_LOWER) {
|
||||
}
|
||||
#ifdef U8_STRCMP_CI_LOWER
|
||||
else if (f != U8_STRCMP_CS && f != U8_STRCMP_CI_UPPER &&
|
||||
f != U8_STRCMP_CI_LOWER)
|
||||
#else
|
||||
else if (f != U8_STRCMP_CS && f != U8_STRCMP_CI_UPPER)
|
||||
#endif
|
||||
{
|
||||
*errnum = EBADF;
|
||||
flag = U8_STRCMP_CS;
|
||||
}
|
||||
@ -1908,10 +1926,13 @@ u8_strcmp(const char *s1, const char *s2, size_t n, int flag, size_t uv,
|
||||
if (flag == U8_STRCMP_CI_UPPER) {
|
||||
return (do_case_compare(uv, (uchar_t *)s1, (uchar_t *)s2,
|
||||
n1, n2, B_TRUE, errnum));
|
||||
} else if (flag == U8_STRCMP_CI_LOWER) {
|
||||
}
|
||||
#ifdef U8_STRCMP_CI_LOWER
|
||||
else if (flag == U8_STRCMP_CI_LOWER) {
|
||||
return (do_case_compare(uv, (uchar_t *)s1, (uchar_t *)s2,
|
||||
n1, n2, B_FALSE, errnum));
|
||||
}
|
||||
#endif
|
||||
|
||||
return (do_norm_compare(uv, (uchar_t *)s1, (uchar_t *)s2, n1, n2,
|
||||
flag, errnum));
|
||||
@ -1945,11 +1966,13 @@ u8_textprep_str(char *inarray, size_t *inlen, char *outarray, size_t *outlen,
|
||||
return ((size_t)-1);
|
||||
}
|
||||
|
||||
#ifdef U8_TEXTPREP_TOLOWER
|
||||
f = flag & (U8_TEXTPREP_TOUPPER | U8_TEXTPREP_TOLOWER);
|
||||
if (f == (U8_TEXTPREP_TOUPPER | U8_TEXTPREP_TOLOWER)) {
|
||||
*errnum = EBADF;
|
||||
return ((size_t)-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
f = flag & (U8_CANON_DECOMP | U8_COMPAT_DECOMP | U8_CANON_COMP);
|
||||
if (f && f != U8_TEXTPREP_NFD && f != U8_TEXTPREP_NFC &&
|
||||
@ -1974,7 +1997,11 @@ u8_textprep_str(char *inarray, size_t *inlen, char *outarray, size_t *outlen,
|
||||
do_not_ignore_null = !(flag & U8_TEXTPREP_IGNORE_NULL);
|
||||
do_not_ignore_invalid = !(flag & U8_TEXTPREP_IGNORE_INVALID);
|
||||
is_it_toupper = flag & U8_TEXTPREP_TOUPPER;
|
||||
#ifdef U8_TEXTPREP_TOLOWER
|
||||
is_it_tolower = flag & U8_TEXTPREP_TOLOWER;
|
||||
#else
|
||||
is_it_tolower = 0;
|
||||
#endif
|
||||
|
||||
ret_val = 0;
|
||||
|
||||
|
@ -1,859 +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 https://opensource.org/licenses/CDDL-1.0.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Unicode encoding conversion functions among UTF-8, UTF-16, and UTF-32.
|
||||
* (PSARC/2005/446, PSARC/2007/038, PSARC/2007/517)
|
||||
* Man pages: uconv_u16tou32(9F), uconv_u16tou8(9F), uconv_u32tou16(9F),
|
||||
* uconv_u32tou8(9F), uconv_u8tou16(9F), and uconv_u8tou32(9F). See also
|
||||
* the section 3C man pages.
|
||||
* Interface stability: Committed
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifdef _KERNEL
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/debug.h>
|
||||
#include <sys/kmem.h>
|
||||
#include <sys/sunddi.h>
|
||||
#else
|
||||
#include <sys/u8_textprep.h>
|
||||
#endif /* _KERNEL */
|
||||
#include <sys/byteorder.h>
|
||||
#include <sys/errno.h>
|
||||
|
||||
|
||||
/*
|
||||
* The max and min values of high and low surrogate pairs of UTF-16,
|
||||
* UTF-16 bit shift value, bit mask, and starting value outside of BMP.
|
||||
*/
|
||||
#define UCONV_U16_HI_MIN (0xd800U)
|
||||
#define UCONV_U16_HI_MAX (0xdbffU)
|
||||
#define UCONV_U16_LO_MIN (0xdc00U)
|
||||
#define UCONV_U16_LO_MAX (0xdfffU)
|
||||
#define UCONV_U16_BIT_SHIFT (0x0400U)
|
||||
#define UCONV_U16_BIT_MASK (0x0fffffU)
|
||||
#define UCONV_U16_START (0x010000U)
|
||||
|
||||
/* The maximum value of Unicode coding space and ASCII coding space. */
|
||||
#define UCONV_UNICODE_MAX (0x10ffffU)
|
||||
#define UCONV_ASCII_MAX (0x7fU)
|
||||
|
||||
/* The mask values for input and output endians. */
|
||||
#define UCONV_IN_ENDIAN_MASKS (UCONV_IN_BIG_ENDIAN | UCONV_IN_LITTLE_ENDIAN)
|
||||
#define UCONV_OUT_ENDIAN_MASKS (UCONV_OUT_BIG_ENDIAN | UCONV_OUT_LITTLE_ENDIAN)
|
||||
|
||||
/* Native and reversed endian macros. */
|
||||
#ifdef _ZFS_BIG_ENDIAN
|
||||
#define UCONV_IN_NAT_ENDIAN UCONV_IN_BIG_ENDIAN
|
||||
#define UCONV_IN_REV_ENDIAN UCONV_IN_LITTLE_ENDIAN
|
||||
#define UCONV_OUT_NAT_ENDIAN UCONV_OUT_BIG_ENDIAN
|
||||
#define UCONV_OUT_REV_ENDIAN UCONV_OUT_LITTLE_ENDIAN
|
||||
#else
|
||||
#define UCONV_IN_NAT_ENDIAN UCONV_IN_LITTLE_ENDIAN
|
||||
#define UCONV_IN_REV_ENDIAN UCONV_IN_BIG_ENDIAN
|
||||
#define UCONV_OUT_NAT_ENDIAN UCONV_OUT_LITTLE_ENDIAN
|
||||
#define UCONV_OUT_REV_ENDIAN UCONV_OUT_BIG_ENDIAN
|
||||
#endif /* _BIG_ENDIAN */
|
||||
|
||||
/* The Byte Order Mark (BOM) character in normal and reversed byte orderings. */
|
||||
#define UCONV_BOM_NORMAL (0xfeffU)
|
||||
#define UCONV_BOM_SWAPPED (0xfffeU)
|
||||
#define UCONV_BOM_SWAPPED_32 (0xfffe0000U)
|
||||
|
||||
/* UTF-32 boundaries based on UTF-8 character byte lengths. */
|
||||
#define UCONV_U8_ONE_BYTE (0x7fU)
|
||||
#define UCONV_U8_TWO_BYTES (0x7ffU)
|
||||
#define UCONV_U8_THREE_BYTES (0xffffU)
|
||||
#define UCONV_U8_FOUR_BYTES (0x10ffffU)
|
||||
|
||||
/* The common minimum and maximum values at the UTF-8 character bytes. */
|
||||
#define UCONV_U8_BYTE_MIN (0x80U)
|
||||
#define UCONV_U8_BYTE_MAX (0xbfU)
|
||||
|
||||
/*
|
||||
* The following "6" and "0x3f" came from "10xx xxxx" bit representation of
|
||||
* UTF-8 character bytes.
|
||||
*/
|
||||
#define UCONV_U8_BIT_SHIFT 6
|
||||
#define UCONV_U8_BIT_MASK 0x3f
|
||||
|
||||
/*
|
||||
* The following vector shows remaining bytes in a UTF-8 character.
|
||||
* Index will be the first byte of the character.
|
||||
*/
|
||||
static const uchar_t remaining_bytes_tbl[0x100] = {
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
|
||||
/* C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF */
|
||||
0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
|
||||
/* D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF */
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
|
||||
/* E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF */
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
|
||||
/* F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF */
|
||||
3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
/*
|
||||
* The following is a vector of bit-masks to get used bits in
|
||||
* the first byte of a UTF-8 character. Index is remaining bytes at above of
|
||||
* the character.
|
||||
*/
|
||||
static const uchar_t u8_masks_tbl[6] = { 0x00, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
|
||||
|
||||
/*
|
||||
* The following two vectors are to provide valid minimum and
|
||||
* maximum values for the 2'nd byte of a multibyte UTF-8 character for
|
||||
* better illegal sequence checking. The index value must be the value of
|
||||
* the first byte of the UTF-8 character.
|
||||
*/
|
||||
static const uchar_t valid_min_2nd_byte[0x100] = {
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
|
||||
/* C0 C1 C2 C3 C4 C5 C6 C7 */
|
||||
0, 0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
||||
|
||||
/* C8 C9 CA CB CC CD CE CF */
|
||||
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
||||
|
||||
/* D0 D1 D2 D3 D4 D5 D6 D7 */
|
||||
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
||||
|
||||
/* D8 D9 DA DB DC DD DE DF */
|
||||
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
||||
|
||||
/* E0 E1 E2 E3 E4 E5 E6 E7 */
|
||||
0xa0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
||||
|
||||
/* E8 E9 EA EB EC ED EE EF */
|
||||
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
||||
|
||||
/* F0 F1 F2 F3 F4 F5 F6 F7 */
|
||||
0x90, 0x80, 0x80, 0x80, 0x80, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
static const uchar_t valid_max_2nd_byte[0x100] = {
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
|
||||
/* C0 C1 C2 C3 C4 C5 C6 C7 */
|
||||
0, 0, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
|
||||
|
||||
/* C8 C9 CA CB CC CD CE CF */
|
||||
0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
|
||||
|
||||
/* D0 D1 D2 D3 D4 D5 D6 D7 */
|
||||
0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
|
||||
|
||||
/* D8 D9 DA DB DC DD DE DF */
|
||||
0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
|
||||
|
||||
/* E0 E1 E2 E3 E4 E5 E6 E7 */
|
||||
0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
|
||||
|
||||
/* E8 E9 EA EB EC ED EE EF */
|
||||
0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0x9f, 0xbf, 0xbf,
|
||||
|
||||
/* F0 F1 F2 F3 F4 F5 F6 F7 */
|
||||
0xbf, 0xbf, 0xbf, 0xbf, 0x8f, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
check_endian(int flag, int *in, int *out)
|
||||
{
|
||||
*in = flag & UCONV_IN_ENDIAN_MASKS;
|
||||
|
||||
/* You cannot have both. */
|
||||
if (*in == UCONV_IN_ENDIAN_MASKS)
|
||||
return (EBADF);
|
||||
|
||||
if (*in == 0)
|
||||
*in = UCONV_IN_NAT_ENDIAN;
|
||||
|
||||
*out = flag & UCONV_OUT_ENDIAN_MASKS;
|
||||
|
||||
/* You cannot have both. */
|
||||
if (*out == UCONV_OUT_ENDIAN_MASKS)
|
||||
return (EBADF);
|
||||
|
||||
if (*out == 0)
|
||||
*out = UCONV_OUT_NAT_ENDIAN;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static boolean_t
|
||||
check_bom16(const uint16_t *u16s, size_t u16l, int *in)
|
||||
{
|
||||
if (u16l > 0) {
|
||||
if (*u16s == UCONV_BOM_NORMAL) {
|
||||
*in = UCONV_IN_NAT_ENDIAN;
|
||||
return (B_TRUE);
|
||||
}
|
||||
if (*u16s == UCONV_BOM_SWAPPED) {
|
||||
*in = UCONV_IN_REV_ENDIAN;
|
||||
return (B_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
return (B_FALSE);
|
||||
}
|
||||
|
||||
static boolean_t
|
||||
check_bom32(const uint32_t *u32s, size_t u32l, int *in)
|
||||
{
|
||||
if (u32l > 0) {
|
||||
if (*u32s == UCONV_BOM_NORMAL) {
|
||||
*in = UCONV_IN_NAT_ENDIAN;
|
||||
return (B_TRUE);
|
||||
}
|
||||
if (*u32s == UCONV_BOM_SWAPPED_32) {
|
||||
*in = UCONV_IN_REV_ENDIAN;
|
||||
return (B_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
return (B_FALSE);
|
||||
}
|
||||
|
||||
int
|
||||
uconv_u16tou32(const uint16_t *u16s, size_t *utf16len,
|
||||
uint32_t *u32s, size_t *utf32len, int flag)
|
||||
{
|
||||
int inendian;
|
||||
int outendian;
|
||||
size_t u16l;
|
||||
size_t u32l;
|
||||
uint32_t hi;
|
||||
uint32_t lo;
|
||||
boolean_t do_not_ignore_null;
|
||||
|
||||
/*
|
||||
* Do preliminary validity checks on parameters and collect info on
|
||||
* endians.
|
||||
*/
|
||||
if (u16s == NULL || utf16len == NULL)
|
||||
return (EILSEQ);
|
||||
|
||||
if (u32s == NULL || utf32len == NULL)
|
||||
return (E2BIG);
|
||||
|
||||
if (check_endian(flag, &inendian, &outendian) != 0)
|
||||
return (EBADF);
|
||||
|
||||
/*
|
||||
* Initialize input and output parameter buffer indices and
|
||||
* temporary variables.
|
||||
*/
|
||||
u16l = u32l = 0;
|
||||
hi = 0;
|
||||
do_not_ignore_null = ((flag & UCONV_IGNORE_NULL) == 0);
|
||||
|
||||
/*
|
||||
* Check on the BOM at the beginning of the input buffer if required
|
||||
* and if there is indeed one, process it.
|
||||
*/
|
||||
if ((flag & UCONV_IN_ACCEPT_BOM) &&
|
||||
check_bom16(u16s, *utf16len, &inendian))
|
||||
u16l++;
|
||||
|
||||
/*
|
||||
* Reset inendian and outendian so that after this point, those can be
|
||||
* used as condition values.
|
||||
*/
|
||||
inendian &= UCONV_IN_NAT_ENDIAN;
|
||||
outendian &= UCONV_OUT_NAT_ENDIAN;
|
||||
|
||||
/*
|
||||
* If there is something in the input buffer and if necessary and
|
||||
* requested, save the BOM at the output buffer.
|
||||
*/
|
||||
if (*utf16len > 0 && *utf32len > 0 && (flag & UCONV_OUT_EMIT_BOM))
|
||||
u32s[u32l++] = (outendian) ? UCONV_BOM_NORMAL :
|
||||
UCONV_BOM_SWAPPED_32;
|
||||
|
||||
/*
|
||||
* Do conversion; if encounter a surrogate pair, assemble high and
|
||||
* low pair values to form a UTF-32 character. If a half of a pair
|
||||
* exists alone, then, either it is an illegal (EILSEQ) or
|
||||
* invalid (EINVAL) value.
|
||||
*/
|
||||
for (; u16l < *utf16len; u16l++) {
|
||||
if (u16s[u16l] == 0 && do_not_ignore_null)
|
||||
break;
|
||||
|
||||
lo = (uint32_t)((inendian) ? u16s[u16l] : BSWAP_16(u16s[u16l]));
|
||||
|
||||
if (lo >= UCONV_U16_HI_MIN && lo <= UCONV_U16_HI_MAX) {
|
||||
if (hi)
|
||||
return (EILSEQ);
|
||||
hi = lo;
|
||||
continue;
|
||||
} else if (lo >= UCONV_U16_LO_MIN && lo <= UCONV_U16_LO_MAX) {
|
||||
if (! hi)
|
||||
return (EILSEQ);
|
||||
lo = (((hi - UCONV_U16_HI_MIN) * UCONV_U16_BIT_SHIFT +
|
||||
lo - UCONV_U16_LO_MIN) & UCONV_U16_BIT_MASK)
|
||||
+ UCONV_U16_START;
|
||||
hi = 0;
|
||||
} else if (hi) {
|
||||
return (EILSEQ);
|
||||
}
|
||||
|
||||
if (u32l >= *utf32len)
|
||||
return (E2BIG);
|
||||
|
||||
u32s[u32l++] = (outendian) ? lo : BSWAP_32(lo);
|
||||
}
|
||||
|
||||
/*
|
||||
* If high half didn't see low half, then, it's most likely the input
|
||||
* parameter is incomplete.
|
||||
*/
|
||||
if (hi)
|
||||
return (EINVAL);
|
||||
|
||||
/*
|
||||
* Save the number of consumed and saved characters. They do not
|
||||
* include terminating NULL character (U+0000) at the end of
|
||||
* the input buffer (even when UCONV_IGNORE_NULL isn't specified and
|
||||
* the input buffer length is big enough to include the terminating
|
||||
* NULL character).
|
||||
*/
|
||||
*utf16len = u16l;
|
||||
*utf32len = u32l;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
uconv_u16tou8(const uint16_t *u16s, size_t *utf16len,
|
||||
uchar_t *u8s, size_t *utf8len, int flag)
|
||||
{
|
||||
int inendian;
|
||||
int outendian;
|
||||
size_t u16l;
|
||||
size_t u8l;
|
||||
uint32_t hi;
|
||||
uint32_t lo;
|
||||
boolean_t do_not_ignore_null;
|
||||
|
||||
if (u16s == NULL || utf16len == NULL)
|
||||
return (EILSEQ);
|
||||
|
||||
if (u8s == NULL || utf8len == NULL)
|
||||
return (E2BIG);
|
||||
|
||||
if (check_endian(flag, &inendian, &outendian) != 0)
|
||||
return (EBADF);
|
||||
|
||||
u16l = u8l = 0;
|
||||
hi = 0;
|
||||
do_not_ignore_null = ((flag & UCONV_IGNORE_NULL) == 0);
|
||||
|
||||
if ((flag & UCONV_IN_ACCEPT_BOM) &&
|
||||
check_bom16(u16s, *utf16len, &inendian))
|
||||
u16l++;
|
||||
|
||||
inendian &= UCONV_IN_NAT_ENDIAN;
|
||||
|
||||
for (; u16l < *utf16len; u16l++) {
|
||||
if (u16s[u16l] == 0 && do_not_ignore_null)
|
||||
break;
|
||||
|
||||
lo = (uint32_t)((inendian) ? u16s[u16l] : BSWAP_16(u16s[u16l]));
|
||||
|
||||
if (lo >= UCONV_U16_HI_MIN && lo <= UCONV_U16_HI_MAX) {
|
||||
if (hi)
|
||||
return (EILSEQ);
|
||||
hi = lo;
|
||||
continue;
|
||||
} else if (lo >= UCONV_U16_LO_MIN && lo <= UCONV_U16_LO_MAX) {
|
||||
if (! hi)
|
||||
return (EILSEQ);
|
||||
lo = (((hi - UCONV_U16_HI_MIN) * UCONV_U16_BIT_SHIFT +
|
||||
lo - UCONV_U16_LO_MIN) & UCONV_U16_BIT_MASK)
|
||||
+ UCONV_U16_START;
|
||||
hi = 0;
|
||||
} else if (hi) {
|
||||
return (EILSEQ);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we convert a UTF-32 character into a UTF-8 character.
|
||||
* Unicode coding space is between U+0000 and U+10FFFF;
|
||||
* anything bigger is an illegal character.
|
||||
*/
|
||||
if (lo <= UCONV_U8_ONE_BYTE) {
|
||||
if (u8l >= *utf8len)
|
||||
return (E2BIG);
|
||||
u8s[u8l++] = (uchar_t)lo;
|
||||
} else if (lo <= UCONV_U8_TWO_BYTES) {
|
||||
if ((u8l + 1) >= *utf8len)
|
||||
return (E2BIG);
|
||||
u8s[u8l++] = (uchar_t)(0xc0 | ((lo & 0x07c0) >> 6));
|
||||
u8s[u8l++] = (uchar_t)(0x80 | (lo & 0x003f));
|
||||
} else if (lo <= UCONV_U8_THREE_BYTES) {
|
||||
if ((u8l + 2) >= *utf8len)
|
||||
return (E2BIG);
|
||||
u8s[u8l++] = (uchar_t)(0xe0 | ((lo & 0x0f000) >> 12));
|
||||
u8s[u8l++] = (uchar_t)(0x80 | ((lo & 0x00fc0) >> 6));
|
||||
u8s[u8l++] = (uchar_t)(0x80 | (lo & 0x0003f));
|
||||
} else if (lo <= UCONV_U8_FOUR_BYTES) {
|
||||
if ((u8l + 3) >= *utf8len)
|
||||
return (E2BIG);
|
||||
u8s[u8l++] = (uchar_t)(0xf0 | ((lo & 0x01c0000) >> 18));
|
||||
u8s[u8l++] = (uchar_t)(0x80 | ((lo & 0x003f000) >> 12));
|
||||
u8s[u8l++] = (uchar_t)(0x80 | ((lo & 0x0000fc0) >> 6));
|
||||
u8s[u8l++] = (uchar_t)(0x80 | (lo & 0x000003f));
|
||||
} else {
|
||||
return (EILSEQ);
|
||||
}
|
||||
}
|
||||
|
||||
if (hi)
|
||||
return (EINVAL);
|
||||
|
||||
*utf16len = u16l;
|
||||
*utf8len = u8l;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
uconv_u32tou16(const uint32_t *u32s, size_t *utf32len,
|
||||
uint16_t *u16s, size_t *utf16len, int flag)
|
||||
{
|
||||
int inendian;
|
||||
int outendian;
|
||||
size_t u16l;
|
||||
size_t u32l;
|
||||
uint32_t hi;
|
||||
uint32_t lo;
|
||||
boolean_t do_not_ignore_null;
|
||||
|
||||
if (u32s == NULL || utf32len == NULL)
|
||||
return (EILSEQ);
|
||||
|
||||
if (u16s == NULL || utf16len == NULL)
|
||||
return (E2BIG);
|
||||
|
||||
if (check_endian(flag, &inendian, &outendian) != 0)
|
||||
return (EBADF);
|
||||
|
||||
u16l = u32l = 0;
|
||||
do_not_ignore_null = ((flag & UCONV_IGNORE_NULL) == 0);
|
||||
|
||||
if ((flag & UCONV_IN_ACCEPT_BOM) &&
|
||||
check_bom32(u32s, *utf32len, &inendian))
|
||||
u32l++;
|
||||
|
||||
inendian &= UCONV_IN_NAT_ENDIAN;
|
||||
outendian &= UCONV_OUT_NAT_ENDIAN;
|
||||
|
||||
if (*utf32len > 0 && *utf16len > 0 && (flag & UCONV_OUT_EMIT_BOM))
|
||||
u16s[u16l++] = (outendian) ? UCONV_BOM_NORMAL :
|
||||
UCONV_BOM_SWAPPED;
|
||||
|
||||
for (; u32l < *utf32len; u32l++) {
|
||||
if (u32s[u32l] == 0 && do_not_ignore_null)
|
||||
break;
|
||||
|
||||
hi = (inendian) ? u32s[u32l] : BSWAP_32(u32s[u32l]);
|
||||
|
||||
/*
|
||||
* Anything bigger than the Unicode coding space, i.e.,
|
||||
* Unicode scalar value bigger than U+10FFFF, is an illegal
|
||||
* character.
|
||||
*/
|
||||
if (hi > UCONV_UNICODE_MAX)
|
||||
return (EILSEQ);
|
||||
|
||||
/*
|
||||
* Anything bigger than U+FFFF must be converted into
|
||||
* a surrogate pair in UTF-16.
|
||||
*/
|
||||
if (hi >= UCONV_U16_START) {
|
||||
lo = ((hi - UCONV_U16_START) % UCONV_U16_BIT_SHIFT) +
|
||||
UCONV_U16_LO_MIN;
|
||||
hi = ((hi - UCONV_U16_START) / UCONV_U16_BIT_SHIFT) +
|
||||
UCONV_U16_HI_MIN;
|
||||
|
||||
if ((u16l + 1) >= *utf16len)
|
||||
return (E2BIG);
|
||||
|
||||
if (outendian) {
|
||||
u16s[u16l++] = (uint16_t)hi;
|
||||
u16s[u16l++] = (uint16_t)lo;
|
||||
} else {
|
||||
u16s[u16l++] = BSWAP_16(((uint16_t)hi));
|
||||
u16s[u16l++] = BSWAP_16(((uint16_t)lo));
|
||||
}
|
||||
} else {
|
||||
if (u16l >= *utf16len)
|
||||
return (E2BIG);
|
||||
u16s[u16l++] = (outendian) ? (uint16_t)hi :
|
||||
BSWAP_16(((uint16_t)hi));
|
||||
}
|
||||
}
|
||||
|
||||
*utf16len = u16l;
|
||||
*utf32len = u32l;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
uconv_u32tou8(const uint32_t *u32s, size_t *utf32len,
|
||||
uchar_t *u8s, size_t *utf8len, int flag)
|
||||
{
|
||||
int inendian;
|
||||
int outendian;
|
||||
size_t u32l;
|
||||
size_t u8l;
|
||||
uint32_t lo;
|
||||
boolean_t do_not_ignore_null;
|
||||
|
||||
if (u32s == NULL || utf32len == NULL)
|
||||
return (EILSEQ);
|
||||
|
||||
if (u8s == NULL || utf8len == NULL)
|
||||
return (E2BIG);
|
||||
|
||||
if (check_endian(flag, &inendian, &outendian) != 0)
|
||||
return (EBADF);
|
||||
|
||||
u32l = u8l = 0;
|
||||
do_not_ignore_null = ((flag & UCONV_IGNORE_NULL) == 0);
|
||||
|
||||
if ((flag & UCONV_IN_ACCEPT_BOM) &&
|
||||
check_bom32(u32s, *utf32len, &inendian))
|
||||
u32l++;
|
||||
|
||||
inendian &= UCONV_IN_NAT_ENDIAN;
|
||||
|
||||
for (; u32l < *utf32len; u32l++) {
|
||||
if (u32s[u32l] == 0 && do_not_ignore_null)
|
||||
break;
|
||||
|
||||
lo = (inendian) ? u32s[u32l] : BSWAP_32(u32s[u32l]);
|
||||
|
||||
if (lo <= UCONV_U8_ONE_BYTE) {
|
||||
if (u8l >= *utf8len)
|
||||
return (E2BIG);
|
||||
u8s[u8l++] = (uchar_t)lo;
|
||||
} else if (lo <= UCONV_U8_TWO_BYTES) {
|
||||
if ((u8l + 1) >= *utf8len)
|
||||
return (E2BIG);
|
||||
u8s[u8l++] = (uchar_t)(0xc0 | ((lo & 0x07c0) >> 6));
|
||||
u8s[u8l++] = (uchar_t)(0x80 | (lo & 0x003f));
|
||||
} else if (lo <= UCONV_U8_THREE_BYTES) {
|
||||
if ((u8l + 2) >= *utf8len)
|
||||
return (E2BIG);
|
||||
u8s[u8l++] = (uchar_t)(0xe0 | ((lo & 0x0f000) >> 12));
|
||||
u8s[u8l++] = (uchar_t)(0x80 | ((lo & 0x00fc0) >> 6));
|
||||
u8s[u8l++] = (uchar_t)(0x80 | (lo & 0x0003f));
|
||||
} else if (lo <= UCONV_U8_FOUR_BYTES) {
|
||||
if ((u8l + 3) >= *utf8len)
|
||||
return (E2BIG);
|
||||
u8s[u8l++] = (uchar_t)(0xf0 | ((lo & 0x01c0000) >> 18));
|
||||
u8s[u8l++] = (uchar_t)(0x80 | ((lo & 0x003f000) >> 12));
|
||||
u8s[u8l++] = (uchar_t)(0x80 | ((lo & 0x0000fc0) >> 6));
|
||||
u8s[u8l++] = (uchar_t)(0x80 | (lo & 0x000003f));
|
||||
} else {
|
||||
return (EILSEQ);
|
||||
}
|
||||
}
|
||||
|
||||
*utf32len = u32l;
|
||||
*utf8len = u8l;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
uconv_u8tou16(const uchar_t *u8s, size_t *utf8len,
|
||||
uint16_t *u16s, size_t *utf16len, int flag)
|
||||
{
|
||||
int inendian;
|
||||
int outendian;
|
||||
size_t u16l;
|
||||
size_t u8l;
|
||||
uint32_t hi;
|
||||
uint32_t lo;
|
||||
int remaining_bytes;
|
||||
int first_b;
|
||||
boolean_t do_not_ignore_null;
|
||||
|
||||
if (u8s == NULL || utf8len == NULL)
|
||||
return (EILSEQ);
|
||||
|
||||
if (u16s == NULL || utf16len == NULL)
|
||||
return (E2BIG);
|
||||
|
||||
if (check_endian(flag, &inendian, &outendian) != 0)
|
||||
return (EBADF);
|
||||
|
||||
u16l = u8l = 0;
|
||||
do_not_ignore_null = ((flag & UCONV_IGNORE_NULL) == 0);
|
||||
|
||||
outendian &= UCONV_OUT_NAT_ENDIAN;
|
||||
|
||||
if (*utf8len > 0 && *utf16len > 0 && (flag & UCONV_OUT_EMIT_BOM))
|
||||
u16s[u16l++] = (outendian) ? UCONV_BOM_NORMAL :
|
||||
UCONV_BOM_SWAPPED;
|
||||
|
||||
for (; u8l < *utf8len; ) {
|
||||
if (u8s[u8l] == 0 && do_not_ignore_null)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Collect a UTF-8 character and convert it to a UTF-32
|
||||
* character. In doing so, we screen out illegally formed
|
||||
* UTF-8 characters and treat such as illegal characters.
|
||||
* The algorithm at below also screens out anything bigger
|
||||
* than the U+10FFFF.
|
||||
*
|
||||
* See Unicode 3.1 UTF-8 Corrigendum and Unicode 3.2 for
|
||||
* more details on the illegal values of UTF-8 character
|
||||
* bytes.
|
||||
*/
|
||||
hi = (uint32_t)u8s[u8l++];
|
||||
|
||||
if (hi > UCONV_ASCII_MAX) {
|
||||
if ((remaining_bytes = remaining_bytes_tbl[hi]) == 0)
|
||||
return (EILSEQ);
|
||||
|
||||
first_b = hi;
|
||||
hi = hi & u8_masks_tbl[remaining_bytes];
|
||||
|
||||
for (; remaining_bytes > 0; remaining_bytes--) {
|
||||
/*
|
||||
* If we have no more bytes, the current
|
||||
* UTF-8 character is incomplete.
|
||||
*/
|
||||
if (u8l >= *utf8len)
|
||||
return (EINVAL);
|
||||
|
||||
lo = (uint32_t)u8s[u8l++];
|
||||
|
||||
if (first_b) {
|
||||
if (lo < valid_min_2nd_byte[first_b] ||
|
||||
lo > valid_max_2nd_byte[first_b])
|
||||
return (EILSEQ);
|
||||
first_b = 0;
|
||||
} else if (lo < UCONV_U8_BYTE_MIN ||
|
||||
lo > UCONV_U8_BYTE_MAX) {
|
||||
return (EILSEQ);
|
||||
}
|
||||
hi = (hi << UCONV_U8_BIT_SHIFT) |
|
||||
(lo & UCONV_U8_BIT_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
if (hi >= UCONV_U16_START) {
|
||||
lo = ((hi - UCONV_U16_START) % UCONV_U16_BIT_SHIFT) +
|
||||
UCONV_U16_LO_MIN;
|
||||
hi = ((hi - UCONV_U16_START) / UCONV_U16_BIT_SHIFT) +
|
||||
UCONV_U16_HI_MIN;
|
||||
|
||||
if ((u16l + 1) >= *utf16len)
|
||||
return (E2BIG);
|
||||
|
||||
if (outendian) {
|
||||
u16s[u16l++] = (uint16_t)hi;
|
||||
u16s[u16l++] = (uint16_t)lo;
|
||||
} else {
|
||||
u16s[u16l++] = BSWAP_16(((uint16_t)hi));
|
||||
u16s[u16l++] = BSWAP_16(((uint16_t)lo));
|
||||
}
|
||||
} else {
|
||||
if (u16l >= *utf16len)
|
||||
return (E2BIG);
|
||||
|
||||
u16s[u16l++] = (outendian) ? (uint16_t)hi :
|
||||
BSWAP_16(((uint16_t)hi));
|
||||
}
|
||||
}
|
||||
|
||||
*utf16len = u16l;
|
||||
*utf8len = u8l;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
uconv_u8tou32(const uchar_t *u8s, size_t *utf8len,
|
||||
uint32_t *u32s, size_t *utf32len, int flag)
|
||||
{
|
||||
int inendian;
|
||||
int outendian;
|
||||
size_t u32l;
|
||||
size_t u8l;
|
||||
uint32_t hi;
|
||||
uint32_t c;
|
||||
int remaining_bytes;
|
||||
int first_b;
|
||||
boolean_t do_not_ignore_null;
|
||||
|
||||
if (u8s == NULL || utf8len == NULL)
|
||||
return (EILSEQ);
|
||||
|
||||
if (u32s == NULL || utf32len == NULL)
|
||||
return (E2BIG);
|
||||
|
||||
if (check_endian(flag, &inendian, &outendian) != 0)
|
||||
return (EBADF);
|
||||
|
||||
u32l = u8l = 0;
|
||||
do_not_ignore_null = ((flag & UCONV_IGNORE_NULL) == 0);
|
||||
|
||||
outendian &= UCONV_OUT_NAT_ENDIAN;
|
||||
|
||||
if (*utf8len > 0 && *utf32len > 0 && (flag & UCONV_OUT_EMIT_BOM))
|
||||
u32s[u32l++] = (outendian) ? UCONV_BOM_NORMAL :
|
||||
UCONV_BOM_SWAPPED_32;
|
||||
|
||||
for (; u8l < *utf8len; ) {
|
||||
if (u8s[u8l] == 0 && do_not_ignore_null)
|
||||
break;
|
||||
|
||||
hi = (uint32_t)u8s[u8l++];
|
||||
|
||||
if (hi > UCONV_ASCII_MAX) {
|
||||
if ((remaining_bytes = remaining_bytes_tbl[hi]) == 0)
|
||||
return (EILSEQ);
|
||||
|
||||
first_b = hi;
|
||||
hi = hi & u8_masks_tbl[remaining_bytes];
|
||||
|
||||
for (; remaining_bytes > 0; remaining_bytes--) {
|
||||
if (u8l >= *utf8len)
|
||||
return (EINVAL);
|
||||
|
||||
c = (uint32_t)u8s[u8l++];
|
||||
|
||||
if (first_b) {
|
||||
if (c < valid_min_2nd_byte[first_b] ||
|
||||
c > valid_max_2nd_byte[first_b])
|
||||
return (EILSEQ);
|
||||
first_b = 0;
|
||||
} else if (c < UCONV_U8_BYTE_MIN ||
|
||||
c > UCONV_U8_BYTE_MAX) {
|
||||
return (EILSEQ);
|
||||
}
|
||||
hi = (hi << UCONV_U8_BIT_SHIFT) |
|
||||
(c & UCONV_U8_BIT_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
if (u32l >= *utf32len)
|
||||
return (E2BIG);
|
||||
|
||||
u32s[u32l++] = (outendian) ? hi : BSWAP_32(hi);
|
||||
}
|
||||
|
||||
*utf32len = u32l;
|
||||
*utf8len = u8l;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
#if defined(_KERNEL)
|
||||
EXPORT_SYMBOL(uconv_u16tou32);
|
||||
EXPORT_SYMBOL(uconv_u16tou8);
|
||||
EXPORT_SYMBOL(uconv_u32tou16);
|
||||
EXPORT_SYMBOL(uconv_u32tou8);
|
||||
EXPORT_SYMBOL(uconv_u8tou16);
|
||||
EXPORT_SYMBOL(uconv_u8tou32);
|
||||
#endif
|
@ -182,6 +182,7 @@ static void dbuf_sync_leaf_verify_bonus_dnode(dbuf_dirty_record_t *dr);
|
||||
* Global data structures and functions for the dbuf cache.
|
||||
*/
|
||||
static kmem_cache_t *dbuf_kmem_cache;
|
||||
kmem_cache_t *dbuf_dirty_kmem_cache;
|
||||
static taskq_t *dbu_evict_taskq;
|
||||
|
||||
static kthread_t *dbuf_cache_evict_thread;
|
||||
@ -966,6 +967,8 @@ dbuf_init(void)
|
||||
dbuf_kmem_cache = kmem_cache_create("dmu_buf_impl_t",
|
||||
sizeof (dmu_buf_impl_t),
|
||||
0, dbuf_cons, dbuf_dest, NULL, NULL, NULL, 0);
|
||||
dbuf_dirty_kmem_cache = kmem_cache_create("dbuf_dirty_record_t",
|
||||
sizeof (dbuf_dirty_record_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
|
||||
|
||||
for (int i = 0; i < hmsize; i++)
|
||||
mutex_init(&h->hash_mutexes[i], NULL, MUTEX_NOLOCKDEP, NULL);
|
||||
@ -1041,6 +1044,7 @@ dbuf_fini(void)
|
||||
sizeof (kmutex_t));
|
||||
|
||||
kmem_cache_destroy(dbuf_kmem_cache);
|
||||
kmem_cache_destroy(dbuf_dirty_kmem_cache);
|
||||
taskq_destroy(dbu_evict_taskq);
|
||||
|
||||
mutex_enter(&dbuf_evict_lock);
|
||||
@ -2343,7 +2347,8 @@ dbuf_dirty(dmu_buf_impl_t *db, dmu_tx_t *tx)
|
||||
* to make a copy of it so that the changes we make in this
|
||||
* transaction group won't leak out when we sync the older txg.
|
||||
*/
|
||||
dr = kmem_zalloc(sizeof (dbuf_dirty_record_t), KM_SLEEP);
|
||||
dr = kmem_cache_alloc(dbuf_dirty_kmem_cache, KM_SLEEP);
|
||||
memset(dr, 0, sizeof (*dr));
|
||||
list_link_init(&dr->dr_dirty_node);
|
||||
list_link_init(&dr->dr_dbuf_node);
|
||||
dr->dr_dnode = dn;
|
||||
@ -2526,7 +2531,7 @@ dbuf_undirty_bonus(dbuf_dirty_record_t *dr)
|
||||
mutex_destroy(&dr->dt.di.dr_mtx);
|
||||
list_destroy(&dr->dt.di.dr_children);
|
||||
}
|
||||
kmem_free(dr, sizeof (dbuf_dirty_record_t));
|
||||
kmem_cache_free(dbuf_dirty_kmem_cache, dr);
|
||||
ASSERT3U(db->db_dirtycnt, >, 0);
|
||||
db->db_dirtycnt -= 1;
|
||||
}
|
||||
@ -2616,7 +2621,7 @@ dbuf_undirty(dmu_buf_impl_t *db, dmu_tx_t *tx)
|
||||
}
|
||||
}
|
||||
|
||||
kmem_free(dr, sizeof (dbuf_dirty_record_t));
|
||||
kmem_cache_free(dbuf_dirty_kmem_cache, dr);
|
||||
|
||||
ASSERT(db->db_dirtycnt > 0);
|
||||
db->db_dirtycnt -= 1;
|
||||
@ -2941,7 +2946,7 @@ dmu_buf_set_crypt_params(dmu_buf_t *db_fake, boolean_t byteorder,
|
||||
* (see dbuf_sync_dnode_leaf_crypt()).
|
||||
*/
|
||||
ASSERT3U(db->db.db_object, ==, DMU_META_DNODE_OBJECT);
|
||||
ASSERT3U(db->db_level, ==, 0);
|
||||
ASSERT0(db->db_level);
|
||||
ASSERT(db->db_objset->os_raw_receive);
|
||||
|
||||
dmu_buf_will_dirty_impl(db_fake,
|
||||
@ -2950,6 +2955,7 @@ dmu_buf_set_crypt_params(dmu_buf_t *db_fake, boolean_t byteorder,
|
||||
dr = dbuf_find_dirty_eq(db, tx->tx_txg);
|
||||
|
||||
ASSERT3P(dr, !=, NULL);
|
||||
ASSERT3U(dr->dt.dl.dr_override_state, ==, DR_NOT_OVERRIDDEN);
|
||||
|
||||
dr->dt.dl.dr_has_raw_params = B_TRUE;
|
||||
dr->dt.dl.dr_byteorder = byteorder;
|
||||
@ -2964,10 +2970,14 @@ dbuf_override_impl(dmu_buf_impl_t *db, const blkptr_t *bp, dmu_tx_t *tx)
|
||||
struct dirty_leaf *dl;
|
||||
dbuf_dirty_record_t *dr;
|
||||
|
||||
ASSERT3U(db->db.db_object, !=, DMU_META_DNODE_OBJECT);
|
||||
ASSERT0(db->db_level);
|
||||
|
||||
dr = list_head(&db->db_dirty_records);
|
||||
ASSERT3P(dr, !=, NULL);
|
||||
ASSERT3U(dr->dr_txg, ==, tx->tx_txg);
|
||||
dl = &dr->dt.dl;
|
||||
ASSERT0(dl->dr_has_raw_params);
|
||||
dl->dr_overridden_by = *bp;
|
||||
dl->dr_override_state = DR_OVERRIDDEN;
|
||||
BP_SET_LOGICAL_BIRTH(&dl->dr_overridden_by, dr->dr_txg);
|
||||
@ -3040,6 +3050,7 @@ dmu_buf_write_embedded(dmu_buf_t *dbuf, void *data,
|
||||
ASSERT3P(dr, !=, NULL);
|
||||
ASSERT3U(dr->dr_txg, ==, tx->tx_txg);
|
||||
dl = &dr->dt.dl;
|
||||
ASSERT0(dl->dr_has_raw_params);
|
||||
encode_embedded_bp_compressed(&dl->dr_overridden_by,
|
||||
data, comp, uncompressed_size, compressed_size);
|
||||
BPE_SET_ETYPE(&dl->dr_overridden_by, etype);
|
||||
@ -5083,7 +5094,7 @@ dbuf_write_done(zio_t *zio, arc_buf_t *buf, void *vdb)
|
||||
dsl_pool_undirty_space(dmu_objset_pool(os), dr->dr_accounted,
|
||||
zio->io_txg);
|
||||
|
||||
kmem_free(dr, sizeof (dbuf_dirty_record_t));
|
||||
kmem_cache_free(dbuf_dirty_kmem_cache, dr);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1895,6 +1895,7 @@ dmu_sync_done(zio_t *zio, arc_buf_t *buf, void *varg)
|
||||
mutex_enter(&db->db_mtx);
|
||||
ASSERT(dr->dt.dl.dr_override_state == DR_IN_DMU_SYNC);
|
||||
if (zio->io_error == 0) {
|
||||
ASSERT0(dr->dt.dl.dr_has_raw_params);
|
||||
dr->dt.dl.dr_nopwrite = !!(zio->io_flags & ZIO_FLAG_NOPWRITE);
|
||||
if (dr->dt.dl.dr_nopwrite) {
|
||||
blkptr_t *bp = zio->io_bp;
|
||||
@ -2190,6 +2191,7 @@ dmu_sync(zio_t *pio, uint64_t txg, dmu_sync_cb_t *done, zgd_t *zgd)
|
||||
return (SET_ERROR(EALREADY));
|
||||
}
|
||||
|
||||
ASSERT0(dr->dt.dl.dr_has_raw_params);
|
||||
ASSERT(dr->dt.dl.dr_override_state == DR_NOT_OVERRIDDEN);
|
||||
dr->dt.dl.dr_override_state = DR_IN_DMU_SYNC;
|
||||
mutex_exit(&db->db_mtx);
|
||||
@ -2657,6 +2659,7 @@ dmu_brt_clone(objset_t *os, uint64_t object, uint64_t offset, uint64_t length,
|
||||
db = (dmu_buf_impl_t *)dbuf;
|
||||
bp = &bps[i];
|
||||
|
||||
ASSERT3U(db->db.db_object, !=, DMU_META_DNODE_OBJECT);
|
||||
ASSERT0(db->db_level);
|
||||
ASSERT(db->db_blkid != DMU_BONUS_BLKID);
|
||||
ASSERT(db->db_blkid != DMU_SPILL_BLKID);
|
||||
@ -2672,11 +2675,6 @@ dmu_brt_clone(objset_t *os, uint64_t object, uint64_t offset, uint64_t length,
|
||||
db = (dmu_buf_impl_t *)dbuf;
|
||||
bp = &bps[i];
|
||||
|
||||
ASSERT0(db->db_level);
|
||||
ASSERT(db->db_blkid != DMU_BONUS_BLKID);
|
||||
ASSERT(db->db_blkid != DMU_SPILL_BLKID);
|
||||
ASSERT(BP_IS_HOLE(bp) || dbuf->db_size == BP_GET_LSIZE(bp));
|
||||
|
||||
dmu_buf_will_clone_or_dio(dbuf, tx);
|
||||
|
||||
mutex_enter(&db->db_mtx);
|
||||
@ -2685,6 +2683,7 @@ dmu_brt_clone(objset_t *os, uint64_t object, uint64_t offset, uint64_t length,
|
||||
VERIFY(dr != NULL);
|
||||
ASSERT3U(dr->dr_txg, ==, tx->tx_txg);
|
||||
dl = &dr->dt.dl;
|
||||
ASSERT0(dl->dr_has_raw_params);
|
||||
dl->dr_overridden_by = *bp;
|
||||
if (!BP_IS_HOLE(bp) || BP_GET_LOGICAL_BIRTH(bp) != 0) {
|
||||
if (!BP_IS_EMBEDDED(bp)) {
|
||||
|
@ -180,6 +180,7 @@ dmu_write_direct(zio_t *pio, dmu_buf_impl_t *db, abd_t *data, dmu_tx_t *tx)
|
||||
if (list_next(&db->db_dirty_records, dr_head) != NULL)
|
||||
zp.zp_nopwrite = B_FALSE;
|
||||
|
||||
ASSERT0(dr_head->dt.dl.dr_has_raw_params);
|
||||
ASSERT3S(dr_head->dt.dl.dr_override_state, ==, DR_NOT_OVERRIDDEN);
|
||||
dr_head->dt.dl.dr_override_state = DR_IN_DMU_SYNC;
|
||||
|
||||
|
@ -180,6 +180,8 @@ struct send_range {
|
||||
*/
|
||||
dnode_phys_t *dnp;
|
||||
blkptr_t bp;
|
||||
/* Piggyback unmodified spill block */
|
||||
struct send_range *spill_range;
|
||||
} object;
|
||||
struct srr {
|
||||
uint32_t datablksz;
|
||||
@ -231,6 +233,8 @@ range_free(struct send_range *range)
|
||||
size_t size = sizeof (dnode_phys_t) *
|
||||
(range->sru.object.dnp->dn_extra_slots + 1);
|
||||
kmem_free(range->sru.object.dnp, size);
|
||||
if (range->sru.object.spill_range)
|
||||
range_free(range->sru.object.spill_range);
|
||||
} else if (range->type == DATA) {
|
||||
mutex_enter(&range->sru.data.lock);
|
||||
while (range->sru.data.io_outstanding)
|
||||
@ -617,7 +621,7 @@ dump_spill(dmu_send_cookie_t *dscp, const blkptr_t *bp, uint64_t object,
|
||||
drrs->drr_length = blksz;
|
||||
drrs->drr_toguid = dscp->dsc_toguid;
|
||||
|
||||
/* See comment in dump_dnode() for full details */
|
||||
/* See comment in piggyback_unmodified_spill() for full details */
|
||||
if (zfs_send_unmodified_spill_blocks &&
|
||||
(BP_GET_LOGICAL_BIRTH(bp) <= dscp->dsc_fromtxg)) {
|
||||
drrs->drr_flags |= DRR_SPILL_UNMODIFIED;
|
||||
@ -793,35 +797,6 @@ dump_dnode(dmu_send_cookie_t *dscp, const blkptr_t *bp, uint64_t object,
|
||||
(dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT), DMU_OBJECT_END) != 0)
|
||||
return (SET_ERROR(EINTR));
|
||||
|
||||
/*
|
||||
* Send DRR_SPILL records for unmodified spill blocks. This is useful
|
||||
* because changing certain attributes of the object (e.g. blocksize)
|
||||
* can cause old versions of ZFS to incorrectly remove a spill block.
|
||||
* Including these records in the stream forces an up to date version
|
||||
* to always be written ensuring they're never lost. Current versions
|
||||
* of the code which understand the DRR_FLAG_SPILL_BLOCK feature can
|
||||
* ignore these unmodified spill blocks.
|
||||
*/
|
||||
if (zfs_send_unmodified_spill_blocks &&
|
||||
(dnp->dn_flags & DNODE_FLAG_SPILL_BLKPTR) &&
|
||||
(BP_GET_LOGICAL_BIRTH(DN_SPILL_BLKPTR(dnp)) <= dscp->dsc_fromtxg)) {
|
||||
struct send_range record;
|
||||
blkptr_t *bp = DN_SPILL_BLKPTR(dnp);
|
||||
|
||||
memset(&record, 0, sizeof (struct send_range));
|
||||
record.type = DATA;
|
||||
record.object = object;
|
||||
record.eos_marker = B_FALSE;
|
||||
record.start_blkid = DMU_SPILL_BLKID;
|
||||
record.end_blkid = record.start_blkid + 1;
|
||||
record.sru.data.bp = *bp;
|
||||
record.sru.data.obj_type = dnp->dn_type;
|
||||
record.sru.data.datablksz = BP_GET_LSIZE(bp);
|
||||
|
||||
if (do_dump(dscp, &record) != 0)
|
||||
return (SET_ERROR(EINTR));
|
||||
}
|
||||
|
||||
if (dscp->dsc_err != 0)
|
||||
return (SET_ERROR(EINTR));
|
||||
|
||||
@ -911,6 +886,9 @@ do_dump(dmu_send_cookie_t *dscp, struct send_range *range)
|
||||
case OBJECT:
|
||||
err = dump_dnode(dscp, &range->sru.object.bp, range->object,
|
||||
range->sru.object.dnp);
|
||||
/* Dump piggybacked unmodified spill block */
|
||||
if (!err && range->sru.object.spill_range)
|
||||
err = do_dump(dscp, range->sru.object.spill_range);
|
||||
return (err);
|
||||
case OBJECT_RANGE: {
|
||||
ASSERT3U(range->start_blkid + 1, ==, range->end_blkid);
|
||||
@ -939,34 +917,7 @@ do_dump(dmu_send_cookie_t *dscp, struct send_range *range)
|
||||
|
||||
ASSERT3U(srdp->datablksz, ==, BP_GET_LSIZE(bp));
|
||||
ASSERT3U(range->start_blkid + 1, ==, range->end_blkid);
|
||||
if (BP_GET_TYPE(bp) == DMU_OT_SA) {
|
||||
arc_flags_t aflags = ARC_FLAG_WAIT;
|
||||
zio_flag_t zioflags = ZIO_FLAG_CANFAIL;
|
||||
|
||||
if (dscp->dsc_featureflags & DMU_BACKUP_FEATURE_RAW) {
|
||||
ASSERT(BP_IS_PROTECTED(bp));
|
||||
zioflags |= ZIO_FLAG_RAW;
|
||||
}
|
||||
|
||||
zbookmark_phys_t zb;
|
||||
ASSERT3U(range->start_blkid, ==, DMU_SPILL_BLKID);
|
||||
zb.zb_objset = dmu_objset_id(dscp->dsc_os);
|
||||
zb.zb_object = range->object;
|
||||
zb.zb_level = 0;
|
||||
zb.zb_blkid = range->start_blkid;
|
||||
|
||||
arc_buf_t *abuf = NULL;
|
||||
if (!dscp->dsc_dso->dso_dryrun && arc_read(NULL, spa,
|
||||
bp, arc_getbuf_func, &abuf, ZIO_PRIORITY_ASYNC_READ,
|
||||
zioflags, &aflags, &zb) != 0)
|
||||
return (SET_ERROR(EIO));
|
||||
|
||||
err = dump_spill(dscp, bp, zb.zb_object,
|
||||
(abuf == NULL ? NULL : abuf->b_data));
|
||||
if (abuf != NULL)
|
||||
arc_buf_destroy(abuf, &abuf);
|
||||
return (err);
|
||||
}
|
||||
if (send_do_embed(bp, dscp->dsc_featureflags)) {
|
||||
err = dump_write_embedded(dscp, range->object,
|
||||
range->start_blkid * srdp->datablksz,
|
||||
@ -975,8 +926,9 @@ do_dump(dmu_send_cookie_t *dscp, struct send_range *range)
|
||||
}
|
||||
ASSERT(range->object > dscp->dsc_resume_object ||
|
||||
(range->object == dscp->dsc_resume_object &&
|
||||
(range->start_blkid == DMU_SPILL_BLKID ||
|
||||
range->start_blkid * srdp->datablksz >=
|
||||
dscp->dsc_resume_offset));
|
||||
dscp->dsc_resume_offset)));
|
||||
/* it's a level-0 block of a regular object */
|
||||
|
||||
mutex_enter(&srdp->lock);
|
||||
@ -1006,8 +958,6 @@ do_dump(dmu_send_cookie_t *dscp, struct send_range *range)
|
||||
ASSERT(dscp->dsc_dso->dso_dryrun ||
|
||||
srdp->abuf != NULL || srdp->abd != NULL);
|
||||
|
||||
uint64_t offset = range->start_blkid * srdp->datablksz;
|
||||
|
||||
char *data = NULL;
|
||||
if (srdp->abd != NULL) {
|
||||
data = abd_to_buf(srdp->abd);
|
||||
@ -1016,6 +966,14 @@ do_dump(dmu_send_cookie_t *dscp, struct send_range *range)
|
||||
data = srdp->abuf->b_data;
|
||||
}
|
||||
|
||||
if (BP_GET_TYPE(bp) == DMU_OT_SA) {
|
||||
ASSERT3U(range->start_blkid, ==, DMU_SPILL_BLKID);
|
||||
err = dump_spill(dscp, bp, range->object, data);
|
||||
return (err);
|
||||
}
|
||||
|
||||
uint64_t offset = range->start_blkid * srdp->datablksz;
|
||||
|
||||
/*
|
||||
* If we have large blocks stored on disk but the send flags
|
||||
* don't allow us to send large blocks, we split the data from
|
||||
@ -1098,6 +1056,8 @@ range_alloc(enum type type, uint64_t object, uint64_t start_blkid,
|
||||
range->sru.data.io_outstanding = 0;
|
||||
range->sru.data.io_err = 0;
|
||||
range->sru.data.io_compressed = B_FALSE;
|
||||
} else if (type == OBJECT) {
|
||||
range->sru.object.spill_range = NULL;
|
||||
}
|
||||
return (range);
|
||||
}
|
||||
@ -1742,6 +1702,45 @@ enqueue_range(struct send_reader_thread_arg *srta, bqueue_t *q, dnode_t *dn,
|
||||
bqueue_enqueue(q, range, datablksz);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send DRR_SPILL records for unmodified spill blocks. This is useful
|
||||
* because changing certain attributes of the object (e.g. blocksize)
|
||||
* can cause old versions of ZFS to incorrectly remove a spill block.
|
||||
* Including these records in the stream forces an up to date version
|
||||
* to always be written ensuring they're never lost. Current versions
|
||||
* of the code which understand the DRR_FLAG_SPILL_BLOCK feature can
|
||||
* ignore these unmodified spill blocks.
|
||||
*
|
||||
* We piggyback the spill_range to dnode range instead of enqueueing it
|
||||
* so send_range_after won't complain.
|
||||
*/
|
||||
static uint64_t
|
||||
piggyback_unmodified_spill(struct send_reader_thread_arg *srta,
|
||||
struct send_range *range)
|
||||
{
|
||||
ASSERT3U(range->type, ==, OBJECT);
|
||||
|
||||
dnode_phys_t *dnp = range->sru.object.dnp;
|
||||
uint64_t fromtxg = srta->smta->to_arg->fromtxg;
|
||||
|
||||
if (!zfs_send_unmodified_spill_blocks ||
|
||||
!(dnp->dn_flags & DNODE_FLAG_SPILL_BLKPTR) ||
|
||||
!(BP_GET_LOGICAL_BIRTH(DN_SPILL_BLKPTR(dnp)) <= fromtxg))
|
||||
return (0);
|
||||
|
||||
blkptr_t *bp = DN_SPILL_BLKPTR(dnp);
|
||||
struct send_range *spill_range = range_alloc(DATA, range->object,
|
||||
DMU_SPILL_BLKID, DMU_SPILL_BLKID+1, B_FALSE);
|
||||
spill_range->sru.data.bp = *bp;
|
||||
spill_range->sru.data.obj_type = dnp->dn_type;
|
||||
spill_range->sru.data.datablksz = BP_GET_LSIZE(bp);
|
||||
|
||||
issue_data_read(srta, spill_range);
|
||||
range->sru.object.spill_range = spill_range;
|
||||
|
||||
return (BP_GET_LSIZE(bp));
|
||||
}
|
||||
|
||||
/*
|
||||
* This thread is responsible for two things: First, it retrieves the correct
|
||||
* blkptr in the to ds if we need to send the data because of something from
|
||||
@ -1773,17 +1772,20 @@ send_reader_thread(void *arg)
|
||||
uint64_t last_obj_exists = B_TRUE;
|
||||
while (!range->eos_marker && !srta->cancel && smta->error == 0 &&
|
||||
err == 0) {
|
||||
uint64_t spill = 0;
|
||||
switch (range->type) {
|
||||
case DATA:
|
||||
issue_data_read(srta, range);
|
||||
bqueue_enqueue(outq, range, range->sru.data.datablksz);
|
||||
range = get_next_range_nofree(inq, range);
|
||||
break;
|
||||
case HOLE:
|
||||
case OBJECT:
|
||||
spill = piggyback_unmodified_spill(srta, range);
|
||||
zfs_fallthrough;
|
||||
case HOLE:
|
||||
case OBJECT_RANGE:
|
||||
case REDACT: // Redacted blocks must exist
|
||||
bqueue_enqueue(outq, range, sizeof (*range));
|
||||
bqueue_enqueue(outq, range, sizeof (*range) + spill);
|
||||
range = get_next_range_nofree(inq, range);
|
||||
break;
|
||||
case PREVIOUSLY_REDACTED: {
|
||||
|
@ -1377,6 +1377,13 @@ dmu_tx_pool(dmu_tx_t *tx)
|
||||
return (tx->tx_pool);
|
||||
}
|
||||
|
||||
/*
|
||||
* Register a callback to be executed at the end of a TXG.
|
||||
*
|
||||
* Note: This currently exists for outside consumers, specifically the ZFS OSD
|
||||
* for Lustre. Please do not remove before checking that project. For examples
|
||||
* on how to use this see `ztest_commit_callback`.
|
||||
*/
|
||||
void
|
||||
dmu_tx_callback_register(dmu_tx_t *tx, dmu_tx_callback_func_t *func, void *data)
|
||||
{
|
||||
|
@ -566,7 +566,7 @@ dnode_undirty_dbufs(list_t *list)
|
||||
mutex_destroy(&dr->dt.di.dr_mtx);
|
||||
list_destroy(&dr->dt.di.dr_children);
|
||||
}
|
||||
kmem_free(dr, sizeof (dbuf_dirty_record_t));
|
||||
kmem_cache_free(dbuf_dirty_kmem_cache, dr);
|
||||
dbuf_rele_and_unlock(db, (void *)(uintptr_t)txg, B_FALSE);
|
||||
}
|
||||
}
|
||||
|
@ -2205,10 +2205,11 @@ vdev_open(vdev_t *vd)
|
||||
vd->vdev_max_asize = max_asize;
|
||||
|
||||
/*
|
||||
* If the vdev_ashift was not overridden at creation time,
|
||||
* If the vdev_ashift was not overridden at creation time
|
||||
* (0) or the override value is impossible for the device,
|
||||
* then set it the logical ashift and optimize the ashift.
|
||||
*/
|
||||
if (vd->vdev_ashift == 0) {
|
||||
if (vd->vdev_ashift < vd->vdev_logical_ashift) {
|
||||
vd->vdev_ashift = vd->vdev_logical_ashift;
|
||||
|
||||
if (vd->vdev_logical_ashift > ASHIFT_MAX) {
|
||||
|
@ -58,9 +58,9 @@
|
||||
#include <sys/zfs_znode.h>
|
||||
|
||||
/*
|
||||
* Enable the experimental block cloning feature. If this setting is 0, then
|
||||
* even if feature@block_cloning is enabled, attempts to clone blocks will act
|
||||
* as though the feature is disabled.
|
||||
* Enables access to the block cloning feature. If this setting is 0, then even
|
||||
* if feature@block_cloning is enabled, using functions and system calls that
|
||||
* attempt to clone blocks will act as though the feature is disabled.
|
||||
*/
|
||||
int zfs_bclone_enabled = 1;
|
||||
|
||||
|
@ -147,6 +147,12 @@ tags = ['functional', 'largest_pool']
|
||||
tests = ['longname_001_pos', 'longname_002_pos', 'longname_003_pos']
|
||||
tags = ['functional', 'longname']
|
||||
|
||||
[tests/functional/luks:Linux]
|
||||
pre =
|
||||
post =
|
||||
tests = ['luks_sanity']
|
||||
tags = ['functional', 'luks']
|
||||
|
||||
[tests/functional/mmap:Linux]
|
||||
tests = ['mmap_libaio_001_pos', 'mmap_sync_001_pos']
|
||||
tags = ['functional', 'mmap']
|
||||
|
@ -213,6 +213,7 @@ maybe = {
|
||||
'cli_root/zfs_unshare/zfs_unshare_006_pos': ['SKIP', na_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_devices_missing': ['FAIL', 16669],
|
||||
'cli_root/zpool_import/zpool_import_missing_003_pos': ['SKIP', 6839],
|
||||
'cli_root/zpool_initialize/zpool_initialize_import_export':
|
||||
['FAIL', 11948],
|
||||
@ -275,7 +276,8 @@ if sys.platform.startswith('freebsd'):
|
||||
'pool_checkpoint/checkpoint_big_rewind': ['FAIL', 12622],
|
||||
'pool_checkpoint/checkpoint_indirect': ['FAIL', 12623],
|
||||
'resilver/resilver_restart_001': ['FAIL', known_reason],
|
||||
'snapshot/snapshot_002_pos': ['FAIL', '14831'],
|
||||
'snapshot/snapshot_002_pos': ['FAIL', 14831],
|
||||
'zvol/zvol_misc/zvol_misc_volmode': ['FAIL', 16668],
|
||||
'bclone/bclone_crossfs_corner_cases': ['SKIP', cfr_cross_reason],
|
||||
'bclone/bclone_crossfs_corner_cases_limited':
|
||||
['SKIP', cfr_cross_reason],
|
||||
|
@ -19,9 +19,9 @@
|
||||
*/
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <linux/fs.h>
|
||||
#include <err.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
@ -129,6 +129,7 @@ export SYSTEM_FILES_LINUX='attr
|
||||
blkdiscard
|
||||
blockdev
|
||||
chattr
|
||||
cryptsetup
|
||||
exportfs
|
||||
fallocate
|
||||
flock
|
||||
|
@ -80,7 +80,8 @@ if BUILD_LINUX
|
||||
nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
|
||||
functional/simd/simd_supported.ksh \
|
||||
functional/tmpfile/cleanup.ksh \
|
||||
functional/tmpfile/setup.ksh
|
||||
functional/tmpfile/setup.ksh \
|
||||
functional/luks/luks_sanity.ksh
|
||||
endif
|
||||
|
||||
nobase_dist_datadir_zfs_tests_tests_DATA += \
|
||||
|
@ -148,9 +148,9 @@ done
|
||||
|
||||
# Foreach test create pool, add -n devices and check output.
|
||||
for (( i=0; i < ${#tests[@]}; i+=1 )); do
|
||||
typeset tree="${tests[$i].tree}"
|
||||
typeset add="${tests[$i].add}"
|
||||
typeset want="${tests[$i].want}"
|
||||
tree="${tests[$i].tree}"
|
||||
add="${tests[$i].add}"
|
||||
want="${tests[$i].want}"
|
||||
|
||||
log_must eval zpool create "$TESTPOOL" $tree
|
||||
log_must poolexists "$TESTPOOL"
|
||||
|
@ -124,8 +124,8 @@ done
|
||||
|
||||
# Foreach test create pool, add -n devices and check output.
|
||||
for (( i=0; i < ${#tests[@]}; i+=1 )); do
|
||||
typeset tree="${tests[$i].tree}"
|
||||
typeset want="${tests[$i].want}"
|
||||
tree="${tests[$i].tree}"
|
||||
want="${tests[$i].want}"
|
||||
|
||||
typeset out="$(log_must eval "zpool create -n '$TESTPOOL' $tree" | \
|
||||
sed /^SUCCESS/d)"
|
||||
|
@ -133,9 +133,9 @@ done
|
||||
|
||||
# Foreach test create pool, add -n devices and check output.
|
||||
for (( i=0; i < ${#tests[@]}; i+=1 )); do
|
||||
typeset tree="${tests[$i].tree}"
|
||||
typeset devs="${tests[$i].devs}"
|
||||
typeset want="${tests[$i].want}"
|
||||
tree="${tests[$i].tree}"
|
||||
devs="${tests[$i].devs}"
|
||||
want="${tests[$i].want}"
|
||||
|
||||
log_must eval zpool create "$TESTPOOL" $tree
|
||||
log_must poolexists "$TESTPOOL"
|
||||
|
90
sys/contrib/openzfs/tests/zfs-tests/tests/functional/luks/luks_sanity.ksh
Executable file
90
sys/contrib/openzfs/tests/zfs-tests/tests/functional/luks/luks_sanity.ksh
Executable file
@ -0,0 +1,90 @@
|
||||
#!/bin/ksh -p
|
||||
#
|
||||
# CDDL HEADER START
|
||||
#
|
||||
# The contents of this file are subject to the terms of the
|
||||
# Common Development and Distribution License (the "License").
|
||||
# You may not use this file except in compliance with the License.
|
||||
#
|
||||
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
# or https://opensource.org/licenses/CDDL-1.0.
|
||||
# See the License for the specific language governing permissions
|
||||
# and limitations under the License.
|
||||
#
|
||||
# When distributing Covered Code, include this CDDL HEADER in each
|
||||
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
# If applicable, add the following below this CDDL HEADER, with the
|
||||
# fields enclosed by brackets "[]" replaced with your own identifying
|
||||
# information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
#
|
||||
# CDDL HEADER END
|
||||
#
|
||||
|
||||
#
|
||||
# Copyright (c) 2024 by Lawrence Livermore National Security, LLC.
|
||||
# Use is subject to license terms.
|
||||
#
|
||||
|
||||
# DESCRIPTION:
|
||||
# Verify ZFS works on a LUKS-backed pool
|
||||
#
|
||||
# STRATEGY:
|
||||
# 1. Create a LUKS device
|
||||
# 2. Make a pool with it
|
||||
# 3. Write files to the pool
|
||||
# 4. Verify no errors
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
|
||||
verify_runnable "both"
|
||||
|
||||
VDEV=$(mktemp --suffix=luks_sanity)
|
||||
TESTPOOL=testpool
|
||||
|
||||
function cleanup
|
||||
{
|
||||
log_must zpool destroy $TESTPOOL
|
||||
|
||||
log_must cryptsetup luksClose /dev/mapper/luksdev
|
||||
log_must rm -f $VDEV
|
||||
}
|
||||
|
||||
log_assert "Verify ZFS on LUKS works"
|
||||
log_onexit cleanup
|
||||
|
||||
PASS="fdsjfosdijfsdkjsldfjdlk"
|
||||
|
||||
# Make a small LUKS device since LUKS formatting takes time and we want to
|
||||
# make this test run as quickly as possible.
|
||||
truncate -s 100M $VDEV
|
||||
|
||||
log_must cryptsetup luksFormat --type luks2 $VDEV <<< $PASS
|
||||
log_must cryptsetup luksOpen $VDEV luksdev <<< $PASS
|
||||
|
||||
log_must zpool create $TESTPOOL /dev/mapper/luksdev
|
||||
|
||||
CPUS=$(get_num_cpus)
|
||||
|
||||
# Use these specific size and offset ranges as they often cause errors with
|
||||
# https://github.com/openzfs/zfs/issues/16631
|
||||
# and we want to try to test for that.
|
||||
for SIZE in {70..100} ; do
|
||||
for OFF in {70..100} ; do
|
||||
for i in {1..$CPUS} ; do
|
||||
dd if=/dev/urandom of=/$TESTPOOL/file$i-bs$SIZE-off$OFF \
|
||||
seek=$OFF bs=$SIZE count=1 &>/dev/null &
|
||||
done
|
||||
wait
|
||||
done
|
||||
sync_pool $TESTPOOL
|
||||
rm -f /$TESTPOOL/file*
|
||||
done
|
||||
|
||||
# Verify no read/write/checksum errors. Don't use JSON here so that we could
|
||||
# could potentially backport this test case to the 2.2.x branch.
|
||||
if zpool status -e | grep -q "luksdev" ; then
|
||||
log_note "$(zpool status -v)"
|
||||
log_fail "Saw errors writing to LUKS device"
|
||||
fi
|
||||
|
||||
log_pass "Verified ZFS on LUKS works"
|
@ -30,7 +30,7 @@
|
||||
|
||||
/*
|
||||
* This tests the vdev_disk page alignment check callback
|
||||
* vdev_disk_check_pages_cb(). For now, this test includes a copy of that
|
||||
* vdev_disk_check_alignment_cb(). For now, this test includes a copy of that
|
||||
* function from module/os/linux/zfs/vdev_disk.c. If you change it here,
|
||||
* remember to change it there too, and add tests data here to validate the
|
||||
* change you're making.
|
||||
@ -38,36 +38,69 @@
|
||||
|
||||
struct page;
|
||||
|
||||
/*
|
||||
* This is spl_pagesize() in userspace, which requires linking libspl, but
|
||||
* would also then use the platform page size, which isn't what we want for
|
||||
* a test. To keep the check callback the same as the real one, we just
|
||||
* redefine it.
|
||||
*/
|
||||
#undef PAGESIZE
|
||||
#define PAGESIZE (4096)
|
||||
|
||||
typedef struct {
|
||||
uint32_t bmask;
|
||||
uint32_t npages;
|
||||
uint32_t end;
|
||||
} vdev_disk_check_pages_t;
|
||||
size_t blocksize;
|
||||
int seen_first;
|
||||
int seen_last;
|
||||
} vdev_disk_check_alignment_t;
|
||||
|
||||
static int
|
||||
vdev_disk_check_pages_cb(struct page *page, size_t off, size_t len, void *priv)
|
||||
vdev_disk_check_alignment_cb(struct page *page, size_t off, size_t len,
|
||||
void *priv)
|
||||
{
|
||||
(void) page;
|
||||
vdev_disk_check_pages_t *s = priv;
|
||||
vdev_disk_check_alignment_t *s = priv;
|
||||
|
||||
/*
|
||||
* If we didn't finish on a block size boundary last time, then there
|
||||
* would be a gap if we tried to use this ABD as-is, so abort.
|
||||
* The cardinal rule: a single on-disk block must never cross an
|
||||
* physical (order-0) page boundary, as the kernel expects to be able
|
||||
* to split at both LBS and page boundaries.
|
||||
*
|
||||
* This implies various alignment rules for the blocks in this
|
||||
* (possibly compound) page, which we can check for.
|
||||
*/
|
||||
if (s->end != 0)
|
||||
|
||||
/*
|
||||
* If the previous page did not end on a page boundary, then we
|
||||
* can't proceed without creating a hole.
|
||||
*/
|
||||
if (s->seen_last)
|
||||
return (1);
|
||||
|
||||
/* This page must contain only whole LBS-sized blocks. */
|
||||
if (!IS_P2ALIGNED(len, s->blocksize))
|
||||
return (1);
|
||||
|
||||
/*
|
||||
* Note if we're taking less than a full block, so we can check it
|
||||
* above on the next call.
|
||||
* If this is not the first page in the ABD, then the data must start
|
||||
* on a page-aligned boundary (so the kernel can split on page
|
||||
* boundaries without having to deal with a hole). If it is, then
|
||||
* it can start on LBS-alignment.
|
||||
*/
|
||||
s->end = (off+len) & s->bmask;
|
||||
|
||||
/* All blocks after the first must start on a block size boundary. */
|
||||
if (s->npages != 0 && (off & s->bmask) != 0)
|
||||
if (s->seen_first) {
|
||||
if (!IS_P2ALIGNED(off, PAGESIZE))
|
||||
return (1);
|
||||
} else {
|
||||
if (!IS_P2ALIGNED(off, s->blocksize))
|
||||
return (1);
|
||||
s->seen_first = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this data does not end on a page-aligned boundary, then this
|
||||
* must be the last page in the ABD, for the same reason.
|
||||
*/
|
||||
s->seen_last = !IS_P2ALIGNED(off+len, PAGESIZE);
|
||||
|
||||
s->npages++;
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -75,8 +108,8 @@ typedef struct {
|
||||
/* test name */
|
||||
const char *name;
|
||||
|
||||
/* blocks size mask */
|
||||
uint32_t mask;
|
||||
/* stored block size */
|
||||
uint32_t blocksize;
|
||||
|
||||
/* amount of data to take */
|
||||
size_t size;
|
||||
@ -89,39 +122,39 @@ static const page_test_t valid_tests[] = {
|
||||
/* 512B block tests */
|
||||
{
|
||||
"512B blocks, 4K single page",
|
||||
0x1ff, 0x1000, {
|
||||
512, 0x1000, {
|
||||
{ 0x0, 0x1000 },
|
||||
},
|
||||
}, {
|
||||
"512B blocks, 1K at start of page",
|
||||
0x1ff, 0x400, {
|
||||
512, 0x400, {
|
||||
{ 0x0, 0x1000 },
|
||||
},
|
||||
}, {
|
||||
"512B blocks, 1K at end of page",
|
||||
0x1ff, 0x400, {
|
||||
512, 0x400, {
|
||||
{ 0x0c00, 0x0400 },
|
||||
},
|
||||
}, {
|
||||
"512B blocks, 1K within page, 512B start offset",
|
||||
0x1ff, 0x400, {
|
||||
512, 0x400, {
|
||||
{ 0x0200, 0x0e00 },
|
||||
},
|
||||
}, {
|
||||
"512B blocks, 8K across 2x4K pages",
|
||||
0x1ff, 0x2000, {
|
||||
512, 0x2000, {
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x1000 },
|
||||
},
|
||||
}, {
|
||||
"512B blocks, 4K across two pages, 2K start offset",
|
||||
0x1ff, 0x1000, {
|
||||
512, 0x1000, {
|
||||
{ 0x0800, 0x0800 },
|
||||
{ 0x0, 0x0800 },
|
||||
},
|
||||
}, {
|
||||
"512B blocks, 16K across 5x4K pages, 512B start offset",
|
||||
0x1ff, 0x4000, {
|
||||
512, 0x4000, {
|
||||
{ 0x0200, 0x0e00 },
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x1000 },
|
||||
@ -130,7 +163,7 @@ static const page_test_t valid_tests[] = {
|
||||
},
|
||||
}, {
|
||||
"512B blocks, 64K data, 8x8K compound pages",
|
||||
0x1ff, 0x10000, {
|
||||
512, 0x10000, {
|
||||
{ 0x0, 0x2000 },
|
||||
{ 0x0, 0x2000 },
|
||||
{ 0x0, 0x2000 },
|
||||
@ -142,7 +175,7 @@ static const page_test_t valid_tests[] = {
|
||||
},
|
||||
}, {
|
||||
"512B blocks, 64K data, 9x8K compound pages, 512B start offset",
|
||||
0x1ff, 0x10000, {
|
||||
512, 0x10000, {
|
||||
{ 0x0200, 0x1e00 },
|
||||
{ 0x0, 0x2000 },
|
||||
{ 0x0, 0x2000 },
|
||||
@ -155,7 +188,7 @@ static const page_test_t valid_tests[] = {
|
||||
},
|
||||
}, {
|
||||
"512B blocks, 64K data, 2x16K compound pages, 8x4K pages",
|
||||
0x1ff, 0x10000, {
|
||||
512, 0x10000, {
|
||||
{ 0x0, 0x8000 },
|
||||
{ 0x0, 0x8000 },
|
||||
{ 0x0, 0x1000 },
|
||||
@ -169,7 +202,7 @@ static const page_test_t valid_tests[] = {
|
||||
},
|
||||
}, {
|
||||
"512B blocks, 64K data, mixed 4K/8K/16K pages",
|
||||
0x1ff, 0x10000, {
|
||||
512, 0x10000, {
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x2000 },
|
||||
{ 0x0, 0x1000 },
|
||||
@ -183,7 +216,7 @@ static const page_test_t valid_tests[] = {
|
||||
},
|
||||
}, {
|
||||
"512B blocks, 64K data, mixed 4K/8K/16K pages, 1K start offset",
|
||||
0x1ff, 0x10000, {
|
||||
512, 0x10000, {
|
||||
{ 0x0400, 0x0c00 },
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x1000 },
|
||||
@ -200,48 +233,18 @@ static const page_test_t valid_tests[] = {
|
||||
/* 4K block tests */
|
||||
{
|
||||
"4K blocks, 4K single page",
|
||||
0xfff, 0x1000, {
|
||||
4096, 0x1000, {
|
||||
{ 0x0, 0x1000 },
|
||||
},
|
||||
}, {
|
||||
"4K blocks, 1K at start of page",
|
||||
0xfff, 0x400, {
|
||||
{ 0x0, 0x1000 },
|
||||
},
|
||||
}, {
|
||||
"4K blocks, 1K at end of page",
|
||||
0xfff, 0x400, {
|
||||
{ 0x0c00, 0x0400 },
|
||||
},
|
||||
}, {
|
||||
"4K blocks, 1K within page, 512B start offset",
|
||||
0xfff, 0x400, {
|
||||
{ 0x0200, 0x0e00 },
|
||||
},
|
||||
}, {
|
||||
"4K blocks, 8K across 2x4K pages",
|
||||
0xfff, 0x2000, {
|
||||
4096, 0x2000, {
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x1000 },
|
||||
},
|
||||
}, {
|
||||
"4K blocks, 4K across two pages, 2K start offset",
|
||||
0xfff, 0x1000, {
|
||||
{ 0x0800, 0x0800 },
|
||||
{ 0x0, 0x0800 },
|
||||
},
|
||||
}, {
|
||||
"4K blocks, 16K across 5x4K pages, 512B start offset",
|
||||
0xfff, 0x4000, {
|
||||
{ 0x0200, 0x0e00 },
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x0200 },
|
||||
},
|
||||
}, {
|
||||
"4K blocks, 64K data, 8x8K compound pages",
|
||||
0xfff, 0x10000, {
|
||||
4096, 0x10000, {
|
||||
{ 0x0, 0x2000 },
|
||||
{ 0x0, 0x2000 },
|
||||
{ 0x0, 0x2000 },
|
||||
@ -251,22 +254,9 @@ static const page_test_t valid_tests[] = {
|
||||
{ 0x0, 0x2000 },
|
||||
{ 0x0, 0x2000 },
|
||||
},
|
||||
}, {
|
||||
"4K blocks, 64K data, 9x8K compound pages, 512B start offset",
|
||||
0xfff, 0x10000, {
|
||||
{ 0x0200, 0x1e00 },
|
||||
{ 0x0, 0x2000 },
|
||||
{ 0x0, 0x2000 },
|
||||
{ 0x0, 0x2000 },
|
||||
{ 0x0, 0x2000 },
|
||||
{ 0x0, 0x2000 },
|
||||
{ 0x0, 0x2000 },
|
||||
{ 0x0, 0x2000 },
|
||||
{ 0x0, 0x0200 },
|
||||
},
|
||||
}, {
|
||||
"4K blocks, 64K data, 2x16K compound pages, 8x4K pages",
|
||||
0xfff, 0x10000, {
|
||||
4096, 0x10000, {
|
||||
{ 0x0, 0x8000 },
|
||||
{ 0x0, 0x8000 },
|
||||
{ 0x0, 0x1000 },
|
||||
@ -280,7 +270,7 @@ static const page_test_t valid_tests[] = {
|
||||
},
|
||||
}, {
|
||||
"4K blocks, 64K data, mixed 4K/8K/16K pages",
|
||||
0xfff, 0x10000, {
|
||||
4096, 0x10000, {
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x2000 },
|
||||
{ 0x0, 0x1000 },
|
||||
@ -292,9 +282,78 @@ static const page_test_t valid_tests[] = {
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x2000 },
|
||||
},
|
||||
},
|
||||
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
static const page_test_t invalid_tests[] = {
|
||||
/*
|
||||
* Gang tests. Composed of lots of smaller allocations, rarely properly
|
||||
* aligned.
|
||||
*/
|
||||
{
|
||||
"512B blocks, 16K data, 512 leader (gang block simulation)",
|
||||
512, 0x8000, {
|
||||
{ 0x0, 0x0200 },
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x0c00 },
|
||||
},
|
||||
}, {
|
||||
"4K blocks, 32K data, 2 incompatible spans "
|
||||
"(gang abd simulation)",
|
||||
4096, 0x8000, {
|
||||
{ 0x0800, 0x0800 },
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x0800 },
|
||||
{ 0x0800, 0x0800 },
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x0800 },
|
||||
},
|
||||
},
|
||||
|
||||
/*
|
||||
* Blocks must not span multiple physical pages. These tests used to
|
||||
* be considered valid, but were since found to be invalid and were
|
||||
* moved here.
|
||||
*/
|
||||
{
|
||||
"4K blocks, 4K across two pages, 2K start offset",
|
||||
4096, 0x1000, {
|
||||
{ 0x0800, 0x0800 },
|
||||
{ 0x0, 0x0800 },
|
||||
},
|
||||
}, {
|
||||
"4K blocks, 16K across 5x4K pages, 512B start offset",
|
||||
4096, 0x4000, {
|
||||
{ 0x0200, 0x0e00 },
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x0200 },
|
||||
},
|
||||
}, {
|
||||
"4K blocks, 64K data, 9x8K compound pages, 512B start offset",
|
||||
4096, 0x10000, {
|
||||
{ 0x0200, 0x1e00 },
|
||||
{ 0x0, 0x2000 },
|
||||
{ 0x0, 0x2000 },
|
||||
{ 0x0, 0x2000 },
|
||||
{ 0x0, 0x2000 },
|
||||
{ 0x0, 0x2000 },
|
||||
{ 0x0, 0x2000 },
|
||||
{ 0x0, 0x2000 },
|
||||
{ 0x0, 0x0200 },
|
||||
},
|
||||
}, {
|
||||
"4K blocks, 64K data, mixed 4K/8K/16K pages, 1K start offset",
|
||||
0xfff, 0x10000, {
|
||||
4096, 0x10000, {
|
||||
{ 0x0400, 0x0c00 },
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x1000 },
|
||||
@ -308,35 +367,40 @@ static const page_test_t valid_tests[] = {
|
||||
},
|
||||
},
|
||||
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
static const page_test_t invalid_tests[] = {
|
||||
/*
|
||||
* This is the very typical case of a 4K block being allocated from
|
||||
* the middle of a mixed-used slab backed by a higher-order compound
|
||||
* page.
|
||||
*/
|
||||
{
|
||||
"512B blocks, 16K data, 512 leader (gang block simulation)",
|
||||
0x1ff, 0x8000, {
|
||||
{ 0x0, 0x0200 },
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x0c00 },
|
||||
"4K blocks, 4K data from compound slab, 2K-align offset",
|
||||
4096, 0x1000, {
|
||||
{ 0x1800, 0x6800 }
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Blocks smaller than LBS should never be possible, but used to be by
|
||||
* accident (see GH#16990). We test for and reject them just to be
|
||||
* sure.
|
||||
*/
|
||||
{
|
||||
"4K blocks, 1K at end of page",
|
||||
4096, 0x400, {
|
||||
{ 0x0c00, 0x0400 },
|
||||
},
|
||||
}, {
|
||||
"4K blocks, 32K data, 2 incompatible spans "
|
||||
"(gang abd simulation)",
|
||||
0xfff, 0x8000, {
|
||||
{ 0x0800, 0x0800 },
|
||||
"4K blocks, 1K at start of page",
|
||||
4096, 0x400, {
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x0800 },
|
||||
{ 0x0800, 0x0800 },
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x1000 },
|
||||
{ 0x0, 0x0800 },
|
||||
},
|
||||
}, {
|
||||
"4K blocks, 1K within page, 512B start offset",
|
||||
4096, 0x400, {
|
||||
{ 0x0200, 0x0e00 },
|
||||
},
|
||||
},
|
||||
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
@ -345,10 +409,8 @@ run_test(const page_test_t *test, bool verbose)
|
||||
{
|
||||
size_t rem = test->size;
|
||||
|
||||
vdev_disk_check_pages_t s = {
|
||||
.bmask = 0xfff,
|
||||
.npages = 0,
|
||||
.end = 0,
|
||||
vdev_disk_check_alignment_t s = {
|
||||
.blocksize = test->blocksize,
|
||||
};
|
||||
|
||||
for (int i = 0; test->pages[i][1] > 0; i++) {
|
||||
@ -362,7 +424,7 @@ run_test(const page_test_t *test, bool verbose)
|
||||
"rem %lx, take %lx\n",
|
||||
i, off, len, rem, take);
|
||||
|
||||
if (vdev_disk_check_pages_cb(NULL, off, take, &s)) {
|
||||
if (vdev_disk_check_alignment_cb(NULL, off, take, &s)) {
|
||||
if (verbose)
|
||||
printf(" ABORT: misalignment detected, "
|
||||
"rem %lx\n", rem);
|
||||
@ -389,7 +451,7 @@ run_test_set(const page_test_t *tests, bool want, int *ntests, int *npassed)
|
||||
for (const page_test_t *test = &tests[0]; test->name; test++) {
|
||||
bool pass = (run_test(test, false) == want);
|
||||
if (pass) {
|
||||
printf("%s: PASS\n", test->name);
|
||||
printf("%c %s: PASS\n", want ? '+' : '-', test->name);
|
||||
(*npassed)++;
|
||||
} else {
|
||||
printf("%s: FAIL [expected %s, got %s]\n", test->name,
|
||||
|
@ -202,8 +202,7 @@ SRCS+= abd_os.c \
|
||||
zvol_os.c
|
||||
|
||||
#unicode
|
||||
SRCS+= uconv.c \
|
||||
u8_textprep.c
|
||||
SRCS+= u8_textprep.c
|
||||
|
||||
#zcommon
|
||||
SRCS+= zfeature_common.c \
|
||||
|
@ -226,8 +226,8 @@
|
||||
/* DECLARE_EVENT_CLASS() is available */
|
||||
/* #undef HAVE_DECLARE_EVENT_CLASS */
|
||||
|
||||
/* dequeue_signal() takes a task argument */
|
||||
/* #undef HAVE_DEQUEUE_SIGNAL_3ARG_TASK */
|
||||
/* 3-arg dequeue_signal() takes a type argument */
|
||||
/* #undef HAVE_DEQUEUE_SIGNAL_3ARG_TYPE */
|
||||
|
||||
/* dequeue_signal() takes 4 arguments */
|
||||
/* #undef HAVE_DEQUEUE_SIGNAL_4ARG */
|
||||
@ -600,6 +600,9 @@
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the 'strerror_l' function. */
|
||||
#define HAVE_STRERROR_L 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#define HAVE_STRINGS_H 1
|
||||
|
||||
@ -681,21 +684,18 @@
|
||||
/* generic_copy_file_range() is available */
|
||||
/* #undef HAVE_VFS_GENERIC_COPY_FILE_RANGE */
|
||||
|
||||
/* invalidate_folio exists */
|
||||
/* #undef HAVE_VFS_INVALIDATE_FOLIO */
|
||||
|
||||
/* All required iov_iter interfaces are available */
|
||||
/* #undef HAVE_VFS_IOV_ITER */
|
||||
|
||||
/* migrate_folio exists */
|
||||
/* #undef HAVE_VFS_MIGRATE_FOLIO */
|
||||
|
||||
/* address_space_operations->readpages exists */
|
||||
/* #undef HAVE_VFS_READPAGES */
|
||||
|
||||
/* read_folio exists */
|
||||
/* #undef HAVE_VFS_READ_FOLIO */
|
||||
|
||||
/* release_folio exists */
|
||||
/* #undef HAVE_VFS_RELEASE_FOLIO */
|
||||
|
||||
/* fops->remap_file_range() is available */
|
||||
/* #undef HAVE_VFS_REMAP_FILE_RANGE */
|
||||
|
||||
@ -792,7 +792,7 @@
|
||||
/* #undef ZFS_DEVICE_MINOR */
|
||||
|
||||
/* Define the project alias string. */
|
||||
#define ZFS_META_ALIAS "zfs-2.3.99-31-FreeBSD_gb2f6de7b5"
|
||||
#define ZFS_META_ALIAS "zfs-2.3.99-64-FreeBSD_g1c9a4c8cb"
|
||||
|
||||
/* Define the project author. */
|
||||
#define ZFS_META_AUTHOR "OpenZFS"
|
||||
@ -822,7 +822,7 @@
|
||||
#define ZFS_META_NAME "zfs"
|
||||
|
||||
/* Define the project release. */
|
||||
#define ZFS_META_RELEASE "31-FreeBSD_gb2f6de7b5"
|
||||
#define ZFS_META_RELEASE "64-FreeBSD_g1c9a4c8cb"
|
||||
|
||||
/* Define the project version. */
|
||||
#define ZFS_META_VERSION "2.3.99"
|
||||
|
@ -1 +1 @@
|
||||
#define ZFS_META_GITREV "zfs-2.3.99-31-gb2f6de7b5"
|
||||
#define ZFS_META_GITREV "zfs-2.3.99-64-g1c9a4c8cb"
|
||||
|
Loading…
Reference in New Issue
Block a user