Re: [PATCH] blkpr: add block persistent reservations command

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Any reason this never got picked up or commented on?

On Thu, Sep 16, 2021 at 11:29:01AM +0800, zhenwei pi wrote:
> Linux kernel block layer supports PR (persistent reservations) ioctl
> on a block device. Typically SCSI and NVMe disk support PR feature,
> and blkpr could operation on them.
> 
> Signed-off-by: zhenwei pi <pizhenwei@xxxxxxxxxxxxx>
> ---
>  configure.ac            |  11 ++
>  sys-utils/Makemodule.am |   8 ++
>  sys-utils/blkpr.8.adoc  |  64 ++++++++++
>  sys-utils/blkpr.c       | 277 ++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 360 insertions(+)
>  create mode 100644 sys-utils/blkpr.8.adoc
>  create mode 100644 sys-utils/blkpr.c
> 
> diff --git a/configure.ac b/configure.ac
> index 60e63592b..ae47a5c6c 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -310,6 +310,7 @@ AC_CHECK_HEADERS([ \
>  	linux/fiemap.h \
>  	linux/net_namespace.h \
>  	linux/nsfs.h \
> +	linux/pr.h \
>  	linux/raw.h \
>  	linux/securebits.h \
>  	linux/tiocl.h \
> @@ -387,6 +388,10 @@ AC_CHECK_DECLS([BLK_ZONE_REP_CAPACITY], [], [], [
>  	#include <linux/blkzoned.h>
>  ])
>  
> +AC_CHECK_DECLS([PR_REP_CAPACITY], [], [], [
> +	#include <linux/pr.h>
> +])
> +
>  AC_CHECK_HEADERS([security/openpam.h], [], [], [
>  #ifdef HAVE_SECURITY_PAM_APPL_H
>  #include <security/pam_appl.h>
> @@ -454,6 +459,7 @@ dnl
>  have_linux_blkzoned_h=$ac_cv_header_linux_blkzoned_h
>  have_linux_btrfs_h=$ac_cv_header_linux_btrfs_h
>  have_linux_capability_h=$ac_cv_header_linux_capability_h
> +have_linux_pr_h=$ac_cv_header_linux_pr_h
>  have_linux_raw_h=$ac_cv_header_linux_raw_h
>  have_linux_securebits_h=$ac_cv_header_linux_securebits_h
>  have_linux_version_h=$ac_cv_header_linux_version_h
> @@ -1905,6 +1911,11 @@ UL_REQUIRES_LINUX([blkzone])
>  UL_REQUIRES_HAVE([blkzone], [linux_blkzoned_h], [linux/blkzoned.h header])
>  AM_CONDITIONAL([BUILD_BLKZONE], [test "x$build_blkzone" = xyes])
>  
> +UL_BUILD_INIT([blkpr], [check])
> +UL_REQUIRES_LINUX([blkpr])
> +UL_REQUIRES_HAVE([blkpr], [linux_pr_h], [linux/pr.h header])
> +AM_CONDITIONAL([BUILD_BLKPR], [test "x$build_blkpr" = xyes])
> +
>  UL_BUILD_INIT([ldattach], [check])
>  UL_REQUIRES_LINUX([ldattach])
>  AM_CONDITIONAL([BUILD_LDATTACH], [test "x$build_ldattach" = xyes])
> diff --git a/sys-utils/Makemodule.am b/sys-utils/Makemodule.am
> index e55363484..22047d9bd 100644
> --- a/sys-utils/Makemodule.am
> +++ b/sys-utils/Makemodule.am
> @@ -202,6 +202,14 @@ blkzone_SOURCES = sys-utils/blkzone.c
>  blkzone_LDADD = $(LDADD) libcommon.la
>  endif
>  
> +if BUILD_BLKPR
> +sbin_PROGRAMS += blkpr
> +MANPAGES += sys-utils/blkpr.8
> +dist_noinst_DATA += sys-utils/blkpr.8.adoc
> +blkpr_SOURCES = sys-utils/blkpr.c
> +blkpr_LDADD = $(LDADD) libcommon.la
> +endif
> +
>  if BUILD_LDATTACH
>  usrsbin_exec_PROGRAMS += ldattach
>  MANPAGES += sys-utils/ldattach.8
> diff --git a/sys-utils/blkpr.8.adoc b/sys-utils/blkpr.8.adoc
> new file mode 100644
> index 000000000..dc8bb3893
> --- /dev/null
> +++ b/sys-utils/blkpr.8.adoc
> @@ -0,0 +1,64 @@
> +//po4a: entry man manual
> += blkpr(8)
> +:doctype: manpage
> +:man manual: System Administration
> +:man source: util-linux {release-version}
> +:page-layout: base
> +:command: blkpr
> +
> +== NAME
> +
> +blkpr - run persistent reservations command on a device
> +
> +== SYNOPSIS
> +
> +*blkpr* [options] _device_
> +
> +== DESCRIPTION
> +
> +*blkpr* is used to run persistent reservations command on device that supports Persistent Reservations feature.
> +
> +The _device_ argument is the pathname of the block device.
> +
> +== OPTIONS
> +
> +*-o*, *--operation* _operation_::
> +The operation of persistent reservations, supported [register|reserve|release|preempt|preempt-abort|clear].
> +
> +*-k*, *--key* _key_::
> +The key the operation should operate on.
> +
> +*-K*, *--oldkey* _oldkey_::
> +The old key the operation should operate on.
> +
> +*-f*, *--flag* _flag_::
> +Supported flag [ignore-key].
> +
> +*-t*, *--type*::
> +Supported type [write-exclusive|exclusive-access|write-exclusive-reg-only|exclusive-access-reg-only|write-exclusive-all-regs|exclusive-access-all-regs]
> +
> +*-V*, *--version*::
> +Display version information and exit.
> +
> +*-h*, *--help*::
> +Display help text and exit.
> +
> +== AUTHORS
> +
> +mailto:pizhenwei@xxxxxxxxxxxxx[zhenwei pi]
> +
> +== SEE ALSO
> +
> +*sg_persist*(8)
> +
> +Linux documentation at: <https://www.kernel.org/doc/Documentation/block/pr.txt>
> +iSCSI specification at: <https://datatracker.ietf.org/doc/html/rfc3720>
> +NVMe-oF specification at: <https://nvmexpress.org/nvme-over-fabrics-part-two/>
> +
> +include::man-common/bugreports.adoc[]
> +
> +include::man-common/footer.adoc[]
> +
> +ifdef::translation[]
> +include::man-common/translation.adoc[]
> +endif::[]
> diff --git a/sys-utils/blkpr.c b/sys-utils/blkpr.c
> new file mode 100644
> index 000000000..3f8c19343
> --- /dev/null
> +++ b/sys-utils/blkpr.c
> @@ -0,0 +1,277 @@
> +/*
> + * blkpr.c -- persistent reservations on a block device.
> + *
> + * Copyright (C) 2021 zhenwei pi <pizhenwei@xxxxxxxxxxxxx>
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * This program uses IOC_PR_XXX ioctl to do persistent reservations
> + * operation on a block device if the device supports it.
> + */
> +
> +
> +#include <string.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <getopt.h>
> +#include <locale.h>
> +#include <sys/ioctl.h>
> +#include <linux/pr.h>
> +
> +#include "nls.h"
> +#include "c.h"
> +#include "closestream.h"
> +#include "strutils.h"
> +#include "xalloc.h"
> +
> +struct type_string {
> +	int type;
> +	char *str;
> +};
> +
> +/* This array should keep align with enum pr_type of linux/types.h */
> +static struct type_string pr_type[] = {
> +	{PR_WRITE_EXCLUSIVE,           "write-exclusive"},
> +	{PR_EXCLUSIVE_ACCESS,          "exclusive-access"},
> +	{PR_WRITE_EXCLUSIVE_REG_ONLY,  "write-exclusive-reg-only"},
> +	{PR_EXCLUSIVE_ACCESS_REG_ONLY, "exclusive-access-reg-only"},
> +	{PR_WRITE_EXCLUSIVE_ALL_REGS,  "write-exclusive-all-regs"},
> +	{PR_EXCLUSIVE_ACCESS_ALL_REGS, "exclusive-access-all-regs"}
> +};
> +
> +static struct type_string pr_operation[] = {
> +	{IOC_PR_REGISTER,      "register"},
> +	{IOC_PR_RESERVE,       "reserve"},
> +	{IOC_PR_RELEASE,       "release"},
> +	{IOC_PR_PREEMPT,       "preempt"},
> +	{IOC_PR_PREEMPT_ABORT, "preempt-abort"},
> +	{IOC_PR_CLEAR,         "clear"},
> +};
> +
> +static struct type_string pr_flag[] = {
> +	{PR_FL_IGNORE_KEY, "ignore-key"}
> +};
> +
> +static char *all_type_string(struct type_string *ts, int nmem)
> +{
> +	char *prtypes, *tmp;
> +	size_t total = 0, length;
> +	int i;
> +
> +	for (i = 0; i < nmem; i++) {
> +		total += (strlen(ts[i].str) + 1);
> +	}
> +
> +	tmp = prtypes = xmalloc(total);
> +	for (i = 0; i < nmem; i++) {
> +		strcpy(tmp, ts[i].str);
> +		length = strlen(ts[i].str);
> +
> +		tmp[length++] = '|';
> +		tmp += length;
> +	}
> +
> +	/* strip the last '|' */
> +	prtypes[total - 1] = '\0';
> +
> +	return prtypes;
> +}
> +
> +static int parse_type_by_str(struct type_string *ts, int nmem, char *pattern)
> +{
> +	int i;
> +
> +	for (i = 0; i < nmem; i++) {
> +		if (!strcmp(ts[i].str, pattern)) {
> +			return ts[i].type;
> +		}
> +	}
> +
> +	return -1;
> +}
> +
> +#define SUPPORTED(XX) \
> +	static char *supported_##XX(void) \
> +	{ return all_type_string(XX, ARRAY_SIZE(XX)); }
> +
> +#define PARSE(XX) \
> +	static int parse_##XX(char *pattern) \
> +	{ return parse_type_by_str(XX, ARRAY_SIZE(XX), pattern); }
> +
> +SUPPORTED(pr_type);
> +SUPPORTED(pr_operation);
> +SUPPORTED(pr_flag);
> +
> +PARSE(pr_type);
> +PARSE(pr_operation);
> +PARSE(pr_flag);
> +
> +static int do_pr(char *path, uint64_t key, uint64_t oldkey, int op, int type, int flag)
> +{
> +	struct pr_registration pr_reg;
> +	struct pr_reservation pr_res;
> +	struct pr_preempt pr_prt;
> +	struct pr_clear pr_clr;
> +	int fd, ret;
> +
> +	fd = open(path, O_RDWR);
> +	if (fd < 0) {
> +		err(EXIT_FAILURE, _("cannot open %s"), path);
> +	}
> +
> +	switch (op) {
> +	case IOC_PR_REGISTER:
> +		pr_reg.old_key = oldkey;
> +		pr_reg.new_key = key;
> +		pr_reg.flags = flag;
> +		ret = ioctl(fd, op, &pr_reg);
> +		break;
> +	case IOC_PR_RESERVE:
> +	case IOC_PR_RELEASE:
> +		pr_res.key = key;
> +		pr_res.type = type;
> +		pr_res.flags = flag;
> +		ret = ioctl(fd, op, &pr_res);
> +		break;
> +	case IOC_PR_PREEMPT:
> +	case IOC_PR_PREEMPT_ABORT:
> +		pr_prt.old_key = oldkey;
> +		pr_prt.new_key = key;
> +		pr_prt.type = type;
> +		pr_prt.flags = flag;
> +		ret = ioctl(fd, op, &pr_prt);
> +		break;
> +	case IOC_PR_CLEAR:
> +		pr_clr.key = key;
> +		pr_clr.flags = flag;
> +		ret = ioctl(fd, op, &pr_clr);
> +		break;
> +	default:
> +		errno = EINVAL;
> +		err(EXIT_FAILURE, _("unknown operation"));
> +	}
> +
> +	close(fd);
> +	if (ret < 0) {
> +		err(EXIT_FAILURE, _("pr ioctl failed"));
> +	} else if (ret > 0) {
> +		errx(EXIT_FAILURE, _("error code 0x%x, for more detailed information see specification of device model."), ret);
> +	}
> +
> +	return ret;
> +}
> +
> +static void __attribute__((__noreturn__)) usage(void)
> +{
> +	FILE *out = stdout;
> +	fputs(USAGE_HEADER, out);
> +	fprintf(out,
> +	      _(" %s [options] <device>\n"), program_invocation_short_name);
> +
> +	fputs(USAGE_SEPARATOR, out);
> +	fputs(_("Persistent reservations on a device.\n"), out);
> +
> +	fputs(USAGE_OPTIONS, out);
> +	fprintf(out, _(" -o, --operation <string>  supported operation [%s]\n"), supported_pr_operation());
> +	fputs(_(" -k, --key <num>           key to operate\n"), out);
> +	fputs(_(" -K, --oldkey <num>        old key to operate\n"), out);
> +	fprintf(out, _(" -f, --flag <string>       supported flag [%s]\n"), supported_pr_flag());
> +	fprintf(out, _(" -t, --type <string>       supported type [%s]\n"), supported_pr_type());
> +
> +	fputs(USAGE_SEPARATOR, out);
> +	printf(USAGE_HELP_OPTIONS(21));
> +
> +	fputs(USAGE_ARGUMENTS, out);
> +
> +	printf(USAGE_MAN_TAIL("blkpr(8)"));
> +	exit(EXIT_SUCCESS);
> +}
> +
> +int main(int argc, char **argv)
> +{
> +	char c;
> +	char *path;
> +	uint64_t key = 0, oldkey = 0;
> +	int operation = -1, type = -1, flag = 0;
> +
> +	static const struct option longopts[] = {
> +	    { "help",            no_argument,       NULL, 'h' },
> +	    { "version",         no_argument,       NULL, 'V' },
> +	    { "operation",       required_argument, NULL, 'o' },
> +	    { "key",             required_argument, NULL, 'k' },
> +	    { "oldkey",          required_argument, NULL, 'K' },
> +	    { "flag",            required_argument, NULL, 'f' },
> +	    { "type",            required_argument, NULL, 't' },
> +	    { NULL, 0, NULL, 0 }
> +	};
> +
> +	setlocale(LC_ALL, "");
> +	bindtextdomain(PACKAGE, LOCALEDIR);
> +	textdomain(PACKAGE);
> +	close_stdout_atexit();
> +
> +	errno = EINVAL;
> +	while ((c = getopt_long(argc, argv, "hVo:k:K:f:t:", longopts, NULL)) != -1) {
> +		switch(c) {
> +		case 'k':
> +			key = strtosize_or_err(optarg,
> +					_("failed to parse key"));
> +			break;
> +		case 'K':
> +			oldkey = strtosize_or_err(optarg,
> +					_("failed to parse old key"));
> +			break;
> +		case 'o':
> +			operation = parse_pr_operation(optarg);
> +			if (operation < 0) {
> +				err(EXIT_FAILURE, _("unknown operation"));
> +			}
> +			break;
> +		case 't':
> +			type = parse_pr_type(optarg);
> +			if (type < 0) {
> +				err(EXIT_FAILURE, _("unknown type"));
> +			}
> +			break;
> +		case 'f':
> +			flag = parse_pr_flag(optarg);
> +			if (flag < 0) {
> +				err(EXIT_FAILURE, _("unknown flag"));
> +			}
> +			break;
> +
> +		case 'h':
> +			usage();
> +		case 'V':
> +			print_version(EXIT_SUCCESS);
> +		default:
> +			errtryhelp(EXIT_FAILURE);
> +		}
> +	}
> +
> +	if (optind == argc) {
> +		errx(EXIT_FAILURE, _("no device specified"));
> +	}
> +
> +	path = argv[optind++];
> +	if (optind != argc) {
> +		warnx(_("unexpected number of arguments"));
> +		errtryhelp(EXIT_FAILURE);
> +	}
> +
> +	do_pr(path, key, oldkey, operation, type, flag);
> +
> +	return EXIT_SUCCESS;
> +}
> -- 
> 2.25.1
> 
---end quoted text---



[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux