[PATCH v3] Handle OpenZFS ioctls

Dmitry V. Levin ldv at altlinux.org
Wed Feb 17 02:00:59 UTC 2021


On Thu, Jan 21, 2021 at 07:13:25PM +0100, наб wrote:
> Before/after of strace zfs list:
> -ioctl(3, _IOC(_IOC_NONE, 0x5a, 0x4, 0), 0x7ffe7f41e3b0) = 0
> -ioctl(3, _IOC(_IOC_NONE, 0x5a, 0x12, 0), 0x7ffe7f41e3c0) = 0
> -ioctl(3, _IOC(_IOC_NONE, 0x5a, 0x5, 0), 0x7ffe7f41ad30) = 0
> -ioctl(3, _IOC(_IOC_NONE, 0x5a, 0x27, 0), 0x7ffe7f41e320) = 0
> -ioctl(3, _IOC(_IOC_NONE, 0x5a, 0x14, 0), 0x7ffe7f41e370) = 0
> -ioctl(3, _IOC(_IOC_NONE, 0x5a, 0x14, 0), 0x7ffe7f41ad30) = -1 ESRCH (No such process)
> +ioctl(3, ZFS_IOC_POOL_CONFIGS, 0x7ffffae160c0) = 0
> +ioctl(3, ZFS_IOC_OBJSET_STATS, 0x7ffffae160d0) = 0
> +ioctl(3, ZFS_IOC_POOL_STATS, 0x7ffffae12a40) = 0
> +ioctl(3, ZFS_IOC_POOL_GET_PROPS, 0x7ffffae16030) = 0
> +ioctl(3, ZFS_IOC_DATASET_LIST_NEXT, 0x7ffffae16080) = 0
> +ioctl(3, ZFS_IOC_DATASET_LIST_NEXT, 0x7ffffae12a40) = -1 ESRCH (No such process)
> -ioctl(3, _IOC(_IOC_NONE, 0x5a, 0x3f, 0), 0x7ffe7f41e5b0) = -1 EPERM (Operation not permitted)
> +ioctl(3, ZFS_IOC_LOG_HISTORY, 0x7ffffae162c0) = -1 EPERM (Operation not permitted)
> 
> Before/after of strace zfs/cmd/zvol_id/zvol_id /dev/zd0:
> -ioctl(3, _IOC(_IOC_READ, 0x12, 0x7d, 0x100), 0x7fffa7776e20) = 0
> +ioctl(3, BLKZNAME, 0x7ffe02f435b0)      = 0
> 
> * maint/extract_zfs.sh: New file.
> * maint/extract_zfs.awk: New file.
> * ioctls_zfs.h: New file.
> * ioctlsort.c: Always include ioctls_zfs.h,
> as it's personality-independent
> * tests/ioctl.c: Test a few ZFS ioctls.
> ---
> This is a clean rebase of the patch I sent last month,
> since it appears to have been forgotten since.

Sorry, I had to prepare changes necessary for v5.11.
Nothing is forgotten. :)

