Compare commits
23 Commits
zfs-0.7.12
...
zfs-0.7-re
Author | SHA1 | Date |
---|---|---|
Tony Hutter | a8c2b7ebc6 | |
John Wren Kennedy | 2af898ee24 | |
Gregor Kopka | c32c2f17d0 | |
Tony Hutter | 2254b2bbbe | |
Brian Behlendorf | 5c4ec382a7 | |
Tony Hutter | e22bfd8149 | |
Tony Hutter | f45ad7bff6 | |
Tony Hutter | 0a3a4d067a | |
Tony Hutter | ba8024a284 | |
Tony Hutter | edc2675aed | |
ilbsmart | 98bb45e27a | |
Neal Gompa (ニール・ゴンパ) | 44f463824b | |
Neal Gompa (ニール・ゴンパ) | b0d579bc55 | |
Benjamin Gentil | 7e5def8ae0 | |
Tony Hutter | 89019a846b | |
Simon Guest | 41f7723e9c | |
Simon Guest | 2b8c3cb0c8 | |
Olaf Faaland | f325d76e96 | |
Brian Behlendorf | e3fb781c5f | |
Ben Wolsieffer | 14a5e48fb9 | |
Matthew Ahrens | 01937958ce | |
LOLi | edb504f9db | |
LOLi | 2428fbbfcf |
|
@ -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
2
META
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
|
])
|
||||||
|
])
|
|
@ -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
|
||||||
|
])
|
||||||
|
|
|
@ -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([
|
||||||
|
#include <asm/i387.h>
|
||||||
|
#include <asm/xcr.h>
|
||||||
|
],[
|
||||||
|
kernel_fpu_begin();
|
||||||
|
kernel_fpu_end();
|
||||||
|
],[
|
||||||
|
AC_MSG_RESULT(kernel_fpu_*)
|
||||||
|
AC_DEFINE(HAVE_KERNEL_FPU, 1, [kernel has kernel_fpu_* functions])
|
||||||
|
AC_DEFINE(KERNEL_EXPORTS_X86_FPU, 1, [kernel exports FPU functions])
|
||||||
|
],[
|
||||||
ZFS_LINUX_TRY_COMPILE([
|
ZFS_LINUX_TRY_COMPILE([
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <asm/fpu/api.h>
|
#include <asm/fpu/api.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_UNDERSCORE_KERNEL_FPU, 1, [kernel has __kernel_fpu_* functions])
|
||||||
|
AC_DEFINE(KERNEL_EXPORTS_X86_FPU, 1, [kernel exports FPU functions])
|
||||||
],[
|
],[
|
||||||
AC_MSG_RESULT(no)
|
AC_MSG_RESULT(not exported)
|
||||||
|
])
|
||||||
])
|
])
|
||||||
])
|
])
|
||||||
|
|
|
@ -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.])
|
||||||
|
])
|
||||||
|
])
|
|
@ -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"], [
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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::
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
zfs
|
|
@ -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)
|
|
@ -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"
|
|
@ -0,0 +1 @@
|
||||||
|
zfs
|
|
@ -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)
|
|
@ -0,0 +1,3 @@
|
||||||
|
localtopdir = $(datarootdir)/initramfs-tools/scripts/local-top
|
||||||
|
|
||||||
|
EXTRA_DIST = zfs
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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 */
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
if (libzfs_run_process("/sbin/modprobe", argv, 0))
|
||||||
return (ENOEXEC);
|
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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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@
|
||||||
|
|
|
@ -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,9 +78,24 @@ 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) {
|
||||||
|
if (!zfs_access_ok(VERIFY_READ,
|
||||||
|
(iov->iov_base + skip), cnt)) {
|
||||||
return (EFAULT);
|
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:
|
||||||
if (rw == UIO_READ)
|
if (rw == UIO_READ)
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,6 +2997,7 @@ 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);
|
||||||
|
|
||||||
|
if (!evicting)
|
||||||
dbuf_evict_notify();
|
dbuf_evict_notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
|
|
|
@ -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:
|
|
||||||
fail('%s' % e)
|
|
||||||
filename = os.path.join(self.outputdir, 'log')
|
filename = os.path.join(self.outputdir, 'log')
|
||||||
|
LOG_FILE_OBJ = open(filename, buffering=0, mode='wb')
|
||||||
logfile = logging.FileHandler(filename)
|
except OSError as e:
|
||||||
logfile.setLevel(logging.DEBUG)
|
fail('%s' % e)
|
||||||
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)
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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."
|
||||||
|
|
|
@ -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}"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue