diff options
author | Hannes Reinecke <hare@suse.de> | 2013-01-30 09:26:19 (GMT) |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2013-07-01 15:31:26 (GMT) |
commit | 5ea34a01423a27d4526f3551e8542f2f991bd4a0 (patch) | |
tree | badb135a40e6070c2a4d474e6a240457cb18b484 /drivers/s390 | |
parent | 3d71ad32167c9124d5621b54c37a74ef38aa93b0 (diff) | |
download | linux-5ea34a01423a27d4526f3551e8542f2f991bd4a0.tar.xz |
s390/dasd: Fail all requests when DASD_FLAG_ABORTIO is set
Whenever a DASD request encounters a timeout we might
need to abort all outstanding requests on this or
even other devices.
This is especially useful if one wants to fail all
devices on one side of a RAID10 configuration, even
though only one device exhibited an error.
To handle this I've introduced a new device flag
DASD_FLAG_ABORTIO.
This flag is evaluated in __dasd_process_request_queue()
and will invoke blk_abort_request() for all
outstanding requests with DASD_CQR_FLAGS_FAILFAST set.
This will cause any of these requests to be aborted
immediately if the blk_timeout function is activated.
The DASD_FLAG_ABORTIO is also evaluated in
__dasd_process_request_queue to abort all
new request which would have the
DASD_CQR_FLAGS_FAILFAST bit set.
The flag can be set with the new ioctls 'BIODASDABORTIO'
and removed with 'BIODASDALLOWIO'.
Signed-off-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Stefan Weinhuber <wein@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/block/dasd.c | 13 | ||||
-rw-r--r-- | drivers/s390/block/dasd_int.h | 3 | ||||
-rw-r--r-- | drivers/s390/block/dasd_ioctl.c | 59 |
3 files changed, 72 insertions, 3 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 54f4bb8..17150a7 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -38,9 +38,6 @@ */ #define DASD_CHANQ_MAX_SIZE 4 -#define DASD_SLEEPON_START_TAG (void *) 1 -#define DASD_SLEEPON_END_TAG (void *) 2 - /* * SECTION: exported variables of dasd.c */ @@ -2535,6 +2532,16 @@ static void __dasd_process_request_queue(struct dasd_block *block) __blk_end_request_all(req, -EIO); continue; } + if (test_bit(DASD_FLAG_ABORTALL, &basedev->flags) && + (basedev->features & DASD_FEATURE_FAILFAST || + blk_noretry_request(req))) { + DBF_DEV_EVENT(DBF_ERR, basedev, + "Rejecting failfast request %p", + req); + blk_start_request(req); + __blk_end_request_all(req, -ETIMEDOUT); + continue; + } cqr = basedev->discipline->build_cp(basedev, block, req); if (IS_ERR(cqr)) { if (PTR_ERR(cqr) == -EBUSY) diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 2bd03f4..690001a 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -524,7 +524,10 @@ struct dasd_block { #define DASD_FLAG_SUSPENDED 9 /* The device was suspended */ #define DASD_FLAG_SAFE_OFFLINE 10 /* safe offline processing requested*/ #define DASD_FLAG_SAFE_OFFLINE_RUNNING 11 /* safe offline running */ +#define DASD_FLAG_ABORTALL 12 /* Abort all noretry requests */ +#define DASD_SLEEPON_START_TAG ((void *) 1) +#define DASD_SLEEPON_END_TAG ((void *) 2) void dasd_put_device_wake(struct dasd_device *); diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index 8be1b51..25a0f2f 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c @@ -141,6 +141,59 @@ static int dasd_ioctl_resume(struct dasd_block *block) } /* + * Abort all failfast I/O on a device. + */ +static int dasd_ioctl_abortio(struct dasd_block *block) +{ + unsigned long flags; + struct dasd_device *base; + struct dasd_ccw_req *cqr, *n; + + base = block->base; + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (test_and_set_bit(DASD_FLAG_ABORTALL, &base->flags)) + return 0; + DBF_DEV_EVENT(DBF_NOTICE, base, "%s", "abortall flag set"); + + spin_lock_irqsave(&block->request_queue_lock, flags); + spin_lock(&block->queue_lock); + list_for_each_entry_safe(cqr, n, &block->ccw_queue, blocklist) { + if (test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) && + cqr->callback_data && + cqr->callback_data != DASD_SLEEPON_START_TAG && + cqr->callback_data != DASD_SLEEPON_END_TAG) { + spin_unlock(&block->queue_lock); + blk_abort_request(cqr->callback_data); + spin_lock(&block->queue_lock); + } + } + spin_unlock(&block->queue_lock); + spin_unlock_irqrestore(&block->request_queue_lock, flags); + + dasd_schedule_block_bh(block); + return 0; +} + +/* + * Allow I/O on a device + */ +static int dasd_ioctl_allowio(struct dasd_block *block) +{ + struct dasd_device *base; + + base = block->base; + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (test_and_clear_bit(DASD_FLAG_ABORTALL, &base->flags)) + DBF_DEV_EVENT(DBF_NOTICE, base, "%s", "abortall flag unset"); + + return 0; +} + +/* * performs formatting of _device_ according to _fdata_ * Note: The discipline's format_function is assumed to deliver formatting * commands to format multiple units of the device. In terms of the ECKD @@ -458,6 +511,12 @@ int dasd_ioctl(struct block_device *bdev, fmode_t mode, case BIODASDRESUME: rc = dasd_ioctl_resume(block); break; + case BIODASDABORTIO: + rc = dasd_ioctl_abortio(block); + break; + case BIODASDALLOWIO: + rc = dasd_ioctl_allowio(block); + break; case BIODASDFMT: rc = dasd_ioctl_format(bdev, argp); break; |