>  ioctls_zfs.h          | 101 ++++++++++++++++++++++++++++++++++++++++++
>  ioctlsort.c           |   2 +
>  maint/extract_zfs.awk |  57 ++++++++++++++++++++++++
>  maint/extract_zfs.sh  |  25 +++++++++++
>  tests/ioctl.c         |  16 +++++++
>  5 files changed, 201 insertions(+)
>  create mode 100644 ioctls_zfs.h
>  create mode 100644 maint/extract_zfs.awk
>  create mode 100755 maint/extract_zfs.sh
> 
> diff --git a/ioctls_zfs.h b/ioctls_zfs.h
> new file mode 100644
> index 00000000..08f48bea
> --- /dev/null
> +++ b/ioctls_zfs.h
> @@ -0,0 +1,101 @@
> +/* Generated by extract_zfs.sh from OpenZFS version 2.0.0 */
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_POOL_CREATE", 0, 0x5A00, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_POOL_DESTROY", 0, 0x5A01, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_POOL_IMPORT", 0, 0x5A02, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_POOL_EXPORT", 0, 0x5A03, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_POOL_CONFIGS", 0, 0x5A04, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_POOL_STATS", 0, 0x5A05, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_POOL_TRYIMPORT", 0, 0x5A06, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_POOL_SCAN", 0, 0x5A07, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_POOL_FREEZE", 0, 0x5A08, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_POOL_UPGRADE", 0, 0x5A09, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_POOL_GET_HISTORY", 0, 0x5A0A, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_VDEV_ADD", 0, 0x5A0B, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_VDEV_REMOVE", 0, 0x5A0C, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_VDEV_SET_STATE", 0, 0x5A0D, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_VDEV_ATTACH", 0, 0x5A0E, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_VDEV_DETACH", 0, 0x5A0F, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_VDEV_SETPATH", 0, 0x5A10, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_VDEV_SETFRU", 0, 0x5A11, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_OBJSET_STATS", 0, 0x5A12, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_OBJSET_ZPLPROPS", 0, 0x5A13, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_DATASET_LIST_NEXT", 0, 0x5A14, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_SNAPSHOT_LIST_NEXT", 0, 0x5A15, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_SET_PROP", 0, 0x5A16, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_CREATE", 0, 0x5A17, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_DESTROY", 0, 0x5A18, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_ROLLBACK", 0, 0x5A19, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_RENAME", 0, 0x5A1A, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_RECV", 0, 0x5A1B, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_SEND", 0, 0x5A1C, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_INJECT_FAULT", 0, 0x5A1D, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_CLEAR_FAULT", 0, 0x5A1E, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_INJECT_LIST_NEXT", 0, 0x5A1F, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_ERROR_LOG", 0, 0x5A20, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_CLEAR", 0, 0x5A21, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_PROMOTE", 0, 0x5A22, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_SNAPSHOT", 0, 0x5A23, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_DSOBJ_TO_DSNAME", 0, 0x5A24, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_OBJ_TO_PATH", 0, 0x5A25, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_POOL_SET_PROPS", 0, 0x5A26, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_POOL_GET_PROPS", 0, 0x5A27, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_SET_FSACL", 0, 0x5A28, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_GET_FSACL", 0, 0x5A29, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_SHARE", 0, 0x5A2A, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_INHERIT_PROP", 0, 0x5A2B, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_SMB_ACL", 0, 0x5A2C, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_USERSPACE_ONE", 0, 0x5A2D, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_USERSPACE_MANY", 0, 0x5A2E, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_USERSPACE_UPGRADE", 0, 0x5A2F, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_HOLD", 0, 0x5A30, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_RELEASE", 0, 0x5A31, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_GET_HOLDS", 0, 0x5A32, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_OBJSET_RECVD_PROPS", 0, 0x5A33, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_VDEV_SPLIT", 0, 0x5A34, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_NEXT_OBJ", 0, 0x5A35, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_DIFF", 0, 0x5A36, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_TMP_SNAPSHOT", 0, 0x5A37, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_OBJ_TO_STATS", 0, 0x5A38, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_SPACE_WRITTEN", 0, 0x5A39, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_SPACE_SNAPS", 0, 0x5A3A, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_DESTROY_SNAPS", 0, 0x5A3B, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_POOL_REGUID", 0, 0x5A3C, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_POOL_REOPEN", 0, 0x5A3D, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_SEND_PROGRESS", 0, 0x5A3E, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_LOG_HISTORY", 0, 0x5A3F, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_SEND_NEW", 0, 0x5A40, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_SEND_SPACE", 0, 0x5A41, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_CLONE", 0, 0x5A42, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_BOOKMARK", 0, 0x5A43, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_GET_BOOKMARKS", 0, 0x5A44, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_DESTROY_BOOKMARKS", 0, 0x5A45, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_RECV_NEW", 0, 0x5A46, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_POOL_SYNC", 0, 0x5A47, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_CHANNEL_PROGRAM", 0, 0x5A48, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_LOAD_KEY", 0, 0x5A49, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_UNLOAD_KEY", 0, 0x5A4A, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_CHANGE_KEY", 0, 0x5A4B, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_REMAP", 0, 0x5A4C, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_POOL_CHECKPOINT", 0, 0x5A4D, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_POOL_DISCARD_CHECKPOINT", 0, 0x5A4E, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_POOL_INITIALIZE", 0, 0x5A4F, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_POOL_TRIM", 0, 0x5A50, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_REDACT", 0, 0x5A51, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_GET_BOOKMARK_PROPS", 0, 0x5A52, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_WAIT", 0, 0x5A53, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_WAIT_FS", 0, 0x5A54, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_PLATFORM", 0, 0x5A80, 0 },

