mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-24 11:18:52 +03:00
Compare commits
59 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c840612ee1 | |||
| 65579f4cba | |||
| 2032f21857 | |||
| dc58baf9d1 | |||
| 06a88f9d13 | |||
| 88ce22ed95 | |||
| 366dad1cac | |||
| 1dc5088e6a | |||
| 135fffbc3e | |||
| 18065e9296 | |||
| 00ee7f9430 | |||
| 3662c7f33c | |||
| 29bda86d7b | |||
| 6788dcd47c | |||
| beb25b936b | |||
| d857aea6d4 | |||
| f7ab47908b | |||
| d56f3cb331 | |||
| d8594ba2b8 | |||
| a65bb7c518 | |||
| 328a823848 | |||
| 8bbd86693e | |||
| 36c315571c | |||
| 8010a8a3ca | |||
| a1d839eddd | |||
| 411249498e | |||
| 9a5027ccce | |||
| a50b8a727c | |||
| bf4b271af1 | |||
| 38ed094954 | |||
| 497b9291d1 | |||
| 60b37bc647 | |||
| 44e6a07bff | |||
| 08d34f28f1 | |||
| 1397bf1e0e | |||
| c87a1f7137 | |||
| b2d052e617 | |||
| 23d4ce66f8 | |||
| af9ae623e0 | |||
| e35fdeb411 | |||
| 00ab445b51 | |||
| e3fe4293f7 | |||
| e51c8c0e83 | |||
| 0afe9b67c2 | |||
| 4f77b30135 | |||
| 445879656b | |||
| 0dcb882037 | |||
| 2fec0e3add | |||
| b8c5d43f34 | |||
| b3922eb8c1 | |||
| 8ebb586e0e | |||
| f4ead6682c | |||
| a82b804250 | |||
| 8757506930 | |||
| c1f1464525 | |||
| 51ab0e2185 | |||
| 51421ecbe8 | |||
| bbbf438d66 | |||
| 2d9ba1e3c8 |
@@ -6,12 +6,19 @@
|
|||||||
|
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
# We've been seeing this script take over 15min to run. This may or
|
# The default 'azure.archive.ubuntu.com' mirrors can be really slow.
|
||||||
# may not be normal. Just to get a little more insight, print out
|
# Prioritize the official Ubuntu mirrors.
|
||||||
# a message to stdout with the top running process, and do this every
|
#
|
||||||
# 30 seconds. We can delete this watchdog later once we get a better
|
# The normal apt-mirrors.txt will look like:
|
||||||
# handle on what the timeout value should be.
|
#
|
||||||
(while [ 1 ] ; do sleep 30 && echo "[watchdog: $(ps -eo cmd --sort=-pcpu | head -n 2 | tail -n 1)}')]"; done) &
|
# http://azure.archive.ubuntu.com/ubuntu/ priority:1
|
||||||
|
# https://archive.ubuntu.com/ubuntu/ priority:2
|
||||||
|
# https://security.ubuntu.com/ubuntu/ priority:3
|
||||||
|
#
|
||||||
|
# Just delete the 'azure.archive.ubuntu.com' line.
|
||||||
|
sudo sed -i '/azure.archive.ubuntu.com/d' /etc/apt/apt-mirrors.txt
|
||||||
|
echo "Using mirrors:"
|
||||||
|
cat /etc/apt/apt-mirrors.txt
|
||||||
|
|
||||||
# install needed packages
|
# install needed packages
|
||||||
export DEBIAN_FRONTEND="noninteractive"
|
export DEBIAN_FRONTEND="noninteractive"
|
||||||
@@ -27,35 +34,89 @@ ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -q -N ""
|
|||||||
sudo systemctl stop docker.socket
|
sudo systemctl stop docker.socket
|
||||||
sudo systemctl stop multipathd.socket
|
sudo systemctl stop multipathd.socket
|
||||||
|
|
||||||
# remove default swapfile and /mnt
|
|
||||||
sudo swapoff -a
|
sudo swapoff -a
|
||||||
sudo umount -l /mnt
|
|
||||||
DISK="/dev/disk/cloud/azure_resource-part1"
|
# Special case:
|
||||||
sudo sed -e "s|^$DISK.*||g" -i /etc/fstab
|
#
|
||||||
sudo wipefs -aq $DISK
|
# For reasons unknown, the runner can boot-up with two different block device
|
||||||
sudo systemctl daemon-reload
|
# configurations. On one config you get two 75GB block devices, and on the
|
||||||
|
# other you get a single 150GB block device. Here's what both look like:
|
||||||
|
#
|
||||||
|
# --- Two 75GB block devices ---
|
||||||
|
# NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
|
||||||
|
# sda 8:0 0 150G 0 disk
|
||||||
|
# ├─sda1 8:1 0 149G 0 part /
|
||||||
|
# ├─sda14 8:14 0 4M 0 part
|
||||||
|
# ├─sda15 8:15 0 106M 0 part /boot/efi
|
||||||
|
# └─sda16 259:0 0 913M 0 part /boot
|
||||||
|
#
|
||||||
|
# lrwxrwxrwx 1 root root 9 Jan 29 18:07 azure_root -> ../../sda
|
||||||
|
# lrwxrwxrwx 1 root root 10 Jan 29 18:07 azure_root-part1 -> ../../sda1
|
||||||
|
# lrwxrwxrwx 1 root root 11 Jan 29 18:07 azure_root-part14 -> ../../sda14
|
||||||
|
# lrwxrwxrwx 1 root root 11 Jan 29 18:07 azure_root-part15 -> ../../sda15
|
||||||
|
# lrwxrwxrwx 1 root root 11 Jan 29 18:07 azure_root-part16 -> ../../sda16
|
||||||
|
#
|
||||||
|
# --- One 150GB block device ---
|
||||||
|
# NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
|
||||||
|
# sda 8:0 0 75G 0 disk
|
||||||
|
# ├─sda1 8:1 0 74G 0 part /
|
||||||
|
# ├─sda14 8:14 0 4M 0 part
|
||||||
|
# ├─sda15 8:15 0 106M 0 part /boot/efi
|
||||||
|
# └─sda16 259:0 0 913M 0 part /boot
|
||||||
|
# sdb 8:16 0 75G 0 disk
|
||||||
|
# └─sdb1 8:17 0 75G 0 part
|
||||||
|
#
|
||||||
|
# lrwxrwxrwx 1 root root 9 Jan 29 18:07 azure_resource -> ../../sdb
|
||||||
|
# lrwxrwxrwx 1 root root 10 Jan 29 18:07 azure_resource-part1 -> ../../sdb1
|
||||||
|
# lrwxrwxrwx 1 root root 9 Jan 29 18:07 azure_root -> ../../sda
|
||||||
|
# lrwxrwxrwx 1 root root 10 Jan 29 18:07 azure_root-part1 -> ../../sda1
|
||||||
|
# lrwxrwxrwx 1 root root 11 Jan 29 18:07 azure_root-part14 -> ../../sda14
|
||||||
|
# lrwxrwxrwx 1 root root 11 Jan 29 18:07 azure_root-part15 -> ../../sda15
|
||||||
|
#
|
||||||
|
# If we have the azure_resource-part1 partition, umount it, partition it, and
|
||||||
|
# use it as our ZFS disk and swap partition. If not, just create a file VDEV
|
||||||
|
# and swap file and use that instead.
|
||||||
|
|
||||||
|
# remove default swapfile and /mnt
|
||||||
|
if [ -e /dev/disk/cloud/azure_resource-part1 ] ; then
|
||||||
|
sudo umount -l /mnt
|
||||||
|
DISK="/dev/disk/cloud/azure_resource-part1"
|
||||||
|
sudo sed -e "s|^$DISK.*||g" -i /etc/fstab
|
||||||
|
sudo wipefs -aq $DISK
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
fi
|
||||||
|
|
||||||
sudo modprobe loop
|
sudo modprobe loop
|
||||||
sudo modprobe zfs
|
sudo modprobe zfs
|
||||||
|
|
||||||
# partition the disk as needed
|
if [ -e /dev/disk/cloud/azure_resource-part1 ] ; then
|
||||||
DISK="/dev/disk/cloud/azure_resource"
|
echo "We have two 75GB block devices"
|
||||||
sudo sgdisk --zap-all $DISK
|
# partition the disk as needed
|
||||||
sudo sgdisk -p \
|
DISK="/dev/disk/cloud/azure_resource"
|
||||||
-n 1:0:+16G -c 1:"swap" \
|
sudo sgdisk --zap-all $DISK
|
||||||
-n 2:0:0 -c 2:"tests" \
|
sudo sgdisk -p \
|
||||||
$DISK
|
-n 1:0:+16G -c 1:"swap" \
|
||||||
sync
|
-n 2:0:0 -c 2:"tests" \
|
||||||
sleep 1
|
$DISK
|
||||||
|
sync
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
sudo fallocate -l 12G /test.ssd2
|
||||||
|
DISKS="$DISK-part2 /test.ssd2"
|
||||||
|
|
||||||
|
SWAP=$DISK-part1
|
||||||
|
else
|
||||||
|
echo "We have a single 150GB block device"
|
||||||
|
sudo fallocate -l 72G /test.ssd2
|
||||||
|
SWAP=/swapfile.ssd
|
||||||
|
sudo fallocate -l 16G $SWAP
|
||||||
|
sudo chmod 600 $SWAP
|
||||||
|
DISKS="/test.ssd2"
|
||||||
|
fi
|
||||||
|
|
||||||
# swap with same size as RAM (16GiB)
|
# swap with same size as RAM (16GiB)
|
||||||
sudo mkswap $DISK-part1
|
sudo mkswap $SWAP
|
||||||
sudo swapon $DISK-part1
|
sudo swapon $SWAP
|
||||||
|
|
||||||
# JBOD 2xdisk for OpenZFS storage (test vm's)
|
|
||||||
SSD1="$DISK-part2"
|
|
||||||
sudo fallocate -l 12G /test.ssd2
|
|
||||||
SSD2=$(sudo losetup -b 4096 -f /test.ssd2 --show)
|
|
||||||
|
|
||||||
# adjust zfs module parameter and create pool
|
# adjust zfs module parameter and create pool
|
||||||
exec 1>/dev/null
|
exec 1>/dev/null
|
||||||
@@ -64,7 +125,7 @@ ARC_MAX=$((1024*1024*512))
|
|||||||
echo $ARC_MIN | sudo tee /sys/module/zfs/parameters/zfs_arc_min
|
echo $ARC_MIN | sudo tee /sys/module/zfs/parameters/zfs_arc_min
|
||||||
echo $ARC_MAX | sudo tee /sys/module/zfs/parameters/zfs_arc_max
|
echo $ARC_MAX | sudo tee /sys/module/zfs/parameters/zfs_arc_max
|
||||||
echo 1 | sudo tee /sys/module/zfs/parameters/zvol_use_blk_mq
|
echo 1 | sudo tee /sys/module/zfs/parameters/zvol_use_blk_mq
|
||||||
sudo zpool create -f -o ashift=12 zpool $SSD1 $SSD2 -O relatime=off \
|
sudo zpool create -f -o ashift=12 zpool $DISKS -O relatime=off \
|
||||||
-O atime=off -O xattr=sa -O compression=lz4 -O sync=disabled \
|
-O atime=off -O xattr=sa -O compression=lz4 -O sync=disabled \
|
||||||
-O redundant_metadata=none -O mountpoint=/mnt/tests
|
-O redundant_metadata=none -O mountpoint=/mnt/tests
|
||||||
|
|
||||||
@@ -72,6 +133,3 @@ sudo zpool create -f -o ashift=12 zpool $SSD1 $SSD2 -O relatime=off \
|
|||||||
for i in /sys/block/s*/queue/scheduler; do
|
for i in /sys/block/s*/queue/scheduler; do
|
||||||
echo "none" | sudo tee $i
|
echo "none" | sudo tee $i
|
||||||
done
|
done
|
||||||
|
|
||||||
# Kill off our watchdog
|
|
||||||
kill $(jobs -p)
|
|
||||||
|
|||||||
@@ -43,6 +43,12 @@ case "$OS" in
|
|||||||
OSv="almalinux9"
|
OSv="almalinux9"
|
||||||
URL="https://repo.almalinux.org/almalinux/10/cloud/x86_64/images/AlmaLinux-10-GenericCloud-latest.x86_64.qcow2"
|
URL="https://repo.almalinux.org/almalinux/10/cloud/x86_64/images/AlmaLinux-10-GenericCloud-latest.x86_64.qcow2"
|
||||||
;;
|
;;
|
||||||
|
alpine3-23)
|
||||||
|
OSNAME="Alpine Linux 3.23.2"
|
||||||
|
# Alpine Linux v3.22 and v3.23 are unknown to osinfo as of 2025-12-26.
|
||||||
|
OSv="alpinelinux3.21"
|
||||||
|
URL="https://dl-cdn.alpinelinux.org/alpine/v3.23/releases/cloud/generic_alpine-3.23.2-x86_64-bios-cloudinit-r0.qcow2"
|
||||||
|
;;
|
||||||
archlinux)
|
archlinux)
|
||||||
OSNAME="Archlinux"
|
OSNAME="Archlinux"
|
||||||
URL="https://geo.mirror.pkgbuild.com/images/latest/Arch-Linux-x86_64-cloudimg.qcow2"
|
URL="https://geo.mirror.pkgbuild.com/images/latest/Arch-Linux-x86_64-cloudimg.qcow2"
|
||||||
@@ -223,13 +229,21 @@ if [ ${OS:0:7} != "freebsd" ]; then
|
|||||||
hostname: $OS
|
hostname: $OS
|
||||||
|
|
||||||
users:
|
users:
|
||||||
- name: root
|
- name: root
|
||||||
shell: $BASH
|
shell: /bin/bash
|
||||||
- name: zfs
|
sudo: ['ALL=(ALL) NOPASSWD:ALL']
|
||||||
sudo: ALL=(ALL) NOPASSWD:ALL
|
- name: zfs
|
||||||
shell: $BASH
|
shell: /bin/bash
|
||||||
ssh_authorized_keys:
|
sudo: ['ALL=(ALL) NOPASSWD:ALL']
|
||||||
- $PUBKEY
|
ssh_authorized_keys:
|
||||||
|
- $PUBKEY
|
||||||
|
# Workaround for Alpine Linux.
|
||||||
|
lock_passwd: false
|
||||||
|
passwd: '*'
|
||||||
|
|
||||||
|
packages:
|
||||||
|
- sudo
|
||||||
|
- bash
|
||||||
|
|
||||||
growpart:
|
growpart:
|
||||||
mode: auto
|
mode: auto
|
||||||
@@ -312,3 +326,23 @@ else
|
|||||||
scp ~/src.txz "root@vm0:/tmp/src.txz"
|
scp ~/src.txz "root@vm0:/tmp/src.txz"
|
||||||
ssh root@vm0 'tar -C / -zxf /tmp/src.txz'
|
ssh root@vm0 'tar -C / -zxf /tmp/src.txz'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
#
|
||||||
|
# Config for Alpine Linux similar to FreeBSD.
|
||||||
|
#
|
||||||
|
if [ ${OS:0:6} == "alpine" ]; then
|
||||||
|
while pidof /usr/bin/qemu-system-x86_64 >/dev/null; do
|
||||||
|
ssh 2>/dev/null zfs@vm0 "uname -a" && break
|
||||||
|
done
|
||||||
|
# Enable community and testing repositories.
|
||||||
|
ssh zfs@vm0 "sudo rm -rf /etc/apk/repositories"
|
||||||
|
ssh zfs@vm0 "sudo setup-apkrepos -c1"
|
||||||
|
ssh zfs@vm0 "echo '@testing http://dl-cdn.alpinelinux.org/alpine/edge/testing' | sudo tee -a /etc/apk/repositories"
|
||||||
|
# Upgrade to edge or latest-stable.
|
||||||
|
#ssh zfs@vm0 "sudo sed -i 's#/v[0-9]\+\.[0-9]\+/#/edge/#g' /etc/apk/repositories"
|
||||||
|
#ssh zfs@vm0 "sudo sed -i 's#/v[0-9]\+\.[0-9]\+/#/latest-stable/#g' /etc/apk/repositories"
|
||||||
|
# Update and upgrade after repository setup.
|
||||||
|
ssh zfs@vm0 "sudo apk update"
|
||||||
|
ssh zfs@vm0 "sudo apk add --upgrade apk-tools"
|
||||||
|
ssh zfs@vm0 "sudo apk upgrade --available"
|
||||||
|
fi
|
||||||
|
|||||||
@@ -10,6 +10,32 @@
|
|||||||
|
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
|
function alpine() {
|
||||||
|
echo "##[group]Install Development Tools"
|
||||||
|
sudo apk add \
|
||||||
|
acl alpine-sdk attr autoconf automake bash build-base clang21 coreutils \
|
||||||
|
cpio cryptsetup curl curl-dev dhcpcd eudev eudev-dev eudev-libs findutils \
|
||||||
|
fio gawk gdb gettext-dev git grep jq libaio libaio-dev libcurl \
|
||||||
|
libtirpc-dev libtool libunwind libunwind-dev linux-headers linux-tools \
|
||||||
|
linux-virt linux-virt-dev lsscsi m4 make nfs-utils openssl-dev parted \
|
||||||
|
pax procps py3-cffi py3-distlib py3-packaging py3-setuptools python3 \
|
||||||
|
python3-dev qemu-guest-agent rng-tools rsync samba samba-server sed \
|
||||||
|
strace sysstat util-linux util-linux-dev wget words xfsprogs xxhash \
|
||||||
|
zlib-dev pamtester@testing
|
||||||
|
echo "##[endgroup]"
|
||||||
|
|
||||||
|
echo "##[group]Switch to eudev"
|
||||||
|
sudo setup-devd udev
|
||||||
|
echo "##[endgroup]"
|
||||||
|
|
||||||
|
echo "##[group]Install ksh93 from Source"
|
||||||
|
git clone --depth 1 https://github.com/ksh93/ksh.git /tmp/ksh
|
||||||
|
cd /tmp/ksh
|
||||||
|
./bin/package make
|
||||||
|
sudo ./bin/package install /
|
||||||
|
echo "##[endgroup]"
|
||||||
|
}
|
||||||
|
|
||||||
function archlinux() {
|
function archlinux() {
|
||||||
echo "##[group]Running pacman -Syu"
|
echo "##[group]Running pacman -Syu"
|
||||||
sudo btrfs filesystem resize max /
|
sudo btrfs filesystem resize max /
|
||||||
@@ -27,6 +53,10 @@ function archlinux() {
|
|||||||
function debian() {
|
function debian() {
|
||||||
export DEBIAN_FRONTEND="noninteractive"
|
export DEBIAN_FRONTEND="noninteractive"
|
||||||
|
|
||||||
|
echo "##[group]Wait for cloud-init to finish"
|
||||||
|
cloud-init status --wait
|
||||||
|
echo "##[endgroup]"
|
||||||
|
|
||||||
echo "##[group]Running apt-get update+upgrade"
|
echo "##[group]Running apt-get update+upgrade"
|
||||||
sudo sed -i '/[[:alpha:]]-backports/d' /etc/apt/sources.list
|
sudo sed -i '/[[:alpha:]]-backports/d' /etc/apt/sources.list
|
||||||
sudo apt-get update -y
|
sudo apt-get update -y
|
||||||
@@ -90,6 +120,11 @@ function rhel() {
|
|||||||
kernel-devel python3-setuptools qemu-guest-agent rng-tools rpcgen \
|
kernel-devel python3-setuptools qemu-guest-agent rng-tools rpcgen \
|
||||||
rpm-build rsync samba strace sysstat systemd watchdog wget xfsprogs-devel \
|
rpm-build rsync samba strace sysstat systemd watchdog wget xfsprogs-devel \
|
||||||
xxhash zlib-devel
|
xxhash zlib-devel
|
||||||
|
|
||||||
|
# These are needed for building Lustre. We only install these on EL VMs since
|
||||||
|
# we don't plan to test build Lustre on other platforms.
|
||||||
|
sudo dnf install -y libnl3-devel libyaml-devel libmount-devel
|
||||||
|
|
||||||
echo "##[endgroup]"
|
echo "##[endgroup]"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,6 +175,9 @@ case "$1" in
|
|||||||
sudo dnf install -y kernel-abi-stablelists
|
sudo dnf install -y kernel-abi-stablelists
|
||||||
echo "##[endgroup]"
|
echo "##[endgroup]"
|
||||||
;;
|
;;
|
||||||
|
alpine*)
|
||||||
|
alpine
|
||||||
|
;;
|
||||||
archlinux)
|
archlinux)
|
||||||
archlinux
|
archlinux
|
||||||
;;
|
;;
|
||||||
@@ -188,6 +226,16 @@ test -z "${ONLY_DEPS:-}" || exit 0
|
|||||||
# Start services
|
# Start services
|
||||||
echo "##[group]Enable services"
|
echo "##[group]Enable services"
|
||||||
case "$1" in
|
case "$1" in
|
||||||
|
alpine*)
|
||||||
|
sudo -E rc-update add qemu-guest-agent
|
||||||
|
sudo -E rc-update add nfs
|
||||||
|
sudo -E rc-update add samba
|
||||||
|
sudo -E rc-update add dhcpcd
|
||||||
|
# Remove services related to cloud-init.
|
||||||
|
sudo -E rc-update del cloud-init default
|
||||||
|
sudo -E rc-update del cloud-final default
|
||||||
|
sudo -E rc-update del cloud-config default
|
||||||
|
;;
|
||||||
freebsd*)
|
freebsd*)
|
||||||
# add virtio things
|
# add virtio things
|
||||||
echo 'virtio_load="YES"' | sudo -E tee -a /boot/loader.conf
|
echo 'virtio_load="YES"' | sudo -E tee -a /boot/loader.conf
|
||||||
@@ -243,7 +291,7 @@ case "$1" in
|
|||||||
esac
|
esac
|
||||||
|
|
||||||
case "$1" in
|
case "$1" in
|
||||||
archlinux|freebsd*)
|
alpine*|archlinux|freebsd*)
|
||||||
true
|
true
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
|
|||||||
@@ -58,13 +58,21 @@ for ((i=1; i<=VMs; i++)); do
|
|||||||
fqdn: vm$i
|
fqdn: vm$i
|
||||||
|
|
||||||
users:
|
users:
|
||||||
- name: root
|
- name: root
|
||||||
shell: $BASH
|
shell: /bin/bash
|
||||||
- name: zfs
|
sudo: ['ALL=(ALL) NOPASSWD:ALL']
|
||||||
sudo: ALL=(ALL) NOPASSWD:ALL
|
- name: zfs
|
||||||
shell: $BASH
|
shell: /bin/bash
|
||||||
ssh_authorized_keys:
|
sudo: ['ALL=(ALL) NOPASSWD:ALL']
|
||||||
- $PUBKEY
|
ssh_authorized_keys:
|
||||||
|
- $PUBKEY
|
||||||
|
# Workaround for Alpine Linux.
|
||||||
|
lock_passwd: false
|
||||||
|
passwd: '*'
|
||||||
|
|
||||||
|
packages:
|
||||||
|
- sudo
|
||||||
|
- bash
|
||||||
|
|
||||||
growpart:
|
growpart:
|
||||||
mode: auto
|
mode: auto
|
||||||
|
|||||||
+51
@@ -0,0 +1,51 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# 6) Test if Lustre can still build against ZFS
|
||||||
|
######################################################################
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Build from the latest Lustre tag rather than the master branch. We do this
|
||||||
|
# under the assumption that master is going to have a lot of churn thus will be
|
||||||
|
# more prone to breaking the build than a point release. We don't want ZFS
|
||||||
|
# PR's reporting bad test results simply because upstream Lustre accidentally
|
||||||
|
# broke their build.
|
||||||
|
#
|
||||||
|
# Skip any RC tags, or any tags where the last version digit is 50 or more.
|
||||||
|
# Versions with 50 or more are development versions of Lustre.
|
||||||
|
repo=https://github.com/lustre/lustre-release.git
|
||||||
|
tag="$(git ls-remote --refs --exit-code --sort=version:refname --tags $repo | \
|
||||||
|
awk -F '_' '/-RC/{next}; /refs\/tags\/v/{if ($NF < 50){print}}' | \
|
||||||
|
tail -n 1 | sed 's/.*\///')"
|
||||||
|
|
||||||
|
echo "Cloning Lustre tag $tag"
|
||||||
|
git clone --depth 1 --branch "$tag" "$repo"
|
||||||
|
|
||||||
|
cd lustre-release
|
||||||
|
|
||||||
|
# Include Lustre patches to build against master/zfs-2.4.x. Once these
|
||||||
|
# patches are merged we can remove these lines.
|
||||||
|
patches=('https://review.whamcloud.com/changes/fs%2Flustre-release~62101/revisions/2/patch?download'
|
||||||
|
'https://review.whamcloud.com/changes/fs%2Flustre-release~63267/revisions/9/patch?download')
|
||||||
|
|
||||||
|
for p in "${patches[@]}" ; do
|
||||||
|
curl $p | base64 -d > patch
|
||||||
|
patch -p1 < patch || true
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Configure Lustre"
|
||||||
|
./autogen.sh
|
||||||
|
# EL 9 needs '--disable-gss-keyring'
|
||||||
|
./configure --with-zfs --disable-gss-keyring
|
||||||
|
echo "Building Lustre RPMs"
|
||||||
|
make rpms
|
||||||
|
ls *.rpm
|
||||||
|
|
||||||
|
# There's only a handful of Lustre RPMs we actually need to install
|
||||||
|
lustrerpms="$(ls *.rpm | grep -E 'kmod-lustre-osd-zfs-[0-9]|kmod-lustre-[0-9]|lustre-osd-zfs-mount-[0-9]')"
|
||||||
|
echo "Installing: $lustrerpms"
|
||||||
|
sudo dnf -y install $lustrerpms
|
||||||
|
sudo modprobe -v lustre
|
||||||
|
|
||||||
|
# Should see some Lustre lines in dmesg
|
||||||
|
sudo dmesg | grep -Ei 'lnet|lustre'
|
||||||
@@ -4,7 +4,10 @@
|
|||||||
# 6) load openzfs module and run the tests
|
# 6) load openzfs module and run the tests
|
||||||
#
|
#
|
||||||
# called on runner: qemu-6-tests.sh
|
# called on runner: qemu-6-tests.sh
|
||||||
# called on qemu-vm: qemu-6-tests.sh $OS $2/$3
|
# called on qemu-vm: qemu-6-tests.sh $OS $2 $3 [--lustre|--builtin] [quick|default]
|
||||||
|
#
|
||||||
|
# --lustre: Test build lustre in addition to the normal tests
|
||||||
|
# --builtin: Test build ZFS as a kernel built-in in addition to the normal tests
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
set -eu
|
set -eu
|
||||||
@@ -38,6 +41,54 @@ function prefix() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function do_lustre_build() {
|
||||||
|
local rc=0
|
||||||
|
$HOME/zfs/.github/workflows/scripts/qemu-6-lustre-tests-vm.sh &> /var/tmp/lustre.txt || rc=$?
|
||||||
|
echo "$rc" > /var/tmp/lustre-exitcode.txt
|
||||||
|
if [ "$rc" != "0" ] ; then
|
||||||
|
echo "$rc" > /var/tmp/tests-exitcode.txt
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
export -f do_lustre_build
|
||||||
|
|
||||||
|
# Test build ZFS into the kernel directly
|
||||||
|
function do_builtin_build() {
|
||||||
|
local rc=0
|
||||||
|
# Get currently full kernel version (like '6.18.8')
|
||||||
|
fullver=$(uname -r | grep -Eo '^[0-9]+\.[0-9]+\.[0-9]+')
|
||||||
|
|
||||||
|
# Get just the major ('6')
|
||||||
|
major=$(echo $fullver | grep -Eo '^[0-9]+')
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
|
||||||
|
wget https://cdn.kernel.org/pub/linux/kernel/v${major}.x/linux-$fullver.tar.xz
|
||||||
|
tar -xf $HOME/linux-$fullver.tar.xz
|
||||||
|
cd $HOME/linux-$fullver
|
||||||
|
make tinyconfig
|
||||||
|
./scripts/config --enable EFI_PARTITON
|
||||||
|
./scripts/config --enable BLOCK
|
||||||
|
# BTRFS_FS is easiest config option to enable CONFIG_ZLIB_INFLATE|DEFLATE
|
||||||
|
./scripts/config --enable BTRFS_FS
|
||||||
|
yes "" | make oldconfig
|
||||||
|
make prepare
|
||||||
|
|
||||||
|
cd $HOME/zfs
|
||||||
|
./configure --with-linux=$HOME/linux-$fullver --enable-linux-builtin --enable-debug
|
||||||
|
./copy-builtin $HOME/linux-$fullver
|
||||||
|
|
||||||
|
cd $HOME/linux-$fullver
|
||||||
|
./scripts/config --enable ZFS
|
||||||
|
yes "" | make oldconfig
|
||||||
|
make -j `nproc`
|
||||||
|
) &> /var/tmp/builtin.txt || rc=$?
|
||||||
|
echo "$rc" > /var/tmp/builtin-exitcode.txt
|
||||||
|
if [ "$rc" != "0" ] ; then
|
||||||
|
echo "$rc" > /var/tmp/tests-exitcode.txt
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
export -f do_builtin_build
|
||||||
|
|
||||||
# called directly on the runner
|
# called directly on the runner
|
||||||
if [ -z ${1:-} ]; then
|
if [ -z ${1:-} ]; then
|
||||||
cd "/var/tmp"
|
cd "/var/tmp"
|
||||||
@@ -49,8 +100,24 @@ if [ -z ${1:-} ]; then
|
|||||||
|
|
||||||
for ((i=1; i<=VMs; i++)); do
|
for ((i=1; i<=VMs; i++)); do
|
||||||
IP="192.168.122.1$i"
|
IP="192.168.122.1$i"
|
||||||
|
|
||||||
|
# We do an additional test build of Lustre against ZFS if we're vm2
|
||||||
|
# on almalinux*. At the time of writing, the vm2 tests were
|
||||||
|
# completing roughly 15min before the vm1 tests, so it makes sense
|
||||||
|
# to have vm2 do the build.
|
||||||
|
#
|
||||||
|
# In addition, we do an additional test build of ZFS as a Linux
|
||||||
|
# kernel built-in on Fedora. Again, we do it on vm2 to exploit vm2's
|
||||||
|
# early finish time.
|
||||||
|
extra=""
|
||||||
|
if [[ "$OS" == almalinux* ]] && [[ "$i" == "2" ]] ; then
|
||||||
|
extra="--lustre"
|
||||||
|
elif [[ "$OS" == fedora* ]] && [[ "$i" == "2" ]] ; then
|
||||||
|
extra="--builtin"
|
||||||
|
fi
|
||||||
|
|
||||||
daemonize -c /var/tmp -p vm${i}.pid -o vm${i}log.txt -- \
|
daemonize -c /var/tmp -p vm${i}.pid -o vm${i}log.txt -- \
|
||||||
$SSH zfs@$IP $TESTS $OS $i $VMs $CI_TYPE
|
$SSH zfs@$IP $TESTS $OS $i $VMs $extra $CI_TYPE
|
||||||
# handly line by line and add info prefix
|
# handly line by line and add info prefix
|
||||||
stdbuf -oL tail -fq vm${i}log.txt \
|
stdbuf -oL tail -fq vm${i}log.txt \
|
||||||
| while read -r line; do prefix "$i" "$line"; done &
|
| while read -r line; do prefix "$i" "$line"; done &
|
||||||
@@ -70,9 +137,35 @@ if [ -z ${1:-} ]; then
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# this part runs inside qemu vm
|
|
||||||
|
#############################################
|
||||||
|
# Everything from here on runs inside qemu vm
|
||||||
|
#############################################
|
||||||
|
|
||||||
|
# Process cmd line args
|
||||||
|
OS="$1"
|
||||||
|
shift
|
||||||
|
NUM="$1"
|
||||||
|
shift
|
||||||
|
DEN="$1"
|
||||||
|
shift
|
||||||
|
|
||||||
|
BUILD_LUSTRE=0
|
||||||
|
BUILD_BUILTIN=0
|
||||||
|
if [ "$1" == "--lustre" ] ; then
|
||||||
|
BUILD_LUSTRE=1
|
||||||
|
shift
|
||||||
|
elif [ "$1" == "--builtin" ] ; then
|
||||||
|
BUILD_BUILTIN=1
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$1" == "quick" ] ; then
|
||||||
|
export RUNFILES="sanity.run"
|
||||||
|
fi
|
||||||
|
|
||||||
export PATH="$PATH:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/sbin:/usr/local/bin"
|
export PATH="$PATH:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/sbin:/usr/local/bin"
|
||||||
case "$1" in
|
case "$OS" in
|
||||||
freebsd*)
|
freebsd*)
|
||||||
TDIR="/usr/local/share/zfs"
|
TDIR="/usr/local/share/zfs"
|
||||||
sudo kldstat -n zfs 2>/dev/null && sudo kldunload zfs
|
sudo kldstat -n zfs 2>/dev/null && sudo kldunload zfs
|
||||||
@@ -95,23 +188,42 @@ case "$1" in
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# enable io_uring on el9/el10
|
# Distribution-specific settings.
|
||||||
case "$1" in
|
case "$OS" in
|
||||||
almalinux9|almalinux10|centos-stream*)
|
almalinux9|almalinux10|centos-stream*)
|
||||||
|
# Enable io_uring on Enterprise Linux 9 and 10.
|
||||||
sudo sysctl kernel.io_uring_disabled=0 > /dev/null
|
sudo sysctl kernel.io_uring_disabled=0 > /dev/null
|
||||||
;;
|
;;
|
||||||
|
alpine*)
|
||||||
|
# Ensure `/etc/zfs/zpool.cache` exists.
|
||||||
|
sudo mkdir -p /etc/zfs
|
||||||
|
sudo touch /etc/zfs/zpool.cache
|
||||||
|
sudo chmod 644 /etc/zfs/zpool.cache
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
# Lustre calls a number of exported ZFS module symbols. To make sure we don't
|
||||||
|
# change the symbols and break Lustre, do a quick Lustre build of the latest
|
||||||
|
# released Lustre against ZFS.
|
||||||
|
#
|
||||||
|
# Note that we do the Lustre test build in parallel with ZTS. ZTS isn't very
|
||||||
|
# CPU intensive, so we can use idle CPU cycles "guilt free" for the build.
|
||||||
|
# The Lustre build on its own takes ~15min.
|
||||||
|
if [ "$BUILD_LUSTRE" == "1" ] ; then
|
||||||
|
do_lustre_build &
|
||||||
|
elif [ "$BUILD_BUILTIN" == "1" ] ; then
|
||||||
|
# Try building ZFS directly into the Linux kernel (not as a module)
|
||||||
|
do_builtin_build &
|
||||||
|
fi
|
||||||
|
|
||||||
# run functional testings and save exitcode
|
# run functional testings and save exitcode
|
||||||
cd /var/tmp
|
cd /var/tmp
|
||||||
TAGS=$2/$3
|
TAGS=$NUM/$DEN
|
||||||
if [ "$4" == "quick" ]; then
|
|
||||||
export RUNFILES="sanity.run"
|
|
||||||
fi
|
|
||||||
sudo dmesg -c > dmesg-prerun.txt
|
sudo dmesg -c > dmesg-prerun.txt
|
||||||
mount > mount.txt
|
mount > mount.txt
|
||||||
df -h > df-prerun.txt
|
df -h > df-prerun.txt
|
||||||
$TDIR/zfs-tests.sh -vKO -s 3GB -T $TAGS
|
$TDIR/zfs-tests.sh -vKO -s 3GB -T $TAGS
|
||||||
|
|
||||||
RV=$?
|
RV=$?
|
||||||
df -h > df-postrun.txt
|
df -h > df-postrun.txt
|
||||||
echo $RV > tests-exitcode.txt
|
echo $RV > tests-exitcode.txt
|
||||||
|
|||||||
@@ -31,6 +31,12 @@ EOF
|
|||||||
rm -f tmp$$
|
rm -f tmp$$
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showfile_tail() {
|
||||||
|
echo "##[group]$2 (final lines)"
|
||||||
|
tail -n 80 $1
|
||||||
|
echo "##[endgroup]"
|
||||||
|
}
|
||||||
|
|
||||||
# overview
|
# overview
|
||||||
cat /tmp/summary.txt
|
cat /tmp/summary.txt
|
||||||
echo ""
|
echo ""
|
||||||
@@ -46,6 +52,32 @@ fi
|
|||||||
echo -e "\nFull logs for download:\n $1\n"
|
echo -e "\nFull logs for download:\n $1\n"
|
||||||
|
|
||||||
for ((i=1; i<=VMs; i++)); do
|
for ((i=1; i<=VMs; i++)); do
|
||||||
|
|
||||||
|
# Print Lustre build test results (the build is only done on vm2)
|
||||||
|
if [ -f vm$i/lustre-exitcode.txt ] ; then
|
||||||
|
rv=$(< vm$i/lustre-exitcode.txt)
|
||||||
|
if [ $rv = 0 ]; then
|
||||||
|
vm="[92mvm$i[0m"
|
||||||
|
else
|
||||||
|
vm="[1;91mvm$i[0m"
|
||||||
|
touch /tmp/have_failed_tests
|
||||||
|
fi
|
||||||
|
file="vm$i/lustre.txt"
|
||||||
|
test -s "$file" && showfile_tail "$file" "$vm: Lustre build"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f vm$i/builtin-exitcode.txt ] ; then
|
||||||
|
rv=$(< vm$i/builtin-exitcode.txt)
|
||||||
|
if [ $rv = 0 ]; then
|
||||||
|
vm="[92mvm$i[0m"
|
||||||
|
else
|
||||||
|
vm="[1;91mvm$i[0m"
|
||||||
|
touch /tmp/have_failed_tests
|
||||||
|
fi
|
||||||
|
file="vm$i/builtin.txt"
|
||||||
|
test -s "$file" && showfile_tail "$file" "$vm: Linux built-in build"
|
||||||
|
fi
|
||||||
|
|
||||||
rv=$(cat vm$i/tests-exitcode.txt)
|
rv=$(cat vm$i/tests-exitcode.txt)
|
||||||
|
|
||||||
if [ $rv = 0 ]; then
|
if [ $rv = 0 ]; then
|
||||||
|
|||||||
@@ -4,7 +4,11 @@
|
|||||||
#
|
#
|
||||||
# USAGE:
|
# USAGE:
|
||||||
#
|
#
|
||||||
# ./qemu-test-repo-vm [URL]
|
# ./qemu-test-repo-vm [--install] [URL]
|
||||||
|
#
|
||||||
|
# --lookup: When testing a repo, only lookup the latest package versions,
|
||||||
|
# don't try to install them. Installing all of them takes over
|
||||||
|
# an hour, so this is much quicker.
|
||||||
#
|
#
|
||||||
# URL: URL to use instead of http://download.zfsonlinux.org
|
# URL: URL to use instead of http://download.zfsonlinux.org
|
||||||
# If blank, use the default repo from zfs-release RPM.
|
# If blank, use the default repo from zfs-release RPM.
|
||||||
@@ -15,6 +19,13 @@ source /etc/os-release
|
|||||||
OS="$ID"
|
OS="$ID"
|
||||||
VERSION="$VERSION_ID"
|
VERSION="$VERSION_ID"
|
||||||
|
|
||||||
|
|
||||||
|
LOOKUP=""
|
||||||
|
if [ -n "$1" ] && [ "$1" == "--lookup" ] ; then
|
||||||
|
LOOKUP=1
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
|
||||||
ALTHOST=""
|
ALTHOST=""
|
||||||
if [ -n "$1" ] ; then
|
if [ -n "$1" ] ; then
|
||||||
ALTHOST="$1"
|
ALTHOST="$1"
|
||||||
@@ -42,7 +53,19 @@ function test_install {
|
|||||||
sudo sed -i "s;baseurl=http://download.zfsonlinux.org;baseurl=$host;g" /etc/yum.repos.d/zfs.repo
|
sudo sed -i "s;baseurl=http://download.zfsonlinux.org;baseurl=$host;g" /etc/yum.repos.d/zfs.repo
|
||||||
fi
|
fi
|
||||||
|
|
||||||
sudo dnf -y install $args zfs zfs-test
|
baseurl=$(grep -A 5 "\[$repo\]" /etc/yum.repos.d/zfs.repo | awk -F'=' '/baseurl=/{print $2; exit}')
|
||||||
|
|
||||||
|
# Just do a version lookup - don't try to install any RPMs
|
||||||
|
if [ "$LOOKUP" == "1" ] ; then
|
||||||
|
package="$(dnf list $args zfs | tail -n 1 | awk '{print $2}')"
|
||||||
|
echo "$repo ${package} $baseurl" >> $SUMMARY
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! sudo dnf -y install $args zfs zfs-test ; then
|
||||||
|
echo "$repo ${package}...[FAILED] $baseurl" >> $SUMMARY
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
# Load modules and create a simple pool as a sanity test.
|
# Load modules and create a simple pool as a sanity test.
|
||||||
sudo /usr/share/zfs/zfs.sh -r
|
sudo /usr/share/zfs/zfs.sh -r
|
||||||
@@ -51,7 +74,6 @@ function test_install {
|
|||||||
sudo zpool status
|
sudo zpool status
|
||||||
|
|
||||||
# Print out repo name, rpm installed (kmod or dkms), and repo URL
|
# Print out repo name, rpm installed (kmod or dkms), and repo URL
|
||||||
baseurl=$(grep -A 5 "\[$repo\]" /etc/yum.repos.d/zfs.repo | awk -F'=' '/baseurl=/{print $2; exit}')
|
|
||||||
package=$(sudo rpm -qa | grep zfs | grep -E 'kmod|dkms')
|
package=$(sudo rpm -qa | grep zfs | grep -E 'kmod|dkms')
|
||||||
|
|
||||||
echo "$repo $package $baseurl" >> $SUMMARY
|
echo "$repo $package $baseurl" >> $SUMMARY
|
||||||
@@ -70,16 +92,19 @@ almalinux*)
|
|||||||
name=$(curl -Ls $url | grep 'dnf install' | grep -Eo 'zfs-release-[0-9]+-[0-9]+')
|
name=$(curl -Ls $url | grep 'dnf install' | grep -Eo 'zfs-release-[0-9]+-[0-9]+')
|
||||||
sudo dnf -y install https://zfsonlinux.org/epel/$name$(rpm --eval "%{dist}").noarch.rpm 2>&1
|
sudo dnf -y install https://zfsonlinux.org/epel/$name$(rpm --eval "%{dist}").noarch.rpm 2>&1
|
||||||
sudo rpm -qi zfs-release
|
sudo rpm -qi zfs-release
|
||||||
test_install zfs $ALTHOST
|
for i in zfs zfs-kmod zfs-testing zfs-testing-kmod zfs-latest \
|
||||||
test_install zfs-kmod $ALTHOST
|
zfs-latest-kmod zfs-legacy zfs-legacy-kmod zfs-2.2 \
|
||||||
test_install zfs-testing $ALTHOST
|
zfs-2.2-kmod zfs-2.3 zfs-2.3-kmod zfs-2.4 zfs-2.4-kmod; do
|
||||||
test_install zfs-testing-kmod $ALTHOST
|
test_install $i $ALTHOST
|
||||||
|
done
|
||||||
;;
|
;;
|
||||||
fedora*)
|
fedora*)
|
||||||
url='https://raw.githubusercontent.com/openzfs/openzfs-docs/refs/heads/master/docs/Getting%20Started/Fedora/index.rst'
|
url='https://raw.githubusercontent.com/openzfs/openzfs-docs/refs/heads/master/docs/Getting%20Started/Fedora/index.rst'
|
||||||
name=$(curl -Ls $url | grep 'dnf install' | grep -Eo 'zfs-release-[0-9]+-[0-9]+')
|
name=$(curl -Ls $url | grep 'dnf install' | grep -Eo 'zfs-release-[0-9]+-[0-9]+')
|
||||||
sudo dnf -y install -y https://zfsonlinux.org/fedora/$name$(rpm --eval "%{dist}").noarch.rpm
|
sudo dnf -y install -y https://zfsonlinux.org/fedora/$name$(rpm --eval "%{dist}").noarch.rpm
|
||||||
test_install zfs $ALTHOST
|
for i in zfs zfs-latest zfs-legacy zfs-2.2 zfs-2.3 zfs-2.4 ; do
|
||||||
|
test_install $i $ALTHOST
|
||||||
|
done
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
echo "##[endgroup]"
|
echo "##[endgroup]"
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
name: smatch
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
smatch:
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
steps:
|
||||||
|
- name: Checkout smatch
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: error27/smatch
|
||||||
|
ref: master
|
||||||
|
path: smatch
|
||||||
|
- name: Install smatch dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get install -y llvm gcc make sqlite3 libsqlite3-dev libdbd-sqlite3-perl libssl-dev libtry-tiny-perl
|
||||||
|
- name: Make smatch
|
||||||
|
run: |
|
||||||
|
cd $GITHUB_WORKSPACE/smatch
|
||||||
|
make -j$(nproc)
|
||||||
|
- name: Checkout OpenZFS
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: ${{ github.event.pull_request.head.sha }}
|
||||||
|
path: zfs
|
||||||
|
- name: Install OpenZFS dependencies
|
||||||
|
run: |
|
||||||
|
cd $GITHUB_WORKSPACE/zfs
|
||||||
|
sudo apt-get purge -y snapd google-chrome-stable firefox
|
||||||
|
ONLY_DEPS=1 .github/workflows/scripts/qemu-3-deps-vm.sh ubuntu24
|
||||||
|
- name: Autogen.sh OpenZFS
|
||||||
|
run: |
|
||||||
|
cd $GITHUB_WORKSPACE/zfs
|
||||||
|
./autogen.sh
|
||||||
|
- name: Configure OpenZFS
|
||||||
|
run: |
|
||||||
|
cd $GITHUB_WORKSPACE/zfs
|
||||||
|
./configure --enable-debug
|
||||||
|
- name: Make OpenZFS
|
||||||
|
run: |
|
||||||
|
cd $GITHUB_WORKSPACE/zfs
|
||||||
|
make -j$(nproc) CHECK="$GITHUB_WORKSPACE/smatch/smatch" CC=$GITHUB_WORKSPACE/smatch/cgcc | tee $GITHUB_WORKSPACE/smatch.log
|
||||||
|
- name: Smatch results log
|
||||||
|
run: |
|
||||||
|
grep -E 'error:|warn:|warning:' $GITHUB_WORKSPACE/smatch.log
|
||||||
@@ -42,6 +42,12 @@ on:
|
|||||||
required: false
|
required: false
|
||||||
default: ""
|
default: ""
|
||||||
description: "(optional) repo URL (blank: use http://download.zfsonlinux.org)"
|
description: "(optional) repo URL (blank: use http://download.zfsonlinux.org)"
|
||||||
|
lookup:
|
||||||
|
type: boolean
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
|
description: "(optional) do version lookup only on repo test"
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
@@ -60,20 +66,16 @@ jobs:
|
|||||||
ref: ${{ github.event.pull_request.head.sha }}
|
ref: ${{ github.event.pull_request.head.sha }}
|
||||||
|
|
||||||
- name: Setup QEMU
|
- name: Setup QEMU
|
||||||
timeout-minutes: 10
|
|
||||||
run: .github/workflows/scripts/qemu-1-setup.sh
|
run: .github/workflows/scripts/qemu-1-setup.sh
|
||||||
|
|
||||||
- name: Start build machine
|
- name: Start build machine
|
||||||
timeout-minutes: 10
|
|
||||||
run: .github/workflows/scripts/qemu-2-start.sh ${{ matrix.os }}
|
run: .github/workflows/scripts/qemu-2-start.sh ${{ matrix.os }}
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
timeout-minutes: 20
|
|
||||||
run: |
|
run: |
|
||||||
.github/workflows/scripts/qemu-3-deps.sh ${{ matrix.os }}
|
.github/workflows/scripts/qemu-3-deps.sh ${{ matrix.os }}
|
||||||
|
|
||||||
- name: Build modules or Test repo
|
- name: Build modules or Test repo
|
||||||
timeout-minutes: 30
|
|
||||||
run: |
|
run: |
|
||||||
set -e
|
set -e
|
||||||
if [ "${{ github.event.inputs.test_type }}" == "Test repo" ] ; then
|
if [ "${{ github.event.inputs.test_type }}" == "Test repo" ] ; then
|
||||||
@@ -81,7 +83,12 @@ jobs:
|
|||||||
.github/workflows/scripts/qemu-prepare-for-build.sh
|
.github/workflows/scripts/qemu-prepare-for-build.sh
|
||||||
|
|
||||||
mkdir -p /tmp/repo
|
mkdir -p /tmp/repo
|
||||||
ssh zfs@vm0 '$HOME/zfs/.github/workflows/scripts/qemu-test-repo-vm.sh' ${{ github.event.inputs.repo_url }}
|
EXTRA=""
|
||||||
|
if [ "${{ github.event.inputs.lookup }}" == 'true' ] ; then
|
||||||
|
EXTRA="--lookup"
|
||||||
|
fi
|
||||||
|
|
||||||
|
ssh zfs@vm0 '$HOME/zfs/.github/workflows/scripts/qemu-test-repo-vm.sh' $EXTRA ${{ github.event.inputs.repo_url }}
|
||||||
else
|
else
|
||||||
EXTRA=""
|
EXTRA=""
|
||||||
if [ -n "${{ github.event.inputs.patch_level }}" ] ; then
|
if [ -n "${{ github.event.inputs.patch_level }}" ] ; then
|
||||||
@@ -94,7 +101,6 @@ jobs:
|
|||||||
|
|
||||||
- name: Prepare artifacts
|
- name: Prepare artifacts
|
||||||
if: always()
|
if: always()
|
||||||
timeout-minutes: 10
|
|
||||||
run: |
|
run: |
|
||||||
rsync -a zfs@vm0:/tmp/repo /tmp || true
|
rsync -a zfs@vm0:/tmp/repo /tmp || true
|
||||||
.github/workflows/scripts/replace-dupes-with-symlinks.sh /tmp/repo
|
.github/workflows/scripts/replace-dupes-with-symlinks.sh /tmp/repo
|
||||||
|
|||||||
@@ -10,6 +10,11 @@ on:
|
|||||||
required: false
|
required: false
|
||||||
default: ""
|
default: ""
|
||||||
description: "(optional) Experimental kernel version to install on Fedora (like '6.14' or '6.13.3-0.rc3')"
|
description: "(optional) Experimental kernel version to install on Fedora (like '6.14' or '6.13.3-0.rc3')"
|
||||||
|
specific_os:
|
||||||
|
type: string
|
||||||
|
required: false
|
||||||
|
default: ""
|
||||||
|
description: "(optional) Only run on this specific OS (like 'fedora42' or 'alpine3-23')"
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||||
@@ -58,6 +63,9 @@ jobs:
|
|||||||
# They specified a custom kernel version for Fedora.
|
# They specified a custom kernel version for Fedora.
|
||||||
# Use only Fedora runners.
|
# Use only Fedora runners.
|
||||||
os_json=$(echo ${os_selection} | jq -c '[.[] | select(startswith("fedora"))]')
|
os_json=$(echo ${os_selection} | jq -c '[.[] | select(startswith("fedora"))]')
|
||||||
|
elif ${{ github.event.inputs.specific_os != '' }}; then
|
||||||
|
# Use only the specified runner.
|
||||||
|
os_json=$(jq -cn --arg os "${{ github.event.inputs.specific_os }}" '[ $os ]')
|
||||||
else
|
else
|
||||||
# Normal case
|
# Normal case
|
||||||
os_json=$(echo ${os_selection} | jq -c)
|
os_json=$(echo ${os_selection} | jq -c)
|
||||||
@@ -87,19 +95,15 @@ jobs:
|
|||||||
ref: ${{ github.event.pull_request.head.sha }}
|
ref: ${{ github.event.pull_request.head.sha }}
|
||||||
|
|
||||||
- name: Setup QEMU
|
- name: Setup QEMU
|
||||||
timeout-minutes: 20
|
timeout-minutes: 60
|
||||||
run: |
|
run: .github/workflows/scripts/qemu-1-setup.sh
|
||||||
# Add a timestamp to each line to debug timeouts
|
|
||||||
while IFS=$'\n' read -r line; do
|
|
||||||
echo "$(date +'%H:%M:%S') $line"
|
|
||||||
done < <(.github/workflows/scripts/qemu-1-setup.sh)
|
|
||||||
|
|
||||||
- name: Start build machine
|
- name: Start build machine
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
run: .github/workflows/scripts/qemu-2-start.sh ${{ matrix.os }}
|
run: .github/workflows/scripts/qemu-2-start.sh ${{ matrix.os }}
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
timeout-minutes: 20
|
timeout-minutes: 60
|
||||||
run: .github/workflows/scripts/qemu-3-deps.sh ${{ matrix.os }} ${{ github.event.inputs.fedora_kernel_ver }}
|
run: .github/workflows/scripts/qemu-3-deps.sh ${{ matrix.os }} ${{ github.event.inputs.fedora_kernel_ver }}
|
||||||
|
|
||||||
- name: Build modules
|
- name: Build modules
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
Meta: 1
|
Meta: 1
|
||||||
Name: zfs
|
Name: zfs
|
||||||
Branch: 1.0
|
Branch: 1.0
|
||||||
Version: 2.3.5
|
Version: 2.3.6
|
||||||
Release: 1
|
Release: 1
|
||||||
Release-Tags: relext
|
Release-Tags: relext
|
||||||
License: CDDL
|
License: CDDL
|
||||||
Author: OpenZFS
|
Author: OpenZFS
|
||||||
Linux-Maximum: 6.17
|
Linux-Maximum: 6.19
|
||||||
Linux-Minimum: 4.18
|
Linux-Minimum: 4.18
|
||||||
|
|||||||
@@ -264,9 +264,21 @@ cmp_data(raidz_test_opts_t *opts, raidz_map_t *rm)
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
init_rand(void *data, size_t size, void *private)
|
init_rand(void *data, size_t size, void *private)
|
||||||
|
{
|
||||||
|
size_t *offsetp = (size_t *)private;
|
||||||
|
size_t offset = *offsetp;
|
||||||
|
|
||||||
|
VERIFY3U(offset + size, <=, SPA_MAXBLOCKSIZE);
|
||||||
|
memcpy(data, (char *)rand_data + offset, size);
|
||||||
|
*offsetp = offset + size;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
corrupt_rand_fill(void *data, size_t size, void *private)
|
||||||
{
|
{
|
||||||
(void) private;
|
(void) private;
|
||||||
memcpy(data, rand_data, size);
|
memset(data, 0xAA, size);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,7 +290,7 @@ corrupt_colums(raidz_map_t *rm, const int *tgts, const int cnt)
|
|||||||
for (int i = 0; i < cnt; i++) {
|
for (int i = 0; i < cnt; i++) {
|
||||||
raidz_col_t *col = &rr->rr_col[tgts[i]];
|
raidz_col_t *col = &rr->rr_col[tgts[i]];
|
||||||
abd_iterate_func(col->rc_abd, 0, col->rc_size,
|
abd_iterate_func(col->rc_abd, 0, col->rc_size,
|
||||||
init_rand, NULL);
|
corrupt_rand_fill, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -286,7 +298,8 @@ corrupt_colums(raidz_map_t *rm, const int *tgts, const int cnt)
|
|||||||
void
|
void
|
||||||
init_zio_abd(zio_t *zio)
|
init_zio_abd(zio_t *zio)
|
||||||
{
|
{
|
||||||
abd_iterate_func(zio->io_abd, 0, zio->io_size, init_rand, NULL);
|
size_t offset = 0;
|
||||||
|
abd_iterate_func(zio->io_abd, 0, zio->io_size, init_rand, &offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -373,7 +386,7 @@ init_raidz_map(raidz_test_opts_t *opts, zio_t **zio, const int parity)
|
|||||||
|
|
||||||
*zio = umem_zalloc(sizeof (zio_t), UMEM_NOFAIL);
|
*zio = umem_zalloc(sizeof (zio_t), UMEM_NOFAIL);
|
||||||
|
|
||||||
(*zio)->io_offset = 0;
|
(*zio)->io_offset = opts->rto_offset;
|
||||||
(*zio)->io_size = alloc_dsize;
|
(*zio)->io_size = alloc_dsize;
|
||||||
(*zio)->io_abd = raidz_alloc(alloc_dsize);
|
(*zio)->io_abd = raidz_alloc(alloc_dsize);
|
||||||
init_zio_abd(*zio);
|
init_zio_abd(*zio);
|
||||||
@@ -834,6 +847,8 @@ main(int argc, char **argv)
|
|||||||
err = run_test(NULL);
|
err = run_test(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mprotect(rand_data, SPA_MAXBLOCKSIZE, PROT_READ | PROT_WRITE);
|
||||||
|
|
||||||
umem_free(rand_data, SPA_MAXBLOCKSIZE);
|
umem_free(rand_data, SPA_MAXBLOCKSIZE);
|
||||||
kernel_fini();
|
kernel_fini();
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ typedef struct raidz_test_opts {
|
|||||||
|
|
||||||
static const raidz_test_opts_t rto_opts_defaults = {
|
static const raidz_test_opts_t rto_opts_defaults = {
|
||||||
.rto_ashift = 9,
|
.rto_ashift = 9,
|
||||||
.rto_offset = 1ULL << 0,
|
.rto_offset = 0,
|
||||||
.rto_dcols = 8,
|
.rto_dcols = 8,
|
||||||
.rto_dsize = 1<<19,
|
.rto_dsize = 1<<19,
|
||||||
.rto_v = D_ALL,
|
.rto_v = D_ALL,
|
||||||
|
|||||||
+39
-6
@@ -107,7 +107,9 @@ extern uint_t zfs_reconstruct_indirect_combinations_max;
|
|||||||
extern uint_t zfs_btree_verify_intensity;
|
extern uint_t zfs_btree_verify_intensity;
|
||||||
|
|
||||||
static const char cmdname[] = "zdb";
|
static const char cmdname[] = "zdb";
|
||||||
uint8_t dump_opt[256];
|
uint8_t dump_opt[512];
|
||||||
|
|
||||||
|
#define ALLOCATED_OPT 256
|
||||||
|
|
||||||
typedef void object_viewer_t(objset_t *, uint64_t, void *data, size_t size);
|
typedef void object_viewer_t(objset_t *, uint64_t, void *data, size_t size);
|
||||||
|
|
||||||
@@ -1651,6 +1653,16 @@ dump_metaslab_stats(metaslab_t *msp)
|
|||||||
dump_histogram(rt->rt_histogram, ZFS_RANGE_TREE_HISTOGRAM_SIZE, 0);
|
dump_histogram(rt->rt_histogram, ZFS_RANGE_TREE_HISTOGRAM_SIZE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dump_allocated(void *arg, uint64_t start, uint64_t size)
|
||||||
|
{
|
||||||
|
uint64_t *off = arg;
|
||||||
|
if (*off != start)
|
||||||
|
(void) printf("ALLOC: %"PRIu64" %"PRIu64"\n", *off,
|
||||||
|
start - *off);
|
||||||
|
*off = start + size;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dump_metaslab(metaslab_t *msp)
|
dump_metaslab(metaslab_t *msp)
|
||||||
{
|
{
|
||||||
@@ -1667,13 +1679,24 @@ dump_metaslab(metaslab_t *msp)
|
|||||||
(u_longlong_t)msp->ms_id, (u_longlong_t)msp->ms_start,
|
(u_longlong_t)msp->ms_id, (u_longlong_t)msp->ms_start,
|
||||||
(u_longlong_t)space_map_object(sm), freebuf);
|
(u_longlong_t)space_map_object(sm), freebuf);
|
||||||
|
|
||||||
if (dump_opt['m'] > 2 && !dump_opt['L']) {
|
if (dump_opt[ALLOCATED_OPT] ||
|
||||||
|
(dump_opt['m'] > 2 && !dump_opt['L'])) {
|
||||||
mutex_enter(&msp->ms_lock);
|
mutex_enter(&msp->ms_lock);
|
||||||
VERIFY0(metaslab_load(msp));
|
VERIFY0(metaslab_load(msp));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dump_opt['m'] > 2 && !dump_opt['L']) {
|
||||||
zfs_range_tree_stat_verify(msp->ms_allocatable);
|
zfs_range_tree_stat_verify(msp->ms_allocatable);
|
||||||
dump_metaslab_stats(msp);
|
dump_metaslab_stats(msp);
|
||||||
metaslab_unload(msp);
|
}
|
||||||
mutex_exit(&msp->ms_lock);
|
|
||||||
|
if (dump_opt[ALLOCATED_OPT]) {
|
||||||
|
uint64_t off = msp->ms_start;
|
||||||
|
zfs_range_tree_walk(msp->ms_allocatable, dump_allocated,
|
||||||
|
&off);
|
||||||
|
if (off != msp->ms_start + msp->ms_size)
|
||||||
|
(void) printf("ALLOC: %"PRIu64" %"PRIu64"\n", off,
|
||||||
|
msp->ms_size - off);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dump_opt['m'] > 1 && sm != NULL &&
|
if (dump_opt['m'] > 1 && sm != NULL &&
|
||||||
@@ -1688,6 +1711,12 @@ dump_metaslab(metaslab_t *msp)
|
|||||||
SPACE_MAP_HISTOGRAM_SIZE, sm->sm_shift);
|
SPACE_MAP_HISTOGRAM_SIZE, sm->sm_shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dump_opt[ALLOCATED_OPT] ||
|
||||||
|
(dump_opt['m'] > 2 && !dump_opt['L'])) {
|
||||||
|
metaslab_unload(msp);
|
||||||
|
mutex_exit(&msp->ms_lock);
|
||||||
|
}
|
||||||
|
|
||||||
if (vd->vdev_ops == &vdev_draid_ops)
|
if (vd->vdev_ops == &vdev_draid_ops)
|
||||||
ASSERT3U(msp->ms_size, <=, 1ULL << vd->vdev_ms_shift);
|
ASSERT3U(msp->ms_size, <=, 1ULL << vd->vdev_ms_shift);
|
||||||
else
|
else
|
||||||
@@ -1724,8 +1753,9 @@ print_vdev_metaslab_header(vdev_t *vd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(void) printf("\tvdev %10llu %s",
|
(void) printf("\tvdev %10llu\t%s metaslab shift %4llu",
|
||||||
(u_longlong_t)vd->vdev_id, bias_str);
|
(u_longlong_t)vd->vdev_id, bias_str,
|
||||||
|
(u_longlong_t)vd->vdev_ms_shift);
|
||||||
|
|
||||||
if (ms_flush_data_obj != 0) {
|
if (ms_flush_data_obj != 0) {
|
||||||
(void) printf(" ms_unflushed_phys object %llu",
|
(void) printf(" ms_unflushed_phys object %llu",
|
||||||
@@ -9318,6 +9348,8 @@ main(int argc, char **argv)
|
|||||||
{"all-reconstruction", no_argument, NULL, 'Y'},
|
{"all-reconstruction", no_argument, NULL, 'Y'},
|
||||||
{"livelist", no_argument, NULL, 'y'},
|
{"livelist", no_argument, NULL, 'y'},
|
||||||
{"zstd-headers", no_argument, NULL, 'Z'},
|
{"zstd-headers", no_argument, NULL, 'Z'},
|
||||||
|
{"allocated-map", no_argument, NULL,
|
||||||
|
ALLOCATED_OPT},
|
||||||
{0, 0, 0, 0}
|
{0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -9348,6 +9380,7 @@ main(int argc, char **argv)
|
|||||||
case 'u':
|
case 'u':
|
||||||
case 'y':
|
case 'y':
|
||||||
case 'Z':
|
case 'Z':
|
||||||
|
case ALLOCATED_OPT:
|
||||||
dump_opt[c]++;
|
dump_opt[c]++;
|
||||||
dump_all = 0;
|
dump_all = 0;
|
||||||
break;
|
break;
|
||||||
|
|||||||
+1
-1
@@ -29,6 +29,6 @@
|
|||||||
#define _ZDB_H
|
#define _ZDB_H
|
||||||
|
|
||||||
void dump_intent_log(zilog_t *);
|
void dump_intent_log(zilog_t *);
|
||||||
extern uint8_t dump_opt[256];
|
extern uint8_t dump_opt[512];
|
||||||
|
|
||||||
#endif /* _ZDB_H */
|
#endif /* _ZDB_H */
|
||||||
|
|||||||
@@ -48,8 +48,6 @@
|
|||||||
|
|
||||||
#include "zdb.h"
|
#include "zdb.h"
|
||||||
|
|
||||||
extern uint8_t dump_opt[256];
|
|
||||||
|
|
||||||
static char tab_prefix[4] = "\t\t\t";
|
static char tab_prefix[4] = "\t\t\t";
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|||||||
+344
-6
@@ -52,12 +52,15 @@
|
|||||||
#include <sys/zio_compress.h>
|
#include <sys/zio_compress.h>
|
||||||
#include <sys/zfeature.h>
|
#include <sys/zfeature.h>
|
||||||
#include <sys/dmu_tx.h>
|
#include <sys/dmu_tx.h>
|
||||||
|
#include <sys/backtrace.h>
|
||||||
#include <zfeature_common.h>
|
#include <zfeature_common.h>
|
||||||
#include <libzutil.h>
|
#include <libzutil.h>
|
||||||
|
#include <sys/metaslab_impl.h>
|
||||||
|
|
||||||
static importargs_t g_importargs;
|
static importargs_t g_importargs;
|
||||||
static char *g_pool;
|
static char *g_pool;
|
||||||
static boolean_t g_readonly;
|
static boolean_t g_readonly;
|
||||||
|
static boolean_t g_dump_dbgmsg;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ZHACK_REPAIR_OP_UNKNOWN = 0,
|
ZHACK_REPAIR_OP_UNKNOWN = 0,
|
||||||
@@ -69,11 +72,23 @@ static __attribute__((noreturn)) void
|
|||||||
usage(void)
|
usage(void)
|
||||||
{
|
{
|
||||||
(void) fprintf(stderr,
|
(void) fprintf(stderr,
|
||||||
"Usage: zhack [-c cachefile] [-d dir] <subcommand> <args> ...\n"
|
"Usage: zhack [-o tunable] [-c cachefile] [-d dir] [-G] "
|
||||||
"where <subcommand> <args> is one of the following:\n"
|
"<subcommand> <args> ...\n"
|
||||||
|
" where <subcommand> <args> is one of the following:\n"
|
||||||
"\n");
|
"\n");
|
||||||
|
|
||||||
(void) fprintf(stderr,
|
(void) fprintf(stderr,
|
||||||
|
" global options:\n"
|
||||||
|
" -c <cachefile> reads config from the given cachefile\n"
|
||||||
|
" -d <dir> directory with vdevs for import\n"
|
||||||
|
" -o var=value... set global variable to an unsigned "
|
||||||
|
"32-bit integer\n"
|
||||||
|
" -G dump zfs_dbgmsg buffer before exiting\n"
|
||||||
|
"\n"
|
||||||
|
" action idle <pool> [-f] [-t seconds]\n"
|
||||||
|
" import the pool for a set time then export it\n"
|
||||||
|
" -t <seconds> sets the time the pool is imported\n"
|
||||||
|
"\n"
|
||||||
" feature stat <pool>\n"
|
" feature stat <pool>\n"
|
||||||
" print information about enabled features\n"
|
" print information about enabled features\n"
|
||||||
" feature enable [-r] [-d desc] <pool> <feature>\n"
|
" feature enable [-r] [-d desc] <pool> <feature>\n"
|
||||||
@@ -93,10 +108,46 @@ usage(void)
|
|||||||
" -c repair corrupted label checksums\n"
|
" -c repair corrupted label checksums\n"
|
||||||
" -u restore the label on a detached device\n"
|
" -u restore the label on a detached device\n"
|
||||||
"\n"
|
"\n"
|
||||||
" <device> : path to vdev\n");
|
" <device> : path to vdev\n"
|
||||||
|
"\n"
|
||||||
|
" metaslab leak <pool>\n"
|
||||||
|
" apply allocation map from zdb to specified pool\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dump_debug_buffer(void)
|
||||||
|
{
|
||||||
|
ssize_t ret __attribute__((unused));
|
||||||
|
|
||||||
|
if (!g_dump_dbgmsg)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We use write() instead of printf() so that this function
|
||||||
|
* is safe to call from a signal handler.
|
||||||
|
*/
|
||||||
|
ret = write(STDERR_FILENO, "\n", 1);
|
||||||
|
zfs_dbgmsg_print(STDERR_FILENO, "zhack");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sig_handler(int signo)
|
||||||
|
{
|
||||||
|
struct sigaction action;
|
||||||
|
|
||||||
|
libspl_backtrace(STDERR_FILENO);
|
||||||
|
dump_debug_buffer();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Restore default action and re-raise signal so SIGSEGV and
|
||||||
|
* SIGABRT can trigger a core dump.
|
||||||
|
*/
|
||||||
|
action.sa_handler = SIG_DFL;
|
||||||
|
sigemptyset(&action.sa_mask);
|
||||||
|
action.sa_flags = 0;
|
||||||
|
(void) sigaction(signo, &action, NULL);
|
||||||
|
raise(signo);
|
||||||
|
}
|
||||||
|
|
||||||
static __attribute__((format(printf, 3, 4))) __attribute__((noreturn)) void
|
static __attribute__((format(printf, 3, 4))) __attribute__((noreturn)) void
|
||||||
fatal(spa_t *spa, const void *tag, const char *fmt, ...)
|
fatal(spa_t *spa, const void *tag, const char *fmt, ...)
|
||||||
@@ -114,6 +165,8 @@ fatal(spa_t *spa, const void *tag, const char *fmt, ...)
|
|||||||
va_end(ap);
|
va_end(ap);
|
||||||
(void) fputc('\n', stderr);
|
(void) fputc('\n', stderr);
|
||||||
|
|
||||||
|
dump_debug_buffer();
|
||||||
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,7 +222,7 @@ zhack_import(char *target, boolean_t readonly)
|
|||||||
|
|
||||||
zfeature_checks_disable = B_TRUE;
|
zfeature_checks_disable = B_TRUE;
|
||||||
error = spa_import(target, config, props,
|
error = spa_import(target, config, props,
|
||||||
(readonly ? ZFS_IMPORT_SKIP_MMP : ZFS_IMPORT_NORMAL));
|
(readonly ? ZFS_IMPORT_SKIP_MMP : ZFS_IMPORT_NORMAL));
|
||||||
fnvlist_free(config);
|
fnvlist_free(config);
|
||||||
zfeature_checks_disable = B_FALSE;
|
zfeature_checks_disable = B_FALSE;
|
||||||
if (error == EEXIST)
|
if (error == EEXIST)
|
||||||
@@ -500,6 +553,259 @@ zhack_do_feature(int argc, char **argv)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
zhack_do_action_idle(int argc, char **argv)
|
||||||
|
{
|
||||||
|
spa_t *spa;
|
||||||
|
char *target, *tmp;
|
||||||
|
int idle_time = 0;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
optind = 1;
|
||||||
|
while ((c = getopt(argc, argv, "+t:")) != -1) {
|
||||||
|
switch (c) {
|
||||||
|
case 't':
|
||||||
|
idle_time = strtol(optarg, &tmp, 0);
|
||||||
|
if (*tmp) {
|
||||||
|
(void) fprintf(stderr, "error: time must "
|
||||||
|
"be an integer in seconds: %s\n", tmp);
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
if (idle_time < 0) {
|
||||||
|
(void) fprintf(stderr, "error: time must "
|
||||||
|
"not be negative: %d\n", idle_time);
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
argc -= optind;
|
||||||
|
argv += optind;
|
||||||
|
|
||||||
|
if (argc < 1) {
|
||||||
|
(void) fprintf(stderr, "error: missing pool name\n");
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
target = argv[0];
|
||||||
|
|
||||||
|
zhack_spa_open(target, B_FALSE, FTAG, &spa);
|
||||||
|
|
||||||
|
fprintf(stdout, "Imported pool %s, idle for %d seconds\n",
|
||||||
|
target, idle_time);
|
||||||
|
sleep(idle_time);
|
||||||
|
|
||||||
|
spa_close(spa, FTAG);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
zhack_do_action(int argc, char **argv)
|
||||||
|
{
|
||||||
|
char *subcommand;
|
||||||
|
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
|
if (argc == 0) {
|
||||||
|
(void) fprintf(stderr,
|
||||||
|
"error: no import operation specified\n");
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
subcommand = argv[0];
|
||||||
|
if (strcmp(subcommand, "idle") == 0) {
|
||||||
|
zhack_do_action_idle(argc, argv);
|
||||||
|
} else {
|
||||||
|
(void) fprintf(stderr, "error: unknown subcommand: %s\n",
|
||||||
|
subcommand);
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static boolean_t
|
||||||
|
strstarts(const char *a, const char *b)
|
||||||
|
{
|
||||||
|
return (strncmp(a, b, strlen(b)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
metaslab_force_alloc(metaslab_t *msp, uint64_t start, uint64_t size,
|
||||||
|
dmu_tx_t *tx)
|
||||||
|
{
|
||||||
|
ASSERT(msp->ms_disabled);
|
||||||
|
ASSERT(MUTEX_HELD(&msp->ms_lock));
|
||||||
|
uint64_t txg = dmu_tx_get_txg(tx);
|
||||||
|
|
||||||
|
uint64_t off = start;
|
||||||
|
while (off < start + size) {
|
||||||
|
uint64_t ostart, osize;
|
||||||
|
boolean_t found = zfs_range_tree_find_in(msp->ms_allocatable,
|
||||||
|
off, start + size - off, &ostart, &osize);
|
||||||
|
if (!found)
|
||||||
|
break;
|
||||||
|
zfs_range_tree_remove(msp->ms_allocatable, ostart, osize);
|
||||||
|
|
||||||
|
if (zfs_range_tree_is_empty(msp->ms_allocating[txg & TXG_MASK]))
|
||||||
|
vdev_dirty(msp->ms_group->mg_vd, VDD_METASLAB, msp,
|
||||||
|
txg);
|
||||||
|
|
||||||
|
zfs_range_tree_add(msp->ms_allocating[txg & TXG_MASK], ostart,
|
||||||
|
osize);
|
||||||
|
msp->ms_allocating_total += osize;
|
||||||
|
off = ostart + osize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
zhack_do_metaslab_leak(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
char *target;
|
||||||
|
spa_t *spa;
|
||||||
|
|
||||||
|
optind = 1;
|
||||||
|
boolean_t force = B_FALSE;
|
||||||
|
while ((c = getopt(argc, argv, "f")) != -1) {
|
||||||
|
switch (c) {
|
||||||
|
case 'f':
|
||||||
|
force = B_TRUE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
argc -= optind;
|
||||||
|
argv += optind;
|
||||||
|
|
||||||
|
if (argc < 1) {
|
||||||
|
(void) fprintf(stderr, "error: missing pool name\n");
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
target = argv[0];
|
||||||
|
|
||||||
|
zhack_spa_open(target, B_FALSE, FTAG, &spa);
|
||||||
|
spa_config_enter(spa, SCL_VDEV | SCL_ALLOC, FTAG, RW_READER);
|
||||||
|
|
||||||
|
char *line = NULL;
|
||||||
|
size_t cap = 0;
|
||||||
|
|
||||||
|
vdev_t *vd = NULL;
|
||||||
|
metaslab_t *prev = NULL;
|
||||||
|
dmu_tx_t *tx = NULL;
|
||||||
|
while (getline(&line, &cap, stdin) > 0) {
|
||||||
|
if (strstarts(line, "\tvdev ")) {
|
||||||
|
uint64_t vdev_id, ms_shift;
|
||||||
|
if (sscanf(line,
|
||||||
|
"\tvdev %10"PRIu64"\t%*s metaslab shift %4"PRIu64,
|
||||||
|
&vdev_id, &ms_shift) == 1) {
|
||||||
|
VERIFY3U(sscanf(line, "\tvdev %"PRIu64
|
||||||
|
"\t metaslab shift %4"PRIu64,
|
||||||
|
&vdev_id, &ms_shift), ==, 2);
|
||||||
|
}
|
||||||
|
vd = vdev_lookup_top(spa, vdev_id);
|
||||||
|
if (vd == NULL) {
|
||||||
|
fprintf(stderr, "error: no such vdev with "
|
||||||
|
"id %"PRIu64"\n", vdev_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (tx) {
|
||||||
|
dmu_tx_commit(tx);
|
||||||
|
mutex_exit(&prev->ms_lock);
|
||||||
|
metaslab_enable(prev, B_FALSE, B_FALSE);
|
||||||
|
tx = NULL;
|
||||||
|
prev = NULL;
|
||||||
|
}
|
||||||
|
if (vd->vdev_ms_shift != ms_shift) {
|
||||||
|
fprintf(stderr, "error: ms_shift mismatch: %"
|
||||||
|
PRIu64" != %"PRIu64"\n", vd->vdev_ms_shift,
|
||||||
|
ms_shift);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (strstarts(line, "\tmetaslabs ")) {
|
||||||
|
uint64_t ms_count;
|
||||||
|
VERIFY3U(sscanf(line, "\tmetaslabs %"PRIu64, &ms_count),
|
||||||
|
==, 1);
|
||||||
|
ASSERT(vd);
|
||||||
|
if (!force && vd->vdev_ms_count != ms_count) {
|
||||||
|
fprintf(stderr, "error: ms_count mismatch: %"
|
||||||
|
PRIu64" != %"PRIu64"\n", vd->vdev_ms_count,
|
||||||
|
ms_count);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (strstarts(line, "ALLOC:")) {
|
||||||
|
uint64_t start, size;
|
||||||
|
VERIFY3U(sscanf(line, "ALLOC: %"PRIu64" %"PRIu64"\n",
|
||||||
|
&start, &size), ==, 2);
|
||||||
|
|
||||||
|
ASSERT(vd);
|
||||||
|
metaslab_t *cur =
|
||||||
|
vd->vdev_ms[start >> vd->vdev_ms_shift];
|
||||||
|
if (prev != cur) {
|
||||||
|
if (prev) {
|
||||||
|
dmu_tx_commit(tx);
|
||||||
|
mutex_exit(&prev->ms_lock);
|
||||||
|
metaslab_enable(prev, B_FALSE, B_FALSE);
|
||||||
|
}
|
||||||
|
ASSERT(cur);
|
||||||
|
metaslab_disable(cur);
|
||||||
|
mutex_enter(&cur->ms_lock);
|
||||||
|
metaslab_load(cur);
|
||||||
|
prev = cur;
|
||||||
|
tx = dmu_tx_create_dd(
|
||||||
|
spa_get_dsl(vd->vdev_spa)->dp_root_dir);
|
||||||
|
dmu_tx_assign(tx, DMU_TX_WAIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
metaslab_force_alloc(cur, start, size, tx);
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tx) {
|
||||||
|
dmu_tx_commit(tx);
|
||||||
|
mutex_exit(&prev->ms_lock);
|
||||||
|
metaslab_enable(prev, B_FALSE, B_FALSE);
|
||||||
|
tx = NULL;
|
||||||
|
prev = NULL;
|
||||||
|
}
|
||||||
|
if (line)
|
||||||
|
free(line);
|
||||||
|
|
||||||
|
spa_config_exit(spa, SCL_VDEV | SCL_ALLOC, FTAG);
|
||||||
|
spa_close(spa, FTAG);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
zhack_do_metaslab(int argc, char **argv)
|
||||||
|
{
|
||||||
|
char *subcommand;
|
||||||
|
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
|
if (argc == 0) {
|
||||||
|
(void) fprintf(stderr,
|
||||||
|
"error: no metaslab operation specified\n");
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
subcommand = argv[0];
|
||||||
|
if (strcmp(subcommand, "leak") == 0) {
|
||||||
|
zhack_do_metaslab_leak(argc, argv);
|
||||||
|
} else {
|
||||||
|
(void) fprintf(stderr, "error: unknown subcommand: %s\n",
|
||||||
|
subcommand);
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
#define ASHIFT_UBERBLOCK_SHIFT(ashift) \
|
#define ASHIFT_UBERBLOCK_SHIFT(ashift) \
|
||||||
MIN(MAX(ashift, UBERBLOCK_SHIFT), \
|
MIN(MAX(ashift, UBERBLOCK_SHIFT), \
|
||||||
MAX_UBERBLOCK_SHIFT)
|
MAX_UBERBLOCK_SHIFT)
|
||||||
@@ -975,17 +1281,35 @@ zhack_do_label(int argc, char **argv)
|
|||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
struct sigaction action;
|
||||||
char *path[MAX_NUM_PATHS];
|
char *path[MAX_NUM_PATHS];
|
||||||
const char *subcommand;
|
const char *subcommand;
|
||||||
int rv = 0;
|
int rv = 0;
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up signal handlers, so if we crash due to bad on-disk data we
|
||||||
|
* can get more info. Unlike ztest, we don't bail out if we can't set
|
||||||
|
* up signal handlers, because zhack is very useful without them.
|
||||||
|
*/
|
||||||
|
action.sa_handler = sig_handler;
|
||||||
|
sigemptyset(&action.sa_mask);
|
||||||
|
action.sa_flags = 0;
|
||||||
|
if (sigaction(SIGSEGV, &action, NULL) < 0) {
|
||||||
|
(void) fprintf(stderr, "zhack: cannot catch SIGSEGV: %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
}
|
||||||
|
if (sigaction(SIGABRT, &action, NULL) < 0) {
|
||||||
|
(void) fprintf(stderr, "zhack: cannot catch SIGABRT: %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
g_importargs.path = path;
|
g_importargs.path = path;
|
||||||
|
|
||||||
dprintf_setup(&argc, argv);
|
dprintf_setup(&argc, argv);
|
||||||
zfs_prop_init();
|
zfs_prop_init();
|
||||||
|
|
||||||
while ((c = getopt(argc, argv, "+c:d:")) != -1) {
|
while ((c = getopt(argc, argv, "+c:d:Go:")) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'c':
|
case 'c':
|
||||||
g_importargs.cachefile = optarg;
|
g_importargs.cachefile = optarg;
|
||||||
@@ -994,6 +1318,13 @@ main(int argc, char **argv)
|
|||||||
assert(g_importargs.paths < MAX_NUM_PATHS);
|
assert(g_importargs.paths < MAX_NUM_PATHS);
|
||||||
g_importargs.path[g_importargs.paths++] = optarg;
|
g_importargs.path[g_importargs.paths++] = optarg;
|
||||||
break;
|
break;
|
||||||
|
case 'G':
|
||||||
|
g_dump_dbgmsg = B_TRUE;
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
if (set_global_var(optarg) != 0)
|
||||||
|
exit(1);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
break;
|
break;
|
||||||
@@ -1011,10 +1342,14 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
subcommand = argv[0];
|
subcommand = argv[0];
|
||||||
|
|
||||||
if (strcmp(subcommand, "feature") == 0) {
|
if (strcmp(subcommand, "action") == 0) {
|
||||||
|
rv = zhack_do_action(argc, argv);
|
||||||
|
} else if (strcmp(subcommand, "feature") == 0) {
|
||||||
rv = zhack_do_feature(argc, argv);
|
rv = zhack_do_feature(argc, argv);
|
||||||
} else if (strcmp(subcommand, "label") == 0) {
|
} else if (strcmp(subcommand, "label") == 0) {
|
||||||
return (zhack_do_label(argc, argv));
|
return (zhack_do_label(argc, argv));
|
||||||
|
} else if (strcmp(subcommand, "metaslab") == 0) {
|
||||||
|
rv = zhack_do_metaslab(argc, argv);
|
||||||
} else {
|
} else {
|
||||||
(void) fprintf(stderr, "error: unknown subcommand: %s\n",
|
(void) fprintf(stderr, "error: unknown subcommand: %s\n",
|
||||||
subcommand);
|
subcommand);
|
||||||
@@ -1026,6 +1361,9 @@ main(int argc, char **argv)
|
|||||||
"changes may not be committed to disk\n");
|
"changes may not be committed to disk\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (g_dump_dbgmsg)
|
||||||
|
dump_debug_buffer();
|
||||||
|
|
||||||
kernel_fini();
|
kernel_fini();
|
||||||
|
|
||||||
return (rv);
|
return (rv);
|
||||||
|
|||||||
@@ -3883,6 +3883,9 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts,
|
|||||||
hostid, ctime(×tamp));
|
hostid, ctime(×tamp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (getenv("ZFS_LOAD_INFO_DEBUG"))
|
||||||
|
dump_nvlist(nvinfo, 4);
|
||||||
|
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+33
-31
@@ -270,14 +270,13 @@ is_spare(nvlist_t *config, const char *path)
|
|||||||
* draid* Virtual dRAID spare
|
* draid* Virtual dRAID spare
|
||||||
*/
|
*/
|
||||||
static nvlist_t *
|
static nvlist_t *
|
||||||
make_leaf_vdev(nvlist_t *props, const char *arg, boolean_t is_primary)
|
make_leaf_vdev(const char *arg, boolean_t is_primary, uint64_t ashift)
|
||||||
{
|
{
|
||||||
char path[MAXPATHLEN];
|
char path[MAXPATHLEN];
|
||||||
struct stat64 statbuf;
|
struct stat64 statbuf;
|
||||||
nvlist_t *vdev = NULL;
|
nvlist_t *vdev = NULL;
|
||||||
const char *type = NULL;
|
const char *type = NULL;
|
||||||
boolean_t wholedisk = B_FALSE;
|
boolean_t wholedisk = B_FALSE;
|
||||||
uint64_t ashift = 0;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -381,31 +380,6 @@ make_leaf_vdev(nvlist_t *props, const char *arg, boolean_t is_primary)
|
|||||||
verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK,
|
verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK,
|
||||||
(uint64_t)wholedisk) == 0);
|
(uint64_t)wholedisk) == 0);
|
||||||
|
|
||||||
/*
|
|
||||||
* Override defaults if custom properties are provided.
|
|
||||||
*/
|
|
||||||
if (props != NULL) {
|
|
||||||
const char *value = NULL;
|
|
||||||
|
|
||||||
if (nvlist_lookup_string(props,
|
|
||||||
zpool_prop_to_name(ZPOOL_PROP_ASHIFT), &value) == 0) {
|
|
||||||
if (zfs_nicestrtonum(NULL, value, &ashift) != 0) {
|
|
||||||
(void) fprintf(stderr,
|
|
||||||
gettext("ashift must be a number.\n"));
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
if (ashift != 0 &&
|
|
||||||
(ashift < ASHIFT_MIN || ashift > ASHIFT_MAX)) {
|
|
||||||
(void) fprintf(stderr,
|
|
||||||
gettext("invalid 'ashift=%" PRIu64 "' "
|
|
||||||
"property: only values between %" PRId32 " "
|
|
||||||
"and %" PRId32 " are allowed.\n"),
|
|
||||||
ashift, ASHIFT_MIN, ASHIFT_MAX);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the device is known to incorrectly report its physical sector
|
* If the device is known to incorrectly report its physical sector
|
||||||
* size explicitly provide the known correct value.
|
* size explicitly provide the known correct value.
|
||||||
@@ -1502,6 +1476,29 @@ construct_spec(nvlist_t *props, int argc, char **argv)
|
|||||||
const char *type, *fulltype;
|
const char *type, *fulltype;
|
||||||
boolean_t is_log, is_special, is_dedup, is_spare;
|
boolean_t is_log, is_special, is_dedup, is_spare;
|
||||||
boolean_t seen_logs;
|
boolean_t seen_logs;
|
||||||
|
uint64_t ashift = 0;
|
||||||
|
|
||||||
|
if (props != NULL) {
|
||||||
|
const char *value = NULL;
|
||||||
|
|
||||||
|
if (nvlist_lookup_string(props,
|
||||||
|
zpool_prop_to_name(ZPOOL_PROP_ASHIFT), &value) == 0) {
|
||||||
|
if (zfs_nicestrtonum(NULL, value, &ashift) != 0) {
|
||||||
|
(void) fprintf(stderr,
|
||||||
|
gettext("ashift must be a number.\n"));
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
if (ashift != 0 &&
|
||||||
|
(ashift < ASHIFT_MIN || ashift > ASHIFT_MAX)) {
|
||||||
|
(void) fprintf(stderr,
|
||||||
|
gettext("invalid 'ashift=%" PRIu64 "' "
|
||||||
|
"property: only values between %" PRId32 " "
|
||||||
|
"and %" PRId32 " are allowed.\n"),
|
||||||
|
ashift, ASHIFT_MIN, ASHIFT_MAX);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
top = NULL;
|
top = NULL;
|
||||||
toplevels = 0;
|
toplevels = 0;
|
||||||
@@ -1608,9 +1605,9 @@ construct_spec(nvlist_t *props, int argc, char **argv)
|
|||||||
children * sizeof (nvlist_t *));
|
children * sizeof (nvlist_t *));
|
||||||
if (child == NULL)
|
if (child == NULL)
|
||||||
zpool_no_memory();
|
zpool_no_memory();
|
||||||
if ((nv = make_leaf_vdev(props, argv[c],
|
if ((nv = make_leaf_vdev(argv[c],
|
||||||
!(is_log || is_special || is_dedup ||
|
!(is_log || is_special || is_dedup ||
|
||||||
is_spare))) == NULL) {
|
is_spare), ashift)) == NULL) {
|
||||||
for (c = 0; c < children - 1; c++)
|
for (c = 0; c < children - 1; c++)
|
||||||
nvlist_free(child[c]);
|
nvlist_free(child[c]);
|
||||||
free(child);
|
free(child);
|
||||||
@@ -1674,6 +1671,10 @@ construct_spec(nvlist_t *props, int argc, char **argv)
|
|||||||
ZPOOL_CONFIG_ALLOCATION_BIAS,
|
ZPOOL_CONFIG_ALLOCATION_BIAS,
|
||||||
VDEV_ALLOC_BIAS_DEDUP) == 0);
|
VDEV_ALLOC_BIAS_DEDUP) == 0);
|
||||||
}
|
}
|
||||||
|
if (ashift > 0) {
|
||||||
|
fnvlist_add_uint64(nv,
|
||||||
|
ZPOOL_CONFIG_ASHIFT, ashift);
|
||||||
|
}
|
||||||
if (strcmp(type, VDEV_TYPE_RAIDZ) == 0) {
|
if (strcmp(type, VDEV_TYPE_RAIDZ) == 0) {
|
||||||
verify(nvlist_add_uint64(nv,
|
verify(nvlist_add_uint64(nv,
|
||||||
ZPOOL_CONFIG_NPARITY,
|
ZPOOL_CONFIG_NPARITY,
|
||||||
@@ -1701,8 +1702,9 @@ construct_spec(nvlist_t *props, int argc, char **argv)
|
|||||||
* We have a device. Pass off to make_leaf_vdev() to
|
* We have a device. Pass off to make_leaf_vdev() to
|
||||||
* construct the appropriate nvlist describing the vdev.
|
* construct the appropriate nvlist describing the vdev.
|
||||||
*/
|
*/
|
||||||
if ((nv = make_leaf_vdev(props, argv[0], !(is_log ||
|
if ((nv = make_leaf_vdev(argv[0], !(is_log ||
|
||||||
is_special || is_dedup || is_spare))) == NULL)
|
is_special || is_dedup || is_spare),
|
||||||
|
ashift)) == NULL)
|
||||||
goto spec_out;
|
goto spec_out;
|
||||||
|
|
||||||
verify(nvlist_add_uint64(nv,
|
verify(nvlist_add_uint64(nv,
|
||||||
|
|||||||
@@ -29,9 +29,8 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLKDEV_GET_BY_PATH_4ARG], [
|
|||||||
const char *path = "path";
|
const char *path = "path";
|
||||||
fmode_t mode = 0;
|
fmode_t mode = 0;
|
||||||
void *holder = NULL;
|
void *holder = NULL;
|
||||||
struct blk_holder_ops h;
|
|
||||||
|
|
||||||
bdev = blkdev_get_by_path(path, mode, holder, &h);
|
bdev = blkdev_get_by_path(path, mode, holder, NULL);
|
||||||
])
|
])
|
||||||
])
|
])
|
||||||
|
|
||||||
@@ -48,9 +47,8 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLKDEV_BDEV_OPEN_BY_PATH], [
|
|||||||
const char *path = "path";
|
const char *path = "path";
|
||||||
fmode_t mode = 0;
|
fmode_t mode = 0;
|
||||||
void *holder = NULL;
|
void *holder = NULL;
|
||||||
struct blk_holder_ops h;
|
|
||||||
|
|
||||||
bdh = bdev_open_by_path(path, mode, holder, &h);
|
bdh = bdev_open_by_path(path, mode, holder, NULL);
|
||||||
])
|
])
|
||||||
])
|
])
|
||||||
|
|
||||||
@@ -68,9 +66,8 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BDEV_FILE_OPEN_BY_PATH], [
|
|||||||
const char *path = "path";
|
const char *path = "path";
|
||||||
fmode_t mode = 0;
|
fmode_t mode = 0;
|
||||||
void *holder = NULL;
|
void *holder = NULL;
|
||||||
struct blk_holder_ops h;
|
|
||||||
|
|
||||||
file = bdev_file_open_by_path(path, mode, holder, &h);
|
file = bdev_file_open_by_path(path, mode, holder, NULL);
|
||||||
])
|
])
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|||||||
@@ -119,15 +119,49 @@ AC_DEFUN([ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_REVALIDATE_DISK], [
|
|||||||
])
|
])
|
||||||
])
|
])
|
||||||
|
|
||||||
|
dnl #
|
||||||
|
dnl # 6.18 API change
|
||||||
|
dnl # block_device_operation->getgeo takes struct gendisk* as first arg
|
||||||
|
dnl #
|
||||||
|
AC_DEFUN([ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_GETGEO_GENDISK], [
|
||||||
|
ZFS_LINUX_TEST_SRC([block_device_operations_getgeo_gendisk], [
|
||||||
|
#include <linux/blkdev.h>
|
||||||
|
|
||||||
|
static int blk_getgeo(struct gendisk *disk, struct hd_geometry *geo)
|
||||||
|
{
|
||||||
|
(void) disk, (void) geo;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct block_device_operations
|
||||||
|
bops __attribute__ ((unused)) = {
|
||||||
|
.getgeo = blk_getgeo,
|
||||||
|
};
|
||||||
|
], [], [])
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_DEFUN([ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_GETGEO_GENDISK], [
|
||||||
|
AC_MSG_CHECKING([whether bops->getgeo() takes gendisk as first arg])
|
||||||
|
ZFS_LINUX_TEST_RESULT([block_device_operations_getgeo_gendisk], [
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
AC_DEFINE([HAVE_BLOCK_DEVICE_OPERATIONS_GETGEO_GENDISK], [1],
|
||||||
|
[Define if getgeo() in block_device_operations takes struct gendisk * as its first arg])
|
||||||
|
],[
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
])
|
||||||
|
])
|
||||||
|
|
||||||
AC_DEFUN([ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS], [
|
AC_DEFUN([ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS], [
|
||||||
ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_CHECK_EVENTS
|
ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_CHECK_EVENTS
|
||||||
ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID
|
ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID
|
||||||
ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_RELEASE_1ARG
|
ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_RELEASE_1ARG
|
||||||
ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_REVALIDATE_DISK
|
ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_REVALIDATE_DISK
|
||||||
|
ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_GETGEO_GENDISK
|
||||||
])
|
])
|
||||||
|
|
||||||
AC_DEFUN([ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS], [
|
AC_DEFUN([ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS], [
|
||||||
ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_CHECK_EVENTS
|
ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_CHECK_EVENTS
|
||||||
ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID
|
ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID
|
||||||
ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_REVALIDATE_DISK
|
ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_REVALIDATE_DISK
|
||||||
|
ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_GETGEO_GENDISK
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -46,14 +46,37 @@ AC_DEFUN([ZFS_AC_KERNEL_D_SET_D_OP], [
|
|||||||
])
|
])
|
||||||
])
|
])
|
||||||
|
|
||||||
|
dnl #
|
||||||
|
dnl # 6.17 API change
|
||||||
|
dnl # sb->s_d_op removed; set_default_d_op(sb, dop) added
|
||||||
|
dnl #
|
||||||
|
AC_DEFUN([ZFS_AC_KERNEL_SRC_SET_DEFAULT_D_OP], [
|
||||||
|
ZFS_LINUX_TEST_SRC([set_default_d_op], [
|
||||||
|
#include <linux/dcache.h>
|
||||||
|
], [
|
||||||
|
set_default_d_op(NULL, NULL);
|
||||||
|
])
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_DEFUN([ZFS_AC_KERNEL_SET_DEFAULT_D_OP], [
|
||||||
|
AC_MSG_CHECKING([whether set_default_d_op() is available])
|
||||||
|
ZFS_LINUX_TEST_RESULT([set_default_d_op], [
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
AC_DEFINE(HAVE_SET_DEFAULT_D_OP, 1,
|
||||||
|
[Define if set_default_d_op() is available])
|
||||||
|
], [
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
])
|
||||||
|
])
|
||||||
|
|
||||||
AC_DEFUN([ZFS_AC_KERNEL_SRC_DENTRY], [
|
AC_DEFUN([ZFS_AC_KERNEL_SRC_DENTRY], [
|
||||||
ZFS_AC_KERNEL_SRC_D_OBTAIN_ALIAS
|
ZFS_AC_KERNEL_SRC_D_OBTAIN_ALIAS
|
||||||
ZFS_AC_KERNEL_SRC_D_SET_D_OP
|
ZFS_AC_KERNEL_SRC_D_SET_D_OP
|
||||||
ZFS_AC_KERNEL_SRC_S_D_OP
|
ZFS_AC_KERNEL_SRC_SET_DEFAULT_D_OP
|
||||||
])
|
])
|
||||||
|
|
||||||
AC_DEFUN([ZFS_AC_KERNEL_DENTRY], [
|
AC_DEFUN([ZFS_AC_KERNEL_DENTRY], [
|
||||||
ZFS_AC_KERNEL_D_OBTAIN_ALIAS
|
ZFS_AC_KERNEL_D_OBTAIN_ALIAS
|
||||||
ZFS_AC_KERNEL_D_SET_D_OP
|
ZFS_AC_KERNEL_D_SET_D_OP
|
||||||
ZFS_AC_KERNEL_S_D_OP
|
ZFS_AC_KERNEL_SET_DEFAULT_D_OP
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
dnl #
|
||||||
|
dnl # 6.18 API change
|
||||||
|
dnl # - generic_drop_inode() renamed to inode_generic_drop()
|
||||||
|
dnl # - generic_delete_inode() renamed to inode_just_drop()
|
||||||
|
dnl #
|
||||||
|
AC_DEFUN([ZFS_AC_KERNEL_SRC_INODE_GENERIC_DROP], [
|
||||||
|
ZFS_LINUX_TEST_SRC([inode_generic_drop], [
|
||||||
|
#include <linux/fs.h>
|
||||||
|
],[
|
||||||
|
struct inode *ip = NULL;
|
||||||
|
inode_generic_drop(ip);
|
||||||
|
])
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_DEFUN([ZFS_AC_KERNEL_INODE_GENERIC_DROP], [
|
||||||
|
AC_MSG_CHECKING([whether inode_generic_drop() exists])
|
||||||
|
ZFS_LINUX_TEST_RESULT([inode_generic_drop], [
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
AC_DEFINE(HAVE_INODE_GENERIC_DROP, 1,
|
||||||
|
[inode_generic_drop() exists])
|
||||||
|
],[
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
])
|
||||||
|
])
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
dnl #
|
||||||
|
dnl # 6.19 API change. inode->i_state no longer accessible directly; helper
|
||||||
|
dnl # functions exist.
|
||||||
|
dnl #
|
||||||
|
AC_DEFUN([ZFS_AC_KERNEL_SRC_INODE_STATE_READ_ONCE], [
|
||||||
|
ZFS_LINUX_TEST_SRC([inode_state_read_once], [
|
||||||
|
#include <linux/fs.h>
|
||||||
|
], [
|
||||||
|
struct inode i = {};
|
||||||
|
inode_state_read_once(&i);
|
||||||
|
],[])
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_DEFUN([ZFS_AC_KERNEL_INODE_STATE_READ_ONCE], [
|
||||||
|
AC_MSG_CHECKING([whether inode_state_read_once() exists])
|
||||||
|
ZFS_LINUX_TEST_RESULT([inode_state_read_once], [
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
AC_DEFINE(HAVE_INODE_STATE_READ_ONCE, 1,
|
||||||
|
[inode_state_read_once() exists])
|
||||||
|
],[
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
])
|
||||||
|
])
|
||||||
@@ -7,7 +7,7 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_KMAP_ATOMIC_ARGS], [
|
|||||||
ZFS_LINUX_TEST_SRC([kmap_atomic], [
|
ZFS_LINUX_TEST_SRC([kmap_atomic], [
|
||||||
#include <linux/pagemap.h>
|
#include <linux/pagemap.h>
|
||||||
],[
|
],[
|
||||||
struct page page;
|
struct page page = {};
|
||||||
kmap_atomic(&page);
|
kmap_atomic(&page);
|
||||||
])
|
])
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -16,9 +16,36 @@ AC_DEFUN([ZFS_AC_KERNEL_MM_PAGE_FLAG_ERROR], [
|
|||||||
])
|
])
|
||||||
])
|
])
|
||||||
|
|
||||||
|
dnl #
|
||||||
|
dnl # Linux 6.18+ uses a struct typedef (memdesc_flags_t) instead of an
|
||||||
|
dnl # 'unsigned long' for the 'flags' field in 'struct page'.
|
||||||
|
dnl #
|
||||||
|
AC_DEFUN([ZFS_AC_KERNEL_SRC_MM_PAGE_FLAGS_STRUCT], [
|
||||||
|
ZFS_LINUX_TEST_SRC([mm_page_flags_struct], [
|
||||||
|
#include <linux/mm.h>
|
||||||
|
|
||||||
|
static const struct page p __attribute__ ((unused)) = {
|
||||||
|
.flags = { .f = 0 }
|
||||||
|
};
|
||||||
|
],[])
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_DEFUN([ZFS_AC_KERNEL_MM_PAGE_FLAGS_STRUCT], [
|
||||||
|
AC_MSG_CHECKING([whether 'flags' in 'struct page' is a struct])
|
||||||
|
ZFS_LINUX_TEST_RESULT([mm_page_flags_struct], [
|
||||||
|
AC_MSG_RESULT([yes])
|
||||||
|
AC_DEFINE(HAVE_MM_PAGE_FLAGS_STRUCT, 1,
|
||||||
|
['flags' in 'struct page' is a struct])
|
||||||
|
],[
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
])
|
||||||
|
])
|
||||||
|
|
||||||
AC_DEFUN([ZFS_AC_KERNEL_SRC_MM_PAGE_FLAGS], [
|
AC_DEFUN([ZFS_AC_KERNEL_SRC_MM_PAGE_FLAGS], [
|
||||||
ZFS_AC_KERNEL_SRC_MM_PAGE_FLAG_ERROR
|
ZFS_AC_KERNEL_SRC_MM_PAGE_FLAG_ERROR
|
||||||
|
ZFS_AC_KERNEL_SRC_MM_PAGE_FLAGS_STRUCT
|
||||||
])
|
])
|
||||||
AC_DEFUN([ZFS_AC_KERNEL_MM_PAGE_FLAGS], [
|
AC_DEFUN([ZFS_AC_KERNEL_MM_PAGE_FLAGS], [
|
||||||
ZFS_AC_KERNEL_MM_PAGE_FLAG_ERROR
|
ZFS_AC_KERNEL_MM_PAGE_FLAG_ERROR
|
||||||
|
ZFS_AC_KERNEL_MM_PAGE_FLAGS_STRUCT
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
dnl #
|
||||||
|
dnl # 6.18 API change
|
||||||
|
dnl # ns->ops->type was moved to ns->ns.ns_type (struct ns_common)
|
||||||
|
dnl #
|
||||||
|
AC_DEFUN([ZFS_AC_KERNEL_SRC_NS_COMMON_TYPE], [
|
||||||
|
ZFS_LINUX_TEST_SRC([ns_common_type], [
|
||||||
|
#include <linux/user_namespace.h>
|
||||||
|
],[
|
||||||
|
struct user_namespace ns;
|
||||||
|
ns.ns.ns_type = 0;
|
||||||
|
])
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_DEFUN([ZFS_AC_KERNEL_NS_COMMON_TYPE], [
|
||||||
|
AC_MSG_CHECKING([whether ns_type is accessible through ns_common])
|
||||||
|
ZFS_LINUX_TEST_RESULT([ns_common_type], [
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
AC_DEFINE([HAVE_NS_COMMON_TYPE], 1,
|
||||||
|
[Define if ns_type is accessible through ns_common])
|
||||||
|
],[
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
])
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_DEFUN([ZFS_AC_KERNEL_SRC_NAMESPACE], [
|
||||||
|
ZFS_AC_KERNEL_SRC_NS_COMMON_TYPE
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_DEFUN([ZFS_AC_KERNEL_NAMESPACE], [
|
||||||
|
ZFS_AC_KERNEL_NS_COMMON_TYPE
|
||||||
|
])
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
dnl #
|
|
||||||
dnl # 2.6.38 API change
|
|
||||||
dnl # ns_capable() was introduced
|
|
||||||
dnl #
|
|
||||||
AC_DEFUN([ZFS_AC_KERNEL_SRC_NS_CAPABLE], [
|
|
||||||
ZFS_LINUX_TEST_SRC([ns_capable], [
|
|
||||||
#include <linux/capability.h>
|
|
||||||
],[
|
|
||||||
ns_capable((struct user_namespace *)NULL, CAP_SYS_ADMIN);
|
|
||||||
])
|
|
||||||
])
|
|
||||||
|
|
||||||
AC_DEFUN([ZFS_AC_KERNEL_NS_CAPABLE], [
|
|
||||||
AC_MSG_CHECKING([whether ns_capable exists])
|
|
||||||
ZFS_LINUX_TEST_RESULT([ns_capable], [
|
|
||||||
AC_MSG_RESULT(yes)
|
|
||||||
],[
|
|
||||||
ZFS_LINUX_TEST_ERROR([ns_capable()])
|
|
||||||
])
|
|
||||||
])
|
|
||||||
|
|
||||||
dnl #
|
|
||||||
dnl # 2.6.39 API change
|
|
||||||
dnl # struct user_namespace was added to struct cred_t as cred->user_ns member
|
|
||||||
dnl #
|
|
||||||
AC_DEFUN([ZFS_AC_KERNEL_SRC_CRED_USER_NS], [
|
|
||||||
ZFS_LINUX_TEST_SRC([cred_user_ns], [
|
|
||||||
#include <linux/cred.h>
|
|
||||||
],[
|
|
||||||
struct cred cr;
|
|
||||||
cr.user_ns = (struct user_namespace *)NULL;
|
|
||||||
])
|
|
||||||
])
|
|
||||||
|
|
||||||
AC_DEFUN([ZFS_AC_KERNEL_CRED_USER_NS], [
|
|
||||||
AC_MSG_CHECKING([whether cred_t->user_ns exists])
|
|
||||||
ZFS_LINUX_TEST_RESULT([cred_user_ns], [
|
|
||||||
AC_MSG_RESULT(yes)
|
|
||||||
],[
|
|
||||||
ZFS_LINUX_TEST_ERROR([cred_t->user_ns()])
|
|
||||||
])
|
|
||||||
])
|
|
||||||
|
|
||||||
dnl #
|
|
||||||
dnl # 3.4 API change
|
|
||||||
dnl # kuid_has_mapping() and kgid_has_mapping() were added to distinguish
|
|
||||||
dnl # between internal kernel uids/gids and user namespace uids/gids.
|
|
||||||
dnl #
|
|
||||||
AC_DEFUN([ZFS_AC_KERNEL_SRC_KUID_HAS_MAPPING], [
|
|
||||||
ZFS_LINUX_TEST_SRC([kuid_has_mapping], [
|
|
||||||
#include <linux/uidgid.h>
|
|
||||||
],[
|
|
||||||
kuid_has_mapping((struct user_namespace *)NULL, KUIDT_INIT(0));
|
|
||||||
kgid_has_mapping((struct user_namespace *)NULL, KGIDT_INIT(0));
|
|
||||||
])
|
|
||||||
])
|
|
||||||
|
|
||||||
AC_DEFUN([ZFS_AC_KERNEL_KUID_HAS_MAPPING], [
|
|
||||||
AC_MSG_CHECKING([whether kuid_has_mapping/kgid_has_mapping exist])
|
|
||||||
ZFS_LINUX_TEST_RESULT([kuid_has_mapping], [
|
|
||||||
AC_MSG_RESULT(yes)
|
|
||||||
],[
|
|
||||||
ZFS_LINUX_TEST_ERROR([kuid_has_mapping()])
|
|
||||||
])
|
|
||||||
])
|
|
||||||
|
|
||||||
AC_DEFUN([ZFS_AC_KERNEL_SRC_USERNS_CAPABILITIES], [
|
|
||||||
ZFS_AC_KERNEL_SRC_NS_CAPABLE
|
|
||||||
ZFS_AC_KERNEL_SRC_HAS_CAPABILITY
|
|
||||||
ZFS_AC_KERNEL_SRC_CRED_USER_NS
|
|
||||||
ZFS_AC_KERNEL_SRC_KUID_HAS_MAPPING
|
|
||||||
])
|
|
||||||
|
|
||||||
AC_DEFUN([ZFS_AC_KERNEL_USERNS_CAPABILITIES], [
|
|
||||||
ZFS_AC_KERNEL_NS_CAPABLE
|
|
||||||
ZFS_AC_KERNEL_HAS_CAPABILITY
|
|
||||||
ZFS_AC_KERNEL_CRED_USER_NS
|
|
||||||
ZFS_AC_KERNEL_KUID_HAS_MAPPING
|
|
||||||
])
|
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
AC_DEFUN([ZFS_AC_KERNEL_SRC_WRITEPAGE_T], [
|
||||||
|
dnl #
|
||||||
|
dnl # 6.3 API change
|
||||||
|
dnl # The writepage_t function type now has its first argument as
|
||||||
|
dnl # struct folio* instead of struct page*
|
||||||
|
dnl #
|
||||||
|
ZFS_LINUX_TEST_SRC([writepage_t_folio], [
|
||||||
|
#include <linux/writeback.h>
|
||||||
|
static int putpage(struct folio *folio,
|
||||||
|
struct writeback_control *wbc, void *data)
|
||||||
|
{ return 0; }
|
||||||
|
writepage_t func = putpage;
|
||||||
|
],[])
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_DEFUN([ZFS_AC_KERNEL_WRITEPAGE_T], [
|
||||||
|
AC_MSG_CHECKING([whether int (*writepage_t)() takes struct folio*])
|
||||||
|
ZFS_LINUX_TEST_RESULT([writepage_t_folio], [
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
AC_DEFINE(HAVE_WRITEPAGE_T_FOLIO, 1,
|
||||||
|
[int (*writepage_t)() takes struct folio*])
|
||||||
|
],[
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
])
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_DEFUN([ZFS_AC_KERNEL_SRC_WRITE_CACHE_PAGES], [
|
||||||
|
dnl #
|
||||||
|
dnl # 6.18 API change
|
||||||
|
dnl # write_cache_pages() has been removed.
|
||||||
|
dnl #
|
||||||
|
ZFS_LINUX_TEST_SRC([write_cache_pages], [
|
||||||
|
#include <linux/writeback.h>
|
||||||
|
], [
|
||||||
|
(void) write_cache_pages(NULL, NULL, NULL, NULL);
|
||||||
|
])
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_DEFUN([ZFS_AC_KERNEL_WRITE_CACHE_PAGES], [
|
||||||
|
AC_MSG_CHECKING([whether write_cache_pages() is available])
|
||||||
|
ZFS_LINUX_TEST_RESULT([write_cache_pages], [
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
AC_DEFINE(HAVE_WRITE_CACHE_PAGES, 1,
|
||||||
|
[write_cache_pages() is available])
|
||||||
|
],[
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
])
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_DEFUN([ZFS_AC_KERNEL_SRC_WRITEBACK], [
|
||||||
|
ZFS_AC_KERNEL_SRC_WRITEPAGE_T
|
||||||
|
ZFS_AC_KERNEL_SRC_WRITE_CACHE_PAGES
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_DEFUN([ZFS_AC_KERNEL_WRITEBACK], [
|
||||||
|
ZFS_AC_KERNEL_WRITEPAGE_T
|
||||||
|
ZFS_AC_KERNEL_WRITE_CACHE_PAGES
|
||||||
|
])
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
AC_DEFUN([ZFS_AC_KERNEL_SRC_WRITEPAGE_T], [
|
|
||||||
dnl #
|
|
||||||
dnl # 6.3 API change
|
|
||||||
dnl # The writepage_t function type now has its first argument as
|
|
||||||
dnl # struct folio* instead of struct page*
|
|
||||||
dnl #
|
|
||||||
ZFS_LINUX_TEST_SRC([writepage_t_folio], [
|
|
||||||
#include <linux/writeback.h>
|
|
||||||
static int putpage(struct folio *folio,
|
|
||||||
struct writeback_control *wbc, void *data)
|
|
||||||
{ return 0; }
|
|
||||||
writepage_t func = putpage;
|
|
||||||
],[])
|
|
||||||
])
|
|
||||||
|
|
||||||
AC_DEFUN([ZFS_AC_KERNEL_WRITEPAGE_T], [
|
|
||||||
AC_MSG_CHECKING([whether int (*writepage_t)() takes struct folio*])
|
|
||||||
ZFS_LINUX_TEST_RESULT([writepage_t_folio], [
|
|
||||||
AC_MSG_RESULT(yes)
|
|
||||||
AC_DEFINE(HAVE_WRITEPAGE_T_FOLIO, 1,
|
|
||||||
[int (*writepage_t)() takes struct folio*])
|
|
||||||
],[
|
|
||||||
AC_MSG_RESULT(no)
|
|
||||||
])
|
|
||||||
])
|
|
||||||
|
|
||||||
+10
-2
@@ -59,6 +59,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
|
|||||||
ZFS_AC_KERNEL_SRC_ACL
|
ZFS_AC_KERNEL_SRC_ACL
|
||||||
ZFS_AC_KERNEL_SRC_INODE_SETATTR
|
ZFS_AC_KERNEL_SRC_INODE_SETATTR
|
||||||
ZFS_AC_KERNEL_SRC_INODE_GETATTR
|
ZFS_AC_KERNEL_SRC_INODE_GETATTR
|
||||||
|
ZFS_AC_KERNEL_SRC_INODE_STATE_READ_ONCE
|
||||||
ZFS_AC_KERNEL_SRC_SHOW_OPTIONS
|
ZFS_AC_KERNEL_SRC_SHOW_OPTIONS
|
||||||
ZFS_AC_KERNEL_SRC_SHRINKER
|
ZFS_AC_KERNEL_SRC_SHRINKER
|
||||||
ZFS_AC_KERNEL_SRC_MKDIR
|
ZFS_AC_KERNEL_SRC_MKDIR
|
||||||
@@ -70,6 +71,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
|
|||||||
ZFS_AC_KERNEL_SRC_COMMIT_METADATA
|
ZFS_AC_KERNEL_SRC_COMMIT_METADATA
|
||||||
ZFS_AC_KERNEL_SRC_SETATTR_PREPARE
|
ZFS_AC_KERNEL_SRC_SETATTR_PREPARE
|
||||||
ZFS_AC_KERNEL_SRC_INSERT_INODE_LOCKED
|
ZFS_AC_KERNEL_SRC_INSERT_INODE_LOCKED
|
||||||
|
ZFS_AC_KERNEL_SRC_DENTRY
|
||||||
ZFS_AC_KERNEL_SRC_TRUNCATE_SETSIZE
|
ZFS_AC_KERNEL_SRC_TRUNCATE_SETSIZE
|
||||||
ZFS_AC_KERNEL_SRC_SECURITY_INODE
|
ZFS_AC_KERNEL_SRC_SECURITY_INODE
|
||||||
ZFS_AC_KERNEL_SRC_FST_MOUNT
|
ZFS_AC_KERNEL_SRC_FST_MOUNT
|
||||||
@@ -120,7 +122,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
|
|||||||
ZFS_AC_KERNEL_SRC_IDMAP_MNT_API
|
ZFS_AC_KERNEL_SRC_IDMAP_MNT_API
|
||||||
ZFS_AC_KERNEL_SRC_IDMAP_NO_USERNS
|
ZFS_AC_KERNEL_SRC_IDMAP_NO_USERNS
|
||||||
ZFS_AC_KERNEL_SRC_IATTR_VFSID
|
ZFS_AC_KERNEL_SRC_IATTR_VFSID
|
||||||
ZFS_AC_KERNEL_SRC_WRITEPAGE_T
|
ZFS_AC_KERNEL_SRC_WRITEBACK
|
||||||
ZFS_AC_KERNEL_SRC_RECLAIMED
|
ZFS_AC_KERNEL_SRC_RECLAIMED
|
||||||
ZFS_AC_KERNEL_SRC_REGISTER_SYSCTL_TABLE
|
ZFS_AC_KERNEL_SRC_REGISTER_SYSCTL_TABLE
|
||||||
ZFS_AC_KERNEL_SRC_REGISTER_SYSCTL_SZ
|
ZFS_AC_KERNEL_SRC_REGISTER_SYSCTL_SZ
|
||||||
@@ -135,6 +137,8 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
|
|||||||
ZFS_AC_KERNEL_SRC_TIMER
|
ZFS_AC_KERNEL_SRC_TIMER
|
||||||
ZFS_AC_KERNEL_SRC_SUPER_BLOCK_S_WB_ERR
|
ZFS_AC_KERNEL_SRC_SUPER_BLOCK_S_WB_ERR
|
||||||
ZFS_AC_KERNEL_SRC_SOPS_FREE_INODE
|
ZFS_AC_KERNEL_SRC_SOPS_FREE_INODE
|
||||||
|
ZFS_AC_KERNEL_SRC_NAMESPACE
|
||||||
|
ZFS_AC_KERNEL_SRC_INODE_GENERIC_DROP
|
||||||
case "$host_cpu" in
|
case "$host_cpu" in
|
||||||
powerpc*)
|
powerpc*)
|
||||||
ZFS_AC_KERNEL_SRC_CPU_HAS_FEATURE
|
ZFS_AC_KERNEL_SRC_CPU_HAS_FEATURE
|
||||||
@@ -177,6 +181,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
|
|||||||
ZFS_AC_KERNEL_ACL
|
ZFS_AC_KERNEL_ACL
|
||||||
ZFS_AC_KERNEL_INODE_SETATTR
|
ZFS_AC_KERNEL_INODE_SETATTR
|
||||||
ZFS_AC_KERNEL_INODE_GETATTR
|
ZFS_AC_KERNEL_INODE_GETATTR
|
||||||
|
ZFS_AC_KERNEL_INODE_STATE_READ_ONCE
|
||||||
ZFS_AC_KERNEL_SHOW_OPTIONS
|
ZFS_AC_KERNEL_SHOW_OPTIONS
|
||||||
ZFS_AC_KERNEL_SHRINKER
|
ZFS_AC_KERNEL_SHRINKER
|
||||||
ZFS_AC_KERNEL_MKDIR
|
ZFS_AC_KERNEL_MKDIR
|
||||||
@@ -188,6 +193,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
|
|||||||
ZFS_AC_KERNEL_COMMIT_METADATA
|
ZFS_AC_KERNEL_COMMIT_METADATA
|
||||||
ZFS_AC_KERNEL_SETATTR_PREPARE
|
ZFS_AC_KERNEL_SETATTR_PREPARE
|
||||||
ZFS_AC_KERNEL_INSERT_INODE_LOCKED
|
ZFS_AC_KERNEL_INSERT_INODE_LOCKED
|
||||||
|
ZFS_AC_KERNEL_DENTRY
|
||||||
ZFS_AC_KERNEL_TRUNCATE_SETSIZE
|
ZFS_AC_KERNEL_TRUNCATE_SETSIZE
|
||||||
ZFS_AC_KERNEL_SECURITY_INODE
|
ZFS_AC_KERNEL_SECURITY_INODE
|
||||||
ZFS_AC_KERNEL_FST_MOUNT
|
ZFS_AC_KERNEL_FST_MOUNT
|
||||||
@@ -238,7 +244,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
|
|||||||
ZFS_AC_KERNEL_IDMAP_MNT_API
|
ZFS_AC_KERNEL_IDMAP_MNT_API
|
||||||
ZFS_AC_KERNEL_IDMAP_NO_USERNS
|
ZFS_AC_KERNEL_IDMAP_NO_USERNS
|
||||||
ZFS_AC_KERNEL_IATTR_VFSID
|
ZFS_AC_KERNEL_IATTR_VFSID
|
||||||
ZFS_AC_KERNEL_WRITEPAGE_T
|
ZFS_AC_KERNEL_WRITEBACK
|
||||||
ZFS_AC_KERNEL_RECLAIMED
|
ZFS_AC_KERNEL_RECLAIMED
|
||||||
ZFS_AC_KERNEL_REGISTER_SYSCTL_TABLE
|
ZFS_AC_KERNEL_REGISTER_SYSCTL_TABLE
|
||||||
ZFS_AC_KERNEL_REGISTER_SYSCTL_SZ
|
ZFS_AC_KERNEL_REGISTER_SYSCTL_SZ
|
||||||
@@ -254,6 +260,8 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
|
|||||||
ZFS_AC_KERNEL_TIMER
|
ZFS_AC_KERNEL_TIMER
|
||||||
ZFS_AC_KERNEL_SUPER_BLOCK_S_WB_ERR
|
ZFS_AC_KERNEL_SUPER_BLOCK_S_WB_ERR
|
||||||
ZFS_AC_KERNEL_SOPS_FREE_INODE
|
ZFS_AC_KERNEL_SOPS_FREE_INODE
|
||||||
|
ZFS_AC_KERNEL_NAMESPACE
|
||||||
|
ZFS_AC_KERNEL_INODE_GENERIC_DROP
|
||||||
case "$host_cpu" in
|
case "$host_cpu" in
|
||||||
powerpc*)
|
powerpc*)
|
||||||
ZFS_AC_KERNEL_CPU_HAS_FEATURE
|
ZFS_AC_KERNEL_CPU_HAS_FEATURE
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ dnl #
|
|||||||
dnl # Check for statx() function and STATX_MNT_ID availability
|
dnl # Check for statx() function and STATX_MNT_ID availability
|
||||||
dnl #
|
dnl #
|
||||||
AC_DEFUN([ZFS_AC_CONFIG_USER_STATX], [
|
AC_DEFUN([ZFS_AC_CONFIG_USER_STATX], [
|
||||||
AC_CHECK_HEADERS([linux/stat.h],
|
AC_CHECK_HEADERS([sys/stat.h],
|
||||||
[have_stat_headers=yes],
|
[have_stat_headers=yes],
|
||||||
[have_stat_headers=no])
|
[have_stat_headers=no])
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ AC_DEFUN([ZFS_AC_CONFIG_USER_STATX], [
|
|||||||
AC_MSG_CHECKING([for STATX_MNT_ID])
|
AC_MSG_CHECKING([for STATX_MNT_ID])
|
||||||
AC_COMPILE_IFELSE([
|
AC_COMPILE_IFELSE([
|
||||||
AC_LANG_PROGRAM([[
|
AC_LANG_PROGRAM([[
|
||||||
#include <linux/stat.h>
|
#include <sys/stat.h>
|
||||||
]], [[
|
]], [[
|
||||||
struct statx stx;
|
struct statx stx;
|
||||||
int mask = STATX_MNT_ID;
|
int mask = STATX_MNT_ID;
|
||||||
@@ -29,6 +29,6 @@ AC_DEFUN([ZFS_AC_CONFIG_USER_STATX], [
|
|||||||
])
|
])
|
||||||
])
|
])
|
||||||
], [
|
], [
|
||||||
AC_MSG_WARN([linux/stat.h not found; skipping statx support])
|
AC_MSG_WARN([sys/stat.h not found; skipping statx support])
|
||||||
])
|
])
|
||||||
]) dnl end AC_DEFUN
|
]) dnl end AC_DEFUN
|
||||||
|
|||||||
@@ -604,5 +604,4 @@ class RaidzExpansionRunning(ZFSError):
|
|||||||
errno = ZFS_ERR_RAIDZ_EXPAND_IN_PROGRESS
|
errno = ZFS_ERR_RAIDZ_EXPAND_IN_PROGRESS
|
||||||
message = "A raidz device is currently expanding"
|
message = "A raidz device is currently expanding"
|
||||||
|
|
||||||
|
|
||||||
# vim: softtabstop=4 tabstop=4 expandtab shiftwidth=4
|
# vim: softtabstop=4 tabstop=4 expandtab shiftwidth=4
|
||||||
|
|||||||
+4
-1
@@ -8,7 +8,9 @@ usage()
|
|||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
[ "$#" -eq 1 ] || usage
|
if ! [ -d "$1" ] ; then
|
||||||
|
usage
|
||||||
|
fi
|
||||||
KERNEL_DIR="$1"
|
KERNEL_DIR="$1"
|
||||||
|
|
||||||
if ! [ -e 'zfs_config.h' ]
|
if ! [ -e 'zfs_config.h' ]
|
||||||
@@ -31,6 +33,7 @@ cat > "$KERNEL_DIR/fs/zfs/Kconfig" <<EOF
|
|||||||
config ZFS
|
config ZFS
|
||||||
tristate "ZFS filesystem support"
|
tristate "ZFS filesystem support"
|
||||||
depends on EFI_PARTITION
|
depends on EFI_PARTITION
|
||||||
|
depends on BLOCK
|
||||||
select ZLIB_INFLATE
|
select ZLIB_INFLATE
|
||||||
select ZLIB_DEFLATE
|
select ZLIB_DEFLATE
|
||||||
help
|
help
|
||||||
|
|||||||
@@ -104,6 +104,9 @@
|
|||||||
#define spa_taskq_write_param_set_args(var) \
|
#define spa_taskq_write_param_set_args(var) \
|
||||||
CTLTYPE_STRING, NULL, 0, spa_taskq_write_param, "A"
|
CTLTYPE_STRING, NULL, 0, spa_taskq_write_param, "A"
|
||||||
|
|
||||||
|
#define spa_taskq_free_param_set_args(var) \
|
||||||
|
CTLTYPE_STRING, NULL, 0, spa_taskq_free_param, "A"
|
||||||
|
|
||||||
#define fletcher_4_param_set_args(var) \
|
#define fletcher_4_param_set_args(var) \
|
||||||
CTLTYPE_STRING, NULL, 0, fletcher_4_param, "A"
|
CTLTYPE_STRING, NULL, 0, fletcher_4_param, "A"
|
||||||
|
|
||||||
|
|||||||
@@ -290,80 +290,11 @@ extern unsigned char bcd_to_byte[256];
|
|||||||
#define offsetof(type, field) __offsetof(type, field)
|
#define offsetof(type, field) __offsetof(type, field)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
#define highbit(x) flsl(x)
|
||||||
* Find highest one bit set.
|
#define lowbit(x) ffsl(x)
|
||||||
* Returns bit number + 1 of highest bit that is set, otherwise returns 0.
|
|
||||||
* High order bit is 31 (or 63 in _LP64 kernel).
|
|
||||||
*/
|
|
||||||
static __inline int
|
|
||||||
highbit(ulong_t i)
|
|
||||||
{
|
|
||||||
#if defined(HAVE_INLINE_FLSL)
|
|
||||||
return (flsl(i));
|
|
||||||
#else
|
|
||||||
int h = 1;
|
|
||||||
|
|
||||||
if (i == 0)
|
#define highbit64(x) flsll(x)
|
||||||
return (0);
|
#define lowbit64(x) ffsll(x)
|
||||||
#ifdef _LP64
|
|
||||||
if (i & 0xffffffff00000000ul) {
|
|
||||||
h += 32; i >>= 32;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (i & 0xffff0000) {
|
|
||||||
h += 16; i >>= 16;
|
|
||||||
}
|
|
||||||
if (i & 0xff00) {
|
|
||||||
h += 8; i >>= 8;
|
|
||||||
}
|
|
||||||
if (i & 0xf0) {
|
|
||||||
h += 4; i >>= 4;
|
|
||||||
}
|
|
||||||
if (i & 0xc) {
|
|
||||||
h += 2; i >>= 2;
|
|
||||||
}
|
|
||||||
if (i & 0x2) {
|
|
||||||
h += 1;
|
|
||||||
}
|
|
||||||
return (h);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Find highest one bit set.
|
|
||||||
* Returns bit number + 1 of highest bit that is set, otherwise returns 0.
|
|
||||||
*/
|
|
||||||
static __inline int
|
|
||||||
highbit64(uint64_t i)
|
|
||||||
{
|
|
||||||
#if defined(HAVE_INLINE_FLSLL)
|
|
||||||
return (flsll(i));
|
|
||||||
#else
|
|
||||||
int h = 1;
|
|
||||||
|
|
||||||
if (i == 0)
|
|
||||||
return (0);
|
|
||||||
if (i & 0xffffffff00000000ULL) {
|
|
||||||
h += 32; i >>= 32;
|
|
||||||
}
|
|
||||||
if (i & 0xffff0000) {
|
|
||||||
h += 16; i >>= 16;
|
|
||||||
}
|
|
||||||
if (i & 0xff00) {
|
|
||||||
h += 8; i >>= 8;
|
|
||||||
}
|
|
||||||
if (i & 0xf0) {
|
|
||||||
h += 4; i >>= 4;
|
|
||||||
}
|
|
||||||
if (i & 0xc) {
|
|
||||||
h += 2; i >>= 2;
|
|
||||||
}
|
|
||||||
if (i & 0x2) {
|
|
||||||
h += 1;
|
|
||||||
}
|
|
||||||
return (h);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,17 @@
|
|||||||
|
|
||||||
#define d_alias d_u.d_alias
|
#define d_alias d_u.d_alias
|
||||||
|
|
||||||
|
#ifdef HAVE_MM_PAGE_FLAGS_STRUCT
|
||||||
|
/*
|
||||||
|
* Starting from Linux 6.18, the 'flags' field in 'struct page' is defined
|
||||||
|
* to a struct ('memdesc_flags_t' typedef) instead of an unsigned long for
|
||||||
|
* improved typesafety.
|
||||||
|
*/
|
||||||
|
#define page_flags flags.f
|
||||||
|
#else
|
||||||
|
#define page_flags flags
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Starting from Linux 5.13, flush_dcache_page() becomes an inline function
|
* Starting from Linux 5.13, flush_dcache_page() becomes an inline function
|
||||||
* and under some configurations, may indirectly referencing GPL-only
|
* and under some configurations, may indirectly referencing GPL-only
|
||||||
@@ -44,8 +55,8 @@
|
|||||||
#include <linux/simd_powerpc.h>
|
#include <linux/simd_powerpc.h>
|
||||||
#define flush_dcache_page(page) do { \
|
#define flush_dcache_page(page) do { \
|
||||||
if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE) && \
|
if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE) && \
|
||||||
test_bit(PG_dcache_clean, &(page)->flags)) \
|
test_bit(PG_dcache_clean, &(page)->page_flags)) \
|
||||||
clear_bit(PG_dcache_clean, &(page)->flags); \
|
clear_bit(PG_dcache_clean, &(page)->page_flags);\
|
||||||
} while (0)
|
} while (0)
|
||||||
#endif
|
#endif
|
||||||
/*
|
/*
|
||||||
@@ -55,8 +66,8 @@
|
|||||||
*/
|
*/
|
||||||
#if defined __riscv && defined HAVE_FLUSH_DCACHE_PAGE_GPL_ONLY
|
#if defined __riscv && defined HAVE_FLUSH_DCACHE_PAGE_GPL_ONLY
|
||||||
#define flush_dcache_page(page) do { \
|
#define flush_dcache_page(page) do { \
|
||||||
if (test_bit(PG_dcache_clean, &(page)->flags)) \
|
if (test_bit(PG_dcache_clean, &(page)->page_flags)) \
|
||||||
clear_bit(PG_dcache_clean, &(page)->flags); \
|
clear_bit(PG_dcache_clean, &(page)->page_flags);\
|
||||||
} while (0)
|
} while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2011 Lawrence Livermore National Security, LLC.
|
* Copyright (C) 2011 Lawrence Livermore National Security, LLC.
|
||||||
* Copyright (C) 2015 Jörg Thalheim.
|
* Copyright (C) 2015 Jörg Thalheim.
|
||||||
|
* Copyright (c) 2025, Rob Norris <robn@despairlabs.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _ZFS_VFS_H
|
#ifndef _ZFS_VFS_H
|
||||||
@@ -262,4 +263,18 @@ zpl_is_32bit_api(void)
|
|||||||
#define zpl_generic_fillattr(user_ns, ip, sp) generic_fillattr(ip, sp)
|
#define zpl_generic_fillattr(user_ns, ip, sp) generic_fillattr(ip, sp)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_INODE_GENERIC_DROP
|
||||||
|
/* 6.18 API change. These were renamed, alias the old names to the new. */
|
||||||
|
#define generic_delete_inode(ip) inode_just_drop(ip)
|
||||||
|
#define generic_drop_inode(ip) inode_generic_drop(ip)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAVE_INODE_STATE_READ_ONCE
|
||||||
|
/*
|
||||||
|
* 6.19 API change. We should no longer access i_state directly. If the new
|
||||||
|
* helper function doesn't exist, define our own.
|
||||||
|
*/
|
||||||
|
#define inode_state_read_once(ip) READ_ONCE(ip->i_state)
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* _ZFS_VFS_H */
|
#endif /* _ZFS_VFS_H */
|
||||||
|
|||||||
@@ -25,6 +25,6 @@
|
|||||||
#ifndef _SPL_STAT_H
|
#ifndef _SPL_STAT_H
|
||||||
#define _SPL_STAT_H
|
#define _SPL_STAT_H
|
||||||
|
|
||||||
#include <linux/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#endif /* SPL_STAT_H */
|
#endif /* SPL_STAT_H */
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ extern const struct file_operations zpl_dir_file_operations;
|
|||||||
extern void zpl_prune_sb(uint64_t nr_to_scan, void *arg);
|
extern void zpl_prune_sb(uint64_t nr_to_scan, void *arg);
|
||||||
|
|
||||||
extern const struct super_operations zpl_super_operations;
|
extern const struct super_operations zpl_super_operations;
|
||||||
|
extern const struct dentry_operations zpl_dentry_operations;
|
||||||
extern const struct export_operations zpl_export_operations;
|
extern const struct export_operations zpl_export_operations;
|
||||||
extern struct file_system_type zpl_fs_type;
|
extern struct file_system_type zpl_fs_type;
|
||||||
|
|
||||||
|
|||||||
@@ -863,6 +863,10 @@ typedef struct zpool_load_policy {
|
|||||||
#define ZPOOL_CONFIG_MMP_SEQ "mmp_seq" /* not stored on disk */
|
#define ZPOOL_CONFIG_MMP_SEQ "mmp_seq" /* not stored on disk */
|
||||||
#define ZPOOL_CONFIG_MMP_HOSTNAME "mmp_hostname" /* not stored on disk */
|
#define ZPOOL_CONFIG_MMP_HOSTNAME "mmp_hostname" /* not stored on disk */
|
||||||
#define ZPOOL_CONFIG_MMP_HOSTID "mmp_hostid" /* not stored on disk */
|
#define ZPOOL_CONFIG_MMP_HOSTID "mmp_hostid" /* not stored on disk */
|
||||||
|
#define ZPOOL_CONFIG_MMP_RESULT "mmp_result" /* not stored on disk */
|
||||||
|
#define ZPOOL_CONFIG_MMP_TRYIMPORT_NS "mmp_tryimport_ns" /* not stored */
|
||||||
|
#define ZPOOL_CONFIG_MMP_IMPORT_NS "mmp_import_ns" /* not stored on disk */
|
||||||
|
#define ZPOOL_CONFIG_MMP_CLAIM_NS "mmp_claim_ns" /* not stored on disk */
|
||||||
#define ZPOOL_CONFIG_ALLOCATION_BIAS "alloc_bias" /* not stored on disk */
|
#define ZPOOL_CONFIG_ALLOCATION_BIAS "alloc_bias" /* not stored on disk */
|
||||||
#define ZPOOL_CONFIG_EXPANSION_TIME "expansion_time" /* not stored */
|
#define ZPOOL_CONFIG_EXPANSION_TIME "expansion_time" /* not stored */
|
||||||
#define ZPOOL_CONFIG_REBUILD_STATS "org.openzfs:rebuild_stats"
|
#define ZPOOL_CONFIG_REBUILD_STATS "org.openzfs:rebuild_stats"
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ extern "C" {
|
|||||||
#define MMP_DEFAULT_IMPORT_INTERVALS 20
|
#define MMP_DEFAULT_IMPORT_INTERVALS 20
|
||||||
#define MMP_DEFAULT_FAIL_INTERVALS 10
|
#define MMP_DEFAULT_FAIL_INTERVALS 10
|
||||||
#define MMP_MIN_FAIL_INTERVALS 2 /* min if != 0 */
|
#define MMP_MIN_FAIL_INTERVALS 2 /* min if != 0 */
|
||||||
|
#define MMP_IMPORT_VERIFY_ITERS 10
|
||||||
#define MMP_IMPORT_SAFETY_FACTOR 200 /* pct */
|
#define MMP_IMPORT_SAFETY_FACTOR 200 /* pct */
|
||||||
#define MMP_INTERVAL_OK(interval) MAX(interval, MMP_MIN_INTERVAL)
|
#define MMP_INTERVAL_OK(interval) MAX(interval, MMP_MIN_INTERVAL)
|
||||||
#define MMP_FAIL_INTVS_OK(fails) (fails == 0 ? 0 : MAX(fails, \
|
#define MMP_FAIL_INTVS_OK(fails) (fails == 0 ? 0 : MAX(fails, \
|
||||||
@@ -53,6 +54,9 @@ typedef struct mmp_thread {
|
|||||||
vdev_t *mmp_last_leaf; /* last mmp write sent here */
|
vdev_t *mmp_last_leaf; /* last mmp write sent here */
|
||||||
uint64_t mmp_leaf_last_gen; /* last mmp write sent here */
|
uint64_t mmp_leaf_last_gen; /* last mmp write sent here */
|
||||||
uint32_t mmp_seq; /* intra-second update counter */
|
uint32_t mmp_seq; /* intra-second update counter */
|
||||||
|
uint64_t mmp_tryimport_ns; /* tryimport activity check time */
|
||||||
|
uint64_t mmp_import_ns; /* import activity check time */
|
||||||
|
uint64_t mmp_claim_ns; /* claim activity check time */
|
||||||
} mmp_thread_t;
|
} mmp_thread_t;
|
||||||
|
|
||||||
|
|
||||||
@@ -62,6 +66,7 @@ extern void mmp_thread_start(struct spa *spa);
|
|||||||
extern void mmp_thread_stop(struct spa *spa);
|
extern void mmp_thread_stop(struct spa *spa);
|
||||||
extern void mmp_update_uberblock(struct spa *spa, struct uberblock *ub);
|
extern void mmp_update_uberblock(struct spa *spa, struct uberblock *ub);
|
||||||
extern void mmp_signal_all_threads(void);
|
extern void mmp_signal_all_threads(void);
|
||||||
|
extern int mmp_claim_uberblock(spa_t *spa, vdev_t *vd, uberblock_t *ub);
|
||||||
|
|
||||||
/* Global tuning */
|
/* Global tuning */
|
||||||
extern int param_set_multihost_interval(ZFS_MODULE_PARAM_ARGS);
|
extern int param_set_multihost_interval(ZFS_MODULE_PARAM_ARGS);
|
||||||
|
|||||||
@@ -1044,6 +1044,7 @@ extern void spa_set_rootblkptr(spa_t *spa, const blkptr_t *bp);
|
|||||||
extern void spa_altroot(spa_t *, char *, size_t);
|
extern void spa_altroot(spa_t *, char *, size_t);
|
||||||
extern uint32_t spa_sync_pass(spa_t *spa);
|
extern uint32_t spa_sync_pass(spa_t *spa);
|
||||||
extern char *spa_name(spa_t *spa);
|
extern char *spa_name(spa_t *spa);
|
||||||
|
extern char *spa_load_name(spa_t *spa);
|
||||||
extern uint64_t spa_guid(spa_t *spa);
|
extern uint64_t spa_guid(spa_t *spa);
|
||||||
extern uint64_t spa_load_guid(spa_t *spa);
|
extern uint64_t spa_load_guid(spa_t *spa);
|
||||||
extern uint64_t spa_last_synced_txg(spa_t *spa);
|
extern uint64_t spa_last_synced_txg(spa_t *spa);
|
||||||
|
|||||||
@@ -224,6 +224,7 @@ struct spa {
|
|||||||
* Fields protected by spa_namespace_lock.
|
* Fields protected by spa_namespace_lock.
|
||||||
*/
|
*/
|
||||||
char spa_name[ZFS_MAX_DATASET_NAME_LEN]; /* pool name */
|
char spa_name[ZFS_MAX_DATASET_NAME_LEN]; /* pool name */
|
||||||
|
char *spa_load_name; /* unmodified pool name */
|
||||||
char *spa_comment; /* comment */
|
char *spa_comment; /* comment */
|
||||||
avl_node_t spa_avl; /* node in spa_namespace_avl */
|
avl_node_t spa_avl; /* node in spa_namespace_avl */
|
||||||
nvlist_t *spa_config; /* last synced config */
|
nvlist_t *spa_config; /* last synced config */
|
||||||
@@ -303,6 +304,7 @@ struct spa {
|
|||||||
void *spa_cksum_tmpls[ZIO_CHECKSUM_FUNCTIONS];
|
void *spa_cksum_tmpls[ZIO_CHECKSUM_FUNCTIONS];
|
||||||
uberblock_t spa_ubsync; /* last synced uberblock */
|
uberblock_t spa_ubsync; /* last synced uberblock */
|
||||||
uberblock_t spa_uberblock; /* current uberblock */
|
uberblock_t spa_uberblock; /* current uberblock */
|
||||||
|
boolean_t spa_activity_check; /* activity check required */
|
||||||
boolean_t spa_extreme_rewind; /* rewind past deferred frees */
|
boolean_t spa_extreme_rewind; /* rewind past deferred frees */
|
||||||
kmutex_t spa_scrub_lock; /* resilver/scrub lock */
|
kmutex_t spa_scrub_lock; /* resilver/scrub lock */
|
||||||
uint64_t spa_scrub_inflight; /* in-flight scrub bytes */
|
uint64_t spa_scrub_inflight; /* in-flight scrub bytes */
|
||||||
|
|||||||
@@ -51,6 +51,12 @@ extern "C" {
|
|||||||
#define MMP_SEQ_VALID_BIT 0x02
|
#define MMP_SEQ_VALID_BIT 0x02
|
||||||
#define MMP_FAIL_INT_VALID_BIT 0x04
|
#define MMP_FAIL_INT_VALID_BIT 0x04
|
||||||
|
|
||||||
|
#define MMP_INTERVAL_MASK 0x00000000FFFFFF00
|
||||||
|
#define MMP_SEQ_MASK 0x0000FFFF00000000
|
||||||
|
#define MMP_FAIL_INT_MASK 0xFFFF000000000000
|
||||||
|
|
||||||
|
#define MMP_SEQ_MAX UINT16_MAX
|
||||||
|
|
||||||
#define MMP_VALID(ubp) ((ubp)->ub_magic == UBERBLOCK_MAGIC && \
|
#define MMP_VALID(ubp) ((ubp)->ub_magic == UBERBLOCK_MAGIC && \
|
||||||
(ubp)->ub_mmp_magic == MMP_MAGIC)
|
(ubp)->ub_mmp_magic == MMP_MAGIC)
|
||||||
#define MMP_INTERVAL_VALID(ubp) (MMP_VALID(ubp) && ((ubp)->ub_mmp_config & \
|
#define MMP_INTERVAL_VALID(ubp) (MMP_VALID(ubp) && ((ubp)->ub_mmp_config & \
|
||||||
@@ -60,21 +66,25 @@ extern "C" {
|
|||||||
#define MMP_FAIL_INT_VALID(ubp) (MMP_VALID(ubp) && ((ubp)->ub_mmp_config & \
|
#define MMP_FAIL_INT_VALID(ubp) (MMP_VALID(ubp) && ((ubp)->ub_mmp_config & \
|
||||||
MMP_FAIL_INT_VALID_BIT))
|
MMP_FAIL_INT_VALID_BIT))
|
||||||
|
|
||||||
#define MMP_INTERVAL(ubp) (((ubp)->ub_mmp_config & 0x00000000FFFFFF00) \
|
#define MMP_INTERVAL(ubp) (((ubp)->ub_mmp_config & MMP_INTERVAL_MASK) \
|
||||||
>> 8)
|
>> 8)
|
||||||
#define MMP_SEQ(ubp) (((ubp)->ub_mmp_config & 0x0000FFFF00000000) \
|
#define MMP_SEQ(ubp) (((ubp)->ub_mmp_config & MMP_SEQ_MASK) \
|
||||||
>> 32)
|
>> 32)
|
||||||
#define MMP_FAIL_INT(ubp) (((ubp)->ub_mmp_config & 0xFFFF000000000000) \
|
#define MMP_FAIL_INT(ubp) (((ubp)->ub_mmp_config & MMP_FAIL_INT_MASK) \
|
||||||
>> 48)
|
>> 48)
|
||||||
|
|
||||||
#define MMP_INTERVAL_SET(write) \
|
#define MMP_INTERVAL_SET(write) \
|
||||||
(((uint64_t)(write & 0xFFFFFF) << 8) | MMP_INTERVAL_VALID_BIT)
|
(((uint64_t)((write) & 0xFFFFFF) << 8) | MMP_INTERVAL_VALID_BIT)
|
||||||
|
|
||||||
#define MMP_SEQ_SET(seq) \
|
#define MMP_SEQ_SET(seq) \
|
||||||
(((uint64_t)(seq & 0xFFFF) << 32) | MMP_SEQ_VALID_BIT)
|
(((uint64_t)((seq) & 0xFFFF) << 32) | MMP_SEQ_VALID_BIT)
|
||||||
|
|
||||||
#define MMP_FAIL_INT_SET(fail) \
|
#define MMP_FAIL_INT_SET(fail) \
|
||||||
(((uint64_t)(fail & 0xFFFF) << 48) | MMP_FAIL_INT_VALID_BIT)
|
(((uint64_t)((fail) & 0xFFFF) << 48) | MMP_FAIL_INT_VALID_BIT)
|
||||||
|
|
||||||
|
|
||||||
|
#define MMP_SEQ_CLEAR(ubp) \
|
||||||
|
((ubp)->ub_mmp_config &= ~(MMP_SEQ_MASK | MMP_SEQ_VALID_BIT))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RAIDZ expansion reflow information.
|
* RAIDZ expansion reflow information.
|
||||||
|
|||||||
@@ -212,6 +212,8 @@ extern void vdev_label_write(zio_t *zio, vdev_t *vd, int l, abd_t *buf, uint64_t
|
|||||||
extern int vdev_label_read_bootenv(vdev_t *, nvlist_t *);
|
extern int vdev_label_read_bootenv(vdev_t *, nvlist_t *);
|
||||||
extern int vdev_label_write_bootenv(vdev_t *, nvlist_t *);
|
extern int vdev_label_write_bootenv(vdev_t *, nvlist_t *);
|
||||||
extern int vdev_uberblock_sync_list(vdev_t **, int, struct uberblock *, int);
|
extern int vdev_uberblock_sync_list(vdev_t **, int, struct uberblock *, int);
|
||||||
|
extern int vdev_uberblock_compare(const struct uberblock *,
|
||||||
|
const struct uberblock *);
|
||||||
extern int vdev_check_boot_reserve(spa_t *, vdev_t *);
|
extern int vdev_check_boot_reserve(spa_t *, vdev_t *);
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ void zfs_file_close(zfs_file_t *fp);
|
|||||||
|
|
||||||
int zfs_file_write(zfs_file_t *fp, const void *buf, size_t len, ssize_t *resid);
|
int zfs_file_write(zfs_file_t *fp, const void *buf, size_t len, ssize_t *resid);
|
||||||
int zfs_file_pwrite(zfs_file_t *fp, const void *buf, size_t len, loff_t off,
|
int zfs_file_pwrite(zfs_file_t *fp, const void *buf, size_t len, loff_t off,
|
||||||
ssize_t *resid);
|
uint8_t ashift, ssize_t *resid);
|
||||||
int zfs_file_read(zfs_file_t *fp, void *buf, size_t len, ssize_t *resid);
|
int zfs_file_read(zfs_file_t *fp, void *buf, size_t len, ssize_t *resid);
|
||||||
int zfs_file_pread(zfs_file_t *fp, void *buf, size_t len, loff_t off,
|
int zfs_file_pread(zfs_file_t *fp, void *buf, size_t len, loff_t off,
|
||||||
ssize_t *resid);
|
ssize_t *resid);
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
#ifdef HAVE_STATX
|
#ifdef HAVE_STATX
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <linux/stat.h>
|
#include <sys/stat.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -2238,6 +2238,11 @@ zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
|
|||||||
|
|
||||||
zpool_get_load_policy(config, &policy);
|
zpool_get_load_policy(config, &policy);
|
||||||
|
|
||||||
|
if (getenv("ZFS_LOAD_INFO_DEBUG") && nv != NULL &&
|
||||||
|
nvlist_lookup_nvlist(nv, ZPOOL_CONFIG_LOAD_INFO, &nvinfo) == 0) {
|
||||||
|
dump_nvlist(nvinfo, 4);
|
||||||
|
}
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
char desc[1024];
|
char desc[1024];
|
||||||
char aux[256];
|
char aux[256];
|
||||||
|
|||||||
+43
-35
@@ -98,57 +98,57 @@ static const char *const zfs_msgid_table[] = {
|
|||||||
#define NMSGID (sizeof (zfs_msgid_table) / sizeof (zfs_msgid_table[0]))
|
#define NMSGID (sizeof (zfs_msgid_table) / sizeof (zfs_msgid_table[0]))
|
||||||
|
|
||||||
static int
|
static int
|
||||||
vdev_missing(vdev_stat_t *vs, uint_t vsc)
|
vdev_missing(vdev_stat_t *vs, uint_t vsc, void *arg)
|
||||||
{
|
{
|
||||||
(void) vsc;
|
(void) vsc, (void) arg;
|
||||||
return (vs->vs_state == VDEV_STATE_CANT_OPEN &&
|
return (vs->vs_state == VDEV_STATE_CANT_OPEN &&
|
||||||
vs->vs_aux == VDEV_AUX_OPEN_FAILED);
|
vs->vs_aux == VDEV_AUX_OPEN_FAILED);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
vdev_faulted(vdev_stat_t *vs, uint_t vsc)
|
vdev_faulted(vdev_stat_t *vs, uint_t vsc, void *arg)
|
||||||
{
|
{
|
||||||
(void) vsc;
|
(void) vsc, (void) arg;
|
||||||
return (vs->vs_state == VDEV_STATE_FAULTED);
|
return (vs->vs_state == VDEV_STATE_FAULTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
vdev_errors(vdev_stat_t *vs, uint_t vsc)
|
vdev_errors(vdev_stat_t *vs, uint_t vsc, void *arg)
|
||||||
{
|
{
|
||||||
(void) vsc;
|
(void) vsc, (void) arg;
|
||||||
return (vs->vs_state == VDEV_STATE_DEGRADED ||
|
return (vs->vs_state == VDEV_STATE_DEGRADED ||
|
||||||
vs->vs_read_errors != 0 || vs->vs_write_errors != 0 ||
|
vs->vs_read_errors != 0 || vs->vs_write_errors != 0 ||
|
||||||
vs->vs_checksum_errors != 0);
|
vs->vs_checksum_errors != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
vdev_broken(vdev_stat_t *vs, uint_t vsc)
|
vdev_broken(vdev_stat_t *vs, uint_t vsc, void *arg)
|
||||||
{
|
{
|
||||||
(void) vsc;
|
(void) vsc, (void) arg;
|
||||||
return (vs->vs_state == VDEV_STATE_CANT_OPEN);
|
return (vs->vs_state == VDEV_STATE_CANT_OPEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
vdev_offlined(vdev_stat_t *vs, uint_t vsc)
|
vdev_offlined(vdev_stat_t *vs, uint_t vsc, void *arg)
|
||||||
{
|
{
|
||||||
(void) vsc;
|
(void) vsc, (void) arg;
|
||||||
return (vs->vs_state == VDEV_STATE_OFFLINE);
|
return (vs->vs_state == VDEV_STATE_OFFLINE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
vdev_removed(vdev_stat_t *vs, uint_t vsc)
|
vdev_removed(vdev_stat_t *vs, uint_t vsc, void *arg)
|
||||||
{
|
{
|
||||||
(void) vsc;
|
(void) vsc, (void) arg;
|
||||||
return (vs->vs_state == VDEV_STATE_REMOVED);
|
return (vs->vs_state == VDEV_STATE_REMOVED);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
vdev_non_native_ashift(vdev_stat_t *vs, uint_t vsc)
|
vdev_non_native_ashift(vdev_stat_t *vs, uint_t vsc, void *arg)
|
||||||
{
|
{
|
||||||
if (getenv("ZPOOL_STATUS_NON_NATIVE_ASHIFT_IGNORE") != NULL)
|
uint64_t ashift = *(uint64_t *)arg;
|
||||||
return (0);
|
|
||||||
|
|
||||||
return (VDEV_STAT_VALID(vs_physical_ashift, vsc) &&
|
return (VDEV_STAT_VALID(vs_physical_ashift, vsc) &&
|
||||||
|
(ashift == 0 || vs->vs_configured_ashift < ashift) &&
|
||||||
vs->vs_configured_ashift < vs->vs_physical_ashift);
|
vs->vs_configured_ashift < vs->vs_physical_ashift);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,8 +156,8 @@ vdev_non_native_ashift(vdev_stat_t *vs, uint_t vsc)
|
|||||||
* Detect if any leaf devices that have seen errors or could not be opened.
|
* Detect if any leaf devices that have seen errors or could not be opened.
|
||||||
*/
|
*/
|
||||||
static boolean_t
|
static boolean_t
|
||||||
find_vdev_problem(nvlist_t *vdev, int (*func)(vdev_stat_t *, uint_t),
|
find_vdev_problem(nvlist_t *vdev, int (*func)(vdev_stat_t *, uint_t, void *),
|
||||||
boolean_t ignore_replacing)
|
void *arg, boolean_t ignore_replacing)
|
||||||
{
|
{
|
||||||
nvlist_t **child;
|
nvlist_t **child;
|
||||||
uint_t c, children;
|
uint_t c, children;
|
||||||
@@ -177,14 +177,16 @@ find_vdev_problem(nvlist_t *vdev, int (*func)(vdev_stat_t *, uint_t),
|
|||||||
|
|
||||||
if (nvlist_lookup_nvlist_array(vdev, ZPOOL_CONFIG_CHILDREN, &child,
|
if (nvlist_lookup_nvlist_array(vdev, ZPOOL_CONFIG_CHILDREN, &child,
|
||||||
&children) == 0) {
|
&children) == 0) {
|
||||||
for (c = 0; c < children; c++)
|
for (c = 0; c < children; c++) {
|
||||||
if (find_vdev_problem(child[c], func, ignore_replacing))
|
if (find_vdev_problem(child[c], func, arg,
|
||||||
|
ignore_replacing))
|
||||||
return (B_TRUE);
|
return (B_TRUE);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
uint_t vsc;
|
uint_t vsc;
|
||||||
vdev_stat_t *vs = (vdev_stat_t *)fnvlist_lookup_uint64_array(
|
vdev_stat_t *vs = (vdev_stat_t *)fnvlist_lookup_uint64_array(
|
||||||
vdev, ZPOOL_CONFIG_VDEV_STATS, &vsc);
|
vdev, ZPOOL_CONFIG_VDEV_STATS, &vsc);
|
||||||
if (func(vs, vsc) != 0)
|
if (func(vs, vsc, arg) != 0)
|
||||||
return (B_TRUE);
|
return (B_TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,9 +195,11 @@ find_vdev_problem(nvlist_t *vdev, int (*func)(vdev_stat_t *, uint_t),
|
|||||||
*/
|
*/
|
||||||
if (nvlist_lookup_nvlist_array(vdev, ZPOOL_CONFIG_L2CACHE, &child,
|
if (nvlist_lookup_nvlist_array(vdev, ZPOOL_CONFIG_L2CACHE, &child,
|
||||||
&children) == 0) {
|
&children) == 0) {
|
||||||
for (c = 0; c < children; c++)
|
for (c = 0; c < children; c++) {
|
||||||
if (find_vdev_problem(child[c], func, ignore_replacing))
|
if (find_vdev_problem(child[c], func, arg,
|
||||||
|
ignore_replacing))
|
||||||
return (B_TRUE);
|
return (B_TRUE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (B_FALSE);
|
return (B_FALSE);
|
||||||
@@ -220,7 +224,7 @@ find_vdev_problem(nvlist_t *vdev, int (*func)(vdev_stat_t *, uint_t),
|
|||||||
*/
|
*/
|
||||||
static zpool_status_t
|
static zpool_status_t
|
||||||
check_status(nvlist_t *config, boolean_t isimport,
|
check_status(nvlist_t *config, boolean_t isimport,
|
||||||
zpool_errata_t *erratap, const char *compat)
|
zpool_errata_t *erratap, const char *compat, uint64_t ashift)
|
||||||
{
|
{
|
||||||
pool_scan_stat_t *ps = NULL;
|
pool_scan_stat_t *ps = NULL;
|
||||||
uint_t vsc, psc;
|
uint_t vsc, psc;
|
||||||
@@ -371,15 +375,15 @@ check_status(nvlist_t *config, boolean_t isimport,
|
|||||||
* Bad devices in non-replicated config.
|
* Bad devices in non-replicated config.
|
||||||
*/
|
*/
|
||||||
if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
|
if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
|
||||||
find_vdev_problem(nvroot, vdev_faulted, B_TRUE))
|
find_vdev_problem(nvroot, vdev_faulted, NULL, B_TRUE))
|
||||||
return (ZPOOL_STATUS_FAULTED_DEV_NR);
|
return (ZPOOL_STATUS_FAULTED_DEV_NR);
|
||||||
|
|
||||||
if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
|
if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
|
||||||
find_vdev_problem(nvroot, vdev_missing, B_TRUE))
|
find_vdev_problem(nvroot, vdev_missing, NULL, B_TRUE))
|
||||||
return (ZPOOL_STATUS_MISSING_DEV_NR);
|
return (ZPOOL_STATUS_MISSING_DEV_NR);
|
||||||
|
|
||||||
if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
|
if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
|
||||||
find_vdev_problem(nvroot, vdev_broken, B_TRUE))
|
find_vdev_problem(nvroot, vdev_broken, NULL, B_TRUE))
|
||||||
return (ZPOOL_STATUS_CORRUPT_LABEL_NR);
|
return (ZPOOL_STATUS_CORRUPT_LABEL_NR);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -402,35 +406,37 @@ check_status(nvlist_t *config, boolean_t isimport,
|
|||||||
/*
|
/*
|
||||||
* Missing devices in a replicated config.
|
* Missing devices in a replicated config.
|
||||||
*/
|
*/
|
||||||
if (find_vdev_problem(nvroot, vdev_faulted, B_TRUE))
|
if (find_vdev_problem(nvroot, vdev_faulted, NULL, B_TRUE))
|
||||||
return (ZPOOL_STATUS_FAULTED_DEV_R);
|
return (ZPOOL_STATUS_FAULTED_DEV_R);
|
||||||
if (find_vdev_problem(nvroot, vdev_missing, B_TRUE))
|
if (find_vdev_problem(nvroot, vdev_missing, NULL, B_TRUE))
|
||||||
return (ZPOOL_STATUS_MISSING_DEV_R);
|
return (ZPOOL_STATUS_MISSING_DEV_R);
|
||||||
if (find_vdev_problem(nvroot, vdev_broken, B_TRUE))
|
if (find_vdev_problem(nvroot, vdev_broken, NULL, B_TRUE))
|
||||||
return (ZPOOL_STATUS_CORRUPT_LABEL_R);
|
return (ZPOOL_STATUS_CORRUPT_LABEL_R);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Devices with errors
|
* Devices with errors
|
||||||
*/
|
*/
|
||||||
if (!isimport && find_vdev_problem(nvroot, vdev_errors, B_TRUE))
|
if (!isimport && find_vdev_problem(nvroot, vdev_errors, NULL, B_TRUE))
|
||||||
return (ZPOOL_STATUS_FAILING_DEV);
|
return (ZPOOL_STATUS_FAILING_DEV);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Offlined devices
|
* Offlined devices
|
||||||
*/
|
*/
|
||||||
if (find_vdev_problem(nvroot, vdev_offlined, B_TRUE))
|
if (find_vdev_problem(nvroot, vdev_offlined, NULL, B_TRUE))
|
||||||
return (ZPOOL_STATUS_OFFLINE_DEV);
|
return (ZPOOL_STATUS_OFFLINE_DEV);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Removed device
|
* Removed device
|
||||||
*/
|
*/
|
||||||
if (find_vdev_problem(nvroot, vdev_removed, B_TRUE))
|
if (find_vdev_problem(nvroot, vdev_removed, NULL, B_TRUE))
|
||||||
return (ZPOOL_STATUS_REMOVED_DEV);
|
return (ZPOOL_STATUS_REMOVED_DEV);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Suboptimal, but usable, ashift configuration.
|
* Suboptimal, but usable, ashift configuration.
|
||||||
*/
|
*/
|
||||||
if (find_vdev_problem(nvroot, vdev_non_native_ashift, B_FALSE))
|
if (!isimport &&
|
||||||
|
getenv("ZPOOL_STATUS_NON_NATIVE_ASHIFT_IGNORE") == NULL &&
|
||||||
|
find_vdev_problem(nvroot, vdev_non_native_ashift, &ashift, B_FALSE))
|
||||||
return (ZPOOL_STATUS_NON_NATIVE_ASHIFT);
|
return (ZPOOL_STATUS_NON_NATIVE_ASHIFT);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -509,8 +515,10 @@ zpool_get_status(zpool_handle_t *zhp, const char **msgid,
|
|||||||
ZFS_MAXPROPLEN, NULL, B_FALSE) != 0)
|
ZFS_MAXPROPLEN, NULL, B_FALSE) != 0)
|
||||||
compatibility[0] = '\0';
|
compatibility[0] = '\0';
|
||||||
|
|
||||||
|
uint64_t ashift = zpool_get_prop_int(zhp, ZPOOL_PROP_ASHIFT, NULL);
|
||||||
|
|
||||||
zpool_status_t ret = check_status(zhp->zpool_config, B_FALSE, errata,
|
zpool_status_t ret = check_status(zhp->zpool_config, B_FALSE, errata,
|
||||||
compatibility);
|
compatibility, ashift);
|
||||||
|
|
||||||
if (msgid != NULL) {
|
if (msgid != NULL) {
|
||||||
if (ret >= NMSGID)
|
if (ret >= NMSGID)
|
||||||
@@ -525,7 +533,7 @@ zpool_status_t
|
|||||||
zpool_import_status(nvlist_t *config, const char **msgid,
|
zpool_import_status(nvlist_t *config, const char **msgid,
|
||||||
zpool_errata_t *errata)
|
zpool_errata_t *errata)
|
||||||
{
|
{
|
||||||
zpool_status_t ret = check_status(config, B_TRUE, errata, NULL);
|
zpool_status_t ret = check_status(config, B_TRUE, errata, NULL, 0);
|
||||||
|
|
||||||
if (ret >= NMSGID)
|
if (ret >= NMSGID)
|
||||||
*msgid = NULL;
|
*msgid = NULL;
|
||||||
|
|||||||
@@ -1175,7 +1175,7 @@ zfs_file_write(zfs_file_t *fp, const void *buf, size_t count, ssize_t *resid)
|
|||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
zfs_file_pwrite(zfs_file_t *fp, const void *buf,
|
zfs_file_pwrite(zfs_file_t *fp, const void *buf,
|
||||||
size_t count, loff_t pos, ssize_t *resid)
|
size_t count, loff_t pos, uint8_t ashift, ssize_t *resid)
|
||||||
{
|
{
|
||||||
ssize_t rc, split, done;
|
ssize_t rc, split, done;
|
||||||
int sectors;
|
int sectors;
|
||||||
@@ -1185,8 +1185,8 @@ zfs_file_pwrite(zfs_file_t *fp, const void *buf,
|
|||||||
* system calls so that the process can be killed in between.
|
* system calls so that the process can be killed in between.
|
||||||
* This is used by ztest to simulate realistic failure modes.
|
* This is used by ztest to simulate realistic failure modes.
|
||||||
*/
|
*/
|
||||||
sectors = count >> SPA_MINBLOCKSHIFT;
|
sectors = count >> ashift;
|
||||||
split = (sectors > 0 ? rand() % sectors : 0) << SPA_MINBLOCKSHIFT;
|
split = (sectors > 0 ? rand() % sectors : 0) << ashift;
|
||||||
rc = pwrite64(fp->f_fd, buf, split, pos);
|
rc = pwrite64(fp->f_fd, buf, split, pos);
|
||||||
if (rc != -1) {
|
if (rc != -1) {
|
||||||
done = rc;
|
done = rc;
|
||||||
|
|||||||
@@ -122,6 +122,24 @@ Example:
|
|||||||
.Nm zhack Cm label repair Fl cu Ar device
|
.Nm zhack Cm label repair Fl cu Ar device
|
||||||
Fix checksums and undetach a device
|
Fix checksums and undetach a device
|
||||||
.
|
.
|
||||||
|
.It Xo
|
||||||
|
.Nm zhack
|
||||||
|
.Cm metaslab leak
|
||||||
|
.Op Fl f
|
||||||
|
.Ar pool
|
||||||
|
.Xc
|
||||||
|
Apply a fragmentation profile generated by
|
||||||
|
.Sy zdb
|
||||||
|
to the specified
|
||||||
|
.Ar pool Ns
|
||||||
|
\&.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Fl f
|
||||||
|
flag forces the profile to apply even if the vdevs in the
|
||||||
|
.Ar pool
|
||||||
|
don't have the same number of metaslabs as the fragmentation profile.
|
||||||
|
.
|
||||||
.El
|
.El
|
||||||
.
|
.
|
||||||
.Sh GLOBAL OPTIONS
|
.Sh GLOBAL OPTIONS
|
||||||
@@ -143,6 +161,8 @@ Search for
|
|||||||
members in
|
members in
|
||||||
.Ar dir .
|
.Ar dir .
|
||||||
Can be specified more than once.
|
Can be specified more than once.
|
||||||
|
.It Fl o Ar var Ns = Ns Ar value
|
||||||
|
Set the given tunable to the provided value.
|
||||||
.El
|
.El
|
||||||
.
|
.
|
||||||
.Sh EXAMPLES
|
.Sh EXAMPLES
|
||||||
|
|||||||
+82
-1
@@ -17,7 +17,7 @@
|
|||||||
.\" own identifying information:
|
.\" own identifying information:
|
||||||
.\" Portions Copyright [yyyy] [name of copyright owner]
|
.\" Portions Copyright [yyyy] [name of copyright owner]
|
||||||
.\"
|
.\"
|
||||||
.Dd May 24, 2025
|
.Dd September 15, 2025
|
||||||
.Dt ZFS 4
|
.Dt ZFS 4
|
||||||
.Os
|
.Os
|
||||||
.
|
.
|
||||||
@@ -2551,6 +2551,49 @@ the xattr so as to not accumulate duplicates.
|
|||||||
.It Sy zio_requeue_io_start_cut_in_line Ns = Ns Sy 0 Ns | Ns 1 Pq int
|
.It Sy zio_requeue_io_start_cut_in_line Ns = Ns Sy 0 Ns | Ns 1 Pq int
|
||||||
Prioritize requeued I/O.
|
Prioritize requeued I/O.
|
||||||
.
|
.
|
||||||
|
.It Sy zfs_delete_inode Ns = Ns Sy 0 Ns | Ns 1 Pq int
|
||||||
|
Sets whether the kernel should free an inode structure when the last reference
|
||||||
|
is released, or cache it in memory.
|
||||||
|
Intended for testing/debugging.
|
||||||
|
.Pp
|
||||||
|
A live inode structure "pins" versious internal OpenZFS structures in memory,
|
||||||
|
which can result in large amounts of "unusable" memory on systems with lots of
|
||||||
|
infrequently-accessed files, until the kernel's memory pressure mechanism
|
||||||
|
asks OpenZFS to release them.
|
||||||
|
.Pp
|
||||||
|
The default value of
|
||||||
|
.Sy 0
|
||||||
|
always caches inodes that appear to still exist on disk.
|
||||||
|
Setting it to
|
||||||
|
.Sy 1
|
||||||
|
will immediately release unused inodes and their associated memory back to the
|
||||||
|
dbuf cache or the ARC for reuse, but may reduce performance if inodes are
|
||||||
|
frequently evicted and reloaded.
|
||||||
|
.Pp
|
||||||
|
This parameter is only available on Linux.
|
||||||
|
.
|
||||||
|
.It Sy zfs_delete_dentry Ns = Ns Sy 0 Ns | Ns 1 Pq int
|
||||||
|
Sets whether the kernel should free a dentry structure when it is no longer
|
||||||
|
required, or hold it in the dentry cache.
|
||||||
|
Intended for testing/debugging.
|
||||||
|
.
|
||||||
|
Since a dentry structure holds an inode reference, a cached dentry can "pin"
|
||||||
|
an inode in memory indefinitely, along with associated OpenZFS structures (See
|
||||||
|
.Sy zfs_delete_inode ) .
|
||||||
|
.Pp
|
||||||
|
The default value of
|
||||||
|
.Sy 0
|
||||||
|
instructs the kernel to cache entries and their associated inodes when they
|
||||||
|
are no longer directly referenced.
|
||||||
|
They will be reclaimed as part of the kernel's normal cache management
|
||||||
|
processes.
|
||||||
|
Setting it to
|
||||||
|
.Sy 1
|
||||||
|
will instruct the kernel to release directory entries and their inodes as soon
|
||||||
|
as they are no longer referenced by the filesystem.
|
||||||
|
.Pp
|
||||||
|
This parameter is only available on Linux.
|
||||||
|
.
|
||||||
.It Sy zio_taskq_batch_pct Ns = Ns Sy 80 Ns % Pq uint
|
.It Sy zio_taskq_batch_pct Ns = Ns Sy 80 Ns % Pq uint
|
||||||
Percentage of online CPUs which will run a worker thread for I/O.
|
Percentage of online CPUs which will run a worker thread for I/O.
|
||||||
These workers are responsible for I/O work such as compression, encryption,
|
These workers are responsible for I/O work such as compression, encryption,
|
||||||
@@ -2585,12 +2628,50 @@ Set value only applies to pools imported/created after that.
|
|||||||
Set the queue and thread configuration for the IO read queues.
|
Set the queue and thread configuration for the IO read queues.
|
||||||
This is an advanced debugging parameter.
|
This is an advanced debugging parameter.
|
||||||
Don't change this unless you understand what it does.
|
Don't change this unless you understand what it does.
|
||||||
|
Each of the four values corresponds to the issue, issue high-priority,
|
||||||
|
interrupt, and interrupt high-priority queues.
|
||||||
|
Valid values are
|
||||||
|
.Sy fixed,N,M
|
||||||
|
(M queues with N threads each),
|
||||||
|
.Sy scale[,MIN]
|
||||||
|
(scale with CPUs, minimum MIN total threads),
|
||||||
|
.Sy sync ,
|
||||||
|
and
|
||||||
|
.Sy null .
|
||||||
Set values only apply to pools imported/created after that.
|
Set values only apply to pools imported/created after that.
|
||||||
.
|
.
|
||||||
.It Sy zio_taskq_write Ns = Ns Sy sync null scale null Pq charp
|
.It Sy zio_taskq_write Ns = Ns Sy sync null scale null Pq charp
|
||||||
Set the queue and thread configuration for the IO write queues.
|
Set the queue and thread configuration for the IO write queues.
|
||||||
This is an advanced debugging parameter.
|
This is an advanced debugging parameter.
|
||||||
Don't change this unless you understand what it does.
|
Don't change this unless you understand what it does.
|
||||||
|
Each of the four values corresponds to the issue, issue high-priority,
|
||||||
|
interrupt, and interrupt high-priority queues.
|
||||||
|
Valid values are
|
||||||
|
.Sy fixed,N,M
|
||||||
|
(M queues with N threads each),
|
||||||
|
.Sy scale[,MIN]
|
||||||
|
(scale with CPUs, minimum MIN total threads),
|
||||||
|
.Sy sync ,
|
||||||
|
and
|
||||||
|
.Sy null .
|
||||||
|
Set values only apply to pools imported/created after that.
|
||||||
|
.
|
||||||
|
.It Sy zio_taskq_free Ns = Ns Sy scale,32 null null null Pq charp
|
||||||
|
Set the queue and thread configuration for the IO free queues.
|
||||||
|
This is an advanced debugging parameter.
|
||||||
|
Don't change this unless you understand what it does.
|
||||||
|
Each of the four values corresponds to the issue, issue high-priority,
|
||||||
|
interrupt, and interrupt high-priority queues.
|
||||||
|
Valid values are
|
||||||
|
.Sy fixed,N,M
|
||||||
|
(M queues with N threads each),
|
||||||
|
.Sy scale[,MIN]
|
||||||
|
(scale with CPUs, minimum MIN total threads),
|
||||||
|
.Sy sync ,
|
||||||
|
and
|
||||||
|
.Sy null .
|
||||||
|
The default uses a minimum of 32 threads to improve parallelism for
|
||||||
|
DDT and BRT metadata operations during frees.
|
||||||
Set values only apply to pools imported/created after that.
|
Set values only apply to pools imported/created after that.
|
||||||
.
|
.
|
||||||
.It Sy zvol_inhibit_dev Ns = Ns Sy 0 Ns | Ns 1 Pq uint
|
.It Sy zvol_inhibit_dev Ns = Ns Sy 0 Ns | Ns 1 Pq uint
|
||||||
|
|||||||
@@ -69,6 +69,13 @@
|
|||||||
.Op Fl U Ar cache
|
.Op Fl U Ar cache
|
||||||
.Ar poolname Op Ar vdev Oo Ar metaslab Oc Ns …
|
.Ar poolname Op Ar vdev Oo Ar metaslab Oc Ns …
|
||||||
.Nm
|
.Nm
|
||||||
|
.Fl -allocated-map
|
||||||
|
.Op Fl mAFLPXY
|
||||||
|
.Op Fl e Oo Fl V Oc Oo Fl p Ar path Oc Ns …
|
||||||
|
.Op Fl t Ar txg
|
||||||
|
.Op Fl U Ar cache
|
||||||
|
.Ar poolname Op Ar vdev Oo Ar metaslab Oc Ns …
|
||||||
|
.Nm
|
||||||
.Fl O
|
.Fl O
|
||||||
.Op Fl K Ar key
|
.Op Fl K Ar key
|
||||||
.Ar dataset path
|
.Ar dataset path
|
||||||
@@ -128,6 +135,11 @@ that zdb may interpret inconsistent pool data and behave erratically.
|
|||||||
.Sh OPTIONS
|
.Sh OPTIONS
|
||||||
Display options:
|
Display options:
|
||||||
.Bl -tag -width Ds
|
.Bl -tag -width Ds
|
||||||
|
.It Fl Sy -allocated-map
|
||||||
|
Prints out a list of all the allocated regions in the pool.
|
||||||
|
Primarily intended for use with the
|
||||||
|
.Nm zhack metaslab leak
|
||||||
|
subcommand.
|
||||||
.It Fl b , -block-stats
|
.It Fl b , -block-stats
|
||||||
Display statistics regarding the number, size
|
Display statistics regarding the number, size
|
||||||
.Pq logical, physical and allocated
|
.Pq logical, physical and allocated
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
# first. This ensures its module initialization function is run before
|
# first. This ensures its module initialization function is run before
|
||||||
# any of the other module initialization functions which depend on it.
|
# any of the other module initialization functions which depend on it.
|
||||||
|
|
||||||
ZFS_MODULE_CFLAGS += -std=gnu99 -Wno-declaration-after-statement
|
ZFS_MODULE_CFLAGS += -std=gnu11 -Wno-declaration-after-statement
|
||||||
ZFS_MODULE_CFLAGS += -Wmissing-prototypes
|
ZFS_MODULE_CFLAGS += -Wmissing-prototypes
|
||||||
ZFS_MODULE_CFLAGS += @KERNEL_DEBUG_CFLAGS@ @NO_FORMAT_ZERO_LENGTH@
|
ZFS_MODULE_CFLAGS += @KERNEL_DEBUG_CFLAGS@ @NO_FORMAT_ZERO_LENGTH@
|
||||||
|
|
||||||
|
|||||||
@@ -62,11 +62,6 @@ CFLAGS+= -DZFS_DEBUG -g
|
|||||||
CFLAGS += -DNDEBUG
|
CFLAGS += -DNDEBUG
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
.if defined(WITH_VFS_DEBUG) && ${WITH_VFS_DEBUG} == "true"
|
|
||||||
# kernel must also be built with this option for this to work
|
|
||||||
CFLAGS+= -DDEBUG_VFS_LOCKS
|
|
||||||
.endif
|
|
||||||
|
|
||||||
.if defined(WITH_GCOV) && ${WITH_GCOV} == "true"
|
.if defined(WITH_GCOV) && ${WITH_GCOV} == "true"
|
||||||
CFLAGS+= -fprofile-arcs -ftest-coverage
|
CFLAGS+= -fprofile-arcs -ftest-coverage
|
||||||
.endif
|
.endif
|
||||||
|
|||||||
@@ -77,7 +77,8 @@ static const uint32_t SHA256_K[64] = {
|
|||||||
h = g, g = f, f = e, e = d + T1; \
|
h = g, g = f, f = e, e = d + T1; \
|
||||||
d = c, c = b, b = a, a = T1 + T2;
|
d = c, c = b, b = a, a = T1 + T2;
|
||||||
|
|
||||||
static void sha256_generic(uint32_t state[8], const void *data, size_t num_blks)
|
static void
|
||||||
|
icp_sha256_generic(uint32_t state[8], const void *data, size_t num_blks)
|
||||||
{
|
{
|
||||||
uint64_t blk;
|
uint64_t blk;
|
||||||
|
|
||||||
@@ -173,7 +174,8 @@ static const uint64_t SHA512_K[80] = {
|
|||||||
0x5fcb6fab3ad6faec, 0x6c44198c4a475817
|
0x5fcb6fab3ad6faec, 0x6c44198c4a475817
|
||||||
};
|
};
|
||||||
|
|
||||||
static void sha512_generic(uint64_t state[8], const void *data, size_t num_blks)
|
static void
|
||||||
|
icp_sha512_generic(uint64_t state[8], const void *data, size_t num_blks)
|
||||||
{
|
{
|
||||||
uint64_t blk;
|
uint64_t blk;
|
||||||
|
|
||||||
@@ -226,7 +228,8 @@ static void sha512_generic(uint64_t state[8], const void *data, size_t num_blks)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sha256_update(sha256_ctx *ctx, const uint8_t *data, size_t len)
|
static void
|
||||||
|
icp_sha256_update(sha256_ctx *ctx, const uint8_t *data, size_t len)
|
||||||
{
|
{
|
||||||
uint64_t pos = ctx->count[0];
|
uint64_t pos = ctx->count[0];
|
||||||
uint64_t total = ctx->count[1];
|
uint64_t total = ctx->count[1];
|
||||||
@@ -258,7 +261,8 @@ static void sha256_update(sha256_ctx *ctx, const uint8_t *data, size_t len)
|
|||||||
ctx->count[1] = total;
|
ctx->count[1] = total;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sha512_update(sha512_ctx *ctx, const uint8_t *data, size_t len)
|
static void
|
||||||
|
icp_sha512_update(sha512_ctx *ctx, const uint8_t *data, size_t len)
|
||||||
{
|
{
|
||||||
uint64_t pos = ctx->count[0];
|
uint64_t pos = ctx->count[0];
|
||||||
uint64_t total = ctx->count[1];
|
uint64_t total = ctx->count[1];
|
||||||
@@ -290,7 +294,8 @@ static void sha512_update(sha512_ctx *ctx, const uint8_t *data, size_t len)
|
|||||||
ctx->count[1] = total;
|
ctx->count[1] = total;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sha256_final(sha256_ctx *ctx, uint8_t *result, int bits)
|
static void
|
||||||
|
icp_sha256_final(sha256_ctx *ctx, uint8_t *result, int bits)
|
||||||
{
|
{
|
||||||
uint64_t mlen, pos = ctx->count[0];
|
uint64_t mlen, pos = ctx->count[0];
|
||||||
uint8_t *m = ctx->wbuf;
|
uint8_t *m = ctx->wbuf;
|
||||||
@@ -334,7 +339,8 @@ static void sha256_final(sha256_ctx *ctx, uint8_t *result, int bits)
|
|||||||
memset(ctx, 0, sizeof (*ctx));
|
memset(ctx, 0, sizeof (*ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sha512_final(sha512_ctx *ctx, uint8_t *result, int bits)
|
static void
|
||||||
|
icp_sha512_final(sha512_ctx *ctx, uint8_t *result, int bits)
|
||||||
{
|
{
|
||||||
uint64_t mlen, pos = ctx->count[0];
|
uint64_t mlen, pos = ctx->count[0];
|
||||||
uint8_t *m = ctx->wbuf, *r;
|
uint8_t *m = ctx->wbuf, *r;
|
||||||
@@ -461,14 +467,14 @@ SHA2Update(SHA2_CTX *ctx, const void *data, size_t len)
|
|||||||
|
|
||||||
switch (ctx->algotype) {
|
switch (ctx->algotype) {
|
||||||
case SHA256:
|
case SHA256:
|
||||||
sha256_update(&ctx->sha256, data, len);
|
icp_sha256_update(&ctx->sha256, data, len);
|
||||||
break;
|
break;
|
||||||
case SHA512:
|
case SHA512:
|
||||||
case SHA512_HMAC_MECH_INFO_TYPE:
|
case SHA512_HMAC_MECH_INFO_TYPE:
|
||||||
sha512_update(&ctx->sha512, data, len);
|
icp_sha512_update(&ctx->sha512, data, len);
|
||||||
break;
|
break;
|
||||||
case SHA512_256:
|
case SHA512_256:
|
||||||
sha512_update(&ctx->sha512, data, len);
|
icp_sha512_update(&ctx->sha512, data, len);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -479,32 +485,33 @@ SHA2Final(void *digest, SHA2_CTX *ctx)
|
|||||||
{
|
{
|
||||||
switch (ctx->algotype) {
|
switch (ctx->algotype) {
|
||||||
case SHA256:
|
case SHA256:
|
||||||
sha256_final(&ctx->sha256, digest, 256);
|
icp_sha256_final(&ctx->sha256, digest, 256);
|
||||||
break;
|
break;
|
||||||
case SHA512:
|
case SHA512:
|
||||||
case SHA512_HMAC_MECH_INFO_TYPE:
|
case SHA512_HMAC_MECH_INFO_TYPE:
|
||||||
sha512_final(&ctx->sha512, digest, 512);
|
icp_sha512_final(&ctx->sha512, digest, 512);
|
||||||
break;
|
break;
|
||||||
case SHA512_256:
|
case SHA512_256:
|
||||||
sha512_final(&ctx->sha512, digest, 256);
|
icp_sha512_final(&ctx->sha512, digest, 256);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* the generic implementation is always okay */
|
/* the generic implementation is always okay */
|
||||||
static boolean_t sha2_is_supported(void)
|
static boolean_t
|
||||||
|
icp_sha2_is_supported(void)
|
||||||
{
|
{
|
||||||
return (B_TRUE);
|
return (B_TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
const sha256_ops_t sha256_generic_impl = {
|
const sha256_ops_t sha256_generic_impl = {
|
||||||
.name = "generic",
|
.name = "generic",
|
||||||
.transform = sha256_generic,
|
.transform = icp_sha256_generic,
|
||||||
.is_supported = sha2_is_supported
|
.is_supported = icp_sha2_is_supported
|
||||||
};
|
};
|
||||||
|
|
||||||
const sha512_ops_t sha512_generic_impl = {
|
const sha512_ops_t sha512_generic_impl = {
|
||||||
.name = "generic",
|
.name = "generic",
|
||||||
.transform = sha512_generic,
|
.transform = icp_sha512_generic,
|
||||||
.is_supported = sha2_is_supported
|
.is_supported = icp_sha2_is_supported
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3246,7 +3246,8 @@ nvs_xdr_nvl_fini(nvstream_t *nvs)
|
|||||||
* xdrproc_t-compatible callbacks for xdr_array()
|
* xdrproc_t-compatible callbacks for xdr_array()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if defined(_KERNEL) && defined(__linux__) /* Linux kernel */
|
#if (defined(__FreeBSD_version) && __FreeBSD_version >= 1600010) || \
|
||||||
|
defined(_KERNEL) && defined(__linux__) /* Linux kernel */
|
||||||
|
|
||||||
#define NVS_BUILD_XDRPROC_T(type) \
|
#define NVS_BUILD_XDRPROC_T(type) \
|
||||||
static bool_t \
|
static bool_t \
|
||||||
@@ -3255,7 +3256,7 @@ nvs_xdr_nvp_##type(XDR *xdrs, void *ptr) \
|
|||||||
return (xdr_##type(xdrs, ptr)); \
|
return (xdr_##type(xdrs, ptr)); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif !defined(_KERNEL) && defined(XDR_CONTROL) /* tirpc */
|
#elif !defined(_KERNEL) && defined(XDR_CONTROL) /* tirpc, FreeBSD < 16 */
|
||||||
|
|
||||||
#define NVS_BUILD_XDRPROC_T(type) \
|
#define NVS_BUILD_XDRPROC_T(type) \
|
||||||
static bool_t \
|
static bool_t \
|
||||||
@@ -3271,7 +3272,7 @@ nvs_xdr_nvp_##type(XDR *xdrs, ...) \
|
|||||||
return (xdr_##type(xdrs, ptr)); \
|
return (xdr_##type(xdrs, ptr)); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* FreeBSD, sunrpc */
|
#else /* FreeBSD kernel < 16, sunrpc */
|
||||||
|
|
||||||
#define NVS_BUILD_XDRPROC_T(type) \
|
#define NVS_BUILD_XDRPROC_T(type) \
|
||||||
static bool_t \
|
static bool_t \
|
||||||
|
|||||||
@@ -164,8 +164,9 @@ zfs_file_write(zfs_file_t *fp, const void *buf, size_t count, ssize_t *resid)
|
|||||||
|
|
||||||
int
|
int
|
||||||
zfs_file_pwrite(zfs_file_t *fp, const void *buf, size_t count, loff_t off,
|
zfs_file_pwrite(zfs_file_t *fp, const void *buf, size_t count, loff_t off,
|
||||||
ssize_t *resid)
|
uint8_t ashift, ssize_t *resid)
|
||||||
{
|
{
|
||||||
|
(void) ashift;
|
||||||
return (zfs_file_write_impl(fp, buf, count, &off, resid));
|
return (zfs_file_write_impl(fp, buf, count, &off, resid));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -100,14 +100,6 @@
|
|||||||
|
|
||||||
VFS_SMR_DECLARE;
|
VFS_SMR_DECLARE;
|
||||||
|
|
||||||
#ifdef DEBUG_VFS_LOCKS
|
|
||||||
#define VNCHECKREF(vp) \
|
|
||||||
VNASSERT((vp)->v_holdcnt > 0 && (vp)->v_usecount > 0, vp, \
|
|
||||||
("%s: wrong ref counts", __func__));
|
|
||||||
#else
|
|
||||||
#define VNCHECKREF(vp)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __FreeBSD_version >= 1400045
|
#if __FreeBSD_version >= 1400045
|
||||||
typedef uint64_t cookie_t;
|
typedef uint64_t cookie_t;
|
||||||
#else
|
#else
|
||||||
@@ -965,9 +957,6 @@ zfs_create(znode_t *dzp, const char *name, vattr_t *vap, int excl, int mode,
|
|||||||
zfs_acl_ids_t acl_ids;
|
zfs_acl_ids_t acl_ids;
|
||||||
boolean_t fuid_dirtied;
|
boolean_t fuid_dirtied;
|
||||||
uint64_t txtype;
|
uint64_t txtype;
|
||||||
#ifdef DEBUG_VFS_LOCKS
|
|
||||||
vnode_t *dvp = ZTOV(dzp);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (is_nametoolong(zfsvfs, name))
|
if (is_nametoolong(zfsvfs, name))
|
||||||
return (SET_ERROR(ENAMETOOLONG));
|
return (SET_ERROR(ENAMETOOLONG));
|
||||||
@@ -1097,7 +1086,8 @@ zfs_create(znode_t *dzp, const char *name, vattr_t *vap, int excl, int mode,
|
|||||||
getnewvnode_drop_reserve();
|
getnewvnode_drop_reserve();
|
||||||
|
|
||||||
out:
|
out:
|
||||||
VNCHECKREF(dvp);
|
VNASSERT(ZTOV(dzp)->v_holdcnt > 0 && ZTOV(dzp)->v_usecount > 0,
|
||||||
|
ZTOV(dzp), ("%s: wrong ref counts", __func__));
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
*zpp = zp;
|
*zpp = zp;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -371,9 +371,6 @@ error:
|
|||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *failed_decrypt_buf;
|
|
||||||
int failed_decrypt_size;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function handles all encryption and decryption in zfs. When
|
* This function handles all encryption and decryption in zfs. When
|
||||||
* encrypting it expects puio to reference the plaintext and cuio to
|
* encrypting it expects puio to reference the plaintext and cuio to
|
||||||
@@ -1663,9 +1660,6 @@ error:
|
|||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *failed_decrypt_buf;
|
|
||||||
int faile_decrypt_size;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Primary encryption / decryption entrypoint for zio data.
|
* Primary encryption / decryption entrypoint for zio data.
|
||||||
*/
|
*/
|
||||||
@@ -1758,13 +1752,6 @@ zio_do_crypt_data(boolean_t encrypt, zio_crypt_key_t *key,
|
|||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (!encrypt) {
|
|
||||||
if (failed_decrypt_buf != NULL)
|
|
||||||
kmem_free(failed_decrypt_buf, failed_decrypt_size);
|
|
||||||
failed_decrypt_buf = kmem_alloc(datalen, KM_SLEEP);
|
|
||||||
failed_decrypt_size = datalen;
|
|
||||||
memcpy(failed_decrypt_buf, cipherbuf, datalen);
|
|
||||||
}
|
|
||||||
if (locked)
|
if (locked)
|
||||||
rw_exit(&key->zk_salt_lock);
|
rw_exit(&key->zk_salt_lock);
|
||||||
if (authbuf != NULL)
|
if (authbuf != NULL)
|
||||||
|
|||||||
@@ -25,6 +25,10 @@
|
|||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2025, Rob Norris <robn@despairlabs.com>
|
||||||
|
*/
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/sysmacros.h>
|
#include <sys/sysmacros.h>
|
||||||
#include <sys/kmem.h>
|
#include <sys/kmem.h>
|
||||||
@@ -56,6 +60,19 @@ typedef struct zone_dataset {
|
|||||||
} zone_dataset_t;
|
} zone_dataset_t;
|
||||||
|
|
||||||
#ifdef CONFIG_USER_NS
|
#ifdef CONFIG_USER_NS
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Linux 6.18 moved the generic namespace type away from ns->ops->type onto
|
||||||
|
* ns_common itself.
|
||||||
|
*/
|
||||||
|
#ifdef HAVE_NS_COMMON_TYPE
|
||||||
|
#define ns_is_newuser(ns) \
|
||||||
|
((ns)->ns_type == CLONE_NEWUSER)
|
||||||
|
#else
|
||||||
|
#define ns_is_newuser(ns) \
|
||||||
|
((ns)->ops != NULL && (ns)->ops->type == CLONE_NEWUSER)
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns:
|
* Returns:
|
||||||
* - 0 on success
|
* - 0 on success
|
||||||
@@ -84,7 +101,7 @@ user_ns_get(int fd, struct user_namespace **userns)
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
ns = get_proc_ns(file_inode(nsfile));
|
ns = get_proc_ns(file_inode(nsfile));
|
||||||
if (ns->ops->type != CLONE_NEWUSER) {
|
if (!ns_is_newuser(ns)) {
|
||||||
error = ENOTTY;
|
error = ENOTTY;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
* Copyright (c) 2014 by Chunwei Chen. All rights reserved.
|
* Copyright (c) 2014 by Chunwei Chen. All rights reserved.
|
||||||
* Copyright (c) 2019 by Delphix. All rights reserved.
|
* Copyright (c) 2019 by Delphix. All rights reserved.
|
||||||
* Copyright (c) 2023, 2024, Klara Inc.
|
* Copyright (c) 2023, 2024, Klara Inc.
|
||||||
|
* Copyright (c) 2025, Rob Norris <robn@despairlabs.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -891,6 +892,14 @@ abd_iter_advance(struct abd_iter *aiter, size_t amount)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef nth_page
|
||||||
|
/*
|
||||||
|
* Since 6.18 nth_page() no longer exists, and is no longer required to iterate
|
||||||
|
* within a single SG entry, so we replace it with a simple addition.
|
||||||
|
*/
|
||||||
|
#define nth_page(p, n) ((p)+(n))
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Map the current chunk into aiter. This can be safely called when the aiter
|
* Map the current chunk into aiter. This can be safely called when the aiter
|
||||||
* has already exhausted, in which case this does nothing.
|
* has already exhausted, in which case this does nothing.
|
||||||
@@ -918,7 +927,14 @@ abd_iter_map(struct abd_iter *aiter)
|
|||||||
aiter->iter_mapsize = MIN(aiter->iter_sg->length - offset,
|
aiter->iter_mapsize = MIN(aiter->iter_sg->length - offset,
|
||||||
aiter->iter_abd->abd_size - aiter->iter_pos);
|
aiter->iter_abd->abd_size - aiter->iter_pos);
|
||||||
|
|
||||||
paddr = zfs_kmap_local(sg_page(aiter->iter_sg));
|
struct page *page = sg_page(aiter->iter_sg);
|
||||||
|
if (PageHighMem(page)) {
|
||||||
|
page = nth_page(page, offset / PAGE_SIZE);
|
||||||
|
offset &= PAGE_SIZE - 1;
|
||||||
|
aiter->iter_mapsize = MIN(aiter->iter_mapsize,
|
||||||
|
PAGE_SIZE - offset);
|
||||||
|
}
|
||||||
|
paddr = zfs_kmap_local(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
aiter->iter_mapaddr = (char *)paddr + offset;
|
aiter->iter_mapaddr = (char *)paddr + offset;
|
||||||
@@ -936,8 +952,14 @@ abd_iter_unmap(struct abd_iter *aiter)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (!abd_is_linear(aiter->iter_abd)) {
|
if (!abd_is_linear(aiter->iter_abd)) {
|
||||||
|
size_t offset = aiter->iter_offset;
|
||||||
|
|
||||||
|
struct page *page = sg_page(aiter->iter_sg);
|
||||||
|
if (PageHighMem(page))
|
||||||
|
offset &= PAGE_SIZE - 1;
|
||||||
|
|
||||||
/* LINTED E_FUNC_SET_NOT_USED */
|
/* LINTED E_FUNC_SET_NOT_USED */
|
||||||
zfs_kunmap_local(aiter->iter_mapaddr - aiter->iter_offset);
|
zfs_kunmap_local(aiter->iter_mapaddr - offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT3P(aiter->iter_mapaddr, !=, NULL);
|
ASSERT3P(aiter->iter_mapaddr, !=, NULL);
|
||||||
|
|||||||
@@ -115,8 +115,9 @@ zfs_file_write(zfs_file_t *fp, const void *buf, size_t count, ssize_t *resid)
|
|||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
zfs_file_pwrite(zfs_file_t *fp, const void *buf, size_t count, loff_t off,
|
zfs_file_pwrite(zfs_file_t *fp, const void *buf, size_t count, loff_t off,
|
||||||
ssize_t *resid)
|
uint8_t ashift, ssize_t *resid)
|
||||||
{
|
{
|
||||||
|
(void) ashift;
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
|
|
||||||
rc = kernel_write(fp, buf, count, &off);
|
rc = kernel_write(fp, buf, count, &off);
|
||||||
|
|||||||
@@ -100,15 +100,17 @@ zfs_uiomove_bvec_impl(void *p, size_t n, zfs_uio_rw_t rw, zfs_uio_t *uio)
|
|||||||
|
|
||||||
while (n && uio->uio_resid) {
|
while (n && uio->uio_resid) {
|
||||||
void *paddr;
|
void *paddr;
|
||||||
cnt = MIN(bv->bv_len - skip, n);
|
size_t offset = bv->bv_offset + skip;
|
||||||
|
cnt = MIN(PAGE_SIZE - (offset & ~PAGE_MASK),
|
||||||
|
MIN(bv->bv_len - skip, n));
|
||||||
|
|
||||||
paddr = zfs_kmap_local(bv->bv_page);
|
paddr = zfs_kmap_local(bv->bv_page + (offset >> PAGE_SHIFT));
|
||||||
if (rw == UIO_READ) {
|
if (rw == UIO_READ) {
|
||||||
/* Copy from buffer 'p' to the bvec data */
|
/* Copy from buffer 'p' to the bvec data */
|
||||||
memcpy(paddr + bv->bv_offset + skip, p, cnt);
|
memcpy(paddr + (offset & ~PAGE_MASK), p, cnt);
|
||||||
} else {
|
} else {
|
||||||
/* Copy from bvec data to buffer 'p' */
|
/* Copy from bvec data to buffer 'p' */
|
||||||
memcpy(p, paddr + bv->bv_offset + skip, cnt);
|
memcpy(p, paddr + (offset & ~PAGE_MASK), cnt);
|
||||||
}
|
}
|
||||||
zfs_kunmap_local(paddr);
|
zfs_kunmap_local(paddr);
|
||||||
|
|
||||||
|
|||||||
@@ -1521,6 +1521,12 @@ zfs_domount(struct super_block *sb, zfs_mnt_t *zm, int silent)
|
|||||||
sb->s_xattr = zpl_xattr_handlers;
|
sb->s_xattr = zpl_xattr_handlers;
|
||||||
sb->s_export_op = &zpl_export_operations;
|
sb->s_export_op = &zpl_export_operations;
|
||||||
|
|
||||||
|
#ifdef HAVE_SET_DEFAULT_D_OP
|
||||||
|
set_default_d_op(sb, &zpl_dentry_operations);
|
||||||
|
#else
|
||||||
|
sb->s_d_op = &zpl_dentry_operations;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Set features for file system. */
|
/* Set features for file system. */
|
||||||
zfs_set_fuid_feature(zfsvfs);
|
zfs_set_fuid_feature(zfsvfs);
|
||||||
|
|
||||||
|
|||||||
@@ -3516,7 +3516,8 @@ zfs_link(znode_t *tdzp, znode_t *szp, char *name, cred_t *cr,
|
|||||||
boolean_t is_tmpfile = 0;
|
boolean_t is_tmpfile = 0;
|
||||||
uint64_t txg;
|
uint64_t txg;
|
||||||
|
|
||||||
is_tmpfile = (sip->i_nlink == 0 && (sip->i_state & I_LINKABLE));
|
is_tmpfile = (sip->i_nlink == 0 &&
|
||||||
|
(inode_state_read_once(sip) & I_LINKABLE));
|
||||||
|
|
||||||
ASSERT(S_ISDIR(ZTOI(tdzp)->i_mode));
|
ASSERT(S_ISDIR(ZTOI(tdzp)->i_mode));
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2011, Lawrence Livermore National Security, LLC.
|
* Copyright (c) 2011, Lawrence Livermore National Security, LLC.
|
||||||
* Copyright (c) 2015 by Chunwei Chen. All rights reserved.
|
* Copyright (c) 2015 by Chunwei Chen. All rights reserved.
|
||||||
|
* Copyright (c) 2025, Rob Norris <robn@despairlabs.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@@ -444,6 +445,7 @@ zpl_putpage(struct page *pp, struct writeback_control *wbc, void *data)
|
|||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_WRITE_CACHE_PAGES
|
||||||
#ifdef HAVE_WRITEPAGE_T_FOLIO
|
#ifdef HAVE_WRITEPAGE_T_FOLIO
|
||||||
static int
|
static int
|
||||||
zpl_putfolio(struct folio *pp, struct writeback_control *wbc, void *data)
|
zpl_putfolio(struct folio *pp, struct writeback_control *wbc, void *data)
|
||||||
@@ -465,6 +467,78 @@ zpl_write_cache_pages(struct address_space *mapping,
|
|||||||
#endif
|
#endif
|
||||||
return (result);
|
return (result);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
static inline int
|
||||||
|
zpl_write_cache_pages(struct address_space *mapping,
|
||||||
|
struct writeback_control *wbc, void *data)
|
||||||
|
{
|
||||||
|
pgoff_t start = wbc->range_start >> PAGE_SHIFT;
|
||||||
|
pgoff_t end = wbc->range_end >> PAGE_SHIFT;
|
||||||
|
|
||||||
|
struct folio_batch fbatch;
|
||||||
|
folio_batch_init(&fbatch);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This atomically (-ish) tags all DIRTY pages in the range with
|
||||||
|
* TOWRITE, allowing users to continue dirtying or undirtying pages
|
||||||
|
* while we get on with writeback, without us treading on each other.
|
||||||
|
*/
|
||||||
|
tag_pages_for_writeback(mapping, start, end);
|
||||||
|
|
||||||
|
int err = 0;
|
||||||
|
unsigned int npages;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Grab references to the TOWRITE pages just flagged. This may not get
|
||||||
|
* all of them, so we do it in a loop until there are none left.
|
||||||
|
*/
|
||||||
|
while ((npages = filemap_get_folios_tag(mapping, &start, end,
|
||||||
|
PAGECACHE_TAG_TOWRITE, &fbatch)) != 0) {
|
||||||
|
|
||||||
|
/* Loop over each page and write it out. */
|
||||||
|
struct folio *folio;
|
||||||
|
while ((folio = folio_batch_next(&fbatch)) != NULL) {
|
||||||
|
folio_lock(folio);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the folio has been remapped, or is no longer
|
||||||
|
* dirty, then there's nothing to do.
|
||||||
|
*/
|
||||||
|
if (folio->mapping != mapping ||
|
||||||
|
!folio_test_dirty(folio)) {
|
||||||
|
folio_unlock(folio);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If writeback is already in progress, wait for it to
|
||||||
|
* finish. We continue after this even if the page
|
||||||
|
* ends up clean; zfs_putpage() will skip it if no
|
||||||
|
* further work is required.
|
||||||
|
*/
|
||||||
|
while (folio_test_writeback(folio))
|
||||||
|
folio_wait_bit(folio, PG_writeback);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write it out and collect any error. zfs_putpage()
|
||||||
|
* will clear the TOWRITE and DIRTY flags, and return
|
||||||
|
* with the page unlocked.
|
||||||
|
*/
|
||||||
|
int ferr = zpl_putpage(&folio->page, wbc, data);
|
||||||
|
if (err == 0 && ferr != 0)
|
||||||
|
err = ferr;
|
||||||
|
|
||||||
|
/* Housekeeping for the caller. */
|
||||||
|
wbc->nr_to_write -= folio_nr_pages(folio);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release any remaining references on the batch. */
|
||||||
|
folio_batch_release(&fbatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int
|
static int
|
||||||
zpl_writepages(struct address_space *mapping, struct writeback_control *wbc)
|
zpl_writepages(struct address_space *mapping, struct writeback_control *wbc)
|
||||||
|
|||||||
@@ -22,6 +22,8 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2011, Lawrence Livermore National Security, LLC.
|
* Copyright (c) 2011, Lawrence Livermore National Security, LLC.
|
||||||
* Copyright (c) 2023, Datto Inc. All rights reserved.
|
* Copyright (c) 2023, Datto Inc. All rights reserved.
|
||||||
|
* Copyright (c) 2025, Klara, Inc.
|
||||||
|
* Copyright (c) 2025, Rob Norris <robn@despairlabs.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@@ -32,7 +34,22 @@
|
|||||||
#include <sys/zpl.h>
|
#include <sys/zpl.h>
|
||||||
#include <linux/iversion.h>
|
#include <linux/iversion.h>
|
||||||
#include <linux/version.h>
|
#include <linux/version.h>
|
||||||
|
#include <linux/vfs_compat.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* What to do when the last reference to an inode is released. If 0, the kernel
|
||||||
|
* will cache it on the superblock. If 1, the inode will be freed immediately.
|
||||||
|
* See zpl_drop_inode().
|
||||||
|
*/
|
||||||
|
int zfs_delete_inode = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* What to do when the last reference to a dentry is released. If 0, the kernel
|
||||||
|
* will cache it until the entry (file) is destroyed. If 1, the dentry will be
|
||||||
|
* marked for cleanup, at which time its inode reference will be released. See
|
||||||
|
* zpl_dentry_delete().
|
||||||
|
*/
|
||||||
|
int zfs_delete_dentry = 0;
|
||||||
|
|
||||||
static struct inode *
|
static struct inode *
|
||||||
zpl_inode_alloc(struct super_block *sb)
|
zpl_inode_alloc(struct super_block *sb)
|
||||||
@@ -77,11 +94,36 @@ zpl_dirty_inode(struct inode *ip, int flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When ->drop_inode() is called its return value indicates if the
|
* ->drop_inode() is called when the last reference to an inode is released.
|
||||||
* inode should be evicted from the inode cache. If the inode is
|
* Its return value indicates if the inode should be destroyed immediately, or
|
||||||
* unhashed and has no links the default policy is to evict it
|
* cached on the superblock structure.
|
||||||
* immediately.
|
|
||||||
*
|
*
|
||||||
|
* By default (zfs_delete_inode=0), we call generic_drop_inode(), which returns
|
||||||
|
* "destroy immediately" if the inode is unhashed and has no links (roughly: no
|
||||||
|
* longer exists on disk). On datasets with millions of rarely-accessed files,
|
||||||
|
* this can cause a large amount of memory to be "pinned" by cached inodes,
|
||||||
|
* which in turn pin their associated dnodes and dbufs, until the kernel starts
|
||||||
|
* reporting memory pressure and requests OpenZFS release some memory (see
|
||||||
|
* zfs_prune()).
|
||||||
|
*
|
||||||
|
* When set to 1, we call generic_delete_inode(), which always returns "destroy
|
||||||
|
* immediately", resulting in inodes being destroyed immediately, releasing
|
||||||
|
* their associated dnodes and dbufs to the dbuf cached and the ARC to be
|
||||||
|
* evicted as normal.
|
||||||
|
*
|
||||||
|
* Note that the "last reference" doesn't always mean the last _userspace_
|
||||||
|
* reference; the dentry cache also holds a reference, so "busy" inodes will
|
||||||
|
* still be kept alive that way (subject to dcache tuning).
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
zpl_drop_inode(struct inode *ip)
|
||||||
|
{
|
||||||
|
if (zfs_delete_inode)
|
||||||
|
return (generic_delete_inode(ip));
|
||||||
|
return (generic_drop_inode(ip));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
* The ->evict_inode() callback must minimally truncate the inode pages,
|
* The ->evict_inode() callback must minimally truncate the inode pages,
|
||||||
* and call clear_inode(). For 2.6.35 and later kernels this will
|
* and call clear_inode(). For 2.6.35 and later kernels this will
|
||||||
* simply update the inode state, with the sync occurring before the
|
* simply update the inode state, with the sync occurring before the
|
||||||
@@ -470,6 +512,7 @@ const struct super_operations zpl_super_operations = {
|
|||||||
.destroy_inode = zpl_inode_destroy,
|
.destroy_inode = zpl_inode_destroy,
|
||||||
.dirty_inode = zpl_dirty_inode,
|
.dirty_inode = zpl_dirty_inode,
|
||||||
.write_inode = NULL,
|
.write_inode = NULL,
|
||||||
|
.drop_inode = zpl_drop_inode,
|
||||||
.evict_inode = zpl_evict_inode,
|
.evict_inode = zpl_evict_inode,
|
||||||
.put_super = zpl_put_super,
|
.put_super = zpl_put_super,
|
||||||
.sync_fs = zpl_sync_fs,
|
.sync_fs = zpl_sync_fs,
|
||||||
@@ -480,6 +523,35 @@ const struct super_operations zpl_super_operations = {
|
|||||||
.show_stats = NULL,
|
.show_stats = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ->d_delete() is called when the last reference to a dentry is released. Its
|
||||||
|
* return value indicates if the dentry should be destroyed immediately, or
|
||||||
|
* retained in the dentry cache.
|
||||||
|
*
|
||||||
|
* By default (zfs_delete_dentry=0) the kernel will always cache unused
|
||||||
|
* entries. Each dentry holds an inode reference, so cached dentries can hold
|
||||||
|
* the final inode reference indefinitely, leading to the inode and its related
|
||||||
|
* data being pinned (see zpl_drop_inode()).
|
||||||
|
*
|
||||||
|
* When set to 1, we signal that the dentry should be destroyed immediately and
|
||||||
|
* never cached. This reduces memory usage, at the cost of higher overheads to
|
||||||
|
* lookup a file, as the inode and its underlying data (dnode/dbuf) need to be
|
||||||
|
* reloaded and reinflated.
|
||||||
|
*
|
||||||
|
* Note that userspace does not have direct control over dentry references and
|
||||||
|
* reclaim; rather, this is part of the kernel's caching and reclaim subsystems
|
||||||
|
* (eg vm.vfs_cache_pressure).
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
zpl_dentry_delete(const struct dentry *dentry)
|
||||||
|
{
|
||||||
|
return (zfs_delete_dentry ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct dentry_operations zpl_dentry_operations = {
|
||||||
|
.d_delete = zpl_dentry_delete,
|
||||||
|
};
|
||||||
|
|
||||||
struct file_system_type zpl_fs_type = {
|
struct file_system_type zpl_fs_type = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.name = ZFS_DRIVER,
|
.name = ZFS_DRIVER,
|
||||||
@@ -491,3 +563,10 @@ struct file_system_type zpl_fs_type = {
|
|||||||
.mount = zpl_mount,
|
.mount = zpl_mount,
|
||||||
.kill_sb = zpl_kill_sb,
|
.kill_sb = zpl_kill_sb,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ZFS_MODULE_PARAM(zfs, zfs_, delete_inode, INT, ZMOD_RW,
|
||||||
|
"Delete inodes as soon as the last reference is released.");
|
||||||
|
|
||||||
|
ZFS_MODULE_PARAM(zfs, zfs_, delete_dentry, INT, ZMOD_RW,
|
||||||
|
"Delete dentries from dentry cache as soon as the last reference is "
|
||||||
|
"released.");
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012, 2020 by Delphix. All rights reserved.
|
* Copyright (c) 2012, 2020 by Delphix. All rights reserved.
|
||||||
* Copyright (c) 2024, Rob Norris <robn@despairlabs.com>
|
* Copyright (c) 2024, 2025, Rob Norris <robn@despairlabs.com>
|
||||||
* Copyright (c) 2024, Klara, Inc.
|
* Copyright (c) 2024, Klara, Inc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -1066,12 +1066,13 @@ zvol_os_clear_private(zvol_state_t *zv)
|
|||||||
* tiny devices. For devices over 1 Mib a standard head and sector count
|
* tiny devices. For devices over 1 Mib a standard head and sector count
|
||||||
* is used to keep the cylinders count reasonable.
|
* is used to keep the cylinders count reasonable.
|
||||||
*/
|
*/
|
||||||
static int
|
static inline int
|
||||||
zvol_getgeo(struct block_device *bdev, struct hd_geometry *geo)
|
zvol_getgeo_impl(struct gendisk *disk, struct hd_geometry *geo)
|
||||||
{
|
{
|
||||||
zvol_state_t *zv = bdev->bd_disk->private_data;
|
zvol_state_t *zv = disk->private_data;
|
||||||
sector_t sectors;
|
sector_t sectors;
|
||||||
|
|
||||||
|
ASSERT3P(zv, !=, NULL);
|
||||||
ASSERT3U(zv->zv_open_count, >, 0);
|
ASSERT3U(zv->zv_open_count, >, 0);
|
||||||
|
|
||||||
sectors = get_capacity(zv->zv_zso->zvo_disk);
|
sectors = get_capacity(zv->zv_zso->zvo_disk);
|
||||||
@@ -1090,6 +1091,20 @@ zvol_getgeo(struct block_device *bdev, struct hd_geometry *geo)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_BLOCK_DEVICE_OPERATIONS_GETGEO_GENDISK
|
||||||
|
static int
|
||||||
|
zvol_getgeo(struct gendisk *disk, struct hd_geometry *geo)
|
||||||
|
{
|
||||||
|
return (zvol_getgeo_impl(disk, geo));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static int
|
||||||
|
zvol_getgeo(struct block_device *bdev, struct hd_geometry *geo)
|
||||||
|
{
|
||||||
|
return (zvol_getgeo_impl(bdev->bd_disk, geo));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Why have two separate block_device_operations structs?
|
* Why have two separate block_device_operations structs?
|
||||||
*
|
*
|
||||||
@@ -1531,7 +1546,7 @@ zvol_os_free(zvol_state_t *zv)
|
|||||||
if (zv->zv_zso->use_blk_mq)
|
if (zv->zv_zso->use_blk_mq)
|
||||||
blk_mq_free_tag_set(&zv->zv_zso->tag_set);
|
blk_mq_free_tag_set(&zv->zv_zso->tag_set);
|
||||||
|
|
||||||
ida_simple_remove(&zvol_ida,
|
ida_free(&zvol_ida,
|
||||||
MINOR(zv->zv_zso->zvo_dev) >> ZVOL_MINOR_BITS);
|
MINOR(zv->zv_zso->zvo_dev) >> ZVOL_MINOR_BITS);
|
||||||
|
|
||||||
cv_destroy(&zv->zv_removing_cv);
|
cv_destroy(&zv->zv_removing_cv);
|
||||||
@@ -1665,7 +1680,7 @@ zvol_os_create_minor(const char *name)
|
|||||||
if (zvol_inhibit_dev)
|
if (zvol_inhibit_dev)
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
idx = ida_simple_get(&zvol_ida, 0, 0, kmem_flags_convert(KM_SLEEP));
|
idx = ida_alloc(&zvol_ida, kmem_flags_convert(KM_SLEEP));
|
||||||
if (idx < 0)
|
if (idx < 0)
|
||||||
return (SET_ERROR(-idx));
|
return (SET_ERROR(-idx));
|
||||||
minor = idx << ZVOL_MINOR_BITS;
|
minor = idx << ZVOL_MINOR_BITS;
|
||||||
@@ -1673,7 +1688,7 @@ zvol_os_create_minor(const char *name)
|
|||||||
/* too many partitions can cause an overflow */
|
/* too many partitions can cause an overflow */
|
||||||
zfs_dbgmsg("zvol: create minor overflow: %s, minor %u/%u",
|
zfs_dbgmsg("zvol: create minor overflow: %s, minor %u/%u",
|
||||||
name, minor, MINOR(minor));
|
name, minor, MINOR(minor));
|
||||||
ida_simple_remove(&zvol_ida, idx);
|
ida_free(&zvol_ida, idx);
|
||||||
return (SET_ERROR(EINVAL));
|
return (SET_ERROR(EINVAL));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1681,7 +1696,7 @@ zvol_os_create_minor(const char *name)
|
|||||||
if (zv) {
|
if (zv) {
|
||||||
ASSERT(MUTEX_HELD(&zv->zv_state_lock));
|
ASSERT(MUTEX_HELD(&zv->zv_state_lock));
|
||||||
mutex_exit(&zv->zv_state_lock);
|
mutex_exit(&zv->zv_state_lock);
|
||||||
ida_simple_remove(&zvol_ida, idx);
|
ida_free(&zvol_ida, idx);
|
||||||
return (SET_ERROR(EEXIST));
|
return (SET_ERROR(EEXIST));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1783,7 +1798,7 @@ out_doi:
|
|||||||
rw_exit(&zvol_state_lock);
|
rw_exit(&zvol_state_lock);
|
||||||
error = zvol_os_add_disk(zv->zv_zso->zvo_disk);
|
error = zvol_os_add_disk(zv->zv_zso->zvo_disk);
|
||||||
} else {
|
} else {
|
||||||
ida_simple_remove(&zvol_ida, idx);
|
ida_free(&zvol_ida, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (error);
|
return (error);
|
||||||
|
|||||||
+8
-8
@@ -1111,13 +1111,6 @@ abd_raidz_gen_iterate(abd_t **cabds, abd_t *dabd, size_t off,
|
|||||||
|
|
||||||
func_raidz_gen(caddrs, daddr, len, dlen);
|
func_raidz_gen(caddrs, daddr, len, dlen);
|
||||||
|
|
||||||
for (i = parity-1; i >= 0; i--) {
|
|
||||||
abd_iter_unmap(&caiters[i]);
|
|
||||||
c_cabds[i] =
|
|
||||||
abd_advance_abd_iter(cabds[i], c_cabds[i],
|
|
||||||
&caiters[i], len);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dsize > 0) {
|
if (dsize > 0) {
|
||||||
abd_iter_unmap(&daiter);
|
abd_iter_unmap(&daiter);
|
||||||
c_dabd =
|
c_dabd =
|
||||||
@@ -1126,6 +1119,13 @@ abd_raidz_gen_iterate(abd_t **cabds, abd_t *dabd, size_t off,
|
|||||||
dsize -= dlen;
|
dsize -= dlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i = parity - 1; i >= 0; i--) {
|
||||||
|
abd_iter_unmap(&caiters[i]);
|
||||||
|
c_cabds[i] =
|
||||||
|
abd_advance_abd_iter(cabds[i], c_cabds[i],
|
||||||
|
&caiters[i], len);
|
||||||
|
}
|
||||||
|
|
||||||
csize -= len;
|
csize -= len;
|
||||||
}
|
}
|
||||||
abd_exit_critical(flags);
|
abd_exit_critical(flags);
|
||||||
@@ -1194,7 +1194,7 @@ abd_raidz_rec_iterate(abd_t **cabds, abd_t **tabds,
|
|||||||
|
|
||||||
func_raidz_rec(xaddrs, len, caddrs, mul);
|
func_raidz_rec(xaddrs, len, caddrs, mul);
|
||||||
|
|
||||||
for (i = parity-1; i >= 0; i--) {
|
for (i = parity - 1; i >= 0; i--) {
|
||||||
abd_iter_unmap(&xiters[i]);
|
abd_iter_unmap(&xiters[i]);
|
||||||
abd_iter_unmap(&citers[i]);
|
abd_iter_unmap(&citers[i]);
|
||||||
c_tabds[i] =
|
c_tabds[i] =
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ dataset_kstats_rename(dataset_kstats_t *dk, const char *name)
|
|||||||
char *ds_name;
|
char *ds_name;
|
||||||
|
|
||||||
ds_name = KSTAT_NAMED_STR_PTR(&dkv->dkv_ds_name);
|
ds_name = KSTAT_NAMED_STR_PTR(&dkv->dkv_ds_name);
|
||||||
ASSERT3S(ds_name, !=, NULL);
|
ASSERT3P(ds_name, !=, NULL);
|
||||||
(void) strlcpy(ds_name, name,
|
(void) strlcpy(ds_name, name,
|
||||||
KSTAT_NAMED_STR_BUFLEN(&dkv->dkv_ds_name));
|
KSTAT_NAMED_STR_BUFLEN(&dkv->dkv_ds_name));
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1508,7 +1508,7 @@ ddt_configure(ddt_t *ddt, boolean_t new)
|
|||||||
DMU_POOL_DIRECTORY_OBJECT, name, sizeof (uint64_t), 1,
|
DMU_POOL_DIRECTORY_OBJECT, name, sizeof (uint64_t), 1,
|
||||||
&ddt->ddt_dir_object);
|
&ddt->ddt_dir_object);
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
ASSERT3U(spa->spa_meta_objset, ==, ddt->ddt_os);
|
ASSERT3P(spa->spa_meta_objset, ==, ddt->ddt_os);
|
||||||
|
|
||||||
error = zap_lookup(ddt->ddt_os, ddt->ddt_dir_object,
|
error = zap_lookup(ddt->ddt_os, ddt->ddt_dir_object,
|
||||||
DDT_DIR_VERSION, sizeof (uint64_t), 1,
|
DDT_DIR_VERSION, sizeof (uint64_t), 1,
|
||||||
|
|||||||
@@ -262,7 +262,7 @@ ddt_log_update_entry(ddt_t *ddt, ddt_log_t *ddl, ddt_lightweight_entry_t *ddlwe)
|
|||||||
void
|
void
|
||||||
ddt_log_entry(ddt_t *ddt, ddt_lightweight_entry_t *ddlwe, ddt_log_update_t *dlu)
|
ddt_log_entry(ddt_t *ddt, ddt_lightweight_entry_t *ddlwe, ddt_log_update_t *dlu)
|
||||||
{
|
{
|
||||||
ASSERT3U(dlu->dlu_dbp, !=, NULL);
|
ASSERT3P(dlu->dlu_dbp, !=, NULL);
|
||||||
|
|
||||||
ddt_log_update_entry(ddt, ddt->ddt_log_active, ddlwe);
|
ddt_log_update_entry(ddt, ddt->ddt_log_active, ddlwe);
|
||||||
ddt_histogram_add_entry(ddt, &ddt->ddt_log_histogram, ddlwe);
|
ddt_histogram_add_entry(ddt, &ddt->ddt_log_histogram, ddlwe);
|
||||||
@@ -312,7 +312,7 @@ ddt_log_entry(ddt_t *ddt, ddt_lightweight_entry_t *ddlwe, ddt_log_update_t *dlu)
|
|||||||
void
|
void
|
||||||
ddt_log_commit(ddt_t *ddt, ddt_log_update_t *dlu)
|
ddt_log_commit(ddt_t *ddt, ddt_log_update_t *dlu)
|
||||||
{
|
{
|
||||||
ASSERT3U(dlu->dlu_dbp, !=, NULL);
|
ASSERT3P(dlu->dlu_dbp, !=, NULL);
|
||||||
ASSERT3U(dlu->dlu_block+1, ==, dlu->dlu_ndbp);
|
ASSERT3U(dlu->dlu_block+1, ==, dlu->dlu_ndbp);
|
||||||
ASSERT3U(dlu->dlu_offset, >, 0);
|
ASSERT3U(dlu->dlu_offset, >, 0);
|
||||||
|
|
||||||
|
|||||||
+135
-23
@@ -145,6 +145,15 @@
|
|||||||
* Additionally, the duration is then extended by a random 25% to attempt to to
|
* Additionally, the duration is then extended by a random 25% to attempt to to
|
||||||
* detect simultaneous imports. For example, if both partner hosts are rebooted
|
* detect simultaneous imports. For example, if both partner hosts are rebooted
|
||||||
* at the same time and automatically attempt to import the pool.
|
* at the same time and automatically attempt to import the pool.
|
||||||
|
*
|
||||||
|
* Once the read-only activity check completes and the pool is determined to
|
||||||
|
* be inactive a second check is performed to claim the pool. During this
|
||||||
|
* phase the host writes out MMP uberblocks to each of the devices which are
|
||||||
|
* identical to the best uberblock but with a randomly selected sequence id.
|
||||||
|
* The "best" uberblock is then read back and it must contain this new sequence
|
||||||
|
* number. This check is performed multiple times to ensure that there is
|
||||||
|
* no window where a concurrently importing system can incorrectly determine
|
||||||
|
* the pool to be inactive.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -237,8 +246,8 @@ mmp_thread_start(spa_t *spa)
|
|||||||
if (!mmp->mmp_thread) {
|
if (!mmp->mmp_thread) {
|
||||||
mmp->mmp_thread = thread_create(NULL, 0, mmp_thread,
|
mmp->mmp_thread = thread_create(NULL, 0, mmp_thread,
|
||||||
spa, 0, &p0, TS_RUN, defclsyspri);
|
spa, 0, &p0, TS_RUN, defclsyspri);
|
||||||
zfs_dbgmsg("MMP thread started pool '%s' "
|
zfs_dbgmsg("mmp: mmp thread started spa=%s "
|
||||||
"gethrtime %llu", spa_name(spa), gethrtime());
|
"gethrtime=%llu", spa_name(spa), gethrtime());
|
||||||
}
|
}
|
||||||
mutex_exit(&mmp->mmp_thread_lock);
|
mutex_exit(&mmp->mmp_thread_lock);
|
||||||
}
|
}
|
||||||
@@ -257,7 +266,7 @@ mmp_thread_stop(spa_t *spa)
|
|||||||
cv_wait(&mmp->mmp_thread_cv, &mmp->mmp_thread_lock);
|
cv_wait(&mmp->mmp_thread_cv, &mmp->mmp_thread_lock);
|
||||||
}
|
}
|
||||||
mutex_exit(&mmp->mmp_thread_lock);
|
mutex_exit(&mmp->mmp_thread_lock);
|
||||||
zfs_dbgmsg("MMP thread stopped pool '%s' gethrtime %llu",
|
zfs_dbgmsg("mmp: mmp thread stopped spa=%s gethrtime=%llu",
|
||||||
spa_name(spa), gethrtime());
|
spa_name(spa), gethrtime());
|
||||||
|
|
||||||
ASSERT(mmp->mmp_thread == NULL);
|
ASSERT(mmp->mmp_thread == NULL);
|
||||||
@@ -449,9 +458,9 @@ mmp_write_uberblock(spa_t *spa)
|
|||||||
spa_config_enter_mmp(spa, SCL_STATE, mmp_tag, RW_READER);
|
spa_config_enter_mmp(spa, SCL_STATE, mmp_tag, RW_READER);
|
||||||
lock_acquire_time = gethrtime() - lock_acquire_time;
|
lock_acquire_time = gethrtime() - lock_acquire_time;
|
||||||
if (lock_acquire_time > (MSEC2NSEC(MMP_MIN_INTERVAL) / 10))
|
if (lock_acquire_time > (MSEC2NSEC(MMP_MIN_INTERVAL) / 10))
|
||||||
zfs_dbgmsg("MMP SCL_STATE acquisition pool '%s' took %llu ns "
|
zfs_dbgmsg("mmp: long SCL_STATE acquisition, spa=%s "
|
||||||
"gethrtime %llu", spa_name(spa), lock_acquire_time,
|
"acquire_time=%llu gethrtime=%llu", spa_name(spa),
|
||||||
gethrtime());
|
lock_acquire_time, gethrtime());
|
||||||
|
|
||||||
mutex_enter(&mmp->mmp_io_lock);
|
mutex_enter(&mmp->mmp_io_lock);
|
||||||
|
|
||||||
@@ -474,8 +483,8 @@ mmp_write_uberblock(spa_t *spa)
|
|||||||
spa_mmp_history_add(spa, mmp->mmp_ub.ub_txg,
|
spa_mmp_history_add(spa, mmp->mmp_ub.ub_txg,
|
||||||
gethrestime_sec(), mmp->mmp_delay, NULL, 0,
|
gethrestime_sec(), mmp->mmp_delay, NULL, 0,
|
||||||
mmp->mmp_kstat_id++, error);
|
mmp->mmp_kstat_id++, error);
|
||||||
zfs_dbgmsg("MMP error choosing leaf pool '%s' "
|
zfs_dbgmsg("mmp: error choosing leaf, spa=%s "
|
||||||
"gethrtime %llu fail_mask %#x", spa_name(spa),
|
"gethrtime=%llu fail_mask=%#x", spa_name(spa),
|
||||||
gethrtime(), error);
|
gethrtime(), error);
|
||||||
}
|
}
|
||||||
mutex_exit(&mmp->mmp_io_lock);
|
mutex_exit(&mmp->mmp_io_lock);
|
||||||
@@ -485,11 +494,11 @@ mmp_write_uberblock(spa_t *spa)
|
|||||||
|
|
||||||
vd = spa->spa_mmp.mmp_last_leaf;
|
vd = spa->spa_mmp.mmp_last_leaf;
|
||||||
if (mmp->mmp_skip_error != 0) {
|
if (mmp->mmp_skip_error != 0) {
|
||||||
mmp->mmp_skip_error = 0;
|
zfs_dbgmsg("mmp: write after skipping due to unavailable "
|
||||||
zfs_dbgmsg("MMP write after skipping due to unavailable "
|
"leaves, spa=%s gethrtime=%llu vdev=%llu error=%d",
|
||||||
"leaves, pool '%s' gethrtime %llu leaf %llu",
|
|
||||||
spa_name(spa), (u_longlong_t)gethrtime(),
|
spa_name(spa), (u_longlong_t)gethrtime(),
|
||||||
(u_longlong_t)vd->vdev_guid);
|
(u_longlong_t)vd->vdev_guid, mmp->mmp_skip_error);
|
||||||
|
mmp->mmp_skip_error = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mmp->mmp_zio_root == NULL)
|
if (mmp->mmp_zio_root == NULL)
|
||||||
@@ -540,6 +549,108 @@ mmp_write_uberblock(spa_t *spa)
|
|||||||
zio_nowait(zio);
|
zio_nowait(zio);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mmp_claim_uberblock_sync_done(zio_t *zio)
|
||||||
|
{
|
||||||
|
uint64_t *good_writes = zio->io_private;
|
||||||
|
|
||||||
|
if (zio->io_error == 0 && zio->io_vd->vdev_top->vdev_ms_array != 0)
|
||||||
|
atomic_inc_64(good_writes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the uberblock to the first label of all leaves of the specified vdev.
|
||||||
|
* Two writes required for each mirror, one for a singleton, and parity+1 for
|
||||||
|
* raidz or draid vdevs.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
mmp_claim_uberblock_sync(zio_t *zio, uint64_t *good_writes,
|
||||||
|
uint64_t *req_writes, uberblock_t *ub, vdev_t *vd, int flags)
|
||||||
|
{
|
||||||
|
for (uint64_t c = 0; c < vd->vdev_children; c++) {
|
||||||
|
vdev_t *cvd = vd->vdev_child[c];
|
||||||
|
|
||||||
|
if (cvd->vdev_islog || cvd->vdev_isspare || cvd->vdev_isl2cache)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (cvd->vdev_top == cvd) {
|
||||||
|
uint64_t nparity = vdev_get_nparity(cvd);
|
||||||
|
if (nparity) {
|
||||||
|
*req_writes += nparity + 1;
|
||||||
|
} else {
|
||||||
|
*req_writes +=
|
||||||
|
MIN(MAX(cvd->vdev_children, 1), 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mmp_claim_uberblock_sync(zio, good_writes, req_writes,
|
||||||
|
ub, cvd, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vd->vdev_ops->vdev_op_leaf)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!vdev_writeable(vd))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (vd->vdev_ops == &vdev_draid_spare_ops)
|
||||||
|
return;
|
||||||
|
|
||||||
|
abd_t *ub_abd = abd_alloc_for_io(VDEV_UBERBLOCK_SIZE(vd), B_TRUE);
|
||||||
|
abd_copy_from_buf(ub_abd, ub, sizeof (uberblock_t));
|
||||||
|
abd_zero_off(ub_abd, sizeof (uberblock_t),
|
||||||
|
VDEV_UBERBLOCK_SIZE(vd) - sizeof (uberblock_t));
|
||||||
|
|
||||||
|
vdev_label_write(zio, vd, 0, ub_abd,
|
||||||
|
VDEV_UBERBLOCK_OFFSET(vd, VDEV_UBERBLOCK_COUNT(vd) -
|
||||||
|
MMP_BLOCKS_PER_LABEL), VDEV_UBERBLOCK_SIZE(vd),
|
||||||
|
mmp_claim_uberblock_sync_done, good_writes,
|
||||||
|
flags | ZIO_FLAG_DONT_PROPAGATE);
|
||||||
|
|
||||||
|
abd_free(ub_abd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
mmp_claim_uberblock(spa_t *spa, vdev_t *vd, uberblock_t *ub)
|
||||||
|
{
|
||||||
|
int flags = ZIO_FLAG_CONFIG_WRITER | ZIO_FLAG_CANFAIL;
|
||||||
|
uint64_t good_writes = 0;
|
||||||
|
uint64_t req_writes = 0;
|
||||||
|
zio_t *zio;
|
||||||
|
|
||||||
|
ASSERT(MMP_VALID(ub));
|
||||||
|
ASSERT(MMP_SEQ_VALID(ub));
|
||||||
|
|
||||||
|
spa_config_enter(spa, SCL_ALL, mmp_tag, RW_WRITER);
|
||||||
|
|
||||||
|
/* Sync the uberblock to all writeable leaves */
|
||||||
|
zio = zio_root(spa, NULL, NULL, flags);
|
||||||
|
mmp_claim_uberblock_sync(zio, &good_writes, &req_writes, ub, vd, flags);
|
||||||
|
(void) zio_wait(zio);
|
||||||
|
|
||||||
|
/* Flush the new uberblocks so they're immediately visible */
|
||||||
|
zio = zio_root(spa, NULL, NULL, flags);
|
||||||
|
zio_flush(zio, vd);
|
||||||
|
(void) zio_wait(zio);
|
||||||
|
|
||||||
|
spa_config_exit(spa, SCL_ALL, mmp_tag);
|
||||||
|
|
||||||
|
zfs_dbgmsg("mmp: claiming uberblock, spa=%s txg=%llu seq=%llu "
|
||||||
|
"req_writes=%llu good_writes=%llu", spa_load_name(spa),
|
||||||
|
(u_longlong_t)ub->ub_txg, (u_longlong_t)MMP_SEQ(ub),
|
||||||
|
(u_longlong_t)req_writes, (u_longlong_t)good_writes);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* To guarantee visibility from a remote host we require a minimum
|
||||||
|
* number of good writes. For raidz/draid vdevs parity+1 writes, for
|
||||||
|
* mirrors 2 writes, and for singletons 1 write.
|
||||||
|
*/
|
||||||
|
if (req_writes == 0 || good_writes < req_writes)
|
||||||
|
return (SET_ERROR(EIO));
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
static __attribute__((noreturn)) void
|
static __attribute__((noreturn)) void
|
||||||
mmp_thread(void *arg)
|
mmp_thread(void *arg)
|
||||||
{
|
{
|
||||||
@@ -616,11 +727,11 @@ mmp_thread(void *arg)
|
|||||||
next_time = gethrtime() + mmp_interval / leaves;
|
next_time = gethrtime() + mmp_interval / leaves;
|
||||||
|
|
||||||
if (mmp_fail_ns != last_mmp_fail_ns) {
|
if (mmp_fail_ns != last_mmp_fail_ns) {
|
||||||
zfs_dbgmsg("MMP interval change pool '%s' "
|
zfs_dbgmsg("mmp: interval change, spa=%s "
|
||||||
"gethrtime %llu last_mmp_interval %llu "
|
"gethrtime=%llu last_mmp_interval=%llu "
|
||||||
"mmp_interval %llu last_mmp_fail_intervals %u "
|
"mmp_interval=%llu last_mmp_fail_intervals=%u "
|
||||||
"mmp_fail_intervals %u mmp_fail_ns %llu "
|
"mmp_fail_intervals=%u mmp_fail_ns=%llu "
|
||||||
"skip_wait %d leaves %d next_time %llu",
|
"skip_wait=%d leaves=%d next_time=%llu",
|
||||||
spa_name(spa), (u_longlong_t)gethrtime(),
|
spa_name(spa), (u_longlong_t)gethrtime(),
|
||||||
(u_longlong_t)last_mmp_interval,
|
(u_longlong_t)last_mmp_interval,
|
||||||
(u_longlong_t)mmp_interval, last_mmp_fail_intervals,
|
(u_longlong_t)mmp_interval, last_mmp_fail_intervals,
|
||||||
@@ -635,9 +746,9 @@ mmp_thread(void *arg)
|
|||||||
*/
|
*/
|
||||||
if ((!last_spa_multihost && multihost) ||
|
if ((!last_spa_multihost && multihost) ||
|
||||||
(last_spa_suspended && !suspended)) {
|
(last_spa_suspended && !suspended)) {
|
||||||
zfs_dbgmsg("MMP state change pool '%s': gethrtime %llu "
|
zfs_dbgmsg("mmp: state change spa=%s: gethrtime=%llu "
|
||||||
"last_spa_multihost %u multihost %u "
|
"last_spa_multihost=%u multihost=%u "
|
||||||
"last_spa_suspended %u suspended %u",
|
"last_spa_suspended=%u suspended=%u",
|
||||||
spa_name(spa), (u_longlong_t)gethrtime(),
|
spa_name(spa), (u_longlong_t)gethrtime(),
|
||||||
last_spa_multihost, multihost, last_spa_suspended,
|
last_spa_multihost, multihost, last_spa_suspended,
|
||||||
suspended);
|
suspended);
|
||||||
@@ -663,9 +774,10 @@ mmp_thread(void *arg)
|
|||||||
*/
|
*/
|
||||||
if (multihost && !suspended && mmp_fail_intervals &&
|
if (multihost && !suspended && mmp_fail_intervals &&
|
||||||
(gethrtime() - mmp->mmp_last_write) > mmp_fail_ns) {
|
(gethrtime() - mmp->mmp_last_write) > mmp_fail_ns) {
|
||||||
zfs_dbgmsg("MMP suspending pool '%s': gethrtime %llu "
|
zfs_dbgmsg("mmp: suspending pool, spa=%s "
|
||||||
"mmp_last_write %llu mmp_interval %llu "
|
"gethrtime=%llu mmp_last_write=%llu "
|
||||||
"mmp_fail_intervals %llu mmp_fail_ns %llu txg %llu",
|
"mmp_interval=%llu mmp_fail_intervals=%llu "
|
||||||
|
"mmp_fail_ns=%llu txg=%llu",
|
||||||
spa_name(spa), (u_longlong_t)gethrtime(),
|
spa_name(spa), (u_longlong_t)gethrtime(),
|
||||||
(u_longlong_t)mmp->mmp_last_write,
|
(u_longlong_t)mmp->mmp_last_write,
|
||||||
(u_longlong_t)mmp_interval,
|
(u_longlong_t)mmp_interval,
|
||||||
|
|||||||
+658
-193
File diff suppressed because it is too large
Load Diff
+21
-4
@@ -413,7 +413,7 @@ spa_load_failed(spa_t *spa, const char *fmt, ...)
|
|||||||
(void) vsnprintf(buf, sizeof (buf), fmt, adx);
|
(void) vsnprintf(buf, sizeof (buf), fmt, adx);
|
||||||
va_end(adx);
|
va_end(adx);
|
||||||
|
|
||||||
zfs_dbgmsg("spa_load(%s, config %s): FAILED: %s", spa->spa_name,
|
zfs_dbgmsg("spa_load(%s, config %s): FAILED: %s", spa_load_name(spa),
|
||||||
spa->spa_trust_config ? "trusted" : "untrusted", buf);
|
spa->spa_trust_config ? "trusted" : "untrusted", buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -427,7 +427,7 @@ spa_load_note(spa_t *spa, const char *fmt, ...)
|
|||||||
(void) vsnprintf(buf, sizeof (buf), fmt, adx);
|
(void) vsnprintf(buf, sizeof (buf), fmt, adx);
|
||||||
va_end(adx);
|
va_end(adx);
|
||||||
|
|
||||||
zfs_dbgmsg("spa_load(%s, config %s): %s", spa->spa_name,
|
zfs_dbgmsg("spa_load(%s, config %s): %s", spa_load_name(spa),
|
||||||
spa->spa_trust_config ? "trusted" : "untrusted", buf);
|
spa->spa_trust_config ? "trusted" : "untrusted", buf);
|
||||||
|
|
||||||
spa_import_progress_set_notes_nolog(spa, "%s", buf);
|
spa_import_progress_set_notes_nolog(spa, "%s", buf);
|
||||||
@@ -857,6 +857,9 @@ spa_remove(spa_t *spa)
|
|||||||
if (spa->spa_root)
|
if (spa->spa_root)
|
||||||
spa_strfree(spa->spa_root);
|
spa_strfree(spa->spa_root);
|
||||||
|
|
||||||
|
if (spa->spa_load_name)
|
||||||
|
spa_strfree(spa->spa_load_name);
|
||||||
|
|
||||||
while ((dp = list_remove_head(&spa->spa_config_list)) != NULL) {
|
while ((dp = list_remove_head(&spa->spa_config_list)) != NULL) {
|
||||||
if (dp->scd_path != NULL)
|
if (dp->scd_path != NULL)
|
||||||
spa_strfree(dp->scd_path);
|
spa_strfree(dp->scd_path);
|
||||||
@@ -1242,7 +1245,7 @@ spa_vdev_enter(spa_t *spa)
|
|||||||
mutex_enter(&spa->spa_vdev_top_lock);
|
mutex_enter(&spa->spa_vdev_top_lock);
|
||||||
mutex_enter(&spa_namespace_lock);
|
mutex_enter(&spa_namespace_lock);
|
||||||
|
|
||||||
ASSERT0(spa->spa_export_thread);
|
ASSERT0P(spa->spa_export_thread);
|
||||||
|
|
||||||
vdev_autotrim_stop_all(spa);
|
vdev_autotrim_stop_all(spa);
|
||||||
|
|
||||||
@@ -1261,7 +1264,7 @@ spa_vdev_detach_enter(spa_t *spa, uint64_t guid)
|
|||||||
mutex_enter(&spa->spa_vdev_top_lock);
|
mutex_enter(&spa->spa_vdev_top_lock);
|
||||||
mutex_enter(&spa_namespace_lock);
|
mutex_enter(&spa_namespace_lock);
|
||||||
|
|
||||||
ASSERT0(spa->spa_export_thread);
|
ASSERT0P(spa->spa_export_thread);
|
||||||
|
|
||||||
vdev_autotrim_stop_all(spa);
|
vdev_autotrim_stop_all(spa);
|
||||||
|
|
||||||
@@ -1777,6 +1780,19 @@ spa_name(spa_t *spa)
|
|||||||
return (spa->spa_name);
|
return (spa->spa_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
spa_load_name(spa_t *spa)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* During spa_tryimport() the pool name includes a unique prefix.
|
||||||
|
* Returns the original name which can be used for log messages.
|
||||||
|
*/
|
||||||
|
if (spa->spa_load_name)
|
||||||
|
return (spa->spa_load_name);
|
||||||
|
|
||||||
|
return (spa->spa_name);
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t
|
uint64_t
|
||||||
spa_guid(spa_t *spa)
|
spa_guid(spa_t *spa)
|
||||||
{
|
{
|
||||||
@@ -3089,6 +3105,7 @@ EXPORT_SYMBOL(spa_set_rootblkptr);
|
|||||||
EXPORT_SYMBOL(spa_altroot);
|
EXPORT_SYMBOL(spa_altroot);
|
||||||
EXPORT_SYMBOL(spa_sync_pass);
|
EXPORT_SYMBOL(spa_sync_pass);
|
||||||
EXPORT_SYMBOL(spa_name);
|
EXPORT_SYMBOL(spa_name);
|
||||||
|
EXPORT_SYMBOL(spa_load_name);
|
||||||
EXPORT_SYMBOL(spa_guid);
|
EXPORT_SYMBOL(spa_guid);
|
||||||
EXPORT_SYMBOL(spa_last_synced_txg);
|
EXPORT_SYMBOL(spa_last_synced_txg);
|
||||||
EXPORT_SYMBOL(spa_first_txg);
|
EXPORT_SYMBOL(spa_first_txg);
|
||||||
|
|||||||
@@ -228,7 +228,8 @@ vdev_file_io_strategy(void *arg)
|
|||||||
abd_return_buf_copy(zio->io_abd, buf, size);
|
abd_return_buf_copy(zio->io_abd, buf, size);
|
||||||
} else {
|
} else {
|
||||||
buf = abd_borrow_buf_copy(zio->io_abd, zio->io_size);
|
buf = abd_borrow_buf_copy(zio->io_abd, zio->io_size);
|
||||||
err = zfs_file_pwrite(vf->vf_file, buf, size, off, &resid);
|
err = zfs_file_pwrite(vf->vf_file, buf, size, off,
|
||||||
|
vd->vdev_ashift, &resid);
|
||||||
abd_return_buf(zio->io_abd, buf, size);
|
abd_return_buf(zio->io_abd, buf, size);
|
||||||
}
|
}
|
||||||
zio->io_error = err;
|
zio->io_error = err;
|
||||||
|
|||||||
@@ -1500,7 +1500,7 @@ retry:
|
|||||||
* conflicting uberblocks on disk with the same txg. The solution is simple:
|
* conflicting uberblocks on disk with the same txg. The solution is simple:
|
||||||
* among uberblocks with equal txg, choose the one with the latest timestamp.
|
* among uberblocks with equal txg, choose the one with the latest timestamp.
|
||||||
*/
|
*/
|
||||||
static int
|
int
|
||||||
vdev_uberblock_compare(const uberblock_t *ub1, const uberblock_t *ub2)
|
vdev_uberblock_compare(const uberblock_t *ub1, const uberblock_t *ub2)
|
||||||
{
|
{
|
||||||
int cmp = TREE_CMP(ub1->ub_txg, ub2->ub_txg);
|
int cmp = TREE_CMP(ub1->ub_txg, ub2->ub_txg);
|
||||||
@@ -1631,8 +1631,10 @@ vdev_uberblock_load(vdev_t *rvd, uberblock_t *ub, nvlist_t **config)
|
|||||||
* matches the txg for our uberblock.
|
* matches the txg for our uberblock.
|
||||||
*/
|
*/
|
||||||
if (cb.ubl_vd != NULL) {
|
if (cb.ubl_vd != NULL) {
|
||||||
vdev_dbgmsg(cb.ubl_vd, "best uberblock found for spa %s. "
|
vdev_dbgmsg(cb.ubl_vd, "best uberblock found for spa %s, "
|
||||||
"txg %llu", spa->spa_name, (u_longlong_t)ub->ub_txg);
|
"txg=%llu seq=%llu", spa_load_name(spa),
|
||||||
|
(u_longlong_t)ub->ub_txg,
|
||||||
|
(u_longlong_t)(MMP_SEQ_VALID(ub) ? MMP_SEQ(ub) : 0));
|
||||||
|
|
||||||
if (ub->ub_raidz_reflow_info !=
|
if (ub->ub_raidz_reflow_info !=
|
||||||
cb.ubl_latest.ub_raidz_reflow_info) {
|
cb.ubl_latest.ub_raidz_reflow_info) {
|
||||||
@@ -1640,7 +1642,7 @@ vdev_uberblock_load(vdev_t *rvd, uberblock_t *ub, nvlist_t **config)
|
|||||||
"spa=%s best uberblock (txg=%llu info=0x%llx) "
|
"spa=%s best uberblock (txg=%llu info=0x%llx) "
|
||||||
"has different raidz_reflow_info than latest "
|
"has different raidz_reflow_info than latest "
|
||||||
"uberblock (txg=%llu info=0x%llx)",
|
"uberblock (txg=%llu info=0x%llx)",
|
||||||
spa->spa_name,
|
spa_load_name(spa),
|
||||||
(u_longlong_t)ub->ub_txg,
|
(u_longlong_t)ub->ub_txg,
|
||||||
(u_longlong_t)ub->ub_raidz_reflow_info,
|
(u_longlong_t)ub->ub_raidz_reflow_info,
|
||||||
(u_longlong_t)cb.ubl_latest.ub_txg,
|
(u_longlong_t)cb.ubl_latest.ub_txg,
|
||||||
|
|||||||
+13
-11
@@ -155,11 +155,11 @@ chksum_run(chksum_stat_t *cs, abd_t *abd, void *ctx, int round,
|
|||||||
switch (round) {
|
switch (round) {
|
||||||
case 1: /* 1k */
|
case 1: /* 1k */
|
||||||
size = 1<<10; loops = 128; break;
|
size = 1<<10; loops = 128; break;
|
||||||
case 2: /* 2k */
|
case 2: /* 4k */
|
||||||
size = 1<<12; loops = 64; break;
|
size = 1<<12; loops = 64; break;
|
||||||
case 3: /* 4k */
|
case 3: /* 16k */
|
||||||
size = 1<<14; loops = 32; break;
|
size = 1<<14; loops = 32; break;
|
||||||
case 4: /* 16k */
|
case 4: /* 64k */
|
||||||
size = 1<<16; loops = 16; break;
|
size = 1<<16; loops = 16; break;
|
||||||
case 5: /* 256k */
|
case 5: /* 256k */
|
||||||
size = 1<<18; loops = 8; break;
|
size = 1<<18; loops = 8; break;
|
||||||
@@ -212,6 +212,7 @@ chksum_benchit(chksum_stat_t *cs)
|
|||||||
chksum_run(cs, abd, ctx, 2, &cs->bs4k);
|
chksum_run(cs, abd, ctx, 2, &cs->bs4k);
|
||||||
chksum_run(cs, abd, ctx, 3, &cs->bs16k);
|
chksum_run(cs, abd, ctx, 3, &cs->bs16k);
|
||||||
chksum_run(cs, abd, ctx, 4, &cs->bs64k);
|
chksum_run(cs, abd, ctx, 4, &cs->bs64k);
|
||||||
|
chksum_run(cs, abd, ctx, 5, &cs->bs256k);
|
||||||
chksum_run(cs, abd, ctx, 6, &cs->bs1m);
|
chksum_run(cs, abd, ctx, 6, &cs->bs1m);
|
||||||
abd_free(abd);
|
abd_free(abd);
|
||||||
|
|
||||||
@@ -249,15 +250,16 @@ chksum_benchmark(void)
|
|||||||
if (chksum_stat_limit == AT_DONE)
|
if (chksum_stat_limit == AT_DONE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
||||||
/* count implementations */
|
/* count implementations */
|
||||||
chksum_stat_cnt = 1; /* edonr */
|
if (chksum_stat_limit == AT_STARTUP) {
|
||||||
chksum_stat_cnt += 1; /* skein */
|
chksum_stat_cnt = 1; /* edonr */
|
||||||
chksum_stat_cnt += sha256->getcnt();
|
chksum_stat_cnt += 1; /* skein */
|
||||||
chksum_stat_cnt += sha512->getcnt();
|
chksum_stat_cnt += sha256->getcnt();
|
||||||
chksum_stat_cnt += blake3->getcnt();
|
chksum_stat_cnt += sha512->getcnt();
|
||||||
chksum_stat_data = kmem_zalloc(
|
chksum_stat_cnt += blake3->getcnt();
|
||||||
sizeof (chksum_stat_t) * chksum_stat_cnt, KM_SLEEP);
|
chksum_stat_data = kmem_zalloc(
|
||||||
|
sizeof (chksum_stat_t) * chksum_stat_cnt, KM_SLEEP);
|
||||||
|
}
|
||||||
|
|
||||||
/* edonr - needs to be the first one here (slow CPU check) */
|
/* edonr - needs to be the first one here (slow CPU check) */
|
||||||
cs = &chksum_stat_data[cbid++];
|
cs = &chksum_stat_data[cbid++];
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ zio_compress_data(enum zio_compress c, abd_t *src, abd_t **dst, size_t s_len,
|
|||||||
uint8_t complevel;
|
uint8_t complevel;
|
||||||
zio_compress_info_t *ci = &zio_compress_table[c];
|
zio_compress_info_t *ci = &zio_compress_table[c];
|
||||||
|
|
||||||
ASSERT3U(ci->ci_compress, !=, NULL);
|
ASSERT3P(ci->ci_compress, !=, NULL);
|
||||||
ASSERT3U(s_len, >, 0);
|
ASSERT3U(s_len, >, 0);
|
||||||
|
|
||||||
complevel = ci->ci_level;
|
complevel = ci->ci_level;
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ REF="HEAD"
|
|||||||
test_commit_bodylength()
|
test_commit_bodylength()
|
||||||
{
|
{
|
||||||
length="72"
|
length="72"
|
||||||
body=$(git log --no-show-signature -n 1 --pretty=%b "$REF" | grep -Ev "http(s)*://" | grep -E -m 1 ".{$((length + 1))}")
|
body=$(git log --no-show-signature -n 1 --pretty=%b "$REF" |
|
||||||
|
grep -Evi -e "http(s)*://" -e "signed-off-by:" -e "reviewed-by:" |
|
||||||
|
grep -E -m 1 ".{$((length + 1))}")
|
||||||
if [ -n "$body" ]; then
|
if [ -n "$body" ]; then
|
||||||
echo "error: commit message body contains line over ${length} characters"
|
echo "error: commit message body contains line over ${length} characters"
|
||||||
return 1
|
return 1
|
||||||
|
|||||||
@@ -22,10 +22,10 @@
|
|||||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
# IN THE SOFTWARE.
|
# IN THE SOFTWARE.
|
||||||
|
|
||||||
# Filter out objtools '--Werror' flag.
|
# Filter out objtools '--Werror or --werror' flag.
|
||||||
|
|
||||||
objtool="@abs_objtool_binary@"
|
objtool="@abs_objtool_binary@"
|
||||||
args=$(echo "$*" | sed s/--Werror//)
|
args=$(echo "$*" | sed 's/--Werror\|--werror//')
|
||||||
|
|
||||||
if [ -z "$objtool" ]; then
|
if [ -z "$objtool" ]; then
|
||||||
echo "$(basename "$0"): No objtool binary configured" 1>&2
|
echo "$(basename "$0"): No objtool binary configured" 1>&2
|
||||||
|
|||||||
@@ -378,7 +378,7 @@ tags = ['functional', 'cli_root', 'zfs_wait']
|
|||||||
|
|
||||||
[tests/functional/cli_root/zhack]
|
[tests/functional/cli_root/zhack]
|
||||||
tests = ['zhack_label_repair_001', 'zhack_label_repair_002',
|
tests = ['zhack_label_repair_001', 'zhack_label_repair_002',
|
||||||
'zhack_label_repair_003', 'zhack_label_repair_004']
|
'zhack_label_repair_003', 'zhack_label_repair_004', 'zhack_metaslab_leak']
|
||||||
pre =
|
pre =
|
||||||
post =
|
post =
|
||||||
tags = ['functional', 'cli_root', 'zhack']
|
tags = ['functional', 'cli_root', 'zhack']
|
||||||
|
|||||||
@@ -161,11 +161,13 @@ tags = ['functional', 'mmap']
|
|||||||
tests = ['mmp_on_thread', 'mmp_on_uberblocks', 'mmp_on_off', 'mmp_interval',
|
tests = ['mmp_on_thread', 'mmp_on_uberblocks', 'mmp_on_off', 'mmp_interval',
|
||||||
'mmp_active_import', 'mmp_inactive_import', 'mmp_exported_import',
|
'mmp_active_import', 'mmp_inactive_import', 'mmp_exported_import',
|
||||||
'mmp_write_uberblocks', 'mmp_reset_interval', 'multihost_history',
|
'mmp_write_uberblocks', 'mmp_reset_interval', 'multihost_history',
|
||||||
'mmp_on_zdb', 'mmp_write_distribution', 'mmp_hostid', 'mmp_write_slow_disk']
|
'mmp_on_zdb', 'mmp_write_distribution', 'mmp_hostid', 'mmp_write_slow_disk',
|
||||||
|
'mmp_concurrent_import']
|
||||||
tags = ['functional', 'mmp']
|
tags = ['functional', 'mmp']
|
||||||
|
timeout = 1200
|
||||||
|
|
||||||
[tests/functional/mount:Linux]
|
[tests/functional/mount:Linux]
|
||||||
tests = ['umount_unlinked_drain']
|
tests = ['umount_unlinked_drain', 'mount_loopback']
|
||||||
tags = ['functional', 'mount']
|
tags = ['functional', 'mount']
|
||||||
|
|
||||||
[tests/functional/pam:Linux]
|
[tests/functional/pam:Linux]
|
||||||
|
|||||||
@@ -247,7 +247,6 @@ maybe = {
|
|||||||
'l2arc/persist_l2arc_005_pos': ['FAIL', known_reason],
|
'l2arc/persist_l2arc_005_pos': ['FAIL', known_reason],
|
||||||
'largest_pool/largest_pool_001_pos': ['FAIL', known_reason],
|
'largest_pool/largest_pool_001_pos': ['FAIL', known_reason],
|
||||||
'mmap/mmap_sync_001_pos': ['FAIL', known_reason],
|
'mmap/mmap_sync_001_pos': ['FAIL', known_reason],
|
||||||
'mmp/mmp_on_uberblocks': ['FAIL', known_reason],
|
|
||||||
'pam/setup': ['SKIP', "pamtester might be not available"],
|
'pam/setup': ['SKIP', "pamtester might be not available"],
|
||||||
'pool_checkpoint/checkpoint_discard_busy': ['FAIL', 11946],
|
'pool_checkpoint/checkpoint_discard_busy': ['FAIL', 11946],
|
||||||
'projectquota/setup': ['SKIP', exec_reason],
|
'projectquota/setup': ['SKIP', exec_reason],
|
||||||
@@ -366,9 +365,6 @@ elif sys.platform.startswith('linux'):
|
|||||||
'io/io_uring': ['SKIP', 'io_uring support required'],
|
'io/io_uring': ['SKIP', 'io_uring support required'],
|
||||||
'limits/filesystem_limit': ['SKIP', known_reason],
|
'limits/filesystem_limit': ['SKIP', known_reason],
|
||||||
'limits/snapshot_limit': ['SKIP', known_reason],
|
'limits/snapshot_limit': ['SKIP', known_reason],
|
||||||
'mmp/mmp_active_import': ['FAIL', known_reason],
|
|
||||||
'mmp/mmp_exported_import': ['FAIL', known_reason],
|
|
||||||
'mmp/mmp_inactive_import': ['FAIL', known_reason],
|
|
||||||
'stat/statx_dioalign': ['SKIP', 'statx_reason'],
|
'stat/statx_dioalign': ['SKIP', 'statx_reason'],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ echo "================================================================="
|
|||||||
sudo tail -n $lines /proc/spl/kstat/zfs/dbgmsg
|
sudo tail -n $lines /proc/spl/kstat/zfs/dbgmsg
|
||||||
|
|
||||||
# reset dbgmsg
|
# reset dbgmsg
|
||||||
sudo bash -c "echo > /proc/spl/kstat/zfs/dbgmsg"
|
sudo sh -c "echo > /proc/spl/kstat/zfs/dbgmsg"
|
||||||
|
|
||||||
echo "================================================================="
|
echo "================================================================="
|
||||||
echo " End of zfs_dbgmsg log"
|
echo " End of zfs_dbgmsg log"
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ for f in /proc/spl/kstat/zfs/*/multihost; do
|
|||||||
echo "================================================================="
|
echo "================================================================="
|
||||||
|
|
||||||
sudo tail -n $lines $f
|
sudo tail -n $lines $f
|
||||||
sudo bash -c "echo > $f"
|
sudo sh -c "echo > $f"
|
||||||
done
|
done
|
||||||
|
|
||||||
echo "================================================================="
|
echo "================================================================="
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ export SYSTEM_FILES_COMMON='awk
|
|||||||
uniq
|
uniq
|
||||||
vmstat
|
vmstat
|
||||||
wc
|
wc
|
||||||
|
which
|
||||||
xargs
|
xargs
|
||||||
xxh128sum'
|
xxh128sum'
|
||||||
|
|
||||||
@@ -146,6 +147,7 @@ export SYSTEM_FILES_LINUX='attr
|
|||||||
lscpu
|
lscpu
|
||||||
lsmod
|
lsmod
|
||||||
lsscsi
|
lsscsi
|
||||||
|
mkfs.xfs
|
||||||
mkswap
|
mkswap
|
||||||
modprobe
|
modprobe
|
||||||
mountpoint
|
mountpoint
|
||||||
|
|||||||
@@ -559,7 +559,7 @@ function default_cleanup_noexit
|
|||||||
# Here, we loop through the pools we're allowed to
|
# Here, we loop through the pools we're allowed to
|
||||||
# destroy, only destroying them if it's safe to do
|
# destroy, only destroying them if it's safe to do
|
||||||
# so.
|
# so.
|
||||||
while [ ! -z ${ALL_POOLS} ]
|
while [ -n "${ALL_POOLS}" ]
|
||||||
do
|
do
|
||||||
for pool in ${ALL_POOLS}
|
for pool in ${ALL_POOLS}
|
||||||
do
|
do
|
||||||
@@ -3803,8 +3803,6 @@ function directory_diff # dir_a dir_b
|
|||||||
# do not match there is a "c" entry in one of the columns).
|
# do not match there is a "c" entry in one of the columns).
|
||||||
if rsync --version | grep -q "[, ] crtimes"; then
|
if rsync --version | grep -q "[, ] crtimes"; then
|
||||||
args+=("--crtimes")
|
args+=("--crtimes")
|
||||||
else
|
|
||||||
log_note "This rsync package does not support --crtimes (-N)."
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# If we are testing a ZIL replay, we need to ignore timestamp changes.
|
# If we are testing a ZIL replay, we need to ignore timestamp changes.
|
||||||
|
|||||||
@@ -1004,6 +1004,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
|
|||||||
functional/cli_root/zhack/zhack_label_repair_002.ksh \
|
functional/cli_root/zhack/zhack_label_repair_002.ksh \
|
||||||
functional/cli_root/zhack/zhack_label_repair_003.ksh \
|
functional/cli_root/zhack/zhack_label_repair_003.ksh \
|
||||||
functional/cli_root/zhack/zhack_label_repair_004.ksh \
|
functional/cli_root/zhack/zhack_label_repair_004.ksh \
|
||||||
|
functional/cli_root/zhack/zhack_metaslab_leak.ksh \
|
||||||
functional/cli_root/zpool_add/add_nested_replacing_spare.ksh \
|
functional/cli_root/zpool_add/add_nested_replacing_spare.ksh \
|
||||||
functional/cli_root/zpool_add/add-o_ashift.ksh \
|
functional/cli_root/zpool_add/add-o_ashift.ksh \
|
||||||
functional/cli_root/zpool_add/add_prop_ashift.ksh \
|
functional/cli_root/zpool_add/add_prop_ashift.ksh \
|
||||||
@@ -1666,6 +1667,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
|
|||||||
functional/mmap/setup.ksh \
|
functional/mmap/setup.ksh \
|
||||||
functional/mmp/cleanup.ksh \
|
functional/mmp/cleanup.ksh \
|
||||||
functional/mmp/mmp_active_import.ksh \
|
functional/mmp/mmp_active_import.ksh \
|
||||||
|
functional/mmp/mmp_concurrent_import.ksh \
|
||||||
functional/mmp/mmp_exported_import.ksh \
|
functional/mmp/mmp_exported_import.ksh \
|
||||||
functional/mmp/mmp_hostid.ksh \
|
functional/mmp/mmp_hostid.ksh \
|
||||||
functional/mmp/mmp_inactive_import.ksh \
|
functional/mmp/mmp_inactive_import.ksh \
|
||||||
@@ -1682,6 +1684,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
|
|||||||
functional/mmp/setup.ksh \
|
functional/mmp/setup.ksh \
|
||||||
functional/mount/cleanup.ksh \
|
functional/mount/cleanup.ksh \
|
||||||
functional/mount/setup.ksh \
|
functional/mount/setup.ksh \
|
||||||
|
functional/mount/mount_loopback.ksh \
|
||||||
functional/mount/umount_001.ksh \
|
functional/mount/umount_001.ksh \
|
||||||
functional/mount/umountall_001.ksh \
|
functional/mount/umountall_001.ksh \
|
||||||
functional/mount/umount_unlinked_drain.ksh \
|
functional/mount/umount_unlinked_drain.ksh \
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
#!/bin/ksh
|
||||||
|
# SPDX-License-Identifier: CDDL-1.0
|
||||||
|
|
||||||
|
#
|
||||||
|
# This file and its contents are supplied under the terms of the
|
||||||
|
# Common Development and Distribution License ("CDDL"), version 1.0.
|
||||||
|
# You may only use this file in accordance with the terms of version
|
||||||
|
# 1.0 of the CDDL.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Description:
|
||||||
|
#
|
||||||
|
# Test whether zhack metaslab leak functions correctly
|
||||||
|
#
|
||||||
|
# Strategy:
|
||||||
|
#
|
||||||
|
# 1. Create pool on a loopback device with some test data
|
||||||
|
# 2. Gather pool capacity stats
|
||||||
|
# 3. Generate fragmentation data with zdb
|
||||||
|
# 4. Destroy the pool
|
||||||
|
# 5. Create a new pool with the same configuration
|
||||||
|
# 6. Export the pool
|
||||||
|
# 7. Apply the fragmentation information with zhack metaslab leak
|
||||||
|
# 8. Import the pool
|
||||||
|
# 9. Verify that pool capacity stats match
|
||||||
|
|
||||||
|
. "$STF_SUITE"/include/libtest.shlib
|
||||||
|
|
||||||
|
verify_runnable "global"
|
||||||
|
|
||||||
|
function cleanup
|
||||||
|
{
|
||||||
|
zpool destroy $TESTPOOL
|
||||||
|
rm $tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
log_onexit cleanup
|
||||||
|
log_assert "zhack metaslab leak leaks the right amount of space"
|
||||||
|
|
||||||
|
typeset tmp=$(mktemp)
|
||||||
|
|
||||||
|
log_must zpool create $TESTPOOL $DISKS
|
||||||
|
for i in `seq 1 16`; do
|
||||||
|
log_must dd if=/dev/urandom of=/$TESTPOOL/f$i bs=1M count=16
|
||||||
|
log_must zpool sync $TESTPOOL
|
||||||
|
done
|
||||||
|
for i in `seq 2 2 16`; do
|
||||||
|
log_must rm /$TESTPOOL/f$i
|
||||||
|
done
|
||||||
|
for i in `seq 1 16`; do
|
||||||
|
log_must touch /$TESTPOOL/g$i
|
||||||
|
log_must zpool sync $TESTPOOL
|
||||||
|
done
|
||||||
|
|
||||||
|
alloc=$(zpool get -Hpo value alloc $TESTPOOL)
|
||||||
|
log_must eval "zdb -m --allocated-map $TESTPOOL > $tmp"
|
||||||
|
log_must zpool destroy $TESTPOOL
|
||||||
|
|
||||||
|
log_must zpool create $TESTPOOL $DISKS
|
||||||
|
log_must zpool export $TESTPOOL
|
||||||
|
log_must eval "zhack metaslab leak $TESTPOOL < $tmp"
|
||||||
|
log_must zpool import $TESTPOOL
|
||||||
|
|
||||||
|
alloc2=$(zpool get -Hpo value alloc $TESTPOOL)
|
||||||
|
|
||||||
|
[[ $((alloc * 1.05)) -gt $alloc2 ]] && [[ $alloc -lt $alloc2 ]] || \
|
||||||
|
log_fail "space usage changed too much: $alloc to $alloc2"
|
||||||
|
|
||||||
|
log_pass "zhack metaslab leak behaved correctly"
|
||||||
@@ -25,6 +25,8 @@ export DISK=${DISKS%% *}
|
|||||||
export HOSTID_FILE="/etc/hostid"
|
export HOSTID_FILE="/etc/hostid"
|
||||||
export HOSTID1=01234567
|
export HOSTID1=01234567
|
||||||
export HOSTID2=89abcdef
|
export HOSTID2=89abcdef
|
||||||
|
export HOSTID3=aaaabbbb
|
||||||
|
export HOSTID4=ccccdddd
|
||||||
|
|
||||||
export TXG_TIMEOUT_LONG=5000
|
export TXG_TIMEOUT_LONG=5000
|
||||||
export TXG_TIMEOUT_DEFAULT=5
|
export TXG_TIMEOUT_DEFAULT=5
|
||||||
@@ -32,7 +34,7 @@ export TXG_TIMEOUT_DEFAULT=5
|
|||||||
export MMP_POOL=mmppool
|
export MMP_POOL=mmppool
|
||||||
export MMP_DIR=$TEST_BASE_DIR/mmp
|
export MMP_DIR=$TEST_BASE_DIR/mmp
|
||||||
export MMP_CACHE=$MMP_DIR/zpool.cache
|
export MMP_CACHE=$MMP_DIR/zpool.cache
|
||||||
export MMP_ZTEST_LOG=$MMP_DIR/ztest.log
|
export MMP_ZHACK_LOG=$MMP_DIR/zhack.log
|
||||||
export MMP_HISTORY=100
|
export MMP_HISTORY=100
|
||||||
export MMP_HISTORY_OFF=0
|
export MMP_HISTORY_OFF=0
|
||||||
|
|
||||||
@@ -43,5 +45,3 @@ export MMP_INTERVAL_MIN=100
|
|||||||
export MMP_IMPORT_INTERVALS=20
|
export MMP_IMPORT_INTERVALS=20
|
||||||
export MMP_FAIL_INTERVALS_DEFAULT=10
|
export MMP_FAIL_INTERVALS_DEFAULT=10
|
||||||
export MMP_FAIL_INTERVALS_MIN=2
|
export MMP_FAIL_INTERVALS_MIN=2
|
||||||
|
|
||||||
export MMP_TEST_DURATION_DEFAULT=$((MMP_IMPORT_INTERVALS*MMP_INTERVAL_DEFAULT/1000))
|
|
||||||
|
|||||||
@@ -99,11 +99,11 @@ function mmp_pool_create_simple # pool dir
|
|||||||
log_must zpool set multihost=on $pool
|
log_must zpool set multihost=on $pool
|
||||||
}
|
}
|
||||||
|
|
||||||
function mmp_pool_create # pool dir
|
function mmp_pool_create_zhack # pool dir
|
||||||
{
|
{
|
||||||
typeset pool=${1:-$MMP_POOL}
|
typeset pool=${1:-$MMP_POOL}
|
||||||
typeset dir=${2:-$MMP_DIR}
|
typeset dir=${2:-$MMP_DIR}
|
||||||
typeset opts="-VVVVV -T120 -M -k0 -f $dir -E -p $pool"
|
typeset opts="-d $dir action idle -t120 $pool"
|
||||||
|
|
||||||
mmp_pool_create_simple $pool $dir
|
mmp_pool_create_simple $pool $dir
|
||||||
|
|
||||||
@@ -112,11 +112,11 @@ function mmp_pool_create # pool dir
|
|||||||
log_must mmp_clear_hostid
|
log_must mmp_clear_hostid
|
||||||
log_must mmp_set_hostid $HOSTID2
|
log_must mmp_set_hostid $HOSTID2
|
||||||
|
|
||||||
log_note "Starting ztest in the background as hostid $HOSTID1"
|
log_note "Starting zhack in the background as hostid $HOSTID1"
|
||||||
log_must eval "ZFS_HOSTID=$HOSTID1 ztest $opts >$MMP_ZTEST_LOG 2>&1 &"
|
log_must eval "ZFS_HOSTID=$HOSTID1 zhack $opts >$MMP_ZHACK_LOG 2>&1 &"
|
||||||
|
|
||||||
while ! is_pool_imported "$pool" "-d $dir"; do
|
while ! is_pool_imported "$pool" "-d $dir"; do
|
||||||
log_must pgrep ztest
|
log_must pgrep zhack
|
||||||
log_must sleep 5
|
log_must sleep 5
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
@@ -126,10 +126,10 @@ function mmp_pool_destroy # pool dir
|
|||||||
typeset pool=${1:-$MMP_POOL}
|
typeset pool=${1:-$MMP_POOL}
|
||||||
typeset dir=${2:-$MMP_DIR}
|
typeset dir=${2:-$MMP_DIR}
|
||||||
|
|
||||||
ZTESTPID=$(pgrep ztest)
|
ZHACKPID=$(pgrep zhack)
|
||||||
if [ -n "$ZTESTPID" ]; then
|
if [ -n "$ZHACKPID" ]; then
|
||||||
log_must kill $ZTESTPID
|
log_must kill $ZHACKPID
|
||||||
wait $ZTESTPID
|
wait $ZHACKPID
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if poolexists $pool; then
|
if poolexists $pool; then
|
||||||
@@ -158,33 +158,34 @@ function import_no_activity_check # pool opts
|
|||||||
typeset pool=$1
|
typeset pool=$1
|
||||||
typeset opts=$2
|
typeset opts=$2
|
||||||
|
|
||||||
typeset max_duration=$((MMP_TEST_DURATION_DEFAULT-1))
|
RESULT=$(ZFS_LOAD_INFO_DEBUG=1 zpool import $opts $pool)
|
||||||
|
|
||||||
SECONDS=0
|
|
||||||
zpool import $opts $pool
|
|
||||||
typeset rc=$?
|
typeset rc=$?
|
||||||
|
|
||||||
if [[ $SECONDS -gt $max_duration ]]; then
|
# mmp_result: 3 (ESRCH) no activity check was run not required
|
||||||
log_fail "ERROR: import_no_activity_check unexpected activity \
|
# mmp_result: 6 (ENXIO) no activity check was run hostid not set
|
||||||
check (${SECONDS}s gt $max_duration)"
|
if ! echo "$RESULT" | grep -q "mmp_result: 3" &&
|
||||||
|
! echo "$RESULT" | grep -q "mmp_result: 6"; then
|
||||||
|
log_note "ERROR: $RESULT"
|
||||||
|
log_fail "ERROR: import_no_activity_check unexpected activity check"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
return $rc
|
return $rc
|
||||||
}
|
}
|
||||||
|
|
||||||
function import_activity_check # pool opts act_test_duration
|
function import_activity_check # pool opts
|
||||||
{
|
{
|
||||||
typeset pool=$1
|
typeset pool=$1
|
||||||
typeset opts=$2
|
typeset opts=$2
|
||||||
typeset min_duration=${3:-$MMP_TEST_DURATION_DEFAULT}
|
|
||||||
|
|
||||||
SECONDS=0
|
RESULT=$(ZFS_LOAD_INFO_DEBUG=1 zpool import $opts $pool)
|
||||||
zpool import $opts $pool
|
|
||||||
typeset rc=$?
|
typeset rc=$?
|
||||||
|
|
||||||
if [[ $SECONDS -le $min_duration ]]; then
|
# mmp_result: 0 (Success) check was run no activity detected
|
||||||
log_fail "ERROR: import_activity_check expected activity check \
|
# mmp_result: 121 (EREMOTEIO) check was run activity detected
|
||||||
(${SECONDS}s le min_duration $min_duration)"
|
# mmp_result: 4 (EINTR) check was run but interrupted by user
|
||||||
|
if ! echo "$RESULT" | grep -q "mmp_result: 0"; then
|
||||||
|
log_note "ERROR: $RESULT"
|
||||||
|
log_fail "ERROR: import_activity_check expected activity check"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
return $rc
|
return $rc
|
||||||
|
|||||||
@@ -24,10 +24,10 @@
|
|||||||
# with one hostid be importable by a host with a different hostid.
|
# with one hostid be importable by a host with a different hostid.
|
||||||
#
|
#
|
||||||
# STRATEGY:
|
# STRATEGY:
|
||||||
# 1. Simulate an active pool on another host with ztest.
|
# 1. Simulate an active pool on another host with zhack.
|
||||||
# 2. Verify 'zpool import' reports an active pool.
|
# 2. Verify 'zpool import' reports an active pool.
|
||||||
# 3. Verify 'zpool import [-f] $MMP_POOL' cannot import the pool.
|
# 3. Verify 'zpool import [-f] $MMP_POOL' cannot import the pool.
|
||||||
# 4. Kill ztest to make pool eligible for import.
|
# 4. Kill zhack to make pool eligible for import.
|
||||||
# 5. Verify 'zpool import' fails with the expected error message.
|
# 5. Verify 'zpool import' fails with the expected error message.
|
||||||
# 6. Verify 'zpool import $MMP_POOL' fails with the expected message.
|
# 6. Verify 'zpool import $MMP_POOL' fails with the expected message.
|
||||||
# 7. Verify 'zpool import -f $MMP_POOL' can now import the pool.
|
# 7. Verify 'zpool import -f $MMP_POOL' can now import the pool.
|
||||||
@@ -44,16 +44,16 @@ function cleanup
|
|||||||
{
|
{
|
||||||
mmp_pool_destroy $MMP_POOL $MMP_DIR
|
mmp_pool_destroy $MMP_POOL $MMP_DIR
|
||||||
log_must mmp_clear_hostid
|
log_must mmp_clear_hostid
|
||||||
ZTESTPID=$(pgrep ztest)
|
ZHACKPID=$(pgrep zhack)
|
||||||
if [ -n "$ZTESTPID" ]; then
|
if [ -n "$ZHACKPID" ]; then
|
||||||
for pid in $ZTESTPID; do
|
for pid in $ZHACKPID; do
|
||||||
log_must kill -9 $pid
|
log_must kill -9 $pid
|
||||||
done
|
done
|
||||||
else
|
else
|
||||||
# if ztest not running and log present, ztest crashed
|
# if zhack is not running and log present, zhack crashed
|
||||||
if [ -f $MMP_ZTEST_LOG ]; then
|
if [ -f $MMP_ZHACK_LOG ]; then
|
||||||
log_note "ztest appears to have crashed. Tail of log:"
|
log_note "zhack appears to have crashed. Tail of log:"
|
||||||
tail -n 50 $MMP_ZTEST_LOG
|
tail -n 50 $MMP_ZHACK_LOG
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -61,15 +61,18 @@ function cleanup
|
|||||||
log_assert "multihost=on|off active pool activity checks"
|
log_assert "multihost=on|off active pool activity checks"
|
||||||
log_onexit cleanup
|
log_onexit cleanup
|
||||||
|
|
||||||
# 1. Simulate an active pool on another host with ztest.
|
# 1. Simulate an active pool on another host with zhack.
|
||||||
|
log_note "Simulate an active pool on another host with zhack"
|
||||||
mmp_pool_destroy $MMP_POOL $MMP_DIR
|
mmp_pool_destroy $MMP_POOL $MMP_DIR
|
||||||
mmp_pool_create $MMP_POOL $MMP_DIR
|
mmp_pool_create_zhack $MMP_POOL $MMP_DIR
|
||||||
|
|
||||||
# 2. Verify 'zpool import' reports an active pool.
|
# 2. Verify 'zpool import' reports an active pool.
|
||||||
|
log_note "Verify 'zpool import' reports an active pool"
|
||||||
log_must mmp_set_hostid $HOSTID2
|
log_must mmp_set_hostid $HOSTID2
|
||||||
log_must is_pool_imported $MMP_POOL "-d $MMP_DIR"
|
log_must is_pool_imported $MMP_POOL "-d $MMP_DIR"
|
||||||
|
|
||||||
# 3. Verify 'zpool import [-f] $MMP_POOL' cannot import the pool.
|
# 3. Verify 'zpool import [-f] $MMP_POOL' cannot import the pool.
|
||||||
|
log_note "Verify 'zpool import [-f] $MMP_POOL' cannot import the pool"
|
||||||
MMP_IMPORTED_MSG="Cannot import '$MMP_POOL': pool is imported"
|
MMP_IMPORTED_MSG="Cannot import '$MMP_POOL': pool is imported"
|
||||||
|
|
||||||
log_must try_pool_import $MMP_POOL "-d $MMP_DIR" "$MMP_IMPORTED_MSG"
|
log_must try_pool_import $MMP_POOL "-d $MMP_DIR" "$MMP_IMPORTED_MSG"
|
||||||
@@ -84,14 +87,15 @@ for i in {1..10}; do
|
|||||||
"$MMP_IMPORTED_MSG"
|
"$MMP_IMPORTED_MSG"
|
||||||
done
|
done
|
||||||
|
|
||||||
# 4. Kill ztest to make pool eligible for import. Poll with 'zpool status'.
|
# 4. Kill zhack to make pool eligible for import. Poll with 'zpool status'.
|
||||||
ZTESTPID=$(pgrep ztest)
|
log_note "Kill zhack to make pool eligible for import. Poll with 'zpool status'"
|
||||||
if [ -n "$ZTESTPID" ]; then
|
ZHACKPID=$(pgrep zhack)
|
||||||
log_must kill -9 $ZTESTPID
|
if [ -n "$ZHACKPID" ]; then
|
||||||
|
log_must kill -9 $ZHACKPID
|
||||||
fi
|
fi
|
||||||
log_must wait_pool_imported $MMP_POOL "-d $MMP_DIR"
|
log_must wait_pool_imported $MMP_POOL "-d $MMP_DIR"
|
||||||
if [ -f $MMP_ZTEST_LOG ]; then
|
if [ -f $MMP_ZHACK_LOG ]; then
|
||||||
log_must rm $MMP_ZTEST_LOG
|
log_must rm $MMP_ZHACK_LOG
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 5. Verify 'zpool import' fails with the expected error message, when
|
# 5. Verify 'zpool import' fails with the expected error message, when
|
||||||
@@ -99,6 +103,7 @@ fi
|
|||||||
# - hostid=matches - safe to import the pool
|
# - hostid=matches - safe to import the pool
|
||||||
# - hostid=different - previously imported on a different system
|
# - hostid=different - previously imported on a different system
|
||||||
#
|
#
|
||||||
|
log_note "Verify 'zpool import' fails with the expected error message"
|
||||||
log_must mmp_clear_hostid
|
log_must mmp_clear_hostid
|
||||||
MMP_IMPORTED_MSG="Set a unique system hostid"
|
MMP_IMPORTED_MSG="Set a unique system hostid"
|
||||||
log_must check_pool_import $MMP_POOL "-d $MMP_DIR" "action" "$MMP_IMPORTED_MSG"
|
log_must check_pool_import $MMP_POOL "-d $MMP_DIR" "action" "$MMP_IMPORTED_MSG"
|
||||||
@@ -113,13 +118,16 @@ MMP_IMPORTED_MSG="The pool was last accessed by another system."
|
|||||||
log_must check_pool_import $MMP_POOL "-d $MMP_DIR" "status" "$MMP_IMPORTED_MSG"
|
log_must check_pool_import $MMP_POOL "-d $MMP_DIR" "status" "$MMP_IMPORTED_MSG"
|
||||||
|
|
||||||
# 6. Verify 'zpool import $MMP_POOL' fails with the expected message.
|
# 6. Verify 'zpool import $MMP_POOL' fails with the expected message.
|
||||||
|
log_note "Verify 'zpool import $MMP_POOL' fails with the expected message"
|
||||||
MMP_IMPORTED_MSG="pool was previously in use from another system."
|
MMP_IMPORTED_MSG="pool was previously in use from another system."
|
||||||
log_must try_pool_import $MMP_POOL "-d $MMP_DIR" "$MMP_IMPORTED_MSG"
|
log_must try_pool_import $MMP_POOL "-d $MMP_DIR" "$MMP_IMPORTED_MSG"
|
||||||
|
|
||||||
# 7. Verify 'zpool import -f $MMP_POOL' can now import the pool.
|
# 7. Verify 'zpool import -f $MMP_POOL' can now import the pool.
|
||||||
|
log_note "Verify 'zpool import -f $MMP_POOL' can now import the pool"
|
||||||
log_must import_activity_check $MMP_POOL "-f -d $MMP_DIR"
|
log_must import_activity_check $MMP_POOL "-f -d $MMP_DIR"
|
||||||
|
|
||||||
# 8 Verify pool may be exported/imported without -f argument.
|
# 8 Verify pool may be exported/imported without -f argument.
|
||||||
|
log_note "Verify pool may be exported/imported without -f argument"
|
||||||
log_must zpool export $MMP_POOL
|
log_must zpool export $MMP_POOL
|
||||||
log_must import_no_activity_check $MMP_POOL "-d $MMP_DIR"
|
log_must import_no_activity_check $MMP_POOL "-d $MMP_DIR"
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,133 @@
|
|||||||
|
#!/bin/ksh -p
|
||||||
|
# SPDX-License-Identifier: CDDL-1.0
|
||||||
|
#
|
||||||
|
# CDDL HEADER START
|
||||||
|
#
|
||||||
|
# This file and its contents are supplied under the terms of the
|
||||||
|
# Common Development and Distribution License ("CDDL"), version 1.0.
|
||||||
|
# You may only use this file in accordance with the terms of version
|
||||||
|
# 1.0 of the CDDL.
|
||||||
|
#
|
||||||
|
# A full copy of the text of the CDDL should have accompanied this
|
||||||
|
# source. A copy of the CDDL is also available via the Internet at
|
||||||
|
# http://www.illumos.org/license/CDDL.
|
||||||
|
#
|
||||||
|
# CDDL HEADER END
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2026 by Lawrence Livermore National Security, LLC.
|
||||||
|
#
|
||||||
|
|
||||||
|
# DESCRIPTION:
|
||||||
|
# Verify that even when importing a shared pool simultaneously
|
||||||
|
# on systems with different host ids at most one will succeed.
|
||||||
|
#
|
||||||
|
# STRATEGY:
|
||||||
|
# 1. Create an multihost enabled pool
|
||||||
|
# 2. zhack imports: $HOSTID1 (matching) and $HOSTID1 (matching)
|
||||||
|
# 3. zhack imports: $HOSTID1 (matching) and $HOSTID2 (different)
|
||||||
|
# 4. zhack imports: $HOSTID3 (different) and $HOSTID4 (different)
|
||||||
|
#
|
||||||
|
|
||||||
|
. $STF_SUITE/include/libtest.shlib
|
||||||
|
. $STF_SUITE/tests/functional/mmp/mmp.cfg
|
||||||
|
. $STF_SUITE/tests/functional/mmp/mmp.kshlib
|
||||||
|
|
||||||
|
verify_runnable "both"
|
||||||
|
|
||||||
|
function cleanup
|
||||||
|
{
|
||||||
|
ZHACKPIDS=$(pgrep zhack)
|
||||||
|
if [ -n "$ZHACKPIDS" ]; then
|
||||||
|
for pid in $ZHACKPIDS; do
|
||||||
|
log_must kill -9 $pid
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_must rm -f $MMP_ZHACK_LOG.1 $MMP_ZHACK_LOG.2
|
||||||
|
|
||||||
|
mmp_pool_destroy $MMP_POOL $MMP_DIR
|
||||||
|
log_must mmp_clear_hostid
|
||||||
|
}
|
||||||
|
|
||||||
|
# Verify that pool was imported by at most one of the zhack processes.
|
||||||
|
# Check both the return code and expected import message.
|
||||||
|
function verify_zhack
|
||||||
|
{
|
||||||
|
IMPORT_COUNT=0
|
||||||
|
IMPORT_MSGS=0
|
||||||
|
|
||||||
|
ZHACKPIDS=$(pgrep zhack)
|
||||||
|
for pid in $ZHACKPIDS; do
|
||||||
|
wait $pid
|
||||||
|
STATUS=$?
|
||||||
|
if [[ $STATUS -eq 0 ]]; then
|
||||||
|
(( IMPORT_COUNT++ ))
|
||||||
|
fi
|
||||||
|
log_note "PID $pid exited with status $STATUS"
|
||||||
|
done
|
||||||
|
|
||||||
|
grep -H "Imported pool $MMP_POOL" $MMP_ZHACK_LOG.1 && (( IMPORT_MSGS++ ))
|
||||||
|
grep -H "Imported pool $MMP_POOL" $MMP_ZHACK_LOG.2 && (( IMPORT_MSGS++ ))
|
||||||
|
|
||||||
|
if [[ $IMPORT_MSGS -gt 1 ]]; then
|
||||||
|
cat $MMP_ZHACK_LOG.*
|
||||||
|
log_fail "Multiple import success messages"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $IMPORT_COUNT -gt 1 ]]; then
|
||||||
|
cat $MMP_ZHACK_LOG.*
|
||||||
|
log_fail "Multiple import success return codes"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $IMPORT_MSGS -ne $IMPORT_COUNT ]]; then
|
||||||
|
cat $MMP_ZHACK_LOG.*
|
||||||
|
log_fail "Messages ($IMPORT_MSGS) differs from count ($IMPORT_COUNT)"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
OPTS="-d $MMP_DIR action idle -t5 $MMP_POOL"
|
||||||
|
|
||||||
|
log_assert "multihost=on concurrent imports"
|
||||||
|
log_onexit cleanup
|
||||||
|
|
||||||
|
# 1. Create a multihost enabled pool with HOSTID1
|
||||||
|
mmp_pool_create_simple $MMP_POOL $MMP_DIR
|
||||||
|
log_must zpool export -F $MMP_POOL
|
||||||
|
|
||||||
|
# 2. zhack imports: $HOSTID1 (matching) and $HOSTID1 (matching)
|
||||||
|
# Activity check required because the pool was exported with -F above, the
|
||||||
|
# claim phase will detect the double import despite matching hostids.
|
||||||
|
log_note "zhack import with $HOSTID1 (matching) and $HOSTID1 (matching)"
|
||||||
|
log_must eval "ZFS_HOSTID=$HOSTID1 zhack $OPTS >$MMP_ZHACK_LOG.1 2>&1 &"
|
||||||
|
log_must eval "ZFS_HOSTID=$HOSTID1 zhack $OPTS >$MMP_ZHACK_LOG.2 2>&1 &"
|
||||||
|
log_must verify_zhack
|
||||||
|
|
||||||
|
mmp_clear_hostid
|
||||||
|
mmp_set_hostid $HOSTID1
|
||||||
|
log_must import_activity_check $MMP_POOL "-d $MMP_DIR"
|
||||||
|
log_must zpool export $MMP_POOL
|
||||||
|
|
||||||
|
# 3. zhack imports: $HOSTID1 (matching) and $HOSTID2 (different)
|
||||||
|
# Activity check skipped for HOSTID1 it is expected to import successfully.
|
||||||
|
# zhack with HOSTID2 will run the activity check and detect the active pool.
|
||||||
|
log_note "zhack import with $HOSTID1 (matching) and $HOSTID2 (different)"
|
||||||
|
log_must eval "ZFS_HOSTID=$HOSTID1 zhack $OPTS >$MMP_ZHACK_LOG.1 2>&1 &"
|
||||||
|
log_must eval "ZFS_HOSTID=$HOSTID2 zhack $OPTS >$MMP_ZHACK_LOG.2 2>&1 &"
|
||||||
|
log_must verify_zhack
|
||||||
|
|
||||||
|
mmp_clear_hostid
|
||||||
|
mmp_set_hostid $HOSTID3
|
||||||
|
log_must import_activity_check $MMP_POOL "-d $MMP_DIR"
|
||||||
|
log_must zpool export $MMP_POOL
|
||||||
|
|
||||||
|
# 4. zhack imports: $HOSTID1 (different) and $HOSTID2 (different)
|
||||||
|
# Both zhacks will run the activity checks, depending on the exact timing
|
||||||
|
# one may succeed and the other fail, or both may fail.
|
||||||
|
log_note "zhack import with $HOSTID1 (different) and $HOSTID2 (different)"
|
||||||
|
log_must eval "ZFS_HOSTID=$HOSTID1 zhack $OPTS >$MMP_ZHACK_LOG.1 2>&1 &"
|
||||||
|
log_must eval "ZFS_HOSTID=$HOSTID2 zhack $OPTS >$MMP_ZHACK_LOG.2 2>&1 &"
|
||||||
|
log_must verify_zhack
|
||||||
|
|
||||||
|
log_pass "multihost=on concurrent imports"
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
# 3. Verify multihost=off and hostids differ (no activity check)
|
# 3. Verify multihost=off and hostids differ (no activity check)
|
||||||
# 4. Verify multihost=off and hostid zero allowed (no activity check)
|
# 4. Verify multihost=off and hostid zero allowed (no activity check)
|
||||||
# 5. Verify multihost=on and hostids match (no activity check)
|
# 5. Verify multihost=on and hostids match (no activity check)
|
||||||
# 6. Verify multihost=on and hostids differ (no activity check)
|
# 6. Verify multihost=on and hostids differ (activity check)
|
||||||
# 7. Verify multihost=on and hostid zero fails (no activity check)
|
# 7. Verify multihost=on and hostid zero fails (no activity check)
|
||||||
#
|
#
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ verify_runnable "both"
|
|||||||
|
|
||||||
function cleanup
|
function cleanup
|
||||||
{
|
{
|
||||||
default_cleanup_noexit
|
datasetexists $TESTPOOL && destroy_pool $TESTPOOL
|
||||||
log_must mmp_clear_hostid
|
log_must mmp_clear_hostid
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,9 +49,10 @@ log_onexit cleanup
|
|||||||
|
|
||||||
# 1. Create a zpool
|
# 1. Create a zpool
|
||||||
log_must mmp_set_hostid $HOSTID1
|
log_must mmp_set_hostid $HOSTID1
|
||||||
default_setup_noexit $DISK
|
log_must zpool create -f $TESTPOOL $DISK
|
||||||
|
|
||||||
# 2. Verify multihost=off and hostids match (no activity check)
|
# 2. Verify multihost=off and hostids match (no activity check)
|
||||||
|
log_note "Verify multihost=off and hostids match (no activity check)"
|
||||||
log_must zpool set multihost=off $TESTPOOL
|
log_must zpool set multihost=off $TESTPOOL
|
||||||
|
|
||||||
for opt in "" "-f"; do
|
for opt in "" "-f"; do
|
||||||
@@ -60,6 +61,7 @@ for opt in "" "-f"; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
# 3. Verify multihost=off and hostids differ (no activity check)
|
# 3. Verify multihost=off and hostids differ (no activity check)
|
||||||
|
log_note "Verify multihost=off and hostids differ (no activity check)"
|
||||||
for opt in "" "-f"; do
|
for opt in "" "-f"; do
|
||||||
log_must mmp_pool_set_hostid $TESTPOOL $HOSTID1
|
log_must mmp_pool_set_hostid $TESTPOOL $HOSTID1
|
||||||
log_must zpool export $TESTPOOL
|
log_must zpool export $TESTPOOL
|
||||||
@@ -69,6 +71,7 @@ for opt in "" "-f"; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
# 4. Verify multihost=off and hostid zero allowed (no activity check)
|
# 4. Verify multihost=off and hostid zero allowed (no activity check)
|
||||||
|
log_note "Verify multihost=off and hostid zero allowed (no activity check)"
|
||||||
log_must mmp_clear_hostid
|
log_must mmp_clear_hostid
|
||||||
|
|
||||||
for opt in "" "-f"; do
|
for opt in "" "-f"; do
|
||||||
@@ -77,6 +80,7 @@ for opt in "" "-f"; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
# 5. Verify multihost=on and hostids match (no activity check)
|
# 5. Verify multihost=on and hostids match (no activity check)
|
||||||
|
log_note "Verify multihost=on and hostids match (no activity check)"
|
||||||
log_must mmp_pool_set_hostid $TESTPOOL $HOSTID1
|
log_must mmp_pool_set_hostid $TESTPOOL $HOSTID1
|
||||||
log_must zpool set multihost=on $TESTPOOL
|
log_must zpool set multihost=on $TESTPOOL
|
||||||
|
|
||||||
@@ -85,16 +89,18 @@ for opt in "" "-f"; do
|
|||||||
log_must import_no_activity_check $TESTPOOL $opt
|
log_must import_no_activity_check $TESTPOOL $opt
|
||||||
done
|
done
|
||||||
|
|
||||||
# 6. Verify multihost=on and hostids differ (no activity check)
|
# 6. Verify multihost=on and hostids differ (activity check)
|
||||||
|
log_note "Verify multihost=on and hostids differ (activity check)"
|
||||||
for opt in "" "-f"; do
|
for opt in "" "-f"; do
|
||||||
log_must mmp_pool_set_hostid $TESTPOOL $HOSTID1
|
log_must mmp_pool_set_hostid $TESTPOOL $HOSTID1
|
||||||
log_must zpool export $TESTPOOL
|
log_must zpool export $TESTPOOL
|
||||||
log_must mmp_clear_hostid
|
log_must mmp_clear_hostid
|
||||||
log_must mmp_set_hostid $HOSTID2
|
log_must mmp_set_hostid $HOSTID2
|
||||||
log_must import_no_activity_check $TESTPOOL $opt
|
log_must import_activity_check $TESTPOOL $opt
|
||||||
done
|
done
|
||||||
|
|
||||||
# 7. Verify multihost=on and hostid zero fails (no activity check)
|
# 7. Verify multihost=on and hostid zero fails (no activity check)
|
||||||
|
log_note "Verify multihost=on and hostid zero fails (no activity check)"
|
||||||
log_must zpool export $TESTPOOL
|
log_must zpool export $TESTPOOL
|
||||||
log_must mmp_clear_hostid
|
log_must mmp_clear_hostid
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ verify_runnable "both"
|
|||||||
|
|
||||||
function cleanup
|
function cleanup
|
||||||
{
|
{
|
||||||
default_cleanup_noexit
|
datasetexists $MMP_POOL && destroy_pool $MMP_POOL
|
||||||
log_must rm $MMP_DIR/file.{0,1,2,3,4,5}
|
log_must rm $MMP_DIR/file.{0,1,2,3,4,5}
|
||||||
log_must rmdir $MMP_DIR
|
log_must rmdir $MMP_DIR
|
||||||
log_must mmp_clear_hostid
|
log_must mmp_clear_hostid
|
||||||
@@ -56,7 +56,7 @@ log_must mkdir -p $MMP_DIR
|
|||||||
log_must truncate -s $MINVDEVSIZE $MMP_DIR/file.{0,1,2,3,4,5}
|
log_must truncate -s $MINVDEVSIZE $MMP_DIR/file.{0,1,2,3,4,5}
|
||||||
|
|
||||||
# 1. Create a non-redundant pool
|
# 1. Create a non-redundant pool
|
||||||
log_must zpool create $MMP_POOL $MMP_DIR/file.0
|
log_must zpool create -f $MMP_POOL $MMP_DIR/file.0
|
||||||
|
|
||||||
# 2. Create an 'etc' dataset containing a valid hostid file; caching is
|
# 2. Create an 'etc' dataset containing a valid hostid file; caching is
|
||||||
# disabled on the dataset to force the hostid to be read from disk.
|
# disabled on the dataset to force the hostid to be read from disk.
|
||||||
@@ -71,16 +71,19 @@ mntpnt_fs=$(get_prop mountpoint $MMP_POOL/fs)
|
|||||||
log_must mkfile 1M $mntpnt_fs/file
|
log_must mkfile 1M $mntpnt_fs/file
|
||||||
|
|
||||||
# 4. Verify multihost cannot be enabled until the /etc/hostid is linked
|
# 4. Verify multihost cannot be enabled until the /etc/hostid is linked
|
||||||
|
log_note "Verify multihost cannot be enabled until the /etc/hostid is linked"
|
||||||
log_mustnot zpool set multihost=on $MMP_POOL
|
log_mustnot zpool set multihost=on $MMP_POOL
|
||||||
log_mustnot ls -l $HOSTID_FILE
|
log_mustnot ls -l $HOSTID_FILE
|
||||||
log_must ln -s $mntpnt_etc/hostid $HOSTID_FILE
|
log_must ln -s $mntpnt_etc/hostid $HOSTID_FILE
|
||||||
log_must zpool set multihost=on $MMP_POOL
|
log_must zpool set multihost=on $MMP_POOL
|
||||||
|
|
||||||
# 5. Verify vdevs may be attached and detached
|
# 5. Verify vdevs may be attached and detached
|
||||||
|
log_note "Verify vdevs may be attached and detached"
|
||||||
log_must zpool attach $MMP_POOL $MMP_DIR/file.0 $MMP_DIR/file.1
|
log_must zpool attach $MMP_POOL $MMP_DIR/file.0 $MMP_DIR/file.1
|
||||||
log_must zpool detach $MMP_POOL $MMP_DIR/file.1
|
log_must zpool detach $MMP_POOL $MMP_DIR/file.1
|
||||||
|
|
||||||
# 6. Verify normal, cache, log and special vdevs can be added
|
# 6. Verify normal, cache, log and special vdevs can be added
|
||||||
|
log_note "Verify normal, cache, log and special vdevs can be added"
|
||||||
log_must zpool add $MMP_POOL $MMP_DIR/file.1
|
log_must zpool add $MMP_POOL $MMP_DIR/file.1
|
||||||
log_must zpool add $MMP_POOL $MMP_DIR/file.2
|
log_must zpool add $MMP_POOL $MMP_DIR/file.2
|
||||||
log_must zpool add $MMP_POOL cache $MMP_DIR/file.3
|
log_must zpool add $MMP_POOL cache $MMP_DIR/file.3
|
||||||
@@ -88,6 +91,7 @@ log_must zpool add $MMP_POOL log $MMP_DIR/file.4
|
|||||||
log_must zpool add $MMP_POOL special $MMP_DIR/file.5
|
log_must zpool add $MMP_POOL special $MMP_DIR/file.5
|
||||||
|
|
||||||
# 7. Verify normal, cache, and log vdevs can be removed
|
# 7. Verify normal, cache, and log vdevs can be removed
|
||||||
|
log_note "Verify normal, cache, and log vdevs can be removed"
|
||||||
log_must zpool remove $MMP_POOL $MMP_DIR/file.2
|
log_must zpool remove $MMP_POOL $MMP_DIR/file.2
|
||||||
log_must zpool remove $MMP_POOL $MMP_DIR/file.3
|
log_must zpool remove $MMP_POOL $MMP_DIR/file.3
|
||||||
log_must zpool remove $MMP_POOL $MMP_DIR/file.4
|
log_must zpool remove $MMP_POOL $MMP_DIR/file.4
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
# 2. Verify multihost=off and hostids match (no activity check)
|
# 2. Verify multihost=off and hostids match (no activity check)
|
||||||
# 3. Verify multihost=off and hostids differ (no activity check)
|
# 3. Verify multihost=off and hostids differ (no activity check)
|
||||||
# 4. Verify multihost=off and hostid allowed (no activity check)
|
# 4. Verify multihost=off and hostid allowed (no activity check)
|
||||||
# 5. Verify multihost=on and hostids match (no activity check)
|
# 5. Verify multihost=on and hostids match (activity check)
|
||||||
# 6. Verify multihost=on and hostids differ (activity check)
|
# 6. Verify multihost=on and hostids differ (activity check)
|
||||||
# 7. Verify mmp_write and mmp_fail are set correctly
|
# 7. Verify mmp_write and mmp_fail are set correctly
|
||||||
# 8. Verify multihost=on and hostid zero fails (no activity check)
|
# 8. Verify multihost=on and hostid zero fails (no activity check)
|
||||||
@@ -42,7 +42,7 @@ verify_runnable "both"
|
|||||||
|
|
||||||
function cleanup
|
function cleanup
|
||||||
{
|
{
|
||||||
default_cleanup_noexit
|
datasetexists $TESTPOOL && destroy_pool $TESTPOOL
|
||||||
log_must mmp_clear_hostid
|
log_must mmp_clear_hostid
|
||||||
log_must set_tunable64 MULTIHOST_INTERVAL $MMP_INTERVAL_DEFAULT
|
log_must set_tunable64 MULTIHOST_INTERVAL $MMP_INTERVAL_DEFAULT
|
||||||
}
|
}
|
||||||
@@ -52,9 +52,10 @@ log_onexit cleanup
|
|||||||
|
|
||||||
# 1. Create a zpool
|
# 1. Create a zpool
|
||||||
log_must mmp_set_hostid $HOSTID1
|
log_must mmp_set_hostid $HOSTID1
|
||||||
default_setup_noexit $DISK
|
log_must zpool create -f $TESTPOOL $DISK
|
||||||
|
|
||||||
# 2. Verify multihost=off and hostids match (no activity check)
|
# 2. Verify multihost=off and hostids match (no activity check)
|
||||||
|
log_note "Verify multihost=off and hostids match (no activity check)"
|
||||||
log_must zpool set multihost=off $TESTPOOL
|
log_must zpool set multihost=off $TESTPOOL
|
||||||
|
|
||||||
for opt in "" "-f"; do
|
for opt in "" "-f"; do
|
||||||
@@ -63,6 +64,7 @@ for opt in "" "-f"; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
# 3. Verify multihost=off and hostids differ (no activity check)
|
# 3. Verify multihost=off and hostids differ (no activity check)
|
||||||
|
log_note "Verify multihost=off and hostids differ (no activity check)"
|
||||||
log_must zpool export -F $TESTPOOL
|
log_must zpool export -F $TESTPOOL
|
||||||
log_must mmp_clear_hostid
|
log_must mmp_clear_hostid
|
||||||
log_must mmp_set_hostid $HOSTID2
|
log_must mmp_set_hostid $HOSTID2
|
||||||
@@ -70,21 +72,24 @@ log_mustnot import_no_activity_check $TESTPOOL ""
|
|||||||
log_must import_no_activity_check $TESTPOOL "-f"
|
log_must import_no_activity_check $TESTPOOL "-f"
|
||||||
|
|
||||||
# 4. Verify multihost=off and hostid zero allowed (no activity check)
|
# 4. Verify multihost=off and hostid zero allowed (no activity check)
|
||||||
|
log_note "Verify multihost=off and hostid zero allowed (no activity check)"
|
||||||
log_must zpool export -F $TESTPOOL
|
log_must zpool export -F $TESTPOOL
|
||||||
log_must mmp_clear_hostid
|
log_must mmp_clear_hostid
|
||||||
log_mustnot import_no_activity_check $TESTPOOL ""
|
log_mustnot import_no_activity_check $TESTPOOL ""
|
||||||
log_must import_no_activity_check $TESTPOOL "-f"
|
log_must import_no_activity_check $TESTPOOL "-f"
|
||||||
|
|
||||||
# 5. Verify multihost=on and hostids match (no activity check)
|
# 5. Verify multihost=on and hostids match (activity check)
|
||||||
|
log_note "Verify multihost=on and hostids match (activity check)"
|
||||||
log_must mmp_pool_set_hostid $TESTPOOL $HOSTID1
|
log_must mmp_pool_set_hostid $TESTPOOL $HOSTID1
|
||||||
log_must zpool set multihost=on $TESTPOOL
|
log_must zpool set multihost=on $TESTPOOL
|
||||||
|
|
||||||
for opt in "" "-f"; do
|
for opt in "" "-f"; do
|
||||||
log_must zpool export -F $TESTPOOL
|
log_must zpool export -F $TESTPOOL
|
||||||
log_must import_no_activity_check $TESTPOOL $opt
|
log_must import_activity_check $TESTPOOL $opt
|
||||||
done
|
done
|
||||||
|
|
||||||
# 6. Verify multihost=on and hostids differ (activity check)
|
# 6. Verify multihost=on and hostids differ (activity check)
|
||||||
|
log_note "Verify multihost=on and hostids differ (activity check)"
|
||||||
log_must zpool export -F $TESTPOOL
|
log_must zpool export -F $TESTPOOL
|
||||||
log_must mmp_clear_hostid
|
log_must mmp_clear_hostid
|
||||||
log_must mmp_set_hostid $HOSTID2
|
log_must mmp_set_hostid $HOSTID2
|
||||||
@@ -92,10 +97,12 @@ log_mustnot import_activity_check $TESTPOOL ""
|
|||||||
log_must import_activity_check $TESTPOOL "-f"
|
log_must import_activity_check $TESTPOOL "-f"
|
||||||
|
|
||||||
# 7. Verify mmp_write and mmp_fail are set correctly
|
# 7. Verify mmp_write and mmp_fail are set correctly
|
||||||
|
log_note "Verify mmp_write and mmp_fail are set correctly"
|
||||||
log_must zpool export -F $TESTPOOL
|
log_must zpool export -F $TESTPOOL
|
||||||
log_must verify_mmp_write_fail_present ${DISK[0]}
|
log_must verify_mmp_write_fail_present ${DISK[0]}
|
||||||
|
|
||||||
# 8. Verify multihost=on and hostid zero fails (no activity check)
|
# 8. Verify multihost=on and hostid zero fails (no activity check)
|
||||||
|
log_note "Verify multihost=on and hostid zero fails (no activity check)"
|
||||||
log_must mmp_clear_hostid
|
log_must mmp_clear_hostid
|
||||||
MMP_IMPORTED_MSG="Set a unique system hostid"
|
MMP_IMPORTED_MSG="Set a unique system hostid"
|
||||||
log_must check_pool_import $TESTPOOL "-f" "action" "$MMP_IMPORTED_MSG"
|
log_must check_pool_import $TESTPOOL "-f" "action" "$MMP_IMPORTED_MSG"
|
||||||
@@ -104,9 +111,10 @@ log_mustnot import_no_activity_check $TESTPOOL "-f"
|
|||||||
# 9. Verify activity check duration based on mmp_write and mmp_fail
|
# 9. Verify activity check duration based on mmp_write and mmp_fail
|
||||||
# Specify a short test via tunables but import pool imported while
|
# Specify a short test via tunables but import pool imported while
|
||||||
# tunables set to default duration.
|
# tunables set to default duration.
|
||||||
|
log_note "Verify activity check duration based on mmp_write and mmp_fail"
|
||||||
log_must set_tunable64 MULTIHOST_INTERVAL $MMP_INTERVAL_MIN
|
log_must set_tunable64 MULTIHOST_INTERVAL $MMP_INTERVAL_MIN
|
||||||
log_must mmp_clear_hostid
|
log_must mmp_clear_hostid
|
||||||
log_must mmp_set_hostid $HOSTID1
|
log_must mmp_set_hostid $HOSTID1
|
||||||
log_must import_activity_check $TESTPOOL "-f" $MMP_TEST_DURATION_DEFAULT
|
log_must import_activity_check $TESTPOOL "-f"
|
||||||
|
|
||||||
log_pass "multihost=on|off inactive pool activity checks passed"
|
log_pass "multihost=on|off inactive pool activity checks passed"
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user