Compare commits

..

No commits in common. "zfs-2.1-release" and "zfs-2.1.0-rc1" have entirely different histories.

1222 changed files with 43154 additions and 55918 deletions

View File

@ -2,7 +2,7 @@
name: Bug report name: Bug report
about: Create a report to help us improve OpenZFS about: Create a report to help us improve OpenZFS
title: '' title: ''
labels: 'Type: Defect' labels: 'Type: Defect, Status: Triage Needed'
assignees: '' assignees: ''
--- ---
@ -25,16 +25,14 @@ Type | Version/Name
--- | --- --- | ---
Distribution Name | Distribution Name |
Distribution Version | Distribution Version |
Kernel Version | Linux Kernel |
Architecture | Architecture |
OpenZFS Version | ZFS Version |
SPL Version |
<!-- <!--
Command to find OpenZFS version: Commands to find ZFS/SPL versions:
zfs version modinfo zfs | grep -iw version
modinfo spl | grep -iw version
Commands to find kernel version:
uname -r # Linux
freebsd-version -r # FreeBSD
--> -->
### Describe the problem you're observing ### Describe the problem you're observing

View File

@ -10,5 +10,5 @@ contact_links:
url: https://lists.freebsd.org/mailman/listinfo/freebsd-fs url: https://lists.freebsd.org/mailman/listinfo/freebsd-fs
about: Get community support for OpenZFS on FreeBSD about: Get community support for OpenZFS on FreeBSD
- name: OpenZFS on IRC - name: OpenZFS on IRC
url: https://web.libera.chat/#openzfs url: https://webchat.freenode.net/#openzfs
about: Use IRC to get community support for OpenZFS about: Use IRC to get community support for OpenZFS

View File

@ -1,57 +0,0 @@
acl
alien
attr
autoconf
bc
build-essential
curl
dbench
debhelper-compat
dh-python
dkms
fakeroot
fio
gdb
gdebi
git
ksh
lcov
libacl1-dev
libaio-dev
libattr1-dev
libblkid-dev
libcurl4-openssl-dev
libdevmapper-dev
libelf-dev
libffi-dev
libmount-dev
libpam0g-dev
libselinux1-dev
libssl-dev
libtool
libudev-dev
linux-headers-generic
lsscsi
mdadm
nfs-kernel-server
pamtester
parted
po-debconf
python3
python3-all-dev
python3-cffi
python3-dev
python3-packaging
python3-pip
python3-setuptools
python3-sphinx
rng-tools-debian
rsync
samba
sysstat
uuid-dev
watchdog
wget
xfslibs-dev
xz-utils
zlib1g-dev

View File

@ -1,2 +0,0 @@
pax-utils
shellcheck

View File

@ -6,27 +6,20 @@ on:
jobs: jobs:
checkstyle: checkstyle:
runs-on: ubuntu-22.04 runs-on: ubuntu-18.04
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v2
with: with:
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}
- name: Install dependencies - name: Install dependencies
run: | run: |
# https://github.com/orgs/community/discussions/47863 sudo apt-get update
sudo apt-mark hold grub-efi-amd64-signed sudo apt-get install --yes -qq build-essential autoconf libtool gawk alien fakeroot linux-headers-$(uname -r)
sudo apt-get update --fix-missing sudo apt-get install --yes -qq zlib1g-dev uuid-dev libattr1-dev libblkid-dev libselinux-dev libudev-dev libssl-dev python-dev python-setuptools python-cffi python3 python3-dev python3-setuptools python3-cffi
sudo apt-get upgrade # packages for tests
sudo xargs --arg-file=${{ github.workspace }}/.github/workflows/build-dependencies.txt apt-get install -qq sudo apt-get install --yes -qq parted lsscsi ksh attr acl nfs-kernel-server fio
sudo xargs --arg-file=${{ github.workspace }}/.github/workflows/checkstyle-dependencies.txt apt-get install -qq sudo apt-get install --yes -qq mandoc cppcheck pax-utils devscripts abigail-tools
sudo python3 -m pip install --quiet flake8 sudo -E pip --quiet install flake8
sudo apt-get clean
# confirm that the tools are installed
# the build system doesn't fail when they are not
flake8 --version
scanelf --version
shellcheck --version
- name: Prepare - name: Prepare
run: | run: |
sh ./autogen.sh sh ./autogen.sh
@ -39,19 +32,5 @@ jobs:
run: | run: |
make lint make lint
- name: CheckABI - name: CheckABI
id: CheckABI
run: | run: |
sudo docker run -v $(pwd):/source ghcr.io/openzfs/libabigail make checkabi make checkabi
- name: StoreABI
if: failure() && steps.CheckABI.outcome == 'failure'
run: |
sudo docker run -v $(pwd):/source ghcr.io/openzfs/libabigail make storeabi
- name: Prepare artifacts
if: failure() && steps.CheckABI.outcome == 'failure'
run: |
find -name *.abi | tar -cf abi_files.tar -T -
- uses: actions/upload-artifact@v3
if: failure() && steps.CheckABI.outcome == 'failure'
with:
name: New ABI files (use only if you're sure about interface changes)
path: abi_files.tar

View File

@ -1,23 +0,0 @@
#!/bin/sh
set -eu
# remove 4GiB of images
sudo systemd-run docker system prune --force --all --volumes
# remove unused software
sudo systemd-run --wait rm -rf \
"$AGENT_TOOLSDIRECTORY" \
/opt/* \
/usr/local/* \
/usr/share/az* \
/usr/share/dotnet \
/usr/share/gradle* \
/usr/share/miniconda \
/usr/share/swift \
/var/lib/gems \
/var/lib/mysql \
/var/lib/snapd
# trim the cleaned space
sudo fstrim /

View File

@ -9,20 +9,24 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [20.04, 22.04] os: [18.04, 20.04]
runs-on: ubuntu-${{ matrix.os }} runs-on: ubuntu-${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v2
with: with:
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}
- name: Install dependencies - name: Install dependencies
run: | run: |
# https://github.com/orgs/community/discussions/47863 sudo apt-get update
sudo apt-mark hold grub-efi-amd64-signed sudo apt-get install --yes -qq build-essential autoconf libtool gdb lcov \
sudo apt-get update --fix-missing git alien fakeroot wget curl bc fio acl \
sudo apt-get upgrade sysstat mdadm lsscsi parted gdebi attr dbench watchdog ksh \
sudo xargs --arg-file=${{ github.workspace }}/.github/workflows/build-dependencies.txt apt-get install -qq nfs-kernel-server samba rng-tools xz-utils \
sudo apt-get clean zlib1g-dev uuid-dev libblkid-dev libselinux-dev \
xfslibs-dev libattr1-dev libacl1-dev libudev-dev libdevmapper-dev \
libssl-dev libffi-dev libaio-dev libelf-dev libmount-dev \
libpam0g-dev pamtester python-dev python-setuptools python-cffi \
python3 python3-dev python3-setuptools python3-cffi
- name: Autogen.sh - name: Autogen.sh
run: | run: |
sh autogen.sh sh autogen.sh
@ -40,42 +44,21 @@ jobs:
sudo sed -i.bak 's/updates/extra updates/' /etc/depmod.d/ubuntu.conf sudo sed -i.bak 's/updates/extra updates/' /etc/depmod.d/ubuntu.conf
sudo depmod sudo depmod
sudo modprobe zfs sudo modprobe zfs
# Workaround for cloud-init bug
# see https://github.com/openzfs/zfs/issues/12644
FILE=/lib/udev/rules.d/10-cloud-init-hook-hotplug.rules
if [ -r "${FILE}" ]; then
HASH=$(md5sum "${FILE}" | awk '{ print $1 }')
if [ "${HASH}" = "121ff0ef1936cd2ef65aec0458a35772" ]; then
# Just shove a zd* exclusion right above the hotplug hook...
sudo sed -i -e s/'LABEL="cloudinit_hook"'/'KERNEL=="zd*", GOTO="cloudinit_end"\n&'/ "${FILE}"
sudo udevadm control --reload-rules
fi
fi
- name: Clear the kernel ring buffer
run: |
sudo dmesg -c >/var/tmp/dmesg-prerun
- name: Reclaim and report disk space
run: |
${{ github.workspace }}/.github/workflows/scripts/reclaim_disk_space.sh
df -h /
- name: Tests - name: Tests
run: | run: |
/usr/share/zfs/zfs-tests.sh -vR -s 3G /usr/share/zfs/zfs-tests.sh -v -s 3G
timeout-minutes: 330
- name: Prepare artifacts - name: Prepare artifacts
if: failure() if: failure()
run: | run: |
RESULTS_PATH=$(readlink -f /var/tmp/test_results/current) RESULTS_PATH=$(readlink -f /var/tmp/test_results/current)
sudo dmesg > $RESULTS_PATH/dmesg sudo dmesg > $RESULTS_PATH/dmesg
sudo cp /var/log/syslog /var/tmp/dmesg-prerun $RESULTS_PATH/ sudo cp /var/log/syslog $RESULTS_PATH/
sudo chmod +r $RESULTS_PATH/* sudo chmod +r $RESULTS_PATH/*
# Replace ':' in dir names, actions/upload-artifact doesn't support it # Replace ':' in dir names, actions/upload-artifact doesn't support it
for f in $(find /var/tmp/test_results -name '*:*'); do mv "$f" "${f//:/__}"; done for f in $(find $RESULTS_PATH -name '*:*'); do mv "$f" "${f//:/__}"; done
- uses: actions/upload-artifact@v3 - uses: actions/upload-artifact@v2
if: failure() if: failure()
with: with:
name: Test logs Ubuntu-${{ matrix.os }} name: Test logs Ubuntu-${{ matrix.os }}
path: | path: /var/tmp/test_results/20*/
/var/tmp/test_results/*
!/var/tmp/test_results/current
if-no-files-found: ignore if-no-files-found: ignore

View File

@ -6,19 +6,23 @@ on:
jobs: jobs:
tests: tests:
runs-on: ubuntu-22.04 runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v2
with: with:
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}
- name: Install dependencies - name: Install dependencies
run: | run: |
# https://github.com/orgs/community/discussions/47863 sudo apt-get update
sudo apt-mark hold grub-efi-amd64-signed sudo apt-get install --yes -qq build-essential autoconf libtool gdb lcov \
sudo apt-get update --fix-missing git alien fakeroot wget curl bc fio acl \
sudo apt-get upgrade sysstat mdadm lsscsi parted gdebi attr dbench watchdog ksh \
sudo xargs --arg-file=${{ github.workspace }}/.github/workflows/build-dependencies.txt apt-get install -qq nfs-kernel-server samba rng-tools xz-utils \
sudo apt-get clean zlib1g-dev uuid-dev libblkid-dev libselinux-dev \
xfslibs-dev libattr1-dev libacl1-dev libudev-dev libdevmapper-dev \
libssl-dev libffi-dev libaio-dev libelf-dev libmount-dev \
libpam0g-dev pamtester python-dev python-setuptools python-cffi \
python3 python3-dev python3-setuptools python3-cffi
- name: Autogen.sh - name: Autogen.sh
run: | run: |
sh autogen.sh sh autogen.sh
@ -36,42 +40,21 @@ jobs:
sudo sed -i.bak 's/updates/extra updates/' /etc/depmod.d/ubuntu.conf sudo sed -i.bak 's/updates/extra updates/' /etc/depmod.d/ubuntu.conf
sudo depmod sudo depmod
sudo modprobe zfs sudo modprobe zfs
# Workaround for cloud-init bug
# see https://github.com/openzfs/zfs/issues/12644
FILE=/lib/udev/rules.d/10-cloud-init-hook-hotplug.rules
if [ -r "${FILE}" ]; then
HASH=$(md5sum "${FILE}" | awk '{ print $1 }')
if [ "${HASH}" = "121ff0ef1936cd2ef65aec0458a35772" ]; then
# Just shove a zd* exclusion right above the hotplug hook...
sudo sed -i -e s/'LABEL="cloudinit_hook"'/'KERNEL=="zd*", GOTO="cloudinit_end"\n&'/ "${FILE}"
sudo udevadm control --reload-rules
fi
fi
- name: Clear the kernel ring buffer
run: |
sudo dmesg -c >/var/tmp/dmesg-prerun
- name: Reclaim and report disk space
run: |
${{ github.workspace }}/.github/workflows/scripts/reclaim_disk_space.sh
df -h /
- name: Tests - name: Tests
run: | run: |
/usr/share/zfs/zfs-tests.sh -vR -s 3G -r sanity /usr/share/zfs/zfs-tests.sh -v -s 3G -r sanity
timeout-minutes: 330
- name: Prepare artifacts - name: Prepare artifacts
if: failure() if: failure()
run: | run: |
RESULTS_PATH=$(readlink -f /var/tmp/test_results/current) RESULTS_PATH=$(readlink -f /var/tmp/test_results/current)
sudo dmesg > $RESULTS_PATH/dmesg sudo dmesg > $RESULTS_PATH/dmesg
sudo cp /var/log/syslog /var/tmp/dmesg-prerun $RESULTS_PATH/ sudo cp /var/log/syslog $RESULTS_PATH/
sudo chmod +r $RESULTS_PATH/* sudo chmod +r $RESULTS_PATH/*
# Replace ':' in dir names, actions/upload-artifact doesn't support it # Replace ':' in dir names, actions/upload-artifact doesn't support it
for f in $(find /var/tmp/test_results -name '*:*'); do mv "$f" "${f//:/__}"; done for f in $(find $RESULTS_PATH -name '*:*'); do mv "$f" "${f//:/__}"; done
- uses: actions/upload-artifact@v3 - uses: actions/upload-artifact@v2
if: failure() if: failure()
with: with:
name: Test logs Ubuntu-${{ matrix.os }} name: Test logs
path: | path: /var/tmp/test_results/20*/
/var/tmp/test_results/*
!/var/tmp/test_results/current
if-no-files-found: ignore if-no-files-found: ignore

View File

@ -6,21 +6,24 @@ on:
jobs: jobs:
tests: tests:
runs-on: ubuntu-22.04 runs-on: ubuntu-latest
env: env:
TEST_DIR: /var/tmp/zloop TEST_DIR: /var/tmp/zloop
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v2
with: with:
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}
- name: Install dependencies - name: Install dependencies
run: | run: |
# https://github.com/orgs/community/discussions/47863 sudo apt-get update
sudo apt-mark hold grub-efi-amd64-signed sudo apt-get install --yes -qq build-essential autoconf libtool gdb \
sudo apt-get update --fix-missing git alien fakeroot \
sudo apt-get upgrade zlib1g-dev uuid-dev libblkid-dev libselinux-dev \
sudo xargs --arg-file=${{ github.workspace }}/.github/workflows/build-dependencies.txt apt-get install -qq xfslibs-dev libattr1-dev libacl1-dev libudev-dev libdevmapper-dev \
sudo apt-get clean libssl-dev libffi-dev libaio-dev libelf-dev libmount-dev \
libpam0g-dev \
python-dev python-setuptools python-cffi \
python3 python3-dev python3-setuptools python3-cffi
- name: Autogen.sh - name: Autogen.sh
run: | run: |
sh autogen.sh sh autogen.sh
@ -41,14 +44,13 @@ jobs:
- name: Tests - name: Tests
run: | run: |
sudo mkdir -p $TEST_DIR sudo mkdir -p $TEST_DIR
# run for 10 minutes or at most 2 iterations for a maximum runner # run for 20 minutes to have a total runner time of 30 minutes
# time of 20 minutes. sudo /usr/share/zfs/zloop.sh -t 1200 -l -m1
sudo /usr/share/zfs/zloop.sh -t 600 -I 2 -l -m1 -- -T 120 -P 60
- name: Prepare artifacts - name: Prepare artifacts
if: failure() if: failure()
run: | run: |
sudo chmod +r -R $TEST_DIR/ sudo chmod +r -R $TEST_DIR/
- uses: actions/upload-artifact@v3 - uses: actions/upload-artifact@v2
if: failure() if: failure()
with: with:
name: Logs name: Logs
@ -56,7 +58,7 @@ jobs:
/var/tmp/zloop/*/ /var/tmp/zloop/*/
!/var/tmp/zloop/*/vdev/ !/var/tmp/zloop/*/vdev/
if-no-files-found: ignore if-no-files-found: ignore
- uses: actions/upload-artifact@v3 - uses: actions/upload-artifact@v2
if: failure() if: failure()
with: with:
name: Pool files name: Pool files

2
.gitmodules vendored
View File

@ -1,3 +1,3 @@
[submodule "scripts/zfs-images"] [submodule "scripts/zfs-images"]
path = scripts/zfs-images path = scripts/zfs-images
url = https://github.com/openzfs/zfs-images url = https://github.com/zfsonlinux/zfs-images

View File

@ -1,2 +1,2 @@
The [OpenZFS Code of Conduct](https://openzfs.org/wiki/Code_of_Conduct) The [OpenZFS Code of Conduct](http://www.open-zfs.org/wiki/Code_of_Conduct)
applies to spaces associated with the OpenZFS project, including GitHub. applies to spaces associated with the OpenZFS project, including GitHub.

6
META
View File

@ -1,10 +1,10 @@
Meta: 1 Meta: 1
Name: zfs Name: zfs
Branch: 1.0 Branch: 1.0
Version: 2.1.15 Version: 2.1.0
Release: 1 Release: rc1
Release-Tags: relext Release-Tags: relext
License: CDDL License: CDDL
Author: OpenZFS Author: OpenZFS
Linux-Maximum: 6.7 Linux-Maximum: 5.11
Linux-Minimum: 3.10 Linux-Minimum: 3.10

View File

@ -1,5 +1,3 @@
include $(top_srcdir)/config/Shellcheck.am
ACLOCAL_AMFLAGS = -I config ACLOCAL_AMFLAGS = -I config
SUBDIRS = include SUBDIRS = include
@ -8,7 +6,7 @@ SUBDIRS += rpm
endif endif
if CONFIG_USER if CONFIG_USER
SUBDIRS += man scripts lib tests cmd etc contrib SUBDIRS += etc man scripts lib tests cmd contrib
if BUILD_LINUX if BUILD_LINUX
SUBDIRS += udev SUBDIRS += udev
endif endif
@ -28,8 +26,8 @@ endif
AUTOMAKE_OPTIONS = foreign AUTOMAKE_OPTIONS = foreign
EXTRA_DIST = autogen.sh copy-builtin EXTRA_DIST = autogen.sh copy-builtin
EXTRA_DIST += config/config.awk config/rpm.am config/deb.am config/tgz.am EXTRA_DIST += config/config.awk config/rpm.am config/deb.am config/tgz.am
EXTRA_DIST += AUTHORS CODE_OF_CONDUCT.md COPYRIGHT LICENSE META NEWS NOTICE EXTRA_DIST += META AUTHORS COPYRIGHT LICENSE NEWS NOTICE README.md
EXTRA_DIST += README.md RELEASES.md EXTRA_DIST += CODE_OF_CONDUCT.md
EXTRA_DIST += module/lua/README.zfs module/os/linux/spl/README.md EXTRA_DIST += module/lua/README.zfs module/os/linux/spl/README.md
# Include all the extra licensing information for modules # Include all the extra licensing information for modules
@ -103,7 +101,7 @@ endif
endif endif
PHONY += codecheck PHONY += codecheck
codecheck: cstyle shellcheck checkbashisms flake8 mancheck testscheck vcscheck zstdcheck codecheck: cstyle shellcheck checkbashisms flake8 mancheck testscheck vcscheck
PHONY += checkstyle PHONY += checkstyle
checkstyle: codecheck commitcheck checkstyle: codecheck commitcheck
@ -114,47 +112,70 @@ commitcheck:
${top_srcdir}/scripts/commitcheck.sh; \ ${top_srcdir}/scripts/commitcheck.sh; \
fi fi
if HAVE_PARALLEL
cstyle_line = -print0 | parallel -X0 ${top_srcdir}/scripts/cstyle.pl -cpP {}
else
cstyle_line = -exec ${top_srcdir}/scripts/cstyle.pl -cpP {} +
endif
PHONY += cstyle PHONY += cstyle
cstyle: cstyle:
@find ${top_srcdir} -name build -prune \ @find ${top_srcdir} -name build -prune \
-o -type f -name '*.[hc]' \ -o -type f -name '*.[hc]' \
! -name 'zfs_config.*' ! -name '*.mod.c' \ ! -name 'zfs_config.*' ! -name '*.mod.c' \
! -name 'opt_global.h' ! -name '*_if*.h' \ ! -name 'opt_global.h' ! -name '*_if*.h' \
! -name 'zstd_compat_wrapper.h' \
! -path './module/zstd/lib/*' \ ! -path './module/zstd/lib/*' \
$(cstyle_line) -exec ${top_srcdir}/scripts/cstyle.pl -cpP {} \+
filter_executable = -exec test -x '{}' \; -print filter_executable = -exec test -x '{}' \; -print
SHELLCHECKDIRS = cmd contrib etc scripts tests PHONY += shellcheck
SHELLCHECKSCRIPTS = autogen.sh shellcheck:
@if type shellcheck > /dev/null 2>&1; then \
shellcheck --exclude=SC1090 --exclude=SC1117 --format=gcc \
$$(find ${top_srcdir}/scripts/*.sh -type f) \
$$(find ${top_srcdir}/cmd/zed/zed.d/*.sh -type f) \
$$(find ${top_srcdir}/cmd/zpool/zpool.d/* \
-type f ${filter_executable}); \
else \
echo "skipping shellcheck because shellcheck is not installed"; \
fi
PHONY += checkabi storeabi PHONY += checkabi storeabi
checkabi: lib
checklibabiversion:
libabiversion=`abidw -v | $(SED) 's/[^0-9]//g'`; \
if test $$libabiversion -lt "200"; then \
/bin/echo -e "\n" \
"*** Please use libabigail 2.0.0 version or newer;\n" \
"*** otherwise results are not consistent!\n" \
"(or see https://github.com/openzfs/libabigail-docker )\n"; \
exit 1; \
fi;
checkabi: checklibabiversion lib
$(MAKE) -C lib checkabi $(MAKE) -C lib checkabi
storeabi: checklibabiversion lib storeabi: lib
$(MAKE) -C lib storeabi $(MAKE) -C lib storeabi
PHONY += checkbashisms
checkbashisms:
@if type checkbashisms > /dev/null 2>&1; then \
checkbashisms -n -p -x \
$$(find ${top_srcdir} \
-name '.git' -prune \
-o -name 'build' -prune \
-o -name 'tests' -prune \
-o -name 'config' -prune \
-o -name 'zed-functions.sh*' -prune \
-o -name 'zfs-import*' -prune \
-o -name 'zfs-mount*' -prune \
-o -name 'zfs-zed*' -prune \
-o -name 'smart' -prune \
-o -name 'paxcheck.sh' -prune \
-o -name 'make_gitrev.sh' -prune \
-o -name '90zfs' -prune \
-o -type f ! -name 'config*' \
! -name 'libtool' \
-exec sh -c 'awk "NR==1 && /\#\!.*bin\/sh.*/ {print FILENAME;}" "{}"' \;); \
else \
echo "skipping checkbashisms because checkbashisms is not installed"; \
fi
PHONY += mancheck PHONY += mancheck
mancheck: mancheck:
${top_srcdir}/scripts/mancheck.sh ${top_srcdir}/man ${top_srcdir}/tests/test-runner/man @if type mandoc > /dev/null 2>&1; then \
find ${top_srcdir}/man/man8 -type f -name 'zfs.8' \
-o -name 'zpool.8' -o -name 'zdb.8' \
-o -name 'zgenhostid.8' | \
xargs mandoc -Tlint -Werror; \
else \
echo "skipping mancheck because mandoc is not installed"; \
fi
if BUILD_LINUX if BUILD_LINUX
stat_fmt = -c '%A %n' stat_fmt = -c '%A %n'
@ -179,10 +200,6 @@ vcscheck:
awk '{c++; print} END {if(c>0) exit 1}' ; \ awk '{c++; print} END {if(c>0) exit 1}' ; \
fi fi
PHONY += zstdcheck
zstdcheck:
@$(MAKE) -C module/zstd checksymbols
PHONY += lint PHONY += lint
lint: cppcheck paxcheck lint: cppcheck paxcheck

View File

@ -12,7 +12,7 @@ This repository contains the code for running OpenZFS on Linux and FreeBSD.
* [Documentation](https://openzfs.github.io/openzfs-docs/) - for using and developing this repo * [Documentation](https://openzfs.github.io/openzfs-docs/) - for using and developing this repo
* [ZoL Site](https://zfsonlinux.org) - Linux release info & links * [ZoL Site](https://zfsonlinux.org) - Linux release info & links
* [Mailing lists](https://openzfs.github.io/openzfs-docs/Project%20and%20Community/Mailing%20Lists.html) * [Mailing lists](https://openzfs.github.io/openzfs-docs/Project%20and%20Community/Mailing%20Lists.html)
* [OpenZFS site](https://openzfs.org/) - for conference videos and info on other platforms (illumos, OSX, Windows, etc) * [OpenZFS site](http://open-zfs.org/) - for conference videos and info on other platforms (illumos, OSX, Windows, etc)
# Installation # Installation

View File

@ -1,37 +0,0 @@
OpenZFS uses the MAJOR.MINOR.PATCH versioning scheme described here:
* MAJOR - Incremented at the discretion of the OpenZFS developers to indicate
a particularly noteworthy feature or change. An increase in MAJOR number
does not indicate any incompatible on-disk format change. The ability
to import a ZFS pool is controlled by the feature flags enabled on the
pool and the feature flags supported by the installed OpenZFS version.
Increasing the MAJOR version is expected to be an infrequent occurrence.
* MINOR - Incremented to indicate new functionality such as a new feature
flag, pool/dataset property, zfs/zpool sub-command, new user/kernel
interface, etc. MINOR releases may introduce incompatible changes to the
user space library APIs (libzfs.so). Existing user/kernel interfaces are
considered to be stable to maximize compatibility between OpenZFS releases.
Additions to the user/kernel interface are backwards compatible.
* PATCH - Incremented when applying documentation updates, important bug
fixes, minor performance improvements, and kernel compatibility patches.
The user space library APIs and user/kernel interface are considered to
be stable. PATCH releases for a MAJOR.MINOR are published as needed.
Two release branches are maintained for OpenZFS, they are:
* OpenZFS LTS - A designated MAJOR.MINOR release with periodic PATCH
releases that incorporate important changes backported from newer OpenZFS
releases. This branch is intended for use in environments using an
LTS, enterprise, or similarly managed kernel (RHEL, Ubuntu LTS, Debian).
Minor changes to support these distribution kernels will be applied as
needed. New kernel versions released after the OpenZFS LTS release are
not supported. LTS releases will receive patches for at least 2 years.
The current LTS release is OpenZFS 2.1.
* OpenZFS current - Tracks the newest MAJOR.MINOR release. This branch
includes support for the latest OpenZFS features and recently releases
kernels. When a new MINOR release is tagged the previous MINOR release
will no longer be maintained (unless it is an LTS release). New MINOR
releases are planned to occur roughly annually.

View File

@ -1,15 +1,10 @@
include $(top_srcdir)/config/Shellcheck.am SUBDIRS = zfs zpool zdb zhack zinject zstream zstreamdump ztest
SUBDIRS = zfs zpool zdb zhack zinject zstream ztest
SUBDIRS += fsck_zfs vdev_id raidz_test zfs_ids_to_path SUBDIRS += fsck_zfs vdev_id raidz_test zfs_ids_to_path
SUBDIRS += zpool_influxdb SUBDIRS += zpool_influxdb
CPPCHECKDIRS = zfs zpool zdb zhack zinject zstream ztest CPPCHECKDIRS = zfs zpool zdb zhack zinject zstream ztest
CPPCHECKDIRS += raidz_test zfs_ids_to_path zpool_influxdb CPPCHECKDIRS += raidz_test zfs_ids_to_path zpool_influxdb
# TODO: #12084: SHELLCHECKDIRS = fsck_zfs vdev_id zpool
SHELLCHECKDIRS = fsck_zfs zpool
if USING_PYTHON if USING_PYTHON
SUBDIRS += arcstat arc_summary dbufstat SUBDIRS += arcstat arc_summary dbufstat
endif endif
@ -17,7 +12,6 @@ endif
if BUILD_LINUX if BUILD_LINUX
SUBDIRS += mount_zfs zed zgenhostid zvol_id zvol_wait SUBDIRS += mount_zfs zed zgenhostid zvol_id zvol_wait
CPPCHECKDIRS += mount_zfs zed zgenhostid zvol_id CPPCHECKDIRS += mount_zfs zed zgenhostid zvol_id
SHELLCHECKDIRS += zed
endif endif
PHONY = cppcheck PHONY = cppcheck

View File

@ -1,8 +1,13 @@
bin_SCRIPTS = arc_summary bin_SCRIPTS = arc_summary
CLEANFILES = arc_summary CLEANFILES = arc_summary
EXTRA_DIST = arc_summary3 EXTRA_DIST = arc_summary2 arc_summary3
if USING_PYTHON_2
SCRIPT = arc_summary2
else
SCRIPT = arc_summary3 SCRIPT = arc_summary3
endif
arc_summary: $(SCRIPT) arc_summary: $(SCRIPT)
cp $< $@ cp $< $@

1185
cmd/arc_summary/arc_summary2 Executable file

File diff suppressed because it is too large Load Diff

View File

@ -42,13 +42,6 @@ import os
import subprocess import subprocess
import sys import sys
import time import time
import errno
# We can't use env -S portably, and we need python3 -u to handle pipes in
# the shell abruptly closing the way we want to, so...
import io
if isinstance(sys.__stderr__.buffer, io.BufferedWriter):
os.execv(sys.executable, [sys.executable, "-u"] + sys.argv)
DESCRIPTION = 'Print ARC and other statistics for OpenZFS' DESCRIPTION = 'Print ARC and other statistics for OpenZFS'
INDENT = ' '*8 INDENT = ' '*8
@ -168,11 +161,21 @@ elif sys.platform.startswith('linux'):
# The original arc_summary called /sbin/modinfo/{spl,zfs} to get # The original arc_summary called /sbin/modinfo/{spl,zfs} to get
# the version information. We switch to /sys/module/{spl,zfs}/version # the version information. We switch to /sys/module/{spl,zfs}/version
# to make sure we get what is really loaded in the kernel # to make sure we get what is really loaded in the kernel
try: command = ["cat", "/sys/module/{0}/version".format(request)]
with open("/sys/module/{}/version".format(request)) as f: req = request.upper()
return f.read().strip()
except: # The recommended way to do this is with subprocess.run(). However,
return "(unknown)" # some installed versions of Python are < 3.5, so we offer them
# the option of doing it the old way (for now)
if 'run' in dir(subprocess):
info = subprocess.run(command, stdout=subprocess.PIPE,
universal_newlines=True)
version = info.stdout.strip()
else:
info = subprocess.check_output(command, universal_newlines=True)
version = info.strip()
return version
def get_descriptions(request): def get_descriptions(request):
"""Get the descriptions of the Solaris Porting Layer (SPL) or the """Get the descriptions of the Solaris Porting Layer (SPL) or the
@ -191,13 +194,21 @@ elif sys.platform.startswith('linux'):
# there, so we fall back on modinfo # there, so we fall back on modinfo
command = ["/sbin/modinfo", request, "-0"] command = ["/sbin/modinfo", request, "-0"]
# The recommended way to do this is with subprocess.run(). However,
# some installed versions of Python are < 3.5, so we offer them
# the option of doing it the old way (for now)
info = '' info = ''
try: try:
if 'run' in dir(subprocess):
info = subprocess.run(command, stdout=subprocess.PIPE, info = subprocess.run(command, stdout=subprocess.PIPE,
check=True, universal_newlines=True) universal_newlines=True)
raw_output = info.stdout.split('\0') raw_output = info.stdout.split('\0')
else:
info = subprocess.check_output(command,
universal_newlines=True)
raw_output = info.split('\0')
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
print("Error: Descriptions not available", print("Error: Descriptions not available",
@ -220,29 +231,6 @@ elif sys.platform.startswith('linux'):
return descs return descs
def handle_unraisableException(exc_type, exc_value=None, exc_traceback=None,
err_msg=None, object=None):
handle_Exception(exc_type, object, exc_traceback)
def handle_Exception(ex_cls, ex, tb):
if ex_cls is KeyboardInterrupt:
sys.exit()
if ex_cls is BrokenPipeError:
# It turns out that while sys.exit() triggers an exception
# not handled message on Python 3.8+, os._exit() does not.
os._exit(0)
if ex_cls is OSError:
if ex.errno == errno.ENOTCONN:
sys.exit()
raise ex
if hasattr(sys,'unraisablehook'): # Python 3.8+
sys.unraisablehook = handle_unraisableException
sys.excepthook = handle_Exception
def cleanup_line(single_line): def cleanup_line(single_line):
"""Format a raw line of data from /proc and isolate the name value """Format a raw line of data from /proc and isolate the name value
@ -678,9 +666,9 @@ def section_archits(kstats_dict):
print() print()
print('Cache hits by data type:') print('Cache hits by data type:')
dt_todo = (('Demand data:', arc_stats['demand_data_hits']), dt_todo = (('Demand data:', arc_stats['demand_data_hits']),
('Prefetch data:', arc_stats['prefetch_data_hits']), ('Demand prefetch data:', arc_stats['prefetch_data_hits']),
('Demand metadata:', arc_stats['demand_metadata_hits']), ('Demand metadata:', arc_stats['demand_metadata_hits']),
('Prefetch metadata:', ('Demand prefetch metadata:',
arc_stats['prefetch_metadata_hits'])) arc_stats['prefetch_metadata_hits']))
for title, value in dt_todo: for title, value in dt_todo:
@ -689,10 +677,10 @@ def section_archits(kstats_dict):
print() print()
print('Cache misses by data type:') print('Cache misses by data type:')
dm_todo = (('Demand data:', arc_stats['demand_data_misses']), dm_todo = (('Demand data:', arc_stats['demand_data_misses']),
('Prefetch data:', ('Demand prefetch data:',
arc_stats['prefetch_data_misses']), arc_stats['prefetch_data_misses']),
('Demand metadata:', arc_stats['demand_metadata_misses']), ('Demand metadata:', arc_stats['demand_metadata_misses']),
('Prefetch metadata:', ('Demand prefetch metadata:',
arc_stats['prefetch_metadata_misses'])) arc_stats['prefetch_metadata_misses']))
for title, value in dm_todo: for title, value in dm_todo:

View File

@ -47,7 +47,7 @@
# @hdr is the array of fields that needs to be printed, so we # @hdr is the array of fields that needs to be printed, so we
# just iterate over this array and print the values using our pretty printer. # just iterate over this array and print the values using our pretty printer.
# #
# This script must remain compatible with Python 3.6+. # This script must remain compatible with Python 2.6+ and Python 3.4+.
# #
import sys import sys
@ -271,7 +271,7 @@ def print_values():
if pretty_print: if pretty_print:
fmt = lambda col: prettynum(cols[col][0], cols[col][1], v[col]) fmt = lambda col: prettynum(cols[col][0], cols[col][1], v[col])
else: else:
fmt = lambda col: str(v[col]) fmt = lambda col: v[col]
sys.stdout.write(sep.join(fmt(col) for col in hdr)) sys.stdout.write(sep.join(fmt(col) for col in hdr))
sys.stdout.write("\n") sys.stdout.write("\n")

View File

@ -27,7 +27,7 @@
# Copyright (C) 2013 Lawrence Livermore National Security, LLC. # Copyright (C) 2013 Lawrence Livermore National Security, LLC.
# Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). # Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
# #
# This script must remain compatible with and Python 3.6+. # This script must remain compatible with Python 2.6+ and Python 3.4+.
# #
import sys import sys

View File

@ -1 +0,0 @@
/fsck.zfs

View File

@ -1,6 +1 @@
include $(top_srcdir)/config/Substfiles.am
include $(top_srcdir)/config/Shellcheck.am
dist_sbin_SCRIPTS = fsck.zfs dist_sbin_SCRIPTS = fsck.zfs
SUBSTFILES += $(dist_sbin_SCRIPTS)

9
cmd/fsck_zfs/fsck.zfs Executable file
View File

@ -0,0 +1,9 @@
#!/bin/sh
#
# fsck.zfs: A fsck helper to accommodate distributions that expect
# to be able to execute a fsck on all filesystem types. Currently
# this script does nothing but it could be extended to act as a
# compatibility wrapper for 'zpool scrub'.
#
exit 0

View File

@ -1,44 +0,0 @@
#!/bin/sh
#
# fsck.zfs: A fsck helper to accommodate distributions that expect
# to be able to execute a fsck on all filesystem types.
#
# This script simply bubbles up some already-known-about errors,
# see fsck.zfs(8)
#
if [ "$#" = "0" ]; then
echo "Usage: $0 [options] dataset…" >&2
exit 16
fi
ret=0
for dataset in "$@"; do
case "$dataset" in
-*)
continue
;;
*)
;;
esac
pool="${dataset%%/*}"
case "$(@sbindir@/zpool list -Ho health "$pool")" in
DEGRADED)
ret=$(( ret | 4 ))
;;
FAULTED)
awk '!/^([[:space:]]*#.*)?$/ && $1 == "'"$dataset"'" && $3 == "zfs" {exit 1}' /etc/fstab || \
ret=$(( ret | 8 ))
;;
"")
# Pool not found, error printed by zpool(8)
ret=$(( ret | 8 ))
;;
*)
;;
esac
done
exit "$ret"

View File

@ -185,11 +185,10 @@ main(int argc, char **argv)
break; break;
case 'h': case 'h':
case '?': case '?':
if (optopt) (void) fprintf(stderr, gettext("Invalid option '%c'\n"),
(void) fprintf(stderr, optopt);
gettext("Invalid option '%c'\n"), optopt);
(void) fprintf(stderr, gettext("Usage: mount.zfs " (void) fprintf(stderr, gettext("Usage: mount.zfs "
"[-sfnvh] [-o options] <dataset> <mountpoint>\n")); "[-sfnv] [-o options] <dataset> <mountpoint>\n"));
return (MOUNT_USAGE); return (MOUNT_USAGE);
} }
} }
@ -246,6 +245,13 @@ main(int argc, char **argv)
} }
} }
if (verbose)
(void) fprintf(stdout, gettext("mount.zfs:\n"
" dataset: \"%s\"\n mountpoint: \"%s\"\n"
" mountflags: 0x%lx\n zfsflags: 0x%lx\n"
" mountopts: \"%s\"\n mtabopts: \"%s\"\n"),
dataset, mntpoint, mntflags, zfsflags, mntopts, mtabopt);
if (mntflags & MS_REMOUNT) { if (mntflags & MS_REMOUNT) {
nomtab = 1; nomtab = 1;
remount = 1; remount = 1;
@ -268,10 +274,7 @@ main(int argc, char **argv)
return (MOUNT_USAGE); return (MOUNT_USAGE);
} }
if (!zfsutil || sloppy ||
libzfs_envvar_is_set("ZFS_MOUNT_HELPER")) {
zfs_adjust_mount_options(zhp, mntpoint, mntopts, mtabopt); zfs_adjust_mount_options(zhp, mntpoint, mntopts, mtabopt);
}
/* treat all snapshots as legacy mount points */ /* treat all snapshots as legacy mount points */
if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT)
@ -289,11 +292,12 @@ main(int argc, char **argv)
if (zfs_version == 0) { if (zfs_version == 0) {
fprintf(stderr, gettext("unable to fetch " fprintf(stderr, gettext("unable to fetch "
"ZFS version for filesystem '%s'\n"), dataset); "ZFS version for filesystem '%s'\n"), dataset);
zfs_close(zhp);
libzfs_fini(g_zfs);
return (MOUNT_SYSERR); return (MOUNT_SYSERR);
} }
zfs_close(zhp);
libzfs_fini(g_zfs);
/* /*
* Legacy mount points may only be mounted using 'mount', never using * Legacy mount points may only be mounted using 'mount', never using
* 'zfs mount'. However, since 'zfs mount' actually invokes 'mount' * 'zfs mount'. However, since 'zfs mount' actually invokes 'mount'
@ -311,8 +315,6 @@ main(int argc, char **argv)
"Use 'zfs set mountpoint=%s' or 'mount -t zfs %s %s'.\n" "Use 'zfs set mountpoint=%s' or 'mount -t zfs %s %s'.\n"
"See zfs(8) for more information.\n"), "See zfs(8) for more information.\n"),
dataset, mntpoint, dataset, mntpoint); dataset, mntpoint, dataset, mntpoint);
zfs_close(zhp);
libzfs_fini(g_zfs);
return (MOUNT_USAGE); return (MOUNT_USAGE);
} }
@ -323,37 +325,13 @@ main(int argc, char **argv)
"Use 'zfs set mountpoint=%s' or 'zfs mount %s'.\n" "Use 'zfs set mountpoint=%s' or 'zfs mount %s'.\n"
"See zfs(8) for more information.\n"), "See zfs(8) for more information.\n"),
dataset, "legacy", dataset); dataset, "legacy", dataset);
zfs_close(zhp);
libzfs_fini(g_zfs);
return (MOUNT_USAGE); return (MOUNT_USAGE);
} }
if (verbose)
(void) fprintf(stdout, gettext("mount.zfs:\n"
" dataset: \"%s\"\n mountpoint: \"%s\"\n"
" mountflags: 0x%lx\n zfsflags: 0x%lx\n"
" mountopts: \"%s\"\n mtabopts: \"%s\"\n"),
dataset, mntpoint, mntflags, zfsflags, mntopts, mtabopt);
if (!fake) { if (!fake) {
if (zfsutil && !sloppy &&
!libzfs_envvar_is_set("ZFS_MOUNT_HELPER")) {
error = zfs_mount_at(zhp, mntopts, mntflags, mntpoint);
if (error) {
(void) fprintf(stderr, "zfs_mount_at() failed: "
"%s", libzfs_error_description(g_zfs));
zfs_close(zhp);
libzfs_fini(g_zfs);
return (MOUNT_SYSERR);
}
} else {
error = mount(dataset, mntpoint, MNTTYPE_ZFS, error = mount(dataset, mntpoint, MNTTYPE_ZFS,
mntflags, mntopts); mntflags, mntopts);
} }
}
zfs_close(zhp);
libzfs_fini(g_zfs);
if (error) { if (error) {
switch (errno) { switch (errno) {
@ -389,7 +367,7 @@ main(int argc, char **argv)
"mount the filesystem again.\n"), dataset); "mount the filesystem again.\n"), dataset);
return (MOUNT_SYSERR); return (MOUNT_SYSERR);
} }
fallthrough; /* fallthru */
#endif #endif
default: default:
(void) fprintf(stderr, gettext("filesystem " (void) fprintf(stderr, gettext("filesystem "

View File

@ -1,3 +1 @@
include $(top_srcdir)/config/Shellcheck.am
dist_udev_SCRIPTS = vdev_id dist_udev_SCRIPTS = vdev_id

View File

@ -140,17 +140,15 @@ Usage: vdev_id [-h]
-p number of phy's per switch port [default=$PHYS_PER_PORT] -p number of phy's per switch port [default=$PHYS_PER_PORT]
-h show this summary -h show this summary
EOF EOF
exit 1 exit 0
# exit with error to avoid processing usage message by a udev rule
} }
map_slot() { map_slot() {
LINUX_SLOT=$1 LINUX_SLOT=$1
CHANNEL=$2 CHANNEL=$2
MAPPED_SLOT=$(awk -v linux_slot="$LINUX_SLOT" -v channel="$CHANNEL" \ MAPPED_SLOT=$(awk '$1 == "slot" && $2 == "${LINUX_SLOT}" && \
'$1 == "slot" && $2 == linux_slot && \ $4 ~ /^${CHANNEL}$|^$/ { print $3; exit}' $CONFIG)
($4 ~ "^"channel"$" || $4 ~ /^$/) { print $3; exit}' $CONFIG)
if [ -z "$MAPPED_SLOT" ] ; then if [ -z "$MAPPED_SLOT" ] ; then
MAPPED_SLOT=$LINUX_SLOT MAPPED_SLOT=$LINUX_SLOT
fi fi
@ -165,7 +163,7 @@ map_channel() {
case $TOPOLOGY in case $TOPOLOGY in
"sas_switch") "sas_switch")
MAPPED_CHAN=$(awk -v port="$PORT" \ MAPPED_CHAN=$(awk -v port="$PORT" \
'$1 == "channel" && $2 == port \ '$1 == "channel" && $2 == ${PORT} \
{ print $3; exit }' $CONFIG) { print $3; exit }' $CONFIG)
;; ;;
"sas_direct"|"scsi") "sas_direct"|"scsi")
@ -375,7 +373,7 @@ sas_handler() {
i=$((i + 1)) i=$((i + 1))
done done
PHY=$(ls -vd "$port_dir"/phy* 2>/dev/null | head -1 | awk -F: '{print $NF}') PHY=$(ls -d "$port_dir"/phy* 2>/dev/null | head -1 | awk -F: '{print $NF}')
if [ -z "$PHY" ] ; then if [ -z "$PHY" ] ; then
PHY=0 PHY=0
fi fi
@ -596,9 +594,7 @@ enclosure_handler () {
# DEVPATH=/sys/devices/pci0000:00/0000:00:03.0/0000:05:00.0/host0/subsystem/devices/0:0:0:0/scsi_generic/sg0 # DEVPATH=/sys/devices/pci0000:00/0000:00:03.0/0000:05:00.0/host0/subsystem/devices/0:0:0:0/scsi_generic/sg0
# Get the enclosure ID ("0:0:0:0") # Get the enclosure ID ("0:0:0:0")
ENC="${DEVPATH%/*}" ENC=$(basename $(readlink -m "/sys/$DEVPATH/../.."))
ENC="${ENC%/*}"
ENC="${ENC##*/}"
if [ ! -d "/sys/class/enclosure/$ENC" ] ; then if [ ! -d "/sys/class/enclosure/$ENC" ] ; then
# Not an enclosure, bail out # Not an enclosure, bail out
return return
@ -618,15 +614,14 @@ enclosure_handler () {
# The PCI directory is two directories up from the port directory # The PCI directory is two directories up from the port directory
# /sys/devices/pci0000:00/0000:00:03.0/0000:05:00.0 # /sys/devices/pci0000:00/0000:00:03.0/0000:05:00.0
PCI_ID_LONG="$(readlink -m "/sys/$PORT_DIR/../..")" PCI_ID_LONG=$(basename $(readlink -m "/sys/$PORT_DIR/../.."))
PCI_ID_LONG="${PCI_ID_LONG##*/}"
# Strip down the PCI address from 0000:05:00.0 to 05:00.0 # Strip down the PCI address from 0000:05:00.0 to 05:00.0
PCI_ID="${PCI_ID_LONG#[0-9]*:}" PCI_ID=$(echo "$PCI_ID_LONG" | sed -r 's/^[0-9]+://g')
# Name our device according to vdev_id.conf (like "L0" or "U1"). # Name our device according to vdev_id.conf (like "L0" or "U1").
NAME=$(awk "/channel/{if (\$1 == \"channel\" && \$2 == \"$PCI_ID\" && \ NAME=$(awk '/channel/{if ($1 == "channel" && $2 == "$PCI_ID" && \
\$3 == \"$PORT_ID\") {print \$4\$3}}" $CONFIG) $3 == "$PORT_ID") {print ${4}int(count[$4])}; count[$4]++}' $CONFIG)
echo "${NAME}" echo "${NAME}"
} }
@ -677,7 +672,7 @@ alias_handler () {
link=$(echo "$link" | sed 's/p[0-9][0-9]*$//') link=$(echo "$link" | sed 's/p[0-9][0-9]*$//')
fi fi
# Check both the fully qualified and the base name of link. # Check both the fully qualified and the base name of link.
for l in $link ${link##*/} ; do for l in $link $(basename "$link") ; do
if [ ! -z "$l" ]; then if [ ! -z "$l" ]; then
alias=$(awk -v var="$l" '($1 == "alias") && \ alias=$(awk -v var="$l" '($1 == "alias") && \
($3 == var) \ ($3 == var) \
@ -732,7 +727,7 @@ done
if [ ! -r "$CONFIG" ] ; then if [ ! -r "$CONFIG" ] ; then
echo "Error: Config file \"$CONFIG\" not found" echo "Error: Config file \"$CONFIG\" not found"
exit 1 exit 0
fi fi
if [ -z "$DEV" ] && [ -z "$ENCLOSURE_MODE" ] ; then if [ -z "$DEV" ] && [ -z "$ENCLOSURE_MODE" ] ; then

View File

@ -110,9 +110,8 @@ extern int zfs_recover;
extern unsigned long zfs_arc_meta_min, zfs_arc_meta_limit; extern unsigned long zfs_arc_meta_min, zfs_arc_meta_limit;
extern int zfs_vdev_async_read_max_active; extern int zfs_vdev_async_read_max_active;
extern boolean_t spa_load_verify_dryrun; extern boolean_t spa_load_verify_dryrun;
extern boolean_t spa_mode_readable_spacemaps;
extern int zfs_reconstruct_indirect_combinations_max; extern int zfs_reconstruct_indirect_combinations_max;
extern uint_t zfs_btree_verify_intensity; extern int zfs_btree_verify_intensity;
static const char cmdname[] = "zdb"; static const char cmdname[] = "zdb";
uint8_t dump_opt[256]; uint8_t dump_opt[256];
@ -163,6 +162,12 @@ static int dump_bpobj_cb(void *arg, const blkptr_t *bp, boolean_t free,
dmu_tx_t *tx); dmu_tx_t *tx);
typedef struct sublivelist_verify { typedef struct sublivelist_verify {
/* all ALLOC'd blkptr_t in one sub-livelist */
zfs_btree_t sv_all_allocs;
/* all FREE'd blkptr_t in one sub-livelist */
zfs_btree_t sv_all_frees;
/* FREE's that haven't yet matched to an ALLOC, in one sub-livelist */ /* FREE's that haven't yet matched to an ALLOC, in one sub-livelist */
zfs_btree_t sv_pair; zfs_btree_t sv_pair;
@ -221,68 +226,29 @@ typedef struct sublivelist_verify_block {
static void zdb_print_blkptr(const blkptr_t *bp, int flags); static void zdb_print_blkptr(const blkptr_t *bp, int flags);
typedef struct sublivelist_verify_block_refcnt {
/* block pointer entry in livelist being verified */
blkptr_t svbr_blk;
/*
* Refcount gets incremented to 1 when we encounter the first
* FREE entry for the svfbr block pointer and a node for it
* is created in our ZDB verification/tracking metadata.
*
* As we encounter more FREE entries we increment this counter
* and similarly decrement it whenever we find the respective
* ALLOC entries for this block.
*
* When the refcount gets to 0 it means that all the FREE and
* ALLOC entries of this block have paired up and we no longer
* need to track it in our verification logic (e.g. the node
* containing this struct in our verification data structure
* should be freed).
*
* [refer to sublivelist_verify_blkptr() for the actual code]
*/
uint32_t svbr_refcnt;
} sublivelist_verify_block_refcnt_t;
static int
sublivelist_block_refcnt_compare(const void *larg, const void *rarg)
{
const sublivelist_verify_block_refcnt_t *l = larg;
const sublivelist_verify_block_refcnt_t *r = rarg;
return (livelist_compare(&l->svbr_blk, &r->svbr_blk));
}
static int static int
sublivelist_verify_blkptr(void *arg, const blkptr_t *bp, boolean_t free, sublivelist_verify_blkptr(void *arg, const blkptr_t *bp, boolean_t free,
dmu_tx_t *tx) dmu_tx_t *tx)
{ {
ASSERT3P(tx, ==, NULL); ASSERT3P(tx, ==, NULL);
struct sublivelist_verify *sv = arg; struct sublivelist_verify *sv = arg;
sublivelist_verify_block_refcnt_t current = { char blkbuf[BP_SPRINTF_LEN];
.svbr_blk = *bp,
/*
* Start with 1 in case this is the first free entry.
* This field is not used for our B-Tree comparisons
* anyway.
*/
.svbr_refcnt = 1,
};
zfs_btree_index_t where; zfs_btree_index_t where;
sublivelist_verify_block_refcnt_t *pair =
zfs_btree_find(&sv->sv_pair, &current, &where);
if (free) { if (free) {
if (pair == NULL) { zfs_btree_add(&sv->sv_pair, bp);
/* first free entry for this block pointer */ /* Check if the FREE is a duplicate */
zfs_btree_add(&sv->sv_pair, &current); if (zfs_btree_find(&sv->sv_all_frees, bp, &where) != NULL) {
snprintf_blkptr_compact(blkbuf, sizeof (blkbuf), bp,
free);
(void) printf("\tERROR: Duplicate FREE: %s\n", blkbuf);
} else { } else {
pair->svbr_refcnt++; zfs_btree_add_idx(&sv->sv_all_frees, bp, &where);
} }
} else { } else {
if (pair == NULL) { /* Check if the ALLOC has been freed */
/* block that is currently marked as allocated */ if (zfs_btree_find(&sv->sv_pair, bp, &where) != NULL) {
zfs_btree_remove_idx(&sv->sv_pair, &where);
} else {
for (int i = 0; i < SPA_DVAS_PER_BP; i++) { for (int i = 0; i < SPA_DVAS_PER_BP; i++) {
if (DVA_IS_EMPTY(&bp->blk_dva[i])) if (DVA_IS_EMPTY(&bp->blk_dva[i]))
break; break;
@ -297,16 +263,16 @@ sublivelist_verify_blkptr(void *arg, const blkptr_t *bp, boolean_t free,
&svb, &where); &svb, &where);
} }
} }
}
/* Check if the ALLOC is a duplicate */
if (zfs_btree_find(&sv->sv_all_allocs, bp, &where) != NULL) {
snprintf_blkptr_compact(blkbuf, sizeof (blkbuf), bp,
free);
(void) printf("\tERROR: Duplicate ALLOC: %s\n", blkbuf);
} else { } else {
/* alloc matches a free entry */ zfs_btree_add_idx(&sv->sv_all_allocs, bp, &where);
pair->svbr_refcnt--;
if (pair->svbr_refcnt == 0) {
/* all allocs and frees have been matched */
zfs_btree_remove_idx(&sv->sv_pair, &where);
} }
} }
}
return (0); return (0);
} }
@ -314,22 +280,32 @@ static int
sublivelist_verify_func(void *args, dsl_deadlist_entry_t *dle) sublivelist_verify_func(void *args, dsl_deadlist_entry_t *dle)
{ {
int err; int err;
char blkbuf[BP_SPRINTF_LEN];
struct sublivelist_verify *sv = args; struct sublivelist_verify *sv = args;
zfs_btree_create(&sv->sv_pair, sublivelist_block_refcnt_compare, zfs_btree_create(&sv->sv_all_allocs, livelist_compare,
sizeof (sublivelist_verify_block_refcnt_t)); sizeof (blkptr_t));
zfs_btree_create(&sv->sv_all_frees, livelist_compare,
sizeof (blkptr_t));
zfs_btree_create(&sv->sv_pair, livelist_compare,
sizeof (blkptr_t));
err = bpobj_iterate_nofree(&dle->dle_bpobj, sublivelist_verify_blkptr, err = bpobj_iterate_nofree(&dle->dle_bpobj, sublivelist_verify_blkptr,
sv, NULL); sv, NULL);
sublivelist_verify_block_refcnt_t *e; zfs_btree_clear(&sv->sv_all_allocs);
zfs_btree_destroy(&sv->sv_all_allocs);
zfs_btree_clear(&sv->sv_all_frees);
zfs_btree_destroy(&sv->sv_all_frees);
blkptr_t *e;
zfs_btree_index_t *cookie = NULL; zfs_btree_index_t *cookie = NULL;
while ((e = zfs_btree_destroy_nodes(&sv->sv_pair, &cookie)) != NULL) { while ((e = zfs_btree_destroy_nodes(&sv->sv_pair, &cookie)) != NULL) {
char blkbuf[BP_SPRINTF_LEN]; snprintf_blkptr_compact(blkbuf, sizeof (blkbuf), e, B_TRUE);
snprintf_blkptr_compact(blkbuf, sizeof (blkbuf), (void) printf("\tERROR: Unmatched FREE: %s\n", blkbuf);
&e->svbr_blk, B_TRUE);
(void) printf("\tERROR: %d unmatched FREE(s): %s\n",
e->svbr_refcnt, blkbuf);
} }
zfs_btree_destroy(&sv->sv_pair); zfs_btree_destroy(&sv->sv_pair);
@ -638,14 +614,10 @@ mv_populate_livelist_allocs(metaslab_verify_t *mv, sublivelist_verify_t *sv)
/* /*
* [Livelist Check] * [Livelist Check]
* Iterate through all the sublivelists and: * Iterate through all the sublivelists and:
* - report leftover frees (**) * - report leftover frees
* - report double ALLOCs/FREEs
* - record leftover ALLOCs together with their TXG [see Cross Check] * - record leftover ALLOCs together with their TXG [see Cross Check]
* *
* (**) Note: Double ALLOCs are valid in datasets that have dedup
* enabled. Similarly double FREEs are allowed as well but
* only if they pair up with a corresponding ALLOC entry once
* we our done with our sublivelist iteration.
*
* [Spacemap Check] * [Spacemap Check]
* for each metaslab: * for each metaslab:
* - iterate over spacemap and then the metaslab's entries in the * - iterate over spacemap and then the metaslab's entries in the
@ -2219,8 +2191,7 @@ snprintf_zstd_header(spa_t *spa, char *blkbuf, size_t buflen,
(void) snprintf(blkbuf + strlen(blkbuf), (void) snprintf(blkbuf + strlen(blkbuf),
buflen - strlen(blkbuf), buflen - strlen(blkbuf),
" ZSTD:size=%u:version=%u:level=%u:EMBEDDED", " ZSTD:size=%u:version=%u:level=%u:EMBEDDED",
zstd_hdr.c_len, zfs_get_hdrversion(&zstd_hdr), zstd_hdr.c_len, zstd_hdr.version, zstd_hdr.level);
zfs_get_hdrlevel(&zstd_hdr));
return; return;
} }
@ -2244,8 +2215,7 @@ snprintf_zstd_header(spa_t *spa, char *blkbuf, size_t buflen,
(void) snprintf(blkbuf + strlen(blkbuf), (void) snprintf(blkbuf + strlen(blkbuf),
buflen - strlen(blkbuf), buflen - strlen(blkbuf),
" ZSTD:size=%u:version=%u:level=%u:NORMAL", " ZSTD:size=%u:version=%u:level=%u:NORMAL",
zstd_hdr.c_len, zfs_get_hdrversion(&zstd_hdr), zstd_hdr.c_len, zstd_hdr.version, zstd_hdr.level);
zfs_get_hdrlevel(&zstd_hdr));
abd_return_buf_copy(pabd, buf, BP_GET_LSIZE(bp)); abd_return_buf_copy(pabd, buf, BP_GET_LSIZE(bp));
} }
@ -2995,7 +2965,7 @@ open_objset(const char *path, void *tag, objset_t **osp)
} }
sa_os = *osp; sa_os = *osp;
return (err); return (0);
} }
static void static void
@ -3102,22 +3072,13 @@ dump_znode_sa_xattr(sa_handle_t *hdl)
(void) printf("\tSA xattrs: %d bytes, %d entries\n\n", (void) printf("\tSA xattrs: %d bytes, %d entries\n\n",
sa_xattr_size, sa_xattr_entries); sa_xattr_size, sa_xattr_entries);
while ((elem = nvlist_next_nvpair(sa_xattr, elem)) != NULL) { while ((elem = nvlist_next_nvpair(sa_xattr, elem)) != NULL) {
boolean_t can_print = !dump_opt['P'];
uchar_t *value; uchar_t *value;
uint_t cnt, idx; uint_t cnt, idx;
(void) printf("\t\t%s = ", nvpair_name(elem)); (void) printf("\t\t%s = ", nvpair_name(elem));
nvpair_value_byte_array(elem, &value, &cnt); nvpair_value_byte_array(elem, &value, &cnt);
for (idx = 0; idx < cnt; ++idx) { for (idx = 0; idx < cnt; ++idx) {
if (!isprint(value[idx])) { if (isprint(value[idx]))
can_print = B_FALSE;
break;
}
}
for (idx = 0; idx < cnt; ++idx) {
if (can_print)
(void) putchar(value[idx]); (void) putchar(value[idx]);
else else
(void) printf("\\%3.3o", value[idx]); (void) printf("\\%3.3o", value[idx]);
@ -3134,18 +3095,13 @@ dump_znode_symlink(sa_handle_t *hdl)
{ {
int sa_symlink_size = 0; int sa_symlink_size = 0;
char linktarget[MAXPATHLEN]; char linktarget[MAXPATHLEN];
linktarget[0] = '\0';
int error; int error;
error = sa_size(hdl, sa_attr_table[ZPL_SYMLINK], &sa_symlink_size); error = sa_size(hdl, sa_attr_table[ZPL_SYMLINK], &sa_symlink_size);
if (error || sa_symlink_size == 0) { if (error || sa_symlink_size == 0) {
return; return;
} }
if (sa_symlink_size >= sizeof (linktarget)) {
(void) printf("symlink size %d is too large\n",
sa_symlink_size);
return;
}
linktarget[sa_symlink_size] = '\0';
if (sa_lookup(hdl, sa_attr_table[ZPL_SYMLINK], if (sa_lookup(hdl, sa_attr_table[ZPL_SYMLINK],
&linktarget, sa_symlink_size) == 0) &linktarget, sa_symlink_size) == 0)
(void) printf("\ttarget %s\n", linktarget); (void) printf("\ttarget %s\n", linktarget);
@ -4111,7 +4067,7 @@ cksum_record_compare(const void *x1, const void *x2)
const cksum_record_t *l = (cksum_record_t *)x1; const cksum_record_t *l = (cksum_record_t *)x1;
const cksum_record_t *r = (cksum_record_t *)x2; const cksum_record_t *r = (cksum_record_t *)x2;
int arraysize = ARRAY_SIZE(l->cksum.zc_word); int arraysize = ARRAY_SIZE(l->cksum.zc_word);
int difference = 0; int difference;
for (int i = 0; i < arraysize; i++) { for (int i = 0; i < arraysize; i++) {
difference = TREE_CMP(l->cksum.zc_word[i], r->cksum.zc_word[i]); difference = TREE_CMP(l->cksum.zc_word[i], r->cksum.zc_word[i]);
@ -4588,7 +4544,7 @@ dump_path_impl(objset_t *os, uint64_t obj, char *name, uint64_t *retobj)
case DMU_OT_DIRECTORY_CONTENTS: case DMU_OT_DIRECTORY_CONTENTS:
if (s != NULL && *(s + 1) != '\0') if (s != NULL && *(s + 1) != '\0')
return (dump_path_impl(os, child_obj, s + 1, retobj)); return (dump_path_impl(os, child_obj, s + 1, retobj));
fallthrough; /*FALLTHROUGH*/
case DMU_OT_PLAIN_FILE_CONTENTS: case DMU_OT_PLAIN_FILE_CONTENTS:
if (retobj != NULL) { if (retobj != NULL) {
*retobj = child_obj; *retobj = child_obj;
@ -4815,7 +4771,7 @@ dump_label(const char *dev)
if (nvlist_size(config, &size, NV_ENCODE_XDR) != 0) if (nvlist_size(config, &size, NV_ENCODE_XDR) != 0)
size = buflen; size = buflen;
/* If the device is a cache device read the header. */ /* If the device is a cache device clear the header. */
if (!read_l2arc_header) { if (!read_l2arc_header) {
if (nvlist_lookup_uint64(config, if (nvlist_lookup_uint64(config,
ZPOOL_CONFIG_POOL_STATE, &l2cache) == 0 && ZPOOL_CONFIG_POOL_STATE, &l2cache) == 0 &&
@ -5976,8 +5932,7 @@ zdb_leak_init_prepare_indirect_vdevs(spa_t *spa, zdb_cb_t *zcb)
vdev_metaslab_group_create(vd); vdev_metaslab_group_create(vd);
VERIFY0(vdev_metaslab_init(vd, 0)); VERIFY0(vdev_metaslab_init(vd, 0));
vdev_indirect_mapping_t *vim __maybe_unused = vdev_indirect_mapping_t *vim = vd->vdev_indirect_mapping;
vd->vdev_indirect_mapping;
uint64_t vim_idx = 0; uint64_t vim_idx = 0;
for (uint64_t m = 0; m < vd->vdev_ms_count; m++) { for (uint64_t m = 0; m < vd->vdev_ms_count; m++) {
@ -7086,7 +7041,7 @@ verify_checkpoint_vdev_spacemaps(spa_t *checkpoint, spa_t *current)
for (uint64_t c = ckpoint_rvd->vdev_children; for (uint64_t c = ckpoint_rvd->vdev_children;
c < current_rvd->vdev_children; c++) { c < current_rvd->vdev_children; c++) {
vdev_t *current_vd = current_rvd->vdev_child[c]; vdev_t *current_vd = current_rvd->vdev_child[c];
VERIFY3P(current_vd->vdev_checkpoint_sm, ==, NULL); ASSERT3P(current_vd->vdev_checkpoint_sm, ==, NULL);
} }
} }
@ -8281,23 +8236,6 @@ zdb_embedded_block(char *thing)
free(buf); free(buf);
} }
/* check for valid hex or decimal numeric string */
static boolean_t
zdb_numeric(char *str)
{
int i = 0;
if (strlen(str) == 0)
return (B_FALSE);
if (strncmp(str, "0x", 2) == 0 || strncmp(str, "0X", 2) == 0)
i = 2;
for (; i < strlen(str); i++) {
if (!isxdigit(str[i]))
return (B_FALSE);
}
return (B_TRUE);
}
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
@ -8343,7 +8281,7 @@ main(int argc, char **argv)
zfs_btree_verify_intensity = 3; zfs_btree_verify_intensity = 3;
while ((c = getopt(argc, argv, while ((c = getopt(argc, argv,
"AbcCdDeEFGhiI:klLmMNo:Op:PqrRsSt:uU:vVx:XYyZ")) != -1) { "AbcCdDeEFGhiI:klLmMo:Op:PqrRsSt:uU:vVx:XYyZ")) != -1) {
switch (c) { switch (c) {
case 'b': case 'b':
case 'c': case 'c':
@ -8357,7 +8295,6 @@ main(int argc, char **argv)
case 'l': case 'l':
case 'm': case 'm':
case 'M': case 'M':
case 'N':
case 'O': case 'O':
case 'r': case 'r':
case 'R': case 'R':
@ -8449,6 +8386,31 @@ main(int argc, char **argv)
(void) fprintf(stderr, "-p option requires use of -e\n"); (void) fprintf(stderr, "-p option requires use of -e\n");
usage(); usage();
} }
if (dump_opt['d'] || dump_opt['r']) {
/* <pool>[/<dataset | objset id> is accepted */
if (argv[2] && (objset_str = strchr(argv[2], '/')) != NULL &&
objset_str++ != NULL) {
char *endptr;
errno = 0;
objset_id = strtoull(objset_str, &endptr, 0);
/* dataset 0 is the same as opening the pool */
if (errno == 0 && endptr != objset_str &&
objset_id != 0) {
target_is_spa = B_FALSE;
dataset_lookup = B_TRUE;
} else if (objset_id != 0) {
printf("failed to open objset %s "
"%llu %s", objset_str,
(u_longlong_t)objset_id,
strerror(errno));
exit(1);
}
/* normal dataset name not an objset ID */
if (endptr == objset_str) {
objset_id = -1;
}
}
}
#if defined(_LP64) #if defined(_LP64)
/* /*
@ -8477,18 +8439,13 @@ main(int argc, char **argv)
*/ */
spa_load_verify_dryrun = B_TRUE; spa_load_verify_dryrun = B_TRUE;
/*
* ZDB should have ability to read spacemaps.
*/
spa_mode_readable_spacemaps = B_TRUE;
kernel_init(SPA_MODE_READ); kernel_init(SPA_MODE_READ);
if (dump_all) if (dump_all)
verbose = MAX(verbose, 1); verbose = MAX(verbose, 1);
for (c = 0; c < 256; c++) { for (c = 0; c < 256; c++) {
if (dump_all && strchr("AeEFklLNOPrRSXy", c) == NULL) if (dump_all && strchr("AeEFklLOPrRSXy", c) == NULL)
dump_opt[c] = 1; dump_opt[c] = 1;
if (dump_opt[c]) if (dump_opt[c])
dump_opt[c] += verbose; dump_opt[c] += verbose;
@ -8527,7 +8484,6 @@ main(int argc, char **argv)
return (dump_path(argv[0], argv[1], NULL)); return (dump_path(argv[0], argv[1], NULL));
} }
if (dump_opt['r']) { if (dump_opt['r']) {
target_is_spa = B_FALSE;
if (argc != 3) if (argc != 3)
usage(); usage();
dump_opt['v'] = verbose; dump_opt['v'] = verbose;
@ -8538,10 +8494,6 @@ main(int argc, char **argv)
rewind = ZPOOL_DO_REWIND | rewind = ZPOOL_DO_REWIND |
(dump_opt['X'] ? ZPOOL_EXTREME_REWIND : 0); (dump_opt['X'] ? ZPOOL_EXTREME_REWIND : 0);
/* -N implies -d */
if (dump_opt['N'] && dump_opt['d'] == 0)
dump_opt['d'] = dump_opt['N'];
if (nvlist_alloc(&policy, NV_UNIQUE_NAME_TYPE, 0) != 0 || if (nvlist_alloc(&policy, NV_UNIQUE_NAME_TYPE, 0) != 0 ||
nvlist_add_uint64(policy, ZPOOL_LOAD_REQUEST_TXG, max_txg) != 0 || nvlist_add_uint64(policy, ZPOOL_LOAD_REQUEST_TXG, max_txg) != 0 ||
nvlist_add_uint32(policy, ZPOOL_LOAD_REWIND_POLICY, rewind) != 0) nvlist_add_uint32(policy, ZPOOL_LOAD_REWIND_POLICY, rewind) != 0)
@ -8560,34 +8512,6 @@ main(int argc, char **argv)
targetlen = strlen(target); targetlen = strlen(target);
if (targetlen && target[targetlen - 1] == '/') if (targetlen && target[targetlen - 1] == '/')
target[targetlen - 1] = '\0'; target[targetlen - 1] = '\0';
/*
* See if an objset ID was supplied (-d <pool>/<objset ID>).
* To disambiguate tank/100, consider the 100 as objsetID
* if -N was given, otherwise 100 is an objsetID iff
* tank/100 as a named dataset fails on lookup.
*/
objset_str = strchr(target, '/');
if (objset_str && strlen(objset_str) > 1 &&
zdb_numeric(objset_str + 1)) {
char *endptr;
errno = 0;
objset_str++;
objset_id = strtoull(objset_str, &endptr, 0);
/* dataset 0 is the same as opening the pool */
if (errno == 0 && endptr != objset_str &&
objset_id != 0) {
if (dump_opt['N'])
dataset_lookup = B_TRUE;
}
/* normal dataset name not an objset ID */
if (endptr == objset_str) {
objset_id = -1;
}
} else if (objset_str && !zdb_numeric(objset_str + 1) &&
dump_opt['N']) {
printf("Supply a numeric objset ID with -N\n");
exit(1);
}
} else { } else {
target_pool = target; target_pool = target;
} }
@ -8705,27 +8629,13 @@ main(int argc, char **argv)
} }
return (error); return (error);
} else { } else {
target_pool = strdup(target);
if (strpbrk(target, "/@") != NULL)
*strpbrk(target_pool, "/@") = '\0';
zdb_set_skip_mmp(target); zdb_set_skip_mmp(target);
/*
* If -N was supplied, the user has indicated that
* zdb -d <pool>/<objsetID> is in effect. Otherwise
* we first assume that the dataset string is the
* dataset name. If dmu_objset_hold fails with the
* dataset string, and we have an objset_id, retry the
* lookup with the objsetID.
*/
boolean_t retry = B_TRUE;
retry_lookup:
if (dataset_lookup == B_TRUE) { if (dataset_lookup == B_TRUE) {
/* /*
* Use the supplied id to get the name * Use the supplied id to get the name
* for open_objset. * for open_objset.
*/ */
error = spa_open(target_pool, &spa, FTAG); error = spa_open(target, &spa, FTAG);
if (error == 0) { if (error == 0) {
error = name_from_objset_id(spa, error = name_from_objset_id(spa,
objset_id, dsname); objset_id, dsname);
@ -8734,23 +8644,10 @@ retry_lookup:
target = dsname; target = dsname;
} }
} }
if (error == 0) { if (error == 0)
if (objset_id > 0 && retry) {
int err = dmu_objset_hold(target, FTAG,
&os);
if (err) {
dataset_lookup = B_TRUE;
retry = B_FALSE;
goto retry_lookup;
} else {
dmu_objset_rele(os, FTAG);
}
}
error = open_objset(target, FTAG, &os); error = open_objset(target, FTAG, &os);
}
if (error == 0) if (error == 0)
spa = dmu_objset_spa(os); spa = dmu_objset_spa(os);
free(target_pool);
} }
} }
nvlist_free(policy); nvlist_free(policy);

View File

@ -1,10 +1,8 @@
include $(top_srcdir)/config/Rules.am include $(top_srcdir)/config/Rules.am
include $(top_srcdir)/config/Shellcheck.am
AM_CFLAGS += $(LIBUDEV_CFLAGS) $(LIBUUID_CFLAGS) AM_CFLAGS += $(LIBUDEV_CFLAGS) $(LIBUUID_CFLAGS)
SUBDIRS = zed.d SUBDIRS = zed.d
SHELLCHECKDIRS = $(SUBDIRS)
sbin_PROGRAMS = zed sbin_PROGRAMS = zed
@ -45,7 +43,7 @@ zed_LDADD = \
$(abs_top_builddir)/lib/libnvpair/libnvpair.la \ $(abs_top_builddir)/lib/libnvpair/libnvpair.la \
$(abs_top_builddir)/lib/libuutil/libuutil.la $(abs_top_builddir)/lib/libuutil/libuutil.la
zed_LDADD += -lrt $(LIBATOMIC_LIBS) $(LIBUDEV_LIBS) $(LIBUUID_LIBS) zed_LDADD += -lrt $(LIBUDEV_LIBS) $(LIBUUID_LIBS)
zed_LDFLAGS = -pthread zed_LDFLAGS = -pthread
EXTRA_DIST = agents/README.md EXTRA_DIST = agents/README.md

View File

@ -599,7 +599,6 @@ fmd_timer_install(fmd_hdl_t *hdl, void *arg, fmd_event_t *ep, hrtime_t delta)
sev.sigev_notify_function = _timer_notify; sev.sigev_notify_function = _timer_notify;
sev.sigev_notify_attributes = NULL; sev.sigev_notify_attributes = NULL;
sev.sigev_value.sival_ptr = ftp; sev.sigev_value.sival_ptr = ftp;
sev.sigev_signo = 0;
timer_create(CLOCK_REALTIME, &sev, &ftp->ft_tid); timer_create(CLOCK_REALTIME, &sev, &ftp->ft_tid);
timer_settime(ftp->ft_tid, 0, &its, NULL); timer_settime(ftp->ft_tid, 0, &its, NULL);

View File

@ -80,7 +80,6 @@ zfs_agent_iter_vdev(zpool_handle_t *zhp, nvlist_t *nvl, void *arg)
char *path = NULL; char *path = NULL;
uint_t c, children; uint_t c, children;
nvlist_t **child; nvlist_t **child;
uint64_t vdev_guid;
/* /*
* First iterate over any children. * First iterate over any children.
@ -101,7 +100,7 @@ zfs_agent_iter_vdev(zpool_handle_t *zhp, nvlist_t *nvl, void *arg)
&child, &children) == 0) { &child, &children) == 0) {
for (c = 0; c < children; c++) { for (c = 0; c < children; c++) {
if (zfs_agent_iter_vdev(zhp, child[c], gsp)) { if (zfs_agent_iter_vdev(zhp, child[c], gsp)) {
gsp->gs_vdev_type = DEVICE_TYPE_SPARE; gsp->gs_vdev_type = DEVICE_TYPE_L2ARC;
return (B_TRUE); return (B_TRUE);
} }
} }
@ -110,7 +109,7 @@ zfs_agent_iter_vdev(zpool_handle_t *zhp, nvlist_t *nvl, void *arg)
&child, &children) == 0) { &child, &children) == 0) {
for (c = 0; c < children; c++) { for (c = 0; c < children; c++) {
if (zfs_agent_iter_vdev(zhp, child[c], gsp)) { if (zfs_agent_iter_vdev(zhp, child[c], gsp)) {
gsp->gs_vdev_type = DEVICE_TYPE_L2ARC; gsp->gs_vdev_type = DEVICE_TYPE_SPARE;
return (B_TRUE); return (B_TRUE);
} }
} }
@ -127,21 +126,6 @@ zfs_agent_iter_vdev(zpool_handle_t *zhp, nvlist_t *nvl, void *arg)
&gsp->gs_vdev_expandtime); &gsp->gs_vdev_expandtime);
return (B_TRUE); return (B_TRUE);
} }
/*
* Otherwise, on a vdev guid match, grab the devid and expansion
* time. The devid might be missing on removal since its not part
* of blkid cache and L2ARC VDEV does not contain pool guid in its
* blkid, so this is a special case for L2ARC VDEV.
*/
else if (gsp->gs_vdev_guid != 0 && gsp->gs_devid == NULL &&
nvlist_lookup_uint64(nvl, ZPOOL_CONFIG_GUID, &vdev_guid) == 0 &&
gsp->gs_vdev_guid == vdev_guid) {
(void) nvlist_lookup_string(nvl, ZPOOL_CONFIG_DEVID,
&gsp->gs_devid);
(void) nvlist_lookup_uint64(nvl, ZPOOL_CONFIG_EXPANSION_TIME,
&gsp->gs_vdev_expandtime);
return (B_TRUE);
}
return (B_FALSE); return (B_FALSE);
} }
@ -164,13 +148,13 @@ zfs_agent_iter_pool(zpool_handle_t *zhp, void *arg)
/* /*
* if a match was found then grab the pool guid * if a match was found then grab the pool guid
*/ */
if (gsp->gs_vdev_guid && gsp->gs_devid) { if (gsp->gs_vdev_guid) {
(void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, (void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
&gsp->gs_pool_guid); &gsp->gs_pool_guid);
} }
zpool_close(zhp); zpool_close(zhp);
return (gsp->gs_devid != NULL && gsp->gs_vdev_guid != 0); return (gsp->gs_vdev_guid != 0);
} }
void void
@ -211,13 +195,11 @@ zfs_agent_post_event(const char *class, const char *subclass, nvlist_t *nvl)
uint64_t pool_guid = 0, vdev_guid = 0; uint64_t pool_guid = 0, vdev_guid = 0;
guid_search_t search = { 0 }; guid_search_t search = { 0 };
device_type_t devtype = DEVICE_TYPE_PRIMARY; device_type_t devtype = DEVICE_TYPE_PRIMARY;
char *devid = NULL;
class = "resource.fs.zfs.removed"; class = "resource.fs.zfs.removed";
subclass = ""; subclass = "";
(void) nvlist_add_string(payload, FM_CLASS, class); (void) nvlist_add_string(payload, FM_CLASS, class);
(void) nvlist_lookup_string(nvl, DEV_IDENTIFIER, &devid);
(void) nvlist_lookup_uint64(nvl, ZFS_EV_POOL_GUID, &pool_guid); (void) nvlist_lookup_uint64(nvl, ZFS_EV_POOL_GUID, &pool_guid);
(void) nvlist_lookup_uint64(nvl, ZFS_EV_VDEV_GUID, &vdev_guid); (void) nvlist_lookup_uint64(nvl, ZFS_EV_VDEV_GUID, &vdev_guid);
@ -227,25 +209,21 @@ zfs_agent_post_event(const char *class, const char *subclass, nvlist_t *nvl)
(void) nvlist_add_int64_array(payload, FM_EREPORT_TIME, tod, 2); (void) nvlist_add_int64_array(payload, FM_EREPORT_TIME, tod, 2);
/* /*
* If devid is missing but vdev_guid is available, find devid
* and pool_guid from vdev_guid.
* For multipath, spare and l2arc devices ZFS_EV_VDEV_GUID or * For multipath, spare and l2arc devices ZFS_EV_VDEV_GUID or
* ZFS_EV_POOL_GUID may be missing so find them. * ZFS_EV_POOL_GUID may be missing so find them.
*/ */
if (devid == NULL || pool_guid == 0 || vdev_guid == 0) { if (pool_guid == 0 || vdev_guid == 0) {
if (devid == NULL) if ((nvlist_lookup_string(nvl, DEV_IDENTIFIER,
search.gs_vdev_guid = vdev_guid; &search.gs_devid) == 0) &&
else (zpool_iter(g_zfs_hdl, zfs_agent_iter_pool, &search)
search.gs_devid = devid; == 1)) {
zpool_iter(g_zfs_hdl, zfs_agent_iter_pool, &search);
if (devid == NULL)
devid = search.gs_devid;
if (pool_guid == 0) if (pool_guid == 0)
pool_guid = search.gs_pool_guid; pool_guid = search.gs_pool_guid;
if (vdev_guid == 0) if (vdev_guid == 0)
vdev_guid = search.gs_vdev_guid; vdev_guid = search.gs_vdev_guid;
devtype = search.gs_vdev_type; devtype = search.gs_vdev_type;
} }
}
/* /*
* We want to avoid reporting "remove" events coming from * We want to avoid reporting "remove" events coming from
@ -257,9 +235,7 @@ zfs_agent_post_event(const char *class, const char *subclass, nvlist_t *nvl)
search.gs_vdev_expandtime + 10 > tv.tv_sec) { search.gs_vdev_expandtime + 10 > tv.tv_sec) {
zed_log_msg(LOG_INFO, "agent post event: ignoring '%s' " zed_log_msg(LOG_INFO, "agent post event: ignoring '%s' "
"for recently expanded device '%s'", EC_DEV_REMOVE, "for recently expanded device '%s'", EC_DEV_REMOVE,
devid); search.gs_devid);
fnvlist_free(payload);
free(event);
goto out; goto out;
} }
@ -416,7 +392,6 @@ zfs_agent_init(libzfs_handle_t *zfs_hdl)
list_destroy(&agent_events); list_destroy(&agent_events);
zed_log_die("Failed to initialize agents"); zed_log_die("Failed to initialize agents");
} }
pthread_setname_np(g_agents_tid, "agents");
} }
void void

View File

@ -35,7 +35,6 @@
#include <sys/fs/zfs.h> #include <sys/fs/zfs.h>
#include <sys/fm/protocol.h> #include <sys/fm/protocol.h>
#include <sys/fm/fs/zfs.h> #include <sys/fm/fs/zfs.h>
#include <sys/zio.h>
#include "zfs_agents.h" #include "zfs_agents.h"
#include "fmd_api.h" #include "fmd_api.h"
@ -774,8 +773,6 @@ zfs_fm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_PROBE_FAILURE))) { ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_PROBE_FAILURE))) {
char *failmode = NULL; char *failmode = NULL;
boolean_t checkremove = B_FALSE; boolean_t checkremove = B_FALSE;
uint32_t pri = 0;
int32_t flags = 0;
/* /*
* If this is a checksum or I/O error, then toss it into the * If this is a checksum or I/O error, then toss it into the
@ -798,23 +795,6 @@ zfs_fm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
checkremove = B_TRUE; checkremove = B_TRUE;
} else if (fmd_nvl_class_match(hdl, nvl, } else if (fmd_nvl_class_match(hdl, nvl,
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_CHECKSUM))) { ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_CHECKSUM))) {
/*
* We ignore ereports for checksum errors generated by
* scrub/resilver I/O to avoid potentially further
* degrading the pool while it's being repaired.
*/
if (((nvlist_lookup_uint32(nvl,
FM_EREPORT_PAYLOAD_ZFS_ZIO_PRIORITY, &pri) == 0) &&
(pri == ZIO_PRIORITY_SCRUB ||
pri == ZIO_PRIORITY_REBUILD)) ||
((nvlist_lookup_int32(nvl,
FM_EREPORT_PAYLOAD_ZFS_ZIO_FLAGS, &flags) == 0) &&
(flags & (ZIO_FLAG_SCRUB | ZIO_FLAG_RESILVER)))) {
fmd_hdl_debug(hdl, "ignoring '%s' for "
"scrub/resilver I/O", class);
return;
}
if (zcp->zc_data.zc_serd_checksum[0] == '\0') { if (zcp->zc_data.zc_serd_checksum[0] == '\0') {
zfs_serd_name(zcp->zc_data.zc_serd_checksum, zfs_serd_name(zcp->zc_data.zc_serd_checksum,
pool_guid, vdev_guid, "checksum"); pool_guid, vdev_guid, "checksum");

View File

@ -141,17 +141,6 @@ zfs_unavail_pool(zpool_handle_t *zhp, void *data)
return (0); return (0);
} }
/*
* Write an array of strings to the zed log
*/
static void lines_to_zed_log_msg(char **lines, int lines_cnt)
{
int i;
for (i = 0; i < lines_cnt; i++) {
zed_log_msg(LOG_INFO, "%s", lines[i]);
}
}
/* /*
* Two stage replace on Linux * Two stage replace on Linux
* since we get disk notifications * since we get disk notifications
@ -194,20 +183,16 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
nvlist_t *nvroot, *newvd; nvlist_t *nvroot, *newvd;
pendingdev_t *device; pendingdev_t *device;
uint64_t wholedisk = 0ULL; uint64_t wholedisk = 0ULL;
uint64_t offline = 0ULL, faulted = 0ULL; uint64_t offline = 0ULL;
uint64_t guid = 0ULL; uint64_t guid = 0ULL;
uint64_t is_spare = 0;
char *physpath = NULL, *new_devid = NULL, *enc_sysfs_path = NULL; char *physpath = NULL, *new_devid = NULL, *enc_sysfs_path = NULL;
char rawpath[PATH_MAX], fullpath[PATH_MAX]; char rawpath[PATH_MAX], fullpath[PATH_MAX];
char devpath[PATH_MAX]; char devpath[PATH_MAX];
int ret; int ret;
int online_flag = ZFS_ONLINE_CHECKREMOVE | ZFS_ONLINE_UNSPARE; boolean_t is_dm = B_FALSE;
boolean_t is_sd = B_FALSE; boolean_t is_sd = B_FALSE;
boolean_t is_mpath_wholedisk = B_FALSE;
uint_t c; uint_t c;
vdev_stat_t *vs; vdev_stat_t *vs;
char **lines = NULL;
int lines_cnt = 0;
if (nvlist_lookup_string(vdev, ZPOOL_CONFIG_PATH, &path) != 0) if (nvlist_lookup_string(vdev, ZPOOL_CONFIG_PATH, &path) != 0)
return; return;
@ -222,82 +207,19 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
} }
(void) nvlist_lookup_string(vdev, ZPOOL_CONFIG_PHYS_PATH, &physpath); (void) nvlist_lookup_string(vdev, ZPOOL_CONFIG_PHYS_PATH, &physpath);
update_vdev_config_dev_sysfs_path(vdev, path,
ZPOOL_CONFIG_VDEV_ENC_SYSFS_PATH);
(void) nvlist_lookup_string(vdev, ZPOOL_CONFIG_VDEV_ENC_SYSFS_PATH, (void) nvlist_lookup_string(vdev, ZPOOL_CONFIG_VDEV_ENC_SYSFS_PATH,
&enc_sysfs_path); &enc_sysfs_path);
(void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK, &wholedisk); (void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK, &wholedisk);
(void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_OFFLINE, &offline); (void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_OFFLINE, &offline);
(void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_FAULTED, &faulted);
(void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_GUID, &guid); (void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_GUID, &guid);
(void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_IS_SPARE, &is_spare);
/* if (offline)
* Special case: return; /* don't intervene if it was taken offline */
*
* We've seen times where a disk won't have a ZPOOL_CONFIG_PHYS_PATH
* entry in their config. For example, on this force-faulted disk:
*
* children[0]:
* type: 'disk'
* id: 0
* guid: 14309659774640089719
* path: '/dev/disk/by-vdev/L28'
* whole_disk: 0
* DTL: 654
* create_txg: 4
* com.delphix:vdev_zap_leaf: 1161
* faulted: 1
* aux_state: 'external'
* children[1]:
* type: 'disk'
* id: 1
* guid: 16002508084177980912
* path: '/dev/disk/by-vdev/L29'
* devid: 'dm-uuid-mpath-35000c500a61d68a3'
* phys_path: 'L29'
* vdev_enc_sysfs_path: '/sys/class/enclosure/0:0:1:0/SLOT 30 32'
* whole_disk: 0
* DTL: 1028
* create_txg: 4
* com.delphix:vdev_zap_leaf: 131
*
* If the disk's path is a /dev/disk/by-vdev/ path, then we can infer
* the ZPOOL_CONFIG_PHYS_PATH from the by-vdev disk name.
*/
if (physpath == NULL && path != NULL) {
/* If path begins with "/dev/disk/by-vdev/" ... */
if (strncmp(path, DEV_BYVDEV_PATH,
strlen(DEV_BYVDEV_PATH)) == 0) {
/* Set physpath to the char after "/dev/disk/by-vdev" */
physpath = &path[strlen(DEV_BYVDEV_PATH)];
}
}
/* is_dm = zfs_dev_is_dm(path);
* We don't want to autoreplace offlined disks. However, we do want to
* replace force-faulted disks (`zpool offline -f`). Force-faulted
* disks have both offline=1 and faulted=1 in the nvlist.
*/
if (offline && !faulted) {
zed_log_msg(LOG_INFO, "%s: %s is offline, skip autoreplace",
__func__, path);
return;
}
is_mpath_wholedisk = is_mpath_whole_disk(path);
zed_log_msg(LOG_INFO, "zfs_process_add: pool '%s' vdev '%s', phys '%s'" zed_log_msg(LOG_INFO, "zfs_process_add: pool '%s' vdev '%s', phys '%s'"
" %s blank disk, %s mpath blank disk, %s labeled, enc sysfs '%s', " " wholedisk %d, %s dm (guid %llu)", zpool_get_name(zhp), path,
"(guid %llu)", physpath ? physpath : "NULL", wholedisk, is_dm ? "is" : "not",
zpool_get_name(zhp), path,
physpath ? physpath : "NULL",
wholedisk ? "is" : "not",
is_mpath_wholedisk? "is" : "not",
labeled ? "is" : "not",
enc_sysfs_path,
(long long unsigned int)guid); (long long unsigned int)guid);
/* /*
@ -324,18 +246,15 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
} }
} }
if (is_spare)
online_flag |= ZFS_ONLINE_SPARE;
/* /*
* Attempt to online the device. * Attempt to online the device.
*/ */
if (zpool_vdev_online(zhp, fullpath, online_flag, &newstate) == 0 && if (zpool_vdev_online(zhp, fullpath,
ZFS_ONLINE_CHECKREMOVE | ZFS_ONLINE_UNSPARE, &newstate) == 0 &&
(newstate == VDEV_STATE_HEALTHY || (newstate == VDEV_STATE_HEALTHY ||
newstate == VDEV_STATE_DEGRADED)) { newstate == VDEV_STATE_DEGRADED)) {
zed_log_msg(LOG_INFO, zed_log_msg(LOG_INFO, " zpool_vdev_online: vdev %s is %s",
" zpool_vdev_online: vdev '%s' ('%s') is " fullpath, (newstate == VDEV_STATE_HEALTHY) ?
"%s", fullpath, physpath, (newstate == VDEV_STATE_HEALTHY) ?
"HEALTHY" : "DEGRADED"); "HEALTHY" : "DEGRADED");
return; return;
} }
@ -352,12 +271,11 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
* vdev online to trigger a FMA fault by posting an ereport. * vdev online to trigger a FMA fault by posting an ereport.
*/ */
if (!zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOREPLACE, NULL) || if (!zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOREPLACE, NULL) ||
!(wholedisk || is_mpath_wholedisk) || (physpath == NULL)) { !(wholedisk || is_dm) || (physpath == NULL)) {
(void) zpool_vdev_online(zhp, fullpath, ZFS_ONLINE_FORCEFAULT, (void) zpool_vdev_online(zhp, fullpath, ZFS_ONLINE_FORCEFAULT,
&newstate); &newstate);
zed_log_msg(LOG_INFO, "Pool's autoreplace is not enabled or " zed_log_msg(LOG_INFO, "Pool's autoreplace is not enabled or "
"not a blank disk for '%s' ('%s')", fullpath, "not a whole disk for '%s'", fullpath);
physpath);
return; return;
} }
@ -369,7 +287,7 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
(void) snprintf(rawpath, sizeof (rawpath), "%s%s", (void) snprintf(rawpath, sizeof (rawpath), "%s%s",
is_sd ? DEV_BYVDEV_PATH : DEV_BYPATH_PATH, physpath); is_sd ? DEV_BYVDEV_PATH : DEV_BYPATH_PATH, physpath);
if (realpath(rawpath, devpath) == NULL && !is_mpath_wholedisk) { if (realpath(rawpath, devpath) == NULL && !is_dm) {
zed_log_msg(LOG_INFO, " realpath: %s failed (%s)", zed_log_msg(LOG_INFO, " realpath: %s failed (%s)",
rawpath, strerror(errno)); rawpath, strerror(errno));
@ -385,31 +303,13 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
if ((vs->vs_state != VDEV_STATE_DEGRADED) && if ((vs->vs_state != VDEV_STATE_DEGRADED) &&
(vs->vs_state != VDEV_STATE_FAULTED) && (vs->vs_state != VDEV_STATE_FAULTED) &&
(vs->vs_state != VDEV_STATE_CANT_OPEN)) { (vs->vs_state != VDEV_STATE_CANT_OPEN)) {
zed_log_msg(LOG_INFO, " not autoreplacing since disk isn't in "
"a bad state (currently %d)", vs->vs_state);
return; return;
} }
nvlist_lookup_string(vdev, "new_devid", &new_devid); nvlist_lookup_string(vdev, "new_devid", &new_devid);
if (is_mpath_wholedisk) { if (is_dm) {
/* Don't label device mapper or multipath disks. */ /* Don't label device mapper or multipath disks. */
zed_log_msg(LOG_INFO,
" it's a multipath wholedisk, don't label");
if (zpool_prepare_disk(zhp, vdev, "autoreplace", &lines,
&lines_cnt) != 0) {
zed_log_msg(LOG_INFO,
" zpool_prepare_disk: could not "
"prepare '%s' (%s)", fullpath,
libzfs_error_description(g_zfshdl));
if (lines_cnt > 0) {
zed_log_msg(LOG_INFO,
" zfs_prepare_disk output:");
lines_to_zed_log_msg(lines, lines_cnt);
}
libzfs_free_str_array(lines, lines_cnt);
return;
}
} else if (!labeled) { } else if (!labeled) {
/* /*
* we're auto-replacing a raw disk, so label it first * we're auto-replacing a raw disk, so label it first
@ -432,18 +332,10 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
* If this is a request to label a whole disk, then attempt to * If this is a request to label a whole disk, then attempt to
* write out the label. * write out the label.
*/ */
if (zpool_prepare_and_label_disk(g_zfshdl, zhp, leafname, if (zpool_label_disk(g_zfshdl, zhp, leafname) != 0) {
vdev, "autoreplace", &lines, &lines_cnt) != 0) { zed_log_msg(LOG_INFO, " zpool_label_disk: could not "
zed_log_msg(LOG_INFO,
" zpool_prepare_and_label_disk: could not "
"label '%s' (%s)", leafname, "label '%s' (%s)", leafname,
libzfs_error_description(g_zfshdl)); libzfs_error_description(g_zfshdl));
if (lines_cnt > 0) {
zed_log_msg(LOG_INFO,
" zfs_prepare_disk output:");
lines_to_zed_log_msg(lines, lines_cnt);
}
libzfs_free_str_array(lines, lines_cnt);
(void) zpool_vdev_online(zhp, fullpath, (void) zpool_vdev_online(zhp, fullpath,
ZFS_ONLINE_FORCEFAULT, &newstate); ZFS_ONLINE_FORCEFAULT, &newstate);
@ -498,8 +390,6 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
DEV_BYID_PATH, new_devid); DEV_BYID_PATH, new_devid);
} }
libzfs_free_str_array(lines, lines_cnt);
/* /*
* Construct the root vdev to pass to zpool_vdev_attach(). While adding * Construct the root vdev to pass to zpool_vdev_attach(). While adding
* the entire vdev structure is harmless, we construct a reduced set of * the entire vdev structure is harmless, we construct a reduced set of
@ -573,9 +463,7 @@ typedef struct dev_data {
boolean_t dd_islabeled; boolean_t dd_islabeled;
uint64_t dd_pool_guid; uint64_t dd_pool_guid;
uint64_t dd_vdev_guid; uint64_t dd_vdev_guid;
uint64_t dd_new_vdev_guid;
const char *dd_new_devid; const char *dd_new_devid;
uint64_t dd_num_spares;
} dev_data_t; } dev_data_t;
static void static void
@ -585,8 +473,6 @@ zfs_iter_vdev(zpool_handle_t *zhp, nvlist_t *nvl, void *data)
char *path = NULL; char *path = NULL;
uint_t c, children; uint_t c, children;
nvlist_t **child; nvlist_t **child;
uint64_t guid = 0;
uint64_t isspare = 0;
/* /*
* First iterate over any children. * First iterate over any children.
@ -612,16 +498,19 @@ zfs_iter_vdev(zpool_handle_t *zhp, nvlist_t *nvl, void *data)
} }
/* once a vdev was matched and processed there is nothing left to do */ /* once a vdev was matched and processed there is nothing left to do */
if (dp->dd_found && dp->dd_num_spares == 0) if (dp->dd_found)
return; return;
(void) nvlist_lookup_uint64(nvl, ZPOOL_CONFIG_GUID, &guid);
/* /*
* Match by GUID if available otherwise fallback to devid or physical * Match by GUID if available otherwise fallback to devid or physical
*/ */
if (dp->dd_vdev_guid != 0) { if (dp->dd_vdev_guid != 0) {
if (guid != dp->dd_vdev_guid) uint64_t guid;
if (nvlist_lookup_uint64(nvl, ZPOOL_CONFIG_GUID,
&guid) != 0 || guid != dp->dd_vdev_guid) {
return; return;
}
zed_log_msg(LOG_INFO, " zfs_iter_vdev: matched on %llu", guid); zed_log_msg(LOG_INFO, " zfs_iter_vdev: matched on %llu", guid);
dp->dd_found = B_TRUE; dp->dd_found = B_TRUE;
@ -631,23 +520,10 @@ zfs_iter_vdev(zpool_handle_t *zhp, nvlist_t *nvl, void *data)
* illumos, substring matching is not required to accommodate * illumos, substring matching is not required to accommodate
* the partition suffix. An exact match will be present in * the partition suffix. An exact match will be present in
* the dp->dd_compare value. * the dp->dd_compare value.
* If the attached disk already contains a vdev GUID, it means
* the disk is not clean. In such a scenario, the physical path
* would be a match that makes the disk faulted when trying to
* online it. So, we would only want to proceed if either GUID
* matches with the last attached disk or the disk is in clean
* state.
*/ */
if (nvlist_lookup_string(nvl, dp->dd_prop, &path) != 0 || if (nvlist_lookup_string(nvl, dp->dd_prop, &path) != 0 ||
strcmp(dp->dd_compare, path) != 0) { strcmp(dp->dd_compare, path) != 0)
return; return;
}
if (dp->dd_new_vdev_guid != 0 && dp->dd_new_vdev_guid != guid) {
zed_log_msg(LOG_INFO, " %s: no match (GUID:%llu"
" != vdev GUID:%llu)", __func__,
dp->dd_new_vdev_guid, guid);
return;
}
zed_log_msg(LOG_INFO, " zfs_iter_vdev: matched %s on %s", zed_log_msg(LOG_INFO, " zfs_iter_vdev: matched %s on %s",
dp->dd_prop, path); dp->dd_prop, path);
@ -660,10 +536,6 @@ zfs_iter_vdev(zpool_handle_t *zhp, nvlist_t *nvl, void *data)
} }
} }
if (dp->dd_found == B_TRUE && nvlist_lookup_uint64(nvl,
ZPOOL_CONFIG_IS_SPARE, &isspare) == 0 && isspare)
dp->dd_num_spares++;
(dp->dd_func)(zhp, nvl, dp->dd_islabeled); (dp->dd_func)(zhp, nvl, dp->dd_islabeled);
} }
@ -699,8 +571,6 @@ zfs_iter_pool(zpool_handle_t *zhp, void *data)
ZPOOL_CONFIG_VDEV_TREE, &nvl); ZPOOL_CONFIG_VDEV_TREE, &nvl);
zfs_iter_vdev(zhp, nvl, data); zfs_iter_vdev(zhp, nvl, data);
} }
} else {
zed_log_msg(LOG_INFO, "%s: no config\n", __func__);
} }
/* /*
@ -724,9 +594,7 @@ zfs_iter_pool(zpool_handle_t *zhp, void *data)
} }
zpool_close(zhp); zpool_close(zhp);
return (dp->dd_found); /* cease iteration after a match */
/* cease iteration after a match */
return (dp->dd_found && dp->dd_num_spares == 0);
} }
/* /*
@ -735,7 +603,7 @@ zfs_iter_pool(zpool_handle_t *zhp, void *data)
*/ */
static boolean_t static boolean_t
devphys_iter(const char *physical, const char *devid, zfs_process_func_t func, devphys_iter(const char *physical, const char *devid, zfs_process_func_t func,
boolean_t is_slice, uint64_t new_vdev_guid) boolean_t is_slice)
{ {
dev_data_t data = { 0 }; dev_data_t data = { 0 };
@ -745,73 +613,6 @@ devphys_iter(const char *physical, const char *devid, zfs_process_func_t func,
data.dd_found = B_FALSE; data.dd_found = B_FALSE;
data.dd_islabeled = is_slice; data.dd_islabeled = is_slice;
data.dd_new_devid = devid; /* used by auto replace code */ data.dd_new_devid = devid; /* used by auto replace code */
data.dd_new_vdev_guid = new_vdev_guid;
(void) zpool_iter(g_zfshdl, zfs_iter_pool, &data);
return (data.dd_found);
}
/*
* Given a device identifier, find any vdevs with a matching by-vdev
* path. Normally we shouldn't need this as the comparison would be
* made earlier in the devphys_iter(). For example, if we were replacing
* /dev/disk/by-vdev/L28, normally devphys_iter() would match the
* ZPOOL_CONFIG_PHYS_PATH of "L28" from the old disk config to "L28"
* of the new disk config. However, we've seen cases where
* ZPOOL_CONFIG_PHYS_PATH was not in the config for the old disk. Here's
* an example of a real 2-disk mirror pool where one disk was force
* faulted:
*
* com.delphix:vdev_zap_top: 129
* children[0]:
* type: 'disk'
* id: 0
* guid: 14309659774640089719
* path: '/dev/disk/by-vdev/L28'
* whole_disk: 0
* DTL: 654
* create_txg: 4
* com.delphix:vdev_zap_leaf: 1161
* faulted: 1
* aux_state: 'external'
* children[1]:
* type: 'disk'
* id: 1
* guid: 16002508084177980912
* path: '/dev/disk/by-vdev/L29'
* devid: 'dm-uuid-mpath-35000c500a61d68a3'
* phys_path: 'L29'
* vdev_enc_sysfs_path: '/sys/class/enclosure/0:0:1:0/SLOT 30 32'
* whole_disk: 0
* DTL: 1028
* create_txg: 4
* com.delphix:vdev_zap_leaf: 131
*
* So in the case above, the only thing we could compare is the path.
*
* We can do this because we assume by-vdev paths are authoritative as physical
* paths. We could not assume this for normal paths like /dev/sda since the
* physical location /dev/sda points to could change over time.
*/
static boolean_t
by_vdev_path_iter(const char *by_vdev_path, const char *devid,
zfs_process_func_t func, boolean_t is_slice)
{
dev_data_t data = { 0 };
data.dd_compare = by_vdev_path;
data.dd_func = func;
data.dd_prop = ZPOOL_CONFIG_PATH;
data.dd_found = B_FALSE;
data.dd_islabeled = is_slice;
data.dd_new_devid = devid;
if (strncmp(by_vdev_path, DEV_BYVDEV_PATH,
strlen(DEV_BYVDEV_PATH)) != 0) {
/* by_vdev_path doesn't start with "/dev/disk/by-vdev/" */
return (B_FALSE);
}
(void) zpool_iter(g_zfshdl, zfs_iter_pool, &data); (void) zpool_iter(g_zfshdl, zfs_iter_pool, &data);
@ -839,27 +640,6 @@ devid_iter(const char *devid, zfs_process_func_t func, boolean_t is_slice)
return (data.dd_found); return (data.dd_found);
} }
/*
* Given a device guid, find any vdevs with a matching guid.
*/
static boolean_t
guid_iter(uint64_t pool_guid, uint64_t vdev_guid, const char *devid,
zfs_process_func_t func, boolean_t is_slice)
{
dev_data_t data = { 0 };
data.dd_func = func;
data.dd_found = B_FALSE;
data.dd_pool_guid = pool_guid;
data.dd_vdev_guid = vdev_guid;
data.dd_islabeled = is_slice;
data.dd_new_devid = devid;
(void) zpool_iter(g_zfshdl, zfs_iter_pool, &data);
return (data.dd_found);
}
/* /*
* Handle a EC_DEV_ADD.ESC_DISK event. * Handle a EC_DEV_ADD.ESC_DISK event.
* *
@ -882,21 +662,16 @@ guid_iter(uint64_t pool_guid, uint64_t vdev_guid, const char *devid,
static int static int
zfs_deliver_add(nvlist_t *nvl, boolean_t is_lofi) zfs_deliver_add(nvlist_t *nvl, boolean_t is_lofi)
{ {
char *devpath = NULL, *devid = NULL; char *devpath = NULL, *devid;
uint64_t pool_guid = 0, vdev_guid = 0;
boolean_t is_slice; boolean_t is_slice;
/* /*
* Expecting a devid string and an optional physical location and guid * Expecting a devid string and an optional physical location
*/ */
if (nvlist_lookup_string(nvl, DEV_IDENTIFIER, &devid) != 0) { if (nvlist_lookup_string(nvl, DEV_IDENTIFIER, &devid) != 0)
zed_log_msg(LOG_INFO, "%s: no dev identifier\n", __func__);
return (-1); return (-1);
}
(void) nvlist_lookup_string(nvl, DEV_PHYS_PATH, &devpath); (void) nvlist_lookup_string(nvl, DEV_PHYS_PATH, &devpath);
(void) nvlist_lookup_uint64(nvl, ZFS_EV_POOL_GUID, &pool_guid);
(void) nvlist_lookup_uint64(nvl, ZFS_EV_VDEV_GUID, &vdev_guid);
is_slice = (nvlist_lookup_boolean(nvl, DEV_IS_PART) == 0); is_slice = (nvlist_lookup_boolean(nvl, DEV_IS_PART) == 0);
@ -907,28 +682,12 @@ zfs_deliver_add(nvlist_t *nvl, boolean_t is_lofi)
* Iterate over all vdevs looking for a match in the following order: * Iterate over all vdevs looking for a match in the following order:
* 1. ZPOOL_CONFIG_DEVID (identifies the unique disk) * 1. ZPOOL_CONFIG_DEVID (identifies the unique disk)
* 2. ZPOOL_CONFIG_PHYS_PATH (identifies disk physical location). * 2. ZPOOL_CONFIG_PHYS_PATH (identifies disk physical location).
* 3. ZPOOL_CONFIG_GUID (identifies unique vdev). *
* 4. ZPOOL_CONFIG_PATH for /dev/disk/by-vdev devices only (since * For disks, we only want to pay attention to vdevs marked as whole
* by-vdev paths represent physical paths). * disks or are a multipath device.
*/ */
if (devid_iter(devid, zfs_process_add, is_slice)) if (!devid_iter(devid, zfs_process_add, is_slice) && devpath != NULL)
return (0); (void) devphys_iter(devpath, devid, zfs_process_add, is_slice);
if (devpath != NULL && devphys_iter(devpath, devid, zfs_process_add,
is_slice, vdev_guid))
return (0);
if (vdev_guid != 0)
(void) guid_iter(pool_guid, vdev_guid, devid, zfs_process_add,
is_slice);
if (devpath != NULL) {
/* Can we match a /dev/disk/by-vdev/ path? */
char by_vdev_path[MAXPATHLEN];
snprintf(by_vdev_path, sizeof (by_vdev_path),
"/dev/disk/by-vdev/%s", devpath);
if (by_vdev_path_iter(by_vdev_path, devid, zfs_process_add,
is_slice))
return (0);
}
return (0); return (0);
} }
@ -960,96 +719,21 @@ zfs_deliver_check(nvlist_t *nvl)
return (0); return (0);
} }
/*
* Given a path to a vdev, lookup the vdev's physical size from its
* config nvlist.
*
* Returns the vdev's physical size in bytes on success, 0 on error.
*/
static uint64_t
vdev_size_from_config(zpool_handle_t *zhp, const char *vdev_path)
{
nvlist_t *nvl = NULL;
boolean_t avail_spare, l2cache, log;
vdev_stat_t *vs = NULL;
uint_t c;
nvl = zpool_find_vdev(zhp, vdev_path, &avail_spare, &l2cache, &log);
if (!nvl)
return (0);
verify(nvlist_lookup_uint64_array(nvl, ZPOOL_CONFIG_VDEV_STATS,
(uint64_t **)&vs, &c) == 0);
if (!vs) {
zed_log_msg(LOG_INFO, "%s: no nvlist for '%s'", __func__,
vdev_path);
return (0);
}
return (vs->vs_pspace);
}
/*
* Given a path to a vdev, lookup if the vdev is a "whole disk" in the
* config nvlist. "whole disk" means that ZFS was passed a whole disk
* at pool creation time, which it partitioned up and has full control over.
* Thus a partition with wholedisk=1 set tells us that zfs created the
* partition at creation time. A partition without whole disk set would have
* been created by externally (like with fdisk) and passed to ZFS.
*
* Returns the whole disk value (either 0 or 1).
*/
static uint64_t
vdev_whole_disk_from_config(zpool_handle_t *zhp, const char *vdev_path)
{
nvlist_t *nvl = NULL;
boolean_t avail_spare, l2cache, log;
uint64_t wholedisk = 0;
nvl = zpool_find_vdev(zhp, vdev_path, &avail_spare, &l2cache, &log);
if (!nvl)
return (0);
(void) nvlist_lookup_uint64(nvl, ZPOOL_CONFIG_WHOLE_DISK, &wholedisk);
return (wholedisk);
}
/*
* If the device size grew more than 1% then return true.
*/
#define DEVICE_GREW(oldsize, newsize) \
((newsize > oldsize) && \
((newsize / (newsize - oldsize)) <= 100))
static int static int
zfsdle_vdev_online(zpool_handle_t *zhp, void *data) zfsdle_vdev_online(zpool_handle_t *zhp, void *data)
{ {
char *devname = data;
boolean_t avail_spare, l2cache; boolean_t avail_spare, l2cache;
nvlist_t *udev_nvl = data;
nvlist_t *tgt; nvlist_t *tgt;
int error; int error;
char *tmp_devname, devname[MAXPATHLEN] = "";
uint64_t guid;
if (nvlist_lookup_uint64(udev_nvl, ZFS_EV_VDEV_GUID, &guid) == 0) {
sprintf(devname, "%llu", (u_longlong_t)guid);
} else if (nvlist_lookup_string(udev_nvl, DEV_PHYS_PATH,
&tmp_devname) == 0) {
strlcpy(devname, tmp_devname, MAXPATHLEN);
zfs_append_partition(devname, MAXPATHLEN);
} else {
zed_log_msg(LOG_INFO, "%s: no guid or physpath", __func__);
}
zed_log_msg(LOG_INFO, "zfsdle_vdev_online: searching for '%s' in '%s'", zed_log_msg(LOG_INFO, "zfsdle_vdev_online: searching for '%s' in '%s'",
devname, zpool_get_name(zhp)); devname, zpool_get_name(zhp));
if ((tgt = zpool_find_vdev_by_physpath(zhp, devname, if ((tgt = zpool_find_vdev_by_physpath(zhp, devname,
&avail_spare, &l2cache, NULL)) != NULL) { &avail_spare, &l2cache, NULL)) != NULL) {
char *path, fullpath[MAXPATHLEN]; char *path, fullpath[MAXPATHLEN];
uint64_t wholedisk = 0; uint64_t wholedisk;
error = nvlist_lookup_string(tgt, ZPOOL_CONFIG_PATH, &path); error = nvlist_lookup_string(tgt, ZPOOL_CONFIG_PATH, &path);
if (error) { if (error) {
@ -1057,8 +741,10 @@ zfsdle_vdev_online(zpool_handle_t *zhp, void *data)
return (0); return (0);
} }
(void) nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK, error = nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK,
&wholedisk); &wholedisk);
if (error)
wholedisk = 0;
if (wholedisk) { if (wholedisk) {
path = strrchr(path, '/'); path = strrchr(path, '/');
@ -1092,77 +778,14 @@ zfsdle_vdev_online(zpool_handle_t *zhp, void *data)
vdev_state_t newstate; vdev_state_t newstate;
if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL) { if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL) {
/* error = zpool_vdev_online(zhp, fullpath, 0,
* If this disk size has not changed, then &newstate);
* there's no need to do an autoexpand. To zed_log_msg(LOG_INFO, "zfsdle_vdev_online: "
* check we look at the disk's size in its "setting device '%s' to ONLINE state "
* config, and compare it to the disk size "in pool '%s': %d", fullpath,
* that udev is reporting.
*/
uint64_t udev_size = 0, conf_size = 0,
wholedisk = 0, udev_parent_size = 0;
/*
* Get the size of our disk that udev is
* reporting.
*/
if (nvlist_lookup_uint64(udev_nvl, DEV_SIZE,
&udev_size) != 0) {
udev_size = 0;
}
/*
* Get the size of our disk's parent device
* from udev (where sda1's parent is sda).
*/
if (nvlist_lookup_uint64(udev_nvl,
DEV_PARENT_SIZE, &udev_parent_size) != 0) {
udev_parent_size = 0;
}
conf_size = vdev_size_from_config(zhp,
fullpath);
wholedisk = vdev_whole_disk_from_config(zhp,
fullpath);
/*
* Only attempt an autoexpand if the vdev size
* changed. There are two different cases
* to consider.
*
* 1. wholedisk=1
* If you do a 'zpool create' on a whole disk
* (like /dev/sda), then zfs will create
* partitions on the disk (like /dev/sda1). In
* that case, wholedisk=1 will be set in the
* partition's nvlist config. So zed will need
* to see if your parent device (/dev/sda)
* expanded in size, and if so, then attempt
* the autoexpand.
*
* 2. wholedisk=0
* If you do a 'zpool create' on an existing
* partition, or a device that doesn't allow
* partitions, then wholedisk=0, and you will
* simply need to check if the device itself
* expanded in size.
*/
if (DEVICE_GREW(conf_size, udev_size) ||
(wholedisk && DEVICE_GREW(conf_size,
udev_parent_size))) {
error = zpool_vdev_online(zhp, fullpath,
0, &newstate);
zed_log_msg(LOG_INFO,
"%s: autoexpanding '%s' from %llu"
" to %llu bytes in pool '%s': %d",
__func__, fullpath, conf_size,
MAX(udev_size, udev_parent_size),
zpool_get_name(zhp), error); zpool_get_name(zhp), error);
} }
} }
}
zpool_close(zhp); zpool_close(zhp);
return (1); return (1);
} }
@ -1188,11 +811,10 @@ zfs_deliver_dle(nvlist_t *nvl)
strlcpy(name, devname, MAXPATHLEN); strlcpy(name, devname, MAXPATHLEN);
zfs_append_partition(name, MAXPATHLEN); zfs_append_partition(name, MAXPATHLEN);
} else { } else {
sprintf(name, "unknown");
zed_log_msg(LOG_INFO, "zfs_deliver_dle: no guid or physpath"); zed_log_msg(LOG_INFO, "zfs_deliver_dle: no guid or physpath");
} }
if (zpool_iter(g_zfshdl, zfsdle_vdev_online, nvl) != 1) { if (zpool_iter(g_zfshdl, zfsdle_vdev_online, name) != 1) {
zed_log_msg(LOG_INFO, "zfs_deliver_dle: device '%s' not " zed_log_msg(LOG_INFO, "zfs_deliver_dle: device '%s' not "
"found", name); "found", name);
return (1); return (1);
@ -1278,7 +900,7 @@ zfs_enum_pools(void *arg)
* For now, each agent has its own libzfs instance * For now, each agent has its own libzfs instance
*/ */
int int
zfs_slm_init(void) zfs_slm_init()
{ {
if ((g_zfshdl = libzfs_init()) == NULL) if ((g_zfshdl = libzfs_init()) == NULL)
return (-1); return (-1);
@ -1296,7 +918,6 @@ zfs_slm_init(void)
return (-1); return (-1);
} }
pthread_setname_np(g_zfs_tid, "enum-pools");
list_create(&g_device_list, sizeof (struct pendingdev), list_create(&g_device_list, sizeof (struct pendingdev),
offsetof(struct pendingdev, pd_node)); offsetof(struct pendingdev, pd_node));
@ -1304,7 +925,7 @@ zfs_slm_init(void)
} }
void void
zfs_slm_fini(void) zfs_slm_fini()
{ {
unavailpool_t *pool; unavailpool_t *pool;
pendingdev_t *device; pendingdev_t *device;

View File

@ -40,7 +40,6 @@
#include <sys/fm/fs/zfs.h> #include <sys/fm/fs/zfs.h>
#include <libzfs.h> #include <libzfs.h>
#include <string.h> #include <string.h>
#include <libgen.h>
#include "zfs_agents.h" #include "zfs_agents.h"
#include "fmd_api.h" #include "fmd_api.h"
@ -75,8 +74,6 @@ typedef struct find_cbdata {
uint64_t cb_guid; uint64_t cb_guid;
zpool_handle_t *cb_zhp; zpool_handle_t *cb_zhp;
nvlist_t *cb_vdev; nvlist_t *cb_vdev;
uint64_t cb_vdev_guid;
uint64_t cb_num_spares;
} find_cbdata_t; } find_cbdata_t;
static int static int
@ -142,64 +139,6 @@ find_vdev(libzfs_handle_t *zhdl, nvlist_t *nv, uint64_t search_guid)
return (NULL); return (NULL);
} }
static int
remove_spares(zpool_handle_t *zhp, void *data)
{
nvlist_t *config, *nvroot;
nvlist_t **spares;
uint_t nspares;
char *devname;
find_cbdata_t *cbp = data;
uint64_t spareguid = 0;
vdev_stat_t *vs;
unsigned int c;
config = zpool_get_config(zhp, NULL);
if (nvlist_lookup_nvlist(config,
ZPOOL_CONFIG_VDEV_TREE, &nvroot) != 0) {
zpool_close(zhp);
return (0);
}
if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
&spares, &nspares) != 0) {
zpool_close(zhp);
return (0);
}
for (int i = 0; i < nspares; i++) {
if (nvlist_lookup_uint64(spares[i], ZPOOL_CONFIG_GUID,
&spareguid) == 0 && spareguid == cbp->cb_vdev_guid) {
devname = zpool_vdev_name(NULL, zhp, spares[i],
B_FALSE);
nvlist_lookup_uint64_array(spares[i],
ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&vs, &c);
if (vs->vs_state != VDEV_STATE_REMOVED &&
zpool_vdev_remove_wanted(zhp, devname) == 0)
cbp->cb_num_spares++;
break;
}
}
zpool_close(zhp);
return (0);
}
/*
* Given a vdev guid, find and remove all spares associated with it.
*/
static int
find_and_remove_spares(libzfs_handle_t *zhdl, uint64_t vdev_guid)
{
find_cbdata_t cb;
cb.cb_num_spares = 0;
cb.cb_vdev_guid = vdev_guid;
zpool_iter(zhdl, remove_spares, &cb);
return (cb.cb_num_spares);
}
/* /*
* Given a (pool, vdev) GUID pair, find the matching pool and vdev. * Given a (pool, vdev) GUID pair, find the matching pool and vdev.
*/ */
@ -375,8 +314,6 @@ zfs_retire_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl,
libzfs_handle_t *zhdl = zdp->zrd_hdl; libzfs_handle_t *zhdl = zdp->zrd_hdl;
boolean_t fault_device, degrade_device; boolean_t fault_device, degrade_device;
boolean_t is_repair; boolean_t is_repair;
boolean_t l2arc = B_FALSE;
boolean_t spare = B_FALSE;
char *scheme; char *scheme;
nvlist_t *vdev = NULL; nvlist_t *vdev = NULL;
char *uuid; char *uuid;
@ -385,8 +322,6 @@ zfs_retire_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl,
boolean_t is_disk; boolean_t is_disk;
vdev_aux_t aux; vdev_aux_t aux;
uint64_t state = 0; uint64_t state = 0;
vdev_stat_t *vs;
unsigned int c;
fmd_hdl_debug(hdl, "zfs_retire_recv: '%s'", class); fmd_hdl_debug(hdl, "zfs_retire_recv: '%s'", class);
@ -403,31 +338,10 @@ zfs_retire_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl,
char *devtype; char *devtype;
char *devname; char *devname;
if (nvlist_lookup_string(nvl, FM_EREPORT_PAYLOAD_ZFS_VDEV_TYPE,
&devtype) == 0) {
if (strcmp(devtype, VDEV_TYPE_SPARE) == 0)
spare = B_TRUE;
else if (strcmp(devtype, VDEV_TYPE_L2CACHE) == 0)
l2arc = B_TRUE;
}
if (nvlist_lookup_uint64(nvl,
FM_EREPORT_PAYLOAD_ZFS_VDEV_GUID, &vdev_guid) != 0)
return;
if (vdev_guid == 0) {
fmd_hdl_debug(hdl, "Got a zero GUID");
return;
}
if (spare) {
int nspares = find_and_remove_spares(zhdl, vdev_guid);
fmd_hdl_debug(hdl, "%d spares removed", nspares);
return;
}
if (nvlist_lookup_uint64(nvl, FM_EREPORT_PAYLOAD_ZFS_POOL_GUID, if (nvlist_lookup_uint64(nvl, FM_EREPORT_PAYLOAD_ZFS_POOL_GUID,
&pool_guid) != 0) &pool_guid) != 0 ||
nvlist_lookup_uint64(nvl, FM_EREPORT_PAYLOAD_ZFS_VDEV_GUID,
&vdev_guid) != 0)
return; return;
if ((zhp = find_by_guid(zhdl, pool_guid, vdev_guid, if ((zhp = find_by_guid(zhdl, pool_guid, vdev_guid,
@ -436,30 +350,13 @@ zfs_retire_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl,
devname = zpool_vdev_name(NULL, zhp, vdev, B_FALSE); devname = zpool_vdev_name(NULL, zhp, vdev, B_FALSE);
nvlist_lookup_uint64_array(vdev, ZPOOL_CONFIG_VDEV_STATS, /* Can't replace l2arc with a spare: offline the device */
(uint64_t **)&vs, &c); if (nvlist_lookup_string(nvl, FM_EREPORT_PAYLOAD_ZFS_VDEV_TYPE,
&devtype) == 0 && strcmp(devtype, VDEV_TYPE_L2CACHE) == 0) {
/* fmd_hdl_debug(hdl, "zpool_vdev_offline '%s'", devname);
* If state removed is requested for already removed vdev, zpool_vdev_offline(zhp, devname, B_TRUE);
* its a loopback event from spa_async_remove(). Just } else if (!fmd_prop_get_int32(hdl, "spare_on_remove") ||
* ignore it. replace_with_spare(hdl, zhp, vdev) == B_FALSE) {
*/
if (vs->vs_state == VDEV_STATE_REMOVED &&
state == VDEV_STATE_REMOVED)
return;
/* Remove the vdev since device is unplugged */
int remove_status = 0;
if (l2arc || (strcmp(class, "resource.fs.zfs.removed") == 0)) {
remove_status = zpool_vdev_remove_wanted(zhp, devname);
fmd_hdl_debug(hdl, "zpool_vdev_remove_wanted '%s'"
", err:%d", devname, libzfs_errno(zhdl));
}
/* Replace the vdev with a spare if its not a l2arc */
if (!l2arc && !remove_status &&
(!fmd_prop_get_int32(hdl, "spare_on_remove") ||
replace_with_spare(hdl, zhp, vdev) == B_FALSE)) {
/* Could not handle with spare */ /* Could not handle with spare */
fmd_hdl_debug(hdl, "no spare for '%s'", devname); fmd_hdl_debug(hdl, "no spare for '%s'", devname);
} }

View File

@ -3,7 +3,7 @@
* *
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049). * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC. * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
* Refer to the OpenZFS git commit log for authoritative copyright attribution. * Refer to the ZoL git commit log for authoritative copyright attribution.
* *
* The contents of this file are subject to the terms of the * The contents of this file are subject to the terms of the
* Common Development and Distribution License Version 1.0 (CDDL-1.0). * Common Development and Distribution License Version 1.0 (CDDL-1.0).
@ -60,8 +60,8 @@ _setup_sig_handlers(void)
zed_log_die("Failed to initialize sigset"); zed_log_die("Failed to initialize sigset");
sa.sa_flags = SA_RESTART; sa.sa_flags = SA_RESTART;
sa.sa_handler = SIG_IGN; sa.sa_handler = SIG_IGN;
if (sigaction(SIGPIPE, &sa, NULL) < 0) if (sigaction(SIGPIPE, &sa, NULL) < 0)
zed_log_die("Failed to ignore SIGPIPE"); zed_log_die("Failed to ignore SIGPIPE");
@ -75,10 +75,6 @@ _setup_sig_handlers(void)
sa.sa_handler = _hup_handler; sa.sa_handler = _hup_handler;
if (sigaction(SIGHUP, &sa, NULL) < 0) if (sigaction(SIGHUP, &sa, NULL) < 0)
zed_log_die("Failed to register SIGHUP handler"); zed_log_die("Failed to register SIGHUP handler");
(void) sigaddset(&sa.sa_mask, SIGCHLD);
if (pthread_sigmask(SIG_BLOCK, &sa.sa_mask, NULL) < 0)
zed_log_die("Failed to block SIGCHLD");
} }
/* /*
@ -216,20 +212,22 @@ _finish_daemonize(void)
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
struct zed_conf zcp; struct zed_conf *zcp;
uint64_t saved_eid; uint64_t saved_eid;
int64_t saved_etime[2]; int64_t saved_etime[2];
zed_log_init(argv[0]); zed_log_init(argv[0]);
zed_log_stderr_open(LOG_NOTICE); zed_log_stderr_open(LOG_NOTICE);
zed_conf_init(&zcp); zcp = zed_conf_create();
zed_conf_parse_opts(&zcp, argc, argv); zed_conf_parse_opts(zcp, argc, argv);
if (zcp.do_verbose) if (zcp->do_verbose)
zed_log_stderr_open(LOG_INFO); zed_log_stderr_open(LOG_INFO);
if (geteuid() != 0) if (geteuid() != 0)
zed_log_die("Must be run as root"); zed_log_die("Must be run as root");
zed_conf_parse_file(zcp);
zed_file_close_from(STDERR_FILENO + 1); zed_file_close_from(STDERR_FILENO + 1);
(void) umask(0); (void) umask(0);
@ -237,32 +235,32 @@ main(int argc, char *argv[])
if (chdir("/") < 0) if (chdir("/") < 0)
zed_log_die("Failed to change to root directory"); zed_log_die("Failed to change to root directory");
if (zed_conf_scan_dir(&zcp) < 0) if (zed_conf_scan_dir(zcp) < 0)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
if (!zcp.do_foreground) { if (!zcp->do_foreground) {
_start_daemonize(); _start_daemonize();
zed_log_syslog_open(LOG_DAEMON); zed_log_syslog_open(LOG_DAEMON);
} }
_setup_sig_handlers(); _setup_sig_handlers();
if (zcp.do_memlock) if (zcp->do_memlock)
_lock_memory(); _lock_memory();
if ((zed_conf_write_pid(&zcp) < 0) && (!zcp.do_force)) if ((zed_conf_write_pid(zcp) < 0) && (!zcp->do_force))
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
if (!zcp.do_foreground) if (!zcp->do_foreground)
_finish_daemonize(); _finish_daemonize();
zed_log_msg(LOG_NOTICE, zed_log_msg(LOG_NOTICE,
"ZFS Event Daemon %s-%s (PID %d)", "ZFS Event Daemon %s-%s (PID %d)",
ZFS_META_VERSION, ZFS_META_RELEASE, (int)getpid()); ZFS_META_VERSION, ZFS_META_RELEASE, (int)getpid());
if (zed_conf_open_state(&zcp) < 0) if (zed_conf_open_state(zcp) < 0)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
if (zed_conf_read_state(&zcp, &saved_eid, saved_etime) < 0) if (zed_conf_read_state(zcp, &saved_eid, saved_etime) < 0)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
idle: idle:
@ -271,38 +269,38 @@ idle:
* successful. * successful.
*/ */
do { do {
if (!zed_event_init(&zcp)) if (!zed_event_init(zcp))
break; break;
/* Wait for some time and try again. tunable? */ /* Wait for some time and try again. tunable? */
sleep(30); sleep(30);
} while (!_got_exit && zcp.do_idle); } while (!_got_exit && zcp->do_idle);
if (_got_exit) if (_got_exit)
goto out; goto out;
zed_event_seek(&zcp, saved_eid, saved_etime); zed_event_seek(zcp, saved_eid, saved_etime);
while (!_got_exit) { while (!_got_exit) {
int rv; int rv;
if (_got_hup) { if (_got_hup) {
_got_hup = 0; _got_hup = 0;
(void) zed_conf_scan_dir(&zcp); (void) zed_conf_scan_dir(zcp);
} }
rv = zed_event_service(&zcp); rv = zed_event_service(zcp);
/* ENODEV: When kernel module is unloaded (osx) */ /* ENODEV: When kernel module is unloaded (osx) */
if (rv != 0) if (rv == ENODEV)
break; break;
} }
zed_log_msg(LOG_NOTICE, "Exiting"); zed_log_msg(LOG_NOTICE, "Exiting");
zed_event_fini(&zcp); zed_event_fini(zcp);
if (zcp.do_idle && !_got_exit) if (zcp->do_idle && !_got_exit)
goto idle; goto idle;
out: out:
zed_conf_destroy(&zcp); zed_conf_destroy(zcp);
zed_log_fini(); zed_log_fini();
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }

View File

@ -1,6 +1,5 @@
include $(top_srcdir)/config/Rules.am include $(top_srcdir)/config/Rules.am
include $(top_srcdir)/config/Substfiles.am include $(top_srcdir)/config/Substfiles.am
include $(top_srcdir)/config/Shellcheck.am
EXTRA_DIST += README EXTRA_DIST += README
@ -21,7 +20,6 @@ dist_zedexec_SCRIPTS = \
scrub_finish-notify.sh \ scrub_finish-notify.sh \
statechange-led.sh \ statechange-led.sh \
statechange-notify.sh \ statechange-notify.sh \
statechange-slot_off.sh \
vdev_clear-led.sh \ vdev_clear-led.sh \
vdev_attach-led.sh \ vdev_attach-led.sh \
pool_import-led.sh \ pool_import-led.sh \
@ -40,7 +38,6 @@ zedconfdefaults = \
scrub_finish-notify.sh \ scrub_finish-notify.sh \
statechange-led.sh \ statechange-led.sh \
statechange-notify.sh \ statechange-notify.sh \
statechange-slot_off.sh \
vdev_clear-led.sh \ vdev_clear-led.sh \
vdev_attach-led.sh \ vdev_attach-led.sh \
pool_import-led.sh \ pool_import-led.sh \
@ -54,6 +51,3 @@ install-data-hook:
ln -s "$(zedexecdir)/$${f}" "$(DESTDIR)$(zedconfdir)"; \ ln -s "$(zedexecdir)/$${f}" "$(DESTDIR)$(zedconfdir)"; \
done done
chmod 0600 "$(DESTDIR)$(zedconfdir)/zed.rc" chmod 0600 "$(DESTDIR)$(zedconfdir)/zed.rc"
# False positive: 1>&"${ZED_FLOCK_FD}" looks suspiciously similar to a >&filename bash extension
CHECKBASHISMS_IGNORE = -e 'should be >word 2>&1' -e '&"$${ZED_FLOCK_FD}"'

View File

@ -12,11 +12,15 @@
zed_exit_if_ignoring_this_event zed_exit_if_ignoring_this_event
zed_lock "${ZED_DEBUG_LOG}" lockfile="$(basename -- "${ZED_DEBUG_LOG}").lock"
{
printenv | sort
echo
} 1>&"${ZED_FLOCK_FD}"
zed_unlock "${ZED_DEBUG_LOG}"
umask 077
zed_lock "${lockfile}"
exec >> "${ZED_DEBUG_LOG}"
printenv | sort
echo
exec >&-
zed_unlock "${lockfile}"
exit 0 exit 0

View File

@ -21,7 +21,7 @@ if [ "${ZED_SYSLOG_DISPLAY_GUIDS}" = "1" ]; then
[ -n "${ZEVENT_VDEV_GUID}" ] && msg="${msg} vdev_guid=${ZEVENT_VDEV_GUID}" [ -n "${ZEVENT_VDEV_GUID}" ] && msg="${msg} vdev_guid=${ZEVENT_VDEV_GUID}"
else else
[ -n "${ZEVENT_POOL}" ] && msg="${msg} pool='${ZEVENT_POOL}'" [ -n "${ZEVENT_POOL}" ] && msg="${msg} pool='${ZEVENT_POOL}'"
[ -n "${ZEVENT_VDEV_PATH}" ] && msg="${msg} vdev=${ZEVENT_VDEV_PATH##*/}" [ -n "${ZEVENT_VDEV_PATH}" ] && msg="${msg} vdev=$(basename "${ZEVENT_VDEV_PATH}")"
fi fi
# log pool state if state is anything other than 'ACTIVE' # log pool state if state is anything other than 'ACTIVE'
@ -42,7 +42,6 @@ fi
msg="${msg} delay=$((ZEVENT_ZIO_DELAY / 1000000))ms" msg="${msg} delay=$((ZEVENT_ZIO_DELAY / 1000000))ms"
# list the bookmark data together # list the bookmark data together
# shellcheck disable=SC2153
[ -n "${ZEVENT_ZIO_OBJSET}" ] && \ [ -n "${ZEVENT_ZIO_OBJSET}" ] && \
msg="${msg} bookmark=${ZEVENT_ZIO_OBJSET}:${ZEVENT_ZIO_OBJECT}:${ZEVENT_ZIO_LEVEL}:${ZEVENT_ZIO_BLKID}" msg="${msg} bookmark=${ZEVENT_ZIO_OBJSET}:${ZEVENT_ZIO_OBJECT}:${ZEVENT_ZIO_LEVEL}:${ZEVENT_ZIO_BLKID}"

View File

@ -25,7 +25,7 @@ zed_rate_limit "${rate_limit_tag}" || exit 3
umask 077 umask 077
note_subject="ZFS ${ZEVENT_SUBCLASS} error for ${ZEVENT_POOL} on $(hostname)" note_subject="ZFS ${ZEVENT_SUBCLASS} error for ${ZEVENT_POOL} on $(hostname)"
note_pathname="$(mktemp)" note_pathname="${TMPDIR:="/tmp"}/$(basename -- "$0").${ZEVENT_EID}.$$"
{ {
echo "ZFS has detected a data error:" echo "ZFS has detected a data error:"
echo echo

View File

@ -23,7 +23,7 @@
# Rate-limit the notification based in part on the filename. # Rate-limit the notification based in part on the filename.
# #
rate_limit_tag="${ZEVENT_POOL};${ZEVENT_SUBCLASS};${0##*/}" rate_limit_tag="${ZEVENT_POOL};${ZEVENT_SUBCLASS};$(basename -- "$0")"
rate_limit_interval="${ZED_NOTIFY_INTERVAL_SECS}" rate_limit_interval="${ZED_NOTIFY_INTERVAL_SECS}"
zed_rate_limit "${rate_limit_tag}" "${rate_limit_interval}" || exit 3 zed_rate_limit "${rate_limit_tag}" "${rate_limit_interval}" || exit 3
@ -31,7 +31,7 @@ umask 077
pool_str="${ZEVENT_POOL:+" for ${ZEVENT_POOL}"}" pool_str="${ZEVENT_POOL:+" for ${ZEVENT_POOL}"}"
host_str=" on $(hostname)" host_str=" on $(hostname)"
note_subject="ZFS ${ZEVENT_SUBCLASS} event${pool_str}${host_str}" note_subject="ZFS ${ZEVENT_SUBCLASS} event${pool_str}${host_str}"
note_pathname="$(mktemp)" note_pathname="${TMPDIR:="/tmp"}/$(basename -- "$0").${ZEVENT_EID}.$$"
{ {
echo "ZFS has posted the following event:" echo "ZFS has posted the following event:"
echo echo

View File

@ -3,8 +3,9 @@
# Track changes to enumerated pools for use in early-boot # Track changes to enumerated pools for use in early-boot
set -ef set -ef
FSLIST="@sysconfdir@/zfs/zfs-list.cache/${ZEVENT_POOL}" FSLIST_DIR="@sysconfdir@/zfs/zfs-list.cache"
FSLIST_TMP="@runstatedir@/zfs-list.cache@${ZEVENT_POOL}" FSLIST_TMP="@runstatedir@/zfs-list.cache.new"
FSLIST="${FSLIST_DIR}/${ZEVENT_POOL}"
# If the pool specific cache file is not writeable, abort # If the pool specific cache file is not writeable, abort
[ -w "${FSLIST}" ] || exit 0 [ -w "${FSLIST}" ] || exit 0
@ -13,20 +14,20 @@ FSLIST_TMP="@runstatedir@/zfs-list.cache@${ZEVENT_POOL}"
. "${ZED_ZEDLET_DIR}/zed-functions.sh" . "${ZED_ZEDLET_DIR}/zed-functions.sh"
[ "$ZEVENT_SUBCLASS" != "history_event" ] && exit 0 [ "$ZEVENT_SUBCLASS" != "history_event" ] && exit 0
zed_check_cmd "${ZFS}" sort diff zed_check_cmd "${ZFS}" sort diff grep
# If we are acting on a snapshot, we have nothing to do # If we are acting on a snapshot, we have nothing to do
[ "${ZEVENT_HISTORY_DSNAME%@*}" = "${ZEVENT_HISTORY_DSNAME}" ] || exit 0 printf '%s' "${ZEVENT_HISTORY_DSNAME}" | grep '@' && exit 0
# We lock the output file to avoid simultaneous writes. # We obtain a lock on zfs-list to avoid any simultaneous writes.
# If we run into trouble, log and drop the lock # If we run into trouble, log and drop the lock
abort_alter() { abort_alter() {
zed_log_msg "Error updating zfs-list.cache for ${ZEVENT_POOL}!" zed_log_msg "Error updating zfs-list.cache!"
zed_unlock "${FSLIST}" zed_unlock zfs-list
} }
finished() { finished() {
zed_unlock "${FSLIST}" zed_unlock zfs-list
trap - EXIT trap - EXIT
exit 0 exit 0
} }
@ -36,7 +37,7 @@ case "${ZEVENT_HISTORY_INTERNAL_NAME}" in
;; ;;
export) export)
zed_lock "${FSLIST}" zed_lock zfs-list
trap abort_alter EXIT trap abort_alter EXIT
echo > "${FSLIST}" echo > "${FSLIST}"
finished finished
@ -62,7 +63,7 @@ case "${ZEVENT_HISTORY_INTERNAL_NAME}" in
;; ;;
esac esac
zed_lock "${FSLIST}" zed_lock zfs-list
trap abort_alter EXIT trap abort_alter EXIT
PROPS="name,mountpoint,canmount,atime,relatime,devices,exec\ PROPS="name,mountpoint,canmount,atime,relatime,devices,exec\
@ -78,7 +79,7 @@ PROPS="name,mountpoint,canmount,atime,relatime,devices,exec\
sort "${FSLIST_TMP}" -o "${FSLIST_TMP}" sort "${FSLIST_TMP}" -o "${FSLIST_TMP}"
# Don't modify the file if it hasn't changed # Don't modify the file if it hasn't changed
diff -q "${FSLIST_TMP}" "${FSLIST}" || cat "${FSLIST_TMP}" > "${FSLIST}" diff -q "${FSLIST_TMP}" "${FSLIST}" || mv "${FSLIST_TMP}" "${FSLIST}"
rm -f "${FSLIST_TMP}" rm -f "${FSLIST_TMP}"
finished finished

View File

@ -41,7 +41,7 @@ fi
umask 077 umask 077
note_subject="ZFS ${ZEVENT_SUBCLASS} event for ${ZEVENT_POOL} on $(hostname)" note_subject="ZFS ${ZEVENT_SUBCLASS} event for ${ZEVENT_POOL} on $(hostname)"
note_pathname="$(mktemp)" note_pathname="${TMPDIR:="/tmp"}/$(basename -- "$0").${ZEVENT_EID}.$$"
{ {
echo "ZFS has finished a ${action}:" echo "ZFS has finished a ${action}:"
echo echo

View File

@ -1,21 +1,21 @@
#!/bin/sh #!/bin/sh
# #
# Turn off/on vdevs' enclosure fault LEDs when their pool's state changes. # Turn off/on the VDEV's enclosure fault LEDs when the pool's state changes.
# #
# Turn a vdev's fault LED on if it becomes FAULTED, DEGRADED or UNAVAIL. # Turn the VDEV's fault LED on if it becomes FAULTED, DEGRADED or UNAVAIL.
# Turn its LED off when it's back ONLINE again. # Turn the LED off when it's back ONLINE again.
# #
# This script run in two basic modes: # This script run in two basic modes:
# #
# 1. If $ZEVENT_VDEV_ENC_SYSFS_PATH and $ZEVENT_VDEV_STATE_STR are set, then # 1. If $ZEVENT_VDEV_ENC_SYSFS_PATH and $ZEVENT_VDEV_STATE_STR are set, then
# only set the LED for that particular vdev. This is the case for statechange # only set the LED for that particular VDEV. This is the case for statechange
# events and some vdev_* events. # events and some vdev_* events.
# #
# 2. If those vars are not set, then check the state of all vdevs in the pool # 2. If those vars are not set, then check the state of all VDEVs in the pool
# and set the LEDs accordingly. This is the case for pool_import events. # and set the LEDs accordingly. This is the case for pool_import events.
# #
# Note that this script requires that your enclosure be supported by the # Note that this script requires that your enclosure be supported by the
# Linux SCSI Enclosure services (SES) driver. The script will do nothing # Linux SCSI enclosure services (ses) driver. The script will do nothing
# if you have no enclosure, or if your enclosure isn't supported. # if you have no enclosure, or if your enclosure isn't supported.
# #
# Exit codes: # Exit codes:
@ -29,8 +29,7 @@
[ -f "${ZED_ZEDLET_DIR}/zed.rc" ] && . "${ZED_ZEDLET_DIR}/zed.rc" [ -f "${ZED_ZEDLET_DIR}/zed.rc" ] && . "${ZED_ZEDLET_DIR}/zed.rc"
. "${ZED_ZEDLET_DIR}/zed-functions.sh" . "${ZED_ZEDLET_DIR}/zed-functions.sh"
if [ ! -d /sys/class/enclosure ] && [ ! -d /sys/bus/pci/slots ] ; then if [ ! -d /sys/class/enclosure ] ; then
# No JBOD enclosure or NVMe slots
exit 1 exit 1
fi fi
@ -60,10 +59,6 @@ check_and_set_led()
file="$1" file="$1"
val="$2" val="$2"
if [ -z "$val" ]; then
return 0
fi
if [ ! -e "$file" ] ; then if [ ! -e "$file" ] ; then
return 3 return 3
fi fi
@ -71,11 +66,11 @@ check_and_set_led()
# If another process is accessing the LED when we attempt to update it, # If another process is accessing the LED when we attempt to update it,
# the update will be lost so retry until the LED actually changes or we # the update will be lost so retry until the LED actually changes or we
# timeout. # timeout.
for _ in 1 2 3 4 5; do for _ in $(seq 1 5); do
# We want to check the current state first, since writing to the # We want to check the current state first, since writing to the
# 'fault' entry always causes a SES command, even if the # 'fault' entry always causes a SES command, even if the
# current state is already what you want. # current state is already what you want.
read -r current < "${file}" current=$(cat "${file}")
# On some enclosures if you write 1 to fault, and read it back, # On some enclosures if you write 1 to fault, and read it back,
# it will return 2. Treat all non-zero values as 1 for # it will return 2. Treat all non-zero values as 1 for
@ -93,81 +88,24 @@ check_and_set_led()
done done
} }
# Fault LEDs for JBODs and NVMe drives are handled a little differently.
#
# On JBODs the fault LED is called 'fault' and on a path like this:
#
# /sys/class/enclosure/0:0:1:0/SLOT 10/fault
#
# On NVMe it's called 'attention' and on a path like this:
#
# /sys/bus/pci/slot/0/attention
#
# This function returns the full path to the fault LED file for a given
# enclosure/slot directory.
#
path_to_led()
{
dir=$1
if [ -f "$dir/fault" ] ; then
echo "$dir/fault"
elif [ -f "$dir/attention" ] ; then
echo "$dir/attention"
fi
}
state_to_val() state_to_val()
{ {
state="$1" state="$1"
case "$state" in if [ "$state" = "FAULTED" ] || [ "$state" = "DEGRADED" ] || \
FAULTED|DEGRADED|UNAVAIL) [ "$state" = "UNAVAIL" ] ; then
echo 1 echo 1
;; elif [ "$state" = "ONLINE" ] ; then
ONLINE)
echo 0 echo 0
;;
esac
}
#
# Given a nvme name like 'nvme0n1', pass back its slot directory
# like "/sys/bus/pci/slots/0"
#
nvme_dev_to_slot()
{
dev="$1"
# Get the address "0000:01:00.0"
address=$(cat "/sys/class/block/$dev/device/address")
# For each /sys/bus/pci/slots subdir that is an actual number
# (rather than weird directories like "1-3/").
# shellcheck disable=SC2010
for i in $(ls /sys/bus/pci/slots/ | grep -E "^[0-9]+$") ; do
this_address=$(cat "/sys/bus/pci/slots/$i/address")
# The format of address is a little different between
# /sys/class/block/$dev/device/address and
# /sys/bus/pci/slots/
#
# address= "0000:01:00.0"
# this_address = "0000:01:00"
#
if echo "$address" | grep -Eq ^"$this_address" ; then
echo "/sys/bus/pci/slots/$i"
break
fi fi
done
} }
# process_pool ([pool])
# process_pool (pool)
# #
# Iterate through a pool and set the vdevs' enclosure slot LEDs to # Iterate through a pool (or pools) and set the VDEV's enclosure slot LEDs to
# those vdevs' state. # the VDEV's state.
# #
# Arguments # Arguments
# pool: Pool name. # pool: Optional pool name. If not specified, iterate though all pools.
# #
# Return # Return
# 0 on success, 3 on missing sysfs path # 0 on success, 3 on missing sysfs path
@ -175,27 +113,19 @@ nvme_dev_to_slot()
process_pool() process_pool()
{ {
pool="$1" pool="$1"
# The output will be the vdevs only (from "grep '/dev/'"):
#
# U45 ONLINE 0 0 0 /dev/sdk 0
# U46 ONLINE 0 0 0 /dev/sdm 0
# U47 ONLINE 0 0 0 /dev/sdn 0
# U50 ONLINE 0 0 0 /dev/sdbn 0
#
ZPOOL_SCRIPTS_AS_ROOT=1 $ZPOOL status -c upath,fault_led "$pool" | grep '/dev/' | (
rc=0 rc=0
while read -r vdev state _ _ _ therest; do
# Read out current LED value and path
# Get dev name (like 'sda')
dev=$(basename "$(echo "$therest" | awk '{print $(NF-1)}')")
vdev_enc_sysfs_path=$(realpath "/sys/class/block/$dev/device/enclosure_device"*)
if [ ! -d "$vdev_enc_sysfs_path" ] ; then
# This is not a JBOD disk, but it could be a PCI NVMe drive
vdev_enc_sysfs_path=$(nvme_dev_to_slot "$dev")
fi
current_val=$(echo "$therest" | awk '{print $NF}') # Lookup all the current LED values and paths in parallel
#shellcheck disable=SC2016
cmd='echo led_token=$(cat "$VDEV_ENC_SYSFS_PATH/fault"),"$VDEV_ENC_SYSFS_PATH",'
out=$($ZPOOL status -vc "$cmd" "$pool" | grep 'led_token=')
#shellcheck disable=SC2034
echo "$out" | while read -r vdev state read write chksum therest; do
# Read out current LED value and path
tmp=$(echo "$therest" | sed 's/^.*led_token=//g')
vdev_enc_sysfs_path=$(echo "$tmp" | awk -F ',' '{print $2}')
current_val=$(echo "$tmp" | awk -F ',' '{print $1}')
if [ "$current_val" != "0" ] ; then if [ "$current_val" != "0" ] ; then
current_val=1 current_val=1
@ -206,33 +136,40 @@ process_pool()
continue continue
fi fi
led_path=$(path_to_led "$vdev_enc_sysfs_path") if [ ! -e "$vdev_enc_sysfs_path/fault" ] ; then
if [ ! -e "$led_path" ] ; then #shellcheck disable=SC2030
rc=3 rc=1
zed_log_msg "vdev $vdev '$led_path' doesn't exist" zed_log_msg "vdev $vdev '$file/fault' doesn't exist"
continue continue;
fi fi
val=$(state_to_val "$state") val=$(state_to_val "$state")
if [ "$current_val" = "$val" ] ; then if [ "$current_val" = "$val" ] ; then
# LED is already set correctly # LED is already set correctly
continue continue;
fi fi
if ! check_and_set_led "$led_path" "$val"; then if ! check_and_set_led "$vdev_enc_sysfs_path/fault" "$val"; then
rc=3 rc=1
fi fi
done done
exit "$rc"; )
#shellcheck disable=SC2031
if [ "$rc" = "0" ] ; then
return 0
else
# We didn't see a sysfs entry that we wanted to set
return 3
fi
} }
if [ -n "$ZEVENT_VDEV_ENC_SYSFS_PATH" ] && [ -n "$ZEVENT_VDEV_STATE_STR" ] ; then if [ -n "$ZEVENT_VDEV_ENC_SYSFS_PATH" ] && [ -n "$ZEVENT_VDEV_STATE_STR" ] ; then
# Got a statechange for an individual vdev # Got a statechange for an individual VDEV
val=$(state_to_val "$ZEVENT_VDEV_STATE_STR") val=$(state_to_val "$ZEVENT_VDEV_STATE_STR")
vdev=$(basename "$ZEVENT_VDEV_PATH") vdev=$(basename "$ZEVENT_VDEV_PATH")
ledpath=$(path_to_led "$ZEVENT_VDEV_ENC_SYSFS_PATH") check_and_set_led "$ZEVENT_VDEV_ENC_SYSFS_PATH/fault" "$val"
check_and_set_led "$ledpath" "$val"
else else
# Process the entire pool # Process the entire pool
poolname=$(zed_guid_to_pool "$ZEVENT_POOL_GUID") poolname=$(zed_guid_to_pool "$ZEVENT_POOL_GUID")

View File

@ -15,7 +15,7 @@
# Send notification in response to a fault induced statechange # Send notification in response to a fault induced statechange
# #
# ZEVENT_SUBCLASS: 'statechange' # ZEVENT_SUBCLASS: 'statechange'
# ZEVENT_VDEV_STATE_STR: 'DEGRADED', 'FAULTED', 'REMOVED', or 'UNAVAIL' # ZEVENT_VDEV_STATE_STR: 'DEGRADED', 'FAULTED' or 'REMOVED'
# #
# Exit codes: # Exit codes:
# 0: notification sent # 0: notification sent
@ -31,14 +31,13 @@
if [ "${ZEVENT_VDEV_STATE_STR}" != "FAULTED" ] \ if [ "${ZEVENT_VDEV_STATE_STR}" != "FAULTED" ] \
&& [ "${ZEVENT_VDEV_STATE_STR}" != "DEGRADED" ] \ && [ "${ZEVENT_VDEV_STATE_STR}" != "DEGRADED" ] \
&& [ "${ZEVENT_VDEV_STATE_STR}" != "REMOVED" ] \ && [ "${ZEVENT_VDEV_STATE_STR}" != "REMOVED" ]; then
&& [ "${ZEVENT_VDEV_STATE_STR}" != "UNAVAIL" ]; then
exit 3 exit 3
fi fi
umask 077 umask 077
note_subject="ZFS device fault for pool ${ZEVENT_POOL} on $(hostname)" note_subject="ZFS device fault for pool ${ZEVENT_POOL_GUID} on $(hostname)"
note_pathname="$(mktemp)" note_pathname="${TMPDIR:="/tmp"}/$(basename -- "$0").${ZEVENT_EID}.$$"
{ {
if [ "${ZEVENT_VDEV_STATE_STR}" = "FAULTED" ] ; then if [ "${ZEVENT_VDEV_STATE_STR}" = "FAULTED" ] ; then
echo "The number of I/O errors associated with a ZFS device exceeded" echo "The number of I/O errors associated with a ZFS device exceeded"
@ -65,7 +64,7 @@ note_pathname="$(mktemp)"
[ -n "${ZEVENT_VDEV_GUID}" ] && echo " vguid: ${ZEVENT_VDEV_GUID}" [ -n "${ZEVENT_VDEV_GUID}" ] && echo " vguid: ${ZEVENT_VDEV_GUID}"
[ -n "${ZEVENT_VDEV_DEVID}" ] && echo " devid: ${ZEVENT_VDEV_DEVID}" [ -n "${ZEVENT_VDEV_DEVID}" ] && echo " devid: ${ZEVENT_VDEV_DEVID}"
echo " pool: ${ZEVENT_POOL} (${ZEVENT_POOL_GUID})" echo " pool: ${ZEVENT_POOL_GUID}"
} > "${note_pathname}" } > "${note_pathname}"

View File

@ -1,64 +0,0 @@
#!/bin/sh
# shellcheck disable=SC3014,SC2154,SC2086,SC2034
#
# Turn off disk's enclosure slot if it becomes FAULTED.
#
# Bad SCSI disks can often "disappear and reappear" causing all sorts of chaos
# as they flip between FAULTED and ONLINE. If
# ZED_POWER_OFF_ENCLOSURE_SLOT_ON_FAULT is set in zed.rc, and the disk gets
# FAULTED, then power down the slot via sysfs:
#
# /sys/class/enclosure/<enclosure>/<slot>/power_status
#
# We assume the user will be responsible for turning the slot back on again.
#
# Note that this script requires that your enclosure be supported by the
# Linux SCSI Enclosure services (SES) driver. The script will do nothing
# if you have no enclosure, or if your enclosure isn't supported.
#
# Exit codes:
# 0: slot successfully powered off
# 1: enclosure not available
# 2: ZED_POWER_OFF_ENCLOSURE_SLOT_ON_FAULT disabled
# 3: vdev was not FAULTED
# 4: The enclosure sysfs path passed from ZFS does not exist
# 5: Enclosure slot didn't actually turn off after we told it to
[ -f "${ZED_ZEDLET_DIR}/zed.rc" ] && . "${ZED_ZEDLET_DIR}/zed.rc"
. "${ZED_ZEDLET_DIR}/zed-functions.sh"
if [ ! -d /sys/class/enclosure ] ; then
# No JBOD enclosure or NVMe slots
exit 1
fi
if [ "${ZED_POWER_OFF_ENCLOSURE_SLOT_ON_FAULT}" != "1" ] ; then
exit 2
fi
if [ "$ZEVENT_VDEV_STATE_STR" != "FAULTED" ] ; then
exit 3
fi
if [ ! -f "$ZEVENT_VDEV_ENC_SYSFS_PATH/power_status" ] ; then
exit 4
fi
# Turn off the slot and wait for sysfs to report that the slot is off.
# It can take ~400ms on some enclosures and multiple retries may be needed.
for i in $(seq 1 20) ; do
echo "off" | tee "$ZEVENT_VDEV_ENC_SYSFS_PATH/power_status"
for j in $(seq 1 5) ; do
if [ "$(cat $ZEVENT_VDEV_ENC_SYSFS_PATH/power_status)" == "off" ] ; then
break 2
fi
sleep 0.1
done
done
if [ "$(cat $ZEVENT_VDEV_ENC_SYSFS_PATH/power_status)" != "off" ] ; then
exit 5
fi
zed_log_msg "powered down slot $ZEVENT_VDEV_ENC_SYSFS_PATH for $ZEVENT_VDEV_PATH"

View File

@ -19,7 +19,7 @@ zed_check_cmd "${ZPOOL}" || exit 9
umask 077 umask 077
note_subject="ZFS ${ZEVENT_SUBCLASS} event for ${ZEVENT_POOL} on $(hostname)" note_subject="ZFS ${ZEVENT_SUBCLASS} event for ${ZEVENT_POOL} on $(hostname)"
note_pathname="$(mktemp)" note_pathname="${TMPDIR:="/tmp"}/$(basename -- "$0").${ZEVENT_EID}.$$"
{ {
echo "ZFS has finished a trim:" echo "ZFS has finished a trim:"
echo echo

View File

@ -77,7 +77,7 @@ zed_log_msg()
zed_log_err() zed_log_err()
{ {
logger -p "${ZED_SYSLOG_PRIORITY}" -t "${ZED_SYSLOG_TAG}" -- "error:" \ logger -p "${ZED_SYSLOG_PRIORITY}" -t "${ZED_SYSLOG_TAG}" -- "error:" \
"${0##*/}:""${ZEVENT_EID:+" eid=${ZEVENT_EID}:"}" "$@" "$(basename -- "$0"):""${ZEVENT_EID:+" eid=${ZEVENT_EID}:"}" "$@"
} }
@ -126,8 +126,10 @@ zed_lock()
# Obtain a lock on the file bound to the given file descriptor. # Obtain a lock on the file bound to the given file descriptor.
# #
eval "exec ${fd}>> '${lockfile}'" eval "exec ${fd}> '${lockfile}'"
if ! err="$(flock --exclusive "${fd}" 2>&1)"; then err="$(flock --exclusive "${fd}" 2>&1)"
# shellcheck disable=SC2181
if [ $? -ne 0 ]; then
zed_log_err "failed to lock \"${lockfile}\": ${err}" zed_log_err "failed to lock \"${lockfile}\": ${err}"
fi fi
@ -163,7 +165,9 @@ zed_unlock()
fi fi
# Release the lock and close the file descriptor. # Release the lock and close the file descriptor.
if ! err="$(flock --unlock "${fd}" 2>&1)"; then err="$(flock --unlock "${fd}" 2>&1)"
# shellcheck disable=SC2181
if [ $? -ne 0 ]; then
zed_log_err "failed to unlock \"${lockfile}\": ${err}" zed_log_err "failed to unlock \"${lockfile}\": ${err}"
fi fi
eval "exec ${fd}>&-" eval "exec ${fd}>&-"
@ -202,10 +206,6 @@ zed_notify()
[ "${rv}" -eq 0 ] && num_success=$((num_success + 1)) [ "${rv}" -eq 0 ] && num_success=$((num_success + 1))
[ "${rv}" -eq 1 ] && num_failure=$((num_failure + 1)) [ "${rv}" -eq 1 ] && num_failure=$((num_failure + 1))
zed_notify_pushover "${subject}" "${pathname}"; rv=$?
[ "${rv}" -eq 0 ] && num_success=$((num_success + 1))
[ "${rv}" -eq 1 ] && num_failure=$((num_failure + 1))
[ "${num_success}" -gt 0 ] && return 0 [ "${num_success}" -gt 0 ] && return 0
[ "${num_failure}" -gt 0 ] && return 1 [ "${num_failure}" -gt 0 ] && return 1
return 2 return 2
@ -224,8 +224,6 @@ zed_notify()
# ZED_EMAIL_OPTS. This undergoes the following keyword substitutions: # ZED_EMAIL_OPTS. This undergoes the following keyword substitutions:
# - @ADDRESS@ is replaced with the space-delimited recipient email address(es) # - @ADDRESS@ is replaced with the space-delimited recipient email address(es)
# - @SUBJECT@ is replaced with the notification subject # - @SUBJECT@ is replaced with the notification subject
# If @SUBJECT@ was omited here, a "Subject: ..." header will be added to notification
#
# #
# Arguments # Arguments
# subject: notification subject # subject: notification subject
@ -243,7 +241,7 @@ zed_notify()
# #
zed_notify_email() zed_notify_email()
{ {
local subject="${1:-"ZED notification"}" local subject="$1"
local pathname="${2:-"/dev/null"}" local pathname="${2:-"/dev/null"}"
: "${ZED_EMAIL_PROG:="mail"}" : "${ZED_EMAIL_PROG:="mail"}"
@ -260,30 +258,19 @@ zed_notify_email()
[ -n "${subject}" ] || return 1 [ -n "${subject}" ] || return 1
if [ ! -r "${pathname}" ]; then if [ ! -r "${pathname}" ]; then
zed_log_err \ zed_log_err \
"${ZED_EMAIL_PROG##*/} cannot read \"${pathname}\"" "$(basename "${ZED_EMAIL_PROG}") cannot read \"${pathname}\""
return 1 return 1
fi fi
# construct cmdline options ZED_EMAIL_OPTS="$(echo "${ZED_EMAIL_OPTS}" \
ZED_EMAIL_OPTS_PARSED="$(echo "${ZED_EMAIL_OPTS}" \
| sed -e "s/@ADDRESS@/${ZED_EMAIL_ADDR}/g" \ | sed -e "s/@ADDRESS@/${ZED_EMAIL_ADDR}/g" \
-e "s/@SUBJECT@/${subject}/g")" -e "s/@SUBJECT@/${subject}/g")"
# pipe message to email prog # shellcheck disable=SC2086
# shellcheck disable=SC2086,SC2248 eval "${ZED_EMAIL_PROG}" ${ZED_EMAIL_OPTS} < "${pathname}" >/dev/null 2>&1
{
# no subject passed as option?
if [ "${ZED_EMAIL_OPTS%@SUBJECT@*}" = "${ZED_EMAIL_OPTS}" ] ; then
# inject subject header
printf "Subject: %s\n" "${subject}"
fi
# output message
cat "${pathname}"
} |
eval ${ZED_EMAIL_PROG} ${ZED_EMAIL_OPTS_PARSED} >/dev/null 2>&1
rv=$? rv=$?
if [ "${rv}" -ne 0 ]; then if [ "${rv}" -ne 0 ]; then
zed_log_err "${ZED_EMAIL_PROG##*/} exit=${rv}" zed_log_err "$(basename "${ZED_EMAIL_PROG}") exit=${rv}"
return 1 return 1
fi fi
return 0 return 0
@ -430,7 +417,7 @@ zed_notify_slack_webhook()
# Construct the JSON message for posting. # Construct the JSON message for posting.
# #
msg_json="$(printf '{"text": "*%s*\\n%s"}' "${subject}" "${msg_body}" )" msg_json="$(printf '{"text": "*%s*\n%s"}' "${subject}" "${msg_body}" )"
# Send the POST request and check for errors. # Send the POST request and check for errors.
# #
@ -450,84 +437,6 @@ zed_notify_slack_webhook()
return 0 return 0
} }
# zed_notify_pushover (subject, pathname)
#
# Send a notification via Pushover <https://pushover.net/>.
# The access token (ZED_PUSHOVER_TOKEN) identifies this client to the
# Pushover server. The user token (ZED_PUSHOVER_USER) defines the user or
# group to which the notification will be sent.
#
# Requires curl and sed executables to be installed in the standard PATH.
#
# References
# https://pushover.net/api
#
# Arguments
# subject: notification subject
# pathname: pathname containing the notification message (OPTIONAL)
#
# Globals
# ZED_PUSHOVER_TOKEN
# ZED_PUSHOVER_USER
#
# Return
# 0: notification sent
# 1: notification failed
# 2: not configured
#
zed_notify_pushover()
{
local subject="$1"
local pathname="${2:-"/dev/null"}"
local msg_body
local msg_out
local msg_err
local url="https://api.pushover.net/1/messages.json"
[ -n "${ZED_PUSHOVER_TOKEN}" ] && [ -n "${ZED_PUSHOVER_USER}" ] || return 2
if [ ! -r "${pathname}" ]; then
zed_log_err "pushover cannot read \"${pathname}\""
return 1
fi
zed_check_cmd "curl" "sed" || return 1
# Read the message body in.
#
msg_body="$(cat "${pathname}")"
if [ -z "${msg_body}" ]
then
msg_body=$subject
subject=""
fi
# Send the POST request and check for errors.
#
msg_out="$( \
curl \
--form-string "token=${ZED_PUSHOVER_TOKEN}" \
--form-string "user=${ZED_PUSHOVER_USER}" \
--form-string "message=${msg_body}" \
--form-string "title=${subject}" \
"${url}" \
2>/dev/null \
)"; rv=$?
if [ "${rv}" -ne 0 ]; then
zed_log_err "curl exit=${rv}"
return 1
fi
msg_err="$(echo "${msg_out}" \
| sed -n -e 's/.*"errors" *:.*\[\(.*\)\].*/\1/p')"
if [ -n "${msg_err}" ]; then
zed_log_err "pushover \"${msg_err}"\"
return 1
fi
return 0
}
# zed_rate_limit (tag, [interval]) # zed_rate_limit (tag, [interval])
# #
# Check whether an event of a given type [tag] has already occurred within the # Check whether an event of a given type [tag] has already occurred within the
@ -602,8 +511,10 @@ zed_guid_to_pool()
return return
fi fi
guid="$(printf "%u" "$1")" guid=$(printf "%llu" "$1")
$ZPOOL get -H -ovalue,name guid | awk '$1 == '"$guid"' {print $2; exit}' if [ -n "$guid" ] ; then
$ZPOOL get -H -ovalue,name guid | awk '$1=='"$guid"' {print $2}'
fi
} }
# zed_exit_if_ignoring_this_event # zed_exit_if_ignoring_this_event

View File

@ -13,9 +13,9 @@
# Email address of the zpool administrator for receipt of notifications; # Email address of the zpool administrator for receipt of notifications;
# multiple addresses can be specified if they are delimited by whitespace. # multiple addresses can be specified if they are delimited by whitespace.
# Email will only be sent if ZED_EMAIL_ADDR is defined. # Email will only be sent if ZED_EMAIL_ADDR is defined.
# Enabled by default; comment to disable. # Disabled by default; uncomment to enable.
# #
ZED_EMAIL_ADDR="root" #ZED_EMAIL_ADDR="root"
## ##
# Name or path of executable responsible for sending notifications via email; # Name or path of executable responsible for sending notifications via email;
@ -30,7 +30,6 @@ ZED_EMAIL_ADDR="root"
# The string @SUBJECT@ will be replaced with the notification subject; # The string @SUBJECT@ will be replaced with the notification subject;
# this should be protected with quotes to prevent word-splitting. # this should be protected with quotes to prevent word-splitting.
# Email will only be sent if ZED_EMAIL_ADDR is defined. # Email will only be sent if ZED_EMAIL_ADDR is defined.
# If @SUBJECT@ was omited here, a "Subject: ..." header will be added to notification
# #
#ZED_EMAIL_OPTS="-s '@SUBJECT@' @ADDRESS@" #ZED_EMAIL_OPTS="-s '@SUBJECT@' @ADDRESS@"
@ -83,23 +82,6 @@ ZED_EMAIL_ADDR="root"
# #
#ZED_SLACK_WEBHOOK_URL="" #ZED_SLACK_WEBHOOK_URL=""
##
# Pushover token.
# This defines the application from which the notification will be sent.
# <https://pushover.net/api#registration>
# Disabled by default; uncomment to enable.
# ZED_PUSHOVER_USER, below, must also be configured.
#
#ZED_PUSHOVER_TOKEN=""
##
# Pushover user key.
# This defines which user or group will receive Pushover notifications.
# <https://pushover.net/api#identifiers>
# Disabled by default; uncomment to enable.
# ZED_PUSHOVER_TOKEN, above, must also be configured.
#ZED_PUSHOVER_USER=""
## ##
# Default directory for zed state files. # Default directory for zed state files.
# #
@ -107,8 +89,8 @@ ZED_EMAIL_ADDR="root"
## ##
# Turn on/off enclosure LEDs when drives get DEGRADED/FAULTED. This works for # Turn on/off enclosure LEDs when drives get DEGRADED/FAULTED. This works for
# device mapper and multipath devices as well. This works with JBOD enclosures # device mapper and multipath devices as well. Your enclosure must be
# and NVMe PCI drives (assuming they're supported by Linux in sysfs). # supported by the Linux SES driver for this to work.
# #
ZED_USE_ENCLOSURE_LEDS=1 ZED_USE_ENCLOSURE_LEDS=1
@ -143,8 +125,3 @@ ZED_SYSLOG_SUBCLASS_EXCLUDE="history_event"
# Disabled by default, 1 to enable and 0 to disable. # Disabled by default, 1 to enable and 0 to disable.
#ZED_SYSLOG_DISPLAY_GUIDS=1 #ZED_SYSLOG_DISPLAY_GUIDS=1
##
# Power off the drive's slot in the enclosure if it becomes FAULTED. This can
# help silence misbehaving drives. This assumes your drive enclosure fully
# supports slot power control via sysfs.
#ZED_POWER_OFF_ENCLOSURE_SLOT_ON_FAULT=1

View File

@ -3,7 +3,7 @@
* *
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049). * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC. * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
* Refer to the OpenZFS git commit log for authoritative copyright attribution. * Refer to the ZoL git commit log for authoritative copyright attribution.
* *
* The contents of this file are subject to the terms of the * The contents of this file are subject to the terms of the
* Common Development and Distribution License Version 1.0 (CDDL-1.0). * Common Development and Distribution License Version 1.0 (CDDL-1.0).
@ -15,6 +15,11 @@
#ifndef ZED_H #ifndef ZED_H
#define ZED_H #define ZED_H
/*
* Absolute path for the default zed configuration file.
*/
#define ZED_CONF_FILE SYSCONFDIR "/zfs/zed.conf"
/* /*
* Absolute path for the default zed pid file. * Absolute path for the default zed pid file.
*/ */
@ -30,6 +35,16 @@
*/ */
#define ZED_ZEDLET_DIR SYSCONFDIR "/zfs/zed.d" #define ZED_ZEDLET_DIR SYSCONFDIR "/zfs/zed.d"
/*
* Reserved for future use.
*/
#define ZED_MAX_EVENTS 0
/*
* Reserved for future use.
*/
#define ZED_MIN_EVENTS 0
/* /*
* String prefix for ZED variables passed via environment variables. * String prefix for ZED variables passed via environment variables.
*/ */

View File

@ -3,7 +3,7 @@
* *
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049). * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC. * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
* Refer to the OpenZFS git commit log for authoritative copyright attribution. * Refer to the ZoL git commit log for authoritative copyright attribution.
* *
* The contents of this file are subject to the terms of the * The contents of this file are subject to the terms of the
* Common Development and Distribution License Version 1.0 (CDDL-1.0). * Common Development and Distribution License Version 1.0 (CDDL-1.0).
@ -22,7 +22,6 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/uio.h> #include <sys/uio.h>
#include <unistd.h> #include <unistd.h>
@ -33,26 +32,43 @@
#include "zed_strings.h" #include "zed_strings.h"
/* /*
* Initialise the configuration with default values. * Return a new configuration with default values.
*/ */
void struct zed_conf *
zed_conf_init(struct zed_conf *zcp) zed_conf_create(void)
{ {
memset(zcp, 0, sizeof (*zcp)); struct zed_conf *zcp;
/* zcp->zfs_hdl opened in zed_event_init() */ zcp = calloc(1, sizeof (*zcp));
/* zcp->zedlets created in zed_conf_scan_dir() */ if (!zcp)
goto nomem;
zcp->pid_fd = -1; /* opened in zed_conf_write_pid() */ zcp->syslog_facility = LOG_DAEMON;
zcp->state_fd = -1; /* opened in zed_conf_open_state() */ zcp->min_events = ZED_MIN_EVENTS;
zcp->zevent_fd = -1; /* opened in zed_event_init() */ zcp->max_events = ZED_MAX_EVENTS;
zcp->pid_fd = -1;
zcp->zedlets = NULL; /* created via zed_conf_scan_dir() */
zcp->state_fd = -1; /* opened via zed_conf_open_state() */
zcp->zfs_hdl = NULL; /* opened via zed_event_init() */
zcp->zevent_fd = -1; /* opened via zed_event_init() */
zcp->max_jobs = 16; if (!(zcp->conf_file = strdup(ZED_CONF_FILE)))
goto nomem;
if (!(zcp->pid_file = strdup(ZED_PID_FILE)) || if (!(zcp->pid_file = strdup(ZED_PID_FILE)))
!(zcp->zedlet_dir = strdup(ZED_ZEDLET_DIR)) || goto nomem;
!(zcp->state_file = strdup(ZED_STATE_FILE)))
if (!(zcp->zedlet_dir = strdup(ZED_ZEDLET_DIR)))
goto nomem;
if (!(zcp->state_file = strdup(ZED_STATE_FILE)))
goto nomem;
return (zcp);
nomem:
zed_log_die("Failed to create conf: %s", strerror(errno)); zed_log_die("Failed to create conf: %s", strerror(errno));
return (NULL);
} }
/* /*
@ -63,6 +79,9 @@ zed_conf_init(struct zed_conf *zcp)
void void
zed_conf_destroy(struct zed_conf *zcp) zed_conf_destroy(struct zed_conf *zcp)
{ {
if (!zcp)
return;
if (zcp->state_fd >= 0) { if (zcp->state_fd >= 0) {
if (close(zcp->state_fd) < 0) if (close(zcp->state_fd) < 0)
zed_log_msg(LOG_WARNING, zed_log_msg(LOG_WARNING,
@ -83,6 +102,10 @@ zed_conf_destroy(struct zed_conf *zcp)
zcp->pid_file, strerror(errno)); zcp->pid_file, strerror(errno));
zcp->pid_fd = -1; zcp->pid_fd = -1;
} }
if (zcp->conf_file) {
free(zcp->conf_file);
zcp->conf_file = NULL;
}
if (zcp->pid_file) { if (zcp->pid_file) {
free(zcp->pid_file); free(zcp->pid_file);
zcp->pid_file = NULL; zcp->pid_file = NULL;
@ -99,6 +122,7 @@ zed_conf_destroy(struct zed_conf *zcp)
zed_strings_destroy(zcp->zedlets); zed_strings_destroy(zcp->zedlets);
zcp->zedlets = NULL; zcp->zedlets = NULL;
} }
free(zcp);
} }
/* /*
@ -108,52 +132,46 @@ zed_conf_destroy(struct zed_conf *zcp)
* otherwise, output to stderr and exit with a failure status. * otherwise, output to stderr and exit with a failure status.
*/ */
static void static void
_zed_conf_display_help(const char *prog, boolean_t got_err) _zed_conf_display_help(const char *prog, int got_err)
{ {
struct opt { const char *o, *d, *v; };
FILE *fp = got_err ? stderr : stdout; FILE *fp = got_err ? stderr : stdout;
int w1 = 4; /* width of leading whitespace */
struct opt *oo; int w2 = 8; /* width of L-justified option field */
struct opt iopts[] = {
{ .o = "-h", .d = "Display help" },
{ .o = "-L", .d = "Display license information" },
{ .o = "-V", .d = "Display version information" },
{},
};
struct opt nopts[] = {
{ .o = "-v", .d = "Be verbose" },
{ .o = "-f", .d = "Force daemon to run" },
{ .o = "-F", .d = "Run daemon in the foreground" },
{ .o = "-I",
.d = "Idle daemon until kernel module is (re)loaded" },
{ .o = "-M", .d = "Lock all pages in memory" },
{ .o = "-P", .d = "$PATH for ZED to use (only used by ZTS)" },
{ .o = "-Z", .d = "Zero state file" },
{},
};
struct opt vopts[] = {
{ .o = "-d DIR", .d = "Read enabled ZEDLETs from DIR.",
.v = ZED_ZEDLET_DIR },
{ .o = "-p FILE", .d = "Write daemon's PID to FILE.",
.v = ZED_PID_FILE },
{ .o = "-s FILE", .d = "Write daemon's state to FILE.",
.v = ZED_STATE_FILE },
{ .o = "-j JOBS", .d = "Start at most JOBS at once.",
.v = "16" },
{},
};
fprintf(fp, "Usage: %s [OPTION]...\n", (prog ? prog : "zed")); fprintf(fp, "Usage: %s [OPTION]...\n", (prog ? prog : "zed"));
fprintf(fp, "\n"); fprintf(fp, "\n");
for (oo = iopts; oo->o; ++oo) fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-h",
fprintf(fp, " %*s %s\n", -8, oo->o, oo->d); "Display help.");
fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-L",
"Display license information.");
fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-V",
"Display version information.");
fprintf(fp, "\n"); fprintf(fp, "\n");
for (oo = nopts; oo->o; ++oo) fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-v",
fprintf(fp, " %*s %s\n", -8, oo->o, oo->d); "Be verbose.");
fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-f",
"Force daemon to run.");
fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-F",
"Run daemon in the foreground.");
fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-I",
"Idle daemon until kernel module is (re)loaded.");
fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-M",
"Lock all pages in memory.");
fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-P",
"$PATH for ZED to use (only used by ZTS).");
fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-Z",
"Zero state file.");
fprintf(fp, "\n"); fprintf(fp, "\n");
for (oo = vopts; oo->o; ++oo) #if 0
fprintf(fp, " %*s %s [%s]\n", -8, oo->o, oo->d, oo->v); fprintf(fp, "%*c%*s %s [%s]\n", w1, 0x20, -w2, "-c FILE",
"Read configuration from FILE.", ZED_CONF_FILE);
#endif
fprintf(fp, "%*c%*s %s [%s]\n", w1, 0x20, -w2, "-d DIR",
"Read enabled ZEDLETs from DIR.", ZED_ZEDLET_DIR);
fprintf(fp, "%*c%*s %s [%s]\n", w1, 0x20, -w2, "-p FILE",
"Write daemon's PID to FILE.", ZED_PID_FILE);
fprintf(fp, "%*c%*s %s [%s]\n", w1, 0x20, -w2, "-s FILE",
"Write daemon's state to FILE.", ZED_STATE_FILE);
fprintf(fp, "\n"); fprintf(fp, "\n");
exit(got_err ? EXIT_FAILURE : EXIT_SUCCESS); exit(got_err ? EXIT_FAILURE : EXIT_SUCCESS);
@ -165,14 +183,20 @@ _zed_conf_display_help(const char *prog, boolean_t got_err)
static void static void
_zed_conf_display_license(void) _zed_conf_display_license(void)
{ {
printf( const char **pp;
"The ZFS Event Daemon (ZED) is distributed under the terms of the\n" const char *text[] = {
" Common Development and Distribution License (CDDL-1.0)\n" "The ZFS Event Daemon (ZED) is distributed under the terms of the",
" <http://opensource.org/licenses/CDDL-1.0>.\n" " Common Development and Distribution License (CDDL-1.0)",
"\n" " <http://opensource.org/licenses/CDDL-1.0>.",
"",
"Developed at Lawrence Livermore National Laboratory" "Developed at Lawrence Livermore National Laboratory"
" (LLNL-CODE-403049).\n" " (LLNL-CODE-403049).",
"\n"); "",
NULL
};
for (pp = text; *pp; pp++)
printf("%s\n", *pp);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
@ -207,19 +231,16 @@ _zed_conf_parse_path(char **resultp, const char *path)
if (path[0] == '/') { if (path[0] == '/') {
*resultp = strdup(path); *resultp = strdup(path);
} else { } else if (!getcwd(buf, sizeof (buf))) {
if (!getcwd(buf, sizeof (buf)))
zed_log_die("Failed to get current working dir: %s", zed_log_die("Failed to get current working dir: %s",
strerror(errno)); strerror(errno));
} else if (strlcat(buf, "/", sizeof (buf)) >= sizeof (buf)) {
if (strlcat(buf, "/", sizeof (buf)) >= sizeof (buf) || zed_log_die("Failed to copy path: %s", strerror(ENAMETOOLONG));
strlcat(buf, path, sizeof (buf)) >= sizeof (buf)) } else if (strlcat(buf, path, sizeof (buf)) >= sizeof (buf)) {
zed_log_die("Failed to copy path: %s", zed_log_die("Failed to copy path: %s", strerror(ENAMETOOLONG));
strerror(ENAMETOOLONG)); } else {
*resultp = strdup(buf); *resultp = strdup(buf);
} }
if (!*resultp) if (!*resultp)
zed_log_die("Failed to copy path: %s", strerror(ENOMEM)); zed_log_die("Failed to copy path: %s", strerror(ENOMEM));
} }
@ -230,9 +251,8 @@ _zed_conf_parse_path(char **resultp, const char *path)
void void
zed_conf_parse_opts(struct zed_conf *zcp, int argc, char **argv) zed_conf_parse_opts(struct zed_conf *zcp, int argc, char **argv)
{ {
const char * const opts = ":hLVd:p:P:s:vfFMZIj:"; const char * const opts = ":hLVc:d:p:P:s:vfFMZI";
int opt; int opt;
unsigned long raw;
if (!zcp || !argv || !argv[0]) if (!zcp || !argv || !argv[0])
zed_log_die("Failed to parse options: Internal error"); zed_log_die("Failed to parse options: Internal error");
@ -242,7 +262,7 @@ zed_conf_parse_opts(struct zed_conf *zcp, int argc, char **argv)
while ((opt = getopt(argc, argv, opts)) != -1) { while ((opt = getopt(argc, argv, opts)) != -1) {
switch (opt) { switch (opt) {
case 'h': case 'h':
_zed_conf_display_help(argv[0], B_FALSE); _zed_conf_display_help(argv[0], EXIT_SUCCESS);
break; break;
case 'L': case 'L':
_zed_conf_display_license(); _zed_conf_display_license();
@ -250,6 +270,9 @@ zed_conf_parse_opts(struct zed_conf *zcp, int argc, char **argv)
case 'V': case 'V':
_zed_conf_display_version(); _zed_conf_display_version();
break; break;
case 'c':
_zed_conf_parse_path(&zcp->conf_file, optarg);
break;
case 'd': case 'd':
_zed_conf_parse_path(&zcp->zedlet_dir, optarg); _zed_conf_parse_path(&zcp->zedlet_dir, optarg);
break; break;
@ -280,30 +303,31 @@ zed_conf_parse_opts(struct zed_conf *zcp, int argc, char **argv)
case 'Z': case 'Z':
zcp->do_zero = 1; zcp->do_zero = 1;
break; break;
case 'j':
errno = 0;
raw = strtoul(optarg, NULL, 0);
if (errno == ERANGE || raw > INT16_MAX) {
zed_log_die("%lu is too many jobs", raw);
} if (raw == 0) {
zed_log_die("0 jobs makes no sense");
} else {
zcp->max_jobs = raw;
}
break;
case '?': case '?':
default: default:
if (optopt == '?') if (optopt == '?')
_zed_conf_display_help(argv[0], B_FALSE); _zed_conf_display_help(argv[0], EXIT_SUCCESS);
fprintf(stderr, "%s: Invalid option '-%c'\n\n", fprintf(stderr, "%s: %s '-%c'\n\n", argv[0],
argv[0], optopt); "Invalid option", optopt);
_zed_conf_display_help(argv[0], B_TRUE); _zed_conf_display_help(argv[0], EXIT_FAILURE);
break; break;
} }
} }
} }
/*
* Parse the configuration file into the configuration [zcp].
*
* FIXME: Not yet implemented.
*/
void
zed_conf_parse_file(struct zed_conf *zcp)
{
if (!zcp)
zed_log_die("Failed to parse config: %s", strerror(EINVAL));
}
/* /*
* Scan the [zcp] zedlet_dir for files to exec based on the event class. * Scan the [zcp] zedlet_dir for files to exec based on the event class.
* Files must be executable by user, but not writable by group or other. * Files must be executable by user, but not writable by group or other.
@ -311,6 +335,8 @@ zed_conf_parse_opts(struct zed_conf *zcp, int argc, char **argv)
* *
* Return 0 on success with an updated set of zedlets, * Return 0 on success with an updated set of zedlets,
* or -1 on error with errno set. * or -1 on error with errno set.
*
* FIXME: Check if zedlet_dir and all parent dirs are secure.
*/ */
int int
zed_conf_scan_dir(struct zed_conf *zcp) zed_conf_scan_dir(struct zed_conf *zcp)
@ -426,6 +452,8 @@ zed_conf_scan_dir(struct zed_conf *zcp)
int int
zed_conf_write_pid(struct zed_conf *zcp) zed_conf_write_pid(struct zed_conf *zcp)
{ {
const mode_t dirmode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
const mode_t filemode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
char buf[PATH_MAX]; char buf[PATH_MAX];
int n; int n;
char *p; char *p;
@ -453,7 +481,7 @@ zed_conf_write_pid(struct zed_conf *zcp)
if (p) if (p)
*p = '\0'; *p = '\0';
if ((mkdirp(buf, 0755) < 0) && (errno != EEXIST)) { if ((mkdirp(buf, dirmode) < 0) && (errno != EEXIST)) {
zed_log_msg(LOG_ERR, "Failed to create directory \"%s\": %s", zed_log_msg(LOG_ERR, "Failed to create directory \"%s\": %s",
buf, strerror(errno)); buf, strerror(errno));
goto err; goto err;
@ -463,7 +491,7 @@ zed_conf_write_pid(struct zed_conf *zcp)
*/ */
mask = umask(0); mask = umask(0);
umask(mask | 022); umask(mask | 022);
zcp->pid_fd = open(zcp->pid_file, O_RDWR | O_CREAT | O_CLOEXEC, 0644); zcp->pid_fd = open(zcp->pid_file, (O_RDWR | O_CREAT), filemode);
umask(mask); umask(mask);
if (zcp->pid_fd < 0) { if (zcp->pid_fd < 0) {
zed_log_msg(LOG_ERR, "Failed to open PID file \"%s\": %s", zed_log_msg(LOG_ERR, "Failed to open PID file \"%s\": %s",
@ -500,7 +528,7 @@ zed_conf_write_pid(struct zed_conf *zcp)
errno = ERANGE; errno = ERANGE;
zed_log_msg(LOG_ERR, "Failed to write PID file \"%s\": %s", zed_log_msg(LOG_ERR, "Failed to write PID file \"%s\": %s",
zcp->pid_file, strerror(errno)); zcp->pid_file, strerror(errno));
} else if (write(zcp->pid_fd, buf, n) != n) { } else if (zed_file_write_n(zcp->pid_fd, buf, n) != n) {
zed_log_msg(LOG_ERR, "Failed to write PID file \"%s\": %s", zed_log_msg(LOG_ERR, "Failed to write PID file \"%s\": %s",
zcp->pid_file, strerror(errno)); zcp->pid_file, strerror(errno));
} else if (fdatasync(zcp->pid_fd) < 0) { } else if (fdatasync(zcp->pid_fd) < 0) {
@ -528,6 +556,7 @@ int
zed_conf_open_state(struct zed_conf *zcp) zed_conf_open_state(struct zed_conf *zcp)
{ {
char dirbuf[PATH_MAX]; char dirbuf[PATH_MAX];
mode_t dirmode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
int n; int n;
char *p; char *p;
int rv; int rv;
@ -549,7 +578,7 @@ zed_conf_open_state(struct zed_conf *zcp)
if (p) if (p)
*p = '\0'; *p = '\0';
if ((mkdirp(dirbuf, 0755) < 0) && (errno != EEXIST)) { if ((mkdirp(dirbuf, dirmode) < 0) && (errno != EEXIST)) {
zed_log_msg(LOG_WARNING, zed_log_msg(LOG_WARNING,
"Failed to create directory \"%s\": %s", "Failed to create directory \"%s\": %s",
dirbuf, strerror(errno)); dirbuf, strerror(errno));
@ -567,7 +596,7 @@ zed_conf_open_state(struct zed_conf *zcp)
(void) unlink(zcp->state_file); (void) unlink(zcp->state_file);
zcp->state_fd = open(zcp->state_file, zcp->state_fd = open(zcp->state_file,
O_RDWR | O_CREAT | O_CLOEXEC, 0644); (O_RDWR | O_CREAT), (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
if (zcp->state_fd < 0) { if (zcp->state_fd < 0) {
zed_log_msg(LOG_WARNING, "Failed to open state file \"%s\": %s", zed_log_msg(LOG_WARNING, "Failed to open state file \"%s\": %s",
zcp->state_file, strerror(errno)); zcp->state_file, strerror(errno));

View File

@ -3,7 +3,7 @@
* *
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049). * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC. * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
* Refer to the OpenZFS git commit log for authoritative copyright attribution. * Refer to the ZoL git commit log for authoritative copyright attribution.
* *
* The contents of this file are subject to the terms of the * The contents of this file are subject to the terms of the
* Common Development and Distribution License Version 1.0 (CDDL-1.0). * Common Development and Distribution License Version 1.0 (CDDL-1.0).
@ -20,39 +20,43 @@
#include "zed_strings.h" #include "zed_strings.h"
struct zed_conf { struct zed_conf {
unsigned do_force:1; /* true if force enabled */
unsigned do_foreground:1; /* true if run in foreground */
unsigned do_memlock:1; /* true if locking memory */
unsigned do_verbose:1; /* true if verbosity enabled */
unsigned do_zero:1; /* true if zeroing state */
unsigned do_idle:1; /* true if idle enabled */
int syslog_facility; /* syslog facility value */
int min_events; /* RESERVED FOR FUTURE USE */
int max_events; /* RESERVED FOR FUTURE USE */
char *conf_file; /* abs path to config file */
char *pid_file; /* abs path to pid file */ char *pid_file; /* abs path to pid file */
char *zedlet_dir; /* abs path to zedlet dir */
char *state_file; /* abs path to state file */
libzfs_handle_t *zfs_hdl; /* handle to libzfs */
zed_strings_t *zedlets; /* names of enabled zedlets */
char *path; /* custom $PATH for zedlets to use */
int pid_fd; /* fd to pid file for lock */ int pid_fd; /* fd to pid file for lock */
char *zedlet_dir; /* abs path to zedlet dir */
zed_strings_t *zedlets; /* names of enabled zedlets */
char *state_file; /* abs path to state file */
int state_fd; /* fd to state file */ int state_fd; /* fd to state file */
libzfs_handle_t *zfs_hdl; /* handle to libzfs */
int zevent_fd; /* fd for access to zevents */ int zevent_fd; /* fd for access to zevents */
char *path; /* custom $PATH for zedlets to use */
int16_t max_jobs; /* max zedlets to run at one time */
boolean_t do_force:1; /* true if force enabled */
boolean_t do_foreground:1; /* true if run in foreground */
boolean_t do_memlock:1; /* true if locking memory */
boolean_t do_verbose:1; /* true if verbosity enabled */
boolean_t do_zero:1; /* true if zeroing state */
boolean_t do_idle:1; /* true if idle enabled */
}; };
void zed_conf_init(struct zed_conf *zcp); struct zed_conf *zed_conf_create(void);
void zed_conf_destroy(struct zed_conf *zcp); void zed_conf_destroy(struct zed_conf *zcp);
void zed_conf_parse_opts(struct zed_conf *zcp, int argc, char **argv); void zed_conf_parse_opts(struct zed_conf *zcp, int argc, char **argv);
void zed_conf_parse_file(struct zed_conf *zcp);
int zed_conf_scan_dir(struct zed_conf *zcp); int zed_conf_scan_dir(struct zed_conf *zcp);
int zed_conf_write_pid(struct zed_conf *zcp); int zed_conf_write_pid(struct zed_conf *zcp);
int zed_conf_open_state(struct zed_conf *zcp); int zed_conf_open_state(struct zed_conf *zcp);
int zed_conf_read_state(struct zed_conf *zcp, uint64_t *eidp, int64_t etime[]); int zed_conf_read_state(struct zed_conf *zcp, uint64_t *eidp, int64_t etime[]);
int zed_conf_write_state(struct zed_conf *zcp, uint64_t eid, int64_t etime[]); int zed_conf_write_state(struct zed_conf *zcp, uint64_t eid, int64_t etime[]);
#endif /* !ZED_CONF_H */ #endif /* !ZED_CONF_H */

View File

@ -72,14 +72,10 @@ zed_udev_event(const char *class, const char *subclass, nvlist_t *nvl)
zed_log_msg(LOG_INFO, "\t%s: %s", DEV_PATH, strval); zed_log_msg(LOG_INFO, "\t%s: %s", DEV_PATH, strval);
if (nvlist_lookup_string(nvl, DEV_IDENTIFIER, &strval) == 0) if (nvlist_lookup_string(nvl, DEV_IDENTIFIER, &strval) == 0)
zed_log_msg(LOG_INFO, "\t%s: %s", DEV_IDENTIFIER, strval); zed_log_msg(LOG_INFO, "\t%s: %s", DEV_IDENTIFIER, strval);
if (nvlist_lookup_boolean(nvl, DEV_IS_PART) == B_TRUE)
zed_log_msg(LOG_INFO, "\t%s: B_TRUE", DEV_IS_PART);
if (nvlist_lookup_string(nvl, DEV_PHYS_PATH, &strval) == 0) if (nvlist_lookup_string(nvl, DEV_PHYS_PATH, &strval) == 0)
zed_log_msg(LOG_INFO, "\t%s: %s", DEV_PHYS_PATH, strval); zed_log_msg(LOG_INFO, "\t%s: %s", DEV_PHYS_PATH, strval);
if (nvlist_lookup_uint64(nvl, DEV_SIZE, &numval) == 0) if (nvlist_lookup_uint64(nvl, DEV_SIZE, &numval) == 0)
zed_log_msg(LOG_INFO, "\t%s: %llu", DEV_SIZE, numval); zed_log_msg(LOG_INFO, "\t%s: %llu", DEV_SIZE, numval);
if (nvlist_lookup_uint64(nvl, DEV_PARENT_SIZE, &numval) == 0)
zed_log_msg(LOG_INFO, "\t%s: %llu", DEV_PARENT_SIZE, numval);
if (nvlist_lookup_uint64(nvl, ZFS_EV_POOL_GUID, &numval) == 0) if (nvlist_lookup_uint64(nvl, ZFS_EV_POOL_GUID, &numval) == 0)
zed_log_msg(LOG_INFO, "\t%s: %llu", ZFS_EV_POOL_GUID, numval); zed_log_msg(LOG_INFO, "\t%s: %llu", ZFS_EV_POOL_GUID, numval);
if (nvlist_lookup_uint64(nvl, ZFS_EV_VDEV_GUID, &numval) == 0) if (nvlist_lookup_uint64(nvl, ZFS_EV_VDEV_GUID, &numval) == 0)
@ -132,20 +128,6 @@ dev_event_nvlist(struct udev_device *dev)
numval *= strtoull(value, NULL, 10); numval *= strtoull(value, NULL, 10);
(void) nvlist_add_uint64(nvl, DEV_SIZE, numval); (void) nvlist_add_uint64(nvl, DEV_SIZE, numval);
/*
* If the device has a parent, then get the parent block
* device's size as well. For example, /dev/sda1's parent
* is /dev/sda.
*/
struct udev_device *parent_dev = udev_device_get_parent(dev);
if ((value = udev_device_get_sysattr_value(parent_dev, "size"))
!= NULL) {
uint64_t numval = DEV_BSIZE;
numval *= strtoull(value, NULL, 10);
(void) nvlist_add_uint64(nvl, DEV_PARENT_SIZE, numval);
}
} }
/* /*
@ -185,7 +167,7 @@ zed_udev_monitor(void *arg)
while (1) { while (1) {
struct udev_device *dev; struct udev_device *dev;
const char *action, *type, *part, *sectors; const char *action, *type, *part, *sectors;
const char *bus, *uuid, *devpath; const char *bus, *uuid;
const char *class, *subclass; const char *class, *subclass;
nvlist_t *nvl; nvlist_t *nvl;
boolean_t is_zfs = B_FALSE; boolean_t is_zfs = B_FALSE;
@ -224,12 +206,6 @@ zed_udev_monitor(void *arg)
* if this is a disk and it is partitioned, then the * if this is a disk and it is partitioned, then the
* zfs label will reside in a DEVTYPE=partition and * zfs label will reside in a DEVTYPE=partition and
* we can skip passing this event * we can skip passing this event
*
* Special case: Blank disks are sometimes reported with
* an erroneous 'atari' partition, and should not be
* excluded from being used as an autoreplace disk:
*
* https://github.com/openzfs/zfs/issues/13497
*/ */
type = udev_device_get_property_value(dev, "DEVTYPE"); type = udev_device_get_property_value(dev, "DEVTYPE");
part = udev_device_get_property_value(dev, part = udev_device_get_property_value(dev,
@ -237,24 +213,10 @@ zed_udev_monitor(void *arg)
if (type != NULL && type[0] != '\0' && if (type != NULL && type[0] != '\0' &&
strcmp(type, "disk") == 0 && strcmp(type, "disk") == 0 &&
part != NULL && part[0] != '\0') { part != NULL && part[0] != '\0') {
const char *devname =
udev_device_get_property_value(dev, "DEVNAME");
if (strcmp(part, "atari") == 0) {
zed_log_msg(LOG_INFO,
"%s: %s is reporting an atari partition, "
"but we're going to assume it's a false "
"positive and still use it (issue #13497)",
__func__, devname);
} else {
zed_log_msg(LOG_INFO,
"%s: skip %s since it has a %s partition "
"already", __func__, devname, part);
/* skip and wait for partition event */ /* skip and wait for partition event */
udev_device_unref(dev); udev_device_unref(dev);
continue; continue;
} }
}
/* /*
* ignore small partitions * ignore small partitions
@ -265,11 +227,6 @@ zed_udev_monitor(void *arg)
sectors = udev_device_get_sysattr_value(dev, "size"); sectors = udev_device_get_sysattr_value(dev, "size");
if (sectors != NULL && if (sectors != NULL &&
strtoull(sectors, NULL, 10) < MINIMUM_SECTORS) { strtoull(sectors, NULL, 10) < MINIMUM_SECTORS) {
zed_log_msg(LOG_INFO,
"%s: %s sectors %s < %llu (minimum)",
__func__,
udev_device_get_property_value(dev, "DEVNAME"),
sectors, MINIMUM_SECTORS);
udev_device_unref(dev); udev_device_unref(dev);
continue; continue;
} }
@ -279,19 +236,10 @@ zed_udev_monitor(void *arg)
* device id string is required in the message schema * device id string is required in the message schema
* for matching with vdevs. Preflight here for expected * for matching with vdevs. Preflight here for expected
* udev information. * udev information.
*
* Special case:
* NVMe devices don't have ID_BUS set (at least on RHEL 7-8),
* but they are valid for autoreplace. Add a special case for
* them by searching for "/nvme/" in the udev DEVPATH:
*
* DEVPATH=/devices/pci0000:00/0000:00:1e.0/nvme/nvme2/nvme2n1
*/ */
bus = udev_device_get_property_value(dev, "ID_BUS"); bus = udev_device_get_property_value(dev, "ID_BUS");
uuid = udev_device_get_property_value(dev, "DM_UUID"); uuid = udev_device_get_property_value(dev, "DM_UUID");
devpath = udev_device_get_devpath(dev); if (!is_zfs && (bus == NULL && uuid == NULL)) {
if (!is_zfs && (bus == NULL && uuid == NULL &&
strstr(devpath, "/nvme/") == NULL)) {
zed_log_msg(LOG_INFO, "zed_udev_monitor: %s no devid " zed_log_msg(LOG_INFO, "zed_udev_monitor: %s no devid "
"source", udev_device_get_devnode(dev)); "source", udev_device_get_devnode(dev));
udev_device_unref(dev); udev_device_unref(dev);
@ -402,7 +350,7 @@ zed_udev_monitor(void *arg)
} }
int int
zed_disk_event_init(void) zed_disk_event_init()
{ {
int fd, fflags; int fd, fflags;
@ -431,14 +379,13 @@ zed_disk_event_init(void)
return (-1); return (-1);
} }
pthread_setname_np(g_mon_tid, "udev monitor");
zed_log_msg(LOG_INFO, "zed_disk_event_init"); zed_log_msg(LOG_INFO, "zed_disk_event_init");
return (0); return (0);
} }
void void
zed_disk_event_fini(void) zed_disk_event_fini()
{ {
/* cancel monitor thread at recvmsg() */ /* cancel monitor thread at recvmsg() */
(void) pthread_cancel(g_mon_tid); (void) pthread_cancel(g_mon_tid);
@ -456,13 +403,13 @@ zed_disk_event_fini(void)
#include "zed_disk_event.h" #include "zed_disk_event.h"
int int
zed_disk_event_init(void) zed_disk_event_init()
{ {
return (0); return (0);
} }
void void
zed_disk_event_fini(void) zed_disk_event_fini()
{ {
} }

View File

@ -3,7 +3,7 @@
* *
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049). * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC. * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
* Refer to the OpenZFS git commit log for authoritative copyright attribution. * Refer to the ZoL git commit log for authoritative copyright attribution.
* *
* The contents of this file are subject to the terms of the * The contents of this file are subject to the terms of the
* Common Development and Distribution License Version 1.0 (CDDL-1.0). * Common Development and Distribution License Version 1.0 (CDDL-1.0).
@ -15,7 +15,7 @@
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <libzfs_core.h> #include <libzfs.h> /* FIXME: Replace with libzfs_core. */
#include <paths.h> #include <paths.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
@ -35,7 +35,6 @@
#include "zed_strings.h" #include "zed_strings.h"
#include "agents/zfs_agents.h" #include "agents/zfs_agents.h"
#include <libzutil.h>
#define MAXBUF 4096 #define MAXBUF 4096
@ -55,7 +54,7 @@ zed_event_init(struct zed_conf *zcp)
zed_log_die("Failed to initialize libzfs"); zed_log_die("Failed to initialize libzfs");
} }
zcp->zevent_fd = open(ZFS_DEV, O_RDWR | O_CLOEXEC); zcp->zevent_fd = open(ZFS_DEV, O_RDWR);
if (zcp->zevent_fd < 0) { if (zcp->zevent_fd < 0) {
if (zcp->do_idle) if (zcp->do_idle)
return (-1); return (-1);
@ -97,47 +96,6 @@ zed_event_fini(struct zed_conf *zcp)
libzfs_fini(zcp->zfs_hdl); libzfs_fini(zcp->zfs_hdl);
zcp->zfs_hdl = NULL; zcp->zfs_hdl = NULL;
} }
zed_exec_fini();
}
static void
_bump_event_queue_length(void)
{
int zzlm = -1, wr;
char qlen_buf[12] = {0}; /* parameter is int => max "-2147483647\n" */
long int qlen;
zzlm = open("/sys/module/zfs/parameters/zfs_zevent_len_max", O_RDWR);
if (zzlm < 0)
goto done;
if (read(zzlm, qlen_buf, sizeof (qlen_buf)) < 0)
goto done;
qlen_buf[sizeof (qlen_buf) - 1] = '\0';
errno = 0;
qlen = strtol(qlen_buf, NULL, 10);
if (errno == ERANGE)
goto done;
if (qlen <= 0)
qlen = 512; /* default zfs_zevent_len_max value */
else
qlen *= 2;
if (qlen > INT_MAX)
qlen = INT_MAX;
wr = snprintf(qlen_buf, sizeof (qlen_buf), "%ld", qlen);
if (pwrite(zzlm, qlen_buf, wr, 0) < 0)
goto done;
zed_log_msg(LOG_WARNING, "Bumping queue length to %ld", qlen);
done:
if (zzlm > -1)
(void) close(zzlm);
} }
/* /*
@ -178,7 +136,10 @@ zed_event_seek(struct zed_conf *zcp, uint64_t saved_eid, int64_t saved_etime[])
if (n_dropped > 0) { if (n_dropped > 0) {
zed_log_msg(LOG_WARNING, "Missed %d events", n_dropped); zed_log_msg(LOG_WARNING, "Missed %d events", n_dropped);
_bump_event_queue_length(); /*
* FIXME: Increase max size of event nvlist in
* /sys/module/zfs/parameters/zfs_zevent_len_max ?
*/
} }
if (nvlist_lookup_uint64(nvl, "eid", &eid) != 0) { if (nvlist_lookup_uint64(nvl, "eid", &eid) != 0) {
zed_log_msg(LOG_WARNING, "Failed to lookup zevent eid"); zed_log_msg(LOG_WARNING, "Failed to lookup zevent eid");
@ -250,7 +211,7 @@ _zed_event_value_is_hex(const char *name)
* *
* All environment variables in [zsp] should be added through this function. * All environment variables in [zsp] should be added through this function.
*/ */
static __attribute__((format(printf, 5, 6))) int static int
_zed_event_add_var(uint64_t eid, zed_strings_t *zsp, _zed_event_add_var(uint64_t eid, zed_strings_t *zsp,
const char *prefix, const char *name, const char *fmt, ...) const char *prefix, const char *name, const char *fmt, ...)
{ {
@ -625,6 +586,8 @@ _zed_event_add_string_array(uint64_t eid, zed_strings_t *zsp,
* Convert the nvpair [nvp] to a string which is added to the environment * Convert the nvpair [nvp] to a string which is added to the environment
* of the child process. * of the child process.
* Return 0 on success, -1 on error. * Return 0 on success, -1 on error.
*
* FIXME: Refactor with cmd/zpool/zpool_main.c:zpool_do_events_nvprint()?
*/ */
static void static void
_zed_event_add_nvpair(uint64_t eid, zed_strings_t *zsp, nvpair_t *nvp) _zed_event_add_nvpair(uint64_t eid, zed_strings_t *zsp, nvpair_t *nvp)
@ -723,11 +686,23 @@ _zed_event_add_nvpair(uint64_t eid, zed_strings_t *zsp, nvpair_t *nvp)
_zed_event_add_var(eid, zsp, prefix, name, _zed_event_add_var(eid, zsp, prefix, name,
"%llu", (u_longlong_t)i64); "%llu", (u_longlong_t)i64);
break; break;
case DATA_TYPE_NVLIST:
_zed_event_add_var(eid, zsp, prefix, name,
"%s", "_NOT_IMPLEMENTED_"); /* FIXME */
break;
case DATA_TYPE_STRING: case DATA_TYPE_STRING:
(void) nvpair_value_string(nvp, &str); (void) nvpair_value_string(nvp, &str);
_zed_event_add_var(eid, zsp, prefix, name, _zed_event_add_var(eid, zsp, prefix, name,
"%s", (str ? str : "<NULL>")); "%s", (str ? str : "<NULL>"));
break; break;
case DATA_TYPE_BOOLEAN_ARRAY:
_zed_event_add_var(eid, zsp, prefix, name,
"%s", "_NOT_IMPLEMENTED_"); /* FIXME */
break;
case DATA_TYPE_BYTE_ARRAY:
_zed_event_add_var(eid, zsp, prefix, name,
"%s", "_NOT_IMPLEMENTED_"); /* FIXME */
break;
case DATA_TYPE_INT8_ARRAY: case DATA_TYPE_INT8_ARRAY:
_zed_event_add_int8_array(eid, zsp, prefix, nvp); _zed_event_add_int8_array(eid, zsp, prefix, nvp);
break; break;
@ -755,11 +730,9 @@ _zed_event_add_nvpair(uint64_t eid, zed_strings_t *zsp, nvpair_t *nvp)
case DATA_TYPE_STRING_ARRAY: case DATA_TYPE_STRING_ARRAY:
_zed_event_add_string_array(eid, zsp, prefix, nvp); _zed_event_add_string_array(eid, zsp, prefix, nvp);
break; break;
case DATA_TYPE_NVLIST:
case DATA_TYPE_BOOLEAN_ARRAY:
case DATA_TYPE_BYTE_ARRAY:
case DATA_TYPE_NVLIST_ARRAY: case DATA_TYPE_NVLIST_ARRAY:
_zed_event_add_var(eid, zsp, prefix, name, "_NOT_IMPLEMENTED_"); _zed_event_add_var(eid, zsp, prefix, name,
"%s", "_NOT_IMPLEMENTED_"); /* FIXME */
break; break;
default: default:
errno = EINVAL; errno = EINVAL;
@ -908,25 +881,6 @@ _zed_event_add_time_strings(uint64_t eid, zed_strings_t *zsp, int64_t etime[])
} }
} }
static void
_zed_event_update_enc_sysfs_path(nvlist_t *nvl)
{
char *vdev_path;
if (nvlist_lookup_string(nvl, FM_EREPORT_PAYLOAD_ZFS_VDEV_PATH,
&vdev_path) != 0) {
return; /* some other kind of event, ignore it */
}
if (vdev_path == NULL) {
return;
}
update_vdev_config_dev_sysfs_path(nvl, vdev_path,
FM_EREPORT_PAYLOAD_ZFS_VDEV_ENC_SYSFS_PATH);
}
/* /*
* Service the next zevent, blocking until one is available. * Service the next zevent, blocking until one is available.
*/ */
@ -958,7 +912,10 @@ zed_event_service(struct zed_conf *zcp)
if (n_dropped > 0) { if (n_dropped > 0) {
zed_log_msg(LOG_WARNING, "Missed %d events", n_dropped); zed_log_msg(LOG_WARNING, "Missed %d events", n_dropped);
_bump_event_queue_length(); /*
* FIXME: Increase max size of event nvlist in
* /sys/module/zfs/parameters/zfs_zevent_len_max ?
*/
} }
if (nvlist_lookup_uint64(nvl, "eid", &eid) != 0) { if (nvlist_lookup_uint64(nvl, "eid", &eid) != 0) {
zed_log_msg(LOG_WARNING, "Failed to lookup zevent eid"); zed_log_msg(LOG_WARNING, "Failed to lookup zevent eid");
@ -974,17 +931,6 @@ zed_event_service(struct zed_conf *zcp)
zed_log_msg(LOG_WARNING, zed_log_msg(LOG_WARNING,
"Failed to lookup zevent class (eid=%llu)", eid); "Failed to lookup zevent class (eid=%llu)", eid);
} else { } else {
/*
* Special case: If we can dynamically detect an enclosure sysfs
* path, then use that value rather than the one stored in the
* vd->vdev_enc_sysfs_path. There have been rare cases where
* vd->vdev_enc_sysfs_path becomes outdated. However, there
* will be other times when we can not dynamically detect the
* sysfs path (like if a disk disappears) and have to rely on
* the old value for things like turning on the fault LED.
*/
_zed_event_update_enc_sysfs_path(nvl);
/* let internal modules see this event first */ /* let internal modules see this event first */
zfs_agent_post_event(class, NULL, nvl); zfs_agent_post_event(class, NULL, nvl);
@ -1007,7 +953,8 @@ zed_event_service(struct zed_conf *zcp)
_zed_event_add_time_strings(eid, zsp, etime); _zed_event_add_time_strings(eid, zsp, etime);
zed_exec_process(eid, class, subclass, zcp, zsp); zed_exec_process(eid, class, subclass,
zcp->zedlet_dir, zcp->zedlets, zsp, zcp->zevent_fd);
zed_conf_write_state(zcp, eid, etime); zed_conf_write_state(zcp, eid, etime);

View File

@ -3,7 +3,7 @@
* *
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049). * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC. * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
* Refer to the OpenZFS git commit log for authoritative copyright attribution. * Refer to the ZoL git commit log for authoritative copyright attribution.
* *
* The contents of this file are subject to the terms of the * The contents of this file are subject to the terms of the
* Common Development and Distribution License Version 1.0 (CDDL-1.0). * Common Development and Distribution License Version 1.0 (CDDL-1.0).

View File

@ -3,7 +3,7 @@
* *
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049). * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC. * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
* Refer to the OpenZFS git commit log for authoritative copyright attribution. * Refer to the ZoL git commit log for authoritative copyright attribution.
* *
* The contents of this file are subject to the terms of the * The contents of this file are subject to the terms of the
* Common Development and Distribution License Version 1.0 (CDDL-1.0). * Common Development and Distribution License Version 1.0 (CDDL-1.0).
@ -18,55 +18,17 @@
#include <fcntl.h> #include <fcntl.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stddef.h>
#include <sys/avl.h>
#include <sys/resource.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include "zed_exec.h" #include "zed_exec.h"
#include "zed_file.h"
#include "zed_log.h" #include "zed_log.h"
#include "zed_strings.h" #include "zed_strings.h"
#define ZEVENT_FILENO 3 #define ZEVENT_FILENO 3
struct launched_process_node {
avl_node_t node;
pid_t pid;
uint64_t eid;
char *name;
};
static int
_launched_process_node_compare(const void *x1, const void *x2)
{
pid_t p1;
pid_t p2;
assert(x1 != NULL);
assert(x2 != NULL);
p1 = ((const struct launched_process_node *) x1)->pid;
p2 = ((const struct launched_process_node *) x2)->pid;
if (p1 < p2)
return (-1);
else if (p1 == p2)
return (0);
else
return (1);
}
static pthread_t _reap_children_tid = (pthread_t)-1;
static volatile boolean_t _reap_children_stop;
static avl_tree_t _launched_processes;
static pthread_mutex_t _launched_processes_lock = PTHREAD_MUTEX_INITIALIZER;
static int16_t _launched_processes_limit;
/* /*
* Create an environment string array for passing to execve() using the * Create an environment string array for passing to execve() using the
* NAME=VALUE strings in container [zsp]. * NAME=VALUE strings in container [zsp].
@ -117,26 +79,20 @@ _zed_exec_create_env(zed_strings_t *zsp)
*/ */
static void static void
_zed_exec_fork_child(uint64_t eid, const char *dir, const char *prog, _zed_exec_fork_child(uint64_t eid, const char *dir, const char *prog,
char *env[], int zfd, boolean_t in_foreground) char *env[], int zfd)
{ {
char path[PATH_MAX]; char path[PATH_MAX];
int n; int n;
pid_t pid; pid_t pid;
int fd; int fd;
struct launched_process_node *node; pid_t wpid;
sigset_t mask; int status;
struct timespec launch_timeout =
{ .tv_sec = 0, .tv_nsec = 200 * 1000 * 1000, };
assert(dir != NULL); assert(dir != NULL);
assert(prog != NULL); assert(prog != NULL);
assert(env != NULL); assert(env != NULL);
assert(zfd >= 0); assert(zfd >= 0);
while (__atomic_load_n(&_launched_processes_limit,
__ATOMIC_SEQ_CST) <= 0)
(void) nanosleep(&launch_timeout, NULL);
n = snprintf(path, sizeof (path), "%s/%s", dir, prog); n = snprintf(path, sizeof (path), "%s/%s", dir, prog);
if ((n < 0) || (n >= sizeof (path))) { if ((n < 0) || (n >= sizeof (path))) {
zed_log_msg(LOG_WARNING, zed_log_msg(LOG_WARNING,
@ -144,179 +100,101 @@ _zed_exec_fork_child(uint64_t eid, const char *dir, const char *prog,
prog, eid, strerror(ENAMETOOLONG)); prog, eid, strerror(ENAMETOOLONG));
return; return;
} }
(void) pthread_mutex_lock(&_launched_processes_lock);
pid = fork(); pid = fork();
if (pid < 0) { if (pid < 0) {
(void) pthread_mutex_unlock(&_launched_processes_lock);
zed_log_msg(LOG_WARNING, zed_log_msg(LOG_WARNING,
"Failed to fork \"%s\" for eid=%llu: %s", "Failed to fork \"%s\" for eid=%llu: %s",
prog, eid, strerror(errno)); prog, eid, strerror(errno));
return; return;
} else if (pid == 0) { } else if (pid == 0) {
(void) sigemptyset(&mask);
(void) sigprocmask(SIG_SETMASK, &mask, NULL);
(void) umask(022); (void) umask(022);
if (in_foreground && /* we're already devnulled if daemonised */ if ((fd = open("/dev/null", O_RDWR)) != -1) {
(fd = open("/dev/null", O_RDWR | O_CLOEXEC)) != -1) {
(void) dup2(fd, STDIN_FILENO); (void) dup2(fd, STDIN_FILENO);
(void) dup2(fd, STDOUT_FILENO); (void) dup2(fd, STDOUT_FILENO);
(void) dup2(fd, STDERR_FILENO); (void) dup2(fd, STDERR_FILENO);
} }
(void) dup2(zfd, ZEVENT_FILENO); (void) dup2(zfd, ZEVENT_FILENO);
zed_file_close_from(ZEVENT_FILENO + 1);
execle(path, prog, NULL, env); execle(path, prog, NULL, env);
_exit(127); _exit(127);
} }
/* parent process */ /* parent process */
node = calloc(1, sizeof (*node));
if (node) {
node->pid = pid;
node->eid = eid;
node->name = strdup(prog);
avl_add(&_launched_processes, node);
}
(void) pthread_mutex_unlock(&_launched_processes_lock);
__atomic_sub_fetch(&_launched_processes_limit, 1, __ATOMIC_SEQ_CST);
zed_log_msg(LOG_INFO, "Invoking \"%s\" eid=%llu pid=%d", zed_log_msg(LOG_INFO, "Invoking \"%s\" eid=%llu pid=%d",
prog, eid, pid); prog, eid, pid);
}
static void /* FIXME: Timeout rogue child processes with sigalarm? */
_nop(int sig)
{}
static void * /*
_reap_children(void *arg) * Wait for child process using WNOHANG to limit
{ * the time spent waiting to 10 seconds (10,000ms).
struct launched_process_node node, *pnode; */
pid_t pid; for (n = 0; n < 1000; n++) {
int status; wpid = waitpid(pid, &status, WNOHANG);
struct rusage usage; if (wpid == (pid_t)-1) {
struct sigaction sa = {}; if (errno == EINTR)
continue;
(void) sigfillset(&sa.sa_mask);
(void) sigdelset(&sa.sa_mask, SIGCHLD);
(void) pthread_sigmask(SIG_SETMASK, &sa.sa_mask, NULL);
(void) sigemptyset(&sa.sa_mask);
sa.sa_handler = _nop;
sa.sa_flags = SA_NOCLDSTOP;
(void) sigaction(SIGCHLD, &sa, NULL);
for (_reap_children_stop = B_FALSE; !_reap_children_stop; ) {
(void) pthread_mutex_lock(&_launched_processes_lock);
pid = wait4(0, &status, WNOHANG, &usage);
if (pid == 0 || pid == (pid_t)-1) {
(void) pthread_mutex_unlock(&_launched_processes_lock);
if (pid == 0 || errno == ECHILD)
pause();
else if (errno != EINTR)
zed_log_msg(LOG_WARNING, zed_log_msg(LOG_WARNING,
"Failed to wait for children: %s", "Failed to wait for \"%s\" eid=%llu pid=%d",
strerror(errno)); prog, eid, pid);
} else { break;
memset(&node, 0, sizeof (node)); } else if (wpid == 0) {
node.pid = pid; struct timespec t;
pnode = avl_find(&_launched_processes, &node, NULL);
if (pnode) {
memcpy(&node, pnode, sizeof (node));
avl_remove(&_launched_processes, pnode); /* child still running */
free(pnode); t.tv_sec = 0;
t.tv_nsec = 10000000; /* 10ms */
(void) nanosleep(&t, NULL);
continue;
} }
(void) pthread_mutex_unlock(&_launched_processes_lock);
__atomic_add_fetch(&_launched_processes_limit, 1,
__ATOMIC_SEQ_CST);
usage.ru_utime.tv_sec += usage.ru_stime.tv_sec;
usage.ru_utime.tv_usec += usage.ru_stime.tv_usec;
usage.ru_utime.tv_sec +=
usage.ru_utime.tv_usec / (1000 * 1000);
usage.ru_utime.tv_usec %= 1000 * 1000;
if (WIFEXITED(status)) { if (WIFEXITED(status)) {
zed_log_msg(LOG_INFO, zed_log_msg(LOG_INFO,
"Finished \"%s\" eid=%llu pid=%d " "Finished \"%s\" eid=%llu pid=%d exit=%d",
"time=%llu.%06us exit=%d", prog, eid, pid, WEXITSTATUS(status));
node.name, node.eid, pid,
(unsigned long long) usage.ru_utime.tv_sec,
(unsigned int) usage.ru_utime.tv_usec,
WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) { } else if (WIFSIGNALED(status)) {
zed_log_msg(LOG_INFO, zed_log_msg(LOG_INFO,
"Finished \"%s\" eid=%llu pid=%d " "Finished \"%s\" eid=%llu pid=%d sig=%d/%s",
"time=%llu.%06us sig=%d/%s", prog, eid, pid, WTERMSIG(status),
node.name, node.eid, pid,
(unsigned long long) usage.ru_utime.tv_sec,
(unsigned int) usage.ru_utime.tv_usec,
WTERMSIG(status),
strsignal(WTERMSIG(status))); strsignal(WTERMSIG(status)));
} else { } else {
zed_log_msg(LOG_INFO, zed_log_msg(LOG_INFO,
"Finished \"%s\" eid=%llu pid=%d " "Finished \"%s\" eid=%llu pid=%d status=0x%X",
"time=%llu.%06us status=0x%X", prog, eid, (unsigned int) status);
node.name, node.eid, }
(unsigned long long) usage.ru_utime.tv_sec, break;
(unsigned int) usage.ru_utime.tv_usec,
(unsigned int) status);
} }
free(node.name); /*
* kill child process after 10 seconds
*/
if (wpid == 0) {
zed_log_msg(LOG_WARNING, "Killing hung \"%s\" pid=%d",
prog, pid);
(void) kill(pid, SIGKILL);
(void) waitpid(pid, &status, 0);
} }
}
return (NULL);
}
void
zed_exec_fini(void)
{
struct launched_process_node *node;
void *ck = NULL;
if (_reap_children_tid == (pthread_t)-1)
return;
_reap_children_stop = B_TRUE;
(void) pthread_kill(_reap_children_tid, SIGCHLD);
(void) pthread_join(_reap_children_tid, NULL);
while ((node = avl_destroy_nodes(&_launched_processes, &ck)) != NULL) {
free(node->name);
free(node);
}
avl_destroy(&_launched_processes);
(void) pthread_mutex_destroy(&_launched_processes_lock);
(void) pthread_mutex_init(&_launched_processes_lock, NULL);
_reap_children_tid = (pthread_t)-1;
} }
/* /*
* Process the event [eid] by synchronously invoking all zedlets with a * Process the event [eid] by synchronously invoking all zedlets with a
* matching class prefix. * matching class prefix.
* *
* Each executable in [zcp->zedlets] from the directory [zcp->zedlet_dir] * Each executable in [zedlets] from the directory [dir] is matched against
* is matched against the event's [class], [subclass], and the "all" class * the event's [class], [subclass], and the "all" class (which matches
* (which matches all events). * all events). Every zedlet with a matching class prefix is invoked.
* Every zedlet with a matching class prefix is invoked.
* The NAME=VALUE strings in [envs] will be passed to the zedlet as * The NAME=VALUE strings in [envs] will be passed to the zedlet as
* environment variables. * environment variables.
* *
* The file descriptor [zcp->zevent_fd] is the zevent_fd used to track the * The file descriptor [zfd] is the zevent_fd used to track the
* current cursor location within the zevent nvlist. * current cursor location within the zevent nvlist.
* *
* Return 0 on success, -1 on error. * Return 0 on success, -1 on error.
*/ */
int int
zed_exec_process(uint64_t eid, const char *class, const char *subclass, zed_exec_process(uint64_t eid, const char *class, const char *subclass,
struct zed_conf *zcp, zed_strings_t *envs) const char *dir, zed_strings_t *zedlets, zed_strings_t *envs, int zfd)
{ {
const char *class_strings[4]; const char *class_strings[4];
const char *allclass = "all"; const char *allclass = "all";
@ -325,22 +203,9 @@ zed_exec_process(uint64_t eid, const char *class, const char *subclass,
char **e; char **e;
int n; int n;
if (!zcp->zedlet_dir || !zcp->zedlets || !envs || zcp->zevent_fd < 0) if (!dir || !zedlets || !envs || zfd < 0)
return (-1); return (-1);
if (_reap_children_tid == (pthread_t)-1) {
_launched_processes_limit = zcp->max_jobs;
if (pthread_create(&_reap_children_tid, NULL,
_reap_children, NULL) != 0)
return (-1);
pthread_setname_np(_reap_children_tid, "reap ZEDLETs");
avl_create(&_launched_processes, _launched_process_node_compare,
sizeof (struct launched_process_node),
offsetof(struct launched_process_node, node));
}
csp = class_strings; csp = class_strings;
if (class) if (class)
@ -356,13 +221,11 @@ zed_exec_process(uint64_t eid, const char *class, const char *subclass,
e = _zed_exec_create_env(envs); e = _zed_exec_create_env(envs);
for (z = zed_strings_first(zcp->zedlets); z; for (z = zed_strings_first(zedlets); z; z = zed_strings_next(zedlets)) {
z = zed_strings_next(zcp->zedlets)) {
for (csp = class_strings; *csp; csp++) { for (csp = class_strings; *csp; csp++) {
n = strlen(*csp); n = strlen(*csp);
if ((strncmp(z, *csp, n) == 0) && !isalpha(z[n])) if ((strncmp(z, *csp, n) == 0) && !isalpha(z[n]))
_zed_exec_fork_child(eid, zcp->zedlet_dir, _zed_exec_fork_child(eid, dir, z, e, zfd);
z, e, zcp->zevent_fd, zcp->do_foreground);
} }
} }
free(e); free(e);

View File

@ -3,7 +3,7 @@
* *
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049). * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC. * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
* Refer to the OpenZFS git commit log for authoritative copyright attribution. * Refer to the ZoL git commit log for authoritative copyright attribution.
* *
* The contents of this file are subject to the terms of the * The contents of this file are subject to the terms of the
* Common Development and Distribution License Version 1.0 (CDDL-1.0). * Common Development and Distribution License Version 1.0 (CDDL-1.0).
@ -17,11 +17,9 @@
#include <stdint.h> #include <stdint.h>
#include "zed_strings.h" #include "zed_strings.h"
#include "zed_conf.h"
void zed_exec_fini(void);
int zed_exec_process(uint64_t eid, const char *class, const char *subclass, int zed_exec_process(uint64_t eid, const char *class, const char *subclass,
struct zed_conf *zcp, zed_strings_t *envs); const char *dir, zed_strings_t *zedlets, zed_strings_t *envs,
int zevent_fd);
#endif /* !ZED_EXEC_H */ #endif /* !ZED_EXEC_H */

View File

@ -3,7 +3,7 @@
* *
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049). * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC. * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
* Refer to the OpenZFS git commit log for authoritative copyright attribution. * Refer to the ZoL git commit log for authoritative copyright attribution.
* *
* The contents of this file are subject to the terms of the * The contents of this file are subject to the terms of the
* Common Development and Distribution License Version 1.0 (CDDL-1.0). * Common Development and Distribution License Version 1.0 (CDDL-1.0).
@ -12,17 +12,73 @@
* You may not use this file except in compliance with the license. * You may not use this file except in compliance with the license.
*/ */
#include <dirent.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <limits.h> #include <limits.h>
#include <string.h> #include <string.h>
#include <sys/resource.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include "zed_file.h" #include "zed_file.h"
#include "zed_log.h" #include "zed_log.h"
/*
* Read up to [n] bytes from [fd] into [buf].
* Return the number of bytes read, 0 on EOF, or -1 on error.
*/
ssize_t
zed_file_read_n(int fd, void *buf, size_t n)
{
unsigned char *p;
size_t n_left;
ssize_t n_read;
p = buf;
n_left = n;
while (n_left > 0) {
if ((n_read = read(fd, p, n_left)) < 0) {
if (errno == EINTR)
continue;
else
return (-1);
} else if (n_read == 0) {
break;
}
n_left -= n_read;
p += n_read;
}
return (n - n_left);
}
/*
* Write [n] bytes from [buf] out to [fd].
* Return the number of bytes written, or -1 on error.
*/
ssize_t
zed_file_write_n(int fd, void *buf, size_t n)
{
const unsigned char *p;
size_t n_left;
ssize_t n_written;
p = buf;
n_left = n;
while (n_left > 0) {
if ((n_written = write(fd, p, n_left)) < 0) {
if (errno == EINTR)
continue;
else
return (-1);
}
n_left -= n_written;
p += n_written;
}
return (n);
}
/* /*
* Set an exclusive advisory lock on the open file descriptor [fd]. * Set an exclusive advisory lock on the open file descriptor [fd].
* Return 0 on success, 1 if a conflicting lock is held by another process, * Return 0 on success, 1 if a conflicting lock is held by another process,
@ -104,13 +160,6 @@ zed_file_is_locked(int fd)
return (lock.l_pid); return (lock.l_pid);
} }
#if __APPLE__
#define PROC_SELF_FD "/dev/fd"
#else /* Linux-compatible layout */
#define PROC_SELF_FD "/proc/self/fd"
#endif
/* /*
* Close all open file descriptors greater than or equal to [lowfd]. * Close all open file descriptors greater than or equal to [lowfd].
* Any errors encountered while closing file descriptors are ignored. * Any errors encountered while closing file descriptors are ignored.
@ -118,24 +167,51 @@ zed_file_is_locked(int fd)
void void
zed_file_close_from(int lowfd) zed_file_close_from(int lowfd)
{ {
int errno_bak = errno; const int maxfd_def = 256;
int maxfd = 0; int errno_bak;
struct rlimit rl;
int maxfd;
int fd; int fd;
DIR *fddir;
struct dirent *fdent;
if ((fddir = opendir(PROC_SELF_FD)) != NULL) { errno_bak = errno;
while ((fdent = readdir(fddir)) != NULL) {
fd = atoi(fdent->d_name); if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
if (fd > maxfd && fd != dirfd(fddir)) maxfd = maxfd_def;
maxfd = fd; } else if (rl.rlim_max == RLIM_INFINITY) {
} maxfd = maxfd_def;
(void) closedir(fddir);
} else { } else {
maxfd = sysconf(_SC_OPEN_MAX); maxfd = rl.rlim_max;
} }
for (fd = lowfd; fd < maxfd; fd++) for (fd = lowfd; fd < maxfd; fd++)
(void) close(fd); (void) close(fd);
errno = errno_bak; errno = errno_bak;
} }
/*
* Set the CLOEXEC flag on file descriptor [fd] so it will be automatically
* closed upon successful execution of one of the exec functions.
* Return 0 on success, or -1 on error.
*
* FIXME: No longer needed?
*/
int
zed_file_close_on_exec(int fd)
{
int flags;
if (fd < 0) {
errno = EBADF;
return (-1);
}
flags = fcntl(fd, F_GETFD);
if (flags == -1)
return (-1);
flags |= FD_CLOEXEC;
if (fcntl(fd, F_SETFD, flags) == -1)
return (-1);
return (0);
}

View File

@ -3,7 +3,7 @@
* *
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049). * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC. * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
* Refer to the OpenZFS git commit log for authoritative copyright attribution. * Refer to the ZoL git commit log for authoritative copyright attribution.
* *
* The contents of this file are subject to the terms of the * The contents of this file are subject to the terms of the
* Common Development and Distribution License Version 1.0 (CDDL-1.0). * Common Development and Distribution License Version 1.0 (CDDL-1.0).
@ -18,6 +18,10 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
ssize_t zed_file_read_n(int fd, void *buf, size_t n);
ssize_t zed_file_write_n(int fd, void *buf, size_t n);
int zed_file_lock(int fd); int zed_file_lock(int fd);
int zed_file_unlock(int fd); int zed_file_unlock(int fd);
@ -26,4 +30,6 @@ pid_t zed_file_is_locked(int fd);
void zed_file_close_from(int fd); void zed_file_close_from(int fd);
int zed_file_close_on_exec(int fd);
#endif /* !ZED_FILE_H */ #endif /* !ZED_FILE_H */

View File

@ -3,7 +3,7 @@
* *
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049). * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC. * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
* Refer to the OpenZFS git commit log for authoritative copyright attribution. * Refer to the ZoL git commit log for authoritative copyright attribution.
* *
* The contents of this file are subject to the terms of the * The contents of this file are subject to the terms of the
* Common Development and Distribution License Version 1.0 (CDDL-1.0). * Common Development and Distribution License Version 1.0 (CDDL-1.0).

View File

@ -3,7 +3,7 @@
* *
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049). * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC. * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
* Refer to the OpenZFS git commit log for authoritative copyright attribution. * Refer to the ZoL git commit log for authoritative copyright attribution.
* *
* The contents of this file are subject to the terms of the * The contents of this file are subject to the terms of the
* Common Development and Distribution License Version 1.0 (CDDL-1.0). * Common Development and Distribution License Version 1.0 (CDDL-1.0).

View File

@ -3,7 +3,7 @@
* *
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049). * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC. * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
* Refer to the OpenZFS git commit log for authoritative copyright attribution. * Refer to the ZoL git commit log for authoritative copyright attribution.
* *
* The contents of this file are subject to the terms of the * The contents of this file are subject to the terms of the
* Common Development and Distribution License Version 1.0 (CDDL-1.0). * Common Development and Distribution License Version 1.0 (CDDL-1.0).

View File

@ -3,7 +3,7 @@
* *
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049). * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC. * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
* Refer to the OpenZFS git commit log for authoritative copyright attribution. * Refer to the ZoL git commit log for authoritative copyright attribution.
* *
* The contents of this file are subject to the terms of the * The contents of this file are subject to the terms of the
* Common Development and Distribution License Version 1.0 (CDDL-1.0). * Common Development and Distribution License Version 1.0 (CDDL-1.0).

View File

@ -315,14 +315,14 @@ get_usage(zfs_help_t idx)
case HELP_ROLLBACK: case HELP_ROLLBACK:
return (gettext("\trollback [-rRf] <snapshot>\n")); return (gettext("\trollback [-rRf] <snapshot>\n"));
case HELP_SEND: case HELP_SEND:
return (gettext("\tsend [-DnPpRVvLecwhb] [-[i|I] snapshot] " return (gettext("\tsend [-DnPpRvLecwhb] [-[i|I] snapshot] "
"<snapshot>\n" "<snapshot>\n"
"\tsend [-DnVvPLecw] [-i snapshot|bookmark] " "\tsend [-nvPLecw] [-i snapshot|bookmark] "
"<filesystem|volume|snapshot>\n" "<filesystem|volume|snapshot>\n"
"\tsend [-DnPpVvLec] [-i bookmark|snapshot] " "\tsend [-DnPpvLec] [-i bookmark|snapshot] "
"--redact <bookmark> <snapshot>\n" "--redact <bookmark> <snapshot>\n"
"\tsend [-nVvPe] -t <receive_resume_token>\n" "\tsend [-nvPe] -t <receive_resume_token>\n"
"\tsend [-PnVv] --saved filesystem\n")); "\tsend [-Pnv] --saved filesystem\n"));
case HELP_SET: case HELP_SET:
return (gettext("\tset <property=value> ... " return (gettext("\tset <property=value> ... "
"<filesystem|volume|snapshot> ...\n")); "<filesystem|volume|snapshot> ...\n"));
@ -535,7 +535,7 @@ usage(boolean_t requested)
show_properties = B_TRUE; show_properties = B_TRUE;
if (show_properties) { if (show_properties) {
(void) fprintf(fp, "%s", (void) fprintf(fp,
gettext("\nThe following properties are supported:\n")); gettext("\nThe following properties are supported:\n"));
(void) fprintf(fp, "\n\t%-14s %s %s %s\n\n", (void) fprintf(fp, "\n\t%-14s %s %s %s\n\n",
@ -728,32 +728,6 @@ finish_progress(char *done)
pt_header = NULL; pt_header = NULL;
} }
/* This function checks if the passed fd refers to /dev/null or /dev/zero */
#ifdef __linux__
static boolean_t
is_dev_nullzero(int fd)
{
struct stat st;
fstat(fd, &st);
return (major(st.st_rdev) == 1 && (minor(st.st_rdev) == 3 /* null */ ||
minor(st.st_rdev) == 5 /* zero */));
}
#endif
static void
note_dev_error(int err, int fd)
{
#ifdef __linux__
if (err == EINVAL && is_dev_nullzero(fd)) {
(void) fprintf(stderr,
gettext("Error: Writing directly to /dev/{null,zero} files"
" on certain kernels is not currently implemented.\n"
"(As a workaround, "
"try \"zfs send [...] | cat > /dev/null\")\n"));
}
#endif
}
static int static int
zfs_mount_and_share(libzfs_handle_t *hdl, const char *dataset, zfs_type_t type) zfs_mount_and_share(libzfs_handle_t *hdl, const char *dataset, zfs_type_t type)
{ {
@ -2480,7 +2454,7 @@ upgrade_set_callback(zfs_handle_t *zhp, void *data)
/* upgrade */ /* upgrade */
if (version < cb->cb_version) { if (version < cb->cb_version) {
char verstr[24]; char verstr[16];
(void) snprintf(verstr, sizeof (verstr), (void) snprintf(verstr, sizeof (verstr),
"%llu", (u_longlong_t)cb->cb_version); "%llu", (u_longlong_t)cb->cb_version);
if (cb->cb_lastfs[0] && !same_pool(zhp, cb->cb_lastfs)) { if (cb->cb_lastfs[0] && !same_pool(zhp, cb->cb_lastfs)) {
@ -3474,8 +3448,6 @@ print_header(list_cbdata_t *cb)
boolean_t first = B_TRUE; boolean_t first = B_TRUE;
boolean_t right_justify; boolean_t right_justify;
color_start(ANSI_BOLD);
for (; pl != NULL; pl = pl->pl_next) { for (; pl != NULL; pl = pl->pl_next) {
if (!first) { if (!first) {
(void) printf(" "); (void) printf(" ");
@ -3502,31 +3474,9 @@ print_header(list_cbdata_t *cb)
(void) printf("%-*s", (int)pl->pl_width, header); (void) printf("%-*s", (int)pl->pl_width, header);
} }
color_end();
(void) printf("\n"); (void) printf("\n");
} }
/*
* Decides on the color that the avail value should be printed in.
* > 80% used = yellow
* > 90% used = red
*/
static const char *
zfs_list_avail_color(zfs_handle_t *zhp)
{
uint64_t used = zfs_prop_get_int(zhp, ZFS_PROP_USED);
uint64_t avail = zfs_prop_get_int(zhp, ZFS_PROP_AVAILABLE);
int percentage = (int)((double)avail / MAX(avail + used, 1) * 100);
if (percentage > 20)
return (NULL);
else if (percentage > 10)
return (ANSI_YELLOW);
else
return (ANSI_RED);
}
/* /*
* Given a dataset and a list of fields, print out all the properties according * Given a dataset and a list of fields, print out all the properties according
* to the described layout. * to the described layout.
@ -3589,22 +3539,6 @@ print_dataset(zfs_handle_t *zhp, list_cbdata_t *cb)
right_justify = B_FALSE; right_justify = B_FALSE;
} }
/*
* zfs_list_avail_color() needs ZFS_PROP_AVAILABLE + USED
* - so we need another for() search for the USED part
* - when no colors wanted, we can skip the whole thing
*/
if (use_color() && pl->pl_prop == ZFS_PROP_AVAILABLE) {
zprop_list_t *pl2 = cb->cb_proplist;
for (; pl2 != NULL; pl2 = pl2->pl_next) {
if (pl2->pl_prop == ZFS_PROP_USED) {
color_start(zfs_list_avail_color(zhp));
/* found it, no need for more loops */
break;
}
}
}
/* /*
* If this is being called in scripted mode, or if this is the * If this is being called in scripted mode, or if this is the
* last column and it is left-justified, don't include a width * last column and it is left-justified, don't include a width
@ -3616,9 +3550,6 @@ print_dataset(zfs_handle_t *zhp, list_cbdata_t *cb)
(void) printf("%*s", (int)pl->pl_width, propstr); (void) printf("%*s", (int)pl->pl_width, propstr);
else else
(void) printf("%-*s", (int)pl->pl_width, propstr); (void) printf("%-*s", (int)pl->pl_width, propstr);
if (pl->pl_prop == ZFS_PROP_AVAILABLE)
color_end();
} }
(void) printf("\n"); (void) printf("\n");
@ -4445,12 +4376,10 @@ zfs_do_send(int argc, char **argv)
struct option long_options[] = { struct option long_options[] = {
{"replicate", no_argument, NULL, 'R'}, {"replicate", no_argument, NULL, 'R'},
{"skip-missing", no_argument, NULL, 's'},
{"redact", required_argument, NULL, 'd'}, {"redact", required_argument, NULL, 'd'},
{"props", no_argument, NULL, 'p'}, {"props", no_argument, NULL, 'p'},
{"parsable", no_argument, NULL, 'P'}, {"parsable", no_argument, NULL, 'P'},
{"dedup", no_argument, NULL, 'D'}, {"dedup", no_argument, NULL, 'D'},
{"proctitle", no_argument, NULL, 'V'},
{"verbose", no_argument, NULL, 'v'}, {"verbose", no_argument, NULL, 'v'},
{"dryrun", no_argument, NULL, 'n'}, {"dryrun", no_argument, NULL, 'n'},
{"large-block", no_argument, NULL, 'L'}, {"large-block", no_argument, NULL, 'L'},
@ -4465,7 +4394,7 @@ zfs_do_send(int argc, char **argv)
}; };
/* check options */ /* check options */
while ((c = getopt_long(argc, argv, ":i:I:RsDpVvnPLeht:cwbd:S", while ((c = getopt_long(argc, argv, ":i:I:RDpvnPLeht:cwbd:S",
long_options, NULL)) != -1) { long_options, NULL)) != -1) {
switch (c) { switch (c) {
case 'i': case 'i':
@ -4482,9 +4411,6 @@ zfs_do_send(int argc, char **argv)
case 'R': case 'R':
flags.replicate = B_TRUE; flags.replicate = B_TRUE;
break; break;
case 's':
flags.skipmissing = B_TRUE;
break;
case 'd': case 'd':
redactbook = optarg; redactbook = optarg;
break; break;
@ -4500,9 +4426,6 @@ zfs_do_send(int argc, char **argv)
case 'P': case 'P':
flags.parsable = B_TRUE; flags.parsable = B_TRUE;
break; break;
case 'V':
flags.progressastitle = B_TRUE;
break;
case 'v': case 'v':
flags.verbosity++; flags.verbosity++;
flags.progress = B_TRUE; flags.progress = B_TRUE;
@ -4578,7 +4501,7 @@ zfs_do_send(int argc, char **argv)
} }
} }
if ((flags.parsable || flags.progressastitle) && flags.verbosity == 0) if (flags.parsable && flags.verbosity == 0)
flags.verbosity = 1; flags.verbosity = 1;
argc -= optind; argc -= optind;
@ -4645,23 +4568,11 @@ zfs_do_send(int argc, char **argv)
err = zfs_send_saved(zhp, &flags, STDOUT_FILENO, err = zfs_send_saved(zhp, &flags, STDOUT_FILENO,
resume_token); resume_token);
if (err != 0)
note_dev_error(errno, STDOUT_FILENO);
zfs_close(zhp); zfs_close(zhp);
return (err != 0); return (err != 0);
} else if (resume_token != NULL) { } else if (resume_token != NULL) {
err = zfs_send_resume(g_zfs, &flags, STDOUT_FILENO, return (zfs_send_resume(g_zfs, &flags, STDOUT_FILENO,
resume_token); resume_token));
if (err != 0)
note_dev_error(errno, STDOUT_FILENO);
return (err);
}
if (flags.skipmissing && !flags.replicate) {
(void) fprintf(stderr,
gettext("skip-missing flag can only be used in "
"conjunction with replicate\n"));
usage(B_FALSE);
} }
/* /*
@ -4705,8 +4616,6 @@ zfs_do_send(int argc, char **argv)
err = zfs_send_one(zhp, fromname, STDOUT_FILENO, &flags, err = zfs_send_one(zhp, fromname, STDOUT_FILENO, &flags,
redactbook); redactbook);
zfs_close(zhp); zfs_close(zhp);
if (err != 0)
note_dev_error(errno, STDOUT_FILENO);
return (err != 0); return (err != 0);
} }
@ -4783,7 +4692,6 @@ zfs_do_send(int argc, char **argv)
nvlist_free(dbgnv); nvlist_free(dbgnv);
} }
zfs_close(zhp); zfs_close(zhp);
note_dev_error(errno, STDOUT_FILENO);
return (err != 0); return (err != 0);
} }
@ -6640,7 +6548,7 @@ zfs_do_holds(int argc, char **argv)
/* /*
* 1. collect holds data, set format options * 1. collect holds data, set format options
*/ */
ret = zfs_for_each(1, argv + i, flags, types, NULL, NULL, limit, ret = zfs_for_each(argc, argv, flags, types, NULL, NULL, limit,
holds_callback, &cb); holds_callback, &cb);
if (ret != 0) if (ret != 0)
++errors; ++errors;
@ -7522,7 +7430,6 @@ unshare_unmount(int op, int argc, char **argv)
if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) == if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) ==
ZFS_CANMOUNT_NOAUTO) ZFS_CANMOUNT_NOAUTO)
continue; continue;
break;
default: default:
break; break;
} }
@ -7719,7 +7626,7 @@ zfs_do_diff(int argc, char **argv)
int c; int c;
struct sigaction sa; struct sigaction sa;
while ((c = getopt(argc, argv, "FHth")) != -1) { while ((c = getopt(argc, argv, "FHt")) != -1) {
switch (c) { switch (c) {
case 'F': case 'F':
flags |= ZFS_DIFF_CLASSIFY; flags |= ZFS_DIFF_CLASSIFY;
@ -7730,9 +7637,6 @@ zfs_do_diff(int argc, char **argv)
case 't': case 't':
flags |= ZFS_DIFF_TIMESTAMP; flags |= ZFS_DIFF_TIMESTAMP;
break; break;
case 'h':
flags |= ZFS_DIFF_NO_MANGLE;
break;
default: default:
(void) fprintf(stderr, (void) fprintf(stderr,
gettext("invalid option '%c'\n"), optopt); gettext("invalid option '%c'\n"), optopt);
@ -8582,7 +8486,7 @@ static int
zfs_do_wait(int argc, char **argv) zfs_do_wait(int argc, char **argv)
{ {
boolean_t enabled[ZFS_WAIT_NUM_ACTIVITIES]; boolean_t enabled[ZFS_WAIT_NUM_ACTIVITIES];
int error = 0, i; int error, i;
int c; int c;
/* By default, wait for all types of activity. */ /* By default, wait for all types of activity. */
@ -8740,8 +8644,6 @@ main(int argc, char **argv)
libzfs_print_on_error(g_zfs, B_TRUE); libzfs_print_on_error(g_zfs, B_TRUE);
zfs_setproctitle_init(argc, argv, environ);
/* /*
* Many commands modify input strings for string parsing reasons. * Many commands modify input strings for string parsing reasons.
* We create a copy to protect the original argv. * We create a copy to protect the original argv.

View File

@ -207,6 +207,7 @@ static int
zfs_project_handle_dir(const char *name, zfs_project_control_t *zpc, zfs_project_handle_dir(const char *name, zfs_project_control_t *zpc,
list_t *head) list_t *head)
{ {
char fullname[PATH_MAX];
struct dirent *ent; struct dirent *ent;
DIR *dir; DIR *dir;
int ret = 0; int ret = 0;
@ -226,28 +227,21 @@ zfs_project_handle_dir(const char *name, zfs_project_control_t *zpc,
zpc->zpc_ignore_noent = B_TRUE; zpc->zpc_ignore_noent = B_TRUE;
errno = 0; errno = 0;
while (!ret && (ent = readdir(dir)) != NULL) { while (!ret && (ent = readdir(dir)) != NULL) {
char *fullname;
/* skip "." and ".." */ /* skip "." and ".." */
if (strcmp(ent->d_name, ".") == 0 || if (strcmp(ent->d_name, ".") == 0 ||
strcmp(ent->d_name, "..") == 0) strcmp(ent->d_name, "..") == 0)
continue; continue;
if (strlen(ent->d_name) + strlen(name) + 1 >= PATH_MAX) { if (strlen(ent->d_name) + strlen(name) >=
sizeof (fullname) + 1) {
errno = ENAMETOOLONG; errno = ENAMETOOLONG;
break; break;
} }
if (asprintf(&fullname, "%s/%s", name, ent->d_name) == -1) { sprintf(fullname, "%s/%s", name, ent->d_name);
errno = ENOMEM;
break;
}
ret = zfs_project_handle_one(fullname, zpc); ret = zfs_project_handle_one(fullname, zpc);
if (!ret && zpc->zpc_recursive && ent->d_type == DT_DIR) if (!ret && zpc->zpc_recursive && ent->d_type == DT_DIR)
zfs_project_item_alloc(head, fullname); zfs_project_item_alloc(head, fullname);
free(fullname);
} }
if (errno && !ret) { if (errno && !ret) {

View File

@ -35,7 +35,7 @@ libzfs_handle_t *g_zfs;
static void static void
usage(int err) usage(int err)
{ {
fprintf(stderr, "Usage: zfs_ids_to_path [-v] <pool> <objset id> " fprintf(stderr, "Usage: [-v] zfs_ids_to_path <pool> <objset id> "
"<object id>\n"); "<object id>\n");
exit(err); exit(err);
} }
@ -63,11 +63,11 @@ main(int argc, char **argv)
uint64_t objset, object; uint64_t objset, object;
if (sscanf(argv[1], "%llu", (u_longlong_t *)&objset) != 1) { if (sscanf(argv[1], "%llu", (u_longlong_t *)&objset) != 1) {
(void) fprintf(stderr, "Invalid objset id: %s\n", argv[1]); (void) fprintf(stderr, "Invalid objset id: %s\n", argv[2]);
usage(2); usage(2);
} }
if (sscanf(argv[2], "%llu", (u_longlong_t *)&object) != 1) { if (sscanf(argv[2], "%llu", (u_longlong_t *)&object) != 1) {
(void) fprintf(stderr, "Invalid object id: %s\n", argv[2]); (void) fprintf(stderr, "Invalid object id: %s\n", argv[3]);
usage(3); usage(3);
} }
if ((g_zfs = libzfs_init()) == NULL) { if ((g_zfs = libzfs_init()) == NULL) {
@ -76,7 +76,7 @@ main(int argc, char **argv)
} }
zpool_handle_t *pool = zpool_open(g_zfs, argv[0]); zpool_handle_t *pool = zpool_open(g_zfs, argv[0]);
if (pool == NULL) { if (pool == NULL) {
fprintf(stderr, "Could not open pool %s\n", argv[0]); fprintf(stderr, "Could not open pool %s\n", argv[1]);
libzfs_fini(g_zfs); libzfs_fini(g_zfs);
return (5); return (5);
} }

View File

@ -36,6 +36,8 @@
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
static void usage(void);
static void static void
usage(void) usage(void)
{ {
@ -58,11 +60,12 @@ int
main(int argc, char **argv) main(int argc, char **argv)
{ {
/* default file path, can be optionally set by user */ /* default file path, can be optionally set by user */
const char *path = "/etc/hostid"; char path[PATH_MAX] = "/etc/hostid";
/* holds converted user input or lrand48() generated value */ /* holds converted user input or lrand48() generated value */
unsigned long input_i = 0; unsigned long input_i = 0;
int opt; int opt;
int pathlen;
int force_fwrite = 0; int force_fwrite = 0;
while ((opt = getopt_long(argc, argv, "fo:h?", 0, 0)) != -1) { while ((opt = getopt_long(argc, argv, "fo:h?", 0, 0)) != -1) {
switch (opt) { switch (opt) {
@ -70,7 +73,14 @@ main(int argc, char **argv)
force_fwrite = 1; force_fwrite = 1;
break; break;
case 'o': case 'o':
path = optarg; pathlen = snprintf(path, sizeof (path), "%s", optarg);
if (pathlen >= sizeof (path)) {
fprintf(stderr, "%s\n", strerror(EOVERFLOW));
exit(EXIT_FAILURE);
} else if (pathlen < 1) {
fprintf(stderr, "%s\n", strerror(EINVAL));
exit(EXIT_FAILURE);
}
break; break;
case 'h': case 'h':
case '?': case '?':
@ -127,7 +137,7 @@ main(int argc, char **argv)
} }
/* /*
* we need just 4 bytes in native endianness * we need just 4 bytes in native endianess
* not using sethostid() because it may be missing or just a stub * not using sethostid() because it may be missing or just a stub
*/ */
uint32_t hostid = input_i; uint32_t hostid = input_i;

View File

@ -1,5 +1,4 @@
include $(top_srcdir)/config/Rules.am include $(top_srcdir)/config/Rules.am
include $(top_srcdir)/config/Shellcheck.am
AM_CFLAGS += $(LIBBLKID_CFLAGS) $(LIBUUID_CFLAGS) AM_CFLAGS += $(LIBBLKID_CFLAGS) $(LIBUUID_CFLAGS)
@ -26,8 +25,7 @@ zpool_LDADD = \
$(abs_top_builddir)/lib/libzfs/libzfs.la \ $(abs_top_builddir)/lib/libzfs/libzfs.la \
$(abs_top_builddir)/lib/libzfs_core/libzfs_core.la \ $(abs_top_builddir)/lib/libzfs_core/libzfs_core.la \
$(abs_top_builddir)/lib/libnvpair/libnvpair.la \ $(abs_top_builddir)/lib/libnvpair/libnvpair.la \
$(abs_top_builddir)/lib/libuutil/libuutil.la \ $(abs_top_builddir)/lib/libuutil/libuutil.la
$(abs_top_builddir)/lib/libzutil/libzutil.la
zpool_LDADD += $(LTLIBINTL) zpool_LDADD += $(LTLIBINTL)
@ -148,10 +146,6 @@ dist_zpoolcompat_DATA = \
compatibility.d/openzfsonosx-1.9.3 \ compatibility.d/openzfsonosx-1.9.3 \
compatibility.d/openzfs-2.0-freebsd \ compatibility.d/openzfs-2.0-freebsd \
compatibility.d/openzfs-2.0-linux \ compatibility.d/openzfs-2.0-linux \
compatibility.d/openzfs-2.1-freebsd \
compatibility.d/openzfs-2.1-linux \
compatibility.d/zol-0.6.1 \
compatibility.d/zol-0.6.4 \
compatibility.d/zol-0.6.5 \ compatibility.d/zol-0.6.5 \
compatibility.d/zol-0.7 \ compatibility.d/zol-0.7 \
compatibility.d/zol-0.8 compatibility.d/zol-0.8

View File

@ -1,34 +0,0 @@
# Features supported by OpenZFS 2.1 on FreeBSD
allocation_classes
async_destroy
bookmark_v2
bookmark_written
bookmarks
device_rebuild
device_removal
draid
embedded_data
empty_bpobj
enabled_txg
encryption
extensible_dataset
filesystem_limits
hole_birth
large_blocks
large_dnode
livelist
log_spacemap
lz4_compress
multi_vdev_crash_dump
obsolete_counts
project_quota
redacted_datasets
redaction_bookmarks
resilver_defer
sha512
skein
spacemap_histogram
spacemap_v2
userobj_accounting
zpool_checkpoint
zstd_compress

View File

@ -1,35 +0,0 @@
# Features supported by OpenZFS 2.1 on Linux
allocation_classes
async_destroy
bookmark_v2
bookmark_written
bookmarks
device_rebuild
device_removal
draid
edonr
embedded_data
empty_bpobj
enabled_txg
encryption
extensible_dataset
filesystem_limits
hole_birth
large_blocks
large_dnode
livelist
log_spacemap
lz4_compress
multi_vdev_crash_dump
obsolete_counts
project_quota
redacted_datasets
redaction_bookmarks
resilver_defer
sha512
skein
spacemap_histogram
spacemap_v2
userobj_accounting
zpool_checkpoint
zstd_compress

View File

@ -1,4 +0,0 @@
# Features supported by ZFSonLinux v0.6.1
async_destroy
empty_bpobj
lz4_compress

View File

@ -1,10 +0,0 @@
# Features supported by ZFSonLinux v0.6.4
async_destroy
bookmarks
embedded_data
empty_bpobj
enabled_txg
extensible_dataset
hole_birth
lz4_compress
spacemap_histogram

View File

@ -101,39 +101,3 @@ check_sector_size_database(char *path, int *sector_size)
{ {
return (0); return (0);
} }
void
after_zpool_upgrade(zpool_handle_t *zhp)
{
char bootfs[ZPOOL_MAXPROPLEN];
if (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs,
sizeof (bootfs), NULL, B_FALSE) == 0 &&
strcmp(bootfs, "-") != 0) {
(void) printf(gettext("Pool '%s' has the bootfs "
"property set, you might need to update\nthe boot "
"code. See gptzfsboot(8) and loader.efi(8) for "
"details.\n"), zpool_get_name(zhp));
}
}
int
zpool_power_current_state(zpool_handle_t *zhp, char *vdev)
{
(void) zhp;
(void) vdev;
/* Enclosure slot power not supported on FreeBSD yet */
return (-1);
}
int
zpool_power(zpool_handle_t *zhp, char *vdev, boolean_t turn_on)
{
(void) zhp;
(void) vdev;
(void) turn_on;
/* Enclosure slot power not supported on FreeBSD yet */
return (ENOTSUP);
}

View File

@ -405,263 +405,3 @@ check_device(const char *path, boolean_t force,
return (error); return (error);
} }
void
after_zpool_upgrade(zpool_handle_t *zhp)
{
}
/*
* Read from a sysfs file and return an allocated string. Removes
* the newline from the end of the string if there is one.
*
* Returns a string on success (which must be freed), or NULL on error.
*/
static char *zpool_sysfs_gets(char *path)
{
int fd;
struct stat statbuf;
char *buf = NULL;
ssize_t count = 0;
fd = open(path, O_RDONLY);
if (fd < 0)
return (NULL);
if (fstat(fd, &statbuf) != 0) {
close(fd);
return (NULL);
}
buf = calloc(sizeof (*buf), statbuf.st_size + 1);
if (buf == NULL) {
close(fd);
return (NULL);
}
/*
* Note, we can read less bytes than st_size, and that's ok. Sysfs
* files will report their size is 4k even if they only return a small
* string.
*/
count = read(fd, buf, statbuf.st_size);
if (count < 0) {
/* Error doing read() or we overran the buffer */
close(fd);
free(buf);
return (NULL);
}
/* Remove trailing newline */
if (buf[count - 1] == '\n')
buf[count - 1] = 0;
close(fd);
return (buf);
}
/*
* Write a string to a sysfs file.
*
* Returns 0 on success, non-zero otherwise.
*/
static int zpool_sysfs_puts(char *path, char *str)
{
FILE *file;
file = fopen(path, "w");
if (!file) {
return (-1);
}
if (fputs(str, file) < 0) {
fclose(file);
return (-2);
}
fclose(file);
return (0);
}
/* Given a vdev nvlist_t, rescan its enclosure sysfs path */
static void
rescan_vdev_config_dev_sysfs_path(nvlist_t *vdev_nv)
{
update_vdev_config_dev_sysfs_path(vdev_nv,
fnvlist_lookup_string(vdev_nv, ZPOOL_CONFIG_PATH),
ZPOOL_CONFIG_VDEV_ENC_SYSFS_PATH);
}
/*
* Given a power string: "on", "off", "1", or "0", return 0 if it's an
* off value, 1 if it's an on value, and -1 if the value is unrecognized.
*/
static int zpool_power_parse_value(char *str)
{
if ((strcmp(str, "off") == 0) || (strcmp(str, "0") == 0))
return (0);
if ((strcmp(str, "on") == 0) || (strcmp(str, "1") == 0))
return (1);
return (-1);
}
/*
* Given a vdev string return an allocated string containing the sysfs path to
* its power control file. Also do a check if the power control file really
* exists and has correct permissions.
*
* Example returned strings:
*
* /sys/class/enclosure/0:0:122:0/10/power_status
* /sys/bus/pci/slots/10/power
*
* Returns allocated string on success (which must be freed), NULL on failure.
*/
static char *
zpool_power_sysfs_path(zpool_handle_t *zhp, char *vdev)
{
char *enc_sysfs_dir = NULL;
char *path = NULL;
nvlist_t *vdev_nv = zpool_find_vdev(zhp, vdev, NULL, NULL, NULL);
if (vdev_nv == NULL) {
return (NULL);
}
/* Make sure we're getting the updated enclosure sysfs path */
rescan_vdev_config_dev_sysfs_path(vdev_nv);
if (nvlist_lookup_string(vdev_nv, ZPOOL_CONFIG_VDEV_ENC_SYSFS_PATH,
&enc_sysfs_dir) != 0) {
return (NULL);
}
if (asprintf(&path, "%s/power_status", enc_sysfs_dir) == -1)
return (NULL);
if (access(path, W_OK) != 0) {
free(path);
path = NULL;
/* No HDD 'power_control' file, maybe it's NVMe? */
if (asprintf(&path, "%s/power", enc_sysfs_dir) == -1) {
return (NULL);
}
if (access(path, R_OK | W_OK) != 0) {
/* Not NVMe either */
free(path);
return (NULL);
}
}
return (path);
}
/*
* Given a path to a sysfs power control file, return B_TRUE if you should use
* "on/off" words to control it, or B_FALSE otherwise ("0/1" to control).
*/
static boolean_t
zpool_power_use_word(char *sysfs_path)
{
if (strcmp(&sysfs_path[strlen(sysfs_path) - strlen("power_status")],
"power_status") == 0) {
return (B_TRUE);
}
return (B_FALSE);
}
/*
* Check the sysfs power control value for a vdev.
*
* Returns:
* 0 - Power is off
* 1 - Power is on
* -1 - Error or unsupported
*/
int
zpool_power_current_state(zpool_handle_t *zhp, char *vdev)
{
char *val;
int rc;
char *path = zpool_power_sysfs_path(zhp, vdev);
if (path == NULL)
return (-1);
val = zpool_sysfs_gets(path);
if (val == NULL) {
free(path);
return (-1);
}
rc = zpool_power_parse_value(val);
free(val);
free(path);
return (rc);
}
/*
* Turn on or off the slot to a device
*
* Device path is the full path to the device (like /dev/sda or /dev/sda1).
*
* Return code:
* 0: Success
* ENOTSUP: Power control not supported for OS
* EBADSLT: Couldn't read current power state
* ENOENT: No sysfs path to power control
* EIO: Couldn't write sysfs power value
* EBADE: Sysfs power value didn't change
*/
int
zpool_power(zpool_handle_t *zhp, char *vdev, boolean_t turn_on)
{
char *sysfs_path;
const char *val;
int rc;
int timeout_ms;
rc = zpool_power_current_state(zhp, vdev);
if (rc == -1) {
return (EBADSLT);
}
/* Already correct value? */
if (rc == (int)turn_on)
return (0);
sysfs_path = zpool_power_sysfs_path(zhp, vdev);
if (sysfs_path == NULL)
return (ENOENT);
if (zpool_power_use_word(sysfs_path)) {
val = turn_on ? "on" : "off";
} else {
val = turn_on ? "1" : "0";
}
rc = zpool_sysfs_puts(sysfs_path, (char *)val);
free(sysfs_path);
if (rc != 0) {
return (EIO);
}
/*
* Wait up to 30 seconds for sysfs power value to change after
* writing it.
*/
timeout_ms = zpool_getenv_int("ZPOOL_POWER_ON_SLOT_TIMEOUT_MS", 30000);
for (int i = 0; i < MAX(1, timeout_ms / 200); i++) {
rc = zpool_power_current_state(zhp, vdev);
if (rc == (int)turn_on)
return (0); /* success */
fsleep(0.200); /* 200ms */
}
/* sysfs value never changed */
return (EBADE);
}

View File

@ -16,12 +16,14 @@ if [ -L "$dev" ] ; then
dev=$(readlink "$dev") dev=$(readlink "$dev")
fi fi
dev="${dev##*/}" dev=$(basename "$dev")
val="" val=""
if [ -d "/sys/class/block/$dev/slaves" ] ; then if [ -d "/sys/class/block/$dev/slaves" ] ; then
# ls -C: output in columns, no newlines, two spaces (change to one) # ls -C: output in columns, no newlines
# shellcheck disable=SC2012 val=$(ls -C "/sys/class/block/$dev/slaves")
val=$(ls -C "/sys/class/block/$dev/slaves" | tr -s '[:space:]' ' ')
# ls -C will print two spaces between files; change to one space.
val=$(echo "$val" | sed -r 's/[[:blank:]]+/ /g')
fi fi
echo "dm-deps=$val" echo "dm-deps=$val"

View File

@ -9,7 +9,7 @@ iostat: Show iostat values since boot (summary page).
iostat-1s: Do a single 1-second iostat sample and show values. iostat-1s: Do a single 1-second iostat sample and show values.
iostat-10s: Do a single 10-second iostat sample and show values." iostat-10s: Do a single 10-second iostat sample and show values."
script="${0##*/}" script=$(basename "$0")
if [ "$1" = "-h" ] ; then if [ "$1" = "-h" ] ; then
echo "$helpstr" | grep "$script:" | tr -s '\t' | cut -f 2- echo "$helpstr" | grep "$script:" | tr -s '\t' | cut -f 2-
exit exit
@ -42,7 +42,7 @@ else
${brief:+"-y"} \ ${brief:+"-y"} \
${interval:+"$interval"} \ ${interval:+"$interval"} \
${interval:+"1"} \ ${interval:+"1"} \
"$VDEV_UPATH" | grep -v '^$' | tail -n 2) "$VDEV_UPATH" | awk NF | tail -n 2)
fi fi
@ -61,7 +61,7 @@ fi
cols=$(echo "$out" | head -n 1) cols=$(echo "$out" | head -n 1)
# Get the values and tab separate them to make them cut-able. # Get the values and tab separate them to make them cut-able.
vals=$(echo "$out" | tail -n 1 | tr -s '[:space:]' '\t') vals=$(echo "$out" | tail -n 1 | sed -r 's/[[:blank:]]+/\t/g')
i=0 i=0
for col in $cols ; do for col in $cols ; do

View File

@ -48,7 +48,7 @@ size: Show the disk capacity.
vendor: Show the disk vendor. vendor: Show the disk vendor.
lsblk: Show the disk size, vendor, and model number." lsblk: Show the disk size, vendor, and model number."
script="${0##*/}" script=$(basename "$0")
if [ "$1" = "-h" ] ; then if [ "$1" = "-h" ] ; then
echo "$helpstr" | grep "$script:" | tr -s '\t' | cut -f 2- echo "$helpstr" | grep "$script:" | tr -s '\t' | cut -f 2-

View File

@ -4,23 +4,19 @@
# #
if [ "$1" = "-h" ] ; then if [ "$1" = "-h" ] ; then
echo "Show whether a vdev is a file, hdd, ssd, or iscsi." echo "Show whether a vdev is a file, hdd, or ssd."
exit exit
fi fi
if [ -b "$VDEV_UPATH" ]; then if [ -b "$VDEV_UPATH" ]; then
device="${VDEV_UPATH##*/}" device=$(basename "$VDEV_UPATH")
read -r val 2>/dev/null < "/sys/block/$device/queue/rotational" val=$(cat "/sys/block/$device/queue/rotational" 2>/dev/null)
case "$val" in if [ "$val" = "0" ]; then
0) MEDIA="ssd" ;; MEDIA="ssd"
1) MEDIA="hdd" ;;
esac
vpd_pg83="/sys/block/$device/device/vpd_pg83"
if [ -f "$vpd_pg83" ]; then
if grep -q --binary "iqn." "$vpd_pg83"; then
MEDIA="iscsi"
fi fi
if [ "$val" = "1" ]; then
MEDIA="hdd"
fi fi
else else
if [ -f "$VDEV_UPATH" ]; then if [ -f "$VDEV_UPATH" ]; then

View File

@ -11,7 +11,7 @@ fault_led: Show value of the disk enclosure slot fault LED.
locate_led: Show value of the disk enclosure slot locate LED. locate_led: Show value of the disk enclosure slot locate LED.
ses: Show disk's enc, enc device, slot, and fault/locate LED values." ses: Show disk's enc, enc device, slot, and fault/locate LED values."
script="${0##*/}" script=$(basename "$0")
if [ "$1" = "-h" ] ; then if [ "$1" = "-h" ] ; then
echo "$helpstr" | grep "$script:" | tr -s '\t' | cut -f 2- echo "$helpstr" | grep "$script:" | tr -s '\t' | cut -f 2-
exit exit
@ -32,30 +32,16 @@ for i in $scripts ; do
val="" val=""
case $i in case $i in
enc) enc)
if echo "$VDEV_ENC_SYSFS_PATH" | grep -q '/sys/bus/pci/slots' ; then val=$(ls "$VDEV_ENC_SYSFS_PATH/../../" 2>/dev/null)
val="$VDEV_ENC_SYSFS_PATH"
else
val="$(ls """$VDEV_ENC_SYSFS_PATH/../../""" 2>/dev/null)"
fi
;; ;;
slot) slot)
if echo "$VDEV_ENC_SYSFS_PATH" | grep -q '/sys/bus/pci/slots' ; then val=$(cat "$VDEV_ENC_SYSFS_PATH/slot" 2>/dev/null)
val="$(basename """$VDEV_ENC_SYSFS_PATH""")"
else
val="$(cat """$VDEV_ENC_SYSFS_PATH/slot""" 2>/dev/null)"
fi
;; ;;
encdev) encdev)
val=$(ls "$VDEV_ENC_SYSFS_PATH/../device/scsi_generic" 2>/dev/null) val=$(ls "$VDEV_ENC_SYSFS_PATH/../device/scsi_generic" 2>/dev/null)
;; ;;
fault_led) fault_led)
# JBODs fault LED is called 'fault', NVMe fault LED is called
# 'attention'.
if [ -f "$VDEV_ENC_SYSFS_PATH/fault" ] ; then
val=$(cat "$VDEV_ENC_SYSFS_PATH/fault" 2>/dev/null) val=$(cat "$VDEV_ENC_SYSFS_PATH/fault" 2>/dev/null)
elif [ -f "$VDEV_ENC_SYSFS_PATH/attention" ] ; then
val=$(cat "$VDEV_ENC_SYSFS_PATH/attention" 2>/dev/null)
fi
;; ;;
locate_led) locate_led)
val=$(cat "$VDEV_ENC_SYSFS_PATH/locate" 2>/dev/null) val=$(cat "$VDEV_ENC_SYSFS_PATH/locate" 2>/dev/null)

View File

@ -53,7 +53,7 @@ get_filename_from_dir()
num_files=$(find "$dir" -maxdepth 1 -type f | wc -l) num_files=$(find "$dir" -maxdepth 1 -type f | wc -l)
mod=$((pid % num_files)) mod=$((pid % num_files))
i=0 i=0
find "$dir" -type f -printf '%f\n' | while read -r file ; do find "$dir" -type f -printf "%f\n" | while read -r file ; do
if [ "$mod" = "$i" ] ; then if [ "$mod" = "$i" ] ; then
echo "$file" echo "$file"
break break
@ -62,14 +62,17 @@ get_filename_from_dir()
done done
} }
script="${0##*/}" script=$(basename "$0")
if [ "$1" = "-h" ] ; then if [ "$1" = "-h" ] ; then
echo "$helpstr" | grep "$script:" | tr -s '\t' | cut -f 2- echo "$helpstr" | grep "$script:" | tr -s '\t' | cut -f 2-
exit exit
fi fi
if [ -b "$VDEV_UPATH" ] && PATH="/usr/sbin:$PATH" command -v smartctl > /dev/null || [ -n "$samples" ] ; then smartctl_path=$(command -v smartctl)
# shellcheck disable=SC2015
if [ -b "$VDEV_UPATH" ] && [ -x "$smartctl_path" ] || [ -n "$samples" ] ; then
if [ -n "$samples" ] ; then if [ -n "$samples" ] ; then
# cat a smartctl output text file instead of running smartctl # cat a smartctl output text file instead of running smartctl
# on a vdev (only used for developer testing). # on a vdev (only used for developer testing).
@ -77,7 +80,7 @@ if [ -b "$VDEV_UPATH" ] && PATH="/usr/sbin:$PATH" command -v smartctl > /dev/nul
echo "file=$file" echo "file=$file"
raw_out=$(cat "$samples/$file") raw_out=$(cat "$samples/$file")
else else
raw_out=$(sudo smartctl -a "$VDEV_UPATH") raw_out=$(eval "sudo $smartctl_path -a $VDEV_UPATH")
fi fi
# What kind of drive are we? Look for the right line in smartctl: # What kind of drive are we? Look for the right line in smartctl:
@ -228,11 +231,11 @@ esac
with_vals=$(echo "$out" | grep -E "$scripts") with_vals=$(echo "$out" | grep -E "$scripts")
if [ -n "$with_vals" ]; then if [ -n "$with_vals" ]; then
echo "$with_vals" echo "$with_vals"
without_vals=$(echo "$scripts" | tr '|' '\n' | without_vals=$(echo "$scripts" | tr "|" "\n" |
grep -v -E "$(echo "$with_vals" | grep -v -E "$(echo "$with_vals" |
awk -F "=" '{print $1}')" | awk '{print $0"="}') awk -F "=" '{print $1}')" | awk '{print $0"="}')
else else
without_vals=$(echo "$scripts" | tr '|' '\n' | awk '{print $0"="}') without_vals=$(echo "$scripts" | tr "|" "\n" | awk '{print $0"="}')
fi fi
if [ -n "$without_vals" ]; then if [ -n "$without_vals" ]; then

View File

@ -264,6 +264,51 @@ for_each_pool(int argc, char **argv, boolean_t unavail,
return (ret); return (ret);
} }
static int
for_each_vdev_cb(zpool_handle_t *zhp, nvlist_t *nv, pool_vdev_iter_f func,
void *data)
{
nvlist_t **child;
uint_t c, children;
int ret = 0;
int i;
char *type;
const char *list[] = {
ZPOOL_CONFIG_SPARES,
ZPOOL_CONFIG_L2CACHE,
ZPOOL_CONFIG_CHILDREN
};
for (i = 0; i < ARRAY_SIZE(list); i++) {
if (nvlist_lookup_nvlist_array(nv, list[i], &child,
&children) == 0) {
for (c = 0; c < children; c++) {
uint64_t ishole = 0;
(void) nvlist_lookup_uint64(child[c],
ZPOOL_CONFIG_IS_HOLE, &ishole);
if (ishole)
continue;
ret |= for_each_vdev_cb(zhp, child[c], func,
data);
}
}
}
if (nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) != 0)
return (ret);
/* Don't run our function on root vdevs */
if (strcmp(type, VDEV_TYPE_ROOT) != 0) {
ret |= func(zhp, nv, data);
}
return (ret);
}
/* /*
* This is the equivalent of for_each_pool() for vdevs. It iterates thorough * This is the equivalent of for_each_pool() for vdevs. It iterates thorough
* all vdevs in the pool, ignoring root vdevs and holes, calling func() on * all vdevs in the pool, ignoring root vdevs and holes, calling func() on
@ -282,7 +327,7 @@ for_each_vdev(zpool_handle_t *zhp, pool_vdev_iter_f func, void *data)
verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
&nvroot) == 0); &nvroot) == 0);
} }
return (for_each_vdev_cb((void *) zhp, nvroot, func, data)); return (for_each_vdev_cb(zhp, nvroot, func, data));
} }
/* /*
@ -439,23 +484,33 @@ static void
vdev_run_cmd(vdev_cmd_data_t *data, char *cmd) vdev_run_cmd(vdev_cmd_data_t *data, char *cmd)
{ {
int rc; int rc;
char *argv[2] = {cmd}; char *argv[2] = {cmd, 0};
char **env; char *env[5] = {"PATH=/bin:/sbin:/usr/bin:/usr/sbin", NULL, NULL, NULL,
NULL};
char **lines = NULL; char **lines = NULL;
int lines_cnt = 0; int lines_cnt = 0;
int i; int i;
env = zpool_vdev_script_alloc_env(data->pool, data->path, data->upath, /* Setup our custom environment variables */
data->vdev_enc_sysfs_path, NULL, NULL); rc = asprintf(&env[1], "VDEV_PATH=%s",
if (env == NULL) data->path ? data->path : "");
if (rc == -1)
goto out;
rc = asprintf(&env[2], "VDEV_UPATH=%s",
data->upath ? data->upath : "");
if (rc == -1)
goto out;
rc = asprintf(&env[3], "VDEV_ENC_SYSFS_PATH=%s",
data->vdev_enc_sysfs_path ?
data->vdev_enc_sysfs_path : "");
if (rc == -1)
goto out; goto out;
/* Run the command */ /* Run the command */
rc = libzfs_run_process_get_stdout_nopath(cmd, argv, env, &lines, rc = libzfs_run_process_get_stdout_nopath(cmd, argv, env, &lines,
&lines_cnt); &lines_cnt);
zpool_vdev_script_free_env(env);
if (rc != 0) if (rc != 0)
goto out; goto out;
@ -467,6 +522,11 @@ vdev_run_cmd(vdev_cmd_data_t *data, char *cmd)
out: out:
if (lines != NULL) if (lines != NULL)
libzfs_free_str_array(lines, lines_cnt); libzfs_free_str_array(lines, lines_cnt);
/* Start with i = 1 since env[0] was statically allocated */
for (i = 1; i < ARRAY_SIZE(env); i++)
if (env[i] != NULL)
free(env[i]);
} }
/* /*
@ -538,7 +598,7 @@ vdev_run_cmd_thread(void *cb_cmd_data)
/* For each vdev in the pool run a command */ /* For each vdev in the pool run a command */
static int static int
for_each_vdev_run_cb(void *zhp_data, nvlist_t *nv, void *cb_vcdl) for_each_vdev_run_cb(zpool_handle_t *zhp, nvlist_t *nv, void *cb_vcdl)
{ {
vdev_cmd_data_list_t *vcdl = cb_vcdl; vdev_cmd_data_list_t *vcdl = cb_vcdl;
vdev_cmd_data_t *data; vdev_cmd_data_t *data;
@ -546,15 +606,10 @@ for_each_vdev_run_cb(void *zhp_data, nvlist_t *nv, void *cb_vcdl)
char *vname = NULL; char *vname = NULL;
char *vdev_enc_sysfs_path = NULL; char *vdev_enc_sysfs_path = NULL;
int i, match = 0; int i, match = 0;
zpool_handle_t *zhp = zhp_data;
if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) != 0) if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) != 0)
return (1); return (1);
/* Make sure we're getting the updated enclosure sysfs path */
update_vdev_config_dev_sysfs_path(nv, path,
ZPOOL_CONFIG_VDEV_ENC_SYSFS_PATH);
nvlist_lookup_string(nv, ZPOOL_CONFIG_VDEV_ENC_SYSFS_PATH, nvlist_lookup_string(nv, ZPOOL_CONFIG_VDEV_ENC_SYSFS_PATH,
&vdev_enc_sysfs_path); &vdev_enc_sysfs_path);

File diff suppressed because it is too large Load Diff

View File

@ -27,7 +27,6 @@
#include <libnvpair.h> #include <libnvpair.h>
#include <libzfs.h> #include <libzfs.h>
#include <libzutil.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -68,6 +67,7 @@ int for_each_pool(int, char **, boolean_t unavail, zprop_list_t **,
boolean_t, zpool_iter_f, void *); boolean_t, zpool_iter_f, void *);
/* Vdev list functions */ /* Vdev list functions */
typedef int (*pool_vdev_iter_f)(zpool_handle_t *, nvlist_t *, void *);
int for_each_vdev(zpool_handle_t *zhp, pool_vdev_iter_f func, void *data); int for_each_vdev(zpool_handle_t *zhp, pool_vdev_iter_f func, void *data);
typedef struct zpool_list zpool_list_t; typedef struct zpool_list zpool_list_t;
@ -124,19 +124,11 @@ vdev_cmd_data_list_t *all_pools_for_each_vdev_run(int argc, char **argv,
void free_vdev_cmd_data_list(vdev_cmd_data_list_t *vcdl); void free_vdev_cmd_data_list(vdev_cmd_data_list_t *vcdl);
void free_vdev_cmd_data(vdev_cmd_data_t *data);
int vdev_run_cmd_simple(char *path, char *cmd);
int check_device(const char *path, boolean_t force, int check_device(const char *path, boolean_t force,
boolean_t isspare, boolean_t iswholedisk); boolean_t isspare, boolean_t iswholedisk);
boolean_t check_sector_size_database(char *path, int *sector_size); boolean_t check_sector_size_database(char *path, int *sector_size);
void vdev_error(const char *fmt, ...); void vdev_error(const char *fmt, ...);
int check_file(const char *file, boolean_t force, boolean_t isspare); int check_file(const char *file, boolean_t force, boolean_t isspare);
void after_zpool_upgrade(zpool_handle_t *zhp);
int zpool_power(zpool_handle_t *zhp, char *vdev, boolean_t turn_on);
int zpool_power_current_state(zpool_handle_t *zhp, char *vdev);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -373,10 +373,6 @@ make_leaf_vdev(nvlist_t *props, const char *arg, boolean_t is_primary)
verify(nvlist_add_string(vdev, ZPOOL_CONFIG_PATH, path) == 0); verify(nvlist_add_string(vdev, ZPOOL_CONFIG_PATH, path) == 0);
verify(nvlist_add_string(vdev, ZPOOL_CONFIG_TYPE, type) == 0); verify(nvlist_add_string(vdev, ZPOOL_CONFIG_TYPE, type) == 0);
/* Lookup and add the enclosure sysfs path (if exists) */
update_vdev_config_dev_sysfs_path(vdev, path,
ZPOOL_CONFIG_VDEV_ENC_SYSFS_PATH);
if (strcmp(type, VDEV_TYPE_DISK) == 0) if (strcmp(type, VDEV_TYPE_DISK) == 0)
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);
@ -449,7 +445,7 @@ typedef struct replication_level {
/* /*
* N.B. For the purposes of comparing replication levels dRAID can be * N.B. For the purposes of comparing replication levels dRAID can be
* considered functionally equivalent to raidz. * considered functionally equivilant to raidz.
*/ */
static boolean_t static boolean_t
is_raidz_mirror(replication_level_t *a, replication_level_t *b, is_raidz_mirror(replication_level_t *a, replication_level_t *b,
@ -925,15 +921,6 @@ zero_label(char *path)
return (0); return (0);
} }
static void
lines_to_stderr(char *lines[], int lines_cnt)
{
int i;
for (i = 0; i < lines_cnt; i++) {
fprintf(stderr, "%s\n", lines[i]);
}
}
/* /*
* Go through and find any whole disks in the vdev specification, labelling them * Go through and find any whole disks in the vdev specification, labelling them
* as appropriate. When constructing the vdev spec, we were unable to open this * as appropriate. When constructing the vdev spec, we were unable to open this
@ -945,7 +932,7 @@ lines_to_stderr(char *lines[], int lines_cnt)
* need to get the devid after we label the disk. * need to get the devid after we label the disk.
*/ */
static int static int
make_disks(zpool_handle_t *zhp, nvlist_t *nv, boolean_t replacing) make_disks(zpool_handle_t *zhp, nvlist_t *nv)
{ {
nvlist_t **child; nvlist_t **child;
uint_t c, children; uint_t c, children;
@ -1030,8 +1017,6 @@ make_disks(zpool_handle_t *zhp, nvlist_t *nv, boolean_t replacing)
*/ */
if (!is_exclusive && !is_spare(NULL, udevpath)) { if (!is_exclusive && !is_spare(NULL, udevpath)) {
char *devnode = strrchr(devpath, '/') + 1; char *devnode = strrchr(devpath, '/') + 1;
char **lines = NULL;
int lines_cnt = 0;
ret = strncmp(udevpath, UDISK_ROOT, strlen(UDISK_ROOT)); ret = strncmp(udevpath, UDISK_ROOT, strlen(UDISK_ROOT));
if (ret == 0) { if (ret == 0) {
@ -1043,27 +1028,9 @@ make_disks(zpool_handle_t *zhp, nvlist_t *nv, boolean_t replacing)
/* /*
* When labeling a pool the raw device node name * When labeling a pool the raw device node name
* is provided as it appears under /dev/. * is provided as it appears under /dev/.
*
* Note that 'zhp' will be NULL when we're creating a
* pool.
*/ */
if (zpool_prepare_and_label_disk(g_zfs, zhp, devnode, if (zpool_label_disk(g_zfs, zhp, devnode) == -1)
nv, zhp == NULL ? "create" :
replacing ? "replace" : "add", &lines,
&lines_cnt) != 0) {
(void) fprintf(stderr,
gettext(
"Error preparing/labeling disk.\n"));
if (lines_cnt > 0) {
(void) fprintf(stderr,
gettext("zfs_prepare_disk output:\n"));
lines_to_stderr(lines, lines_cnt);
}
libzfs_free_str_array(lines, lines_cnt);
return (-1); return (-1);
}
libzfs_free_str_array(lines, lines_cnt);
/* /*
* Wait for udev to signal the device is available * Wait for udev to signal the device is available
@ -1100,19 +1067,19 @@ make_disks(zpool_handle_t *zhp, nvlist_t *nv, boolean_t replacing)
} }
for (c = 0; c < children; c++) for (c = 0; c < children; c++)
if ((ret = make_disks(zhp, child[c], replacing)) != 0) if ((ret = make_disks(zhp, child[c])) != 0)
return (ret); return (ret);
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
&child, &children) == 0) &child, &children) == 0)
for (c = 0; c < children; c++) for (c = 0; c < children; c++)
if ((ret = make_disks(zhp, child[c], replacing)) != 0) if ((ret = make_disks(zhp, child[c])) != 0)
return (ret); return (ret);
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
&child, &children) == 0) &child, &children) == 0)
for (c = 0; c < children; c++) for (c = 0; c < children; c++)
if ((ret = make_disks(zhp, child[c], replacing)) != 0) if ((ret = make_disks(zhp, child[c])) != 0)
return (ret); return (ret);
return (0); return (0);
@ -1773,7 +1740,7 @@ split_mirror_vdev(zpool_handle_t *zhp, char *newname, nvlist_t *props,
return (NULL); return (NULL);
} }
if (!flags.dryrun && make_disks(zhp, newroot, B_FALSE) != 0) { if (!flags.dryrun && make_disks(zhp, newroot) != 0) {
nvlist_free(newroot); nvlist_free(newroot);
return (NULL); return (NULL);
} }
@ -1894,7 +1861,7 @@ make_root_vdev(zpool_handle_t *zhp, nvlist_t *props, int force, int check_rep,
/* /*
* Run through the vdev specification and label any whole disks found. * Run through the vdev specification and label any whole disks found.
*/ */
if (!dryrun && make_disks(zhp, newroot, replacing) != 0) { if (!dryrun && make_disks(zhp, newroot) != 0) {
nvlist_free(newroot); nvlist_free(newroot);
return (NULL); return (NULL);
} }

View File

@ -1360,7 +1360,7 @@
"type": "row" "type": "row"
}, },
{ {
"content": "I/O requests that are satisfied by accessing pool devices are managed by the ZIO scheduler.\nThe total latency is measured from the start of the I/O to completion by the disk.\nLatency through each queue is shown prior to its submission to the disk queue.\n\nThis view is useful for observing the effects of tuning the ZIO scheduler min and max values\n(see zfs(4) and [ZFS on Linux Module Parameters](https://openzfs.github.io/openzfs-docs/Performance%20and%20tuning/ZFS%20on%20Linux%20Module%20Parameters.html)):\n+ *zfs_vdev_max_active* controls the ZIO scheduler's disk queue depth (do not confuse with the block device's nr_requests)\n+ *zfs_vdev_sync_read_min_active* and *zfs_vdev_sync_read_max_active* control the synchronous queue for reads: most reads are sync\n+ *zfs_vdev_sync_write_min_active* and *zfs_vdev_sync_write_max_active* control the synchronous queue for writes: \nusually metadata or user data depending on the \"sync\" property setting or I/Os that are requested to be flushed\n+ *zfs_vdev_async_read_min_active* and *zfs_vdev_async_read_max_active* control the asynchronous queue for reads: usually prefetches\n+ *zfs_vdev_async_write_min_active* and *zfs_vdev_async_write_max_active* control the asynchronous queue for writes: \nusually the bulk of all writes at transaction group (txg) commit\n+ *zfs_vdev_scrub_min_active* and *zfs_vdev_scrub_max_active* controls the scan reads: usually scrub or resilver\n\n", "content": "I/O requests that are satisfied by accessing pool devices are managed by the ZIO scheduler.\nThe total latency is measured from the start of the I/O to completion by the disk.\nLatency through each queue is shown prior to its submission to the disk queue.\n\nThis view is useful for observing the effects of tuning the ZIO scheduler min and max values\n(see zfs-module-parameters(5) and [ZFS on Linux Module Parameters](https://openzfs.github.io/openzfs-docs/Performance%20and%20tuning/ZFS%20on%20Linux%20Module%20Parameters.html)):\n+ *zfs_vdev_max_active* controls the ZIO scheduler's disk queue depth (do not confuse with the block device's nr_requests)\n+ *zfs_vdev_sync_read_min_active* and *zfs_vdev_sync_read_max_active* control the synchronous queue for reads: most reads are sync\n+ *zfs_vdev_sync_write_min_active* and *zfs_vdev_sync_write_max_active* control the synchronous queue for writes: \nusually metadata or user data depending on the \"sync\" property setting or I/Os that are requested to be flushed\n+ *zfs_vdev_async_read_min_active* and *zfs_vdev_async_read_max_active* control the asynchronous queue for reads: usually prefetches\n+ *zfs_vdev_async_write_min_active* and *zfs_vdev_async_write_max_active* control the asynchronous queue for writes: \nusually the bulk of all writes at transaction group (txg) commit\n+ *zfs_vdev_scrub_min_active* and *zfs_vdev_scrub_max_active* controls the scan reads: usually scrub or resilver\n\n",
"datasource": "${DS_MACBOOK-INFLUX}", "datasource": "${DS_MACBOOK-INFLUX}",
"fieldConfig": { "fieldConfig": {
"defaults": { "defaults": {

View File

@ -117,7 +117,6 @@ escape_string(char *s)
case '=': case '=':
case '\\': case '\\':
*d++ = '\\'; *d++ = '\\';
fallthrough;
default: default:
*d = *c; *d = *c;
} }
@ -684,8 +683,9 @@ print_recursive_stats(stat_printer_f func, nvlist_t *nvroot,
if (descend && nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, if (descend && nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
&child, &children) == 0) { &child, &children) == 0) {
(void) strlcpy(vdev_name, get_vdev_name(nvroot, parent_name), (void) strncpy(vdev_name, get_vdev_name(nvroot, parent_name),
sizeof (vdev_name)); sizeof (vdev_name));
vdev_name[sizeof (vdev_name) - 1] = '\0';
for (c = 0; c < children; c++) { for (c = 0; c < children; c++) {
print_recursive_stats(func, child[c], pool_name, print_recursive_stats(func, child[c], pool_name,

View File

@ -15,6 +15,3 @@ zstream_LDADD = \
$(abs_top_builddir)/lib/libnvpair/libnvpair.la $(abs_top_builddir)/lib/libnvpair/libnvpair.la
include $(top_srcdir)/config/CppCheck.am include $(top_srcdir)/config/CppCheck.am
install-exec-hook:
cd $(DESTDIR)$(sbindir) && $(LN_S) -f zstream zstreamdump

View File

@ -49,11 +49,6 @@ zstream_usage(void)
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
char *basename = strrchr(argv[0], '/');
basename = basename ? (basename + 1) : argv[0];
if (argc >= 1 && strcmp(basename, "zstreamdump") == 0)
return (zstream_do_dump(argc, argv));
if (argc < 2) if (argc < 2)
zstream_usage(); zstream_usage();

View File

@ -297,7 +297,6 @@ zstream_do_dump(int argc, char *argv[])
fletcher_4_init(); fletcher_4_init();
while (read_hdr(drr, &zc)) { while (read_hdr(drr, &zc)) {
uint64_t featureflags = 0;
/* /*
* If this is the first DMU record being processed, check for * If this is the first DMU record being processed, check for
@ -462,18 +461,6 @@ zstream_do_dump(int argc, char *argv[])
BSWAP_64(drro->drr_maxblkid); BSWAP_64(drro->drr_maxblkid);
} }
featureflags =
DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo);
if (featureflags & DMU_BACKUP_FEATURE_RAW &&
drro->drr_bonuslen > drro->drr_raw_bonuslen) {
(void) fprintf(stderr,
"Warning: Object %llu has bonuslen = "
"%u > raw_bonuslen = %u\n\n",
(u_longlong_t)drro->drr_object,
drro->drr_bonuslen, drro->drr_raw_bonuslen);
}
payload_size = DRR_OBJECT_PAYLOAD_SIZE(drro); payload_size = DRR_OBJECT_PAYLOAD_SIZE(drro);
if (verbose) { if (verbose) {

View File

@ -0,0 +1 @@
dist_sbin_SCRIPTS = zstreamdump

3
cmd/zstreamdump/zstreamdump Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
zstream dump "$@"

View File

@ -124,7 +124,6 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <getopt.h>
#include <signal.h> #include <signal.h>
#include <umem.h> #include <umem.h>
#include <ctype.h> #include <ctype.h>
@ -193,58 +192,30 @@ typedef struct ztest_shared_opts {
char zo_gvars[ZO_GVARS_MAX_COUNT][ZO_GVARS_MAX_ARGLEN]; char zo_gvars[ZO_GVARS_MAX_COUNT][ZO_GVARS_MAX_ARGLEN];
} ztest_shared_opts_t; } ztest_shared_opts_t;
/* Default values for command line options. */
#define DEFAULT_POOL "ztest"
#define DEFAULT_VDEV_DIR "/tmp"
#define DEFAULT_VDEV_COUNT 5
#define DEFAULT_VDEV_SIZE (SPA_MINDEVSIZE * 4) /* 256m default size */
#define DEFAULT_VDEV_SIZE_STR "256M"
#define DEFAULT_ASHIFT SPA_MINBLOCKSHIFT
#define DEFAULT_MIRRORS 2
#define DEFAULT_RAID_CHILDREN 4
#define DEFAULT_RAID_PARITY 1
#define DEFAULT_DRAID_DATA 4
#define DEFAULT_DRAID_SPARES 1
#define DEFAULT_DATASETS_COUNT 7
#define DEFAULT_THREADS 23
#define DEFAULT_RUN_TIME 300 /* 300 seconds */
#define DEFAULT_RUN_TIME_STR "300 sec"
#define DEFAULT_PASS_TIME 60 /* 60 seconds */
#define DEFAULT_PASS_TIME_STR "60 sec"
#define DEFAULT_KILL_RATE 70 /* 70% kill rate */
#define DEFAULT_KILLRATE_STR "70%"
#define DEFAULT_INITS 1
#define DEFAULT_MAX_LOOPS 50 /* 5 minutes */
#define DEFAULT_FORCE_GANGING (64 << 10)
#define DEFAULT_FORCE_GANGING_STR "64K"
/* Simplifying assumption: -1 is not a valid default. */
#define NO_DEFAULT -1
static const ztest_shared_opts_t ztest_opts_defaults = { static const ztest_shared_opts_t ztest_opts_defaults = {
.zo_pool = DEFAULT_POOL, .zo_pool = "ztest",
.zo_dir = DEFAULT_VDEV_DIR, .zo_dir = "/tmp",
.zo_alt_ztest = { '\0' }, .zo_alt_ztest = { '\0' },
.zo_alt_libpath = { '\0' }, .zo_alt_libpath = { '\0' },
.zo_vdevs = DEFAULT_VDEV_COUNT, .zo_vdevs = 5,
.zo_ashift = DEFAULT_ASHIFT, .zo_ashift = SPA_MINBLOCKSHIFT,
.zo_mirrors = DEFAULT_MIRRORS, .zo_mirrors = 2,
.zo_raid_children = DEFAULT_RAID_CHILDREN, .zo_raid_children = 4,
.zo_raid_parity = DEFAULT_RAID_PARITY, .zo_raid_parity = 1,
.zo_raid_type = VDEV_TYPE_RAIDZ, .zo_raid_type = VDEV_TYPE_RAIDZ,
.zo_vdev_size = DEFAULT_VDEV_SIZE, .zo_vdev_size = SPA_MINDEVSIZE * 4, /* 256m default size */
.zo_draid_data = DEFAULT_DRAID_DATA, /* data drives */ .zo_draid_data = 4, /* data drives */
.zo_draid_spares = DEFAULT_DRAID_SPARES, /* distributed spares */ .zo_draid_spares = 1, /* distributed spares */
.zo_datasets = DEFAULT_DATASETS_COUNT, .zo_datasets = 7,
.zo_threads = DEFAULT_THREADS, .zo_threads = 23,
.zo_passtime = DEFAULT_PASS_TIME, .zo_passtime = 60, /* 60 seconds */
.zo_killrate = DEFAULT_KILL_RATE, .zo_killrate = 70, /* 70% kill rate */
.zo_verbose = 0, .zo_verbose = 0,
.zo_mmp_test = 0, .zo_mmp_test = 0,
.zo_init = DEFAULT_INITS, .zo_init = 1,
.zo_time = DEFAULT_RUN_TIME, .zo_time = 300, /* 5 minutes */
.zo_maxloops = DEFAULT_MAX_LOOPS, /* max loops during spa_freeze() */ .zo_maxloops = 50, /* max loops during spa_freeze() */
.zo_metaslab_force_ganging = DEFAULT_FORCE_GANGING, .zo_metaslab_force_ganging = 64 << 10,
.zo_special_vdevs = ZTEST_VDEV_CLASS_RND, .zo_special_vdevs = ZTEST_VDEV_CLASS_RND,
.zo_gvars_count = 0, .zo_gvars_count = 0,
}; };
@ -713,154 +684,68 @@ nicenumtoull(const char *buf)
return (val); return (val);
} }
typedef struct ztest_option {
const char short_opt;
const char *long_opt;
const char *long_opt_param;
const char *comment;
unsigned int default_int;
char *default_str;
} ztest_option_t;
/*
* The following option_table is used for generating the usage info as well as
* the long and short option information for calling getopt_long().
*/
static ztest_option_t option_table[] = {
{ 'v', "vdevs", "INTEGER", "Number of vdevs", DEFAULT_VDEV_COUNT,
NULL},
{ 's', "vdev-size", "INTEGER", "Size of each vdev",
NO_DEFAULT, DEFAULT_VDEV_SIZE_STR},
{ 'a', "alignment-shift", "INTEGER",
"Alignment shift; use 0 for random", DEFAULT_ASHIFT, NULL},
{ 'm', "mirror-copies", "INTEGER", "Number of mirror copies",
DEFAULT_MIRRORS, NULL},
{ 'r', "raid-disks", "INTEGER", "Number of raidz/draid disks",
DEFAULT_RAID_CHILDREN, NULL},
{ 'R', "raid-parity", "INTEGER", "Raid parity",
DEFAULT_RAID_PARITY, NULL},
{ 'K', "raid-kind", "raidz|draid|random", "Raid kind",
NO_DEFAULT, "random"},
{ 'D', "draid-data", "INTEGER", "Number of draid data drives",
DEFAULT_DRAID_DATA, NULL},
{ 'S', "draid-spares", "INTEGER", "Number of draid spares",
DEFAULT_DRAID_SPARES, NULL},
{ 'd', "datasets", "INTEGER", "Number of datasets",
DEFAULT_DATASETS_COUNT, NULL},
{ 't', "threads", "INTEGER", "Number of ztest threads",
DEFAULT_THREADS, NULL},
{ 'g', "gang-block-threshold", "INTEGER",
"Metaslab gang block threshold",
NO_DEFAULT, DEFAULT_FORCE_GANGING_STR},
{ 'i', "init-count", "INTEGER", "Number of times to initialize pool",
DEFAULT_INITS, NULL},
{ 'k', "kill-percentage", "INTEGER", "Kill percentage",
NO_DEFAULT, DEFAULT_KILLRATE_STR},
{ 'p', "pool-name", "STRING", "Pool name",
NO_DEFAULT, DEFAULT_POOL},
{ 'f', "vdev-file-directory", "PATH", "File directory for vdev files",
NO_DEFAULT, DEFAULT_VDEV_DIR},
{ 'M', "multi-host", NULL,
"Multi-host; simulate pool imported on remote host",
NO_DEFAULT, NULL},
{ 'E', "use-existing-pool", NULL,
"Use existing pool instead of creating new one", NO_DEFAULT, NULL},
{ 'T', "run-time", "INTEGER", "Total run time",
NO_DEFAULT, DEFAULT_RUN_TIME_STR},
{ 'P', "pass-time", "INTEGER", "Time per pass",
NO_DEFAULT, DEFAULT_PASS_TIME_STR},
{ 'F', "freeze-loops", "INTEGER", "Max loops in spa_freeze()",
DEFAULT_MAX_LOOPS, NULL},
{ 'B', "alt-ztest", "PATH", "Alternate ztest path",
NO_DEFAULT, NULL},
{ 'C', "vdev-class-state", "on|off|random", "vdev class state",
NO_DEFAULT, "random"},
{ 'o', "option", "\"OPTION=INTEGER\"",
"Set global variable to an unsigned 32-bit integer value",
NO_DEFAULT, NULL},
{ 'G', "dump-debug-msg", NULL,
"Dump zfs_dbgmsg buffer before exiting due to an error",
NO_DEFAULT, NULL},
{ 'V', "verbose", NULL,
"Verbose (use multiple times for ever more verbosity)",
NO_DEFAULT, NULL},
{ 'h', "help", NULL, "Show this help",
NO_DEFAULT, NULL},
{0, 0, 0, 0, 0, 0}
};
static struct option *long_opts = NULL;
static char *short_opts = NULL;
static void
init_options(void)
{
ASSERT3P(long_opts, ==, NULL);
ASSERT3P(short_opts, ==, NULL);
int count = sizeof (option_table) / sizeof (option_table[0]);
long_opts = umem_alloc(sizeof (struct option) * count, UMEM_NOFAIL);
short_opts = umem_alloc(sizeof (char) * 2 * count, UMEM_NOFAIL);
int short_opt_index = 0;
for (int i = 0; i < count; i++) {
long_opts[i].val = option_table[i].short_opt;
long_opts[i].name = option_table[i].long_opt;
long_opts[i].has_arg = option_table[i].long_opt_param != NULL
? required_argument : no_argument;
long_opts[i].flag = NULL;
short_opts[short_opt_index++] = option_table[i].short_opt;
if (option_table[i].long_opt_param != NULL) {
short_opts[short_opt_index++] = ':';
}
}
}
static void
fini_options(void)
{
int count = sizeof (option_table) / sizeof (option_table[0]);
umem_free(long_opts, sizeof (struct option) * count);
umem_free(short_opts, sizeof (char) * 2 * count);
long_opts = NULL;
short_opts = NULL;
}
static void static void
usage(boolean_t requested) usage(boolean_t requested)
{ {
char option[80]; const ztest_shared_opts_t *zo = &ztest_opts_defaults;
char nice_vdev_size[NN_NUMBUF_SZ];
char nice_force_ganging[NN_NUMBUF_SZ];
FILE *fp = requested ? stdout : stderr; FILE *fp = requested ? stdout : stderr;
(void) fprintf(fp, "Usage: %s [OPTIONS...]\n", DEFAULT_POOL); nicenum(zo->zo_vdev_size, nice_vdev_size, sizeof (nice_vdev_size));
for (int i = 0; option_table[i].short_opt != 0; i++) { nicenum(zo->zo_metaslab_force_ganging, nice_force_ganging,
if (option_table[i].long_opt_param != NULL) { sizeof (nice_force_ganging));
(void) sprintf(option, " -%c --%s=%s",
option_table[i].short_opt,
option_table[i].long_opt,
option_table[i].long_opt_param);
} else {
(void) sprintf(option, " -%c --%s",
option_table[i].short_opt,
option_table[i].long_opt);
}
(void) fprintf(fp, " %-40s%s", option,
option_table[i].comment);
if (option_table[i].long_opt_param != NULL) { (void) fprintf(fp, "Usage: %s\n"
if (option_table[i].default_str != NULL) { "\t[-v vdevs (default: %llu)]\n"
(void) fprintf(fp, " (default: %s)", "\t[-s size_of_each_vdev (default: %s)]\n"
option_table[i].default_str); "\t[-a alignment_shift (default: %d)] use 0 for random\n"
} else if (option_table[i].default_int != NO_DEFAULT) { "\t[-m mirror_copies (default: %d)]\n"
(void) fprintf(fp, " (default: %u)", "\t[-r raidz_disks / draid_disks (default: %d)]\n"
option_table[i].default_int); "\t[-R raid_parity (default: %d)]\n"
} "\t[-K raid_kind (default: random)] raidz|draid|random\n"
} "\t[-D draid_data (default: %d)] in config\n"
(void) fprintf(fp, "\n"); "\t[-S draid_spares (default: %d)]\n"
} "\t[-d datasets (default: %d)]\n"
"\t[-t threads (default: %d)]\n"
"\t[-g gang_block_threshold (default: %s)]\n"
"\t[-i init_count (default: %d)] initialize pool i times\n"
"\t[-k kill_percentage (default: %llu%%)]\n"
"\t[-p pool_name (default: %s)]\n"
"\t[-f dir (default: %s)] file directory for vdev files\n"
"\t[-M] Multi-host simulate pool imported on remote host\n"
"\t[-V] verbose (use multiple times for ever more blather)\n"
"\t[-E] use existing pool instead of creating new one\n"
"\t[-T time (default: %llu sec)] total run time\n"
"\t[-F freezeloops (default: %llu)] max loops in spa_freeze()\n"
"\t[-P passtime (default: %llu sec)] time per pass\n"
"\t[-B alt_ztest (default: <none>)] alternate ztest path\n"
"\t[-C vdev class state (default: random)] special=on|off|random\n"
"\t[-o variable=value] ... set global variable to an unsigned\n"
"\t 32-bit integer value\n"
"\t[-G dump zfs_dbgmsg buffer before exiting due to an error\n"
"\t[-h] (print help)\n"
"",
zo->zo_pool,
(u_longlong_t)zo->zo_vdevs, /* -v */
nice_vdev_size, /* -s */
zo->zo_ashift, /* -a */
zo->zo_mirrors, /* -m */
zo->zo_raid_children, /* -r */
zo->zo_raid_parity, /* -R */
zo->zo_draid_data, /* -D */
zo->zo_draid_spares, /* -S */
zo->zo_datasets, /* -d */
zo->zo_threads, /* -t */
nice_force_ganging, /* -g */
zo->zo_init, /* -i */
(u_longlong_t)zo->zo_killrate, /* -k */
zo->zo_pool, /* -p */
zo->zo_dir, /* -f */
(u_longlong_t)zo->zo_time, /* -T */
(u_longlong_t)zo->zo_maxloops, /* -F */
(u_longlong_t)zo->zo_passtime);
exit(requested ? 0 : 1); exit(requested ? 0 : 1);
} }
@ -932,10 +817,8 @@ process_options(int argc, char **argv)
bcopy(&ztest_opts_defaults, zo, sizeof (*zo)); bcopy(&ztest_opts_defaults, zo, sizeof (*zo));
init_options(); while ((opt = getopt(argc, argv,
"v:s:a:m:r:R:K:D:S:d:t:g:i:k:p:f:MVET:P:hF:B:C:o:G")) != EOF) {
while ((opt = getopt_long(argc, argv, short_opts, long_opts,
NULL)) != EOF) {
value = 0; value = 0;
switch (opt) { switch (opt) {
case 'v': case 'v':
@ -1070,8 +953,6 @@ process_options(int argc, char **argv)
} }
} }
fini_options();
/* When raid choice is 'random' add a draid pool 50% of the time */ /* When raid choice is 'random' add a draid pool 50% of the time */
if (strcmp(raid_kind, "random") == 0) { if (strcmp(raid_kind, "random") == 0) {
(void) strlcpy(raid_kind, (ztest_random(2) == 0) ? (void) strlcpy(raid_kind, (ztest_random(2) == 0) ?
@ -1184,7 +1065,7 @@ ztest_kill(ztest_shared_t *zs)
* See comment above spa_write_cachefile(). * See comment above spa_write_cachefile().
*/ */
mutex_enter(&spa_namespace_lock); mutex_enter(&spa_namespace_lock);
spa_write_cachefile(ztest_spa, B_FALSE, B_FALSE, B_FALSE); spa_write_cachefile(ztest_spa, B_FALSE, B_FALSE);
mutex_exit(&spa_namespace_lock); mutex_exit(&spa_namespace_lock);
(void) kill(getpid(), SIGKILL); (void) kill(getpid(), SIGKILL);
@ -2193,7 +2074,6 @@ ztest_replay_write(void *arg1, void *arg2, boolean_t byteswap)
* but not always, because we also want to verify correct * but not always, because we also want to verify correct
* behavior when the data was not recently read into cache. * behavior when the data was not recently read into cache.
*/ */
ASSERT(doi.doi_data_block_size);
ASSERT0(offset % doi.doi_data_block_size); ASSERT0(offset % doi.doi_data_block_size);
if (ztest_random(4) != 0) { if (ztest_random(4) != 0) {
int prefetch = ztest_random(2) ? int prefetch = ztest_random(2) ?
@ -6099,7 +5979,7 @@ ztest_fault_inject(ztest_ds_t *zd, uint64_t id)
vd0->vdev_resilver_txg != 0)) { vd0->vdev_resilver_txg != 0)) {
/* /*
* Make vd0 explicitly claim to be unreadable, * Make vd0 explicitly claim to be unreadable,
* or unwritable, or reach behind its back * or unwriteable, or reach behind its back
* and close the underlying fd. We can do this if * and close the underlying fd. We can do this if
* maxfaults == 0 because we'll fail and reexecute, * maxfaults == 0 because we'll fail and reexecute,
* and we can do it if maxfaults >= 2 because we'll * and we can do it if maxfaults >= 2 because we'll
@ -6670,7 +6550,7 @@ ztest_initialize(ztest_ds_t *zd, uint64_t id)
char *path = strdup(rand_vd->vdev_path); char *path = strdup(rand_vd->vdev_path);
boolean_t active = rand_vd->vdev_initialize_thread != NULL; boolean_t active = rand_vd->vdev_initialize_thread != NULL;
zfs_dbgmsg("vd %px, guid %llu", rand_vd, (u_longlong_t)guid); zfs_dbgmsg("vd %px, guid %llu", rand_vd, guid);
spa_config_exit(spa, SCL_VDEV, FTAG); spa_config_exit(spa, SCL_VDEV, FTAG);
uint64_t cmd = ztest_random(POOL_INITIALIZE_FUNCS); uint64_t cmd = ztest_random(POOL_INITIALIZE_FUNCS);
@ -6742,7 +6622,7 @@ ztest_trim(ztest_ds_t *zd, uint64_t id)
char *path = strdup(rand_vd->vdev_path); char *path = strdup(rand_vd->vdev_path);
boolean_t active = rand_vd->vdev_trim_thread != NULL; boolean_t active = rand_vd->vdev_trim_thread != NULL;
zfs_dbgmsg("vd %p, guid %llu", rand_vd, (u_longlong_t)guid); zfs_dbgmsg("vd %p, guid %llu", rand_vd, guid);
spa_config_exit(spa, SCL_VDEV, FTAG); spa_config_exit(spa, SCL_VDEV, FTAG);
uint64_t cmd = ztest_random(POOL_TRIM_FUNCS); uint64_t cmd = ztest_random(POOL_TRIM_FUNCS);

View File

@ -38,39 +38,40 @@
static int static int
ioctl_get_msg(char *var, int fd) ioctl_get_msg(char *var, int fd)
{ {
int ret; int error = 0;
char msg[ZFS_MAX_DATASET_NAME_LEN]; char msg[ZFS_MAX_DATASET_NAME_LEN];
ret = ioctl(fd, BLKZNAME, msg); error = ioctl(fd, BLKZNAME, msg);
if (ret < 0) { if (error < 0) {
return (ret); return (error);
} }
snprintf(var, ZFS_MAX_DATASET_NAME_LEN, "%s", msg); snprintf(var, ZFS_MAX_DATASET_NAME_LEN, "%s", msg);
return (ret); return (error);
} }
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
int fd = -1, ret = 0, status = EXIT_FAILURE; int fd, error = 0;
char zvol_name[ZFS_MAX_DATASET_NAME_LEN]; char zvol_name[ZFS_MAX_DATASET_NAME_LEN];
char *zvol_name_part = NULL; char *zvol_name_part = NULL;
char *dev_name; char *dev_name;
struct stat64 statbuf; struct stat64 statbuf;
int dev_minor, dev_part; int dev_minor, dev_part;
int i; int i;
int rc;
if (argc < 2) { if (argc < 2) {
fprintf(stderr, "Usage: %s /dev/zvol_device_node\n", argv[0]); printf("Usage: %s /dev/zvol_device_node\n", argv[0]);
goto fail; return (EINVAL);
} }
dev_name = argv[1]; dev_name = argv[1];
ret = stat64(dev_name, &statbuf); error = stat64(dev_name, &statbuf);
if (ret != 0) { if (error != 0) {
fprintf(stderr, "Unable to access device file: %s\n", dev_name); printf("Unable to access device file: %s\n", dev_name);
goto fail; return (errno);
} }
dev_minor = minor(statbuf.st_rdev); dev_minor = minor(statbuf.st_rdev);
@ -78,23 +79,23 @@ main(int argc, char **argv)
fd = open(dev_name, O_RDONLY); fd = open(dev_name, O_RDONLY);
if (fd < 0) { if (fd < 0) {
fprintf(stderr, "Unable to open device file: %s\n", dev_name); printf("Unable to open device file: %s\n", dev_name);
goto fail; return (errno);
} }
ret = ioctl_get_msg(zvol_name, fd); error = ioctl_get_msg(zvol_name, fd);
if (ret < 0) { if (error < 0) {
fprintf(stderr, "ioctl_get_msg failed: %s\n", strerror(errno)); printf("ioctl_get_msg failed:%s\n", strerror(errno));
goto fail; return (errno);
} }
if (dev_part > 0) if (dev_part > 0)
ret = asprintf(&zvol_name_part, "%s-part%d", zvol_name, rc = asprintf(&zvol_name_part, "%s-part%d", zvol_name,
dev_part); dev_part);
else else
ret = asprintf(&zvol_name_part, "%s", zvol_name); rc = asprintf(&zvol_name_part, "%s", zvol_name);
if (ret == -1 || zvol_name_part == NULL) if (rc == -1 || zvol_name_part == NULL)
goto fail; goto error;
for (i = 0; i < strlen(zvol_name_part); i++) { for (i = 0; i < strlen(zvol_name_part); i++) {
if (isblank(zvol_name_part[i])) if (isblank(zvol_name_part[i]))
@ -102,13 +103,8 @@ main(int argc, char **argv)
} }
printf("%s\n", zvol_name_part); printf("%s\n", zvol_name_part);
status = EXIT_SUCCESS;
fail:
if (zvol_name_part)
free(zvol_name_part); free(zvol_name_part);
if (fd >= 0) error:
close(fd); close(fd);
return (error);
return (status);
} }

View File

@ -1,3 +1 @@
include $(top_srcdir)/config/Shellcheck.am
dist_bin_SCRIPTS = zvol_wait dist_bin_SCRIPTS = zvol_wait

View File

@ -9,44 +9,45 @@ count_zvols() {
} }
filter_out_zvols_with_links() { filter_out_zvols_with_links() {
echo "$zvols" | tr ' ' '+' | while read -r zvol; do while read -r zvol; do
if ! [ -L "/dev/zvol/$zvol" ]; then if [ ! -L "/dev/zvol/$zvol" ]; then
echo "$zvol" echo "$zvol"
fi fi
done | tr '+' ' ' done
} }
filter_out_deleted_zvols() { filter_out_deleted_zvols() {
OIFS="$IFS" while read -r zvol; do
IFS=" if zfs list "$zvol" >/dev/null 2>&1; then
" echo "$zvol"
# shellcheck disable=SC2086 fi
zfs list -H -o name $zvols 2>/dev/null done
IFS="$OIFS"
} }
list_zvols() { list_zvols() {
read -r default_volmode < /sys/module/zfs/parameters/zvol_volmode
zfs list -t volume -H -o \ zfs list -t volume -H -o \
name,volmode,receive_resume_token,redact_snaps,keystatus | name,volmode,receive_resume_token,redact_snaps |
while IFS=" " read -r name volmode token redacted keystatus; do # IFS=\t here! while read -r zvol_line; do
name=$(echo "$zvol_line" | awk '{print $1}')
# /dev links are not created for zvols with volmode = "none", volmode=$(echo "$zvol_line" | awk '{print $2}')
# redacted zvols, or encrypted zvols for which the key has not token=$(echo "$zvol_line" | awk '{print $3}')
# been loaded. redacted=$(echo "$zvol_line" | awk '{print $4}')
#
# /dev links are not created for zvols with volmode = "none"
# or for redacted zvols.
#
[ "$volmode" = "none" ] && continue [ "$volmode" = "none" ] && continue
[ "$volmode" = "default" ] && [ "$default_volmode" = "3" ] &&
continue
[ "$redacted" = "-" ] || continue [ "$redacted" = "-" ] || continue
[ "$keystatus" = "unavailable" ] && continue #
# We also also ignore partially received zvols if it is
# We also ignore partially received zvols if it is
# not an incremental receive, as those won't even have a block # not an incremental receive, as those won't even have a block
# device minor node created yet. # device minor node created yet.
#
if [ "$token" != "-" ]; then if [ "$token" != "-" ]; then
#
# Incremental receives create an invisible clone that # Incremental receives create an invisible clone that
# is not automatically displayed by zfs list. # is not automatically displayed by zfs list.
#
if ! zfs list "$name/%recv" >/dev/null 2>&1; then if ! zfs list "$name/%recv" >/dev/null 2>&1; then
continue continue
fi fi
@ -74,7 +75,7 @@ while [ "$outer_loop" -lt 20 ]; do
while [ "$inner_loop" -lt 30 ]; do while [ "$inner_loop" -lt 30 ]; do
inner_loop=$((inner_loop + 1)) inner_loop=$((inner_loop + 1))
zvols="$(filter_out_zvols_with_links)" zvols="$(echo "$zvols" | filter_out_zvols_with_links)"
zvols_count=$(count_zvols) zvols_count=$(count_zvols)
if [ "$zvols_count" -eq 0 ]; then if [ "$zvols_count" -eq 0 ]; then
@ -94,7 +95,7 @@ while [ "$outer_loop" -lt 20 ]; do
echo "No progress since last loop." echo "No progress since last loop."
echo "Checking if any zvols were deleted." echo "Checking if any zvols were deleted."
zvols=$(filter_out_deleted_zvols) zvols=$(echo "$zvols" | filter_out_deleted_zvols)
zvols_count=$(count_zvols) zvols_count=$(count_zvols)
if [ "$old_zvols_count" -ne "$zvols_count" ]; then if [ "$old_zvols_count" -ne "$zvols_count" ]; then
@ -109,13 +110,6 @@ while [ "$outer_loop" -lt 20 ]; do
exit 0 exit 0
fi fi
fi fi
#
# zvol_count made some progress - let's stay in this loop.
#
if [ "$old_zvols_count" -gt "$zvols_count" ]; then
outer_loop=$((outer_loop - 1))
fi
done done
echo "Timed out waiting on zvol links" echo "Timed out waiting on zvol links"

View File

@ -25,9 +25,5 @@ checkabi:
storeabi: storeabi:
cd .libs ; \ cd .libs ; \
for lib in $(lib_LTLIBRARIES) ; do \ for lib in $(lib_LTLIBRARIES) ; do \
abidw --no-show-locs \ abidw $${lib%.la}.so > ../$${lib%.la}.abi ; \
--no-corpus-path \
--no-comp-dir-path \
--type-id-style hash \
$${lib%.la}.so > ../$${lib%.la}.abi ; \
done done

View File

@ -1,5 +1,5 @@
# #
# Default rules for running cppcheck against the user space components. # Default rules for running cppcheck against the the user space components.
# #
PHONY += cppcheck PHONY += cppcheck

View File

@ -26,7 +26,6 @@ AM_LIBTOOLFLAGS = --silent
AM_CFLAGS = -std=gnu99 -Wall -Wstrict-prototypes -Wmissing-prototypes AM_CFLAGS = -std=gnu99 -Wall -Wstrict-prototypes -Wmissing-prototypes
AM_CFLAGS += -fno-strict-aliasing AM_CFLAGS += -fno-strict-aliasing
AM_CFLAGS += $(NO_OMIT_FRAME_POINTER) AM_CFLAGS += $(NO_OMIT_FRAME_POINTER)
AM_CFLAGS += $(IMPLICIT_FALLTHROUGH)
AM_CFLAGS += $(DEBUG_CFLAGS) AM_CFLAGS += $(DEBUG_CFLAGS)
AM_CFLAGS += $(ASAN_CFLAGS) AM_CFLAGS += $(ASAN_CFLAGS)
AM_CFLAGS += $(CODE_COVERAGE_CFLAGS) $(NO_FORMAT_ZERO_LENGTH) AM_CFLAGS += $(CODE_COVERAGE_CFLAGS) $(NO_FORMAT_ZERO_LENGTH)
@ -40,8 +39,8 @@ AM_CPPFLAGS = -D_GNU_SOURCE
AM_CPPFLAGS += -D_REENTRANT AM_CPPFLAGS += -D_REENTRANT
AM_CPPFLAGS += -D_FILE_OFFSET_BITS=64 AM_CPPFLAGS += -D_FILE_OFFSET_BITS=64
AM_CPPFLAGS += -D_LARGEFILE64_SOURCE AM_CPPFLAGS += -D_LARGEFILE64_SOURCE
AM_CPPFLAGS += -DHAVE_LARGE_STACKS=1
AM_CPPFLAGS += -DLIBEXECDIR=\"$(libexecdir)\" AM_CPPFLAGS += -DLIBEXECDIR=\"$(libexecdir)\"
AM_CPPFLAGS += -DZFSEXECDIR=\"$(zfsexecdir)\"
AM_CPPFLAGS += -DRUNSTATEDIR=\"$(runstatedir)\" AM_CPPFLAGS += -DRUNSTATEDIR=\"$(runstatedir)\"
AM_CPPFLAGS += -DSBINDIR=\"$(sbindir)\" AM_CPPFLAGS += -DSBINDIR=\"$(sbindir)\"
AM_CPPFLAGS += -DSYSCONFDIR=\"$(sysconfdir)\" AM_CPPFLAGS += -DSYSCONFDIR=\"$(sysconfdir)\"

View File

@ -1,22 +0,0 @@
.PHONY: shellcheck
shellcheck: $(SCRIPTS) $(SHELLCHECKSCRIPTS)
if HAVE_SHELLCHECK
[ -z "$(SCRIPTS)$(SHELLCHECKSCRIPTS)" ] && exit; shellcheck $$([ -n "$(SHELLCHECK_SHELL)" ] && echo "--shell=$(SHELLCHECK_SHELL)") --exclude=SC1090,SC1091$(SHELLCHECK_IGNORE) --format=gcc $(SCRIPTS) $(SHELLCHECKSCRIPTS)
else
@[ -z "$(SCRIPTS)$(SHELLCHECKSCRIPTS)" ] && exit; echo "skipping shellcheck of" $(SCRIPTS) $(SHELLCHECKSCRIPTS) "because shellcheck is not installed"
endif
@set -e; for dir in $(SHELLCHECKDIRS); do $(MAKE) -C $$dir shellcheck; done
# command -v *is* specified by POSIX and every shell in existence supports it
.PHONY: checkbashisms
checkbashisms: $(SCRIPTS) $(SHELLCHECKSCRIPTS)
if HAVE_CHECKBASHISMS
[ -z "$(SCRIPTS)$(SHELLCHECKSCRIPTS)" ] && exit; ! if [ -z "$(SHELLCHECK_SHELL)" ]; then \
checkbashisms -npx $(SCRIPTS) $(SHELLCHECKSCRIPTS); else \
for f in $(SCRIPTS) $(SHELLCHECKSCRIPTS); do echo $$f >&3; { echo '#!/bin/$(SHELLCHECK_SHELL)'; cat $$f; } | checkbashisms -npx; done; \
fi 3>&2 2>&1 | grep -vFe "'command' with option other than -p" -e 'command -v' $(CHECKBASHISMS_IGNORE) >&2
else
@[ -z "$(SCRIPTS)$(SHELLCHECKSCRIPTS)" ] && exit; echo "skipping checkbashisms of" $(SCRIPTS) $(SHELLCHECKSCRIPTS) "because checkbashisms is not installed"
endif
@set -e; for dir in $(SHELLCHECKDIRS); do $(MAKE) -C $$dir checkbashisms; done

View File

@ -15,9 +15,7 @@ subst_sed_cmd = \
-e 's|@PYTHON[@]|$(PYTHON)|g' \ -e 's|@PYTHON[@]|$(PYTHON)|g' \
-e 's|@PYTHON_SHEBANG[@]|$(PYTHON_SHEBANG)|g' \ -e 's|@PYTHON_SHEBANG[@]|$(PYTHON_SHEBANG)|g' \
-e 's|@DEFAULT_INIT_NFS_SERVER[@]|$(DEFAULT_INIT_NFS_SERVER)|g' \ -e 's|@DEFAULT_INIT_NFS_SERVER[@]|$(DEFAULT_INIT_NFS_SERVER)|g' \
-e 's|@DEFAULT_INIT_SHELL[@]|$(DEFAULT_INIT_SHELL)|g' \ -e 's|@DEFAULT_INIT_SHELL[@]|$(DEFAULT_INIT_SHELL)|g'
-e 's|@LIBFETCH_DYNAMIC[@]|$(LIBFETCH_DYNAMIC)|g' \
-e 's|@LIBFETCH_SONAME[@]|$(LIBFETCH_SONAME)|g'
SUBSTFILES = SUBSTFILES =
CLEANFILES = $(SUBSTFILES) CLEANFILES = $(SUBSTFILES)

Some files were not shown because too many files have changed in this diff Show More