tunedasd: add copy_pair swap capability

Add an option to tunedasd to trigger a copy pair swap using the appropriate
ioctl for DASD devices.

      -s, --copy-pair-swap COPY_PAIR

This command requires a comma separated pair of primary,secondary to be
specified. In case of success the old secondary will become the new primary
device and the old primary will become a secondary device.

Example:

tunedasd /dev/dasda -s 0.0.9700,0.0.9740

This will set the old secondary device 0.0.9740 as the new primary.
The old primary device 0.0.9700 will automatically become a secondary
device.

Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
Stefan Haberland
2022-11-11 13:17:32 +01:00
committed by Jan Höppner
parent 3aa7f6e298
commit 3f12bdf4c7
6 changed files with 138 additions and 26 deletions

View File

@@ -20,8 +20,8 @@
#include <stdio.h>
#include <sys/ioctl.h>
/* A bus id of a DASD is 8 characters long. E.g. 0.0.4711 */
#define DASD_BUS_ID_SIZE 9
/* the definition of a BUSID in the DASD driver is 20 */
#define DASD_BUS_ID_SIZE 20
typedef struct dasd_information2_t {
unsigned int devno; /* S/390 devno */
@@ -242,6 +242,13 @@ struct dasd_snid_ioctl_data {
__u8 path_mask;
} __attribute__((packed));
struct dasd_copypair_swap_data {
char primary[DASD_BUS_ID_SIZE]; /* BUSID of primary */
char secondary[DASD_BUS_ID_SIZE]; /* BUSID of secondary */
/* Reserved for future updates. */
char reserved[64];
};
#ifndef __linux__
/* definition from hdreg.h */
struct hd_geometry {
@@ -278,6 +285,8 @@ struct hd_geometry {
#define BIODASDSATTR _IOW(DASD_IOCTL_LETTER, 2, attrib_data_t)
/* Release Allocated Space */
#define BIODASDRAS _IOW(DASD_IOCTL_LETTER, 3, format_data_t)
/* Swap copy pair */
#define BIODASDPPRCSWAP _IOW(DASD_IOCTL_LETTER, 4, struct dasd_copypair_swap_data)
/* Get Sense Path Group ID (SNID) data */
#define BIODASDSNID _IOWR(DASD_IOCTL_LETTER, 1, struct dasd_snid_ioctl_data)
/* Check device format according to format_data_t */
@@ -318,5 +327,6 @@ int dasd_set_cache(const char *device, attrib_data_t *attrib_data);
int dasd_query_reserve(const char *device);
int dasd_profile(const char *device, dasd_profile_info_t *dasd_profile_info);
int dasd_reset_profile(const char *device);
int dasd_copy_swap(const char *device, struct dasd_copypair_swap_data *data);
#endif /* LIB_DASD_BASE_H */

View File

@@ -452,3 +452,31 @@ int dasd_reset_profile(const char *device)
return 0;
}
/*
* Initiate the swap of a copy pairs primary,secondary relation.
* The old secondary will become the new primary and vice versa.
*
* @param[in] device node device node's name
* @param[in] copy_pair data pointer to dasd copypair data with:
* 'primary' old primary, becoming secondary
* 'secondary' old secondary, becoming primary.
*
* @retval errno in case of failure
* @retval 0 in case of success
* @retval 1 swap data invalid
* @retval 2 no active device found
* @retval 3 wrong primary specified
* @retval 4 secondary device not found
* @retval 5 swap already running
*/
int dasd_copy_swap(const char *device, struct dasd_copypair_swap_data *data)
{
int fd;
fd = dasd_open_device(device, O_RDONLY);
RUN_IOCTL(fd, BIODASDPPRCSWAP, data);
dasd_close_device(fd);
return 0;
}

View File

@@ -31,6 +31,7 @@ int disk_query_reserve_status(char* device);
int disk_profile (char* device, char* prof_item);
int disk_reset_prof(char *device);
int disk_reset_chpid(char *device, char *chpid);
int disk_copy_swap(char *device, char *copy_pair);
#endif /* not DISK_H */

View File

@@ -174,6 +174,14 @@ Reset all channel paths of the selected device. The channel paths
might be suspended due to high IFCC error rates or a High Performance
FICON failure. Use this option to resume considering all defined
channel paths for I/O.
.TP
.BR "\-s" " or " "\-\-copy\-pair\-swap <copy_pair>"
Swap the copy roles of the specified copy pair. The <copy_pair> has to
be a comma separated pair of \fBPRIMARY,SECONDARY\fR where
\fBPRIMARY\fR is the old primary device that will become a secondary
automatically. The old \fBSECONDARY\fR device will become the new
primary device. Both devices have to be online for this operation to
succeed.
.\"
.\".TP
.\".BR "\-o" " or " "\-\-online"
@@ -197,6 +205,12 @@ channel paths for I/O.
.br
tunedasd -p 45 /dev/dasdc
.br
4. Scenario: Swap copy pair 0.0.9700 and 0.0.9740
.br
tunedasd -s 0.0.9700,0.0.9740 /dev/dasdc
.br
.SH "SEE ALSO"
.BR dasdview (8),

View File

@@ -21,12 +21,11 @@
#include "lib/dasd_base.h"
#include "lib/dasd_sys.h"
#include "lib/util_libc.h"
#include "disk.h"
#include "tunedasd.h"
#define BUS_ID_SIZE 30
/* id definition for profile items */
enum prof_id {
prof_reqs = 0,
@@ -549,3 +548,50 @@ int disk_reset_chpid(char *device, char *chpid)
return -1;
}
int disk_copy_swap(char *device, char *copy_pair)
{
struct dasd_copypair_swap_data data = { 0 };
char *primary, *secondary;
int rc = 0;
primary = strtok(copy_pair, ",");
secondary = strtok(NULL, ",");
if (!primary || !secondary) {
error_print("%s: Error parsing Copy Pair %s", device, copy_pair);
return -1;
}
util_strlcpy(data.primary, primary, DASD_BUS_ID_SIZE);
util_strlcpy(data.secondary, secondary, DASD_BUS_ID_SIZE);
printf("Swapping copy pair %s %s on device <%s>...\n", primary, secondary, device);
rc = dasd_copy_swap(device, &data);
switch (rc) {
case 0:
printf("Done.\n");
return 0;
case 1:
error_print("Swap data invalid");
break;
case 2:
error_print("No active device found");
break;
case 3:
error_print("Wrong primary device specified");
break;
case 4:
error_print("Secondary device not found");
break;
case 5:
error_print("Swap already running");
break;
default:
error_print("Swap not successful rc %d", rc);
break;
}
return -1;
}

View File

@@ -119,12 +119,17 @@ static struct util_opt opt_vec[] = {
.desc = "Reset all channel paths of a device",
.flags = UTIL_OPT_FLAG_NOSHORT,
},
{
.option = { "copy-pair-swap", required_argument, NULL, 's' },
.argument = "COPY_PAIR",
.desc = "Swap a specified, comma separated copy pair.",
},
UTIL_OPT_HELP,
UTIL_OPT_VERSION,
UTIL_OPT_END
};
#define CMD_KEYWORD_NUM 16
#define CMD_KEYWORD_NUM 17
#define DEVICES_NUM 256
enum cmd_keyword_id {
@@ -144,6 +149,7 @@ enum cmd_keyword_id {
cmd_keyword_path_all,
cmd_keyword_enable_stats,
cmd_keyword_disable_stats,
cmd_keyword_copy_swap,
};
@@ -167,7 +173,8 @@ static const struct {
{ "path_reset", cmd_keyword_path },
{ "path_reset_all", cmd_keyword_path_all },
{ "enable-stats", cmd_keyword_enable_stats },
{ "disable-stats", cmd_keyword_disable_stats }
{ "disable-stats", cmd_keyword_disable_stats },
{ "copy-swap", cmd_keyword_copy_swap },
};
@@ -180,26 +187,27 @@ enum cmd_key_state {
/* Determines which combination of keywords are valid */
static enum cmd_key_state cmd_key_table[CMD_KEYWORD_NUM][CMD_KEYWORD_NUM] = {
/* help vers get_ cach no_c rese rele sloc prof prof rese quer path path
* ion cach e yl rve ase k ile _ite t_pr y_re _all
* e m of serv
/* help vers get_ cach no_c rese rele sloc prof prof rese quer path path enab disa copy
* ion cach e yl rve ase k ile _ite t_pr y_re _all le-s ble- -swa
* e m of serv tats stat p
*/
/* help */ { req, opt, opt, opt, opt, opt, opt, opt, opt, opt, opt, inv, inv, inv, inv, inv },
/* version */ { inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
/* get_cache */ { opt, opt, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
/* cache */ { opt, opt, inv, req, opt, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
/* no_cyl */ { opt, opt, inv, req, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
/* reserve */ { opt, opt, inv, inv, inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
/* release */ { opt, opt, inv, inv, inv, inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv },
/* slock */ { opt, opt, inv, inv, inv, inv, inv, req, inv, inv, inv, inv, inv, inv, inv, inv },
/* profile */ { opt, opt, inv, inv, inv, inv, inv, inv, req, opt, inv, inv, inv, inv, inv, inv },
/* prof_item */ { opt, opt, inv, inv, inv, inv, inv, inv, req, req, inv, inv, inv, inv, inv, inv },
/* reset_prof */ { opt, opt, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv, inv, inv },
/* query_reserve */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv, inv },
/* path */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv },
/* path_all */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv },
/* enable-stats */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv },
/* disable-stats */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req },
/* help */ { req, opt, opt, opt, opt, opt, opt, opt, opt, opt, opt, inv, inv, inv, inv, inv, inv },
/* version */ { inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
/* get_cache */ { opt, opt, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
/* cache */ { opt, opt, inv, req, opt, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
/* no_cyl */ { opt, opt, inv, req, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
/* reserve */ { opt, opt, inv, inv, inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
/* release */ { opt, opt, inv, inv, inv, inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
/* slock */ { opt, opt, inv, inv, inv, inv, inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv },
/* profile */ { opt, opt, inv, inv, inv, inv, inv, inv, req, opt, inv, inv, inv, inv, inv, inv, inv },
/* prof_item */ { opt, opt, inv, inv, inv, inv, inv, inv, req, req, inv, inv, inv, inv, inv, inv, inv },
/* reset_prof */ { opt, opt, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv, inv, inv, inv },
/* query_reserve */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv, inv, inv },
/* path */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv, inv },
/* path_all */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv },
/* enable-stats */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv },
/* disable-stats */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv },
/* copy-swap */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req },
};
struct parameter {
@@ -439,7 +447,9 @@ static int get_command_line(int argc, char *argv[], struct command_line *line)
rc = store_option (&cmdline, cmd_keyword_query_reserve,
optarg);
break;
case 's':
rc = store_option(&cmdline, cmd_keyword_copy_swap, optarg);
break;
case -1:
/* End of options string - start of devices list */
cmdline.device_id = optind;
@@ -508,6 +518,9 @@ static int do_command(char *device, struct command_line cmdline)
case cmd_keyword_path_all:
rc = disk_reset_chpid(device, NULL);
break;
case cmd_keyword_copy_swap:
rc = disk_copy_swap(device, cmdline.parm[cmd_keyword_copy_swap].data);
break;
default:
error_print ("Unknown command '%s' specified",
get_keyword_name (i));