Compare commits

...

23 Commits

Author SHA1 Message Date
Tony Hutter a8c2b7ebc6 Tag zfs-0.7.13
META file and changelog updated.

Signed-off-by: Tony Hutter <hutter2@llnl.gov>
2019-02-22 09:47:55 -08:00
John Wren Kennedy 2af898ee24 test-runner: python3 support
Updated to be compatible with Python 2.6, 2.7, 3.5 or newer.

Reviewed-by: John Ramsden <johnramsden@riseup.net>
Reviewed-by: Neal Gompa <ngompa@datto.com>
Reviewed-by: loli10K <ezomori.nozomu@gmail.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: John Wren Kennedy <john.kennedy@delphix.com>
Closes #8096
2019-02-22 09:47:34 -08:00
Gregor Kopka c32c2f17d0 Fix flake 8 style warnings
Ran zts-report.py and test-runner.py from ./tests/test-runner/bin/
through the 2to3 (https://docs.python.org/2/library/2to3.html).
Checked the result, fixed:
- 'maxint' -> 'maxsize' that 2to3 missed.
- 'cmp=' parameter for a 'sorted()' with a 'key=' version.
- try/except wrapping of configparser import as there are still
  python 2.7 systems that lack a compatibility shim

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Gregor Kopka <gregor@kopka.net>
Closes #7925
Closes #7952
2019-02-22 09:47:34 -08:00
Tony Hutter 2254b2bbbe GCC 9.0: Fix ztest "directive argument is not a nul-terminated string"
GCC 9.0 is complaining because we're trying to print strings that
are defined like this:

.zo_pool = { 'z', 't', 'e', 's', 't', '\0' },

Fix them by making them actual strings.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Tony Hutter <hutter2@llnl.gov>
Closes #8330
2019-02-22 09:47:34 -08:00
Brian Behlendorf 5c4ec382a7 Linux 5.0 compat: Fix bio_set_dev()
The Linux 5.0 kernel updated the bio_set_dev() macro so it calls the
GPL-only bio_associate_blkg() symbol thus inadvertently converting
the entire macro.  Provide a minimal version which always assigns the
request queue's root_blkg to the bio.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #8287
2019-02-22 09:47:34 -08:00
Tony Hutter e22bfd8149 Linux 5.0 compat: Disable vector instructions on 5.0+ kernels
The 5.0 kernel no longer exports the functions we need to do vector
(SSE/SSE2/SSE3/AVX...) instructions.  Disable vector-based checksum
algorithms when building against those kernels.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Tony Hutter <hutter2@llnl.gov>
Closes #8259
2019-02-22 09:47:34 -08:00
Tony Hutter f45ad7bff6 Linux 5.0 compat: Fix SUBDIRs
SUBDIRs has been deprecated for a long time, and was finally removed in
the 5.0 kernel.  Use "M=" instead.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Tony Hutter <hutter2@llnl.gov>
Closes #8257
2019-02-22 09:47:34 -08:00
Tony Hutter 0a3a4d067a Linux 5.0 compat: Convert MS_* macros to SB_*
In the 5.0 kernel, only the mount namespace code should use the MS_*
macos. Filesystems should use the SB_* ones.

https://patchwork.kernel.org/patch/10552493/

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Tony Hutter <hutter2@llnl.gov>
Closes #8264
2019-02-22 09:47:34 -08:00
Tony Hutter ba8024a284 Linux 5.0 compat: Use totalram_pages()
totalram_pages() was converted to an atomic variable in 5.0:

https://patchwork.kernel.org/patch/10652795/

Its value should now be read though the totalram_pages() helper
function.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Tony Hutter <hutter2@llnl.gov>
Closes #8263
2019-02-22 09:47:34 -08:00
Tony Hutter edc2675aed Linux 5.0 compat: access_ok() drops 'type' parameter
access_ok no longer needs a 'type' parameter in the 5.0 kernel.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Tony Hutter <hutter2@llnl.gov>
Closes #8261
2019-02-22 09:47:34 -08:00
ilbsmart 98bb45e27a deadlock between mm_sem and tx assign in zfs_write() and page fault
The bug time sequence:
1. thread #1, `zfs_write` assign a txg "n".
2. In a same process, thread #2, mmap page fault (which means the
   `mm_sem` is hold) occurred, `zfs_dirty_inode` open a txg failed,
   and wait previous txg "n" completed.
3. thread #1 call `uiomove` to write, however page fault is occurred
   in `uiomove`, which means it need `mm_sem`, but `mm_sem` is hold by
   thread #2, so it stuck and can't complete,  then txg "n" will
   not complete.

So thread #1 and thread #2 are deadlocked.

Reviewed-by: Chunwei Chen <tuxoko@gmail.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Matthew Ahrens <mahrens@delphix.com>
Signed-off-by: Grady Wong <grady.w@xtaotech.com>
Closes #7939
2019-02-22 09:47:34 -08:00
Neal Gompa (ニール・ゴンパ) 44f463824b dkms: Enable debuginfo option to be set with zfs sysconfig file
On some Linux distributions, the kernel module build will not
default to building with debuginfo symbols, which can make it
difficult for debugging and testing.

For this case, we provide a flag to override the build to force
debuginfo to be produced for the kernel module build.

Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Co-authored-by: Neal Gompa <ngompa@datto.com>
Co-authored-by: Simon Watson <swatson@datto.com>
Signed-off-by: Neal Gompa <ngompa@datto.com>
Signed-off-by: Simon Watson <swatson@datto.com>
Closes #8304
2019-02-22 09:47:34 -08:00
Neal Gompa (ニール・ゴンパ) b0d579bc55 Bump commit subject length to 72 characters
There's not really a reason to keep the subject length so short,
since the reason to make it this short was for making nice renders
of a summary list of the git log. With 72 characters, this still
works out fine, so let's just raise it to that so that it's easier
to give slightly more descriptive change summaries.

Reviewed by: Matt Ahrens <mahrens@delphix.com>
Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Neal Gompa <ngompa@datto.com>
Closes #8250
2019-02-22 09:47:34 -08:00
Benjamin Gentil 7e5def8ae0 zfs.8 uses wrong snapshot names in Example 15
Reviewed-by: George Melikov <mail@gmelikov.ru>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: bunder2015 <omfgbunder@gmail.com>
Signed-off-by: Benjamin Gentil <benjamin@gentil.io>
Closes #8241
2019-02-22 09:47:34 -08:00
Tony Hutter 89019a846b Add enclosure_symlinks option to vdev_id
Add an 'enclosure_symlinks' option to vdev_id.conf.  This creates
consistently named symlinks to the enclosure devices (/dev/sg*) based
off the configuration in vdev_id.conf.  The enclosure symlinks show
up in /dev/by-enclosure/<prefix>-<channel><num>.  The links make it
make it easy to run sg_ses on a particular enclosure device.  The
enclosure links are created in addition to the normal
/dev/disk/by-vdev links.

'enclosure_symlinks' is only valid in sas_direct configurations.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Simon Guest <simon.guest@tesujimath.org>
Signed-off-by: Tony Hutter <hutter2@llnl.gov>
Closes #8194
2019-02-22 09:47:34 -08:00
Simon Guest 41f7723e9c vdev_id: new slot type ses
This extends vdev_id to support a new slot type, ses, for SCSI Enclosure
Services.  With slot type ses, the disk slot numbers are determined by
using the device slot number reported by sg_ses for the device with
matching SAS address, found by querying all available enclosures.

This is primarily of use on systems with a deficient driver omitting
support for bay_identifier in /sys/devices.  In my testing, I found that
the existing slot types of port and id were not stable across disk
replacement, so an alternative was required.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Simon Guest <simon.guest@tesujimath.org>
Closes #6956
2019-02-22 09:47:34 -08:00
Simon Guest 2b8c3cb0c8 vdev_id: extension for new scsi topology
On systems with SCSI rather than SAS disk topology, this change enables
the vdev_id script to match against the block device path, and therefore
create a vdev alias in /dev/disk/by-vdev.

Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Simon Guest <simon.guest@tesujimath.org>
Closes #6592
2019-02-22 09:47:34 -08:00
Olaf Faaland f325d76e96 Rename macro ZFS_MINOR due to Lustre conflict
Macro ZFS_MINOR, introduced in commit a6cc9756 to record the chosen
static minor number for /dev/zfs, conflicts with an existing macro
in Lustre.  The lustre macro (along with _MAJOR, _PATCH, _FIX) is
used to record the zfsonlinux version Lustre is being built against.

Since the Lustre macro came first, and is used in past versions of
lustre at least going back to 2.10, it makes sense to rename the
macro in ZFS instead of doing so in Lustre which would require
backporting the patch.

Reviewed-by: Giuseppe Di Natale <guss80@gmail.com>
Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Olaf Faaland <faaland1@llnl.gov>
Closes #8195
2019-02-22 09:47:34 -08:00
Brian Behlendorf e3fb781c5f Add kernel module auto-loading
Historically a dynamic misc minor number was registered for the
/dev/zfs device in order to prevent minor number collisions.  This
was fine but it prevented us from being able to use the kernel
module auto-loaded which requires a known reserved value.

Resolve this issue by adding a configure test to find an available
misc minor number which can then be used in MODULE_ALIAS_MISCDEV at
build time.  By adding this alias the zfs kmod is added to the list
of known static-nodes and the systemd-tmpfiles-setup-dev service
will create a /dev/zfs character device at boot time.

This in turn allows us to update the 90-zfs.rules file to make it
aware this is a static node.  The upshot of this is that whenever
a process (zpool, zfs, zed) opens the /dev/zfs the kmods will be
automatic loaded.  This even works for unprivileged users so there
is no longer a need to manually load the modules at boot time.

As an additional bonus the zed now no longer needs to start after
the zfs-import.service since it will trigger the module load.

In the unlikely event the minor number we selected conflicts with
another out of tree unregistered minor number the code falls back
to dynamically allocating it.  In this case the modules again
must be manually loaded.

Note that due to the change in the method of registering the minor
number the zimport.sh test case may incorrectly fail when the
static node for the installed packages is created instead of the
dynamic one.  This issue will only transiently impact zimport.sh
for this single commit when we transition and are mixing and
matching methods.

Reviewed-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
TEST_ZIMPORT_SKIP="yes"
Closes #7287
2019-02-22 09:47:34 -08:00
Ben Wolsieffer 14a5e48fb9 Use autoconf variable for C preprocessor
This fixes the build when cross-compiling, where the preprocessor might
be prefixed.

Reviewed-by: George Melikov <mail@gmelikov.ru>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Signed-off-by: Ben Wolsieffer <benwolsieffer@gmail.com>
Closes #8180
2019-02-22 09:47:34 -08:00
Matthew Ahrens 01937958ce OpenZFS 9577 - remove zfs_dbuf_evict_key tsd
The zfs_dbuf_evict_key TSD (thread-specific data) is not necessary -
we can instead pass a flag down in a few places to prevent recursive
dbuf eviction. Making this change has 3 benefits:

1. The code semantics are easier to understand.
2. On Linux, performance is improved, because creating/removing
   TSD values (by setting to NULL vs non-NULL) is expensive, and
   we do it very often.
3. According to Nexenta, the current semantics can cause a
   deadlock when concurrently calling dmu_objset_evict_dbufs()
   (which is rare today, but they are working on a "parallel
   unmount" change that triggers this more easily):

Porting Notes:
* Minor conflict with OpenZFS 9337 which has not yet been ported.

Authored by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed by: Serapheim Dimitropoulos <serapheim.dimitro@delphix.com>
Reviewed by: Brad Lewis <brad.lewis@delphix.com>
Reviewed-by: George Melikov <mail@gmelikov.ru>
Ported-by: Brian Behlendorf <behlendorf1@llnl.gov>

OpenZFS-issue: https://illumos.org/issues/9577
OpenZFS-commit: https://github.com/openzfs/openzfs/pull/645
External-issue: DLPX-58547
Closes #7602
2019-02-22 09:47:34 -08:00
LOLi edb504f9db Honor --with-mounthelperdir where applicable
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Giuseppe Di Natale <dinatale2@llnl.gov>
Signed-off-by: loli10K <ezomori.nozomu@gmail.com>
Closes #6962
2019-02-22 09:47:34 -08:00
LOLi 2428fbbfcf contrib/initramfs: switch to automake
Use automake to build initramfs scripts and hooks.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: loli10K <ezomori.nozomu@gmail.com>
Closes #6761
2019-02-22 09:47:33 -08:00
54 changed files with 984 additions and 329 deletions

View File

@ -161,7 +161,7 @@ coding convention.
### Commit Message Formats ### Commit Message Formats
#### New Changes #### New Changes
Commit messages for new changes must meet the following guidelines: Commit messages for new changes must meet the following guidelines:
* In 50 characters or less, provide a summary of the change as the * In 72 characters or less, provide a summary of the change as the
first line in the commit message. first line in the commit message.
* A body which provides a description of the change. If necessary, * A body which provides a description of the change. If necessary,
please summarize important information such as why the proposed please summarize important information such as why the proposed

2
META
View File

@ -1,7 +1,7 @@
Meta: 1 Meta: 1
Name: zfs Name: zfs
Branch: 1.0 Branch: 1.0
Version: 0.7.12 Version: 0.7.13
Release: 1 Release: 1
Release-Tags: relext Release-Tags: relext
License: CDDL License: CDDL

View File

@ -7,6 +7,8 @@ DEFAULT_INCLUDES += \
# #
# Ignore the prefix for the mount helper. It must be installed in /sbin/ # Ignore the prefix for the mount helper. It must be installed in /sbin/
# because this path is hardcoded in the mount(8) for security reasons. # because this path is hardcoded in the mount(8) for security reasons.
# However, if needed, the configure option --with-mounthelperdir= can be used
# to override the default install location.
# #
sbindir=$(mounthelperdir) sbindir=$(mounthelperdir)
sbin_PROGRAMS = mount.zfs sbin_PROGRAMS = mount.zfs

View File

@ -100,10 +100,11 @@ usage() {
cat << EOF cat << EOF
Usage: vdev_id [-h] Usage: vdev_id [-h]
vdev_id <-d device> [-c config_file] [-p phys_per_port] vdev_id <-d device> [-c config_file] [-p phys_per_port]
[-g sas_direct|sas_switch] [-m] [-g sas_direct|sas_switch|scsi] [-m]
-c specify name of alernate config file [default=$CONFIG] -c specify name of alernate config file [default=$CONFIG]
-d specify basename of device (i.e. sda) -d specify basename of device (i.e. sda)
-e Create enclose device symlinks only (/dev/by-enclosure)
-g Storage network topology [default="$TOPOLOGY"] -g Storage network topology [default="$TOPOLOGY"]
-m Run in multipath mode -m Run in multipath mode
-p number of phy's per switch port [default=$PHYS_PER_PORT] -p number of phy's per switch port [default=$PHYS_PER_PORT]
@ -135,7 +136,7 @@ map_channel() {
MAPPED_CHAN=`awk "\\$1 == \"channel\" && \\$2 == ${PORT} \ MAPPED_CHAN=`awk "\\$1 == \"channel\" && \\$2 == ${PORT} \
{ print \\$3; exit }" $CONFIG` { print \\$3; exit }" $CONFIG`
;; ;;
"sas_direct") "sas_direct"|"scsi")
MAPPED_CHAN=`awk "\\$1 == \"channel\" && \ MAPPED_CHAN=`awk "\\$1 == \"channel\" && \
\\$2 == \"${PCI_ID}\" && \\$3 == ${PORT} \ \\$2 == \"${PCI_ID}\" && \\$3 == ${PORT} \
{ print \\$4; exit }" $CONFIG` { print \\$4; exit }" $CONFIG`
@ -276,6 +277,23 @@ sas_handler() {
d=$(eval echo \${$i}) d=$(eval echo \${$i})
SLOT=`echo $d | sed -e 's/^.*://'` SLOT=`echo $d | sed -e 's/^.*://'`
;; ;;
"ses")
# look for this SAS path in all SCSI Enclosure Services
# (SES) enclosures
sas_address=`cat $end_device_dir/sas_address 2>/dev/null`
enclosures=`lsscsi -g | \
sed -n -e '/enclosu/s/^.* \([^ ][^ ]*\) *$/\1/p'`
for enclosure in $enclosures; do
set -- $(sg_ses -p aes $enclosure | \
awk "/device slot number:/{slot=\$12} \
/SAS address: $sas_address/\
{print slot}")
SLOT=$1
if [ -n "$SLOT" ] ; then
break
fi
done
;;
esac esac
if [ -z "$SLOT" ] ; then if [ -z "$SLOT" ] ; then
return return
@ -289,6 +307,156 @@ sas_handler() {
echo ${CHAN}${SLOT}${PART} echo ${CHAN}${SLOT}${PART}
} }
scsi_handler() {
if [ -z "$FIRST_BAY_NUMBER" ] ; then
FIRST_BAY_NUMBER=`awk "\\$1 == \"first_bay_number\" \
{print \\$2; exit}" $CONFIG`
fi
FIRST_BAY_NUMBER=${FIRST_BAY_NUMBER:-0}
if [ -z "$PHYS_PER_PORT" ] ; then
PHYS_PER_PORT=`awk "\\$1 == \"phys_per_port\" \
{print \\$2; exit}" $CONFIG`
fi
PHYS_PER_PORT=${PHYS_PER_PORT:-4}
if ! echo $PHYS_PER_PORT | grep -q -E '^[0-9]+$' ; then
echo "Error: phys_per_port value $PHYS_PER_PORT is non-numeric"
exit 1
fi
if [ -z "$MULTIPATH_MODE" ] ; then
MULTIPATH_MODE=`awk "\\$1 == \"multipath\" \
{print \\$2; exit}" $CONFIG`
fi
# Use first running component device if we're handling a dm-mpath device
if [ "$MULTIPATH_MODE" = "yes" ] ; then
# If udev didn't tell us the UUID via DM_NAME, check /dev/mapper
if [ -z "$DM_NAME" ] ; then
DM_NAME=`ls -l --full-time /dev/mapper |
awk "/\/$DEV$/{print \\$9}"`
fi
# For raw disks udev exports DEVTYPE=partition when
# handling partitions, and the rules can be written to
# take advantage of this to append a -part suffix. For
# dm devices we get DEVTYPE=disk even for partitions so
# we have to append the -part suffix directly in the
# helper.
if [ "$DEVTYPE" != "partition" ] ; then
PART=`echo $DM_NAME | awk -Fp '/p/{print "-part"$2}'`
fi
# Strip off partition information.
DM_NAME=`echo $DM_NAME | sed 's/p[0-9][0-9]*$//'`
if [ -z "$DM_NAME" ] ; then
return
fi
# Get the raw scsi device name from multipath -ll. Strip off
# leading pipe symbols to make field numbering consistent.
DEV=`multipath -ll $DM_NAME |
awk '/running/{gsub("^[|]"," "); print $3 ; exit}'`
if [ -z "$DEV" ] ; then
return
fi
fi
if echo $DEV | grep -q ^/devices/ ; then
sys_path=$DEV
else
sys_path=`udevadm info -q path -p /sys/block/$DEV 2>/dev/null`
fi
# expect sys_path like this, for example:
# /devices/pci0000:00/0000:00:0b.0/0000:09:00.0/0000:0a:05.0/0000:0c:00.0/host3/target3:1:0/3:1:0:21/block/sdv
# Use positional parameters as an ad-hoc array
set -- $(echo "$sys_path" | tr / ' ')
num_dirs=$#
scsi_host_dir="/sys"
# Get path up to /sys/.../hostX
i=1
while [ $i -le $num_dirs ] ; do
d=$(eval echo \${$i})
scsi_host_dir="$scsi_host_dir/$d"
echo $d | grep -q -E '^host[0-9]+$' && break
i=$(($i + 1))
done
if [ $i = $num_dirs ] ; then
return
fi
PCI_ID=$(eval echo \${$(($i -1))} | awk -F: '{print $2":"$3}')
# In scsi mode, the directory two levels beneath
# /sys/.../hostX reveals the port and slot.
port_dir=$scsi_host_dir
j=$(($i + 2))
i=$(($i + 1))
while [ $i -le $j ] ; do
port_dir="$port_dir/$(eval echo \${$i})"
i=$(($i + 1))
done
set -- $(echo $port_dir | sed -e 's/^.*:\([^:]*\):\([^:]*\)$/\1 \2/')
PORT=$1
SLOT=$(($2 + $FIRST_BAY_NUMBER))
if [ -z "$SLOT" ] ; then
return
fi
CHAN=`map_channel $PCI_ID $PORT`
SLOT=`map_slot $SLOT $CHAN`
if [ -z "$CHAN" ] ; then
return
fi
echo ${CHAN}${SLOT}${PART}
}
# Figure out the name for the enclosure symlink
enclosure_handler () {
# We get all the info we need from udev's DEVPATH variable:
#
# 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=$(basename $(readlink -m "/sys/$DEVPATH/../.."))
if [ ! -d /sys/class/enclosure/$ENC ] ; then
# Not an enclosure, bail out
return
fi
# Get the long sysfs device path to our enclosure. Looks like:
# /devices/pci0000:00/0000:00:03.0/0000:05:00.0/host0/port-0:0/ ... /enclosure/0:0:0:0
ENC_DEVICE=$(readlink /sys/class/enclosure/$ENC)
# Grab the full path to the hosts port dir:
# /devices/pci0000:00/0000:00:03.0/0000:05:00.0/host0/port-0:0
PORT_DIR=$(echo $ENC_DEVICE | grep -Eo '.+host[0-9]+/port-[0-9]+:[0-9]+')
# Get the port number
PORT_ID=$(echo $PORT_DIR | grep -Eo "[0-9]+$")
# 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=$(basename $(readlink -m "/sys/$PORT_DIR/../.."))
# Strip down the PCI address from 0000:05:00.0 to 05:00.0
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 \$4int(count[\$4])}; count[\$4]++}" $CONFIG)
echo "${NAME}"
}
alias_handler () { alias_handler () {
# Special handling is needed to correctly append a -part suffix # Special handling is needed to correctly append a -part suffix
# to partitions of device mapper devices. The DEVTYPE attribute # to partitions of device mapper devices. The DEVTYPE attribute
@ -344,7 +512,7 @@ alias_handler () {
done done
} }
while getopts 'c:d:g:mp:h' OPTION; do while getopts 'c:d:eg:mp:h' OPTION; do
case ${OPTION} in case ${OPTION} in
c) c)
CONFIG=${OPTARG} CONFIG=${OPTARG}
@ -352,6 +520,16 @@ while getopts 'c:d:g:mp:h' OPTION; do
d) d)
DEV=${OPTARG} DEV=${OPTARG}
;; ;;
e)
# When udev sees a scsi_generic device, it calls this script with -e to
# create the enclosure device symlinks only. We also need
# "enclosure_symlinks yes" set in vdev_id.config to actually create the
# symlink.
ENCLOSURE_MODE=$(awk '{if ($1 == "enclosure_symlinks") print $2}' $CONFIG)
if [ "$ENCLOSURE_MODE" != "yes" ] ; then
exit 0
fi
;;
g) g)
TOPOLOGY=$OPTARG TOPOLOGY=$OPTARG
;; ;;
@ -371,7 +549,7 @@ if [ ! -r $CONFIG ] ; then
exit 0 exit 0
fi fi
if [ -z "$DEV" ] ; then if [ -z "$DEV" -a -z "$ENCLOSURE_MODE" ] ; then
echo "Error: missing required option -d" echo "Error: missing required option -d"
exit 1 exit 1
fi fi
@ -384,16 +562,37 @@ if [ -z "$BAY" ] ; then
BAY=`awk "\\$1 == \"slot\" {print \\$2; exit}" $CONFIG` BAY=`awk "\\$1 == \"slot\" {print \\$2; exit}" $CONFIG`
fi fi
TOPOLOGY=${TOPOLOGY:-sas_direct}
# Should we create /dev/by-enclosure symlinks?
if [ "$ENCLOSURE_MODE" = "yes" -a "$TOPOLOGY" = "sas_direct" ] ; then
ID_ENCLOSURE=$(enclosure_handler)
if [ -z "$ID_ENCLOSURE" ] ; then
exit 0
fi
# Just create the symlinks to the enclosure devices and then exit.
ENCLOSURE_PREFIX=$(awk '/enclosure_symlinks_prefix/{print $2}' $CONFIG)
if [ -z "$ENCLOSURE_PREFIX" ] ; then
ENCLOSURE_PREFIX="enc"
fi
echo "ID_ENCLOSURE=$ID_ENCLOSURE"
echo "ID_ENCLOSURE_PATH=by-enclosure/$ENCLOSURE_PREFIX-$ID_ENCLOSURE"
exit 0
fi
# First check if an alias was defined for this device. # First check if an alias was defined for this device.
ID_VDEV=`alias_handler` ID_VDEV=`alias_handler`
if [ -z "$ID_VDEV" ] ; then if [ -z "$ID_VDEV" ] ; then
BAY=${BAY:-bay} BAY=${BAY:-bay}
TOPOLOGY=${TOPOLOGY:-sas_direct}
case $TOPOLOGY in case $TOPOLOGY in
sas_direct|sas_switch) sas_direct|sas_switch)
ID_VDEV=`sas_handler` ID_VDEV=`sas_handler`
;; ;;
scsi)
ID_VDEV=`scsi_handler`
;;
*) *)
echo "Error: unknown topology $TOPOLOGY" echo "Error: unknown topology $TOPOLOGY"
exit 1 exit 1

View File

@ -171,8 +171,8 @@ typedef struct ztest_shared_opts {
} ztest_shared_opts_t; } ztest_shared_opts_t;
static const ztest_shared_opts_t ztest_opts_defaults = { static const ztest_shared_opts_t ztest_opts_defaults = {
.zo_pool = { 'z', 't', 'e', 's', 't', '\0' }, .zo_pool = "ztest",
.zo_dir = { '/', 't', 'm', 'p', '\0' }, .zo_dir = "/tmp",
.zo_alt_ztest = { '\0' }, .zo_alt_ztest = { '\0' },
.zo_alt_libpath = { '\0' }, .zo_alt_libpath = { '\0' },
.zo_vdevs = 5, .zo_vdevs = 5,

View File

@ -0,0 +1,21 @@
dnl #
dnl # Linux 5.0: access_ok() drops 'type' parameter:
dnl #
dnl # - access_ok(type, addr, size)
dnl # + access_ok(addr, size)
dnl #
AC_DEFUN([ZFS_AC_KERNEL_ACCESS_OK_TYPE], [
AC_MSG_CHECKING([whether access_ok() has 'type' parameter])
ZFS_LINUX_TRY_COMPILE([
#include <linux/uaccess.h>
],[
const void __user __attribute__((unused)) *addr = (void *) 0xdeadbeef;
unsigned long __attribute__((unused)) size = 1;
int error __attribute__((unused)) = access_ok(0, addr, size);
],[
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_ACCESS_OK_TYPE, 1, [kernel has access_ok with 'type' parameter])
],[
AC_MSG_RESULT(no)
])
])

View File

@ -1,10 +1,10 @@
dnl # dnl #
dnl # Linux 4.14 API, dnl # Linux 4.14 API,
dnl # dnl #
dnl # The bio_set_dev() helper was introduced as part of the transition dnl # The bio_set_dev() helper macro was introduced as part of the transition
dnl # to have struct gendisk in struct bio. dnl # to have struct gendisk in struct bio.
dnl # dnl #
AC_DEFUN([ZFS_AC_KERNEL_BIO_SET_DEV], [ AC_DEFUN([ZFS_AC_KERNEL_BIO_SET_DEV_MACRO], [
AC_MSG_CHECKING([whether bio_set_dev() exists]) AC_MSG_CHECKING([whether bio_set_dev() exists])
ZFS_LINUX_TRY_COMPILE([ ZFS_LINUX_TRY_COMPILE([
#include <linux/bio.h> #include <linux/bio.h>
@ -20,3 +20,34 @@ AC_DEFUN([ZFS_AC_KERNEL_BIO_SET_DEV], [
AC_MSG_RESULT(no) AC_MSG_RESULT(no)
]) ])
]) ])
dnl #
dnl # Linux 5.0 API,
dnl #
dnl # The bio_set_dev() helper macro was updated to internally depend on
dnl # bio_associate_blkg() symbol which is exported GPL-only.
dnl #
AC_DEFUN([ZFS_AC_KERNEL_BIO_SET_DEV_GPL_ONLY], [
AC_MSG_CHECKING([whether bio_set_dev() is GPL-only])
ZFS_LINUX_TRY_COMPILE([
#include <linux/module.h>
#include <linux/bio.h>
#include <linux/fs.h>
MODULE_LICENSE("$ZFS_META_LICENSE");
],[
struct block_device *bdev = NULL;
struct bio *bio = NULL;
bio_set_dev(bio, bdev);
],[
AC_MSG_RESULT(no)
],[
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_BIO_SET_DEV_GPL_ONLY, 1,
[bio_set_dev() GPL-only])
])
])
AC_DEFUN([ZFS_AC_KERNEL_BIO_SET_DEV], [
ZFS_AC_KERNEL_BIO_SET_DEV_MACRO
ZFS_AC_KERNEL_BIO_SET_DEV_GPL_ONLY
])

View File

@ -1,18 +1,41 @@
dnl # dnl #
dnl # 4.2 API change dnl # Handle differences in kernel FPU code.
dnl # asm/i387.h is replaced by asm/fpu/api.h dnl #
dnl # Kernel
dnl # 5.0: All kernel fpu functions are GPL only, so we can't use them.
dnl # (nothing defined)
dnl #
dnl # 4.2: Use __kernel_fpu_{begin,end}()
dnl # HAVE_UNDERSCORE_KERNEL_FPU & KERNEL_EXPORTS_X86_FPU
dnl #
dnl # Pre-4.2: Use kernel_fpu_{begin,end}()
dnl # HAVE_KERNEL_FPU & KERNEL_EXPORTS_X86_FPU
dnl # dnl #
AC_DEFUN([ZFS_AC_KERNEL_FPU], [ AC_DEFUN([ZFS_AC_KERNEL_FPU], [
AC_MSG_CHECKING([whether asm/fpu/api.h exists]) AC_MSG_CHECKING([which kernel_fpu function to use])
ZFS_LINUX_TRY_COMPILE([ ZFS_LINUX_TRY_COMPILE([
#include <linux/kernel.h> #include <asm/i387.h>
#include <asm/fpu/api.h> #include <asm/xcr.h>
],[ ],[
__kernel_fpu_begin(); kernel_fpu_begin();
kernel_fpu_end();
],[ ],[
AC_MSG_RESULT(yes) AC_MSG_RESULT(kernel_fpu_*)
AC_DEFINE(HAVE_FPU_API_H, 1, [kernel has <asm/fpu/api.h> interface]) AC_DEFINE(HAVE_KERNEL_FPU, 1, [kernel has kernel_fpu_* functions])
AC_DEFINE(KERNEL_EXPORTS_X86_FPU, 1, [kernel exports FPU functions])
],[ ],[
AC_MSG_RESULT(no) ZFS_LINUX_TRY_COMPILE([
#include <linux/kernel.h>
#include <asm/fpu/api.h>
],[
__kernel_fpu_begin();
__kernel_fpu_end();
],[
AC_MSG_RESULT(__kernel_fpu_*)
AC_DEFINE(HAVE_UNDERSCORE_KERNEL_FPU, 1, [kernel has __kernel_fpu_* functions])
AC_DEFINE(KERNEL_EXPORTS_X86_FPU, 1, [kernel exports FPU functions])
],[
AC_MSG_RESULT(not exported)
])
]) ])
]) ])

View File

@ -0,0 +1,26 @@
dnl #
dnl # Determine an available miscellaneous minor number which can be used
dnl # for the /dev/zfs device. This is needed because kernel module
dnl # auto-loading depends on registering a reserved non-conflicting minor
dnl # number. Start with a large known available unreserved minor and work
dnl # our way down to lower value if a collision is detected.
dnl #
AC_DEFUN([ZFS_AC_KERNEL_MISC_MINOR], [
AC_MSG_CHECKING([for available /dev/zfs minor])
for i in $(seq 249 -1 200); do
if ! grep -q "^#define\s\+.*_MINOR\s\+.*$i" \
${LINUX}/include/linux/miscdevice.h; then
ZFS_DEVICE_MINOR="$i"
AC_MSG_RESULT($ZFS_DEVICE_MINOR)
AC_DEFINE_UNQUOTED([ZFS_DEVICE_MINOR],
[$ZFS_DEVICE_MINOR], [/dev/zfs minor])
break
fi
done
AS_IF([ test -z "$ZFS_DEVICE_MINOR"], [
AC_MSG_ERROR([
*** No available misc minor numbers available for use.])
])
])

View File

@ -5,7 +5,9 @@ AC_DEFUN([ZFS_AC_CONFIG_KERNEL], [
ZFS_AC_KERNEL ZFS_AC_KERNEL
ZFS_AC_SPL ZFS_AC_SPL
ZFS_AC_QAT ZFS_AC_QAT
ZFS_AC_KERNEL_ACCESS_OK_TYPE
ZFS_AC_TEST_MODULE ZFS_AC_TEST_MODULE
ZFS_AC_KERNEL_MISC_MINOR
ZFS_AC_KERNEL_OBJTOOL ZFS_AC_KERNEL_OBJTOOL
ZFS_AC_KERNEL_CONFIG ZFS_AC_KERNEL_CONFIG
ZFS_AC_KERNEL_DECLARE_EVENT_CLASS ZFS_AC_KERNEL_DECLARE_EVENT_CLASS
@ -255,7 +257,7 @@ AC_DEFUN([ZFS_AC_KERNEL], [
AS_IF([test "$utsrelease"], [ AS_IF([test "$utsrelease"], [
kernsrcver=`(echo "#include <$utsrelease>"; kernsrcver=`(echo "#include <$utsrelease>";
echo "kernsrcver=UTS_RELEASE") | echo "kernsrcver=UTS_RELEASE") |
cpp -I $kernelbuild/include | ${CPP} -I $kernelbuild/include - |
grep "^kernsrcver=" | cut -d \" -f 2` grep "^kernsrcver=" | cut -d \" -f 2`
AS_IF([test -z "$kernsrcver"], [ AS_IF([test -z "$kernsrcver"], [

View File

@ -122,6 +122,9 @@ AC_CONFIG_FILES([
contrib/dracut/02zfsexpandknowledge/Makefile contrib/dracut/02zfsexpandknowledge/Makefile
contrib/dracut/90zfs/Makefile contrib/dracut/90zfs/Makefile
contrib/initramfs/Makefile contrib/initramfs/Makefile
contrib/initramfs/hooks/Makefile
contrib/initramfs/scripts/Makefile
contrib/initramfs/scripts/local-top/Makefile
module/Makefile module/Makefile
module/avl/Makefile module/avl/Makefile
module/nvpair/Makefile module/nvpair/Makefile

View File

@ -24,6 +24,7 @@ $(pkgdracut_SCRIPTS):%:%.in
-e 's,@udevruledir\@,$(udevruledir),g' \ -e 's,@udevruledir\@,$(udevruledir),g' \
-e 's,@sysconfdir\@,$(sysconfdir),g' \ -e 's,@sysconfdir\@,$(sysconfdir),g' \
-e 's,@systemdunitdir\@,$(systemdunitdir),g' \ -e 's,@systemdunitdir\@,$(systemdunitdir),g' \
-e 's,@mounthelperdir\@,$(mounthelperdir),g' \
$< >'$@' $< >'$@'
distclean-local:: distclean-local::

View File

@ -5,7 +5,7 @@ check() {
[ "${1}" = "-d" ] && return 0 [ "${1}" = "-d" ] && return 0
# Verify the zfs tool chain # Verify the zfs tool chain
for tool in "@sbindir@/zpool" "@sbindir@/zfs" "@sbindir@/mount.zfs" ; do for tool in "@sbindir@/zpool" "@sbindir@/zfs" "@mounthelperdir@/mount.zfs" ; do
test -x "$tool" || return 1 test -x "$tool" || return 1
done done
# Verify grep exists # Verify grep exists
@ -53,7 +53,7 @@ install() {
# Fallback: Guess the path and include all matches # Fallback: Guess the path and include all matches
dracut_install /usr/lib/gcc/*/*/libgcc_s.so* dracut_install /usr/lib/gcc/*/*/libgcc_s.so*
fi fi
dracut_install @sbindir@/mount.zfs dracut_install @mounthelperdir@/mount.zfs
dracut_install @udevdir@/vdev_id dracut_install @udevdir@/vdev_id
dracut_install awk dracut_install awk
dracut_install head dracut_install head

View File

@ -3,12 +3,11 @@ initrddir = $(datarootdir)/initramfs-tools
initrd_SCRIPTS = \ initrd_SCRIPTS = \
conf.d/zfs conf-hooks.d/zfs hooks/zfs scripts/zfs scripts/local-top/zfs conf.d/zfs conf-hooks.d/zfs hooks/zfs scripts/zfs scripts/local-top/zfs
SUBDIRS = hooks scripts
EXTRA_DIST = \ EXTRA_DIST = \
$(top_srcdir)/contrib/initramfs/conf.d/zfs \ $(top_srcdir)/contrib/initramfs/conf.d/zfs \
$(top_srcdir)/contrib/initramfs/conf-hooks.d/zfs \ $(top_srcdir)/contrib/initramfs/conf-hooks.d/zfs \
$(top_srcdir)/contrib/initramfs/hooks/zfs \
$(top_srcdir)/contrib/initramfs/scripts/zfs \
$(top_srcdir)/contrib/initramfs/scripts/local-top/zfs \
$(top_srcdir)/contrib/initramfs/README.initramfs.markdown $(top_srcdir)/contrib/initramfs/README.initramfs.markdown
install-initrdSCRIPTS: $(EXTRA_DIST) install-initrdSCRIPTS: $(EXTRA_DIST)

1
contrib/initramfs/hooks/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
zfs

View File

@ -0,0 +1,21 @@
hooksdir = $(datarootdir)/initramfs-tools/hooks
hooks_SCRIPTS = \
zfs
EXTRA_DIST = \
$(top_srcdir)/contrib/initramfs/hooks/zfs.in
$(hooks_SCRIPTS):%:%.in
-$(SED) -e 's,@sbindir\@,$(sbindir),g' \
-e 's,@sysconfdir\@,$(sysconfdir),g' \
-e 's,@udevdir\@,$(udevdir),g' \
-e 's,@udevruledir\@,$(udevruledir),g' \
-e 's,@mounthelperdir\@,$(mounthelperdir),g' \
$< >'$@'
clean-local::
-$(RM) $(hooks_SCRIPTS)
distclean-local::
-$(RM) $(hooks_SCRIPTS)

View File

@ -8,11 +8,13 @@ PREREQ="zdev"
# These prerequisites are provided by the zfsutils package. The zdb utility is # These prerequisites are provided by the zfsutils package. The zdb utility is
# not strictly required, but it can be useful at the initramfs recovery prompt. # not strictly required, but it can be useful at the initramfs recovery prompt.
COPY_EXEC_LIST="/sbin/zdb /sbin/zpool /sbin/zfs /sbin/mount.zfs" COPY_EXEC_LIST="@sbindir@/zdb @sbindir@/zpool @sbindir@/zfs"
COPY_EXEC_LIST="$COPY_EXEC_LIST /usr/bin/dirname /lib/udev/vdev_id" COPY_EXEC_LIST="$COPY_EXEC_LIST @mounthelperdir@/mount.zfs @udevdir@/vdev_id"
COPY_FILE_LIST="/etc/hostid /etc/zfs/zpool.cache /etc/default/zfs" COPY_FILE_LIST="/etc/hostid @sysconfdir@/zfs/zpool.cache"
COPY_FILE_LIST="$COPY_FILE_LIST /etc/zfs/zfs-functions /etc/zfs/vdev_id.conf" COPY_FILE_LIST="$COPY_FILE_LIST @sysconfdir@/default/zfs"
COPY_FILE_LIST="$COPY_FILE_LIST /lib/udev/rules.d/69-vdev.rules" COPY_FILE_LIST="$COPY_FILE_LIST @sysconfdir@/zfs/zfs-functions"
COPY_FILE_LIST="$COPY_FILE_LIST @sysconfdir@/zfs/vdev_id.conf"
COPY_FILE_LIST="$COPY_FILE_LIST @udevruledir@/69-vdev.rules"
# These prerequisites are provided by the base system. # These prerequisites are provided by the base system.
COPY_EXEC_LIST="$COPY_EXEC_LIST /usr/bin/dirname /bin/hostname /sbin/blkid" COPY_EXEC_LIST="$COPY_EXEC_LIST /usr/bin/dirname /bin/hostname /sbin/blkid"

1
contrib/initramfs/scripts/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
zfs

View File

@ -0,0 +1,20 @@
scriptsdir = $(datarootdir)/initramfs-tools/scripts
scripts_SCRIPTS = \
zfs
SUBDIRS = local-top
EXTRA_DIST = \
$(top_srcdir)/contrib/initramfs/scripts/zfs.in
$(scripts_SCRIPTS):%:%.in
-$(SED) -e 's,@sbindir\@,$(sbindir),g' \
-e 's,@sysconfdir\@,$(sysconfdir),g' \
$< >'$@'
clean-local::
-$(RM) $(scripts_SCRIPTS)
distclean-local::
-$(RM) $(scripts_SCRIPTS)

View File

@ -0,0 +1,3 @@
localtopdir = $(datarootdir)/initramfs-tools/scripts/local-top
EXTRA_DIST = zfs

View File

@ -11,9 +11,9 @@
# Paths to what we need - in the initrd, these paths are hardcoded, # Paths to what we need - in the initrd, these paths are hardcoded,
# so override the defines in zfs-functions. # so override the defines in zfs-functions.
ZFS="/sbin/zfs" ZFS="@sbindir@/zfs"
ZPOOL="/sbin/zpool" ZPOOL="@sbindir@/zpool"
ZPOOL_CACHE="/etc/zfs/zpool.cache" ZPOOL_CACHE="@sysconfdir@/zfs/zpool.cache"
export ZFS ZPOOL ZPOOL_CACHE export ZFS ZPOOL ZPOOL_CACHE
# This runs any scripts that should run before we start importing # This runs any scripts that should run before we start importing

View File

@ -1,3 +1,3 @@
# Always load kernel modules at boot. The default behavior is to load the # The default behavior is to allow udev to load the kernel modules on demand.
# kernel modules in the zfs-import-*.service or when blkid(8) detects a pool. # Uncomment the following line to unconditionally load them at boot.
#zfs #zfs

View File

@ -12,7 +12,6 @@ ConditionPathExists=@sysconfdir@/zfs/zpool.cache
[Service] [Service]
Type=oneshot Type=oneshot
RemainAfterExit=yes RemainAfterExit=yes
ExecStartPre=-/sbin/modprobe zfs
ExecStart=@sbindir@/zpool import -c @sysconfdir@/zfs/zpool.cache -aN ExecStart=@sbindir@/zpool import -c @sysconfdir@/zfs/zpool.cache -aN
[Install] [Install]

View File

@ -11,7 +11,6 @@ ConditionPathExists=!@sysconfdir@/zfs/zpool.cache
[Service] [Service]
Type=oneshot Type=oneshot
RemainAfterExit=yes RemainAfterExit=yes
ExecStartPre=-/sbin/modprobe zfs
ExecStart=@sbindir@/zpool import -aN -o cachefile=none ExecStart=@sbindir@/zpool import -aN -o cachefile=none
[Install] [Install]

View File

@ -4,6 +4,7 @@ pkgsysconf_DATA = \
vdev_id.conf.alias.example \ vdev_id.conf.alias.example \
vdev_id.conf.sas_direct.example \ vdev_id.conf.sas_direct.example \
vdev_id.conf.sas_switch.example \ vdev_id.conf.sas_switch.example \
vdev_id.conf.multipath.example vdev_id.conf.multipath.example \
vdev_id.conf.scsi.example
EXTRA_DIST = $(pkgsysconf_DATA) EXTRA_DIST = $(pkgsysconf_DATA)

View File

@ -2,6 +2,9 @@ multipath no
topology sas_direct topology sas_direct
phys_per_port 4 phys_per_port 4
# Additionally create /dev/by-enclousure/ symlinks for enclosure devices
enclosure_symlinks yes
# PCI_ID HBA PORT CHANNEL NAME # PCI_ID HBA PORT CHANNEL NAME
channel 85:00.0 1 A channel 85:00.0 1 A
channel 85:00.0 0 B channel 85:00.0 0 B

View File

@ -0,0 +1,9 @@
multipath no
topology scsi
phys_per_port 1
# Usually scsi disks are numbered from 0, but this can be offset, to
# match the physical bay numbers, as follows:
first_bay_number 1
# PCI_ID HBA PORT CHANNEL NAME
channel 0c:00.0 0 Y

View File

@ -27,6 +27,7 @@
#define _ZFS_KMAP_H #define _ZFS_KMAP_H
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/uaccess.h>
#ifdef HAVE_1ARG_KMAP_ATOMIC #ifdef HAVE_1ARG_KMAP_ATOMIC
/* 2.6.37 API change */ /* 2.6.37 API change */
@ -37,4 +38,11 @@
#define zfs_kunmap_atomic(addr, km_type) kunmap_atomic(addr, km_type) #define zfs_kunmap_atomic(addr, km_type) kunmap_atomic(addr, km_type)
#endif #endif
/* 5.0 API change - no more 'type' argument for access_ok() */
#ifdef HAVE_ACCESS_OK_TYPE
#define zfs_access_ok(type, addr, size) access_ok(type, addr, size)
#else
#define zfs_access_ok(type, addr, size) access_ok(addr, size)
#endif
#endif /* _ZFS_KMAP_H */ #endif /* _ZFS_KMAP_H */

View File

@ -81,7 +81,7 @@
#endif #endif
#if defined(_KERNEL) #if defined(_KERNEL)
#if defined(HAVE_FPU_API_H) #if defined(HAVE_UNDERSCORE_KERNEL_FPU)
#include <asm/fpu/api.h> #include <asm/fpu/api.h>
#include <asm/fpu/internal.h> #include <asm/fpu/internal.h>
#define kfpu_begin() \ #define kfpu_begin() \
@ -94,12 +94,18 @@
__kernel_fpu_end(); \ __kernel_fpu_end(); \
preempt_enable(); \ preempt_enable(); \
} }
#else #elif defined(HAVE_KERNEL_FPU)
#include <asm/i387.h> #include <asm/i387.h>
#include <asm/xcr.h> #include <asm/xcr.h>
#define kfpu_begin() kernel_fpu_begin() #define kfpu_begin() kernel_fpu_begin()
#define kfpu_end() kernel_fpu_end() #define kfpu_end() kernel_fpu_end()
#endif /* defined(HAVE_FPU_API_H) */ #else
/* Kernel doesn't export any kernel_fpu_* functions */
#include <asm/fpu/internal.h> /* For kernel xgetbv() */
#define kfpu_begin() panic("This code should never run")
#define kfpu_end() panic("This code should never run")
#endif /* defined(HAVE_KERNEL_FPU) */
#else #else
/* /*
* fpu dummy methods for userspace * fpu dummy methods for userspace
@ -278,11 +284,13 @@ __simd_state_enabled(const uint64_t state)
boolean_t has_osxsave; boolean_t has_osxsave;
uint64_t xcr0; uint64_t xcr0;
#if defined(_KERNEL) && defined(X86_FEATURE_OSXSAVE) #if defined(_KERNEL)
#if defined(X86_FEATURE_OSXSAVE) && defined(KERNEL_EXPORTS_X86_FPU)
has_osxsave = !!boot_cpu_has(X86_FEATURE_OSXSAVE); has_osxsave = !!boot_cpu_has(X86_FEATURE_OSXSAVE);
#elif defined(_KERNEL) && !defined(X86_FEATURE_OSXSAVE)
has_osxsave = B_FALSE;
#else #else
has_osxsave = B_FALSE;
#endif
#elif !defined(_KERNEL)
has_osxsave = __cpuid_has_osxsave(); has_osxsave = __cpuid_has_osxsave();
#endif #endif
@ -307,8 +315,12 @@ static inline boolean_t
zfs_sse_available(void) zfs_sse_available(void)
{ {
#if defined(_KERNEL) #if defined(_KERNEL)
#if defined(KERNEL_EXPORTS_X86_FPU)
return (!!boot_cpu_has(X86_FEATURE_XMM)); return (!!boot_cpu_has(X86_FEATURE_XMM));
#else #else
return (B_FALSE);
#endif
#elif !defined(_KERNEL)
return (__cpuid_has_sse()); return (__cpuid_has_sse());
#endif #endif
} }
@ -320,8 +332,12 @@ static inline boolean_t
zfs_sse2_available(void) zfs_sse2_available(void)
{ {
#if defined(_KERNEL) #if defined(_KERNEL)
#if defined(KERNEL_EXPORTS_X86_FPU)
return (!!boot_cpu_has(X86_FEATURE_XMM2)); return (!!boot_cpu_has(X86_FEATURE_XMM2));
#else #else
return (B_FALSE);
#endif
#elif !defined(_KERNEL)
return (__cpuid_has_sse2()); return (__cpuid_has_sse2());
#endif #endif
} }
@ -333,8 +349,12 @@ static inline boolean_t
zfs_sse3_available(void) zfs_sse3_available(void)
{ {
#if defined(_KERNEL) #if defined(_KERNEL)
#if defined(KERNEL_EXPORTS_X86_FPU)
return (!!boot_cpu_has(X86_FEATURE_XMM3)); return (!!boot_cpu_has(X86_FEATURE_XMM3));
#else #else
return (B_FALSE);
#endif
#elif !defined(_KERNEL)
return (__cpuid_has_sse3()); return (__cpuid_has_sse3());
#endif #endif
} }
@ -346,8 +366,12 @@ static inline boolean_t
zfs_ssse3_available(void) zfs_ssse3_available(void)
{ {
#if defined(_KERNEL) #if defined(_KERNEL)
#if defined(KERNEL_EXPORTS_X86_FPU)
return (!!boot_cpu_has(X86_FEATURE_SSSE3)); return (!!boot_cpu_has(X86_FEATURE_SSSE3));
#else #else
return (B_FALSE);
#endif
#elif !defined(_KERNEL)
return (__cpuid_has_ssse3()); return (__cpuid_has_ssse3());
#endif #endif
} }
@ -359,8 +383,12 @@ static inline boolean_t
zfs_sse4_1_available(void) zfs_sse4_1_available(void)
{ {
#if defined(_KERNEL) #if defined(_KERNEL)
#if defined(KERNEL_EXPORTS_X86_FPU)
return (!!boot_cpu_has(X86_FEATURE_XMM4_1)); return (!!boot_cpu_has(X86_FEATURE_XMM4_1));
#else #else
return (B_FALSE);
#endif
#elif !defined(_KERNEL)
return (__cpuid_has_sse4_1()); return (__cpuid_has_sse4_1());
#endif #endif
} }
@ -372,8 +400,12 @@ static inline boolean_t
zfs_sse4_2_available(void) zfs_sse4_2_available(void)
{ {
#if defined(_KERNEL) #if defined(_KERNEL)
#if defined(KERNEL_EXPORTS_X86_FPU)
return (!!boot_cpu_has(X86_FEATURE_XMM4_2)); return (!!boot_cpu_has(X86_FEATURE_XMM4_2));
#else #else
return (B_FALSE);
#endif
#elif !defined(_KERNEL)
return (__cpuid_has_sse4_2()); return (__cpuid_has_sse4_2());
#endif #endif
} }
@ -386,8 +418,12 @@ zfs_avx_available(void)
{ {
boolean_t has_avx; boolean_t has_avx;
#if defined(_KERNEL) #if defined(_KERNEL)
#if defined(KERNEL_EXPORTS_X86_FPU)
has_avx = !!boot_cpu_has(X86_FEATURE_AVX); has_avx = !!boot_cpu_has(X86_FEATURE_AVX);
#else #else
has_avx = B_FALSE;
#endif
#elif !defined(_KERNEL)
has_avx = __cpuid_has_avx(); has_avx = __cpuid_has_avx();
#endif #endif
@ -401,11 +437,13 @@ static inline boolean_t
zfs_avx2_available(void) zfs_avx2_available(void)
{ {
boolean_t has_avx2; boolean_t has_avx2;
#if defined(_KERNEL) && defined(X86_FEATURE_AVX2) #if defined(_KERNEL)
#if defined(X86_FEATURE_AVX2) && defined(KERNEL_EXPORTS_X86_FPU)
has_avx2 = !!boot_cpu_has(X86_FEATURE_AVX2); has_avx2 = !!boot_cpu_has(X86_FEATURE_AVX2);
#elif defined(_KERNEL) && !defined(X86_FEATURE_AVX2)
has_avx2 = B_FALSE;
#else #else
has_avx2 = B_FALSE;
#endif
#elif !defined(_KERNEL)
has_avx2 = __cpuid_has_avx2(); has_avx2 = __cpuid_has_avx2();
#endif #endif
@ -418,11 +456,13 @@ zfs_avx2_available(void)
static inline boolean_t static inline boolean_t
zfs_bmi1_available(void) zfs_bmi1_available(void)
{ {
#if defined(_KERNEL) && defined(X86_FEATURE_BMI1) #if defined(_KERNEL)
#if defined(X86_FEATURE_BMI1) && defined(KERNEL_EXPORTS_X86_FPU)
return (!!boot_cpu_has(X86_FEATURE_BMI1)); return (!!boot_cpu_has(X86_FEATURE_BMI1));
#elif defined(_KERNEL) && !defined(X86_FEATURE_BMI1)
return (B_FALSE);
#else #else
return (B_FALSE);
#endif
#elif !defined(_KERNEL)
return (__cpuid_has_bmi1()); return (__cpuid_has_bmi1());
#endif #endif
} }
@ -433,16 +473,17 @@ zfs_bmi1_available(void)
static inline boolean_t static inline boolean_t
zfs_bmi2_available(void) zfs_bmi2_available(void)
{ {
#if defined(_KERNEL) && defined(X86_FEATURE_BMI2) #if defined(_KERNEL)
#if defined(X86_FEATURE_BMI2) && defined(KERNEL_EXPORTS_X86_FPU)
return (!!boot_cpu_has(X86_FEATURE_BMI2)); return (!!boot_cpu_has(X86_FEATURE_BMI2));
#elif defined(_KERNEL) && !defined(X86_FEATURE_BMI2)
return (B_FALSE);
#else #else
return (B_FALSE);
#endif
#elif !defined(_KERNEL)
return (__cpuid_has_bmi2()); return (__cpuid_has_bmi2());
#endif #endif
} }
/* /*
* AVX-512 family of instruction sets: * AVX-512 family of instruction sets:
* *
@ -466,8 +507,12 @@ zfs_avx512f_available(void)
{ {
boolean_t has_avx512 = B_FALSE; boolean_t has_avx512 = B_FALSE;
#if defined(_KERNEL) && defined(X86_FEATURE_AVX512F) #if defined(_KERNEL)
#if defined(X86_FEATURE_AVX512F) && defined(KERNEL_EXPORTS_X86_FPU)
has_avx512 = !!boot_cpu_has(X86_FEATURE_AVX512F); has_avx512 = !!boot_cpu_has(X86_FEATURE_AVX512F);
#else
has_avx512 = B_FALSE;
#endif
#elif !defined(_KERNEL) #elif !defined(_KERNEL)
has_avx512 = __cpuid_has_avx512f(); has_avx512 = __cpuid_has_avx512f();
#endif #endif
@ -481,9 +526,13 @@ zfs_avx512cd_available(void)
{ {
boolean_t has_avx512 = B_FALSE; boolean_t has_avx512 = B_FALSE;
#if defined(_KERNEL) && defined(X86_FEATURE_AVX512CD) #if defined(_KERNEL)
#if defined(X86_FEATURE_AVX512CD) && defined(KERNEL_EXPORTS_X86_FPU)
has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) && has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
boot_cpu_has(X86_FEATURE_AVX512CD); boot_cpu_has(X86_FEATURE_AVX512CD);
#else
has_avx512 = B_FALSE;
#endif
#elif !defined(_KERNEL) #elif !defined(_KERNEL)
has_avx512 = __cpuid_has_avx512cd(); has_avx512 = __cpuid_has_avx512cd();
#endif #endif
@ -497,9 +546,13 @@ zfs_avx512er_available(void)
{ {
boolean_t has_avx512 = B_FALSE; boolean_t has_avx512 = B_FALSE;
#if defined(_KERNEL) && defined(X86_FEATURE_AVX512ER) #if defined(_KERNEL)
#if defined(X86_FEATURE_AVX512ER) && defined(KERNEL_EXPORTS_X86_FPU)
has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) && has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
boot_cpu_has(X86_FEATURE_AVX512ER); boot_cpu_has(X86_FEATURE_AVX512ER);
#else
has_avx512 = B_FALSE;
#endif
#elif !defined(_KERNEL) #elif !defined(_KERNEL)
has_avx512 = __cpuid_has_avx512er(); has_avx512 = __cpuid_has_avx512er();
#endif #endif
@ -513,9 +566,13 @@ zfs_avx512pf_available(void)
{ {
boolean_t has_avx512 = B_FALSE; boolean_t has_avx512 = B_FALSE;
#if defined(_KERNEL) && defined(X86_FEATURE_AVX512PF) #if defined(_KERNEL)
#if defined(X86_FEATURE_AVX512PF) && defined(KERNEL_EXPORTS_X86_FPU)
has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) && has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
boot_cpu_has(X86_FEATURE_AVX512PF); boot_cpu_has(X86_FEATURE_AVX512PF);
#else
has_avx512 = B_FALSE;
#endif
#elif !defined(_KERNEL) #elif !defined(_KERNEL)
has_avx512 = __cpuid_has_avx512pf(); has_avx512 = __cpuid_has_avx512pf();
#endif #endif
@ -529,9 +586,13 @@ zfs_avx512bw_available(void)
{ {
boolean_t has_avx512 = B_FALSE; boolean_t has_avx512 = B_FALSE;
#if defined(_KERNEL) && defined(X86_FEATURE_AVX512BW) #if defined(_KERNEL)
#if defined(X86_FEATURE_AVX512BW) && defined(KERNEL_EXPORTS_X86_FPU)
has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) && has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
boot_cpu_has(X86_FEATURE_AVX512BW); boot_cpu_has(X86_FEATURE_AVX512BW);
#else
has_avx512 = B_FALSE;
#endif
#elif !defined(_KERNEL) #elif !defined(_KERNEL)
has_avx512 = __cpuid_has_avx512bw(); has_avx512 = __cpuid_has_avx512bw();
#endif #endif
@ -545,9 +606,13 @@ zfs_avx512dq_available(void)
{ {
boolean_t has_avx512 = B_FALSE; boolean_t has_avx512 = B_FALSE;
#if defined(_KERNEL) && defined(X86_FEATURE_AVX512DQ) #if defined(_KERNEL)
#if defined(X86_FEATURE_AVX512DQ) && defined(KERNEL_EXPORTS_X86_FPU)
has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) && has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
boot_cpu_has(X86_FEATURE_AVX512DQ); boot_cpu_has(X86_FEATURE_AVX512DQ);
#else
has_avx512 = B_FALSE;
#endif
#elif !defined(_KERNEL) #elif !defined(_KERNEL)
has_avx512 = __cpuid_has_avx512dq(); has_avx512 = __cpuid_has_avx512dq();
#endif #endif
@ -561,9 +626,13 @@ zfs_avx512vl_available(void)
{ {
boolean_t has_avx512 = B_FALSE; boolean_t has_avx512 = B_FALSE;
#if defined(_KERNEL) && defined(X86_FEATURE_AVX512VL) #if defined(_KERNEL)
#if defined(X86_FEATURE_AVX512VL) && defined(KERNEL_EXPORTS_X86_FPU)
has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) && has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
boot_cpu_has(X86_FEATURE_AVX512VL); boot_cpu_has(X86_FEATURE_AVX512VL);
#else
has_avx512 = B_FALSE;
#endif
#elif !defined(_KERNEL) #elif !defined(_KERNEL)
has_avx512 = __cpuid_has_avx512vl(); has_avx512 = __cpuid_has_avx512vl();
#endif #endif
@ -577,9 +646,13 @@ zfs_avx512ifma_available(void)
{ {
boolean_t has_avx512 = B_FALSE; boolean_t has_avx512 = B_FALSE;
#if defined(_KERNEL) && defined(X86_FEATURE_AVX512IFMA) #if defined(_KERNEL)
#if defined(X86_FEATURE_AVX512IFMA) && defined(KERNEL_EXPORTS_X86_FPU)
has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) && has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
boot_cpu_has(X86_FEATURE_AVX512IFMA); boot_cpu_has(X86_FEATURE_AVX512IFMA);
#else
has_avx512 = B_FALSE;
#endif
#elif !defined(_KERNEL) #elif !defined(_KERNEL)
has_avx512 = __cpuid_has_avx512ifma(); has_avx512 = __cpuid_has_avx512ifma();
#endif #endif
@ -593,9 +666,13 @@ zfs_avx512vbmi_available(void)
{ {
boolean_t has_avx512 = B_FALSE; boolean_t has_avx512 = B_FALSE;
#if defined(_KERNEL) && defined(X86_FEATURE_AVX512VBMI) #if defined(_KERNEL)
#if defined(X86_FEATURE_AVX512VBMI) && defined(KERNEL_EXPORTS_X86_FPU)
has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) && has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
boot_cpu_has(X86_FEATURE_AVX512VBMI); boot_cpu_has(X86_FEATURE_AVX512VBMI);
#else
has_avx512 = B_FALSE;
#endif
#elif !defined(_KERNEL) #elif !defined(_KERNEL)
has_avx512 = __cpuid_has_avx512f() && has_avx512 = __cpuid_has_avx512f() &&
__cpuid_has_avx512vbmi(); __cpuid_has_avx512vbmi();

View File

@ -20,7 +20,7 @@
*/ */
/* /*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015 by Delphix. All rights reserved. * Copyright (c) 2012, 2018 by Delphix. All rights reserved.
* Copyright (c) 2013 by Saso Kiselkov. All rights reserved. * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved. * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
*/ */
@ -294,7 +294,7 @@ boolean_t dbuf_try_add_ref(dmu_buf_t *db, objset_t *os, uint64_t obj,
uint64_t dbuf_refcount(dmu_buf_impl_t *db); uint64_t dbuf_refcount(dmu_buf_impl_t *db);
void dbuf_rele(dmu_buf_impl_t *db, void *tag); void dbuf_rele(dmu_buf_impl_t *db, void *tag);
void dbuf_rele_and_unlock(dmu_buf_impl_t *db, void *tag); void dbuf_rele_and_unlock(dmu_buf_impl_t *db, void *tag, boolean_t evicting);
dmu_buf_impl_t *dbuf_find(struct objset *os, uint64_t object, uint8_t level, dmu_buf_impl_t *dbuf_find(struct objset *os, uint64_t object, uint8_t level,
uint64_t blkid); uint64_t blkid);

View File

@ -20,7 +20,7 @@
*/ */
/* /*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017 by Delphix. All rights reserved. * Copyright (c) 2012, 2018 by Delphix. All rights reserved.
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved. * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
*/ */
@ -339,7 +339,7 @@ int dnode_hold_impl(struct objset *dd, uint64_t object, int flag, int dn_slots,
void *ref, dnode_t **dnp); void *ref, dnode_t **dnp);
boolean_t dnode_add_ref(dnode_t *dn, void *ref); boolean_t dnode_add_ref(dnode_t *dn, void *ref);
void dnode_rele(dnode_t *dn, void *ref); void dnode_rele(dnode_t *dn, void *ref);
void dnode_rele_and_unlock(dnode_t *dn, void *tag); void dnode_rele_and_unlock(dnode_t *dn, void *tag, boolean_t evicting);
void dnode_setdirty(dnode_t *dn, dmu_tx_t *tx); void dnode_setdirty(dnode_t *dn, dmu_tx_t *tx);
void dnode_sync(dnode_t *dn, dmu_tx_t *tx); void dnode_sync(dnode_t *dn, dmu_tx_t *tx);
void dnode_allocate(dnode_t *dn, dmu_object_type_t ot, int blocksize, int ibs, void dnode_allocate(dnode_t *dn, dmu_object_type_t ot, int blocksize, int ibs,

View File

@ -42,7 +42,7 @@
#include <sys/uio.h> #include <sys/uio.h>
extern int uiomove(void *, size_t, enum uio_rw, uio_t *); extern int uiomove(void *, size_t, enum uio_rw, uio_t *);
extern void uio_prefaultpages(ssize_t, uio_t *); extern int uio_prefaultpages(ssize_t, uio_t *);
extern int uiocopy(void *, size_t, enum uio_rw, uio_t *, size_t *); extern int uiocopy(void *, size_t, enum uio_rw, uio_t *, size_t *);
extern void uioskip(uio_t *, size_t); extern void uioskip(uio_t *, size_t);

View File

@ -963,13 +963,14 @@ libzfs_load_module(const char *module)
load = 0; load = 0;
} }
if (load && libzfs_run_process("/sbin/modprobe", argv, 0)) if (load) {
return (ENOEXEC); if (libzfs_run_process("/sbin/modprobe", argv, 0))
} return (ENOEXEC);
/* Module loading is synchronous it must be available */ if (!libzfs_module_loaded(module))
if (!libzfs_module_loaded(module)) return (ENXIO);
return (ENXIO); }
}
/* /*
* Device creation by udev is asynchronous and waiting may be * Device creation by udev is asynchronous and waiting may be

View File

@ -38,6 +38,19 @@ defined by udev. This may be an absolute path or the base filename.
Maps a physical path to a channel name (typically representing a single Maps a physical path to a channel name (typically representing a single
disk enclosure). disk enclosure).
.TP
\fIenclosure_symlinks\fR <yes|no>
Additionally create /dev/by-enclosure symlinks to the disk enclosure
sg devices using the naming scheme from from vdev_id.conf.
\fIenclosure_symlinks\fR is only allowed for sas_direct mode.
.TP
\fIenclosure_symlinks_prefix\fR <prefix>
Specify the prefix for the enclosure symlinks in the form of:
/dev/by-enclosure/<prefix>-<channel><num>
Defaults to "enc" if not specified.
.TP
\fIpci_slot\fR - specifies the PCI SLOT of the HBA \fIpci_slot\fR - specifies the PCI SLOT of the HBA
hosting the disk enclosure being mapped, as found in the output of hosting the disk enclosure being mapped, as found in the output of
.BR lspci (8). .BR lspci (8).
@ -90,7 +103,7 @@ internally uses this value to determine which HBA or switch port a
device is connected to. The default is 4. device is connected to. The default is 4.
.TP .TP
\fIslot\fR <bay|phy|port|id|lun> \fIslot\fR <bay|phy|port|id|lun|ses>
Specifies from which element of a SAS identifier the slot number is Specifies from which element of a SAS identifier the slot number is
taken. The default is bay. taken. The default is bay.
@ -103,6 +116,12 @@ taken. The default is bay.
\fIid\fR - use the scsi id as the slot number. \fIid\fR - use the scsi id as the slot number.
\fIlun\fR - use the scsi lun as the slot number. \fIlun\fR - use the scsi lun as the slot number.
\fIses\fR - use the SCSI Enclosure Services (SES) enclosure device slot number,
as reported by
.BR sg_ses (8).
This is intended for use only on systems where \fIbay\fR is unsupported,
noting that \fIport\fR and \fIid\fR may be unstable across disk replacement.
.SH EXAMPLES .SH EXAMPLES
A non-multipath configuration with direct-attached SAS enclosures and an A non-multipath configuration with direct-attached SAS enclosures and an
arbitrary slot re-mapping. arbitrary slot re-mapping.
@ -163,6 +182,27 @@ definitions - one per physical path.
channel 86:00.0 0 B channel 86:00.0 0 B
.fi .fi
.P .P
A configuration with enclosure_symlinks enabled.
.P
.nf
multipath yes
enclosure_symlinks yes
# PCI_ID HBA PORT CHANNEL NAME
channel 05:00.0 1 U
channel 05:00.0 0 L
channel 06:00.0 1 U
channel 06:00.0 0 L
.fi
In addition to the disks symlinks, this configuration will create:
.P
.nf
/dev/by-enclosure/enc-L0
/dev/by-enclosure/enc-L1
/dev/by-enclosure/enc-U0
/dev/by-enclosure/enc-U1
.fi
.P
A configuration using device link aliases. A configuration using device link aliases.
.P .P
.nf .nf

View File

@ -29,7 +29,7 @@
.\" Copyright 2016 Nexenta Systems, Inc. .\" Copyright 2016 Nexenta Systems, Inc.
.\" Copyright 2016 Richard Laager. All rights reserved. .\" Copyright 2016 Richard Laager. All rights reserved.
.\" .\"
.Dd July 13, 2018 .Dd Jan 05, 2019
.Dt ZFS 8 SMM .Dt ZFS 8 SMM
.Os Linux .Os Linux
.Sh NAME .Sh NAME
@ -3981,9 +3981,9 @@ renames the remaining snapshots, and then creates a new snapshot, as follows:
# zfs destroy -r pool/users@7daysago # zfs destroy -r pool/users@7daysago
# zfs rename -r pool/users@6daysago @7daysago # zfs rename -r pool/users@6daysago @7daysago
# zfs rename -r pool/users@5daysago @6daysago # zfs rename -r pool/users@5daysago @6daysago
# zfs rename -r pool/users@yesterday @5daysago # zfs rename -r pool/users@4daysago @5daysago
# zfs rename -r pool/users@yesterday @4daysago # zfs rename -r pool/users@3daysago @4daysago
# zfs rename -r pool/users@yesterday @3daysago # zfs rename -r pool/users@2daysago @3daysago
# zfs rename -r pool/users@yesterday @2daysago # zfs rename -r pool/users@yesterday @2daysago
# zfs rename -r pool/users@today @yesterday # zfs rename -r pool/users@today @yesterday
# zfs snapshot -r pool/users@today # zfs snapshot -r pool/users@today

View File

@ -36,12 +36,12 @@ modules:
list='$(SUBDIR_TARGETS)'; for targetdir in $$list; do \ list='$(SUBDIR_TARGETS)'; for targetdir in $$list; do \
$(MAKE) -C $$targetdir; \ $(MAKE) -C $$targetdir; \
done done
$(MAKE) -C @LINUX_OBJ@ SUBDIRS=`pwd` @KERNELMAKE_PARAMS@ CONFIG_ZFS=m $@ $(MAKE) -C @LINUX_OBJ@ M=`pwd` @KERNELMAKE_PARAMS@ CONFIG_ZFS=m $@
clean: clean:
@# Only cleanup the kernel build directories when CONFIG_KERNEL @# Only cleanup the kernel build directories when CONFIG_KERNEL
@# is defined. This indicates that kernel modules should be built. @# is defined. This indicates that kernel modules should be built.
@CONFIG_KERNEL_TRUE@ $(MAKE) -C @LINUX_OBJ@ SUBDIRS=`pwd` @KERNELMAKE_PARAMS@ $@ @CONFIG_KERNEL_TRUE@ $(MAKE) -C @LINUX_OBJ@ M=`pwd` @KERNELMAKE_PARAMS@ $@
if [ -f @SPL_SYMBOLS@ ]; then $(RM) @SPL_SYMBOLS@; fi if [ -f @SPL_SYMBOLS@ ]; then $(RM) @SPL_SYMBOLS@; fi
if [ -f @LINUX_SYMBOLS@ ]; then $(RM) @LINUX_SYMBOLS@; fi if [ -f @LINUX_SYMBOLS@ ]; then $(RM) @LINUX_SYMBOLS@; fi
@ -49,7 +49,7 @@ clean:
modules_install: modules_install:
@# Install the kernel modules @# Install the kernel modules
$(MAKE) -C @LINUX_OBJ@ SUBDIRS=`pwd` $@ \ $(MAKE) -C @LINUX_OBJ@ M=`pwd` $@ \
INSTALL_MOD_PATH=$(DESTDIR)$(INSTALL_MOD_PATH) \ INSTALL_MOD_PATH=$(DESTDIR)$(INSTALL_MOD_PATH) \
INSTALL_MOD_DIR=$(INSTALL_MOD_DIR) \ INSTALL_MOD_DIR=$(INSTALL_MOD_DIR) \
KERNELRELEASE=@LINUX_VERSION@ KERNELRELEASE=@LINUX_VERSION@

View File

@ -50,6 +50,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/uio_impl.h> #include <sys/uio_impl.h>
#include <linux/kmap_compat.h> #include <linux/kmap_compat.h>
#include <linux/uaccess.h>
/* /*
* Move "n" bytes at byte address "p"; "rw" indicates the direction * Move "n" bytes at byte address "p"; "rw" indicates the direction
@ -77,8 +78,23 @@ uiomove_iov(void *p, size_t n, enum uio_rw rw, struct uio *uio)
if (copy_to_user(iov->iov_base+skip, p, cnt)) if (copy_to_user(iov->iov_base+skip, p, cnt))
return (EFAULT); return (EFAULT);
} else { } else {
if (copy_from_user(p, iov->iov_base+skip, cnt)) if (uio->uio_fault_disable) {
return (EFAULT); if (!zfs_access_ok(VERIFY_READ,
(iov->iov_base + skip), cnt)) {
return (EFAULT);
}
pagefault_disable();
if (__copy_from_user_inatomic(p,
(iov->iov_base + skip), cnt)) {
pagefault_enable();
return (EFAULT);
}
pagefault_enable();
} else {
if (copy_from_user(p,
(iov->iov_base + skip), cnt))
return (EFAULT);
}
} }
break; break;
case UIO_SYSSPACE: case UIO_SYSSPACE:
@ -156,7 +172,7 @@ EXPORT_SYMBOL(uiomove);
* error will terminate the process as this is only a best attempt to get * error will terminate the process as this is only a best attempt to get
* the pages resident. * the pages resident.
*/ */
void int
uio_prefaultpages(ssize_t n, struct uio *uio) uio_prefaultpages(ssize_t n, struct uio *uio)
{ {
const struct iovec *iov; const struct iovec *iov;
@ -170,7 +186,7 @@ uio_prefaultpages(ssize_t n, struct uio *uio)
switch (uio->uio_segflg) { switch (uio->uio_segflg) {
case UIO_SYSSPACE: case UIO_SYSSPACE:
case UIO_BVEC: case UIO_BVEC:
return; return (0);
case UIO_USERSPACE: case UIO_USERSPACE:
case UIO_USERISPACE: case UIO_USERISPACE:
break; break;
@ -194,7 +210,7 @@ uio_prefaultpages(ssize_t n, struct uio *uio)
p = iov->iov_base + skip; p = iov->iov_base + skip;
while (cnt) { while (cnt) {
if (fuword8((uint8_t *)p, &tmp)) if (fuword8((uint8_t *)p, &tmp))
return; return (EFAULT);
incr = MIN(cnt, PAGESIZE); incr = MIN(cnt, PAGESIZE);
p += incr; p += incr;
cnt -= incr; cnt -= incr;
@ -204,8 +220,10 @@ uio_prefaultpages(ssize_t n, struct uio *uio)
*/ */
p--; p--;
if (fuword8((uint8_t *)p, &tmp)) if (fuword8((uint8_t *)p, &tmp))
return; return (EFAULT);
} }
return (0);
} }
EXPORT_SYMBOL(uio_prefaultpages); EXPORT_SYMBOL(uio_prefaultpages);

View File

@ -4004,9 +4004,9 @@ arc_all_memory(void)
{ {
#ifdef _KERNEL #ifdef _KERNEL
#ifdef CONFIG_HIGHMEM #ifdef CONFIG_HIGHMEM
return (ptob(totalram_pages - totalhigh_pages)); return (ptob(zfs_totalram_pages - totalhigh_pages));
#else #else
return (ptob(totalram_pages)); return (ptob(zfs_totalram_pages));
#endif /* CONFIG_HIGHMEM */ #endif /* CONFIG_HIGHMEM */
#else #else
return (ptob(physmem) / 2); return (ptob(physmem) / 2);

View File

@ -72,8 +72,6 @@ static void __dbuf_hold_impl_init(struct dbuf_hold_impl_data *dh,
void *tag, dmu_buf_impl_t **dbp, int depth); void *tag, dmu_buf_impl_t **dbp, int depth);
static int __dbuf_hold_impl(struct dbuf_hold_impl_data *dh); static int __dbuf_hold_impl(struct dbuf_hold_impl_data *dh);
uint_t zfs_dbuf_evict_key;
static boolean_t dbuf_undirty(dmu_buf_impl_t *db, dmu_tx_t *tx); static boolean_t dbuf_undirty(dmu_buf_impl_t *db, dmu_tx_t *tx);
static void dbuf_write(dbuf_dirty_record_t *dr, arc_buf_t *data, dmu_tx_t *tx); static void dbuf_write(dbuf_dirty_record_t *dr, arc_buf_t *data, dmu_tx_t *tx);
@ -505,14 +503,6 @@ dbuf_evict_one(void)
dmu_buf_impl_t *db; dmu_buf_impl_t *db;
ASSERT(!MUTEX_HELD(&dbuf_evict_lock)); ASSERT(!MUTEX_HELD(&dbuf_evict_lock));
/*
* Set the thread's tsd to indicate that it's processing evictions.
* Once a thread stops evicting from the dbuf cache it will
* reset its tsd to NULL.
*/
ASSERT3P(tsd_get(zfs_dbuf_evict_key), ==, NULL);
(void) tsd_set(zfs_dbuf_evict_key, (void *)B_TRUE);
db = multilist_sublist_tail(mls); db = multilist_sublist_tail(mls);
while (db != NULL && mutex_tryenter(&db->db_mtx) == 0) { while (db != NULL && mutex_tryenter(&db->db_mtx) == 0) {
db = multilist_sublist_prev(mls, db); db = multilist_sublist_prev(mls, db);
@ -530,7 +520,6 @@ dbuf_evict_one(void)
} else { } else {
multilist_sublist_unlock(mls); multilist_sublist_unlock(mls);
} }
(void) tsd_set(zfs_dbuf_evict_key, NULL);
} }
/* /*
@ -583,29 +572,6 @@ dbuf_evict_thread(void)
static void static void
dbuf_evict_notify(void) dbuf_evict_notify(void)
{ {
/*
* We use thread specific data to track when a thread has
* started processing evictions. This allows us to avoid deeply
* nested stacks that would have a call flow similar to this:
*
* dbuf_rele()-->dbuf_rele_and_unlock()-->dbuf_evict_notify()
* ^ |
* | |
* +-----dbuf_destroy()<--dbuf_evict_one()<--------+
*
* The dbuf_eviction_thread will always have its tsd set until
* that thread exits. All other threads will only set their tsd
* if they are participating in the eviction process. This only
* happens if the eviction thread is unable to process evictions
* fast enough. To keep the dbuf cache size in check, other threads
* can evict from the dbuf cache directly. Those threads will set
* their tsd values so that we ensure that they only evict one dbuf
* from the dbuf cache.
*/
if (tsd_get(zfs_dbuf_evict_key) != NULL)
return;
/* /*
* We check if we should evict without holding the dbuf_evict_lock, * We check if we should evict without holding the dbuf_evict_lock,
* because it's OK to occasionally make the wrong decision here, * because it's OK to occasionally make the wrong decision here,
@ -681,7 +647,6 @@ retry:
dbuf_cache_multilist_index_func); dbuf_cache_multilist_index_func);
zfs_refcount_create(&dbuf_cache_size); zfs_refcount_create(&dbuf_cache_size);
tsd_create(&zfs_dbuf_evict_key, NULL);
dbuf_evict_thread_exit = B_FALSE; dbuf_evict_thread_exit = B_FALSE;
mutex_init(&dbuf_evict_lock, NULL, MUTEX_DEFAULT, NULL); mutex_init(&dbuf_evict_lock, NULL, MUTEX_DEFAULT, NULL);
cv_init(&dbuf_evict_cv, NULL, CV_DEFAULT, NULL); cv_init(&dbuf_evict_cv, NULL, CV_DEFAULT, NULL);
@ -718,7 +683,6 @@ dbuf_fini(void)
cv_wait(&dbuf_evict_cv, &dbuf_evict_lock); cv_wait(&dbuf_evict_cv, &dbuf_evict_lock);
} }
mutex_exit(&dbuf_evict_lock); mutex_exit(&dbuf_evict_lock);
tsd_destroy(&zfs_dbuf_evict_key);
mutex_destroy(&dbuf_evict_lock); mutex_destroy(&dbuf_evict_lock);
cv_destroy(&dbuf_evict_cv); cv_destroy(&dbuf_evict_cv);
@ -1004,7 +968,7 @@ dbuf_read_done(zio_t *zio, arc_buf_t *buf, void *vdb)
db->db_state = DB_UNCACHED; db->db_state = DB_UNCACHED;
} }
cv_broadcast(&db->db_changed); cv_broadcast(&db->db_changed);
dbuf_rele_and_unlock(db, NULL); dbuf_rele_and_unlock(db, NULL, B_FALSE);
} }
static int static int
@ -2178,7 +2142,8 @@ dbuf_destroy(dmu_buf_impl_t *db)
* value in dnode_move(), since DB_DNODE_EXIT doesn't actually * value in dnode_move(), since DB_DNODE_EXIT doesn't actually
* release any lock. * release any lock.
*/ */
dnode_rele(dn, db); mutex_enter(&dn->dn_mtx);
dnode_rele_and_unlock(dn, db, B_TRUE);
db->db_dnode_handle = NULL; db->db_dnode_handle = NULL;
dbuf_hash_remove(db); dbuf_hash_remove(db);
@ -2204,8 +2169,10 @@ dbuf_destroy(dmu_buf_impl_t *db)
* If this dbuf is referenced from an indirect dbuf, * If this dbuf is referenced from an indirect dbuf,
* decrement the ref count on the indirect dbuf. * decrement the ref count on the indirect dbuf.
*/ */
if (parent && parent != dndb) if (parent && parent != dndb) {
dbuf_rele(parent, db); mutex_enter(&parent->db_mtx);
dbuf_rele_and_unlock(parent, db, B_TRUE);
}
} }
/* /*
@ -2912,7 +2879,7 @@ void
dbuf_rele(dmu_buf_impl_t *db, void *tag) dbuf_rele(dmu_buf_impl_t *db, void *tag)
{ {
mutex_enter(&db->db_mtx); mutex_enter(&db->db_mtx);
dbuf_rele_and_unlock(db, tag); dbuf_rele_and_unlock(db, tag, B_FALSE);
} }
void void
@ -2923,10 +2890,19 @@ dmu_buf_rele(dmu_buf_t *db, void *tag)
/* /*
* dbuf_rele() for an already-locked dbuf. This is necessary to allow * dbuf_rele() for an already-locked dbuf. This is necessary to allow
* db_dirtycnt and db_holds to be updated atomically. * db_dirtycnt and db_holds to be updated atomically. The 'evicting'
* argument should be set if we are already in the dbuf-evicting code
* path, in which case we don't want to recursively evict. This allows us to
* avoid deeply nested stacks that would have a call flow similar to this:
*
* dbuf_rele()-->dbuf_rele_and_unlock()-->dbuf_evict_notify()
* ^ |
* | |
* +-----dbuf_destroy()<--dbuf_evict_one()<--------+
*
*/ */
void void
dbuf_rele_and_unlock(dmu_buf_impl_t *db, void *tag) dbuf_rele_and_unlock(dmu_buf_impl_t *db, void *tag, boolean_t evicting)
{ {
int64_t holds; int64_t holds;
@ -3021,7 +2997,8 @@ dbuf_rele_and_unlock(dmu_buf_impl_t *db, void *tag)
db->db.db_size, db); db->db.db_size, db);
mutex_exit(&db->db_mtx); mutex_exit(&db->db_mtx);
dbuf_evict_notify(); if (!evicting)
dbuf_evict_notify();
} }
if (do_arc_evict) if (do_arc_evict)
@ -3314,7 +3291,7 @@ dbuf_sync_leaf(dbuf_dirty_record_t *dr, dmu_tx_t *tx)
kmem_free(dr, sizeof (dbuf_dirty_record_t)); kmem_free(dr, sizeof (dbuf_dirty_record_t));
ASSERT(db->db_dirtycnt > 0); ASSERT(db->db_dirtycnt > 0);
db->db_dirtycnt -= 1; db->db_dirtycnt -= 1;
dbuf_rele_and_unlock(db, (void *)(uintptr_t)txg); dbuf_rele_and_unlock(db, (void *)(uintptr_t)txg, B_FALSE);
return; return;
} }
@ -3670,7 +3647,7 @@ dbuf_write_done(zio_t *zio, arc_buf_t *buf, void *vdb)
ASSERT(db->db_dirtycnt > 0); ASSERT(db->db_dirtycnt > 0);
db->db_dirtycnt -= 1; db->db_dirtycnt -= 1;
db->db_data_pending = NULL; db->db_data_pending = NULL;
dbuf_rele_and_unlock(db, (void *)(uintptr_t)tx->tx_txg); dbuf_rele_and_unlock(db, (void *)(uintptr_t)tx->tx_txg, B_FALSE);
} }
static void static void

View File

@ -1533,11 +1533,11 @@ void
dnode_rele(dnode_t *dn, void *tag) dnode_rele(dnode_t *dn, void *tag)
{ {
mutex_enter(&dn->dn_mtx); mutex_enter(&dn->dn_mtx);
dnode_rele_and_unlock(dn, tag); dnode_rele_and_unlock(dn, tag, B_FALSE);
} }
void void
dnode_rele_and_unlock(dnode_t *dn, void *tag) dnode_rele_and_unlock(dnode_t *dn, void *tag, boolean_t evicting)
{ {
uint64_t refs; uint64_t refs;
/* Get while the hold prevents the dnode from moving. */ /* Get while the hold prevents the dnode from moving. */
@ -1568,7 +1568,8 @@ dnode_rele_and_unlock(dnode_t *dn, void *tag)
* that the handle has zero references, but that will be * that the handle has zero references, but that will be
* asserted anyway when the handle gets destroyed. * asserted anyway when the handle gets destroyed.
*/ */
dbuf_rele(db, dnh); mutex_enter(&db->db_mtx);
dbuf_rele_and_unlock(db, dnh, evicting);
} }
} }

View File

@ -21,7 +21,7 @@
/* /*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017 by Delphix. All rights reserved. * Copyright (c) 2012, 2018 by Delphix. All rights reserved.
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved. * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
*/ */
@ -429,6 +429,19 @@ dnode_evict_dbufs(dnode_t *dn)
avl_insert_here(&dn->dn_dbufs, db_marker, db, avl_insert_here(&dn->dn_dbufs, db_marker, db,
AVL_BEFORE); AVL_BEFORE);
/*
* We need to use the "marker" dbuf rather than
* simply getting the next dbuf, because
* dbuf_destroy() may actually remove multiple dbufs.
* It can call itself recursively on the parent dbuf,
* which may also be removed from dn_dbufs. The code
* flow would look like:
*
* dbuf_destroy():
* dnode_rele_and_unlock(parent_dbuf, evicting=TRUE):
* if (!cacheable || pending_evict)
* dbuf_destroy()
*/
dbuf_destroy(db); dbuf_destroy(db);
db_next = AVL_NEXT(&dn->dn_dbufs, db_marker); db_next = AVL_NEXT(&dn->dn_dbufs, db_marker);
@ -489,7 +502,7 @@ dnode_undirty_dbufs(list_t *list)
list_destroy(&dr->dt.di.dr_children); list_destroy(&dr->dt.di.dr_children);
} }
kmem_free(dr, sizeof (dbuf_dirty_record_t)); kmem_free(dr, sizeof (dbuf_dirty_record_t));
dbuf_rele_and_unlock(db, (void *)(uintptr_t)txg); dbuf_rele_and_unlock(db, (void *)(uintptr_t)txg, B_FALSE);
} }
} }

View File

@ -35,6 +35,7 @@
#include <sys/zio.h> #include <sys/zio.h>
#include <sys/sunldi.h> #include <sys/sunldi.h>
#include <linux/mod_compat.h> #include <linux/mod_compat.h>
#include <linux/vfs_compat.h>
char *zfs_vdev_scheduler = VDEV_SCHEDULER; char *zfs_vdev_scheduler = VDEV_SCHEDULER;
static void *zfs_vdev_holder = VDEV_HOLDER; static void *zfs_vdev_holder = VDEV_HOLDER;
@ -76,7 +77,7 @@ vdev_bdev_mode(int smode)
ASSERT3S(smode & (FREAD | FWRITE), !=, 0); ASSERT3S(smode & (FREAD | FWRITE), !=, 0);
if ((smode & FREAD) && !(smode & FWRITE)) if ((smode & FREAD) && !(smode & FWRITE))
mode = MS_RDONLY; mode = SB_RDONLY;
return (mode); return (mode);
} }
@ -501,13 +502,38 @@ vdev_submit_bio_impl(struct bio *bio)
#endif #endif
} }
#ifndef HAVE_BIO_SET_DEV #ifdef HAVE_BIO_SET_DEV
#if defined(CONFIG_BLK_CGROUP) && defined(HAVE_BIO_SET_DEV_GPL_ONLY)
/*
* The Linux 5.0 kernel updated the bio_set_dev() macro so it calls the
* GPL-only bio_associate_blkg() symbol thus inadvertently converting
* the entire macro. Provide a minimal version which always assigns the
* request queue's root_blkg to the bio.
*/
static inline void
vdev_bio_associate_blkg(struct bio *bio)
{
struct request_queue *q = bio->bi_disk->queue;
ASSERT3P(q, !=, NULL);
ASSERT3P(q->root_blkg, !=, NULL);
ASSERT3P(bio->bi_blkg, ==, NULL);
if (blkg_tryget(q->root_blkg))
bio->bi_blkg = q->root_blkg;
}
#define bio_associate_blkg vdev_bio_associate_blkg
#endif
#else
/*
* Provide a bio_set_dev() helper macro for pre-Linux 4.14 kernels.
*/
static inline void static inline void
bio_set_dev(struct bio *bio, struct block_device *bdev) bio_set_dev(struct bio *bio, struct block_device *bdev)
{ {
bio->bi_bdev = bdev; bio->bi_bdev = bdev;
} }
#endif /* !HAVE_BIO_SET_DEV */ #endif /* HAVE_BIO_SET_DEV */
static inline void static inline void
vdev_submit_bio(struct bio *bio) vdev_submit_bio(struct bio *bio)

View File

@ -6634,11 +6634,14 @@ static const struct file_operations zfsdev_fops = {
}; };
static struct miscdevice zfs_misc = { static struct miscdevice zfs_misc = {
.minor = MISC_DYNAMIC_MINOR, .minor = ZFS_DEVICE_MINOR,
.name = ZFS_DRIVER, .name = ZFS_DRIVER,
.fops = &zfsdev_fops, .fops = &zfsdev_fops,
}; };
MODULE_ALIAS_MISCDEV(ZFS_DEVICE_MINOR);
MODULE_ALIAS("devname:zfs");
static int static int
zfs_attach(void) zfs_attach(void)
{ {
@ -6649,12 +6652,24 @@ zfs_attach(void)
zfsdev_state_list->zs_minor = -1; zfsdev_state_list->zs_minor = -1;
error = misc_register(&zfs_misc); error = misc_register(&zfs_misc);
if (error != 0) { if (error == -EBUSY) {
printk(KERN_INFO "ZFS: misc_register() failed %d\n", error); /*
return (error); * Fallback to dynamic minor allocation in the event of a
* collision with a reserved minor in linux/miscdevice.h.
* In this case the kernel modules must be manually loaded.
*/
printk(KERN_INFO "ZFS: misc_register() with static minor %d "
"failed %d, retrying with MISC_DYNAMIC_MINOR\n",
ZFS_DEVICE_MINOR, error);
zfs_misc.minor = MISC_DYNAMIC_MINOR;
error = misc_register(&zfs_misc);
} }
return (0); if (error)
printk(KERN_INFO "ZFS: misc_register() failed %d\n", error);
return (error);
} }
static void static void

View File

@ -66,6 +66,7 @@
#include <sys/dmu_objset.h> #include <sys/dmu_objset.h>
#include <sys/spa_boot.h> #include <sys/spa_boot.h>
#include <sys/zpl.h> #include <sys/zpl.h>
#include <linux/vfs_compat.h>
#include "zfs_comutil.h" #include "zfs_comutil.h"
enum { enum {
@ -259,7 +260,7 @@ zfsvfs_parse_options(char *mntopts, vfs_t **vfsp)
boolean_t boolean_t
zfs_is_readonly(zfsvfs_t *zfsvfs) zfs_is_readonly(zfsvfs_t *zfsvfs)
{ {
return (!!(zfsvfs->z_sb->s_flags & MS_RDONLY)); return (!!(zfsvfs->z_sb->s_flags & SB_RDONLY));
} }
/*ARGSUSED*/ /*ARGSUSED*/
@ -353,15 +354,15 @@ acltype_changed_cb(void *arg, uint64_t newval)
switch (newval) { switch (newval) {
case ZFS_ACLTYPE_OFF: case ZFS_ACLTYPE_OFF:
zfsvfs->z_acl_type = ZFS_ACLTYPE_OFF; zfsvfs->z_acl_type = ZFS_ACLTYPE_OFF;
zfsvfs->z_sb->s_flags &= ~MS_POSIXACL; zfsvfs->z_sb->s_flags &= ~SB_POSIXACL;
break; break;
case ZFS_ACLTYPE_POSIXACL: case ZFS_ACLTYPE_POSIXACL:
#ifdef CONFIG_FS_POSIX_ACL #ifdef CONFIG_FS_POSIX_ACL
zfsvfs->z_acl_type = ZFS_ACLTYPE_POSIXACL; zfsvfs->z_acl_type = ZFS_ACLTYPE_POSIXACL;
zfsvfs->z_sb->s_flags |= MS_POSIXACL; zfsvfs->z_sb->s_flags |= SB_POSIXACL;
#else #else
zfsvfs->z_acl_type = ZFS_ACLTYPE_OFF; zfsvfs->z_acl_type = ZFS_ACLTYPE_OFF;
zfsvfs->z_sb->s_flags &= ~MS_POSIXACL; zfsvfs->z_sb->s_flags &= ~SB_POSIXACL;
#endif /* CONFIG_FS_POSIX_ACL */ #endif /* CONFIG_FS_POSIX_ACL */
break; break;
default: default:
@ -390,9 +391,9 @@ readonly_changed_cb(void *arg, uint64_t newval)
return; return;
if (newval) if (newval)
sb->s_flags |= MS_RDONLY; sb->s_flags |= SB_RDONLY;
else else
sb->s_flags &= ~MS_RDONLY; sb->s_flags &= ~SB_RDONLY;
} }
static void static void
@ -420,9 +421,9 @@ nbmand_changed_cb(void *arg, uint64_t newval)
return; return;
if (newval == TRUE) if (newval == TRUE)
sb->s_flags |= MS_MANDLOCK; sb->s_flags |= SB_MANDLOCK;
else else
sb->s_flags &= ~MS_MANDLOCK; sb->s_flags &= ~SB_MANDLOCK;
} }
static void static void
@ -1763,8 +1764,8 @@ zfs_remount(struct super_block *sb, int *flags, zfs_mnt_t *zm)
int error; int error;
if ((issnap || !spa_writeable(dmu_objset_spa(zfsvfs->z_os))) && if ((issnap || !spa_writeable(dmu_objset_spa(zfsvfs->z_os))) &&
!(*flags & MS_RDONLY)) { !(*flags & SB_RDONLY)) {
*flags |= MS_RDONLY; *flags |= SB_RDONLY;
return (EROFS); return (EROFS);
} }

View File

@ -675,7 +675,10 @@ zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
xuio = (xuio_t *)uio; xuio = (xuio_t *)uio;
else else
#endif #endif
uio_prefaultpages(MIN(n, max_blksz), uio); if (uio_prefaultpages(MIN(n, max_blksz), uio)) {
ZFS_EXIT(zfsvfs);
return (SET_ERROR(EFAULT));
}
/* /*
* If in append mode, set the io offset pointer to eof. * If in append mode, set the io offset pointer to eof.
@ -820,8 +823,19 @@ zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
if (abuf == NULL) { if (abuf == NULL) {
tx_bytes = uio->uio_resid; tx_bytes = uio->uio_resid;
uio->uio_fault_disable = B_TRUE;
error = dmu_write_uio_dbuf(sa_get_db(zp->z_sa_hdl), error = dmu_write_uio_dbuf(sa_get_db(zp->z_sa_hdl),
uio, nbytes, tx); uio, nbytes, tx);
if (error == EFAULT) {
dmu_tx_commit(tx);
if (uio_prefaultpages(MIN(n, max_blksz), uio)) {
break;
}
continue;
} else if (error != 0) {
dmu_tx_commit(tx);
break;
}
tx_bytes -= uio->uio_resid; tx_bytes -= uio->uio_resid;
} else { } else {
tx_bytes = nbytes; tx_bytes = nbytes;
@ -921,8 +935,12 @@ zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
ASSERT(tx_bytes == nbytes); ASSERT(tx_bytes == nbytes);
n -= nbytes; n -= nbytes;
if (!xuio && n > 0) if (!xuio && n > 0) {
uio_prefaultpages(MIN(n, max_blksz), uio); if (uio_prefaultpages(MIN(n, max_blksz), uio)) {
error = EFAULT;
break;
}
}
} }
zfs_inode_update(zp); zfs_inode_update(zp);

View File

@ -195,6 +195,9 @@ chmod u+x ${RPM_BUILD_ROOT}%{kmodinstdir_prefix}/*/extra/*/*/*
rm -rf $RPM_BUILD_ROOT rm -rf $RPM_BUILD_ROOT
%changelog %changelog
* Fri Feb 22 2019 Tony Hutter <hutter2@llnl.gov> - 0.7.13-1
- Released 0.7.13-1, detailed release notes are available at:
- https://github.com/zfsonlinux/zfs/releases/tag/zfs-0.7.13
* Thu Nov 08 2018 Tony Hutter <hutter2@llnl.gov> - 0.7.12-1 * Thu Nov 08 2018 Tony Hutter <hutter2@llnl.gov> - 0.7.12-1
- Released 0.7.12-1, detailed release notes are available at: - Released 0.7.12-1, detailed release notes are available at:
- https://github.com/zfsonlinux/zfs/releases/tag/zfs-0.7.12 - https://github.com/zfsonlinux/zfs/releases/tag/zfs-0.7.12

View File

