Skip to content

Commit 413862c

Browse files
Stefan Haberlandaxboe
authored andcommitted
s390/dasd: add copy pair swap capability
In case of errors or misbehaviour of the primary device a controlled failover to one of the configured secondary devices needs to be performed. The swap processing stops I/O on the primary device, all requests are re-queued to the blocklayer queue, the entries in the copy relation are swapped and finally the link to the blockdevice is moved from primary to secondary dasd device. After this, the secondary becomes the new primary device and I/O is restarted on that device. Signed-off-by: Stefan Haberland <[email protected]> Reviewed-by: Jan Hoeppner <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent a91ff09 commit 413862c

File tree

4 files changed

+117
-1
lines changed

4 files changed

+117
-1
lines changed

‎drivers/s390/block/dasd.c‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3927,7 +3927,7 @@ EXPORT_SYMBOL_GPL(dasd_generic_space_avail);
39273927
/*
39283928
* clear active requests and requeue them to block layer if possible
39293929
*/
3930-
static int dasd_generic_requeue_all_requests(struct dasd_device *device)
3930+
int dasd_generic_requeue_all_requests(struct dasd_device *device)
39313931
{
39323932
struct list_head requeue_queue;
39333933
struct dasd_ccw_req *cqr, *n;
@@ -4001,6 +4001,7 @@ static int dasd_generic_requeue_all_requests(struct dasd_device *device)
40014001
dasd_schedule_device_bh(device);
40024002
return rc;
40034003
}
4004+
EXPORT_SYMBOL_GPL(dasd_generic_requeue_all_requests);
40044005

40054006
static void do_requeue_requests(struct work_struct *work)
40064007
{

‎drivers/s390/block/dasd_devmap.c‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -937,6 +937,7 @@ void dasd_add_link_to_gendisk(struct gendisk *gdp, struct dasd_device *device)
937937
gdp->private_data = devmap;
938938
spin_unlock(&dasd_devmap_lock);
939939
}
940+
EXPORT_SYMBOL(dasd_add_link_to_gendisk);
940941

941942
struct dasd_device *dasd_device_from_gendisk(struct gendisk *gdp)
942943
{

‎drivers/s390/block/dasd_eckd.c‎

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6119,6 +6119,99 @@ static int dasd_hosts_print(struct dasd_device *device, struct seq_file *m)
61196119
return 0;
61206120
}
61216121

6122+
static struct dasd_device
6123+
*copy_relation_find_device(struct dasd_copy_relation *copy,
6124+
char *busid)
6125+
{
6126+
int i;
6127+
6128+
for (i = 0; i < DASD_CP_ENTRIES; i++) {
6129+
if (copy->entry[i].configured &&
6130+
strncmp(copy->entry[i].busid, busid, DASD_BUS_ID_SIZE) == 0)
6131+
return copy->entry[i].device;
6132+
}
6133+
return NULL;
6134+
}
6135+
6136+
/*
6137+
* set the new active/primary device
6138+
*/
6139+
static void copy_pair_set_active(struct dasd_copy_relation *copy, char *new_busid,
6140+
char *old_busid)
6141+
{
6142+
int i;
6143+
6144+
for (i = 0; i < DASD_CP_ENTRIES; i++) {
6145+
if (copy->entry[i].configured &&
6146+
strncmp(copy->entry[i].busid, new_busid,
6147+
DASD_BUS_ID_SIZE) == 0) {
6148+
copy->active = &copy->entry[i];
6149+
copy->entry[i].primary = true;
6150+
} else if (copy->entry[i].configured &&
6151+
strncmp(copy->entry[i].busid, old_busid,
6152+
DASD_BUS_ID_SIZE) == 0) {
6153+
copy->entry[i].primary = false;
6154+
}
6155+
}
6156+
}
6157+
6158+
/*
6159+
* The function will swap the role of a given copy pair.
6160+
* During the swap operation the relation of the blockdevice is disconnected
6161+
* from the old primary and connected to the new.
6162+
*
6163+
* IO is paused on the block queue before swap and may be resumed afterwards.
6164+
*/
6165+
static int dasd_eckd_copy_pair_swap(struct dasd_device *device, char *prim_busid,
6166+
char *sec_busid)
6167+
{
6168+
struct dasd_device *primary, *secondary;
6169+
struct dasd_copy_relation *copy;
6170+
struct dasd_block *block;
6171+
struct gendisk *gdp;
6172+
6173+
copy = device->copy;
6174+
if (!copy)
6175+
return DASD_COPYPAIRSWAP_INVALID;
6176+
primary = copy->active->device;
6177+
if (!primary)
6178+
return DASD_COPYPAIRSWAP_INVALID;
6179+
/* double check if swap has correct primary */
6180+
if (strncmp(dev_name(&primary->cdev->dev), prim_busid, DASD_BUS_ID_SIZE) != 0)
6181+
return DASD_COPYPAIRSWAP_PRIMARY;
6182+
6183+
secondary = copy_relation_find_device(copy, sec_busid);
6184+
if (!secondary)
6185+
return DASD_COPYPAIRSWAP_SECONDARY;
6186+
6187+
/*
6188+
* usually the device should be quiesced for swap
6189+
* for paranoia stop device and requeue requests again
6190+
*/
6191+
dasd_device_set_stop_bits(primary, DASD_STOPPED_PPRC);
6192+
dasd_device_set_stop_bits(secondary, DASD_STOPPED_PPRC);
6193+
dasd_generic_requeue_all_requests(primary);
6194+
6195+
/* swap DASD internal device <> block assignment */
6196+
block = primary->block;
6197+
primary->block = NULL;
6198+
secondary->block = block;
6199+
block->base = secondary;
6200+
/* set new primary device in COPY relation */
6201+
copy_pair_set_active(copy, sec_busid, prim_busid);
6202+
6203+
/* swap blocklayer device link */
6204+
gdp = block->gdp;
6205+
dasd_add_link_to_gendisk(gdp, secondary);
6206+
6207+
/* re-enable device */
6208+
dasd_device_remove_stop_bits(primary, DASD_STOPPED_PPRC);
6209+
dasd_device_remove_stop_bits(secondary, DASD_STOPPED_PPRC);
6210+
dasd_schedule_device_bh(secondary);
6211+
6212+
return DASD_COPYPAIRSWAP_SUCCESS;
6213+
}
6214+
61226215
/*
61236216
* Perform Subsystem Function - Peer-to-Peer Remote Copy Extended Query
61246217
*/
@@ -6805,6 +6898,7 @@ static struct dasd_discipline dasd_eckd_discipline = {
68056898
.ese_read = dasd_eckd_ese_read,
68066899
.pprc_status = dasd_eckd_query_pprc_status,
68076900
.pprc_enabled = dasd_eckd_pprc_enabled,
6901+
.copy_pair_swap = dasd_eckd_copy_pair_swap,
68086902
};
68096903