ZFS_IOC_PLATFORM doesn't seem to be a valid ioctl command number.

> +{ "include/sys/fs/zfs.h", "ZFS_IOC_EVENTS_NEXT", 0, 0x5A81, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_EVENTS_CLEAR", 0, 0x5A82, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_EVENTS_SEEK", 0, 0x5A83, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_NEXTBOOT", 0, 0x5A84, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_JAIL", 0, 0x5A85, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_UNJAIL", 0, 0x5A86, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_SET_BOOTENV", 0, 0x5A87, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_GET_BOOTENV", 0, 0x5A88, 0 },
> +{ "include/sys/fs/zfs.h", "ZFS_IOC_LAST", 0, 0x5A89, 0 },

Likewise, ZFS_IOC_LAST doesn't seem to be a valid ioctl command number.

> +{ "include/sys/fs/zfs.h", "BLKZNAME", _IOC_READ, (0x12 << 8) | 125, 256 },
> +{ "lib/libspl/include/sys/kstat.h", "KSTAT_IOC_BASE", 0, 0x4B00, 0 },

Likewise, KSTAT_IOC_BASE doesn't seem to be a valid ioctl command number.

> +{ "lib/libspl/include/sys/kstat.h", "KSTAT_IOC_CHAIN_ID", 0, 0x4B01, 0 },
> +{ "lib/libspl/include/sys/kstat.h", "KSTAT_IOC_READ", 0, 0x4B02, 0 },
> +{ "lib/libspl/include/sys/kstat.h", "KSTAT_IOC_WRITE", 0, 0x4B03, 0 },
> diff --git a/ioctlsort.c b/ioctlsort.c
> index b92cbecc..afb61803 100644
> --- a/ioctlsort.c
> +++ b/ioctlsort.c
> @@ -135,6 +135,8 @@ static struct ioctlent ioctls[] = {
>  # include "ioctls_arch.h"
>  # include "ioctls_inc.h"
>  #endif
> +
> +#include "ioctls_zfs.h"
>  };
>  
>  int
> diff --git a/maint/extract_zfs.awk b/maint/extract_zfs.awk
> new file mode 100644
> index 00000000..e674ad61
> --- /dev/null
> +++ b/maint/extract_zfs.awk
> @@ -0,0 +1,57 @@
> +#!/bin/sh -e
> +#
> +# Parse OpenZFS headers into C source
> +# that writes them in ioctlsort.c format.
> +#
> +# See extract_zfs.sh for the driver.
> +#
> +# Copyright (c) 2020 The strace developers.
> +# All rights reserved
> +#
> +# SPDX-License-Identifier: LGPL-2.1-or-later
> +
> +BEGIN {
> +	print "#include <stdio.h>"
> +	print "#include <stdint.h>"
> +	print "#include \"lib/libspl/include/sys/stdtypes.h\""
> +	print "typedef uint64_t hrtime_t;"

Why do you need to manually include headers and define types?
I suppose headers already contain all necessary #include statements,
so proper -I options should do the job.

> +	for(i = 1; i < ARGC; ++i)
> +		print "#include \"" ARGV[i] "\""
> +	print "int main() {"
> +	print "	puts(\"/* Generated by extract_zfs.sh from OpenZFS version " ENVIRON["ZVER"] " */\");"

This line is too long, please fold long lines.

> +}
> +
> +
> +/enum zfs_ioc/ {
> +	in_ioc = 1
> +}
> +
> +in_ioc && $1 ~ /ZFS_IOC_/ {
> +	gsub(/,/, "", $1)
> +	if($1 == "ZFS_IOC_FIRST" || $1 == "ZFS_IOC")
> +		next

If $1 ~ /ZFS_IOC_/ is true, then $1 == "ZFS_IOC" is always false.

> +	print "	printf(\"{ \\\"" FILENAME  "\\\", \\\"" $1 "\\\", 0, 0x%04X, 0 },\\n\", " $1 ");"

This is hard to read, isn't it?

Given that the whole list of ioctl constants defined in
include/sys/fs/zfs.h can be obtained using a simple one-liner, e.g.
sed -rn 's/^[[:space:]]*(ZFS_IOC_[^,[:space:]]+).*/\1/p' include/sys/fs/zfs.h
could you make a straightforward script, please?

> +}
> +
> +in_ioc && /\}/ {
> +	in_ioc = 0
> +}
> +
> +
> +/^#define\tBLKZNAME/ {
> +	$1 = $2 = ""
> +	gsub(/_IOR\(/, "", $0)
> +	gsub(/\)/, "", $0)
> +	gsub(/,/, "", $0)
> +	print "	printf(\"{ \\\"" FILENAME  "\\\", \\\"" "BLKZNAME" "\\\", _IOC_READ, (" $1 " << 8) | " $2 ", %zu },\\n\", sizeof(" $3 "));"
> +}

Sorry, this is too complicated for a single constant with a value known in advance.

> +
> +
> +/^#define\tKSTAT_IOC_/ {
> +	print "	printf(\"{ \\\"" FILENAME  "\\\", \\\"" $2 "\\\", 0, 0x%04X, 0 },\\n\", " $2 ");"
> +}

Likewise,
sed -rn 's/^#define[[:space:]]+(KSTAT_IOC_[^[:space:]]+).*/\1/p' lib/libspl/include/sys/kstat.h
produces the whole list of ioctl constants defined in that file.

> +
> +
> +END {
> +	print "}"
> +}
> diff --git a/maint/extract_zfs.sh b/maint/extract_zfs.sh
> new file mode 100755
> index 00000000..b2652684
> --- /dev/null
> +++ b/maint/extract_zfs.sh
> @@ -0,0 +1,25 @@
> +#!/bin/sh -e
> +#
> +# Scrape out ioctls from an OpenZFS tree.
> +# This should only be needed for getting new definitions,
> +# since OpenZFS is committed to this ABI.
> +#
> +# Copyright (c) 2020 The strace developers.
> +# All rights reserved
> +#
> +# SPDX-License-Identifier: LGPL-2.1-or-later
> +
> +[ -z "$1" ] && {
> +	echo "Usage: $0 <path to OpenZFS clone>" >&2
> +	exit 1
> +}
> +
> +executable="$(mktemp)"

This can leak temporary files.  See maint/ioctls_sym.sh for an example how
to deal with temporary files properly.

> +self="$(realpath "$0")"
> +ZVER="$(awk '/Version/ {print $2}' "$1/META")"

sed '/^Version:[[:space:]]*/!d;s///;q' META

> +export ZVER

Consider using awk -v, or rather print the header right from the shell.

> +
> +cd "$1"
> +awk -f "${self%sh}awk" include/sys/fs/zfs.h lib/libspl/include/sys/kstat.h | cc -isystem include -xc - -o "$executable"

Please save the file being compiled, it helps debugging.


-- 
ldv


More information about the Strace-devel mailing list