zvol: Support blk-mq for better performance

Add support for the kernel's block multiqueue (blk-mq) interface in
the zvol block driver.  blk-mq creates multiple request queues on
different CPUs rather than having a single request queue.  This can
improve zvol performance with multithreaded reads/writes.

This implementation uses the blk-mq interfaces on 4.13 or newer
kernels.  Building against older kernels will fall back to the
older BIO interfaces.

Note that you must set the `zvol_use_blk_mq` module param to
enable the blk-mq API.  It is disabled by default.

In addition, this commit lets the zvol blk-mq layer process whole
`struct request` IOs at a time, rather than breaking them down
into their individual BIOs.  This reduces dbuf lock contention
and overhead versus the legacy zvol submit_bio() codepath.

	sequential dd to one zvol, 8k volblocksize, no O_DIRECT:

	legacy submit_bio()     292MB/s write  453MB/s read
	this commit             453MB/s write  885MB/s read

It also introduces a new `zvol_blk_mq_chunks_per_thread` module
parameter. This parameter represents how many volblocksize'd chunks
to process per each zvol thread.  It can be used to tune your zvols
for better read vs write performance (higher values favor write,
lower favor read).

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz>
Reviewed-by: Tony Nguyen <tony.nguyen@delphix.com>
Signed-off-by: Tony Hutter <hutter2@llnl.gov>
Closes #13148
Issue #12483
This commit is contained in:
Tony Hutter
2022-06-09 07:10:38 -07:00
committed by GitHub
parent 985c33b132
commit 6f73d02168
18 changed files with 1441 additions and 152 deletions
+32 -13
View File
@@ -2770,20 +2770,22 @@ function is_te_enabled
svcs -H -o state labeld 2>/dev/null | grep -q "enabled"
}
# Return the number of CPUs (cross-platform)
function get_num_cpus
{
if is_linux ; then
grep -c '^processor' /proc/cpuinfo
elif is_freebsd; then
sysctl -n kern.smp.cpus
else
psrinfo | wc -l
fi
}
# Utility function to determine if a system has multiple cpus.
function is_mp
{
case "$UNAME" in
Linux)
(($(grep -c '^processor' /proc/cpuinfo) > 1))
;;
FreeBSD)
sysctl -n kern.smp.cpus
;;
*)
(($(psrinfo | wc -l) > 1))
;;
esac
[[ $(get_num_cpus) -gt 1 ]]
}
function get_cpu_freq
@@ -3320,14 +3322,23 @@ function get_tunable_impl
{
typeset name="$1"
typeset module="${2:-zfs}"
typeset check_only="$3"
eval "typeset tunable=\$$name"
case "$tunable" in
UNSUPPORTED)
log_unsupported "Tunable '$name' is unsupported on $UNAME"
if [ -z "$check_only" ] ; then
log_unsupported "Tunable '$name' is unsupported on $UNAME"
else
return 1
fi
;;
"")
log_fail "Tunable '$name' must be added to tunables.cfg"
if [ -z "$check_only" ] ; then
log_fail "Tunable '$name' must be added to tunables.cfg"
else
return 1
fi
;;
*)
;;
@@ -3347,6 +3358,14 @@ function get_tunable_impl
esac
}
# Does a tunable exist?
#
# $1: Tunable name
function tunable_exists
{
get_tunable_impl $1 "zfs" 1
}
#
# Compute MD5 digest for given file or stdin if no file given.
# Note: file path must not contain spaces