Compare commits
No commits in common. "zfs-2.1-release" and "zfs-2.1.0-rc1" have entirely different histories.
zfs-2.1-re
...
zfs-2.1.0-
|
@ -2,7 +2,7 @@
|
|||
name: Bug report
|
||||
about: Create a report to help us improve OpenZFS
|
||||
title: ''
|
||||
labels: 'Type: Defect'
|
||||
labels: 'Type: Defect, Status: Triage Needed'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
@ -25,16 +25,14 @@ Type | Version/Name
|
|||
--- | ---
|
||||
Distribution Name |
|
||||
Distribution Version |
|
||||
Kernel Version |
|
||||
Linux Kernel |
|
||||
Architecture |
|
||||
OpenZFS Version |
|
||||
ZFS Version |
|
||||
SPL Version |
|
||||
<!--
|
||||
Command to find OpenZFS version:
|
||||
zfs version
|
||||
|
||||
Commands to find kernel version:
|
||||
uname -r # Linux
|
||||
freebsd-version -r # FreeBSD
|
||||
Commands to find ZFS/SPL versions:
|
||||
modinfo zfs | grep -iw version
|
||||
modinfo spl | grep -iw version
|
||||
-->
|
||||
|
||||
### Describe the problem you're observing
|
||||
|
|
|
@ -10,5 +10,5 @@ contact_links:
|
|||
url: https://lists.freebsd.org/mailman/listinfo/freebsd-fs
|
||||
about: Get community support for OpenZFS on FreeBSD
|
||||
- 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
|
||||
|
|
|
@ -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
|
|
@ -1,2 +0,0 @@
|
|||
pax-utils
|
||||
shellcheck
|
|
@ -6,27 +6,20 @@ on:
|
|||
|
||||
jobs:
|
||||
checkstyle:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
# https://github.com/orgs/community/discussions/47863
|
||||
sudo apt-mark hold grub-efi-amd64-signed
|
||||
sudo apt-get update --fix-missing
|
||||
sudo apt-get upgrade
|
||||
sudo xargs --arg-file=${{ github.workspace }}/.github/workflows/build-dependencies.txt apt-get install -qq
|
||||
sudo xargs --arg-file=${{ github.workspace }}/.github/workflows/checkstyle-dependencies.txt apt-get install -qq
|
||||
sudo python3 -m pip install --quiet flake8
|
||||
sudo apt-get clean
|
||||
|
||||
# confirm that the tools are installed
|
||||
# the build system doesn't fail when they are not
|
||||
flake8 --version
|
||||
scanelf --version
|
||||
shellcheck --version
|
||||
sudo apt-get update
|
||||
sudo apt-get install --yes -qq build-essential autoconf libtool gawk alien fakeroot linux-headers-$(uname -r)
|
||||
sudo apt-get install --yes -qq zlib1g-dev uuid-dev libattr1-dev libblkid-dev libselinux-dev libudev-dev libssl-dev python-dev python-setuptools python-cffi python3 python3-dev python3-setuptools python3-cffi
|
||||
# packages for tests
|
||||
sudo apt-get install --yes -qq parted lsscsi ksh attr acl nfs-kernel-server fio
|
||||
sudo apt-get install --yes -qq mandoc cppcheck pax-utils devscripts abigail-tools
|
||||
sudo -E pip --quiet install flake8
|
||||
- name: Prepare
|
||||
run: |
|
||||
sh ./autogen.sh
|
||||
|
@ -39,19 +32,5 @@ jobs:
|
|||
run: |
|
||||
make lint
|
||||
- name: CheckABI
|
||||
id: CheckABI
|
||||
run: |
|
||||
sudo docker run -v $(pwd):/source ghcr.io/openzfs/libabigail 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
|
||||
make checkabi
|
||||
|
|
|
@ -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 /
|
|
@ -9,20 +9,24 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [20.04, 22.04]
|
||||
os: [18.04, 20.04]
|
||||
runs-on: ubuntu-${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
# https://github.com/orgs/community/discussions/47863
|
||||
sudo apt-mark hold grub-efi-amd64-signed
|
||||
sudo apt-get update --fix-missing
|
||||
sudo apt-get upgrade
|
||||
sudo xargs --arg-file=${{ github.workspace }}/.github/workflows/build-dependencies.txt apt-get install -qq
|
||||
sudo apt-get clean
|
||||
sudo apt-get update
|
||||
sudo apt-get install --yes -qq build-essential autoconf libtool gdb lcov \
|
||||
git alien fakeroot wget curl bc fio acl \
|
||||
sysstat mdadm lsscsi parted gdebi attr dbench watchdog ksh \
|
||||
nfs-kernel-server samba rng-tools xz-utils \
|
||||
zlib1g-dev uuid-dev libblkid-dev libselinux-dev \
|
||||
xfslibs-dev libattr1-dev libacl1-dev libudev-dev libdevmapper-dev \
|
||||
libssl-dev libffi-dev libaio-dev libelf-dev libmount-dev \
|
||||
libpam0g-dev pamtester python-dev python-setuptools python-cffi \
|
||||
python3 python3-dev python3-setuptools python3-cffi
|
||||
- name: Autogen.sh
|
||||
run: |
|
||||
sh autogen.sh
|
||||
|
@ -40,42 +44,21 @@ jobs:
|
|||
sudo sed -i.bak 's/updates/extra updates/' /etc/depmod.d/ubuntu.conf
|
||||
sudo depmod
|
||||
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
|
||||
run: |
|
||||
/usr/share/zfs/zfs-tests.sh -vR -s 3G
|
||||
timeout-minutes: 330
|
||||
/usr/share/zfs/zfs-tests.sh -v -s 3G
|
||||
- name: Prepare artifacts
|
||||
if: failure()
|
||||
run: |
|
||||
RESULTS_PATH=$(readlink -f /var/tmp/test_results/current)
|
||||
sudo dmesg > $RESULTS_PATH/dmesg
|
||||
sudo cp /var/log/syslog /var/tmp/dmesg-prerun $RESULTS_PATH/
|
||||
sudo cp /var/log/syslog $RESULTS_PATH/
|
||||
sudo chmod +r $RESULTS_PATH/*
|
||||
# Replace ':' in dir names, actions/upload-artifact doesn't support it
|
||||
for f in $(find /var/tmp/test_results -name '*:*'); do mv "$f" "${f//:/__}"; done
|
||||
- uses: actions/upload-artifact@v3
|
||||
for f in $(find $RESULTS_PATH -name '*:*'); do mv "$f" "${f//:/__}"; done
|
||||
- uses: actions/upload-artifact@v2
|
||||
if: failure()
|
||||
with:
|
||||
name: Test logs Ubuntu-${{ matrix.os }}
|
||||
path: |
|
||||
/var/tmp/test_results/*
|
||||
!/var/tmp/test_results/current
|
||||
path: /var/tmp/test_results/20*/
|
||||
if-no-files-found: ignore
|
||||
|
|
|
@ -6,19 +6,23 @@ on:
|
|||
|
||||
jobs:
|
||||
tests:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
# https://github.com/orgs/community/discussions/47863
|
||||
sudo apt-mark hold grub-efi-amd64-signed
|
||||
sudo apt-get update --fix-missing
|
||||
sudo apt-get upgrade
|
||||
sudo xargs --arg-file=${{ github.workspace }}/.github/workflows/build-dependencies.txt apt-get install -qq
|
||||
sudo apt-get clean
|
||||
sudo apt-get update
|
||||
sudo apt-get install --yes -qq build-essential autoconf libtool gdb lcov \
|
||||
git alien fakeroot wget curl bc fio acl \
|
||||
sysstat mdadm lsscsi parted gdebi attr dbench watchdog ksh \
|
||||
nfs-kernel-server samba rng-tools xz-utils \
|
||||
zlib1g-dev uuid-dev libblkid-dev libselinux-dev \
|
||||
xfslibs-dev libattr1-dev libacl1-dev libudev-dev libdevmapper-dev \
|
||||
libssl-dev libffi-dev libaio-dev libelf-dev libmount-dev \
|
||||
libpam0g-dev pamtester python-dev python-setuptools python-cffi \
|
||||
python3 python3-dev python3-setuptools python3-cffi
|
||||
- name: Autogen.sh
|
||||
run: |
|
||||
sh autogen.sh
|
||||
|
@ -36,42 +40,21 @@ jobs:
|
|||
sudo sed -i.bak 's/updates/extra updates/' /etc/depmod.d/ubuntu.conf
|
||||
sudo depmod
|
||||
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
|
||||
run: |
|
||||
/usr/share/zfs/zfs-tests.sh -vR -s 3G -r sanity
|
||||
timeout-minutes: 330
|
||||
/usr/share/zfs/zfs-tests.sh -v -s 3G -r sanity
|
||||
- name: Prepare artifacts
|
||||
if: failure()
|
||||
run: |
|
||||
RESULTS_PATH=$(readlink -f /var/tmp/test_results/current)
|
||||
sudo dmesg > $RESULTS_PATH/dmesg
|
||||
sudo cp /var/log/syslog /var/tmp/dmesg-prerun $RESULTS_PATH/
|
||||
sudo cp /var/log/syslog $RESULTS_PATH/
|
||||
sudo chmod +r $RESULTS_PATH/*
|
||||
# Replace ':' in dir names, actions/upload-artifact doesn't support it
|
||||
for f in $(find /var/tmp/test_results -name '*:*'); do mv "$f" "${f//:/__}"; done
|
||||
- uses: actions/upload-artifact@v3
|
||||
for f in $(find $RESULTS_PATH -name '*:*'); do mv "$f" "${f//:/__}"; done
|
||||
- uses: actions/upload-artifact@v2
|
||||
if: failure()
|
||||
with:
|
||||
name: Test logs Ubuntu-${{ matrix.os }}
|
||||
path: |
|
||||
/var/tmp/test_results/*
|
||||
!/var/tmp/test_results/current
|
||||
name: Test logs
|
||||
path: /var/tmp/test_results/20*/
|
||||
if-no-files-found: ignore
|
||||
|
|
|
@ -6,21 +6,24 @@ on:
|
|||
|
||||
jobs:
|
||||
tests:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TEST_DIR: /var/tmp/zloop
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
# https://github.com/orgs/community/discussions/47863
|
||||
sudo apt-mark hold grub-efi-amd64-signed
|
||||
sudo apt-get update --fix-missing
|
||||
sudo apt-get upgrade
|
||||
sudo xargs --arg-file=${{ github.workspace }}/.github/workflows/build-dependencies.txt apt-get install -qq
|
||||
sudo apt-get clean
|
||||
sudo apt-get update
|
||||
sudo apt-get install --yes -qq build-essential autoconf libtool gdb \
|
||||
git alien fakeroot \
|
||||
zlib1g-dev uuid-dev libblkid-dev libselinux-dev \
|
||||
xfslibs-dev libattr1-dev libacl1-dev libudev-dev libdevmapper-dev \
|
||||
libssl-dev libffi-dev libaio-dev libelf-dev libmount-dev \
|
||||
libpam0g-dev \
|
||||
python-dev python-setuptools python-cffi \
|
||||
python3 python3-dev python3-setuptools python3-cffi
|
||||
- name: Autogen.sh
|
||||
run: |
|
||||
sh autogen.sh
|
||||
|
@ -41,14 +44,13 @@ jobs:
|
|||
- name: Tests
|
||||
run: |
|
||||
sudo mkdir -p $TEST_DIR
|
||||
# run for 10 minutes or at most 2 iterations for a maximum runner
|
||||
# time of 20 minutes.
|
||||
sudo /usr/share/zfs/zloop.sh -t 600 -I 2 -l -m1 -- -T 120 -P 60
|
||||
# run for 20 minutes to have a total runner time of 30 minutes
|
||||
sudo /usr/share/zfs/zloop.sh -t 1200 -l -m1
|
||||
- name: Prepare artifacts
|
||||
if: failure()
|
||||
run: |
|
||||
sudo chmod +r -R $TEST_DIR/
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v2
|
||||
if: failure()
|
||||
with:
|
||||
name: Logs
|
||||
|
@ -56,7 +58,7 @@ jobs:
|
|||
/var/tmp/zloop/*/
|
||||
!/var/tmp/zloop/*/vdev/
|
||||
if-no-files-found: ignore
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v2
|
||||
if: failure()
|
||||
with:
|
||||
name: Pool files
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
[submodule "scripts/zfs-images"]
|
||||
path = scripts/zfs-images
|
||||
url = https://github.com/openzfs/zfs-images
|
||||
url = https://github.com/zfsonlinux/zfs-images
|
||||
|
|
|
@ -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.
|
||||
|
|
6
META
6
META
|
@ -1,10 +1,10 @@
|
|||
Meta: 1
|
||||
Name: zfs
|
||||
Branch: 1.0
|
||||
Version: 2.1.15
|
||||
Release: 1
|
||||
Version: 2.1.0
|
||||
Release: rc1
|
||||
Release-Tags: relext
|
||||
License: CDDL
|
||||
Author: OpenZFS
|
||||
Linux-Maximum: 6.7
|
||||
Linux-Maximum: 5.11
|
||||
Linux-Minimum: 3.10
|
||||
|
|
83
Makefile.am
83
Makefile.am
|
@ -1,5 +1,3 @@
|
|||
include $(top_srcdir)/config/Shellcheck.am
|
||||
|
||||
ACLOCAL_AMFLAGS = -I config
|
||||
|
||||
SUBDIRS = include
|
||||
|
@ -8,7 +6,7 @@ SUBDIRS += rpm
|
|||
endif
|
||||
|
||||
if CONFIG_USER
|
||||
SUBDIRS += man scripts lib tests cmd etc contrib
|
||||
SUBDIRS += etc man scripts lib tests cmd contrib
|
||||
if BUILD_LINUX
|
||||
SUBDIRS += udev
|
||||
endif
|
||||
|
@ -28,8 +26,8 @@ endif
|
|||
AUTOMAKE_OPTIONS = foreign
|
||||
EXTRA_DIST = autogen.sh copy-builtin
|
||||
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 += README.md RELEASES.md
|
||||
EXTRA_DIST += META AUTHORS COPYRIGHT LICENSE NEWS NOTICE README.md
|
||||
EXTRA_DIST += CODE_OF_CONDUCT.md
|
||||
EXTRA_DIST += module/lua/README.zfs module/os/linux/spl/README.md
|
||||
|
||||
# Include all the extra licensing information for modules
|
||||
|
@ -103,7 +101,7 @@ endif
|
|||
endif
|
||||
|
||||
PHONY += codecheck
|
||||
codecheck: cstyle shellcheck checkbashisms flake8 mancheck testscheck vcscheck zstdcheck
|
||||
codecheck: cstyle shellcheck checkbashisms flake8 mancheck testscheck vcscheck
|
||||
|
||||
PHONY += checkstyle
|
||||
checkstyle: codecheck commitcheck
|
||||
|
@ -114,47 +112,70 @@ commitcheck:
|
|||
${top_srcdir}/scripts/commitcheck.sh; \
|
||||
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
|
||||
cstyle:
|
||||
@find ${top_srcdir} -name build -prune \
|
||||
-o -type f -name '*.[hc]' \
|
||||
! -name 'zfs_config.*' ! -name '*.mod.c' \
|
||||
! -name 'opt_global.h' ! -name '*_if*.h' \
|
||||
! -name 'zstd_compat_wrapper.h' \
|
||||
! -path './module/zstd/lib/*' \
|
||||
$(cstyle_line)
|
||||
-exec ${top_srcdir}/scripts/cstyle.pl -cpP {} \+
|
||||
|
||||
filter_executable = -exec test -x '{}' \; -print
|
||||
|
||||
SHELLCHECKDIRS = cmd contrib etc scripts tests
|
||||
SHELLCHECKSCRIPTS = autogen.sh
|
||||
PHONY += shellcheck
|
||||
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
|
||||
|
||||
checklibabiversion:
|
||||
libabiversion=`abidw -v | $(SED) 's/[^0-9]//g'`; \
|
||||
if test $$libabiversion -lt "200"; then \
|
||||
/bin/echo -e "\n" \
|
||||
"*** Please use libabigail 2.0.0 version or newer;\n" \
|
||||
"*** otherwise results are not consistent!\n" \
|
||||
"(or see https://github.com/openzfs/libabigail-docker )\n"; \
|
||||
exit 1; \
|
||||
fi;
|
||||
|
||||
checkabi: checklibabiversion lib
|
||||
checkabi: lib
|
||||
$(MAKE) -C lib checkabi
|
||||
|
||||
storeabi: checklibabiversion lib
|
||||
storeabi: lib
|
||||
$(MAKE) -C lib storeabi
|
||||
|
||||
PHONY += 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
|
||||
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
|
||||
stat_fmt = -c '%A %n'
|
||||
|
@ -179,10 +200,6 @@ vcscheck:
|
|||
awk '{c++; print} END {if(c>0) exit 1}' ; \
|
||||
fi
|
||||
|
||||
PHONY += zstdcheck
|
||||
zstdcheck:
|
||||
@$(MAKE) -C module/zstd checksymbols
|
||||
|
||||
PHONY += lint
|
||||
lint: cppcheck paxcheck
|
||||
|
||||
|
|
|
@ -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
|
||||
* [ZoL Site](https://zfsonlinux.org) - Linux release info & links
|
||||
* [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
|
||||
|
||||
|
|
37
RELEASES.md
37
RELEASES.md
|
@ -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.
|
|
@ -1,15 +1,10 @@
|
|||
include $(top_srcdir)/config/Shellcheck.am
|
||||
|
||||
SUBDIRS = zfs zpool zdb zhack zinject zstream ztest
|
||||
SUBDIRS = zfs zpool zdb zhack zinject zstream zstreamdump ztest
|
||||
SUBDIRS += fsck_zfs vdev_id raidz_test zfs_ids_to_path
|
||||
SUBDIRS += zpool_influxdb
|
||||
|
||||
CPPCHECKDIRS = zfs zpool zdb zhack zinject zstream ztest
|
||||
CPPCHECKDIRS += raidz_test zfs_ids_to_path zpool_influxdb
|
||||
|
||||
# TODO: #12084: SHELLCHECKDIRS = fsck_zfs vdev_id zpool
|
||||
SHELLCHECKDIRS = fsck_zfs zpool
|
||||
|
||||
if USING_PYTHON
|
||||
SUBDIRS += arcstat arc_summary dbufstat
|
||||
endif
|
||||
|
@ -17,7 +12,6 @@ endif
|
|||
if BUILD_LINUX
|
||||
SUBDIRS += mount_zfs zed zgenhostid zvol_id zvol_wait
|
||||
CPPCHECKDIRS += mount_zfs zed zgenhostid zvol_id
|
||||
SHELLCHECKDIRS += zed
|
||||
endif
|
||||
|
||||
PHONY = cppcheck
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
bin_SCRIPTS = 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
|
||||
endif
|
||||
|
||||
arc_summary: $(SCRIPT)
|
||||
cp $< $@
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -42,13 +42,6 @@ import os
|
|||
import subprocess
|
||||
import sys
|
||||
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'
|
||||
INDENT = ' '*8
|
||||
|
@ -168,11 +161,21 @@ elif sys.platform.startswith('linux'):
|
|||
# The original arc_summary called /sbin/modinfo/{spl,zfs} to get
|
||||
# the version information. We switch to /sys/module/{spl,zfs}/version
|
||||
# to make sure we get what is really loaded in the kernel
|
||||
try:
|
||||
with open("/sys/module/{}/version".format(request)) as f:
|
||||
return f.read().strip()
|
||||
except:
|
||||
return "(unknown)"
|
||||
command = ["cat", "/sys/module/{0}/version".format(request)]
|
||||
req = request.upper()
|
||||
|
||||
# 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)
|
||||
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):
|
||||
"""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
|
||||
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 = ''
|
||||
|
||||
try:
|
||||
|
||||
info = subprocess.run(command, stdout=subprocess.PIPE,
|
||||
check=True, universal_newlines=True)
|
||||
raw_output = info.stdout.split('\0')
|
||||
if 'run' in dir(subprocess):
|
||||
info = subprocess.run(command, stdout=subprocess.PIPE,
|
||||
universal_newlines=True)
|
||||
raw_output = info.stdout.split('\0')
|
||||
else:
|
||||
info = subprocess.check_output(command,
|
||||
universal_newlines=True)
|
||||
raw_output = info.split('\0')
|
||||
|
||||
except subprocess.CalledProcessError:
|
||||
print("Error: Descriptions not available",
|
||||
|
@ -220,29 +231,6 @@ elif sys.platform.startswith('linux'):
|
|||
|
||||
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):
|
||||
"""Format a raw line of data from /proc and isolate the name value
|
||||
|
@ -678,9 +666,9 @@ def section_archits(kstats_dict):
|
|||
print()
|
||||
print('Cache hits by data type:')
|
||||
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']),
|
||||
('Prefetch metadata:',
|
||||
('Demand prefetch metadata:',
|
||||
arc_stats['prefetch_metadata_hits']))
|
||||
|
||||
for title, value in dt_todo:
|
||||
|
@ -689,10 +677,10 @@ def section_archits(kstats_dict):
|
|||
print()
|
||||
print('Cache misses by data type:')
|
||||
dm_todo = (('Demand data:', arc_stats['demand_data_misses']),
|
||||
('Prefetch data:',
|
||||
('Demand prefetch data:',
|
||||
arc_stats['prefetch_data_misses']),
|
||||
('Demand metadata:', arc_stats['demand_metadata_misses']),
|
||||
('Prefetch metadata:',
|
||||
('Demand prefetch metadata:',
|
||||
arc_stats['prefetch_metadata_misses']))
|
||||
|
||||
for title, value in dm_todo:
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
# @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.
|
||||
#
|
||||
# This script must remain compatible with Python 3.6+.
|
||||
# This script must remain compatible with Python 2.6+ and Python 3.4+.
|
||||
#
|
||||
|
||||
import sys
|
||||
|
@ -271,7 +271,7 @@ def print_values():
|
|||
if pretty_print:
|
||||
fmt = lambda col: prettynum(cols[col][0], cols[col][1], v[col])
|
||||
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("\n")
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
# Copyright (C) 2013 Lawrence Livermore National Security, LLC.
|
||||
# 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
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
/fsck.zfs
|
|
@ -1,6 +1 @@
|
|||
include $(top_srcdir)/config/Substfiles.am
|
||||
include $(top_srcdir)/config/Shellcheck.am
|
||||
|
||||
dist_sbin_SCRIPTS = fsck.zfs
|
||||
|
||||
SUBSTFILES += $(dist_sbin_SCRIPTS)
|
||||
|
|
|
@ -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
|
|
@ -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"
|
|
@ -185,11 +185,10 @@ main(int argc, char **argv)
|
|||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
if (optopt)
|
||||
(void) fprintf(stderr,
|
||||
gettext("Invalid option '%c'\n"), optopt);
|
||||
(void) fprintf(stderr, gettext("Invalid option '%c'\n"),
|
||||
optopt);
|
||||
(void) fprintf(stderr, gettext("Usage: mount.zfs "
|
||||
"[-sfnvh] [-o options] <dataset> <mountpoint>\n"));
|
||||
"[-sfnv] [-o options] <dataset> <mountpoint>\n"));
|
||||
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) {
|
||||
nomtab = 1;
|
||||
remount = 1;
|
||||
|
@ -268,10 +274,7 @@ main(int argc, char **argv)
|
|||
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 */
|
||||
if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT)
|
||||
|
@ -289,11 +292,12 @@ main(int argc, char **argv)
|
|||
if (zfs_version == 0) {
|
||||
fprintf(stderr, gettext("unable to fetch "
|
||||
"ZFS version for filesystem '%s'\n"), dataset);
|
||||
zfs_close(zhp);
|
||||
libzfs_fini(g_zfs);
|
||||
return (MOUNT_SYSERR);
|
||||
}
|
||||
|
||||
zfs_close(zhp);
|
||||
libzfs_fini(g_zfs);
|
||||
|
||||
/*
|
||||
* Legacy mount points may only be mounted using 'mount', never using
|
||||
* 'zfs mount'. However, since 'zfs mount' actually invokes 'mount'
|
||||
|
@ -311,8 +315,6 @@ main(int argc, char **argv)
|
|||
"Use 'zfs set mountpoint=%s' or 'mount -t zfs %s %s'.\n"
|
||||
"See zfs(8) for more information.\n"),
|
||||
dataset, mntpoint, dataset, mntpoint);
|
||||
zfs_close(zhp);
|
||||
libzfs_fini(g_zfs);
|
||||
return (MOUNT_USAGE);
|
||||
}
|
||||
|
||||
|
@ -323,38 +325,14 @@ main(int argc, char **argv)
|
|||
"Use 'zfs set mountpoint=%s' or 'zfs mount %s'.\n"
|
||||
"See zfs(8) for more information.\n"),
|
||||
dataset, "legacy", dataset);
|
||||
zfs_close(zhp);
|
||||
libzfs_fini(g_zfs);
|
||||
return (MOUNT_USAGE);
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
(void) fprintf(stdout, gettext("mount.zfs:\n"
|
||||
" dataset: \"%s\"\n mountpoint: \"%s\"\n"
|
||||
" mountflags: 0x%lx\n zfsflags: 0x%lx\n"
|
||||
" mountopts: \"%s\"\n mtabopts: \"%s\"\n"),
|
||||
dataset, mntpoint, mntflags, zfsflags, mntopts, mtabopt);
|
||||
|
||||
if (!fake) {
|
||||
if (zfsutil && !sloppy &&
|
||||
!libzfs_envvar_is_set("ZFS_MOUNT_HELPER")) {
|
||||
error = zfs_mount_at(zhp, mntopts, mntflags, mntpoint);
|
||||
if (error) {
|
||||
(void) fprintf(stderr, "zfs_mount_at() failed: "
|
||||
"%s", libzfs_error_description(g_zfs));
|
||||
zfs_close(zhp);
|
||||
libzfs_fini(g_zfs);
|
||||
return (MOUNT_SYSERR);
|
||||
}
|
||||
} else {
|
||||
error = mount(dataset, mntpoint, MNTTYPE_ZFS,
|
||||
mntflags, mntopts);
|
||||
}
|
||||
error = mount(dataset, mntpoint, MNTTYPE_ZFS,
|
||||
mntflags, mntopts);
|
||||
}
|
||||
|
||||
zfs_close(zhp);
|
||||
libzfs_fini(g_zfs);
|
||||
|
||||
if (error) {
|
||||
switch (errno) {
|
||||
case ENOENT:
|
||||
|
@ -389,7 +367,7 @@ main(int argc, char **argv)
|
|||
"mount the filesystem again.\n"), dataset);
|
||||
return (MOUNT_SYSERR);
|
||||
}
|
||||
fallthrough;
|
||||
/* fallthru */
|
||||
#endif
|
||||
default:
|
||||
(void) fprintf(stderr, gettext("filesystem "
|
||||
|
|
|
@ -1,3 +1 @@
|
|||
include $(top_srcdir)/config/Shellcheck.am
|
||||
|
||||
dist_udev_SCRIPTS = vdev_id
|
||||
|
|
|
@ -140,17 +140,15 @@ Usage: vdev_id [-h]
|
|||
-p number of phy's per switch port [default=$PHYS_PER_PORT]
|
||||
-h show this summary
|
||||
EOF
|
||||
exit 1
|
||||
# exit with error to avoid processing usage message by a udev rule
|
||||
exit 0
|
||||
}
|
||||
|
||||
map_slot() {
|
||||
LINUX_SLOT=$1
|
||||
CHANNEL=$2
|
||||
|
||||
MAPPED_SLOT=$(awk -v linux_slot="$LINUX_SLOT" -v channel="$CHANNEL" \
|
||||
'$1 == "slot" && $2 == linux_slot && \
|
||||
($4 ~ "^"channel"$" || $4 ~ /^$/) { print $3; exit}' $CONFIG)
|
||||
MAPPED_SLOT=$(awk '$1 == "slot" && $2 == "${LINUX_SLOT}" && \
|
||||
$4 ~ /^${CHANNEL}$|^$/ { print $3; exit}' $CONFIG)
|
||||
if [ -z "$MAPPED_SLOT" ] ; then
|
||||
MAPPED_SLOT=$LINUX_SLOT
|
||||
fi
|
||||
|
@ -165,7 +163,7 @@ map_channel() {
|
|||
case $TOPOLOGY in
|
||||
"sas_switch")
|
||||
MAPPED_CHAN=$(awk -v port="$PORT" \
|
||||
'$1 == "channel" && $2 == port \
|
||||
'$1 == "channel" && $2 == ${PORT} \
|
||||
{ print $3; exit }' $CONFIG)
|
||||
;;
|
||||
"sas_direct"|"scsi")
|
||||
|
@ -375,7 +373,7 @@ sas_handler() {
|
|||
i=$((i + 1))
|
||||
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
|
||||
PHY=0
|
||||
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
|
||||
|
||||
# Get the enclosure ID ("0:0:0:0")
|
||||
ENC="${DEVPATH%/*}"
|
||||
ENC="${ENC%/*}"
|
||||
ENC="${ENC##*/}"
|
||||
ENC=$(basename $(readlink -m "/sys/$DEVPATH/../.."))
|
||||
if [ ! -d "/sys/class/enclosure/$ENC" ] ; then
|
||||
# Not an enclosure, bail out
|
||||
return
|
||||
|
@ -618,15 +614,14 @@ enclosure_handler () {
|
|||
|
||||
# The PCI directory is two directories up from the port directory
|
||||
# /sys/devices/pci0000:00/0000:00:03.0/0000:05:00.0
|
||||
PCI_ID_LONG="$(readlink -m "/sys/$PORT_DIR/../..")"
|
||||
PCI_ID_LONG="${PCI_ID_LONG##*/}"
|
||||
PCI_ID_LONG=$(basename $(readlink -m "/sys/$PORT_DIR/../.."))
|
||||
|
||||
# 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=$(awk "/channel/{if (\$1 == \"channel\" && \$2 == \"$PCI_ID\" && \
|
||||
\$3 == \"$PORT_ID\") {print \$4\$3}}" $CONFIG)
|
||||
NAME=$(awk '/channel/{if ($1 == "channel" && $2 == "$PCI_ID" && \
|
||||
$3 == "$PORT_ID") {print ${4}int(count[$4])}; count[$4]++}' $CONFIG)
|
||||
|
||||
echo "${NAME}"
|
||||
}
|
||||
|
@ -677,7 +672,7 @@ alias_handler () {
|
|||
link=$(echo "$link" | sed 's/p[0-9][0-9]*$//')
|
||||
fi
|
||||
# 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
|
||||
alias=$(awk -v var="$l" '($1 == "alias") && \
|
||||
($3 == var) \
|
||||
|
@ -732,7 +727,7 @@ done
|
|||
|
||||
if [ ! -r "$CONFIG" ] ; then
|
||||
echo "Error: Config file \"$CONFIG\" not found"
|
||||
exit 1
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -z "$DEV" ] && [ -z "$ENCLOSURE_MODE" ] ; then
|
||||
|
|
273
cmd/zdb/zdb.c
273
cmd/zdb/zdb.c
|
@ -110,9 +110,8 @@ extern int zfs_recover;
|
|||
extern unsigned long zfs_arc_meta_min, zfs_arc_meta_limit;
|
||||
extern int zfs_vdev_async_read_max_active;
|
||||
extern boolean_t spa_load_verify_dryrun;
|
||||
extern boolean_t spa_mode_readable_spacemaps;
|
||||
extern int zfs_reconstruct_indirect_combinations_max;
|
||||
extern uint_t zfs_btree_verify_intensity;
|
||||
extern int zfs_btree_verify_intensity;
|
||||
|
||||
static const char cmdname[] = "zdb";
|
||||
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);
|
||||
|
||||
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 */
|
||||
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);
|
||||
|
||||
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
|
||||
sublivelist_verify_blkptr(void *arg, const blkptr_t *bp, boolean_t free,
|
||||
dmu_tx_t *tx)
|
||||
{
|
||||
ASSERT3P(tx, ==, NULL);
|
||||
struct sublivelist_verify *sv = arg;
|
||||
sublivelist_verify_block_refcnt_t current = {
|
||||
.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,
|
||||
};
|
||||
|
||||
char blkbuf[BP_SPRINTF_LEN];
|
||||
zfs_btree_index_t where;
|
||||
sublivelist_verify_block_refcnt_t *pair =
|
||||
zfs_btree_find(&sv->sv_pair, ¤t, &where);
|
||||
if (free) {
|
||||
if (pair == NULL) {
|
||||
/* first free entry for this block pointer */
|
||||
zfs_btree_add(&sv->sv_pair, ¤t);
|
||||
zfs_btree_add(&sv->sv_pair, bp);
|
||||
/* Check if the FREE is a duplicate */
|
||||
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 {
|
||||
pair->svbr_refcnt++;
|
||||
zfs_btree_add_idx(&sv->sv_all_frees, bp, &where);
|
||||
}
|
||||
} else {
|
||||
if (pair == NULL) {
|
||||
/* block that is currently marked as allocated */
|
||||
/* Check if the ALLOC has been freed */
|
||||
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++) {
|
||||
if (DVA_IS_EMPTY(&bp->blk_dva[i]))
|
||||
break;
|
||||
|
@ -297,16 +263,16 @@ sublivelist_verify_blkptr(void *arg, const blkptr_t *bp, boolean_t free,
|
|||
&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 {
|
||||
/* alloc matches a free entry */
|
||||
pair->svbr_refcnt--;
|
||||
if (pair->svbr_refcnt == 0) {
|
||||
/* all allocs and frees have been matched */
|
||||
zfs_btree_remove_idx(&sv->sv_pair, &where);
|
||||
}
|
||||
zfs_btree_add_idx(&sv->sv_all_allocs, bp, &where);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -314,22 +280,32 @@ static int
|
|||
sublivelist_verify_func(void *args, dsl_deadlist_entry_t *dle)
|
||||
{
|
||||
int err;
|
||||
char blkbuf[BP_SPRINTF_LEN];
|
||||
struct sublivelist_verify *sv = args;
|
||||
|
||||
zfs_btree_create(&sv->sv_pair, sublivelist_block_refcnt_compare,
|
||||
sizeof (sublivelist_verify_block_refcnt_t));
|
||||
zfs_btree_create(&sv->sv_all_allocs, livelist_compare,
|
||||
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,
|
||||
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;
|
||||
while ((e = zfs_btree_destroy_nodes(&sv->sv_pair, &cookie)) != NULL) {
|
||||
char blkbuf[BP_SPRINTF_LEN];
|
||||
snprintf_blkptr_compact(blkbuf, sizeof (blkbuf),
|
||||
&e->svbr_blk, B_TRUE);
|
||||
(void) printf("\tERROR: %d unmatched FREE(s): %s\n",
|
||||
e->svbr_refcnt, blkbuf);
|
||||
snprintf_blkptr_compact(blkbuf, sizeof (blkbuf), e, B_TRUE);
|
||||
(void) printf("\tERROR: Unmatched FREE: %s\n", blkbuf);
|
||||
}
|
||||
zfs_btree_destroy(&sv->sv_pair);
|
||||
|
||||
|
@ -638,14 +614,10 @@ mv_populate_livelist_allocs(metaslab_verify_t *mv, sublivelist_verify_t *sv)
|
|||
/*
|
||||
* [Livelist Check]
|
||||
* 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]
|
||||
*
|
||||
* (**) 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]
|
||||
* for each metaslab:
|
||||
* - 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),
|
||||
buflen - strlen(blkbuf),
|
||||
" ZSTD:size=%u:version=%u:level=%u:EMBEDDED",
|
||||
zstd_hdr.c_len, zfs_get_hdrversion(&zstd_hdr),
|
||||
zfs_get_hdrlevel(&zstd_hdr));
|
||||
zstd_hdr.c_len, zstd_hdr.version, zstd_hdr.level);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2244,8 +2215,7 @@ snprintf_zstd_header(spa_t *spa, char *blkbuf, size_t buflen,
|
|||
(void) snprintf(blkbuf + strlen(blkbuf),
|
||||
buflen - strlen(blkbuf),
|
||||
" ZSTD:size=%u:version=%u:level=%u:NORMAL",
|
||||
zstd_hdr.c_len, zfs_get_hdrversion(&zstd_hdr),
|
||||
zfs_get_hdrlevel(&zstd_hdr));
|
||||
zstd_hdr.c_len, zstd_hdr.version, zstd_hdr.level);
|
||||
|
||||
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;
|
||||
|
||||
return (err);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -3102,22 +3072,13 @@ dump_znode_sa_xattr(sa_handle_t *hdl)
|
|||
(void) printf("\tSA xattrs: %d bytes, %d entries\n\n",
|
||||
sa_xattr_size, sa_xattr_entries);
|
||||
while ((elem = nvlist_next_nvpair(sa_xattr, elem)) != NULL) {
|
||||
boolean_t can_print = !dump_opt['P'];
|
||||
uchar_t *value;
|
||||
uint_t cnt, idx;
|
||||
|
||||
(void) printf("\t\t%s = ", nvpair_name(elem));
|
||||
nvpair_value_byte_array(elem, &value, &cnt);
|
||||
|
||||
for (idx = 0; idx < cnt; ++idx) {
|
||||
if (!isprint(value[idx])) {
|
||||
can_print = B_FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (idx = 0; idx < cnt; ++idx) {
|
||||
if (can_print)
|
||||
if (isprint(value[idx]))
|
||||
(void) putchar(value[idx]);
|
||||
else
|
||||
(void) printf("\\%3.3o", value[idx]);
|
||||
|
@ -3134,18 +3095,13 @@ dump_znode_symlink(sa_handle_t *hdl)
|
|||
{
|
||||
int sa_symlink_size = 0;
|
||||
char linktarget[MAXPATHLEN];
|
||||
linktarget[0] = '\0';
|
||||
int error;
|
||||
|
||||
error = sa_size(hdl, sa_attr_table[ZPL_SYMLINK], &sa_symlink_size);
|
||||
if (error || sa_symlink_size == 0) {
|
||||
return;
|
||||
}
|
||||
if (sa_symlink_size >= sizeof (linktarget)) {
|
||||
(void) printf("symlink size %d is too large\n",
|
||||
sa_symlink_size);
|
||||
return;
|
||||
}
|
||||
linktarget[sa_symlink_size] = '\0';
|
||||
if (sa_lookup(hdl, sa_attr_table[ZPL_SYMLINK],
|
||||
&linktarget, sa_symlink_size) == 0)
|
||||
(void) printf("\ttarget %s\n", linktarget);
|
||||
|
@ -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 *r = (cksum_record_t *)x2;
|
||||
int arraysize = ARRAY_SIZE(l->cksum.zc_word);
|
||||
int difference = 0;
|
||||
int difference;
|
||||
|
||||
for (int i = 0; i < arraysize; 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:
|
||||
if (s != NULL && *(s + 1) != '\0')
|
||||
return (dump_path_impl(os, child_obj, s + 1, retobj));
|
||||
fallthrough;
|
||||
/*FALLTHROUGH*/
|
||||
case DMU_OT_PLAIN_FILE_CONTENTS:
|
||||
if (retobj != NULL) {
|
||||
*retobj = child_obj;
|
||||
|
@ -4815,7 +4771,7 @@ dump_label(const char *dev)
|
|||
if (nvlist_size(config, &size, NV_ENCODE_XDR) != 0)
|
||||
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 (nvlist_lookup_uint64(config,
|
||||
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);
|
||||
VERIFY0(vdev_metaslab_init(vd, 0));
|
||||
|
||||
vdev_indirect_mapping_t *vim __maybe_unused =
|
||||
vd->vdev_indirect_mapping;
|
||||
vdev_indirect_mapping_t *vim = vd->vdev_indirect_mapping;
|
||||
uint64_t vim_idx = 0;
|
||||
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;
|
||||
c < current_rvd->vdev_children; 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);
|
||||
}
|
||||
|
||||
/* 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
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
|
@ -8343,7 +8281,7 @@ main(int argc, char **argv)
|
|||
zfs_btree_verify_intensity = 3;
|
||||
|
||||
while ((c = getopt(argc, argv,
|
||||
"AbcCdDeEFGhiI:klLmMNo:Op:PqrRsSt:uU:vVx:XYyZ")) != -1) {
|
||||
"AbcCdDeEFGhiI:klLmMo:Op:PqrRsSt:uU:vVx:XYyZ")) != -1) {
|
||||
switch (c) {
|
||||
case 'b':
|
||||
case 'c':
|
||||
|
@ -8357,7 +8295,6 @@ main(int argc, char **argv)
|
|||
case 'l':
|
||||
case 'm':
|
||||
case 'M':
|
||||
case 'N':
|
||||
case 'O':
|
||||
case 'r':
|
||||
case 'R':
|
||||
|
@ -8449,6 +8386,31 @@ main(int argc, char **argv)
|
|||
(void) fprintf(stderr, "-p option requires use of -e\n");
|
||||
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)
|
||||
/*
|
||||
|
@ -8477,18 +8439,13 @@ main(int argc, char **argv)
|
|||
*/
|
||||
spa_load_verify_dryrun = B_TRUE;
|
||||
|
||||
/*
|
||||
* ZDB should have ability to read spacemaps.
|
||||
*/
|
||||
spa_mode_readable_spacemaps = B_TRUE;
|
||||
|
||||
kernel_init(SPA_MODE_READ);
|
||||
|
||||
if (dump_all)
|
||||
verbose = MAX(verbose, 1);
|
||||
|
||||
for (c = 0; c < 256; c++) {
|
||||
if (dump_all && strchr("AeEFklLNOPrRSXy", c) == NULL)
|
||||
if (dump_all && strchr("AeEFklLOPrRSXy", c) == NULL)
|
||||
dump_opt[c] = 1;
|
||||
if (dump_opt[c])
|
||||
dump_opt[c] += verbose;
|
||||
|
@ -8527,7 +8484,6 @@ main(int argc, char **argv)
|
|||
return (dump_path(argv[0], argv[1], NULL));
|
||||
}
|
||||
if (dump_opt['r']) {
|
||||
target_is_spa = B_FALSE;
|
||||
if (argc != 3)
|
||||
usage();
|
||||
dump_opt['v'] = verbose;
|
||||
|
@ -8538,10 +8494,6 @@ main(int argc, char **argv)
|
|||
rewind = ZPOOL_DO_REWIND |
|
||||
(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 ||
|
||||
nvlist_add_uint64(policy, ZPOOL_LOAD_REQUEST_TXG, max_txg) != 0 ||
|
||||
nvlist_add_uint32(policy, ZPOOL_LOAD_REWIND_POLICY, rewind) != 0)
|
||||
|
@ -8560,34 +8512,6 @@ main(int argc, char **argv)
|
|||
targetlen = strlen(target);
|
||||
if (targetlen && target[targetlen - 1] == '/')
|
||||
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 {
|
||||
target_pool = target;
|
||||
}
|
||||
|
@ -8705,27 +8629,13 @@ main(int argc, char **argv)
|
|||
}
|
||||
return (error);
|
||||
} else {
|
||||
target_pool = strdup(target);
|
||||
if (strpbrk(target, "/@") != NULL)
|
||||
*strpbrk(target_pool, "/@") = '\0';
|
||||
|
||||
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) {
|
||||
/*
|
||||
* Use the supplied id to get the name
|
||||
* for open_objset.
|
||||
*/
|
||||
error = spa_open(target_pool, &spa, FTAG);
|
||||
error = spa_open(target, &spa, FTAG);
|
||||
if (error == 0) {
|
||||
error = name_from_objset_id(spa,
|
||||
objset_id, dsname);
|
||||
|
@ -8734,23 +8644,10 @@ retry_lookup:
|
|||
target = dsname;
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (error == 0)
|
||||
error = open_objset(target, FTAG, &os);
|
||||
}
|
||||
if (error == 0)
|
||||
spa = dmu_objset_spa(os);
|
||||
free(target_pool);
|
||||
}
|
||||
}
|
||||
nvlist_free(policy);
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
include $(top_srcdir)/config/Rules.am
|
||||
include $(top_srcdir)/config/Shellcheck.am
|
||||
|
||||
AM_CFLAGS += $(LIBUDEV_CFLAGS) $(LIBUUID_CFLAGS)
|
||||
|
||||
SUBDIRS = zed.d
|
||||
SHELLCHECKDIRS = $(SUBDIRS)
|
||||
|
||||
sbin_PROGRAMS = zed
|
||||
|
||||
|
@ -45,7 +43,7 @@ zed_LDADD = \
|
|||
$(abs_top_builddir)/lib/libnvpair/libnvpair.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
|
||||
|
||||
EXTRA_DIST = agents/README.md
|
||||
|
|
|
@ -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_attributes = NULL;
|
||||
sev.sigev_value.sival_ptr = ftp;
|
||||
sev.sigev_signo = 0;
|
||||
|
||||
timer_create(CLOCK_REALTIME, &sev, &ftp->ft_tid);
|
||||
timer_settime(ftp->ft_tid, 0, &its, NULL);
|
||||
|
|
|
@ -80,7 +80,6 @@ zfs_agent_iter_vdev(zpool_handle_t *zhp, nvlist_t *nvl, void *arg)
|
|||
char *path = NULL;
|
||||
uint_t c, children;
|
||||
nvlist_t **child;
|
||||
uint64_t vdev_guid;
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
for (c = 0; c < children; c++) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -110,7 +109,7 @@ zfs_agent_iter_vdev(zpool_handle_t *zhp, nvlist_t *nvl, void *arg)
|
|||
&child, &children) == 0) {
|
||||
for (c = 0; c < children; c++) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -127,21 +126,6 @@ zfs_agent_iter_vdev(zpool_handle_t *zhp, nvlist_t *nvl, void *arg)
|
|||
&gsp->gs_vdev_expandtime);
|
||||
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);
|
||||
}
|
||||
|
@ -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 (gsp->gs_vdev_guid && gsp->gs_devid) {
|
||||
if (gsp->gs_vdev_guid) {
|
||||
(void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
|
||||
&gsp->gs_pool_guid);
|
||||
}
|
||||
|
||||
zpool_close(zhp);
|
||||
return (gsp->gs_devid != NULL && gsp->gs_vdev_guid != 0);
|
||||
return (gsp->gs_vdev_guid != 0);
|
||||
}
|
||||
|
||||
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;
|
||||
guid_search_t search = { 0 };
|
||||
device_type_t devtype = DEVICE_TYPE_PRIMARY;
|
||||
char *devid = NULL;
|
||||
|
||||
class = "resource.fs.zfs.removed";
|
||||
subclass = "";
|
||||
|
||||
(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_VDEV_GUID, &vdev_guid);
|
||||
|
||||
|
@ -227,24 +209,20 @@ zfs_agent_post_event(const char *class, const char *subclass, nvlist_t *nvl)
|
|||
(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
|
||||
* ZFS_EV_POOL_GUID may be missing so find them.
|
||||
*/
|
||||
if (devid == NULL || pool_guid == 0 || vdev_guid == 0) {
|
||||
if (devid == NULL)
|
||||
search.gs_vdev_guid = vdev_guid;
|
||||
else
|
||||
search.gs_devid = devid;
|
||||
zpool_iter(g_zfs_hdl, zfs_agent_iter_pool, &search);
|
||||
if (devid == NULL)
|
||||
devid = search.gs_devid;
|
||||
if (pool_guid == 0)
|
||||
pool_guid = search.gs_pool_guid;
|
||||
if (vdev_guid == 0)
|
||||
vdev_guid = search.gs_vdev_guid;
|
||||
devtype = search.gs_vdev_type;
|
||||
if (pool_guid == 0 || vdev_guid == 0) {
|
||||
if ((nvlist_lookup_string(nvl, DEV_IDENTIFIER,
|
||||
&search.gs_devid) == 0) &&
|
||||
(zpool_iter(g_zfs_hdl, zfs_agent_iter_pool, &search)
|
||||
== 1)) {
|
||||
if (pool_guid == 0)
|
||||
pool_guid = search.gs_pool_guid;
|
||||
if (vdev_guid == 0)
|
||||
vdev_guid = search.gs_vdev_guid;
|
||||
devtype = search.gs_vdev_type;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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) {
|
||||
zed_log_msg(LOG_INFO, "agent post event: ignoring '%s' "
|
||||
"for recently expanded device '%s'", EC_DEV_REMOVE,
|
||||
devid);
|
||||
fnvlist_free(payload);
|
||||
free(event);
|
||||
search.gs_devid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -416,7 +392,6 @@ zfs_agent_init(libzfs_handle_t *zfs_hdl)
|
|||
list_destroy(&agent_events);
|
||||
zed_log_die("Failed to initialize agents");
|
||||
}
|
||||
pthread_setname_np(g_agents_tid, "agents");
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
#include <sys/fs/zfs.h>
|
||||
#include <sys/fm/protocol.h>
|
||||
#include <sys/fm/fs/zfs.h>
|
||||
#include <sys/zio.h>
|
||||
|
||||
#include "zfs_agents.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))) {
|
||||
char *failmode = NULL;
|
||||
boolean_t checkremove = B_FALSE;
|
||||
uint32_t pri = 0;
|
||||
int32_t flags = 0;
|
||||
|
||||
/*
|
||||
* If this is a checksum or I/O error, then toss it into the
|
||||
|
@ -798,23 +795,6 @@ zfs_fm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
|
|||
checkremove = B_TRUE;
|
||||
} else if (fmd_nvl_class_match(hdl, nvl,
|
||||
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_CHECKSUM))) {
|
||||
/*
|
||||
* We ignore ereports for checksum errors generated by
|
||||
* scrub/resilver I/O to avoid potentially further
|
||||
* degrading the pool while it's being repaired.
|
||||
*/
|
||||
if (((nvlist_lookup_uint32(nvl,
|
||||
FM_EREPORT_PAYLOAD_ZFS_ZIO_PRIORITY, &pri) == 0) &&
|
||||
(pri == ZIO_PRIORITY_SCRUB ||
|
||||
pri == ZIO_PRIORITY_REBUILD)) ||
|
||||
((nvlist_lookup_int32(nvl,
|
||||
FM_EREPORT_PAYLOAD_ZFS_ZIO_FLAGS, &flags) == 0) &&
|
||||
(flags & (ZIO_FLAG_SCRUB | ZIO_FLAG_RESILVER)))) {
|
||||
fmd_hdl_debug(hdl, "ignoring '%s' for "
|
||||
"scrub/resilver I/O", class);
|
||||
return;
|
||||
}
|
||||
|
||||
if (zcp->zc_data.zc_serd_checksum[0] == '\0') {
|
||||
zfs_serd_name(zcp->zc_data.zc_serd_checksum,
|
||||
pool_guid, vdev_guid, "checksum");
|
||||
|
|
|
@ -141,17 +141,6 @@ zfs_unavail_pool(zpool_handle_t *zhp, void *data)
|
|||
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
|
||||
* 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;
|
||||
pendingdev_t *device;
|
||||
uint64_t wholedisk = 0ULL;
|
||||
uint64_t offline = 0ULL, faulted = 0ULL;
|
||||
uint64_t offline = 0ULL;
|
||||
uint64_t guid = 0ULL;
|
||||
uint64_t is_spare = 0;
|
||||
char *physpath = NULL, *new_devid = NULL, *enc_sysfs_path = NULL;
|
||||
char rawpath[PATH_MAX], fullpath[PATH_MAX];
|
||||
char devpath[PATH_MAX];
|
||||
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_mpath_wholedisk = B_FALSE;
|
||||
uint_t c;
|
||||
vdev_stat_t *vs;
|
||||
char **lines = NULL;
|
||||
int lines_cnt = 0;
|
||||
|
||||
if (nvlist_lookup_string(vdev, ZPOOL_CONFIG_PATH, &path) != 0)
|
||||
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);
|
||||
|
||||
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,
|
||||
&enc_sysfs_path);
|
||||
|
||||
(void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK, &wholedisk);
|
||||
(void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_OFFLINE, &offline);
|
||||
(void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_FAULTED, &faulted);
|
||||
|
||||
(void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_GUID, &guid);
|
||||
(void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_IS_SPARE, &is_spare);
|
||||
|
||||
/*
|
||||
* Special case:
|
||||
*
|
||||
* We've seen times where a disk won't have a ZPOOL_CONFIG_PHYS_PATH
|
||||
* entry in their config. For example, on this force-faulted disk:
|
||||
*
|
||||
* children[0]:
|
||||
* type: 'disk'
|
||||
* id: 0
|
||||
* guid: 14309659774640089719
|
||||
* path: '/dev/disk/by-vdev/L28'
|
||||
* whole_disk: 0
|
||||
* DTL: 654
|
||||
* create_txg: 4
|
||||
* com.delphix:vdev_zap_leaf: 1161
|
||||
* faulted: 1
|
||||
* aux_state: 'external'
|
||||
* children[1]:
|
||||
* type: 'disk'
|
||||
* id: 1
|
||||
* guid: 16002508084177980912
|
||||
* path: '/dev/disk/by-vdev/L29'
|
||||
* devid: 'dm-uuid-mpath-35000c500a61d68a3'
|
||||
* phys_path: 'L29'
|
||||
* vdev_enc_sysfs_path: '/sys/class/enclosure/0:0:1:0/SLOT 30 32'
|
||||
* whole_disk: 0
|
||||
* DTL: 1028
|
||||
* create_txg: 4
|
||||
* com.delphix:vdev_zap_leaf: 131
|
||||
*
|
||||
* If the disk's path is a /dev/disk/by-vdev/ path, then we can infer
|
||||
* the ZPOOL_CONFIG_PHYS_PATH from the by-vdev disk name.
|
||||
*/
|
||||
if (physpath == NULL && path != NULL) {
|
||||
/* If path begins with "/dev/disk/by-vdev/" ... */
|
||||
if (strncmp(path, DEV_BYVDEV_PATH,
|
||||
strlen(DEV_BYVDEV_PATH)) == 0) {
|
||||
/* Set physpath to the char after "/dev/disk/by-vdev" */
|
||||
physpath = &path[strlen(DEV_BYVDEV_PATH)];
|
||||
}
|
||||
}
|
||||
if (offline)
|
||||
return; /* don't intervene if it was taken offline */
|
||||
|
||||
/*
|
||||
* 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);
|
||||
is_dm = zfs_dev_is_dm(path);
|
||||
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', "
|
||||
"(guid %llu)",
|
||||
zpool_get_name(zhp), path,
|
||||
physpath ? physpath : "NULL",
|
||||
wholedisk ? "is" : "not",
|
||||
is_mpath_wholedisk? "is" : "not",
|
||||
labeled ? "is" : "not",
|
||||
enc_sysfs_path,
|
||||
" wholedisk %d, %s dm (guid %llu)", zpool_get_name(zhp), path,
|
||||
physpath ? physpath : "NULL", wholedisk, is_dm ? "is" : "not",
|
||||
(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.
|
||||
*/
|
||||
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_DEGRADED)) {
|
||||
zed_log_msg(LOG_INFO,
|
||||
" zpool_vdev_online: vdev '%s' ('%s') is "
|
||||
"%s", fullpath, physpath, (newstate == VDEV_STATE_HEALTHY) ?
|
||||
zed_log_msg(LOG_INFO, " zpool_vdev_online: vdev %s is %s",
|
||||
fullpath, (newstate == VDEV_STATE_HEALTHY) ?
|
||||
"HEALTHY" : "DEGRADED");
|
||||
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.
|
||||
*/
|
||||
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,
|
||||
&newstate);
|
||||
zed_log_msg(LOG_INFO, "Pool's autoreplace is not enabled or "
|
||||
"not a blank disk for '%s' ('%s')", fullpath,
|
||||
physpath);
|
||||
"not a whole disk for '%s'", fullpath);
|
||||
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",
|
||||
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)",
|
||||
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) &&
|
||||
(vs->vs_state != VDEV_STATE_FAULTED) &&
|
||||
(vs->vs_state != VDEV_STATE_CANT_OPEN)) {
|
||||
zed_log_msg(LOG_INFO, " not autoreplacing since disk isn't in "
|
||||
"a bad state (currently %d)", vs->vs_state);
|
||||
return;
|
||||
}
|
||||
|
||||
nvlist_lookup_string(vdev, "new_devid", &new_devid);
|
||||
|
||||
if (is_mpath_wholedisk) {
|
||||
if (is_dm) {
|
||||
/* 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) {
|
||||
/*
|
||||
* 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
|
||||
* write out the label.
|
||||
*/
|
||||
if (zpool_prepare_and_label_disk(g_zfshdl, zhp, leafname,
|
||||
vdev, "autoreplace", &lines, &lines_cnt) != 0) {
|
||||
zed_log_msg(LOG_INFO,
|
||||
" zpool_prepare_and_label_disk: could not "
|
||||
if (zpool_label_disk(g_zfshdl, zhp, leafname) != 0) {
|
||||
zed_log_msg(LOG_INFO, " zpool_label_disk: could not "
|
||||
"label '%s' (%s)", leafname,
|
||||
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,
|
||||
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);
|
||||
}
|
||||
|
||||
libzfs_free_str_array(lines, lines_cnt);
|
||||
|
||||
/*
|
||||
* Construct the root vdev to pass to zpool_vdev_attach(). While adding
|
||||
* the entire vdev structure is harmless, we construct a reduced set of
|
||||
|
@ -573,9 +463,7 @@ typedef struct dev_data {
|
|||
boolean_t dd_islabeled;
|
||||
uint64_t dd_pool_guid;
|
||||
uint64_t dd_vdev_guid;
|
||||
uint64_t dd_new_vdev_guid;
|
||||
const char *dd_new_devid;
|
||||
uint64_t dd_num_spares;
|
||||
} dev_data_t;
|
||||
|
||||
static void
|
||||
|
@ -585,8 +473,6 @@ zfs_iter_vdev(zpool_handle_t *zhp, nvlist_t *nvl, void *data)
|
|||
char *path = NULL;
|
||||
uint_t c, children;
|
||||
nvlist_t **child;
|
||||
uint64_t guid = 0;
|
||||
uint64_t isspare = 0;
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
if (dp->dd_found && dp->dd_num_spares == 0)
|
||||
if (dp->dd_found)
|
||||
return;
|
||||
(void) nvlist_lookup_uint64(nvl, ZPOOL_CONFIG_GUID, &guid);
|
||||
|
||||
/*
|
||||
* Match by GUID if available otherwise fallback to devid or physical
|
||||
*/
|
||||
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;
|
||||
}
|
||||
zed_log_msg(LOG_INFO, " zfs_iter_vdev: matched on %llu", guid);
|
||||
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
|
||||
* the partition suffix. An exact match will be present in
|
||||
* 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 ||
|
||||
strcmp(dp->dd_compare, path) != 0) {
|
||||
strcmp(dp->dd_compare, path) != 0)
|
||||
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",
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -699,8 +571,6 @@ zfs_iter_pool(zpool_handle_t *zhp, void *data)
|
|||
ZPOOL_CONFIG_VDEV_TREE, &nvl);
|
||||
zfs_iter_vdev(zhp, nvl, data);
|
||||
}
|
||||
} else {
|
||||
zed_log_msg(LOG_INFO, "%s: no config\n", __func__);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -724,9 +594,7 @@ zfs_iter_pool(zpool_handle_t *zhp, void *data)
|
|||
}
|
||||
|
||||
zpool_close(zhp);
|
||||
|
||||
/* cease iteration after a match */
|
||||
return (dp->dd_found && dp->dd_num_spares == 0);
|
||||
return (dp->dd_found); /* cease iteration after a match */
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -735,7 +603,7 @@ zfs_iter_pool(zpool_handle_t *zhp, void *data)
|
|||
*/
|
||||
static boolean_t
|
||||
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 };
|
||||
|
||||
|
@ -745,73 +613,6 @@ devphys_iter(const char *physical, const char *devid, zfs_process_func_t func,
|
|||
data.dd_found = B_FALSE;
|
||||
data.dd_islabeled = is_slice;
|
||||
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);
|
||||
|
||||
|
@ -839,27 +640,6 @@ devid_iter(const char *devid, zfs_process_func_t func, boolean_t is_slice)
|
|||
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.
|
||||
*
|
||||
|
@ -882,21 +662,16 @@ guid_iter(uint64_t pool_guid, uint64_t vdev_guid, const char *devid,
|
|||
static int
|
||||
zfs_deliver_add(nvlist_t *nvl, boolean_t is_lofi)
|
||||
{
|
||||
char *devpath = NULL, *devid = NULL;
|
||||
uint64_t pool_guid = 0, vdev_guid = 0;
|
||||
char *devpath = NULL, *devid;
|
||||
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) {
|
||||
zed_log_msg(LOG_INFO, "%s: no dev identifier\n", __func__);
|
||||
if (nvlist_lookup_string(nvl, DEV_IDENTIFIER, &devid) != 0)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
(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);
|
||||
|
||||
|
@ -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:
|
||||
* 1. ZPOOL_CONFIG_DEVID (identifies the unique disk)
|
||||
* 2. ZPOOL_CONFIG_PHYS_PATH (identifies disk physical location).
|
||||
* 3. ZPOOL_CONFIG_GUID (identifies unique vdev).
|
||||
* 4. ZPOOL_CONFIG_PATH for /dev/disk/by-vdev devices only (since
|
||||
* by-vdev paths represent physical paths).
|
||||
*
|
||||
* For disks, we only want to pay attention to vdevs marked as whole
|
||||
* disks or are a multipath device.
|
||||
*/
|
||||
if (devid_iter(devid, zfs_process_add, is_slice))
|
||||
return (0);
|
||||
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);
|
||||
}
|
||||
if (!devid_iter(devid, zfs_process_add, is_slice) && devpath != NULL)
|
||||
(void) devphys_iter(devpath, devid, zfs_process_add, is_slice);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
@ -960,96 +719,21 @@ zfs_deliver_check(nvlist_t *nvl)
|
|||
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
|
||||
zfsdle_vdev_online(zpool_handle_t *zhp, void *data)
|
||||
{
|
||||
char *devname = data;
|
||||
boolean_t avail_spare, l2cache;
|
||||
nvlist_t *udev_nvl = data;
|
||||
nvlist_t *tgt;
|
||||
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'",
|
||||
devname, zpool_get_name(zhp));
|
||||
|
||||
if ((tgt = zpool_find_vdev_by_physpath(zhp, devname,
|
||||
&avail_spare, &l2cache, NULL)) != NULL) {
|
||||
char *path, fullpath[MAXPATHLEN];
|
||||
uint64_t wholedisk = 0;
|
||||
uint64_t wholedisk;
|
||||
|
||||
error = nvlist_lookup_string(tgt, ZPOOL_CONFIG_PATH, &path);
|
||||
if (error) {
|
||||
|
@ -1057,8 +741,10 @@ zfsdle_vdev_online(zpool_handle_t *zhp, void *data)
|
|||
return (0);
|
||||
}
|
||||
|
||||
(void) nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK,
|
||||
error = nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK,
|
||||
&wholedisk);
|
||||
if (error)
|
||||
wholedisk = 0;
|
||||
|
||||
if (wholedisk) {
|
||||
path = strrchr(path, '/');
|
||||
|
@ -1092,75 +778,12 @@ zfsdle_vdev_online(zpool_handle_t *zhp, void *data)
|
|||
vdev_state_t newstate;
|
||||
|
||||
if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL) {
|
||||
/*
|
||||
* If this disk size has not changed, then
|
||||
* there's no need to do an autoexpand. To
|
||||
* check we look at the disk's size in its
|
||||
* config, and compare it to the disk size
|
||||
* 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);
|
||||
}
|
||||
error = zpool_vdev_online(zhp, fullpath, 0,
|
||||
&newstate);
|
||||
zed_log_msg(LOG_INFO, "zfsdle_vdev_online: "
|
||||
"setting device '%s' to ONLINE state "
|
||||
"in pool '%s': %d", fullpath,
|
||||
zpool_get_name(zhp), error);
|
||||
}
|
||||
}
|
||||
zpool_close(zhp);
|
||||
|
@ -1188,11 +811,10 @@ zfs_deliver_dle(nvlist_t *nvl)
|
|||
strlcpy(name, devname, MAXPATHLEN);
|
||||
zfs_append_partition(name, MAXPATHLEN);
|
||||
} else {
|
||||
sprintf(name, "unknown");
|
||||
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 "
|
||||
"found", name);
|
||||
return (1);
|
||||
|
@ -1278,7 +900,7 @@ zfs_enum_pools(void *arg)
|
|||
* For now, each agent has its own libzfs instance
|
||||
*/
|
||||
int
|
||||
zfs_slm_init(void)
|
||||
zfs_slm_init()
|
||||
{
|
||||
if ((g_zfshdl = libzfs_init()) == NULL)
|
||||
return (-1);
|
||||
|
@ -1296,7 +918,6 @@ zfs_slm_init(void)
|
|||
return (-1);
|
||||
}
|
||||
|
||||
pthread_setname_np(g_zfs_tid, "enum-pools");
|
||||
list_create(&g_device_list, sizeof (struct pendingdev),
|
||||
offsetof(struct pendingdev, pd_node));
|
||||
|
||||
|
@ -1304,7 +925,7 @@ zfs_slm_init(void)
|
|||
}
|
||||
|
||||
void
|
||||
zfs_slm_fini(void)
|
||||
zfs_slm_fini()
|
||||
{
|
||||
unavailpool_t *pool;
|
||||
pendingdev_t *device;
|
||||
|
|
|
@ -40,7 +40,6 @@
|
|||
#include <sys/fm/fs/zfs.h>
|
||||
#include <libzfs.h>
|
||||
#include <string.h>
|
||||
#include <libgen.h>
|
||||
|
||||
#include "zfs_agents.h"
|
||||
#include "fmd_api.h"
|
||||
|
@ -75,8 +74,6 @@ typedef struct find_cbdata {
|
|||
uint64_t cb_guid;
|
||||
zpool_handle_t *cb_zhp;
|
||||
nvlist_t *cb_vdev;
|
||||
uint64_t cb_vdev_guid;
|
||||
uint64_t cb_num_spares;
|
||||
} find_cbdata_t;
|
||||
|
||||
static int
|
||||
|
@ -142,64 +139,6 @@ find_vdev(libzfs_handle_t *zhdl, nvlist_t *nv, uint64_t search_guid)
|
|||
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.
|
||||
*/
|
||||
|
@ -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;
|
||||
boolean_t fault_device, degrade_device;
|
||||
boolean_t is_repair;
|
||||
boolean_t l2arc = B_FALSE;
|
||||
boolean_t spare = B_FALSE;
|
||||
char *scheme;
|
||||
nvlist_t *vdev = NULL;
|
||||
char *uuid;
|
||||
|
@ -385,8 +322,6 @@ zfs_retire_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl,
|
|||
boolean_t is_disk;
|
||||
vdev_aux_t aux;
|
||||
uint64_t state = 0;
|
||||
vdev_stat_t *vs;
|
||||
unsigned int c;
|
||||
|
||||
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 *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,
|
||||
&pool_guid) != 0)
|
||||
&pool_guid) != 0 ||
|
||||
nvlist_lookup_uint64(nvl, FM_EREPORT_PAYLOAD_ZFS_VDEV_GUID,
|
||||
&vdev_guid) != 0)
|
||||
return;
|
||||
|
||||
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);
|
||||
|
||||
nvlist_lookup_uint64_array(vdev, ZPOOL_CONFIG_VDEV_STATS,
|
||||
(uint64_t **)&vs, &c);
|
||||
|
||||
/*
|
||||
* If state removed is requested for already removed vdev,
|
||||
* its a loopback event from spa_async_remove(). Just
|
||||
* ignore it.
|
||||
*/
|
||||
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)) {
|
||||
/* Can't replace l2arc with a spare: offline the device */
|
||||
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);
|
||||
zpool_vdev_offline(zhp, devname, B_TRUE);
|
||||
} else if (!fmd_prop_get_int32(hdl, "spare_on_remove") ||
|
||||
replace_with_spare(hdl, zhp, vdev) == B_FALSE) {
|
||||
/* Could not handle with spare */
|
||||
fmd_hdl_debug(hdl, "no spare for '%s'", devname);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
||||
* 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
|
||||
* 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");
|
||||
|
||||
sa.sa_flags = SA_RESTART;
|
||||
|
||||
sa.sa_handler = SIG_IGN;
|
||||
|
||||
if (sigaction(SIGPIPE, &sa, NULL) < 0)
|
||||
zed_log_die("Failed to ignore SIGPIPE");
|
||||
|
||||
|
@ -75,10 +75,6 @@ _setup_sig_handlers(void)
|
|||
sa.sa_handler = _hup_handler;
|
||||
if (sigaction(SIGHUP, &sa, NULL) < 0)
|
||||
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
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct zed_conf zcp;
|
||||
struct zed_conf *zcp;
|
||||
uint64_t saved_eid;
|
||||
int64_t saved_etime[2];
|
||||
|
||||
zed_log_init(argv[0]);
|
||||
zed_log_stderr_open(LOG_NOTICE);
|
||||
zed_conf_init(&zcp);
|
||||
zed_conf_parse_opts(&zcp, argc, argv);
|
||||
if (zcp.do_verbose)
|
||||
zcp = zed_conf_create();
|
||||
zed_conf_parse_opts(zcp, argc, argv);
|
||||
if (zcp->do_verbose)
|
||||
zed_log_stderr_open(LOG_INFO);
|
||||
|
||||
if (geteuid() != 0)
|
||||
zed_log_die("Must be run as root");
|
||||
|
||||
zed_conf_parse_file(zcp);
|
||||
|
||||
zed_file_close_from(STDERR_FILENO + 1);
|
||||
|
||||
(void) umask(0);
|
||||
|
@ -237,32 +235,32 @@ main(int argc, char *argv[])
|
|||
if (chdir("/") < 0)
|
||||
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);
|
||||
|
||||
if (!zcp.do_foreground) {
|
||||
if (!zcp->do_foreground) {
|
||||
_start_daemonize();
|
||||
zed_log_syslog_open(LOG_DAEMON);
|
||||
}
|
||||
_setup_sig_handlers();
|
||||
|
||||
if (zcp.do_memlock)
|
||||
if (zcp->do_memlock)
|
||||
_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);
|
||||
|
||||
if (!zcp.do_foreground)
|
||||
if (!zcp->do_foreground)
|
||||
_finish_daemonize();
|
||||
|
||||
zed_log_msg(LOG_NOTICE,
|
||||
"ZFS Event Daemon %s-%s (PID %d)",
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
idle:
|
||||
|
@ -271,38 +269,38 @@ idle:
|
|||
* successful.
|
||||
*/
|
||||
do {
|
||||
if (!zed_event_init(&zcp))
|
||||
if (!zed_event_init(zcp))
|
||||
break;
|
||||
/* Wait for some time and try again. tunable? */
|
||||
sleep(30);
|
||||
} while (!_got_exit && zcp.do_idle);
|
||||
} while (!_got_exit && zcp->do_idle);
|
||||
|
||||
if (_got_exit)
|
||||
goto out;
|
||||
|
||||
zed_event_seek(&zcp, saved_eid, saved_etime);
|
||||
zed_event_seek(zcp, saved_eid, saved_etime);
|
||||
|
||||
while (!_got_exit) {
|
||||
int rv;
|
||||
if (_got_hup) {
|
||||
_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) */
|
||||
if (rv != 0)
|
||||
if (rv == ENODEV)
|
||||
break;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
out:
|
||||
zed_conf_destroy(&zcp);
|
||||
zed_conf_destroy(zcp);
|
||||
zed_log_fini();
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
include $(top_srcdir)/config/Rules.am
|
||||
include $(top_srcdir)/config/Substfiles.am
|
||||
include $(top_srcdir)/config/Shellcheck.am
|
||||
|
||||
EXTRA_DIST += README
|
||||
|
||||
|
@ -21,7 +20,6 @@ dist_zedexec_SCRIPTS = \
|
|||
scrub_finish-notify.sh \
|
||||
statechange-led.sh \
|
||||
statechange-notify.sh \
|
||||
statechange-slot_off.sh \
|
||||
vdev_clear-led.sh \
|
||||
vdev_attach-led.sh \
|
||||
pool_import-led.sh \
|
||||
|
@ -40,7 +38,6 @@ zedconfdefaults = \
|
|||
scrub_finish-notify.sh \
|
||||
statechange-led.sh \
|
||||
statechange-notify.sh \
|
||||
statechange-slot_off.sh \
|
||||
vdev_clear-led.sh \
|
||||
vdev_attach-led.sh \
|
||||
pool_import-led.sh \
|
||||
|
@ -54,6 +51,3 @@ install-data-hook:
|
|||
ln -s "$(zedexecdir)/$${f}" "$(DESTDIR)$(zedconfdir)"; \
|
||||
done
|
||||
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}"'
|
||||
|
|
|
@ -12,11 +12,15 @@
|
|||
|
||||
zed_exit_if_ignoring_this_event
|
||||
|
||||
zed_lock "${ZED_DEBUG_LOG}"
|
||||
{
|
||||
printenv | sort
|
||||
echo
|
||||
} 1>&"${ZED_FLOCK_FD}"
|
||||
zed_unlock "${ZED_DEBUG_LOG}"
|
||||
lockfile="$(basename -- "${ZED_DEBUG_LOG}").lock"
|
||||
|
||||
umask 077
|
||||
zed_lock "${lockfile}"
|
||||
exec >> "${ZED_DEBUG_LOG}"
|
||||
|
||||
printenv | sort
|
||||
echo
|
||||
|
||||
exec >&-
|
||||
zed_unlock "${lockfile}"
|
||||
exit 0
|
||||
|
|
|
@ -21,7 +21,7 @@ if [ "${ZED_SYSLOG_DISPLAY_GUIDS}" = "1" ]; then
|
|||
[ -n "${ZEVENT_VDEV_GUID}" ] && msg="${msg} vdev_guid=${ZEVENT_VDEV_GUID}"
|
||||
else
|
||||
[ -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
|
||||
|
||||
# log pool state if state is anything other than 'ACTIVE'
|
||||
|
@ -42,7 +42,6 @@ fi
|
|||
msg="${msg} delay=$((ZEVENT_ZIO_DELAY / 1000000))ms"
|
||||
|
||||
# list the bookmark data together
|
||||
# shellcheck disable=SC2153
|
||||
[ -n "${ZEVENT_ZIO_OBJSET}" ] && \
|
||||
msg="${msg} bookmark=${ZEVENT_ZIO_OBJSET}:${ZEVENT_ZIO_OBJECT}:${ZEVENT_ZIO_LEVEL}:${ZEVENT_ZIO_BLKID}"
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ zed_rate_limit "${rate_limit_tag}" || exit 3
|
|||
|
||||
umask 077
|
||||
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
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
# 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}"
|
||||
zed_rate_limit "${rate_limit_tag}" "${rate_limit_interval}" || exit 3
|
||||
|
||||
|
@ -31,7 +31,7 @@ umask 077
|
|||
pool_str="${ZEVENT_POOL:+" for ${ZEVENT_POOL}"}"
|
||||
host_str=" on $(hostname)"
|
||||
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
|
||||
|
|
|
@ -3,8 +3,9 @@
|
|||
# Track changes to enumerated pools for use in early-boot
|
||||
set -ef
|
||||
|
||||
FSLIST="@sysconfdir@/zfs/zfs-list.cache/${ZEVENT_POOL}"
|
||||
FSLIST_TMP="@runstatedir@/zfs-list.cache@${ZEVENT_POOL}"
|
||||
FSLIST_DIR="@sysconfdir@/zfs/zfs-list.cache"
|
||||
FSLIST_TMP="@runstatedir@/zfs-list.cache.new"
|
||||
FSLIST="${FSLIST_DIR}/${ZEVENT_POOL}"
|
||||
|
||||
# If the pool specific cache file is not writeable, abort
|
||||
[ -w "${FSLIST}" ] || exit 0
|
||||
|
@ -13,20 +14,20 @@ FSLIST_TMP="@runstatedir@/zfs-list.cache@${ZEVENT_POOL}"
|
|||
. "${ZED_ZEDLET_DIR}/zed-functions.sh"
|
||||
|
||||
[ "$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
|
||||
[ "${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
|
||||
abort_alter() {
|
||||
zed_log_msg "Error updating zfs-list.cache for ${ZEVENT_POOL}!"
|
||||
zed_unlock "${FSLIST}"
|
||||
zed_log_msg "Error updating zfs-list.cache!"
|
||||
zed_unlock zfs-list
|
||||
}
|
||||
|
||||
finished() {
|
||||
zed_unlock "${FSLIST}"
|
||||
zed_unlock zfs-list
|
||||
trap - EXIT
|
||||
exit 0
|
||||
}
|
||||
|
@ -36,7 +37,7 @@ case "${ZEVENT_HISTORY_INTERNAL_NAME}" in
|
|||
;;
|
||||
|
||||
export)
|
||||
zed_lock "${FSLIST}"
|
||||
zed_lock zfs-list
|
||||
trap abort_alter EXIT
|
||||
echo > "${FSLIST}"
|
||||
finished
|
||||
|
@ -62,7 +63,7 @@ case "${ZEVENT_HISTORY_INTERNAL_NAME}" in
|
|||
;;
|
||||
esac
|
||||
|
||||
zed_lock "${FSLIST}"
|
||||
zed_lock zfs-list
|
||||
trap abort_alter EXIT
|
||||
|
||||
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}"
|
||||
|
||||
# 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}"
|
||||
|
||||
finished
|
||||
|
|
|
@ -41,7 +41,7 @@ fi
|
|||
|
||||
umask 077
|
||||
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
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
#!/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 its LED off when it's back ONLINE again.
|
||||
# Turn the VDEV's fault LED on if it becomes FAULTED, DEGRADED or UNAVAIL.
|
||||
# Turn the LED off when it's back ONLINE again.
|
||||
#
|
||||
# This script run in two basic modes:
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# Exit codes:
|
||||
|
@ -29,8 +29,7 @@
|
|||
[ -f "${ZED_ZEDLET_DIR}/zed.rc" ] && . "${ZED_ZEDLET_DIR}/zed.rc"
|
||||
. "${ZED_ZEDLET_DIR}/zed-functions.sh"
|
||||
|
||||
if [ ! -d /sys/class/enclosure ] && [ ! -d /sys/bus/pci/slots ] ; then
|
||||
# No JBOD enclosure or NVMe slots
|
||||
if [ ! -d /sys/class/enclosure ] ; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
@ -60,10 +59,6 @@ check_and_set_led()
|
|||
file="$1"
|
||||
val="$2"
|
||||
|
||||
if [ -z "$val" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ ! -e "$file" ] ; then
|
||||
return 3
|
||||
fi
|
||||
|
@ -71,11 +66,11 @@ check_and_set_led()
|
|||
# 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
|
||||
# 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
|
||||
# 'fault' entry always causes a SES command, even if the
|
||||
# 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,
|
||||
# it will return 2. Treat all non-zero values as 1 for
|
||||
|
@ -90,84 +85,27 @@ check_and_set_led()
|
|||
else
|
||||
break
|
||||
fi
|
||||
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
|
||||
done
|
||||
}
|
||||
|
||||
state_to_val()
|
||||
{
|
||||
state="$1"
|
||||
case "$state" in
|
||||
FAULTED|DEGRADED|UNAVAIL)
|
||||
echo 1
|
||||
;;
|
||||
ONLINE)
|
||||
echo 0
|
||||
;;
|
||||
esac
|
||||
if [ "$state" = "FAULTED" ] || [ "$state" = "DEGRADED" ] || \
|
||||
[ "$state" = "UNAVAIL" ] ; then
|
||||
echo 1
|
||||
elif [ "$state" = "ONLINE" ] ; then
|
||||
echo 0
|
||||
fi
|
||||
}
|
||||
|
||||
# process_pool ([pool])
|
||||
#
|
||||
# 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
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
# process_pool (pool)
|
||||
#
|
||||
# Iterate through a pool and set the vdevs' enclosure slot LEDs to
|
||||
# those vdevs' state.
|
||||
# Iterate through a pool (or pools) and set the VDEV's enclosure slot LEDs to
|
||||
# the VDEV's state.
|
||||
#
|
||||
# Arguments
|
||||
# pool: Pool name.
|
||||
# pool: Optional pool name. If not specified, iterate though all pools.
|
||||
#
|
||||
# Return
|
||||
# 0 on success, 3 on missing sysfs path
|
||||
|
@ -175,27 +113,19 @@ nvme_dev_to_slot()
|
|||
process_pool()
|
||||
{
|
||||
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
|
||||
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
|
||||
current_val=1
|
||||
|
@ -206,33 +136,40 @@ process_pool()
|
|||
continue
|
||||
fi
|
||||
|
||||
led_path=$(path_to_led "$vdev_enc_sysfs_path")
|
||||
if [ ! -e "$led_path" ] ; then
|
||||
rc=3
|
||||
zed_log_msg "vdev $vdev '$led_path' doesn't exist"
|
||||
continue
|
||||
if [ ! -e "$vdev_enc_sysfs_path/fault" ] ; then
|
||||
#shellcheck disable=SC2030
|
||||
rc=1
|
||||
zed_log_msg "vdev $vdev '$file/fault' doesn't exist"
|
||||
continue;
|
||||
fi
|
||||
|
||||
val=$(state_to_val "$state")
|
||||
|
||||
if [ "$current_val" = "$val" ] ; then
|
||||
# LED is already set correctly
|
||||
continue
|
||||
continue;
|
||||
fi
|
||||
|
||||
if ! check_and_set_led "$led_path" "$val"; then
|
||||
rc=3
|
||||
if ! check_and_set_led "$vdev_enc_sysfs_path/fault" "$val"; then
|
||||
rc=1
|
||||
fi
|
||||
|
||||
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
|
||||
# Got a statechange for an individual vdev
|
||||
# Got a statechange for an individual VDEV
|
||||
val=$(state_to_val "$ZEVENT_VDEV_STATE_STR")
|
||||
vdev=$(basename "$ZEVENT_VDEV_PATH")
|
||||
ledpath=$(path_to_led "$ZEVENT_VDEV_ENC_SYSFS_PATH")
|
||||
check_and_set_led "$ledpath" "$val"
|
||||
check_and_set_led "$ZEVENT_VDEV_ENC_SYSFS_PATH/fault" "$val"
|
||||
else
|
||||
# Process the entire pool
|
||||
poolname=$(zed_guid_to_pool "$ZEVENT_POOL_GUID")
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
# Send notification in response to a fault induced statechange
|
||||
#
|
||||
# ZEVENT_SUBCLASS: 'statechange'
|
||||
# ZEVENT_VDEV_STATE_STR: 'DEGRADED', 'FAULTED', 'REMOVED', or 'UNAVAIL'
|
||||
# ZEVENT_VDEV_STATE_STR: 'DEGRADED', 'FAULTED' or 'REMOVED'
|
||||
#
|
||||
# Exit codes:
|
||||
# 0: notification sent
|
||||
|
@ -31,14 +31,13 @@
|
|||
|
||||
if [ "${ZEVENT_VDEV_STATE_STR}" != "FAULTED" ] \
|
||||
&& [ "${ZEVENT_VDEV_STATE_STR}" != "DEGRADED" ] \
|
||||
&& [ "${ZEVENT_VDEV_STATE_STR}" != "REMOVED" ] \
|
||||
&& [ "${ZEVENT_VDEV_STATE_STR}" != "UNAVAIL" ]; then
|
||||
&& [ "${ZEVENT_VDEV_STATE_STR}" != "REMOVED" ]; then
|
||||
exit 3
|
||||
fi
|
||||
|
||||
umask 077
|
||||
note_subject="ZFS device fault for pool ${ZEVENT_POOL} on $(hostname)"
|
||||
note_pathname="$(mktemp)"
|
||||
note_subject="ZFS device fault for pool ${ZEVENT_POOL_GUID} on $(hostname)"
|
||||
note_pathname="${TMPDIR:="/tmp"}/$(basename -- "$0").${ZEVENT_EID}.$$"
|
||||
{
|
||||
if [ "${ZEVENT_VDEV_STATE_STR}" = "FAULTED" ] ; then
|
||||
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_DEVID}" ] && echo " devid: ${ZEVENT_VDEV_DEVID}"
|
||||
|
||||
echo " pool: ${ZEVENT_POOL} (${ZEVENT_POOL_GUID})"
|
||||
echo " pool: ${ZEVENT_POOL_GUID}"
|
||||
|
||||
} > "${note_pathname}"
|
||||
|
||||
|
|
|
@ -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"
|
|
@ -19,7 +19,7 @@ zed_check_cmd "${ZPOOL}" || exit 9
|
|||
|
||||
umask 077
|
||||
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
|
||||
|
|
|
@ -77,7 +77,7 @@ zed_log_msg()
|
|||
zed_log_err()
|
||||
{
|
||||
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.
|
||||
#
|
||||
eval "exec ${fd}>> '${lockfile}'"
|
||||
if ! err="$(flock --exclusive "${fd}" 2>&1)"; then
|
||||
eval "exec ${fd}> '${lockfile}'"
|
||||
err="$(flock --exclusive "${fd}" 2>&1)"
|
||||
# shellcheck disable=SC2181
|
||||
if [ $? -ne 0 ]; then
|
||||
zed_log_err "failed to lock \"${lockfile}\": ${err}"
|
||||
fi
|
||||
|
||||
|
@ -163,7 +165,9 @@ zed_unlock()
|
|||
fi
|
||||
|
||||
# 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}"
|
||||
fi
|
||||
eval "exec ${fd}>&-"
|
||||
|
@ -202,10 +206,6 @@ zed_notify()
|
|||
[ "${rv}" -eq 0 ] && num_success=$((num_success + 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_failure}" -gt 0 ] && return 1
|
||||
return 2
|
||||
|
@ -224,8 +224,6 @@ zed_notify()
|
|||
# ZED_EMAIL_OPTS. This undergoes the following keyword substitutions:
|
||||
# - @ADDRESS@ is replaced with the space-delimited recipient email address(es)
|
||||
# - @SUBJECT@ is replaced with the notification subject
|
||||
# If @SUBJECT@ was omited here, a "Subject: ..." header will be added to notification
|
||||
#
|
||||
#
|
||||
# Arguments
|
||||
# subject: notification subject
|
||||
|
@ -243,7 +241,7 @@ zed_notify()
|
|||
#
|
||||
zed_notify_email()
|
||||
{
|
||||
local subject="${1:-"ZED notification"}"
|
||||
local subject="$1"
|
||||
local pathname="${2:-"/dev/null"}"
|
||||
|
||||
: "${ZED_EMAIL_PROG:="mail"}"
|
||||
|
@ -260,30 +258,19 @@ zed_notify_email()
|
|||
[ -n "${subject}" ] || return 1
|
||||
if [ ! -r "${pathname}" ]; then
|
||||
zed_log_err \
|
||||
"${ZED_EMAIL_PROG##*/} cannot read \"${pathname}\""
|
||||
"$(basename "${ZED_EMAIL_PROG}") cannot read \"${pathname}\""
|
||||
return 1
|
||||
fi
|
||||
|
||||
# construct cmdline options
|
||||
ZED_EMAIL_OPTS_PARSED="$(echo "${ZED_EMAIL_OPTS}" \
|
||||
ZED_EMAIL_OPTS="$(echo "${ZED_EMAIL_OPTS}" \
|
||||
| sed -e "s/@ADDRESS@/${ZED_EMAIL_ADDR}/g" \
|
||||
-e "s/@SUBJECT@/${subject}/g")"
|
||||
|
||||
# pipe message to email prog
|
||||
# shellcheck disable=SC2086,SC2248
|
||||
{
|
||||
# no subject passed as option?
|
||||
if [ "${ZED_EMAIL_OPTS%@SUBJECT@*}" = "${ZED_EMAIL_OPTS}" ] ; then
|
||||
# inject subject header
|
||||
printf "Subject: %s\n" "${subject}"
|
||||
fi
|
||||
# output message
|
||||
cat "${pathname}"
|
||||
} |
|
||||
eval ${ZED_EMAIL_PROG} ${ZED_EMAIL_OPTS_PARSED} >/dev/null 2>&1
|
||||
# shellcheck disable=SC2086
|
||||
eval "${ZED_EMAIL_PROG}" ${ZED_EMAIL_OPTS} < "${pathname}" >/dev/null 2>&1
|
||||
rv=$?
|
||||
if [ "${rv}" -ne 0 ]; then
|
||||
zed_log_err "${ZED_EMAIL_PROG##*/} exit=${rv}"
|
||||
zed_log_err "$(basename "${ZED_EMAIL_PROG}") exit=${rv}"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
|
@ -380,7 +367,7 @@ zed_notify_pushbullet()
|
|||
#
|
||||
# Notification via Slack Webhook <https://api.slack.com/incoming-webhooks>.
|
||||
# The Webhook URL (ZED_SLACK_WEBHOOK_URL) identifies this client to the
|
||||
# Slack channel.
|
||||
# Slack channel.
|
||||
#
|
||||
# Requires awk, curl, and sed executables to be installed in the standard PATH.
|
||||
#
|
||||
|
@ -430,7 +417,7 @@ zed_notify_slack_webhook()
|
|||
|
||||
# Construct the JSON message for posting.
|
||||
#
|
||||
msg_json="$(printf '{"text": "*%s*\\n%s"}' "${subject}" "${msg_body}" )"
|
||||
msg_json="$(printf '{"text": "*%s*\n%s"}' "${subject}" "${msg_body}" )"
|
||||
|
||||
# Send the POST request and check for errors.
|
||||
#
|
||||
|
@ -450,84 +437,6 @@ zed_notify_slack_webhook()
|
|||
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])
|
||||
#
|
||||
# Check whether an event of a given type [tag] has already occurred within the
|
||||
|
@ -602,8 +511,10 @@ zed_guid_to_pool()
|
|||
return
|
||||
fi
|
||||
|
||||
guid="$(printf "%u" "$1")"
|
||||
$ZPOOL get -H -ovalue,name guid | awk '$1 == '"$guid"' {print $2; exit}'
|
||||
guid=$(printf "%llu" "$1")
|
||||
if [ -n "$guid" ] ; then
|
||||
$ZPOOL get -H -ovalue,name guid | awk '$1=='"$guid"' {print $2}'
|
||||
fi
|
||||
}
|
||||
|
||||
# zed_exit_if_ignoring_this_event
|
||||
|
|
|
@ -13,9 +13,9 @@
|
|||
# Email address of the zpool administrator for receipt of notifications;
|
||||
# multiple addresses can be specified if they are delimited by whitespace.
|
||||
# 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;
|
||||
|
@ -30,7 +30,6 @@ ZED_EMAIL_ADDR="root"
|
|||
# The string @SUBJECT@ will be replaced with the notification subject;
|
||||
# this should be protected with quotes to prevent word-splitting.
|
||||
# Email will only be sent if ZED_EMAIL_ADDR is defined.
|
||||
# If @SUBJECT@ was omited here, a "Subject: ..." header will be added to notification
|
||||
#
|
||||
#ZED_EMAIL_OPTS="-s '@SUBJECT@' @ADDRESS@"
|
||||
|
||||
|
@ -83,23 +82,6 @@ ZED_EMAIL_ADDR="root"
|
|||
#
|
||||
#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.
|
||||
#
|
||||
|
@ -107,8 +89,8 @@ ZED_EMAIL_ADDR="root"
|
|||
|
||||
##
|
||||
# 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
|
||||
# and NVMe PCI drives (assuming they're supported by Linux in sysfs).
|
||||
# device mapper and multipath devices as well. Your enclosure must be
|
||||
# supported by the Linux SES driver for this to work.
|
||||
#
|
||||
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.
|
||||
#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
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
||||
* 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
|
||||
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
||||
|
@ -15,6 +15,11 @@
|
|||
#ifndef 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.
|
||||
*/
|
||||
|
@ -30,6 +35,16 @@
|
|||
*/
|
||||
#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.
|
||||
*/
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
||||
* 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
|
||||
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
||||
|
@ -22,7 +22,6 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
|
@ -33,26 +32,43 @@
|
|||
#include "zed_strings.h"
|
||||
|
||||
/*
|
||||
* Initialise the configuration with default values.
|
||||
* Return a new configuration with default values.
|
||||
*/
|
||||
void
|
||||
zed_conf_init(struct zed_conf *zcp)
|
||||
struct zed_conf *
|
||||
zed_conf_create(void)
|
||||
{
|
||||
memset(zcp, 0, sizeof (*zcp));
|
||||
struct zed_conf *zcp;
|
||||
|
||||
/* zcp->zfs_hdl opened in zed_event_init() */
|
||||
/* zcp->zedlets created in zed_conf_scan_dir() */
|
||||
zcp = calloc(1, sizeof (*zcp));
|
||||
if (!zcp)
|
||||
goto nomem;
|
||||
|
||||
zcp->pid_fd = -1; /* opened in zed_conf_write_pid() */
|
||||
zcp->state_fd = -1; /* opened in zed_conf_open_state() */
|
||||
zcp->zevent_fd = -1; /* opened in zed_event_init() */
|
||||
zcp->syslog_facility = LOG_DAEMON;
|
||||
zcp->min_events = ZED_MIN_EVENTS;
|
||||
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)) ||
|
||||
!(zcp->zedlet_dir = strdup(ZED_ZEDLET_DIR)) ||
|
||||
!(zcp->state_file = strdup(ZED_STATE_FILE)))
|
||||
zed_log_die("Failed to create conf: %s", strerror(errno));
|
||||
if (!(zcp->pid_file = strdup(ZED_PID_FILE)))
|
||||
goto nomem;
|
||||
|
||||
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));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -63,6 +79,9 @@ zed_conf_init(struct zed_conf *zcp)
|
|||
void
|
||||
zed_conf_destroy(struct zed_conf *zcp)
|
||||
{
|
||||
if (!zcp)
|
||||
return;
|
||||
|
||||
if (zcp->state_fd >= 0) {
|
||||
if (close(zcp->state_fd) < 0)
|
||||
zed_log_msg(LOG_WARNING,
|
||||
|
@ -83,6 +102,10 @@ zed_conf_destroy(struct zed_conf *zcp)
|
|||
zcp->pid_file, strerror(errno));
|
||||
zcp->pid_fd = -1;
|
||||
}
|
||||
if (zcp->conf_file) {
|
||||
free(zcp->conf_file);
|
||||
zcp->conf_file = NULL;
|
||||
}
|
||||
if (zcp->pid_file) {
|
||||
free(zcp->pid_file);
|
||||
zcp->pid_file = NULL;
|
||||
|
@ -99,6 +122,7 @@ zed_conf_destroy(struct zed_conf *zcp)
|
|||
zed_strings_destroy(zcp->zedlets);
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
|
||||
struct opt *oo;
|
||||
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" },
|
||||
{},
|
||||
};
|
||||
int w1 = 4; /* width of leading whitespace */
|
||||
int w2 = 8; /* width of L-justified option field */
|
||||
|
||||
fprintf(fp, "Usage: %s [OPTION]...\n", (prog ? prog : "zed"));
|
||||
fprintf(fp, "\n");
|
||||
for (oo = iopts; oo->o; ++oo)
|
||||
fprintf(fp, " %*s %s\n", -8, oo->o, oo->d);
|
||||
fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-h",
|
||||
"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");
|
||||
for (oo = nopts; oo->o; ++oo)
|
||||
fprintf(fp, " %*s %s\n", -8, oo->o, oo->d);
|
||||
fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-v",
|
||||
"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");
|
||||
for (oo = vopts; oo->o; ++oo)
|
||||
fprintf(fp, " %*s %s [%s]\n", -8, oo->o, oo->d, oo->v);
|
||||
#if 0
|
||||
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");
|
||||
|
||||
exit(got_err ? EXIT_FAILURE : EXIT_SUCCESS);
|
||||
|
@ -165,14 +183,20 @@ _zed_conf_display_help(const char *prog, boolean_t got_err)
|
|||
static void
|
||||
_zed_conf_display_license(void)
|
||||
{
|
||||
printf(
|
||||
"The ZFS Event Daemon (ZED) is distributed under the terms of the\n"
|
||||
" Common Development and Distribution License (CDDL-1.0)\n"
|
||||
" <http://opensource.org/licenses/CDDL-1.0>.\n"
|
||||
"\n"
|
||||
const char **pp;
|
||||
const char *text[] = {
|
||||
"The ZFS Event Daemon (ZED) is distributed under the terms of the",
|
||||
" Common Development and Distribution License (CDDL-1.0)",
|
||||
" <http://opensource.org/licenses/CDDL-1.0>.",
|
||||
"",
|
||||
"Developed at Lawrence Livermore National Laboratory"
|
||||
" (LLNL-CODE-403049).\n"
|
||||
"\n");
|
||||
" (LLNL-CODE-403049).",
|
||||
"",
|
||||
NULL
|
||||
};
|
||||
|
||||
for (pp = text; *pp; pp++)
|
||||
printf("%s\n", *pp);
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
@ -207,19 +231,16 @@ _zed_conf_parse_path(char **resultp, const char *path)
|
|||
|
||||
if (path[0] == '/') {
|
||||
*resultp = strdup(path);
|
||||
} else if (!getcwd(buf, sizeof (buf))) {
|
||||
zed_log_die("Failed to get current working dir: %s",
|
||||
strerror(errno));
|
||||
} else if (strlcat(buf, "/", sizeof (buf)) >= sizeof (buf)) {
|
||||
zed_log_die("Failed to copy path: %s", strerror(ENAMETOOLONG));
|
||||
} else if (strlcat(buf, path, sizeof (buf)) >= sizeof (buf)) {
|
||||
zed_log_die("Failed to copy path: %s", strerror(ENAMETOOLONG));
|
||||
} else {
|
||||
if (!getcwd(buf, sizeof (buf)))
|
||||
zed_log_die("Failed to get current working dir: %s",
|
||||
strerror(errno));
|
||||
|
||||
if (strlcat(buf, "/", sizeof (buf)) >= sizeof (buf) ||
|
||||
strlcat(buf, path, sizeof (buf)) >= sizeof (buf))
|
||||
zed_log_die("Failed to copy path: %s",
|
||||
strerror(ENAMETOOLONG));
|
||||
|
||||
*resultp = strdup(buf);
|
||||
}
|
||||
|
||||
if (!*resultp)
|
||||
zed_log_die("Failed to copy path: %s", strerror(ENOMEM));
|
||||
}
|
||||
|
@ -230,9 +251,8 @@ _zed_conf_parse_path(char **resultp, const char *path)
|
|||
void
|
||||
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;
|
||||
unsigned long raw;
|
||||
|
||||
if (!zcp || !argv || !argv[0])
|
||||
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) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
_zed_conf_display_help(argv[0], B_FALSE);
|
||||
_zed_conf_display_help(argv[0], EXIT_SUCCESS);
|
||||
break;
|
||||
case 'L':
|
||||
_zed_conf_display_license();
|
||||
|
@ -250,6 +270,9 @@ zed_conf_parse_opts(struct zed_conf *zcp, int argc, char **argv)
|
|||
case 'V':
|
||||
_zed_conf_display_version();
|
||||
break;
|
||||
case 'c':
|
||||
_zed_conf_parse_path(&zcp->conf_file, optarg);
|
||||
break;
|
||||
case 'd':
|
||||
_zed_conf_parse_path(&zcp->zedlet_dir, optarg);
|
||||
break;
|
||||
|
@ -280,30 +303,31 @@ zed_conf_parse_opts(struct zed_conf *zcp, int argc, char **argv)
|
|||
case 'Z':
|
||||
zcp->do_zero = 1;
|
||||
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 '?':
|
||||
default:
|
||||
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",
|
||||
argv[0], optopt);
|
||||
_zed_conf_display_help(argv[0], B_TRUE);
|
||||
fprintf(stderr, "%s: %s '-%c'\n\n", argv[0],
|
||||
"Invalid option", optopt);
|
||||
_zed_conf_display_help(argv[0], EXIT_FAILURE);
|
||||
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.
|
||||
* 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,
|
||||
* or -1 on error with errno set.
|
||||
*
|
||||
* FIXME: Check if zedlet_dir and all parent dirs are secure.
|
||||
*/
|
||||
int
|
||||
zed_conf_scan_dir(struct zed_conf *zcp)
|
||||
|
@ -426,6 +452,8 @@ zed_conf_scan_dir(struct zed_conf *zcp)
|
|||
int
|
||||
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];
|
||||
int n;
|
||||
char *p;
|
||||
|
@ -453,7 +481,7 @@ zed_conf_write_pid(struct zed_conf *zcp)
|
|||
if (p)
|
||||
*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",
|
||||
buf, strerror(errno));
|
||||
goto err;
|
||||
|
@ -463,7 +491,7 @@ zed_conf_write_pid(struct zed_conf *zcp)
|
|||
*/
|
||||
mask = umask(0);
|
||||
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);
|
||||
if (zcp->pid_fd < 0) {
|
||||
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;
|
||||
zed_log_msg(LOG_ERR, "Failed to write PID file \"%s\": %s",
|
||||
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",
|
||||
zcp->pid_file, strerror(errno));
|
||||
} else if (fdatasync(zcp->pid_fd) < 0) {
|
||||
|
@ -528,6 +556,7 @@ int
|
|||
zed_conf_open_state(struct zed_conf *zcp)
|
||||
{
|
||||
char dirbuf[PATH_MAX];
|
||||
mode_t dirmode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
|
||||
int n;
|
||||
char *p;
|
||||
int rv;
|
||||
|
@ -549,7 +578,7 @@ zed_conf_open_state(struct zed_conf *zcp)
|
|||
if (p)
|
||||
*p = '\0';
|
||||
|
||||
if ((mkdirp(dirbuf, 0755) < 0) && (errno != EEXIST)) {
|
||||
if ((mkdirp(dirbuf, dirmode) < 0) && (errno != EEXIST)) {
|
||||
zed_log_msg(LOG_WARNING,
|
||||
"Failed to create directory \"%s\": %s",
|
||||
dirbuf, strerror(errno));
|
||||
|
@ -567,7 +596,7 @@ zed_conf_open_state(struct zed_conf *zcp)
|
|||
(void) unlink(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) {
|
||||
zed_log_msg(LOG_WARNING, "Failed to open state file \"%s\": %s",
|
||||
zcp->state_file, strerror(errno));
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
||||
* 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
|
||||
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
||||
|
@ -20,39 +20,43 @@
|
|||
#include "zed_strings.h"
|
||||
|
||||
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 *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 */
|
||||
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 */
|
||||
libzfs_handle_t *zfs_hdl; /* handle to libzfs */
|
||||
int zevent_fd; /* fd for access to zevents */
|
||||
|
||||
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 */
|
||||
char *path; /* custom $PATH for zedlets to use */
|
||||
};
|
||||
|
||||
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_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_write_pid(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_write_state(struct zed_conf *zcp, uint64_t eid, int64_t etime[]);
|
||||
|
||||
#endif /* !ZED_CONF_H */
|
||||
|
|
|
@ -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);
|
||||
if (nvlist_lookup_string(nvl, DEV_IDENTIFIER, &strval) == 0)
|
||||
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)
|
||||
zed_log_msg(LOG_INFO, "\t%s: %s", DEV_PHYS_PATH, strval);
|
||||
if (nvlist_lookup_uint64(nvl, DEV_SIZE, &numval) == 0)
|
||||
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)
|
||||
zed_log_msg(LOG_INFO, "\t%s: %llu", ZFS_EV_POOL_GUID, numval);
|
||||
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);
|
||||
(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) {
|
||||
struct udev_device *dev;
|
||||
const char *action, *type, *part, *sectors;
|
||||
const char *bus, *uuid, *devpath;
|
||||
const char *bus, *uuid;
|
||||
const char *class, *subclass;
|
||||
nvlist_t *nvl;
|
||||
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
|
||||
* zfs label will reside in a DEVTYPE=partition and
|
||||
* 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");
|
||||
part = udev_device_get_property_value(dev,
|
||||
|
@ -237,23 +213,9 @@ zed_udev_monitor(void *arg)
|
|||
if (type != NULL && type[0] != '\0' &&
|
||||
strcmp(type, "disk") == 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 */
|
||||
udev_device_unref(dev);
|
||||
continue;
|
||||
}
|
||||
/* skip and wait for partition event */
|
||||
udev_device_unref(dev);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -265,11 +227,6 @@ zed_udev_monitor(void *arg)
|
|||
sectors = udev_device_get_sysattr_value(dev, "size");
|
||||
if (sectors != NULL &&
|
||||
strtoull(sectors, NULL, 10) < MINIMUM_SECTORS) {
|
||||
zed_log_msg(LOG_INFO,
|
||||
"%s: %s sectors %s < %llu (minimum)",
|
||||
__func__,
|
||||
udev_device_get_property_value(dev, "DEVNAME"),
|
||||
sectors, MINIMUM_SECTORS);
|
||||
udev_device_unref(dev);
|
||||
continue;
|
||||
}
|
||||
|
@ -279,19 +236,10 @@ zed_udev_monitor(void *arg)
|
|||
* device id string is required in the message schema
|
||||
* for matching with vdevs. Preflight here for expected
|
||||
* 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");
|
||||
uuid = udev_device_get_property_value(dev, "DM_UUID");
|
||||
devpath = udev_device_get_devpath(dev);
|
||||
if (!is_zfs && (bus == NULL && uuid == NULL &&
|
||||
strstr(devpath, "/nvme/") == NULL)) {
|
||||
if (!is_zfs && (bus == NULL && uuid == NULL)) {
|
||||
zed_log_msg(LOG_INFO, "zed_udev_monitor: %s no devid "
|
||||
"source", udev_device_get_devnode(dev));
|
||||
udev_device_unref(dev);
|
||||
|
@ -402,7 +350,7 @@ zed_udev_monitor(void *arg)
|
|||
}
|
||||
|
||||
int
|
||||
zed_disk_event_init(void)
|
||||
zed_disk_event_init()
|
||||
{
|
||||
int fd, fflags;
|
||||
|
||||
|
@ -431,14 +379,13 @@ zed_disk_event_init(void)
|
|||
return (-1);
|
||||
}
|
||||
|
||||
pthread_setname_np(g_mon_tid, "udev monitor");
|
||||
zed_log_msg(LOG_INFO, "zed_disk_event_init");
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
zed_disk_event_fini(void)
|
||||
zed_disk_event_fini()
|
||||
{
|
||||
/* cancel monitor thread at recvmsg() */
|
||||
(void) pthread_cancel(g_mon_tid);
|
||||
|
@ -456,13 +403,13 @@ zed_disk_event_fini(void)
|
|||
#include "zed_disk_event.h"
|
||||
|
||||
int
|
||||
zed_disk_event_init(void)
|
||||
zed_disk_event_init()
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
zed_disk_event_fini(void)
|
||||
zed_disk_event_fini()
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
||||
* 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
|
||||
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
||||
|
@ -15,7 +15,7 @@
|
|||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <libzfs_core.h>
|
||||
#include <libzfs.h> /* FIXME: Replace with libzfs_core. */
|
||||
#include <paths.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
@ -35,7 +35,6 @@
|
|||
#include "zed_strings.h"
|
||||
|
||||
#include "agents/zfs_agents.h"
|
||||
#include <libzutil.h>
|
||||
|
||||
#define MAXBUF 4096
|
||||
|
||||
|
@ -55,7 +54,7 @@ zed_event_init(struct zed_conf *zcp)
|
|||
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->do_idle)
|
||||
return (-1);
|
||||
|
@ -97,47 +96,6 @@ zed_event_fini(struct zed_conf *zcp)
|
|||
libzfs_fini(zcp->zfs_hdl);
|
||||
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) {
|
||||
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) {
|
||||
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.
|
||||
*/
|
||||
static __attribute__((format(printf, 5, 6))) int
|
||||
static int
|
||||
_zed_event_add_var(uint64_t eid, zed_strings_t *zsp,
|
||||
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
|
||||
* of the child process.
|
||||
* Return 0 on success, -1 on error.
|
||||
*
|
||||
* FIXME: Refactor with cmd/zpool/zpool_main.c:zpool_do_events_nvprint()?
|
||||
*/
|
||||
static void
|
||||
_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,
|
||||
"%llu", (u_longlong_t)i64);
|
||||
break;
|
||||
case DATA_TYPE_NVLIST:
|
||||
_zed_event_add_var(eid, zsp, prefix, name,
|
||||
"%s", "_NOT_IMPLEMENTED_"); /* FIXME */
|
||||
break;
|
||||
case DATA_TYPE_STRING:
|
||||
(void) nvpair_value_string(nvp, &str);
|
||||
_zed_event_add_var(eid, zsp, prefix, name,
|
||||
"%s", (str ? str : "<NULL>"));
|
||||
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:
|
||||
_zed_event_add_int8_array(eid, zsp, prefix, nvp);
|
||||
break;
|
||||
|
@ -755,11 +730,9 @@ _zed_event_add_nvpair(uint64_t eid, zed_strings_t *zsp, nvpair_t *nvp)
|
|||
case DATA_TYPE_STRING_ARRAY:
|
||||
_zed_event_add_string_array(eid, zsp, prefix, nvp);
|
||||
break;
|
||||
case DATA_TYPE_NVLIST:
|
||||
case DATA_TYPE_BOOLEAN_ARRAY:
|
||||
case DATA_TYPE_BYTE_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;
|
||||
default:
|
||||
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.
|
||||
*/
|
||||
|
@ -958,7 +912,10 @@ zed_event_service(struct zed_conf *zcp)
|
|||
|
||||
if (n_dropped > 0) {
|
||||
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) {
|
||||
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,
|
||||
"Failed to lookup zevent class (eid=%llu)", eid);
|
||||
} 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 */
|
||||
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_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);
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
||||
* 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
|
||||
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
||||
* 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
|
||||
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
||||
|
@ -18,55 +18,17 @@
|
|||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/avl.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "zed_exec.h"
|
||||
#include "zed_file.h"
|
||||
#include "zed_log.h"
|
||||
#include "zed_strings.h"
|
||||
|
||||
#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
|
||||
* NAME=VALUE strings in container [zsp].
|
||||
|
@ -117,26 +79,20 @@ _zed_exec_create_env(zed_strings_t *zsp)
|
|||
*/
|
||||
static void
|
||||
_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];
|
||||
int n;
|
||||
pid_t pid;
|
||||
int fd;
|
||||
struct launched_process_node *node;
|
||||
sigset_t mask;
|
||||
struct timespec launch_timeout =
|
||||
{ .tv_sec = 0, .tv_nsec = 200 * 1000 * 1000, };
|
||||
pid_t wpid;
|
||||
int status;
|
||||
|
||||
assert(dir != NULL);
|
||||
assert(prog != NULL);
|
||||
assert(env != NULL);
|
||||
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);
|
||||
if ((n < 0) || (n >= sizeof (path))) {
|
||||
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));
|
||||
return;
|
||||
}
|
||||
(void) pthread_mutex_lock(&_launched_processes_lock);
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
(void) pthread_mutex_unlock(&_launched_processes_lock);
|
||||
zed_log_msg(LOG_WARNING,
|
||||
"Failed to fork \"%s\" for eid=%llu: %s",
|
||||
prog, eid, strerror(errno));
|
||||
return;
|
||||
} else if (pid == 0) {
|
||||
(void) sigemptyset(&mask);
|
||||
(void) sigprocmask(SIG_SETMASK, &mask, NULL);
|
||||
|
||||
(void) umask(022);
|
||||
if (in_foreground && /* we're already devnulled if daemonised */
|
||||
(fd = open("/dev/null", O_RDWR | O_CLOEXEC)) != -1) {
|
||||
if ((fd = open("/dev/null", O_RDWR)) != -1) {
|
||||
(void) dup2(fd, STDIN_FILENO);
|
||||
(void) dup2(fd, STDOUT_FILENO);
|
||||
(void) dup2(fd, STDERR_FILENO);
|
||||
}
|
||||
(void) dup2(zfd, ZEVENT_FILENO);
|
||||
zed_file_close_from(ZEVENT_FILENO + 1);
|
||||
execle(path, prog, NULL, env);
|
||||
_exit(127);
|
||||
}
|
||||
|
||||
/* 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",
|
||||
prog, eid, pid);
|
||||
}
|
||||
|
||||
static void
|
||||
_nop(int sig)
|
||||
{}
|
||||
/* FIXME: Timeout rogue child processes with sigalarm? */
|
||||
|
||||
static void *
|
||||
_reap_children(void *arg)
|
||||
{
|
||||
struct launched_process_node node, *pnode;
|
||||
pid_t pid;
|
||||
int status;
|
||||
struct rusage usage;
|
||||
struct sigaction sa = {};
|
||||
/*
|
||||
* Wait for child process using WNOHANG to limit
|
||||
* the time spent waiting to 10 seconds (10,000ms).
|
||||
*/
|
||||
for (n = 0; n < 1000; n++) {
|
||||
wpid = waitpid(pid, &status, WNOHANG);
|
||||
if (wpid == (pid_t)-1) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
zed_log_msg(LOG_WARNING,
|
||||
"Failed to wait for \"%s\" eid=%llu pid=%d",
|
||||
prog, eid, pid);
|
||||
break;
|
||||
} else if (wpid == 0) {
|
||||
struct timespec t;
|
||||
|
||||
(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,
|
||||
"Failed to wait for children: %s",
|
||||
strerror(errno));
|
||||
} else {
|
||||
memset(&node, 0, sizeof (node));
|
||||
node.pid = pid;
|
||||
pnode = avl_find(&_launched_processes, &node, NULL);
|
||||
if (pnode) {
|
||||
memcpy(&node, pnode, sizeof (node));
|
||||
|
||||
avl_remove(&_launched_processes, pnode);
|
||||
free(pnode);
|
||||
}
|
||||
(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)) {
|
||||
zed_log_msg(LOG_INFO,
|
||||
"Finished \"%s\" eid=%llu pid=%d "
|
||||
"time=%llu.%06us exit=%d",
|
||||
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)) {
|
||||
zed_log_msg(LOG_INFO,
|
||||
"Finished \"%s\" eid=%llu pid=%d "
|
||||
"time=%llu.%06us sig=%d/%s",
|
||||
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)));
|
||||
} else {
|
||||
zed_log_msg(LOG_INFO,
|
||||
"Finished \"%s\" eid=%llu pid=%d "
|
||||
"time=%llu.%06us status=0x%X",
|
||||
node.name, node.eid,
|
||||
(unsigned long long) usage.ru_utime.tv_sec,
|
||||
(unsigned int) usage.ru_utime.tv_usec,
|
||||
(unsigned int) status);
|
||||
}
|
||||
|
||||
free(node.name);
|
||||
/* child still running */
|
||||
t.tv_sec = 0;
|
||||
t.tv_nsec = 10000000; /* 10ms */
|
||||
(void) nanosleep(&t, NULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (WIFEXITED(status)) {
|
||||
zed_log_msg(LOG_INFO,
|
||||
"Finished \"%s\" eid=%llu pid=%d exit=%d",
|
||||
prog, eid, pid, WEXITSTATUS(status));
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
zed_log_msg(LOG_INFO,
|
||||
"Finished \"%s\" eid=%llu pid=%d sig=%d/%s",
|
||||
prog, eid, pid, WTERMSIG(status),
|
||||
strsignal(WTERMSIG(status)));
|
||||
} else {
|
||||
zed_log_msg(LOG_INFO,
|
||||
"Finished \"%s\" eid=%llu pid=%d status=0x%X",
|
||||
prog, eid, (unsigned int) status);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
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);
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
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
|
||||
* matching class prefix.
|
||||
*
|
||||
* Each executable in [zcp->zedlets] from the directory [zcp->zedlet_dir]
|
||||
* is matched against the event's [class], [subclass], and the "all" class
|
||||
* (which matches all events).
|
||||
* Every zedlet with a matching class prefix is invoked.
|
||||
* Each executable in [zedlets] from the directory [dir] is matched against
|
||||
* the event's [class], [subclass], and the "all" class (which matches
|
||||
* all events). Every zedlet with a matching class prefix is invoked.
|
||||
* The NAME=VALUE strings in [envs] will be passed to the zedlet as
|
||||
* 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.
|
||||
*
|
||||
* Return 0 on success, -1 on error.
|
||||
*/
|
||||
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 zfd)
|
||||
{
|
||||
const char *class_strings[4];
|
||||
const char *allclass = "all";
|
||||
|
@ -325,22 +203,9 @@ zed_exec_process(uint64_t eid, const char *class, const char *subclass,
|
|||
char **e;
|
||||
int n;
|
||||
|
||||
if (!zcp->zedlet_dir || !zcp->zedlets || !envs || zcp->zevent_fd < 0)
|
||||
if (!dir || !zedlets || !envs || zfd < 0)
|
||||
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;
|
||||
|
||||
if (class)
|
||||
|
@ -356,13 +221,11 @@ zed_exec_process(uint64_t eid, const char *class, const char *subclass,
|
|||
|
||||
e = _zed_exec_create_env(envs);
|
||||
|
||||
for (z = zed_strings_first(zcp->zedlets); z;
|
||||
z = zed_strings_next(zcp->zedlets)) {
|
||||
for (z = zed_strings_first(zedlets); z; z = zed_strings_next(zedlets)) {
|
||||
for (csp = class_strings; *csp; csp++) {
|
||||
n = strlen(*csp);
|
||||
if ((strncmp(z, *csp, n) == 0) && !isalpha(z[n]))
|
||||
_zed_exec_fork_child(eid, zcp->zedlet_dir,
|
||||
z, e, zcp->zevent_fd, zcp->do_foreground);
|
||||
_zed_exec_fork_child(eid, dir, z, e, zfd);
|
||||
}
|
||||
}
|
||||
free(e);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
||||
* 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
|
||||
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
||||
|
@ -17,11 +17,9 @@
|
|||
|
||||
#include <stdint.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,
|
||||
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 */
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
||||
* 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include "zed_file.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].
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
||||
#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].
|
||||
* Any errors encountered while closing file descriptors are ignored.
|
||||
|
@ -118,24 +167,51 @@ zed_file_is_locked(int fd)
|
|||
void
|
||||
zed_file_close_from(int lowfd)
|
||||
{
|
||||
int errno_bak = errno;
|
||||
int maxfd = 0;
|
||||
const int maxfd_def = 256;
|
||||
int errno_bak;
|
||||
struct rlimit rl;
|
||||
int maxfd;
|
||||
int fd;
|
||||
DIR *fddir;
|
||||
struct dirent *fdent;
|
||||
|
||||
if ((fddir = opendir(PROC_SELF_FD)) != NULL) {
|
||||
while ((fdent = readdir(fddir)) != NULL) {
|
||||
fd = atoi(fdent->d_name);
|
||||
if (fd > maxfd && fd != dirfd(fddir))
|
||||
maxfd = fd;
|
||||
}
|
||||
(void) closedir(fddir);
|
||||
errno_bak = errno;
|
||||
|
||||
if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
|
||||
maxfd = maxfd_def;
|
||||
} else if (rl.rlim_max == RLIM_INFINITY) {
|
||||
maxfd = maxfd_def;
|
||||
} else {
|
||||
maxfd = sysconf(_SC_OPEN_MAX);
|
||||
maxfd = rl.rlim_max;
|
||||
}
|
||||
for (fd = lowfd; fd < maxfd; fd++)
|
||||
(void) close(fd);
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
||||
* 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
|
||||
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
||||
|
@ -18,6 +18,10 @@
|
|||
#include <sys/types.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_unlock(int fd);
|
||||
|
@ -26,4 +30,6 @@ pid_t zed_file_is_locked(int fd);
|
|||
|
||||
void zed_file_close_from(int fd);
|
||||
|
||||
int zed_file_close_on_exec(int fd);
|
||||
|
||||
#endif /* !ZED_FILE_H */
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
||||
* 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
|
||||
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
||||
* 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
|
||||
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
||||
* 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
|
||||
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
||||
* 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
|
||||
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
||||
|
|
|
@ -315,14 +315,14 @@ get_usage(zfs_help_t idx)
|
|||
case HELP_ROLLBACK:
|
||||
return (gettext("\trollback [-rRf] <snapshot>\n"));
|
||||
case HELP_SEND:
|
||||
return (gettext("\tsend [-DnPpRVvLecwhb] [-[i|I] snapshot] "
|
||||
return (gettext("\tsend [-DnPpRvLecwhb] [-[i|I] snapshot] "
|
||||
"<snapshot>\n"
|
||||
"\tsend [-DnVvPLecw] [-i snapshot|bookmark] "
|
||||
"\tsend [-nvPLecw] [-i snapshot|bookmark] "
|
||||
"<filesystem|volume|snapshot>\n"
|
||||
"\tsend [-DnPpVvLec] [-i bookmark|snapshot] "
|
||||
"\tsend [-DnPpvLec] [-i bookmark|snapshot] "
|
||||
"--redact <bookmark> <snapshot>\n"
|
||||
"\tsend [-nVvPe] -t <receive_resume_token>\n"
|
||||
"\tsend [-PnVv] --saved filesystem\n"));
|
||||
"\tsend [-nvPe] -t <receive_resume_token>\n"
|
||||
"\tsend [-Pnv] --saved filesystem\n"));
|
||||
case HELP_SET:
|
||||
return (gettext("\tset <property=value> ... "
|
||||
"<filesystem|volume|snapshot> ...\n"));
|
||||
|
@ -535,7 +535,7 @@ usage(boolean_t requested)
|
|||
show_properties = B_TRUE;
|
||||
|
||||
if (show_properties) {
|
||||
(void) fprintf(fp, "%s",
|
||||
(void) fprintf(fp,
|
||||
gettext("\nThe following properties are supported:\n"));
|
||||
|
||||
(void) fprintf(fp, "\n\t%-14s %s %s %s\n\n",
|
||||
|
@ -728,32 +728,6 @@ finish_progress(char *done)
|
|||
pt_header = NULL;
|
||||
}
|
||||
|
||||
/* This function checks if the passed fd refers to /dev/null or /dev/zero */
|
||||
#ifdef __linux__
|
||||
static boolean_t
|
||||
is_dev_nullzero(int fd)
|
||||
{
|
||||
struct stat st;
|
||||
fstat(fd, &st);
|
||||
return (major(st.st_rdev) == 1 && (minor(st.st_rdev) == 3 /* null */ ||
|
||||
minor(st.st_rdev) == 5 /* zero */));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
note_dev_error(int err, int fd)
|
||||
{
|
||||
#ifdef __linux__
|
||||
if (err == EINVAL && is_dev_nullzero(fd)) {
|
||||
(void) fprintf(stderr,
|
||||
gettext("Error: Writing directly to /dev/{null,zero} files"
|
||||
" on certain kernels is not currently implemented.\n"
|
||||
"(As a workaround, "
|
||||
"try \"zfs send [...] | cat > /dev/null\")\n"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
zfs_mount_and_share(libzfs_handle_t *hdl, const char *dataset, zfs_type_t type)
|
||||
{
|
||||
|
@ -2480,7 +2454,7 @@ upgrade_set_callback(zfs_handle_t *zhp, void *data)
|
|||
|
||||
/* upgrade */
|
||||
if (version < cb->cb_version) {
|
||||
char verstr[24];
|
||||
char verstr[16];
|
||||
(void) snprintf(verstr, sizeof (verstr),
|
||||
"%llu", (u_longlong_t)cb->cb_version);
|
||||
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 right_justify;
|
||||
|
||||
color_start(ANSI_BOLD);
|
||||
|
||||
for (; pl != NULL; pl = pl->pl_next) {
|
||||
if (!first) {
|
||||
(void) printf(" ");
|
||||
|
@ -3502,31 +3474,9 @@ print_header(list_cbdata_t *cb)
|
|||
(void) printf("%-*s", (int)pl->pl_width, header);
|
||||
}
|
||||
|
||||
color_end();
|
||||
|
||||
(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
|
||||
* to the described layout.
|
||||
|
@ -3589,22 +3539,6 @@ print_dataset(zfs_handle_t *zhp, list_cbdata_t *cb)
|
|||
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
|
||||
* 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);
|
||||
else
|
||||
(void) printf("%-*s", (int)pl->pl_width, propstr);
|
||||
|
||||
if (pl->pl_prop == ZFS_PROP_AVAILABLE)
|
||||
color_end();
|
||||
}
|
||||
|
||||
(void) printf("\n");
|
||||
|
@ -4445,12 +4376,10 @@ zfs_do_send(int argc, char **argv)
|
|||
|
||||
struct option long_options[] = {
|
||||
{"replicate", no_argument, NULL, 'R'},
|
||||
{"skip-missing", no_argument, NULL, 's'},
|
||||
{"redact", required_argument, NULL, 'd'},
|
||||
{"props", no_argument, NULL, 'p'},
|
||||
{"parsable", no_argument, NULL, 'P'},
|
||||
{"dedup", no_argument, NULL, 'D'},
|
||||
{"proctitle", no_argument, NULL, 'V'},
|
||||
{"verbose", no_argument, NULL, 'v'},
|
||||
{"dryrun", no_argument, NULL, 'n'},
|
||||
{"large-block", no_argument, NULL, 'L'},
|
||||
|
@ -4465,7 +4394,7 @@ zfs_do_send(int argc, char **argv)
|
|||
};
|
||||
|
||||
/* 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) {
|
||||
switch (c) {
|
||||
case 'i':
|
||||
|
@ -4482,9 +4411,6 @@ zfs_do_send(int argc, char **argv)
|
|||
case 'R':
|
||||
flags.replicate = B_TRUE;
|
||||
break;
|
||||
case 's':
|
||||
flags.skipmissing = B_TRUE;
|
||||
break;
|
||||
case 'd':
|
||||
redactbook = optarg;
|
||||
break;
|
||||
|
@ -4500,9 +4426,6 @@ zfs_do_send(int argc, char **argv)
|
|||
case 'P':
|
||||
flags.parsable = B_TRUE;
|
||||
break;
|
||||
case 'V':
|
||||
flags.progressastitle = B_TRUE;
|
||||
break;
|
||||
case 'v':
|
||||
flags.verbosity++;
|
||||
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;
|
||||
|
||||
argc -= optind;
|
||||
|
@ -4645,23 +4568,11 @@ zfs_do_send(int argc, char **argv)
|
|||
|
||||
err = zfs_send_saved(zhp, &flags, STDOUT_FILENO,
|
||||
resume_token);
|
||||
if (err != 0)
|
||||
note_dev_error(errno, STDOUT_FILENO);
|
||||
zfs_close(zhp);
|
||||
return (err != 0);
|
||||
} else if (resume_token != NULL) {
|
||||
err = zfs_send_resume(g_zfs, &flags, STDOUT_FILENO,
|
||||
resume_token);
|
||||
if (err != 0)
|
||||
note_dev_error(errno, STDOUT_FILENO);
|
||||
return (err);
|
||||
}
|
||||
|
||||
if (flags.skipmissing && !flags.replicate) {
|
||||
(void) fprintf(stderr,
|
||||
gettext("skip-missing flag can only be used in "
|
||||
"conjunction with replicate\n"));
|
||||
usage(B_FALSE);
|
||||
return (zfs_send_resume(g_zfs, &flags, STDOUT_FILENO,
|
||||
resume_token));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -4705,8 +4616,6 @@ zfs_do_send(int argc, char **argv)
|
|||
err = zfs_send_one(zhp, fromname, STDOUT_FILENO, &flags,
|
||||
redactbook);
|
||||
zfs_close(zhp);
|
||||
if (err != 0)
|
||||
note_dev_error(errno, STDOUT_FILENO);
|
||||
return (err != 0);
|
||||
}
|
||||
|
||||
|
@ -4783,7 +4692,6 @@ zfs_do_send(int argc, char **argv)
|
|||
nvlist_free(dbgnv);
|
||||
}
|
||||
zfs_close(zhp);
|
||||
note_dev_error(errno, STDOUT_FILENO);
|
||||
|
||||
return (err != 0);
|
||||
}
|
||||
|
@ -6640,7 +6548,7 @@ zfs_do_holds(int argc, char **argv)
|
|||
/*
|
||||
* 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);
|
||||
if (ret != 0)
|
||||
++errors;
|
||||
|
@ -7522,7 +7430,6 @@ unshare_unmount(int op, int argc, char **argv)
|
|||
if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) ==
|
||||
ZFS_CANMOUNT_NOAUTO)
|
||||
continue;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -7719,7 +7626,7 @@ zfs_do_diff(int argc, char **argv)
|
|||
int c;
|
||||
struct sigaction sa;
|
||||
|
||||
while ((c = getopt(argc, argv, "FHth")) != -1) {
|
||||
while ((c = getopt(argc, argv, "FHt")) != -1) {
|
||||
switch (c) {
|
||||
case 'F':
|
||||
flags |= ZFS_DIFF_CLASSIFY;
|
||||
|
@ -7730,9 +7637,6 @@ zfs_do_diff(int argc, char **argv)
|
|||
case 't':
|
||||
flags |= ZFS_DIFF_TIMESTAMP;
|
||||
break;
|
||||
case 'h':
|
||||
flags |= ZFS_DIFF_NO_MANGLE;
|
||||
break;
|
||||
default:
|
||||
(void) fprintf(stderr,
|
||||
gettext("invalid option '%c'\n"), optopt);
|
||||
|
@ -8582,7 +8486,7 @@ static int
|
|||
zfs_do_wait(int argc, char **argv)
|
||||
{
|
||||
boolean_t enabled[ZFS_WAIT_NUM_ACTIVITIES];
|
||||
int error = 0, i;
|
||||
int error, i;
|
||||
int c;
|
||||
|
||||
/* 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);
|
||||
|
||||
zfs_setproctitle_init(argc, argv, environ);
|
||||
|
||||
/*
|
||||
* Many commands modify input strings for string parsing reasons.
|
||||
* We create a copy to protect the original argv.
|
||||
|
|
|
@ -207,6 +207,7 @@ static int
|
|||
zfs_project_handle_dir(const char *name, zfs_project_control_t *zpc,
|
||||
list_t *head)
|
||||
{
|
||||
char fullname[PATH_MAX];
|
||||
struct dirent *ent;
|
||||
DIR *dir;
|
||||
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;
|
||||
errno = 0;
|
||||
while (!ret && (ent = readdir(dir)) != NULL) {
|
||||
char *fullname;
|
||||
|
||||
/* skip "." and ".." */
|
||||
if (strcmp(ent->d_name, ".") == 0 ||
|
||||
strcmp(ent->d_name, "..") == 0)
|
||||
continue;
|
||||
|
||||
if (strlen(ent->d_name) + strlen(name) + 1 >= PATH_MAX) {
|
||||
if (strlen(ent->d_name) + strlen(name) >=
|
||||
sizeof (fullname) + 1) {
|
||||
errno = ENAMETOOLONG;
|
||||
break;
|
||||
}
|
||||
|
||||
if (asprintf(&fullname, "%s/%s", name, ent->d_name) == -1) {
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
sprintf(fullname, "%s/%s", name, ent->d_name);
|
||||
ret = zfs_project_handle_one(fullname, zpc);
|
||||
if (!ret && zpc->zpc_recursive && ent->d_type == DT_DIR)
|
||||
zfs_project_item_alloc(head, fullname);
|
||||
|
||||
free(fullname);
|
||||
}
|
||||
|
||||
if (errno && !ret) {
|
||||
|
|
|
@ -35,7 +35,7 @@ libzfs_handle_t *g_zfs;
|
|||
static void
|
||||
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");
|
||||
exit(err);
|
||||
}
|
||||
|
@ -63,11 +63,11 @@ main(int argc, char **argv)
|
|||
|
||||
uint64_t objset, object;
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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]);
|
||||
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);
|
||||
return (5);
|
||||
}
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static void usage(void);
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
|
@ -58,11 +60,12 @@ int
|
|||
main(int argc, char **argv)
|
||||
{
|
||||
/* 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 */
|
||||
unsigned long input_i = 0;
|
||||
|
||||
int opt;
|
||||
int pathlen;
|
||||
int force_fwrite = 0;
|
||||
while ((opt = getopt_long(argc, argv, "fo:h?", 0, 0)) != -1) {
|
||||
switch (opt) {
|
||||
|
@ -70,7 +73,14 @@ main(int argc, char **argv)
|
|||
force_fwrite = 1;
|
||||
break;
|
||||
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;
|
||||
case 'h':
|
||||
case '?':
|
||||
|
@ -108,7 +118,7 @@ main(int argc, char **argv)
|
|||
if (force_fwrite == 0 && stat(path, &fstat) == 0 &&
|
||||
S_ISREG(fstat.st_mode)) {
|
||||
fprintf(stderr, "%s: %s\n", path, strerror(EEXIST));
|
||||
exit(EXIT_FAILURE);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
*/
|
||||
uint32_t hostid = input_i;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
include $(top_srcdir)/config/Rules.am
|
||||
include $(top_srcdir)/config/Shellcheck.am
|
||||
|
||||
AM_CFLAGS += $(LIBBLKID_CFLAGS) $(LIBUUID_CFLAGS)
|
||||
|
||||
|
@ -26,8 +25,7 @@ zpool_LDADD = \
|
|||
$(abs_top_builddir)/lib/libzfs/libzfs.la \
|
||||
$(abs_top_builddir)/lib/libzfs_core/libzfs_core.la \
|
||||
$(abs_top_builddir)/lib/libnvpair/libnvpair.la \
|
||||
$(abs_top_builddir)/lib/libuutil/libuutil.la \
|
||||
$(abs_top_builddir)/lib/libzutil/libzutil.la
|
||||
$(abs_top_builddir)/lib/libuutil/libuutil.la
|
||||
|
||||
zpool_LDADD += $(LTLIBINTL)
|
||||
|
||||
|
@ -148,10 +146,6 @@ dist_zpoolcompat_DATA = \
|
|||
compatibility.d/openzfsonosx-1.9.3 \
|
||||
compatibility.d/openzfs-2.0-freebsd \
|
||||
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.7 \
|
||||
compatibility.d/zol-0.8
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -1,4 +0,0 @@
|
|||
# Features supported by ZFSonLinux v0.6.1
|
||||
async_destroy
|
||||
empty_bpobj
|
||||
lz4_compress
|
|
@ -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
|
|
@ -101,39 +101,3 @@ check_sector_size_database(char *path, int *sector_size)
|
|||
{
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -405,263 +405,3 @@ check_device(const char *path, boolean_t force,
|
|||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -16,12 +16,14 @@ if [ -L "$dev" ] ; then
|
|||
dev=$(readlink "$dev")
|
||||
fi
|
||||
|
||||
dev="${dev##*/}"
|
||||
dev=$(basename "$dev")
|
||||
val=""
|
||||
if [ -d "/sys/class/block/$dev/slaves" ] ; then
|
||||
# ls -C: output in columns, no newlines, two spaces (change to one)
|
||||
# shellcheck disable=SC2012
|
||||
val=$(ls -C "/sys/class/block/$dev/slaves" | tr -s '[:space:]' ' ')
|
||||
# ls -C: output in columns, no newlines
|
||||
val=$(ls -C "/sys/class/block/$dev/slaves")
|
||||
|
||||
# ls -C will print two spaces between files; change to one space.
|
||||
val=$(echo "$val" | sed -r 's/[[:blank:]]+/ /g')
|
||||
fi
|
||||
|
||||
echo "dm-deps=$val"
|
||||
|
|
|
@ -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-10s: Do a single 10-second iostat sample and show values."
|
||||
|
||||
script="${0##*/}"
|
||||
script=$(basename "$0")
|
||||
if [ "$1" = "-h" ] ; then
|
||||
echo "$helpstr" | grep "$script:" | tr -s '\t' | cut -f 2-
|
||||
exit
|
||||
|
@ -42,7 +42,7 @@ else
|
|||
${brief:+"-y"} \
|
||||
${interval:+"$interval"} \
|
||||
${interval:+"1"} \
|
||||
"$VDEV_UPATH" | grep -v '^$' | tail -n 2)
|
||||
"$VDEV_UPATH" | awk NF | tail -n 2)
|
||||
fi
|
||||
|
||||
|
||||
|
@ -61,7 +61,7 @@ fi
|
|||
cols=$(echo "$out" | head -n 1)
|
||||
|
||||
# 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
|
||||
for col in $cols ; do
|
||||
|
|
|
@ -48,7 +48,7 @@ size: Show the disk capacity.
|
|||
vendor: Show the disk vendor.
|
||||
lsblk: Show the disk size, vendor, and model number."
|
||||
|
||||
script="${0##*/}"
|
||||
script=$(basename "$0")
|
||||
|
||||
if [ "$1" = "-h" ] ; then
|
||||
echo "$helpstr" | grep "$script:" | tr -s '\t' | cut -f 2-
|
||||
|
|
|
@ -4,23 +4,19 @@
|
|||
#
|
||||
|
||||
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
|
||||
fi
|
||||
|
||||
if [ -b "$VDEV_UPATH" ]; then
|
||||
device="${VDEV_UPATH##*/}"
|
||||
read -r val 2>/dev/null < "/sys/block/$device/queue/rotational"
|
||||
case "$val" in
|
||||
0) MEDIA="ssd" ;;
|
||||
1) MEDIA="hdd" ;;
|
||||
esac
|
||||
device=$(basename "$VDEV_UPATH")
|
||||
val=$(cat "/sys/block/$device/queue/rotational" 2>/dev/null)
|
||||
if [ "$val" = "0" ]; then
|
||||
MEDIA="ssd"
|
||||
fi
|
||||
|
||||
vpd_pg83="/sys/block/$device/device/vpd_pg83"
|
||||
if [ -f "$vpd_pg83" ]; then
|
||||
if grep -q --binary "iqn." "$vpd_pg83"; then
|
||||
MEDIA="iscsi"
|
||||
fi
|
||||
if [ "$val" = "1" ]; then
|
||||
MEDIA="hdd"
|
||||
fi
|
||||
else
|
||||
if [ -f "$VDEV_UPATH" ]; then
|
||||
|
|
|
@ -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.
|
||||
ses: Show disk's enc, enc device, slot, and fault/locate LED values."
|
||||
|
||||
script="${0##*/}"
|
||||
script=$(basename "$0")
|
||||
if [ "$1" = "-h" ] ; then
|
||||
echo "$helpstr" | grep "$script:" | tr -s '\t' | cut -f 2-
|
||||
exit
|
||||
|
@ -32,30 +32,16 @@ for i in $scripts ; do
|
|||
val=""
|
||||
case $i in
|
||||
enc)
|
||||
if echo "$VDEV_ENC_SYSFS_PATH" | grep -q '/sys/bus/pci/slots' ; then
|
||||
val="$VDEV_ENC_SYSFS_PATH"
|
||||
else
|
||||
val="$(ls """$VDEV_ENC_SYSFS_PATH/../../""" 2>/dev/null)"
|
||||
fi
|
||||
val=$(ls "$VDEV_ENC_SYSFS_PATH/../../" 2>/dev/null)
|
||||
;;
|
||||
slot)
|
||||
if echo "$VDEV_ENC_SYSFS_PATH" | grep -q '/sys/bus/pci/slots' ; then
|
||||
val="$(basename """$VDEV_ENC_SYSFS_PATH""")"
|
||||
else
|
||||
val="$(cat """$VDEV_ENC_SYSFS_PATH/slot""" 2>/dev/null)"
|
||||
fi
|
||||
val=$(cat "$VDEV_ENC_SYSFS_PATH/slot" 2>/dev/null)
|
||||
;;
|
||||
encdev)
|
||||
val=$(ls "$VDEV_ENC_SYSFS_PATH/../device/scsi_generic" 2>/dev/null)
|
||||
;;
|
||||
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)
|
||||
elif [ -f "$VDEV_ENC_SYSFS_PATH/attention" ] ; then
|
||||
val=$(cat "$VDEV_ENC_SYSFS_PATH/attention" 2>/dev/null)
|
||||
fi
|
||||
val=$(cat "$VDEV_ENC_SYSFS_PATH/fault" 2>/dev/null)
|
||||
;;
|
||||
locate_led)
|
||||
val=$(cat "$VDEV_ENC_SYSFS_PATH/locate" 2>/dev/null)
|
||||
|
|
|
@ -53,7 +53,7 @@ get_filename_from_dir()
|
|||
num_files=$(find "$dir" -maxdepth 1 -type f | wc -l)
|
||||
mod=$((pid % num_files))
|
||||
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
|
||||
echo "$file"
|
||||
break
|
||||
|
@ -62,14 +62,17 @@ get_filename_from_dir()
|
|||
done
|
||||
}
|
||||
|
||||
script="${0##*/}"
|
||||
script=$(basename "$0")
|
||||
|
||||
if [ "$1" = "-h" ] ; then
|
||||
echo "$helpstr" | grep "$script:" | tr -s '\t' | cut -f 2-
|
||||
exit
|
||||
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
|
||||
# cat a smartctl output text file instead of running smartctl
|
||||
# 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"
|
||||
raw_out=$(cat "$samples/$file")
|
||||
else
|
||||
raw_out=$(sudo smartctl -a "$VDEV_UPATH")
|
||||
raw_out=$(eval "sudo $smartctl_path -a $VDEV_UPATH")
|
||||
fi
|
||||
|
||||
# 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")
|
||||
if [ -n "$with_vals" ]; then
|
||||
echo "$with_vals"
|
||||
without_vals=$(echo "$scripts" | tr '|' '\n' |
|
||||
without_vals=$(echo "$scripts" | tr "|" "\n" |
|
||||
grep -v -E "$(echo "$with_vals" |
|
||||
awk -F "=" '{print $1}')" | awk '{print $0"="}')
|
||||
else
|
||||
without_vals=$(echo "$scripts" | tr '|' '\n' | awk '{print $0"="}')
|
||||
without_vals=$(echo "$scripts" | tr "|" "\n" | awk '{print $0"="}')
|
||||
fi
|
||||
|
||||
if [ -n "$without_vals" ]; then
|
||||
|
|
|
@ -264,6 +264,51 @@ for_each_pool(int argc, char **argv, boolean_t unavail,
|
|||
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
|
||||
* 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,
|
||||
&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)
|
||||
{
|
||||
int rc;
|
||||
char *argv[2] = {cmd};
|
||||
char **env;
|
||||
char *argv[2] = {cmd, 0};
|
||||
char *env[5] = {"PATH=/bin:/sbin:/usr/bin:/usr/sbin", NULL, NULL, NULL,
|
||||
NULL};
|
||||
char **lines = NULL;
|
||||
int lines_cnt = 0;
|
||||
int i;
|
||||
|
||||
env = zpool_vdev_script_alloc_env(data->pool, data->path, data->upath,
|
||||
data->vdev_enc_sysfs_path, NULL, NULL);
|
||||
if (env == NULL)
|
||||
/* Setup our custom environment variables */
|
||||
rc = asprintf(&env[1], "VDEV_PATH=%s",
|
||||
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;
|
||||
|
||||
/* Run the command */
|
||||
rc = libzfs_run_process_get_stdout_nopath(cmd, argv, env, &lines,
|
||||
&lines_cnt);
|
||||
|
||||
zpool_vdev_script_free_env(env);
|
||||
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
|
@ -467,6 +522,11 @@ vdev_run_cmd(vdev_cmd_data_t *data, char *cmd)
|
|||
out:
|
||||
if (lines != NULL)
|
||||
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 */
|
||||
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_t *data;
|
||||
|
@ -546,15 +606,10 @@ for_each_vdev_run_cb(void *zhp_data, nvlist_t *nv, void *cb_vcdl)
|
|||
char *vname = NULL;
|
||||
char *vdev_enc_sysfs_path = NULL;
|
||||
int i, match = 0;
|
||||
zpool_handle_t *zhp = zhp_data;
|
||||
|
||||
if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) != 0)
|
||||
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,
|
||||
&vdev_enc_sysfs_path);
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -27,7 +27,6 @@
|
|||
|
||||
#include <libnvpair.h>
|
||||
#include <libzfs.h>
|
||||
#include <libzutil.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -68,6 +67,7 @@ int for_each_pool(int, char **, boolean_t unavail, zprop_list_t **,
|
|||
boolean_t, zpool_iter_f, void *);
|
||||
|
||||
/* 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);
|
||||
|
||||
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(vdev_cmd_data_t *data);
|
||||
|
||||
int vdev_run_cmd_simple(char *path, char *cmd);
|
||||
|
||||
int check_device(const char *path, boolean_t force,
|
||||
boolean_t isspare, boolean_t iswholedisk);
|
||||
boolean_t check_sector_size_database(char *path, int *sector_size);
|
||||
void vdev_error(const char *fmt, ...);
|
||||
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
|
||||
}
|
||||
|
|
|
@ -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_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)
|
||||
verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK,
|
||||
(uint64_t)wholedisk) == 0);
|
||||
|
@ -449,7 +445,7 @@ typedef struct replication_level {
|
|||
|
||||
/*
|
||||
* 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
|
||||
is_raidz_mirror(replication_level_t *a, replication_level_t *b,
|
||||
|
@ -925,15 +921,6 @@ zero_label(char *path)
|
|||
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
|
||||
* 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.
|
||||
*/
|
||||
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;
|
||||
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)) {
|
||||
char *devnode = strrchr(devpath, '/') + 1;
|
||||
char **lines = NULL;
|
||||
int lines_cnt = 0;
|
||||
|
||||
ret = strncmp(udevpath, UDISK_ROOT, strlen(UDISK_ROOT));
|
||||
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
|
||||
* 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,
|
||||
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);
|
||||
if (zpool_label_disk(g_zfs, zhp, devnode) == -1)
|
||||
return (-1);
|
||||
}
|
||||
libzfs_free_str_array(lines, lines_cnt);
|
||||
|
||||
/*
|
||||
* 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++)
|
||||
if ((ret = make_disks(zhp, child[c], replacing)) != 0)
|
||||
if ((ret = make_disks(zhp, child[c])) != 0)
|
||||
return (ret);
|
||||
|
||||
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
|
||||
&child, &children) == 0)
|
||||
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);
|
||||
|
||||
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
|
||||
&child, &children) == 0)
|
||||
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 (0);
|
||||
|
@ -1773,7 +1740,7 @@ split_mirror_vdev(zpool_handle_t *zhp, char *newname, nvlist_t *props,
|
|||
return (NULL);
|
||||
}
|
||||
|
||||
if (!flags.dryrun && make_disks(zhp, newroot, B_FALSE) != 0) {
|
||||
if (!flags.dryrun && make_disks(zhp, newroot) != 0) {
|
||||
nvlist_free(newroot);
|
||||
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.
|
||||
*/
|
||||
if (!dryrun && make_disks(zhp, newroot, replacing) != 0) {
|
||||
if (!dryrun && make_disks(zhp, newroot) != 0) {
|
||||
nvlist_free(newroot);
|
||||
return (NULL);
|
||||
}
|
||||
|
|
|
@ -1360,7 +1360,7 @@
|
|||
"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}",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
|
@ -1664,4 +1664,4 @@
|
|||
"list": []
|
||||
},
|
||||
"version": 2
|
||||
}
|
||||
}
|
|
@ -117,7 +117,6 @@ escape_string(char *s)
|
|||
case '=':
|
||||
case '\\':
|
||||
*d++ = '\\';
|
||||
fallthrough;
|
||||
default:
|
||||
*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,
|
||||
&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));
|
||||
vdev_name[sizeof (vdev_name) - 1] = '\0';
|
||||
|
||||
for (c = 0; c < children; c++) {
|
||||
print_recursive_stats(func, child[c], pool_name,
|
||||
|
|
|
@ -15,6 +15,3 @@ zstream_LDADD = \
|
|||
$(abs_top_builddir)/lib/libnvpair/libnvpair.la
|
||||
|
||||
include $(top_srcdir)/config/CppCheck.am
|
||||
|
||||
install-exec-hook:
|
||||
cd $(DESTDIR)$(sbindir) && $(LN_S) -f zstream zstreamdump
|
||||
|
|
|
@ -49,11 +49,6 @@ zstream_usage(void)
|
|||
int
|
||||
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)
|
||||
zstream_usage();
|
||||
|
||||
|
|
|
@ -297,7 +297,6 @@ zstream_do_dump(int argc, char *argv[])
|
|||
|
||||
fletcher_4_init();
|
||||
while (read_hdr(drr, &zc)) {
|
||||
uint64_t featureflags = 0;
|
||||
|
||||
/*
|
||||
* If this is the first DMU record being processed, check for
|
||||
|
@ -462,18 +461,6 @@ zstream_do_dump(int argc, char *argv[])
|
|||
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);
|
||||
|
||||
if (verbose) {
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
dist_sbin_SCRIPTS = zstreamdump
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
|
||||
zstream dump "$@"
|
|
@ -124,7 +124,6 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <signal.h>
|
||||
#include <umem.h>
|
||||
#include <ctype.h>
|
||||
|
@ -193,58 +192,30 @@ typedef struct ztest_shared_opts {
|
|||
char zo_gvars[ZO_GVARS_MAX_COUNT][ZO_GVARS_MAX_ARGLEN];
|
||||
} 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 = {
|
||||
.zo_pool = DEFAULT_POOL,
|
||||
.zo_dir = DEFAULT_VDEV_DIR,
|
||||
.zo_pool = "ztest",
|
||||
.zo_dir = "/tmp",
|
||||
.zo_alt_ztest = { '\0' },
|
||||
.zo_alt_libpath = { '\0' },
|
||||
.zo_vdevs = DEFAULT_VDEV_COUNT,
|
||||
.zo_ashift = DEFAULT_ASHIFT,
|
||||
.zo_mirrors = DEFAULT_MIRRORS,
|
||||
.zo_raid_children = DEFAULT_RAID_CHILDREN,
|
||||
.zo_raid_parity = DEFAULT_RAID_PARITY,
|
||||
.zo_vdevs = 5,
|
||||
.zo_ashift = SPA_MINBLOCKSHIFT,
|
||||
.zo_mirrors = 2,
|
||||
.zo_raid_children = 4,
|
||||
.zo_raid_parity = 1,
|
||||
.zo_raid_type = VDEV_TYPE_RAIDZ,
|
||||
.zo_vdev_size = DEFAULT_VDEV_SIZE,
|
||||
.zo_draid_data = DEFAULT_DRAID_DATA, /* data drives */
|
||||
.zo_draid_spares = DEFAULT_DRAID_SPARES, /* distributed spares */
|
||||
.zo_datasets = DEFAULT_DATASETS_COUNT,
|
||||
.zo_threads = DEFAULT_THREADS,
|
||||
.zo_passtime = DEFAULT_PASS_TIME,
|
||||
.zo_killrate = DEFAULT_KILL_RATE,
|
||||
.zo_vdev_size = SPA_MINDEVSIZE * 4, /* 256m default size */
|
||||
.zo_draid_data = 4, /* data drives */
|
||||
.zo_draid_spares = 1, /* distributed spares */
|
||||
.zo_datasets = 7,
|
||||
.zo_threads = 23,
|
||||
.zo_passtime = 60, /* 60 seconds */
|
||||
.zo_killrate = 70, /* 70% kill rate */
|
||||
.zo_verbose = 0,
|
||||
.zo_mmp_test = 0,
|
||||
.zo_init = DEFAULT_INITS,
|
||||
.zo_time = DEFAULT_RUN_TIME,
|
||||
.zo_maxloops = DEFAULT_MAX_LOOPS, /* max loops during spa_freeze() */
|
||||
.zo_metaslab_force_ganging = DEFAULT_FORCE_GANGING,
|
||||
.zo_init = 1,
|
||||
.zo_time = 300, /* 5 minutes */
|
||||
.zo_maxloops = 50, /* max loops during spa_freeze() */
|
||||
.zo_metaslab_force_ganging = 64 << 10,
|
||||
.zo_special_vdevs = ZTEST_VDEV_CLASS_RND,
|
||||
.zo_gvars_count = 0,
|
||||
};
|
||||
|
@ -713,154 +684,68 @@ nicenumtoull(const char *buf)
|
|||
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
|
||||
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;
|
||||
|
||||
(void) fprintf(fp, "Usage: %s [OPTIONS...]\n", DEFAULT_POOL);
|
||||
for (int i = 0; option_table[i].short_opt != 0; i++) {
|
||||
if (option_table[i].long_opt_param != NULL) {
|
||||
(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);
|
||||
nicenum(zo->zo_vdev_size, nice_vdev_size, sizeof (nice_vdev_size));
|
||||
nicenum(zo->zo_metaslab_force_ganging, nice_force_ganging,
|
||||
sizeof (nice_force_ganging));
|
||||
|
||||
if (option_table[i].long_opt_param != NULL) {
|
||||
if (option_table[i].default_str != NULL) {
|
||||
(void) fprintf(fp, " (default: %s)",
|
||||
option_table[i].default_str);
|
||||
} else if (option_table[i].default_int != NO_DEFAULT) {
|
||||
(void) fprintf(fp, " (default: %u)",
|
||||
option_table[i].default_int);
|
||||
}
|
||||
}
|
||||
(void) fprintf(fp, "\n");
|
||||
}
|
||||
(void) fprintf(fp, "Usage: %s\n"
|
||||
"\t[-v vdevs (default: %llu)]\n"
|
||||
"\t[-s size_of_each_vdev (default: %s)]\n"
|
||||
"\t[-a alignment_shift (default: %d)] use 0 for random\n"
|
||||
"\t[-m mirror_copies (default: %d)]\n"
|
||||
"\t[-r raidz_disks / draid_disks (default: %d)]\n"
|
||||
"\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"
|
||||
"\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);
|
||||
}
|
||||
|
||||
|
@ -932,10 +817,8 @@ process_options(int argc, char **argv)
|
|||
|
||||
bcopy(&ztest_opts_defaults, zo, sizeof (*zo));
|
||||
|
||||
init_options();
|
||||
|
||||
while ((opt = getopt_long(argc, argv, short_opts, long_opts,
|
||||
NULL)) != EOF) {
|
||||
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) {
|
||||
value = 0;
|
||||
switch (opt) {
|
||||
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 */
|
||||
if (strcmp(raid_kind, "random") == 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().
|
||||
*/
|
||||
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);
|
||||
|
||||
(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
|
||||
* behavior when the data was not recently read into cache.
|
||||
*/
|
||||
ASSERT(doi.doi_data_block_size);
|
||||
ASSERT0(offset % doi.doi_data_block_size);
|
||||
if (ztest_random(4) != 0) {
|
||||
int prefetch = ztest_random(2) ?
|
||||
|
@ -6099,7 +5979,7 @@ ztest_fault_inject(ztest_ds_t *zd, uint64_t id)
|
|||
vd0->vdev_resilver_txg != 0)) {
|
||||
/*
|
||||
* 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
|
||||
* maxfaults == 0 because we'll fail and reexecute,
|
||||
* 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);
|
||||
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);
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
uint64_t cmd = ztest_random(POOL_TRIM_FUNCS);
|
||||
|
|
|
@ -38,39 +38,40 @@
|
|||
static int
|
||||
ioctl_get_msg(char *var, int fd)
|
||||
{
|
||||
int ret;
|
||||
int error = 0;
|
||||
char msg[ZFS_MAX_DATASET_NAME_LEN];
|
||||
|
||||
ret = ioctl(fd, BLKZNAME, msg);
|
||||
if (ret < 0) {
|
||||
return (ret);
|
||||
error = ioctl(fd, BLKZNAME, msg);
|
||||
if (error < 0) {
|
||||
return (error);
|
||||
}
|
||||
|
||||
snprintf(var, ZFS_MAX_DATASET_NAME_LEN, "%s", msg);
|
||||
return (ret);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
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_part = NULL;
|
||||
char *dev_name;
|
||||
struct stat64 statbuf;
|
||||
int dev_minor, dev_part;
|
||||
int i;
|
||||
int rc;
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Usage: %s /dev/zvol_device_node\n", argv[0]);
|
||||
goto fail;
|
||||
printf("Usage: %s /dev/zvol_device_node\n", argv[0]);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
dev_name = argv[1];
|
||||
ret = stat64(dev_name, &statbuf);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Unable to access device file: %s\n", dev_name);
|
||||
goto fail;
|
||||
error = stat64(dev_name, &statbuf);
|
||||
if (error != 0) {
|
||||
printf("Unable to access device file: %s\n", dev_name);
|
||||
return (errno);
|
||||
}
|
||||
|
||||
dev_minor = minor(statbuf.st_rdev);
|
||||
|
@ -78,23 +79,23 @@ main(int argc, char **argv)
|
|||
|
||||
fd = open(dev_name, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "Unable to open device file: %s\n", dev_name);
|
||||
goto fail;
|
||||
printf("Unable to open device file: %s\n", dev_name);
|
||||
return (errno);
|
||||
}
|
||||
|
||||
ret = ioctl_get_msg(zvol_name, fd);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "ioctl_get_msg failed: %s\n", strerror(errno));
|
||||
goto fail;
|
||||
error = ioctl_get_msg(zvol_name, fd);
|
||||
if (error < 0) {
|
||||
printf("ioctl_get_msg failed:%s\n", strerror(errno));
|
||||
return (errno);
|
||||
}
|
||||
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);
|
||||
else
|
||||
ret = asprintf(&zvol_name_part, "%s", zvol_name);
|
||||
rc = asprintf(&zvol_name_part, "%s", zvol_name);
|
||||
|
||||
if (ret == -1 || zvol_name_part == NULL)
|
||||
goto fail;
|
||||
if (rc == -1 || zvol_name_part == NULL)
|
||||
goto error;
|
||||
|
||||
for (i = 0; i < strlen(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);
|
||||
status = EXIT_SUCCESS;
|
||||
|
||||
fail:
|
||||
if (zvol_name_part)
|
||||
free(zvol_name_part);
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
|
||||
return (status);
|
||||
free(zvol_name_part);
|
||||
error:
|
||||
close(fd);
|
||||
return (error);
|
||||
}
|
||||
|
|
|
@ -1,3 +1 @@
|
|||
include $(top_srcdir)/config/Shellcheck.am
|
||||
|
||||
dist_bin_SCRIPTS = zvol_wait
|
||||
|
|
|
@ -9,44 +9,45 @@ count_zvols() {
|
|||
}
|
||||
|
||||
filter_out_zvols_with_links() {
|
||||
echo "$zvols" | tr ' ' '+' | while read -r zvol; do
|
||||
if ! [ -L "/dev/zvol/$zvol" ]; then
|
||||
while read -r zvol; do
|
||||
if [ ! -L "/dev/zvol/$zvol" ]; then
|
||||
echo "$zvol"
|
||||
fi
|
||||
done | tr '+' ' '
|
||||
done
|
||||
}
|
||||
|
||||
filter_out_deleted_zvols() {
|
||||
OIFS="$IFS"
|
||||
IFS="
|
||||
"
|
||||
# shellcheck disable=SC2086
|
||||
zfs list -H -o name $zvols 2>/dev/null
|
||||
IFS="$OIFS"
|
||||
while read -r zvol; do
|
||||
if zfs list "$zvol" >/dev/null 2>&1; then
|
||||
echo "$zvol"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
list_zvols() {
|
||||
read -r default_volmode < /sys/module/zfs/parameters/zvol_volmode
|
||||
zfs list -t volume -H -o \
|
||||
name,volmode,receive_resume_token,redact_snaps,keystatus |
|
||||
while IFS=" " read -r name volmode token redacted keystatus; do # IFS=\t here!
|
||||
|
||||
# /dev links are not created for zvols with volmode = "none",
|
||||
# redacted zvols, or encrypted zvols for which the key has not
|
||||
# been loaded.
|
||||
name,volmode,receive_resume_token,redact_snaps |
|
||||
while read -r zvol_line; do
|
||||
name=$(echo "$zvol_line" | awk '{print $1}')
|
||||
volmode=$(echo "$zvol_line" | awk '{print $2}')
|
||||
token=$(echo "$zvol_line" | awk '{print $3}')
|
||||
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" = "default" ] && [ "$default_volmode" = "3" ] &&
|
||||
continue
|
||||
[ "$redacted" = "-" ] || continue
|
||||
[ "$keystatus" = "unavailable" ] && continue
|
||||
|
||||
# We also ignore partially received zvols if it is
|
||||
#
|
||||
# We also also ignore partially received zvols if it is
|
||||
# not an incremental receive, as those won't even have a block
|
||||
# device minor node created yet.
|
||||
#
|
||||
if [ "$token" != "-" ]; then
|
||||
|
||||
#
|
||||
# Incremental receives create an invisible clone that
|
||||
# is not automatically displayed by zfs list.
|
||||
#
|
||||
if ! zfs list "$name/%recv" >/dev/null 2>&1; then
|
||||
continue
|
||||
fi
|
||||
|
@ -74,7 +75,7 @@ while [ "$outer_loop" -lt 20 ]; do
|
|||
while [ "$inner_loop" -lt 30 ]; do
|
||||
inner_loop=$((inner_loop + 1))
|
||||
|
||||
zvols="$(filter_out_zvols_with_links)"
|
||||
zvols="$(echo "$zvols" | filter_out_zvols_with_links)"
|
||||
|
||||
zvols_count=$(count_zvols)
|
||||
if [ "$zvols_count" -eq 0 ]; then
|
||||
|
@ -94,7 +95,7 @@ while [ "$outer_loop" -lt 20 ]; do
|
|||
echo "No progress since last loop."
|
||||
echo "Checking if any zvols were deleted."
|
||||
|
||||
zvols=$(filter_out_deleted_zvols)
|
||||
zvols=$(echo "$zvols" | filter_out_deleted_zvols)
|
||||
zvols_count=$(count_zvols)
|
||||
|
||||
if [ "$old_zvols_count" -ne "$zvols_count" ]; then
|
||||
|
@ -109,13 +110,6 @@ while [ "$outer_loop" -lt 20 ]; do
|
|||
exit 0
|
||||
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
|
||||
|
||||
echo "Timed out waiting on zvol links"
|
||||
|
|
|
@ -25,9 +25,5 @@ checkabi:
|
|||
storeabi:
|
||||
cd .libs ; \
|
||||
for lib in $(lib_LTLIBRARIES) ; do \
|
||||
abidw --no-show-locs \
|
||||
--no-corpus-path \
|
||||
--no-comp-dir-path \
|
||||
--type-id-style hash \
|
||||
$${lib%.la}.so > ../$${lib%.la}.abi ; \
|
||||
abidw $${lib%.la}.so > ../$${lib%.la}.abi ; \
|
||||
done
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -26,7 +26,6 @@ AM_LIBTOOLFLAGS = --silent
|
|||
AM_CFLAGS = -std=gnu99 -Wall -Wstrict-prototypes -Wmissing-prototypes
|
||||
AM_CFLAGS += -fno-strict-aliasing
|
||||
AM_CFLAGS += $(NO_OMIT_FRAME_POINTER)
|
||||
AM_CFLAGS += $(IMPLICIT_FALLTHROUGH)
|
||||
AM_CFLAGS += $(DEBUG_CFLAGS)
|
||||
AM_CFLAGS += $(ASAN_CFLAGS)
|
||||
AM_CFLAGS += $(CODE_COVERAGE_CFLAGS) $(NO_FORMAT_ZERO_LENGTH)
|
||||
|
@ -40,8 +39,8 @@ AM_CPPFLAGS = -D_GNU_SOURCE
|
|||
AM_CPPFLAGS += -D_REENTRANT
|
||||
AM_CPPFLAGS += -D_FILE_OFFSET_BITS=64
|
||||
AM_CPPFLAGS += -D_LARGEFILE64_SOURCE
|
||||
AM_CPPFLAGS += -DHAVE_LARGE_STACKS=1
|
||||
AM_CPPFLAGS += -DLIBEXECDIR=\"$(libexecdir)\"
|
||||
AM_CPPFLAGS += -DZFSEXECDIR=\"$(zfsexecdir)\"
|
||||
AM_CPPFLAGS += -DRUNSTATEDIR=\"$(runstatedir)\"
|
||||
AM_CPPFLAGS += -DSBINDIR=\"$(sbindir)\"
|
||||
AM_CPPFLAGS += -DSYSCONFDIR=\"$(sysconfdir)\"
|
||||
|
|
|
@ -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
|
|
@ -15,9 +15,7 @@ subst_sed_cmd = \
|
|||
-e 's|@PYTHON[@]|$(PYTHON)|g' \
|
||||
-e 's|@PYTHON_SHEBANG[@]|$(PYTHON_SHEBANG)|g' \
|
||||
-e 's|@DEFAULT_INIT_NFS_SERVER[@]|$(DEFAULT_INIT_NFS_SERVER)|g' \
|
||||
-e 's|@DEFAULT_INIT_SHELL[@]|$(DEFAULT_INIT_SHELL)|g' \
|
||||
-e 's|@LIBFETCH_DYNAMIC[@]|$(LIBFETCH_DYNAMIC)|g' \
|
||||
-e 's|@LIBFETCH_SONAME[@]|$(LIBFETCH_SONAME)|g'
|
||||
-e 's|@DEFAULT_INIT_SHELL[@]|$(DEFAULT_INIT_SHELL)|g'
|
||||
|
||||
SUBSTFILES =
|
||||
CLEANFILES = $(SUBSTFILES)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue