SHA256
1
0
forked from pool/s390-tools
s390-tools/s390-tools-sles12sp2-feat-01-dasd-query-host.patch
2017-02-21 11:14:26 +00:00

745 lines
22 KiB
Diff

Subject: [PATCH] [FEAT LS1213] dasd: add query host access to volume support
From: Stefan Haberland <sth@linux.vnet.ibm.com>
Summary: dasd: add query host access to volume support
Description: With this feature, applications can query if a DASD volume is
online to another operating system instances by checking the
online status of all attached hosts from the storage server.
Upstream-ID: -
Problem-ID: LS1213
Signed-off-by: Stefan Haberland <sth@linux.vnet.ibm.com>
---
dasdfmt/dasdfmt.8 | 7 ++
dasdfmt/dasdfmt.c | 38 ++++++++++++--
dasdfmt/dasdfmt.h | 4 +
fdasd/fdasd.8 | 9 ++-
fdasd/fdasd.c | 32 ++++++++++++
fdasd/fdasd.h | 28 +++++-----
include/libzds.h | 1
include/u2s.h | 5 +
libu2s/u2s.c | 43 ++++++++++++++++
libzds/Makefile | 2
libzds/libzds.c | 46 +++++++++++++++--
zconf/lsdasd | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
zconf/lsdasd.8 | 5 +
zdsfs/zdsfs.1 | 4 +
zdsfs/zdsfs.c | 18 ++++++
15 files changed, 345 insertions(+), 36 deletions(-)
--- a/dasdfmt/dasdfmt.8
+++ b/dasdfmt/dasdfmt.8
@@ -7,7 +7,7 @@ dasdfmt \- formatting of DASD (ECKD) dis
.br
[-r \fIcylinder\fR] [-b \fIblksize\fR] [-l \fIvolser\fR] [-d \fIlayout\fR]
.br
- [-L] [-V] [-F] [-k] \fIdevice\fR
+ [-L] [-V] [-F] [-k] [-C] \fIdevice\fR
.SH DESCRIPTION
\fBdasdfmt\fR formats a DASD (ECKD) disk drive to prepare it
@@ -70,6 +70,11 @@ Print version number and exit.
Formats the device without checking, if the device is in use.
.TP
+\fB-C\fR or \fB--check_host_count\fR
+Force dasdfmt to check the host access open count to ensure the device
+is not online on another operating system instance
+
+.TP
\fB-d\fR \fIlayout\fR or \fB--disk_layout\fR=\fIlayout\fR
Formats the device with compatible disk layout or linux disk layout.
\fIlayout\fR is either \fIcdl\fR for the compatible disk layout
--- a/dasdfmt/dasdfmt.c
+++ b/dasdfmt/dasdfmt.c
@@ -18,6 +18,8 @@
#include "util_proc.h"
#include "dasd_sys.h"
+#define BUSIDSIZE 8
+
/* Full tool name */
static const char tool_name[] = "dasdfmt: zSeries DASD format program";
@@ -46,7 +48,7 @@ print_version (void)
*/
static void exit_usage(int exitcode)
{
- printf("Usage: %s [-htvypPLVFk]\n"
+ printf("Usage: %s [-htvypPLVFkC]\n"
" [-l <volser> | --label=<volser>]\n"
" [-b <blocksize> | --blocksize=<blocksize>]\n"
" [-d <disk layout> | --disk_layout=<disk layout>]\n"
@@ -65,6 +67,9 @@ static void exit_usage(int exitcode)
" -v means verbose mode\n"
" -F means don't check if the device is in use\n"
" -k means keep volume serial\n"
+ " -C or --check_host_count means force dasdfmt to check\n"
+ " the host access open count to ensure the device\n"
+ " is not online on another operating system instance\n"
" --norecordzero prevent storage server from modifying"
" record 0\n\n"
" <volser> is the volume identifier, which is converted\n"
@@ -190,7 +195,6 @@ static void get_device_name(dasdfmt_info
}
}
-
/*
* initialize the dasdfmt info structure
*/
@@ -214,6 +218,7 @@ static void init_info(dasdfmt_info_t *in
info->node_specified = 0;
info->device_id = 0;
info->keep_volser = 0;
+ info->force_host = 0;
}
@@ -776,6 +781,7 @@ static void do_format_dasd(dasdfmt_info_
dasd_information_t dasd_info;
struct dasd_eckd_characteristics *characteristics;
unsigned int cylinders, heads;
+ int count;
if (info->verbosity > 0) printf("Retrieving disk geometry...\n");
@@ -835,6 +841,27 @@ static void do_format_dasd(dasdfmt_info_
if ((info->verbosity > 0) || (!info->withoutprompt))
dasdfmt_print_info(info, vlabel, cylinders, heads, p);
+ count = u2s_get_host_access_count(info->devname);
+ if (info->force_host) {
+ if (count > 1) {
+ ERRMSG_EXIT(EXIT_FAILURE,
+ "\n%s: Disk %s is online on OS instances in %d different LPARs.\n"
+ "Note: Your installation might include z/VM systems that are configured to\n"
+ "automatically vary on disks, regardless of whether they are subsequently used.\n\n",
+ prog_name, info->devname, count);
+ } else if (count < 0) {
+ ERRMSG("\nHosts access information not available for disk %s.\n\n",
+ info->devname);
+ return;
+ }
+ } else if (count > 1)
+ ERRMSG("\nWARNING:\n"
+ "Disk %s is online on operating system instances in %d different LPARs.\n"
+ "Ensure that the disk is not being used by a system outside your LPAR.\n"
+ "Note: Your installation might include z/VM systems that are configured to\n"
+ "automatically vary on disks, regardless of whether they are subsequently used.\n",
+ info->devname, count);
+
if (!info->testmode) {
if (!info->withoutprompt) {
printf("\n--->> ATTENTION! <<---\n");
@@ -916,10 +943,6 @@ int main(int argc,char *argv[])
info.force=1;
break;
- case 'C':
- format_params.intensity |= DASD_FMT_INT_COMPAT;
- break;
-
case 'd' :
if (strncmp(optarg,"cdl",3)==0)
{
@@ -1017,6 +1040,9 @@ int main(int argc,char *argv[])
case 'k' :
info.keep_volser=1;
break;
+ case 'C':
+ info.force_host = 1;
+ break;
case -1:
/* End of options string - start of devices list */
info.device_id = optind;
--- a/dasdfmt/dasdfmt.h
+++ b/dasdfmt/dasdfmt.h
@@ -214,7 +214,7 @@ typedef struct format_data_t {
if (*endptr) ERRMSG_EXIT(EXIT_MISUSE,"%s: " str " " \
"is in invalid format\n",prog_name);}
-#define dasdfmt_getopt_string "b:n:l:f:d:m:r:hpPLtyvVFk"
+#define dasdfmt_getopt_string "b:n:l:f:d:m:r:hpPLtyvVFkC"
static struct option dasdfmt_getopt_long_options[]=
{
@@ -233,6 +233,7 @@ static struct option dasdfmt_getopt_long
{ "help", 0, 0, 'h'},
{ "keep_volser", 0, 0, 'k'},
{ "norecordzero", 0, 0, 'z'},
+ { "check_host_count", 0, 0, 'C'},
{0, 0, 0, 0}
};
@@ -265,6 +266,7 @@ typedef struct dasdfmt_info {
int node_specified;
int device_id;
int keep_volser;
+ int force_host;
} dasdfmt_info_t;
--- a/fdasd/fdasd.8
+++ b/fdasd/fdasd.8
@@ -4,11 +4,11 @@ fdasd \- partitioning tool.
.SH SYNOPSIS
interactive mode:
.br
- \fBfdasd\fR [-s] [-r] \fIdevice\fR
+ \fBfdasd\fR [-s] [-r] [-C] \fIdevice\fR
.br
command line mode:
.br
- \fBfdasd\fR [-s] [-r] {-a[-k|-l \fIvolser\fR]|-i|-p|-c \fIconf_file\fR}
+ \fBfdasd\fR [-s] [-r] [-C] {-a[-k|-l \fIvolser\fR]|-i|-p|-c \fIconf_file\fR}
[-f \fI[type,blocksize]\fR] \fIdevice\fR
.br
help:
@@ -131,6 +131,11 @@ In combination with the -s option fdasd
partition table.
.TP
+\fB-C\fR or \fB--check_host_count\fR
+Force fdasd to check the host access open count to ensure the device
+is not online on another operating system instance
+
+.TP
\fB-f\fR \fI[type,blocksize]\fR or \fB--force\fR \fI[type,blocksize]\fR
Force fdasd to work on non DASD devices.
.br
--- a/fdasd/fdasd.c
+++ b/fdasd/fdasd.c
@@ -369,7 +369,10 @@ fdasd_usage (void)
" found in CONFIGFILE\n"
"-i, --volser Print volume serial\n"
"-p, --table Print partition table\n"
- "-f, --force Force fdasd to work on non DASD devices\n");
+ "-f, --force Force fdasd to work on non DASD devices\n"
+ "-C, --check_host_count Force fdasd to check the host access\n"
+ " open count to ensure the device is not\n"
+ " online on another operating system instance\n");
}
@@ -572,6 +575,9 @@ fdasd_parse_options (fdasd_anchor_t *anc
anc->force_virtual++;
fdasd_parse_force_options(anc, optarg);
break;
+ case 'C':
+ anc->force_host++;
+ break;
case -1:
/* End of options string - start of devices list */
break;
@@ -824,6 +830,7 @@ fdasd_verify_device (fdasd_anchor_t *anc
{
struct stat dst;
char err_str[ERROR_STRING_SIZE];
+ int count;
if ((stat(name, &dst)) < 0 ) {
snprintf(err_str, ERROR_STRING_SIZE,
@@ -856,6 +863,29 @@ fdasd_verify_device (fdasd_anchor_t *anc
fdasd_error(anc, device_verification_failed, err_str);
}
+ count = u2s_get_host_access_count(name);
+ if (anc->force_host) {
+ if (count > 1) {
+ snprintf(err_str, ERROR_STRING_SIZE,
+ "Disk %s is online on operating system instances in %d different LPARs.\n"
+ "Note: Your installation might include z/VM systems that are configured to\n"
+ "automatically vary on disks, regardless of whether they are subsequently used.\n",
+ name, count);
+ fdasd_error(anc, device_verification_failed, err_str);
+ } else if (count < 0) {
+ snprintf(err_str, ERROR_STRING_SIZE,
+ "Hosts access information not available for disk %s.\n",
+ name);
+ fdasd_error(anc, device_verification_failed, err_str);
+ }
+ } else if (count > 1)
+ printf("\nWARNING:\n"
+ "Disk %s is online on operating system instances in %d different LPARs.\n"
+ "Ensure that the disk is not being used by a system outside your LPAR.\n"
+ "Note: Your installation might include z/VM systems that are configured to\n"
+ "automatically vary on disks, regardless of whether they are subsequently used.\n\n",
+ name, count);
+
if (anc->verbose)
printf("Verification successful for '%s' (%d/%d)\n", name,
(unsigned short) major(dst.st_rdev),
--- a/fdasd/fdasd.h
+++ b/fdasd/fdasd.h
@@ -157,22 +157,23 @@ struct dasd_eckd_characteristics {
#define PARTITION_GPFS 5
static struct option fdasd_long_options[] = {
- { "version", no_argument, NULL, 'v'},
- { "auto", no_argument, NULL, 'a'},
- { "silent", no_argument, NULL, 's'},
- { "verbose", no_argument, NULL, 'r'},
- { "label", required_argument, NULL, 'l'},
- { "config", required_argument, NULL, 'c'},
- { "help", no_argument, NULL, 'h'},
- { "table", no_argument, NULL, 'p'},
- { "volser", no_argument, NULL, 'i'},
- { "keep_volser", no_argument, NULL, 'k'},
- { "force", optional_argument, NULL, 'f'},
- { 0, 0, 0, 0 }
+ { "version", no_argument, NULL, 'v'},
+ { "auto", no_argument, NULL, 'a'},
+ { "silent", no_argument, NULL, 's'},
+ { "verbose", no_argument, NULL, 'r'},
+ { "label", required_argument, NULL, 'l'},
+ { "config", required_argument, NULL, 'c'},
+ { "help", no_argument, NULL, 'h'},
+ { "table", no_argument, NULL, 'p'},
+ { "volser", no_argument, NULL, 'i'},
+ { "keep_volser", no_argument, NULL, 'k'},
+ { "force", optional_argument, NULL, 'f'},
+ { "check_host_count", no_argument, NULL, 'C'},
+ { 0, 0, 0, 0 }
};
/* Command line option abbreviations */
-static const char option_string[] = "vasrl:c:hpikf::";
+static const char option_string[] = "vasrl:c:hpikf::C";
struct fdasd_options {
char *device;
@@ -214,6 +215,7 @@ typedef struct fdasd_anchor {
int print_volser;
int keep_volser;
int force_virtual;
+ int force_host;
int big_disk;
int silent;
int verbose;
--- a/include/libzds.h
+++ b/include/libzds.h
@@ -803,6 +803,7 @@ int lzds_zdsroot_extract_datasets_from_d
void lzds_DS1RECFM_to_recfm(char DS1RECFM, char *buffer);
+int lzds_analyse_open_count(struct zdsroot *root, int warn);
/** @} */ /* end of group libzds_functions_helper */
--- a/include/u2s.h
+++ b/include/u2s.h
@@ -13,7 +13,8 @@
#define U2S_BUS_ID_SIZE 32
-int
-u2s_getbusid(char * devicenode, char * busid);
+int u2s_getbusid(char *, char *);
+int u2s_read_attribute(char *, char *, char *, size_t);
+int u2s_get_host_access_count(char *);
#endif /* U2S_H */
--- a/libu2s/u2s.c
+++ b/libu2s/u2s.c
@@ -17,6 +17,7 @@
#include <fcntl.h>
#include <sys/sysmacros.h>
#include <dirent.h>
+#include <stdlib.h>
#include "u2s.h"
@@ -282,3 +283,45 @@ int u2s_getbusid(char *devicenode, char
return rc;
}
+
+/*
+ * Attempts to find the sysfs entry for the given busid and reads
+ * the contents of a specified attribute to the buffer
+ */
+int u2s_read_attribute(char *busid, char *attribute, char *buffer,
+ size_t count)
+{
+ char path[100];
+ int rc, fd;
+ ssize_t rcount;
+
+ rc = 0;
+ snprintf(path, sizeof(path), "/sys/bus/ccw/devices/%s/%s",
+ busid, attribute);
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ return errno;
+ rcount = read(fd, buffer, count);
+ if (rcount < 0)
+ rc = errno;
+ close(fd);
+ return rc;
+}
+
+int u2s_get_host_access_count(char *devicenode)
+{
+ char busid[BUSIDSIZE];
+ unsigned long value;
+ char buffer[10];
+ char *endp;
+
+ u2s_getbusid(devicenode, busid);
+ u2s_read_attribute(busid, "host_access_count", buffer, sizeof(buffer));
+
+ value = strtoul(buffer, &endp, 0);
+
+ if (endp == buffer)
+ return -EINVAL;
+
+ return value;
+}
--- a/libzds/Makefile
+++ b/libzds/Makefile
@@ -8,7 +8,7 @@ CFLAGS += -D_FILE_OFFSET_BITS=64
all: libzds.a
-libzds.a: libzds.o $(rootdir)/libutil/util_list.o $(rootdir)/libvtoc/vtoc.o
+libzds.a: libzds.o $(rootdir)/libutil/util_list.o $(rootdir)/libvtoc/vtoc.o $(rootdir)/libu2s/u2s.o
libzds.o: ../include/libzds.h
--- a/libzds/libzds.c
+++ b/libzds/libzds.c
@@ -29,6 +29,7 @@
#include "libzds.h"
#include "util.h"
+#include "u2s.h"
#include <malloc.h>
#include <linux/types.h>
@@ -72,6 +73,8 @@ struct errorlog {
*/
#define ERRORMSG 240
+#define BUSIDSIZE 8
+
/**
* @brief An internal structure that represents an entry in the error log.
*/
@@ -3760,15 +3763,46 @@ void lzds_DS1RECFM_to_recfm(char DS1RECF
*/
}
+int lzds_analyse_open_count(struct zdsroot *root, int warn)
+{
+ struct dasd *dasd;
+ int value;
+ int rc = 0;
+ util_list_iterate(root->dasdlist, dasd) {
+ value = u2s_get_host_access_count(dasd->device);
+ if (value < 0) {
+ fprintf(stderr,
+ "Hosts access information not available for disk %s.\n",
+ dasd->device);
+ rc = value;
+ continue;
+ }
+ if (value == 1)
+ continue;
+ if (warn)
+ fprintf(stderr,
+ "\nWARNING:\n"
+ "Disk %s is online on operating system instances in %d different LPARs.\n"
+ "Ensure that the disk is not being used by a system outside your LPAR.\n"
+ "Note: Your installation might include z/VM systems that are configured to\n"
+ "automatically vary on disks, regardless of whether they are subsequently used.\n",
+ dasd->device, value);
+ else {
+ fprintf(stderr,
+ "\nERROR:\n"
+ "Disk %s is online on operating system instances in %d different LPARs.\n"
+ "Ensure that the disk is not being used by a system outside your LPAR.\n"
+ "Note: Your installation might include z/VM systems that are configured to\n"
+ "automatically vary on disks, regardless of whether they are subsequently used.\n",
+ dasd->device, value);
+ rc = -EACCES;
+ }
+ }
-
-
-
-
-
-
+ return rc;
+}
--- a/zconf/lsdasd
+++ b/zconf/lsdasd
@@ -30,6 +30,8 @@ function PrintUsage() {
Print old version of lsdasd output.
-l|--long
Print extended information about DASDs.
+ -H|--host-access-list
+ Print information about hosts accessing DASDs.
-v|--verbose
For compatibility/future use. Currently ignored.
--version
@@ -115,6 +117,33 @@ function listDASDDeviceDirectories() {
}
#------------------------------------------------------------------------------
+# find dasd directory in debugfs
+#------------------------------------------------------------------------------
+function findDASDDebugfsDirectorie() {
+ local mntentries
+
+ while read -a mntentries
+ do
+ if [[ "${mntentries[2]}" == "debugfs" ]]
+ then
+ DASD_DBF_DIR="${mntentries[1]}"
+ break;
+ fi
+ done < /etc/mtab
+ if [[ "$DASD_DBF_DIR" == "" ]]
+ then
+ echo "$CMD: No debugfs mount point found" >&2
+ exit 1
+ fi
+ DASD_DBF_DIR="$DASD_DBF_DIR/dasd"
+ if [[ ! -d "$DASD_DBF_DIR" ]]
+ then
+ echo "$CMD: Default DASD debugfs directory $DASD_DBF_DIR does not exist" >&2
+ exit 1
+ fi
+}
+
+#------------------------------------------------------------------------------
# gather device data and call appropriate output function
#------------------------------------------------------------------------------
function gatherDeviceData() {
@@ -197,6 +226,8 @@ function gatherDeviceData() {
extended
elif [[ "$PRINTUID" == "true" ]]; then
uid
+ elif [[ "$OUTPUT" == "host" ]]; then
+ host
else
newoutput
fi
@@ -527,6 +558,104 @@ function extended()
"${HPF_PATHS[@]}" ;
}
+function host()
+{
+findDASDDebugfsDirectorie
+
+if [[ ! -f "$DASD_DBF_DIR/$BUSID/host_access_list" ]]
+then
+ printf "\n%s: hosts access information not available\n" "$BUSID"
+ return
+fi
+
+local temp=`mktemp /tmp/lsdasd.XXXXXX`
+if test -w $temp ; then :; else
+ printf "\nCreating temporary file failed\n"
+ return
+fi
+
+cat $DASD_DBF_DIR/$BUSID/host_access_list > $temp 2> /dev/null
+ret=$?
+if [[ $ret -ne 0 ]]
+then
+ printf "%s: hosts access information not available\n" "$BUSID"
+ rm -f $temp
+ return $ret
+fi
+
+unset index
+unset array
+declare -a array
+
+index=(pgid status_flags sysplex_name supported_cylinder timestamp)
+
+for element in ${index[@]}
+do
+ count=0
+
+ declare -a $element
+ OLDIFS=$IFS
+ IFS=$'\n'
+ for value in `grep $element $temp`
+ do
+ (( ++count ))
+ value=$(echo -e $value | cut -d ' ' -f2)
+ eval $element[$count]=$value
+ done
+ IFS=$OLDIFS
+done
+
+printf "Host information for %s\n" "$BUSID";
+printf "Path-Group-ID LPAR CPU FL Status Sysplex Max_Cyls Time\n";
+printf "================================================================================\n";
+
+# mask bits for online and reserved state
+online_reserved_mask=0xE0
+
+# print name value lists
+for i in `seq 1 $count`;
+do
+ # get flags field
+ value=${status_flags[$i]}
+ # mark as hex value
+ value=0x$value
+ # mask online and reserved bits
+ value=$(($value & $online_reserved_mask))
+
+ case $value in
+ 0 ) # 0x00
+ STATE="OFF"
+ ;;
+ 32 ) # 0x20
+ STATE="OFF-RSV"
+ ;;
+ 64 ) # 0x40
+ STATE="ON"
+ ;;
+ 96 ) # 0x60
+ STATE="ON-RSV"
+ ;;
+ * )
+ STATE="-"
+ ;;
+ esac
+
+ printf "%22s %02s %07s %02s %-6s %-8s %11u %10lu\n" \
+ "${pgid[$i]}" \
+ "${pgid[$i]:4:2}" \
+ "${pgid[$i]:6:4}" \
+ "${status_flags[$i]}" \
+ "$STATE" \
+ "${sysplex_name[$i]}" \
+ "${supported_cylinder[$i]}" \
+ "${timestamp[$i]}" \
+ ;
+done
+printf "\n";
+
+rm -f $temp
+}
+
function uid()
{
#-------------------------------------------#
@@ -586,6 +715,9 @@ while [ $# -gt 0 ]; do
--long|-l)
OUTPUT="extended"
;;
+ --host-access-list|-H)
+ OUTPUT="host"
+ ;;
--version)
PrintVersion
exit 0
@@ -626,8 +758,13 @@ fi
# gather information on devices in list
PROCESSING=" $PROCESSING | gatherDeviceData "
+
# sort resulting list
-PROCESSING=" $PROCESSING | sort -t: -k1n -k2 | cut -d: -f3- "
+if [[ "$OUTPUT" == "host" ]]; then
+ PROCESSING=" $PROCESSING"
+else
+ PROCESSING=" $PROCESSING | sort -t: -k1n -k2 | cut -d: -f3- "
+fi
if [[ "$PRINTUID" == "true" ]] && [[ "$OUTPUT" != "old" ]]; then
printf "Bus-ID Name UID\n"
--- a/zconf/lsdasd.8
+++ b/zconf/lsdasd.8
@@ -40,11 +40,14 @@ Include only base devices.
Old output of lsdasd for compatibility.
.TP
.BR -l | --long
-Extended output of lsdasd including UID, attributes and path information.
+Extended output of lsdasd including UID and attributes.
.TP
.BR -u | --uid
Output includes and is sorted by UID.
.TP
+.BR -H | --host-acces
+Show information about all hosts using this device.
+.TP
.BR -v | --verbose
Only for compatibility (and maybe future) use. This option currently does
nothing.
--- a/zdsfs/zdsfs.1
+++ b/zdsfs/zdsfs.1
@@ -150,6 +150,10 @@ If \fI<s>\fR is set to 0, no seek histor
case `seek' is still supported, but a `seek' operation might result in a
read from the beginning of the data set.
+.TP
+\fB\-o\fR check_host_count
+Stop processing if the device is used by another operating system instance.
+
.SS "Applicable FUSE options (version 2.8):"
This is a selected subset of all FUSE options. Use the zdsfs
\fB\--help\fR option to print a full list.
--- a/zdsfs/zdsfs.c
+++ b/zdsfs/zdsfs.c
@@ -39,6 +39,7 @@ struct zdsfs_info {
int devcount;
int allow_inclomplete_multi_volume;
int keepRDW;
+ int host_count;
unsigned int tracks_per_frame;
unsigned long long seek_buffer_size;
struct zdsroot *zdsroot;
@@ -765,6 +766,7 @@ static const struct fuse_opt zdsfs_opts[
FUSE_OPT_KEY("seekbuffer=", KEY_SEEKBUFFER),
ZDSFS_OPT("rdw", keepRDW, 1),
ZDSFS_OPT("ignore_incomplete", allow_inclomplete_multi_volume, 1),
+ ZDSFS_OPT("check_host_count", host_count, 1),
FUSE_OPT_END
};
@@ -790,7 +792,10 @@ static void usage(const char *progname)
" data set are missing\n"
" -o tracks=N Size of the track buffer in tracks (default 128)\n"
" -o seekbuffer=S Upper limit in bytes for the seek history buffer\n"
-" size (default 1048576)\n", progname);
+" size (default 1048576)\n"
+" -o check_host_count Stop processing if the device is used by another\n"
+" operating system instance\n"
+ , progname);
}
static void zdsfs_process_device(const char *device)
@@ -1014,6 +1019,17 @@ int main(int argc, char *argv[])
argv[0]);
exit(1);
}
+
+ if (zdsfsinfo.host_count) {
+ /* check, print error and exit if multiple online */
+ rc = lzds_analyse_open_count(zdsfsinfo.zdsroot, 0);
+ if (rc == -EACCES)
+ goto cleanup;
+ } else {
+ /* check, print warning if multiple online */
+ lzds_analyse_open_count(zdsfsinfo.zdsroot, 1);
+ }
+
rc = zdsfs_verify_datasets();
if (rc)
goto cleanup;