@ -283,6 +283,15 @@ fi
%endif %endif
exit 0 exit 0
# On RHEL/CentOS 7 the static nodes aren't refreshed by default after
# installing a package. This is the default behavior for Fedora.
%posttrans
%if 0%{?rhel} == 7 || 0%{?centos} == 7
systemctl restart kmod-static-nodes
systemctl restart systemd-tmpfiles-setup-dev
udevadm trigger
%endif
%preun %preun
%if 0%{?_systemd} %if 0%{?_systemd}
%if 0%{?systemd_preun:1} %if 0%{?systemd_preun:1}
@ -372,6 +381,9 @@ systemctl --system daemon-reload >/dev/null || true
%endif %endif
%changelog %changelog
* Fri Feb 22 2019 Tony Hutter <hutter2@llnl.gov> - 0.7.13-1
- Released 0.7.13-1, detailed release notes are available at:
- https://github.com/zfsonlinux/zfs/releases/tag/zfs-0.7.13
* Thu Nov 08 2018 Tony Hutter <hutter2@llnl.gov> - 0.7.12-1 * Thu Nov 08 2018 Tony Hutter <hutter2@llnl.gov> - 0.7.12-1
- Released 0.7.12-1, detailed release notes are available at: - Released 0.7.12-1, detailed release notes are available at:
- https://github.com/zfsonlinux/zfs/releases/tag/zfs-0.7.12 - https://github.com/zfsonlinux/zfs/releases/tag/zfs-0.7.12

View File

@ -50,10 +50,10 @@ function new_change_commit()
{ {
error=0 error=0
# subject is not longer than 50 characters # subject is not longer than 72 characters
long_subject=$(git log -n 1 --pretty=%s "$REF" | grep -E -m 1 '.{51}') long_subject=$(git log -n 1 --pretty=%s "$REF" | grep -E -m 1 '.{73}')
if [ -n "$long_subject" ]; then if [ -n "$long_subject" ]; then
echo "error: commit subject over 50 characters" echo "error: commit subject over 72 characters"
error=1 error=1
fi fi

View File

@ -65,6 +65,10 @@ PRE_BUILD="configure
then then
echo --enable-debug-dmu-tx echo --enable-debug-dmu-tx
fi fi
if [[ \${ZFS_DKMS_ENABLE_DEBUGINFO,,} == @(y|yes) ]]
then
echo --enable-debuginfo
fi
} }
) )
" "

View File

@ -12,13 +12,19 @@
# #
# #
# Copyright (c) 2012, 2015 by Delphix. All rights reserved. # Copyright (c) 2012, 2018 by Delphix. All rights reserved.
# Copyright (c) 2017 Datto Inc. # Copyright (c) 2017 Datto Inc.
# #
import ConfigParser # some python 2.7 system don't have a configparser shim
try:
import configparser
except ImportError:
import ConfigParser as configparser
import os import os
import logging import sys
from datetime import datetime from datetime import datetime
from optparse import OptionParser from optparse import OptionParser
from pwd import getpwnam from pwd import getpwnam
@ -26,8 +32,6 @@ from pwd import getpwuid
from select import select from select import select
from subprocess import PIPE from subprocess import PIPE
from subprocess import Popen from subprocess import Popen
from sys import argv
from sys import maxint
from threading import Timer from threading import Timer
from time import time from time import time
@ -36,6 +40,10 @@ TESTDIR = '/usr/share/zfs/'
KILL = 'kill' KILL = 'kill'
TRUE = 'true' TRUE = 'true'
SUDO = 'sudo' SUDO = 'sudo'
LOG_FILE = 'LOG_FILE'
LOG_OUT = 'LOG_OUT'
LOG_ERR = 'LOG_ERR'
LOG_FILE_OBJ = None
class Result(object): class Result(object):
@ -79,7 +87,7 @@ class Output(object):
""" """
def __init__(self, stream): def __init__(self, stream):
self.stream = stream self.stream = stream
self._buf = '' self._buf = b''
self.lines = [] self.lines = []
def fileno(self): def fileno(self):
@ -104,15 +112,15 @@ class Output(object):
buf = os.read(fd, 4096) buf = os.read(fd, 4096)
if not buf: if not buf:
return None return None
if '\n' not in buf: if b'\n' not in buf:
self._buf += buf self._buf += buf
return [] return []
buf = self._buf + buf buf = self._buf + buf
tmp, rest = buf.rsplit('\n', 1) tmp, rest = buf.rsplit(b'\n', 1)
self._buf = rest self._buf = rest
now = datetime.now() now = datetime.now()
rows = tmp.split('\n') rows = tmp.split(b'\n')
self.lines += [(now, r) for r in rows] self.lines += [(now, r) for r in rows]
@ -204,23 +212,23 @@ class Cmd(object):
if needed. Run the command, and update the result object. if needed. Run the command, and update the result object.
""" """
if options.dryrun is True: if options.dryrun is True:
print self print(self)
return return
privcmd = self.update_cmd_privs(self.pathname, self.user) privcmd = self.update_cmd_privs(self.pathname, self.user)
try: try:
old = os.umask(0) old = os.umask(0)
if not os.path.isdir(self.outputdir): if not os.path.isdir(self.outputdir):
os.makedirs(self.outputdir, mode=0777) os.makedirs(self.outputdir, mode=0o777)
os.umask(old) os.umask(old)
except OSError, e: except OSError as e:
fail('%s' % e) fail('%s' % e)
self.result.starttime = time() self.result.starttime = time()
proc = Popen(privcmd, stdout=PIPE, stderr=PIPE) proc = Popen(privcmd, stdout=PIPE, stderr=PIPE)
# Allow a special timeout value of 0 to mean infinity # Allow a special timeout value of 0 to mean infinity
if int(self.timeout) == 0: if int(self.timeout) == 0:
self.timeout = maxint self.timeout = sys.maxsize
t = Timer(int(self.timeout), self.kill_cmd, [proc]) t = Timer(int(self.timeout), self.kill_cmd, [proc])
try: try:
@ -247,50 +255,52 @@ class Cmd(object):
self.result.runtime = '%02d:%02d' % (m, s) self.result.runtime = '%02d:%02d' % (m, s)
self.result.result = 'SKIP' self.result.result = 'SKIP'
def log(self, logger, options): def log(self, options):
""" """
This function is responsible for writing all output. This includes This function is responsible for writing all output. This includes
the console output, the logfile of all results (with timestamped the console output, the logfile of all results (with timestamped
merged stdout and stderr), and for each test, the unmodified merged stdout and stderr), and for each test, the unmodified
stdout/stderr/merged in it's own file. stdout/stderr/merged in it's own file.
""" """
if logger is None:
return
logname = getpwuid(os.getuid()).pw_name logname = getpwuid(os.getuid()).pw_name
user = ' (run as %s)' % (self.user if len(self.user) else logname) user = ' (run as %s)' % (self.user if len(self.user) else logname)
msga = 'Test: %s%s ' % (self.pathname, user) msga = 'Test: %s%s ' % (self.pathname, user)
msgb = '[%s] [%s]' % (self.result.runtime, self.result.result) msgb = '[%s] [%s]\n' % (self.result.runtime, self.result.result)
pad = ' ' * (80 - (len(msga) + len(msgb))) pad = ' ' * (80 - (len(msga) + len(msgb)))
result_line = msga + pad + msgb
# If -q is specified, only print a line for tests that didn't pass. # The result line is always written to the log file. If -q was
# This means passing tests need to be logged as DEBUG, or the one # specified only failures are written to the console, otherwise
# line summary will only be printed in the logfile for failures. # the result line is written to the console.
write_log(bytearray(result_line, encoding='utf-8'), LOG_FILE)
if not options.quiet: if not options.quiet:
logger.info('%s%s%s' % (msga, pad, msgb)) write_log(result_line, LOG_OUT)
elif self.result.result is not 'PASS': elif options.quiet and self.result.result is not 'PASS':
logger.info('%s%s%s' % (msga, pad, msgb)) write_log(result_line, LOG_OUT)
else:
logger.debug('%s%s%s' % (msga, pad, msgb))
lines = sorted(self.result.stdout + self.result.stderr, lines = sorted(self.result.stdout + self.result.stderr,
cmp=lambda x, y: cmp(x[0], y[0])) key=lambda x: x[0])
# Write timestamped output (stdout and stderr) to the logfile
for dt, line in lines: for dt, line in lines:
logger.debug('%s %s' % (dt.strftime("%H:%M:%S.%f ")[:11], line)) timestamp = bytearray(dt.strftime("%H:%M:%S.%f ")[:11],
encoding='utf-8')
write_log(b'%s %s\n' % (timestamp, line), LOG_FILE)
# Write the separate stdout/stderr/merged files, if the data exists
if len(self.result.stdout): if len(self.result.stdout):
with open(os.path.join(self.outputdir, 'stdout'), 'w') as out: with open(os.path.join(self.outputdir, 'stdout'), 'wb') as out:
for _, line in self.result.stdout: for _, line in self.result.stdout:
os.write(out.fileno(), '%s\n' % line) os.write(out.fileno(), b'%s\n' % line)
if len(self.result.stderr): if len(self.result.stderr):
with open(os.path.join(self.outputdir, 'stderr'), 'w') as err: with open(os.path.join(self.outputdir, 'stderr'), 'wb') as err:
for _, line in self.result.stderr: for _, line in self.result.stderr:
os.write(err.fileno(), '%s\n' % line) os.write(err.fileno(), b'%s\n' % line)
if len(self.result.stdout) and len(self.result.stderr): if len(self.result.stdout) and len(self.result.stderr):
with open(os.path.join(self.outputdir, 'merged'), 'w') as merged: with open(os.path.join(self.outputdir, 'merged'), 'wb') as merged:
for _, line in lines: for _, line in lines:
os.write(merged.fileno(), '%s\n' % line) os.write(merged.fileno(), b'%s\n' % line)
class Test(Cmd): class Test(Cmd):
@ -318,7 +328,7 @@ class Test(Cmd):
(self.pathname, self.outputdir, self.timeout, self.pre, (self.pathname, self.outputdir, self.timeout, self.pre,
pre_user, self.post, post_user, self.user, self.tags) pre_user, self.post, post_user, self.user, self.tags)
def verify(self, logger): def verify(self):
""" """
Check the pre/post scripts, user and Test. Omit the Test from this Check the pre/post scripts, user and Test. Omit the Test from this
run if there are any problems. run if there are any problems.
@ -328,19 +338,19 @@ class Test(Cmd):
for f in [f for f in files if len(f)]: for f in [f for f in files if len(f)]:
if not verify_file(f): if not verify_file(f):
logger.info("Warning: Test '%s' not added to this run because" write_log("Warning: Test '%s' not added to this run because"
" it failed verification." % f) " it failed verification.\n" % f, LOG_ERR)
return False return False
for user in [user for user in users if len(user)]: for user in [user for user in users if len(user)]:
if not verify_user(user, logger): if not verify_user(user):
logger.info("Not adding Test '%s' to this run." % write_log("Not adding Test '%s' to this run.\n" %
self.pathname) self.pathname, LOG_ERR)
return False return False
return True return True
def run(self, logger, options): def run(self, options):
""" """
Create Cmd instances for the pre/post scripts. If the pre script Create Cmd instances for the pre/post scripts. If the pre script
doesn't pass, skip this Test. Run the post script regardless. doesn't pass, skip this Test. Run the post script regardless.
@ -358,18 +368,18 @@ class Test(Cmd):
if len(pretest.pathname): if len(pretest.pathname):
pretest.run(options) pretest.run(options)
cont = pretest.result.result is 'PASS' cont = pretest.result.result is 'PASS'
pretest.log(logger, options) pretest.log(options)
if cont: if cont:
test.run(options) test.run(options)
else: else:
test.skip() test.skip()
test.log(logger, options) test.log(options)
if len(posttest.pathname): if len(posttest.pathname):
posttest.run(options) posttest.run(options)
posttest.log(logger, options) posttest.log(options)
class TestGroup(Test): class TestGroup(Test):
@ -393,7 +403,7 @@ class TestGroup(Test):
(self.pathname, self.outputdir, self.tests, self.timeout, (self.pathname, self.outputdir, self.tests, self.timeout,
self.pre, pre_user, self.post, post_user, self.user, self.tags) self.pre, pre_user, self.post, post_user, self.user, self.tags)
def verify(self, logger): def verify(self):
""" """
Check the pre/post scripts, user and tests in this TestGroup. Omit Check the pre/post scripts, user and tests in this TestGroup. Omit
the TestGroup entirely, or simply delete the relevant tests in the the TestGroup entirely, or simply delete the relevant tests in the
@ -411,34 +421,34 @@ class TestGroup(Test):
for f in [f for f in auxfiles if len(f)]: for f in [f for f in auxfiles if len(f)]:
if self.pathname != os.path.dirname(f): if self.pathname != os.path.dirname(f):
logger.info("Warning: TestGroup '%s' not added to this run. " write_log("Warning: TestGroup '%s' not added to this run. "
"Auxiliary script '%s' exists in a different " "Auxiliary script '%s' exists in a different "
"directory." % (self.pathname, f)) "directory.\n" % (self.pathname, f), LOG_ERR)
return False return False
if not verify_file(f): if not verify_file(f):
logger.info("Warning: TestGroup '%s' not added to this run. " write_log("Warning: TestGroup '%s' not added to this run. "
"Auxiliary script '%s' failed verification." % "Auxiliary script '%s' failed verification.\n" %
(self.pathname, f)) (self.pathname, f), LOG_ERR)
return False return False
for user in [user for user in users if len(user)]: for user in [user for user in users if len(user)]:
if not verify_user(user, logger): if not verify_user(user):
logger.info("Not adding TestGroup '%s' to this run." % write_log("Not adding TestGroup '%s' to this run.\n" %
self.pathname) self.pathname, LOG_ERR)
return False return False
# If one of the tests is invalid, delete it, log it, and drive on. # If one of the tests is invalid, delete it, log it, and drive on.
for test in self.tests: for test in self.tests:
if not verify_file(os.path.join(self.pathname, test)): if not verify_file(os.path.join(self.pathname, test)):
del self.tests[self.tests.index(test)] del self.tests[self.tests.index(test)]
logger.info("Warning: Test '%s' removed from TestGroup '%s' " write_log("Warning: Test '%s' removed from TestGroup '%s' "
"because it failed verification." % "because it failed verification.\n" %
(test, self.pathname)) (test, self.pathname), LOG_ERR)
return len(self.tests) is not 0 return len(self.tests) is not 0
def run(self, logger, options): def run(self, options):
""" """
Create Cmd instances for the pre/post scripts. If the pre script Create Cmd instances for the pre/post scripts. If the pre script
doesn't pass, skip all the tests in this TestGroup. Run the post doesn't pass, skip all the tests in this TestGroup. Run the post
@ -459,7 +469,7 @@ class TestGroup(Test):
if len(pretest.pathname): if len(pretest.pathname):
pretest.run(options) pretest.run(options)
cont = pretest.result.result is 'PASS' cont = pretest.result.result is 'PASS'
pretest.log(logger, options) pretest.log(options)
for fname in self.tests: for fname in self.tests:
test = Cmd(os.path.join(self.pathname, fname), test = Cmd(os.path.join(self.pathname, fname),
@ -470,11 +480,11 @@ class TestGroup(Test):
else: else:
test.skip() test.skip()
test.log(logger, options) test.log(options)
if len(posttest.pathname): if len(posttest.pathname):
posttest.run(options) posttest.run(options)
posttest.log(logger, options) posttest.log(options)
class TestRun(object): class TestRun(object):
@ -486,7 +496,7 @@ class TestRun(object):
self.starttime = time() self.starttime = time()
self.timestamp = datetime.now().strftime('%Y%m%dT%H%M%S') self.timestamp = datetime.now().strftime('%Y%m%dT%H%M%S')
self.outputdir = os.path.join(options.outputdir, self.timestamp) self.outputdir = os.path.join(options.outputdir, self.timestamp)
self.logger = self.setup_logging(options) self.setup_logging(options)
self.defaults = [ self.defaults = [
('outputdir', BASEDIR), ('outputdir', BASEDIR),
('quiet', False), ('quiet', False),
@ -519,7 +529,7 @@ class TestRun(object):
for prop in Test.props: for prop in Test.props:
setattr(test, prop, getattr(options, prop)) setattr(test, prop, getattr(options, prop))
if test.verify(self.logger): if test.verify():
self.tests[pathname] = test self.tests[pathname] = test
def addtestgroup(self, dirname, filenames, options): def addtestgroup(self, dirname, filenames, options):
@ -541,9 +551,9 @@ class TestRun(object):
self.testgroups[dirname] = testgroup self.testgroups[dirname] = testgroup
self.testgroups[dirname].tests = sorted(filenames) self.testgroups[dirname].tests = sorted(filenames)
testgroup.verify(self.logger) testgroup.verify()
def read(self, logger, options): def read(self, options):
""" """
Read in the specified runfile, and apply the TestRun properties Read in the specified runfile, and apply the TestRun properties
listed in the 'DEFAULT' section to our TestRun. Then read each listed in the 'DEFAULT' section to our TestRun. Then read each
@ -552,7 +562,7 @@ class TestRun(object):
in the 'DEFAULT' section. If the Test or TestGroup passes in the 'DEFAULT' section. If the Test or TestGroup passes
verification, add it to the TestRun. verification, add it to the TestRun.
""" """
config = ConfigParser.RawConfigParser() config = configparser.RawConfigParser()
if not len(config.read(options.runfile)): if not len(config.read(options.runfile)):
fail("Coulnd't read config file %s" % options.runfile) fail("Coulnd't read config file %s" % options.runfile)
@ -584,7 +594,7 @@ class TestRun(object):
# Repopulate tests using eval to convert the string to a list # Repopulate tests using eval to convert the string to a list
testgroup.tests = eval(config.get(section, 'tests')) testgroup.tests = eval(config.get(section, 'tests'))
if testgroup.verify(logger): if testgroup.verify():
self.testgroups[section] = testgroup self.testgroups[section] = testgroup
else: else:
test = Test(section) test = Test(section)
@ -593,7 +603,7 @@ class TestRun(object):
if config.has_option(sect, prop): if config.has_option(sect, prop):
setattr(test, prop, config.get(sect, prop)) setattr(test, prop, config.get(sect, prop))
if test.verify(logger): if test.verify():
self.tests[section] = test self.tests[section] = test
def write(self, options): def write(self, options):
@ -608,7 +618,7 @@ class TestRun(object):
defaults = dict([(prop, getattr(options, prop)) for prop, _ in defaults = dict([(prop, getattr(options, prop)) for prop, _ in
self.defaults]) self.defaults])
config = ConfigParser.RawConfigParser(defaults) config = configparser.RawConfigParser(defaults)
for test in sorted(self.tests.keys()): for test in sorted(self.tests.keys()):
config.add_section(test) config.add_section(test)
@ -637,14 +647,15 @@ class TestRun(object):
""" """
done = False done = False
components = 0 components = 0
tmp_dict = dict(self.tests.items() + self.testgroups.items()) tmp_dict = dict(list(self.tests.items()) +
list(self.testgroups.items()))
total = len(tmp_dict) total = len(tmp_dict)
base = self.outputdir base = self.outputdir
while not done: while not done:
paths = [] paths = []
components -= 1 components -= 1
for testfile in tmp_dict.keys(): for testfile in list(tmp_dict.keys()):
uniq = '/'.join(testfile.split('/')[components:]).lstrip('/') uniq = '/'.join(testfile.split('/')[components:]).lstrip('/')
if uniq not in paths: if uniq not in paths:
paths.append(uniq) paths.append(uniq)
@ -655,42 +666,23 @@ class TestRun(object):
def setup_logging(self, options): def setup_logging(self, options):
""" """
Two loggers are set up here. The first is for the logfile which This funtion creates the output directory and gets a file object
will contain one line summarizing the test, including the test for the logfile. This function must be called before write_log()
name, result, and running time. This logger will also capture the can be used.
timestamped combined stdout and stderr of each run. The second
logger is optional console output, which will contain only the one
line summary. The loggers are initialized at two different levels
to facilitate segregating the output.
""" """
if options.dryrun is True: if options.dryrun is True:
return return
testlogger = logging.getLogger(__name__) global LOG_FILE_OBJ
testlogger.setLevel(logging.DEBUG)
if options.cmd is not 'wrconfig': if options.cmd is not 'wrconfig':
try: try:
old = os.umask(0) old = os.umask(0)
os.makedirs(self.outputdir, mode=0777) os.makedirs(self.outputdir, mode=0o777)
os.umask(old) os.umask(old)
except OSError, e: filename = os.path.join(self.outputdir, 'log')
LOG_FILE_OBJ = open(filename, buffering=0, mode='wb')
except OSError as e:
fail('%s' % e) fail('%s' % e)
filename = os.path.join(self.outputdir, 'log')
logfile = logging.FileHandler(filename)
logfile.setLevel(logging.DEBUG)
logfilefmt = logging.Formatter('%(message)s')
logfile.setFormatter(logfilefmt)
testlogger.addHandler(logfile)
cons = logging.StreamHandler()
cons.setLevel(logging.INFO)
consfmt = logging.Formatter('%(message)s')
cons.setFormatter(consfmt)
testlogger.addHandler(cons)
return testlogger
def run(self, options): def run(self, options):
""" """
@ -707,31 +699,31 @@ class TestRun(object):
if not os.path.exists(logsymlink): if not os.path.exists(logsymlink):
os.symlink(self.outputdir, logsymlink) os.symlink(self.outputdir, logsymlink)
else: else:
print 'Could not make a symlink to directory %s' % ( write_log('Could not make a symlink to directory %s\n' %
self.outputdir) self.outputdir, LOG_ERR)
iteration = 0 iteration = 0
while iteration < options.iterations: while iteration < options.iterations:
for test in sorted(self.tests.keys()): for test in sorted(self.tests.keys()):
self.tests[test].run(self.logger, options) self.tests[test].run(options)
for testgroup in sorted(self.testgroups.keys()): for testgroup in sorted(self.testgroups.keys()):
self.testgroups[testgroup].run(self.logger, options) self.testgroups[testgroup].run(options)
iteration += 1 iteration += 1
def summary(self): def summary(self):
if Result.total is 0: if Result.total is 0:
return 2 return 2
print '\nResults Summary' print('\nResults Summary')
for key in Result.runresults.keys(): for key in list(Result.runresults.keys()):
if Result.runresults[key] is not 0: if Result.runresults[key] is not 0:
print '%s\t% 4d' % (key, Result.runresults[key]) print('%s\t% 4d' % (key, Result.runresults[key]))
m, s = divmod(time() - self.starttime, 60) m, s = divmod(time() - self.starttime, 60)
h, m = divmod(m, 60) h, m = divmod(m, 60)
print '\nRunning Time:\t%02d:%02d:%02d' % (h, m, s) print('\nRunning Time:\t%02d:%02d:%02d' % (h, m, s))
print 'Percent passed:\t%.1f%%' % ((float(Result.runresults['PASS']) / print('Percent passed:\t%.1f%%' % ((float(Result.runresults['PASS']) /
float(Result.total)) * 100) float(Result.total)) * 100))
print 'Log directory:\t%s' % self.outputdir print('Log directory:\t%s' % self.outputdir)
if Result.runresults['FAIL'] > 0: if Result.runresults['FAIL'] > 0:
return 1 return 1
@ -742,6 +734,23 @@ class TestRun(object):
return 0 return 0
def write_log(msg, target):
"""
Write the provided message to standard out, standard error or
the logfile. If specifying LOG_FILE, then `msg` must be a bytes
like object. This way we can still handle output from tests that
may be in unexpected encodings.
"""
if target == LOG_OUT:
os.write(sys.stdout.fileno(), bytearray(msg, encoding='utf-8'))
elif target == LOG_ERR:
os.write(sys.stderr.fileno(), bytearray(msg, encoding='utf-8'))
elif target == LOG_FILE:
os.write(LOG_FILE_OBJ.fileno(), msg)
else:
fail('log_msg called with unknown target "%s"' % target)
def verify_file(pathname): def verify_file(pathname):
""" """
Verify that the supplied pathname is an executable regular file. Verify that the supplied pathname is an executable regular file.
@ -757,7 +766,7 @@ def verify_file(pathname):
return False return False
def verify_user(user, logger): def verify_user(user):
""" """
Verify that the specified user exists on this system, and can execute Verify that the specified user exists on this system, and can execute
sudo without being prompted for a password. sudo without being prompted for a password.
@ -770,13 +779,15 @@ def verify_user(user, logger):
try: try:
getpwnam(user) getpwnam(user)
except KeyError: except KeyError:
logger.info("Warning: user '%s' does not exist.", user) write_log("Warning: user '%s' does not exist.\n" % user,
LOG_ERR)
return False return False
p = Popen(testcmd) p = Popen(testcmd)
p.wait() p.wait()
if p.returncode is not 0: if p.returncode is not 0:
logger.info("Warning: user '%s' cannot use passwordless sudo.", user) write_log("Warning: user '%s' cannot use passwordless sudo.\n" % user,
LOG_ERR)
return False return False
else: else:
Cmd.verified_users.append(user) Cmd.verified_users.append(user)
@ -804,7 +815,7 @@ def find_tests(testrun, options):
def fail(retstr, ret=1): def fail(retstr, ret=1):
print '%s: %s' % (argv[0], retstr) print('%s: %s' % (sys.argv[0], retstr))
exit(ret) exit(ret)
@ -894,7 +905,7 @@ def main():
if options.cmd is 'runtests': if options.cmd is 'runtests':
find_tests(testrun, options) find_tests(testrun, options)
elif options.cmd is 'rdconfig': elif options.cmd is 'rdconfig':
testrun.read(testrun.logger, options) testrun.read(options)
elif options.cmd is 'wrconfig': elif options.cmd is 'wrconfig':
find_tests(testrun, options) find_tests(testrun, options)
testrun.write(options) testrun.write(options)

View File

@ -31,74 +31,132 @@
#include <string.h> #include <string.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <pthread.h> #include <pthread.h>
#include <errno.h>
#include <err.h>
/* /*
* -------------------------------------------------------------------- * --------------------------------------------------------------------
* Bug Id: 5032643 * Bug Issue Id: #7512
* The bug time sequence:
* 1. context #1, zfs_write assign a txg "n".
* 2. In the same process, context #2, mmap page fault (which means the mm_sem
* is hold) occurred, zfs_dirty_inode open a txg failed, and wait previous
* txg "n" completed.
* 3. context #1 call uiomove to write, however page fault is occurred in
* uiomove, which means it need mm_sem, but mm_sem is hold by
* context #2, so it stuck and can't complete, then txg "n" will not
* complete.
* *
* Simply writing to a file and mmaping that file at the same time can * So context #1 and context #2 trap into the "dead lock".
* result in deadlock. Nothing perverse like writing from the file's
* own mapping is required.
* -------------------------------------------------------------------- * --------------------------------------------------------------------
*/ */
static void * #define NORMAL_WRITE_TH_NUM 2
mapper(void *fdp)
{
void *addr;
int fd = *(int *)fdp;
if ((addr = static void *
mmap(0, 8192, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { normal_writer(void *filename)
perror("mmap"); {
exit(1); char *file_path = filename;
int fd = -1;
ssize_t write_num = 0;
int page_size = getpagesize();
fd = open(file_path, O_RDWR | O_CREAT, 0777);
if (fd == -1) {
err(1, "failed to open %s", file_path);
} }
for (;;) {
if (mmap(addr, 8192, PROT_READ, char *buf = malloc(1);
MAP_SHARED|MAP_FIXED, fd, 0) == MAP_FAILED) { while (1) {
perror("mmap"); write_num = write(fd, buf, 1);
exit(1); if (write_num == 0) {
err(1, "write failed!");
break;
}
lseek(fd, page_size, SEEK_CUR);
}
if (buf) {
free(buf);
}
}
static void *
map_writer(void *filename)
{
int fd = -1;
int ret = 0;
char *buf = NULL;
int page_size = getpagesize();
int op_errno = 0;
char *file_path = filename;
while (1) {
ret = access(file_path, F_OK);
if (ret) {
op_errno = errno;
if (op_errno == ENOENT) {
fd = open(file_path, O_RDWR | O_CREAT, 0777);
if (fd == -1) {
err(1, "open file failed");
}
ret = ftruncate(fd, page_size);
if (ret == -1) {
err(1, "truncate file failed");
}
} else {
err(1, "access file failed!");
}
} else {
fd = open(file_path, O_RDWR, 0777);
if (fd == -1) {
err(1, "open file failed");
}
}
if ((buf = mmap(NULL, page_size, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0)) == MAP_FAILED) {
err(1, "map file failed");
}
if (fd != -1)
close(fd);
char s[10] = {0, };
memcpy(buf, s, 10);
ret = munmap(buf, page_size);
if (ret != 0) {
err(1, "unmap file failed");
} }
} }
/* NOTREACHED */
return ((void *)1);
} }
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
int fd; pthread_t map_write_tid;
char buf[1024]; pthread_t normal_write_tid[NORMAL_WRITE_TH_NUM];
pthread_t tid; int i = 0;
memset(buf, 'a', sizeof (buf)); if (argc != 3) {
(void) printf("usage: %s <normal write file name>"
if (argc != 2) { "<map write file name>\n", argv[0]);
(void) printf("usage: %s <file name>\n", argv[0]);
exit(1); exit(1);
} }
if ((fd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0666)) == -1) { for (i = 0; i < NORMAL_WRITE_TH_NUM; i++) {
perror("open"); if (pthread_create(&normal_write_tid[i], NULL, normal_writer,
exit(1); argv[1])) {
} err(1, "pthread_create normal_writer failed.");
(void) pthread_setconcurrency(2);
if (pthread_create(&tid, NULL, mapper, &fd) != 0) {
perror("pthread_create");
close(fd);
exit(1);
}
for (;;) {
if (write(fd, buf, sizeof (buf)) == -1) {
perror("write");
close(fd);
exit(1);
} }
} }
close(fd); if (pthread_create(&map_write_tid, NULL, map_writer, argv[2])) {
err(1, "pthread_create map_writer failed.");
}
/* NOTREACHED */ /* NOTREACHED */
pthread_join(map_write_tid, NULL);
return (0); return (0);
} }

View File

@ -53,12 +53,14 @@ if ! is_mp; then
fi fi
log_must chmod 777 $TESTDIR log_must chmod 777 $TESTDIR
mmapwrite $TESTDIR/test-write-file & mmapwrite $TESTDIR/normal_write_file $TESTDIR/map_write_file &
PID_MMAPWRITE=$! PID_MMAPWRITE=$!
log_note "mmapwrite $TESTDIR/test-write-file pid: $PID_MMAPWRITE" log_note "mmapwrite $TESTDIR/normal_write_file $TESTDIR/map_write_file"\
"pid: $PID_MMAPWRITE"
log_must sleep 30 log_must sleep 30
log_must kill -9 $PID_MMAPWRITE log_must kill -9 $PID_MMAPWRITE
log_must ls -l $TESTDIR/test-write-file log_must ls -l $TESTDIR/normal_write_file
log_must ls -l $TESTDIR/map_write_file
log_pass "write(2) a mmap(2)'ing file succeeded." log_pass "write(2) a mmap(2)'ing file succeeded."

View File

@ -8,3 +8,7 @@ ENV{DEVTYPE}=="partition", IMPORT{program}="@udevdir@/vdev_id -d %k"
KERNEL=="*[!0-9]", ENV{SUBSYSTEM}=="block", ENV{ID_VDEV}=="?*", SYMLINK+="$env{ID_VDEV_PATH}" KERNEL=="*[!0-9]", ENV{SUBSYSTEM}=="block", ENV{ID_VDEV}=="?*", SYMLINK+="$env{ID_VDEV_PATH}"
KERNEL=="*[0-9]", ENV{SUBSYSTEM}=="block", ENV{DEVTYPE}=="partition", ENV{ID_VDEV}=="?*", SYMLINK+="$env{ID_VDEV_PATH}-part%n" KERNEL=="*[0-9]", ENV{SUBSYSTEM}=="block", ENV{DEVTYPE}=="partition", ENV{ID_VDEV}=="?*", SYMLINK+="$env{ID_VDEV_PATH}-part%n"
KERNEL=="dm-[0-9]*", ENV{SUBSYSTEM}=="block", ENV{ID_VDEV}=="?*", SYMLINK+="$env{ID_VDEV_PATH}" KERNEL=="dm-[0-9]*", ENV{SUBSYSTEM}=="block", ENV{ID_VDEV}=="?*", SYMLINK+="$env{ID_VDEV_PATH}"
# Enclosure device symlink rules
ENV{SUBSYSTEM}=="scsi_generic", IMPORT{program}="@udevdir@/vdev_id -e"
ENV{SUBSYSTEM}=="scsi_generic", ENV{ID_ENCLOSURE}=="?*", SYMLINK+="$env{ID_ENCLOSURE_PATH}"

View File

@ -7,6 +7,6 @@ ENV{ID_FS_TYPE}=="zfs_member", RUN+="/sbin/modprobe zfs"
KERNEL=="null", SYMLINK+="root" KERNEL=="null", SYMLINK+="root"
SYMLINK=="null", SYMLINK+="root" SYMLINK=="null", SYMLINK+="root"
SUBSYSTEM=="misc", KERNEL=="zfs", MODE="0666" KERNEL=="zfs", MODE="0666", OPTIONS+="static_node=zfs"
LABEL="zfs_end" LABEL="zfs_end"