68106904
static int __init

‎drivers/s390/block/dasd_int.h‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,7 @@ struct dasd_discipline {
438438
int (*ese_read)(struct dasd_ccw_req *, struct irb *);
439439
int (*pprc_status)(struct dasd_device *, struct dasd_pprc_data_sc4 *);
440440
bool (*pprc_enabled)(struct dasd_device *);
441+
int (*copy_pair_swap)(struct dasd_device *, char *, char *);
441442
};
442443

443444
extern struct dasd_discipline *dasd_diag_discipline_pointer;
@@ -681,6 +682,7 @@ struct dasd_queue {
681682
#define DASD_STOPPED_PENDING 4 /* long busy */
682683
#define DASD_STOPPED_DC_WAIT 8 /* disconnected, wait */
683684
#define DASD_STOPPED_SU 16 /* summary unit check handling */
685+
#define DASD_STOPPED_PPRC 32 /* PPRC swap */
684686
#define DASD_STOPPED_NOSPC 128 /* no space left */
685687

686688
/* per device flags */
@@ -705,6 +707,22 @@ struct dasd_queue {
705707

706708
void dasd_put_device_wake(struct dasd_device *);
707709

710+
/*
711+
* return values to be returned from the copy pair swap function
712+
* 0x00: swap successful
713+
* 0x01: swap data invalid
714+
* 0x02: no active device found
715+
* 0x03: wrong primary specified
716+
* 0x04: secondary device not found
717+
* 0x05: swap already running
718+
*/
719+
#define DASD_COPYPAIRSWAP_SUCCESS 0
720+
#define DASD_COPYPAIRSWAP_INVALID 1
721+
#define DASD_COPYPAIRSWAP_NOACTIVE 2
722+
#define DASD_COPYPAIRSWAP_PRIMARY 3
723+
#define DASD_COPYPAIRSWAP_SECONDARY 4
724+
#define DASD_COPYPAIRSWAP_MULTIPLE 5
725+
708726
/*
709727
* Reference count inliners
710728
*/
@@ -889,6 +907,8 @@ int dasd_generic_verify_path(struct dasd_device *, __u8);
889907
void dasd_generic_space_exhaust(struct dasd_device *, struct dasd_ccw_req *);
890908
void dasd_generic_space_avail(struct dasd_device *);
891909

910+
int dasd_generic_requeue_all_requests(struct dasd_device *);
911+
892912
int dasd_generic_read_dev_chars(struct dasd_device *, int, void *, int);
893913
char *dasd_get_sense(struct irb *);
894914

0 commit comments

Comments
 (0)