aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/block
diff options
context:
space:
mode:
authorStefan Haberland <stefan.haberland@de.ibm.com>2012-11-28 07:43:38 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2012-11-30 09:40:44 -0500
commitd07dc5d8ab6f15353c866e2768c389abdc1faba6 (patch)
tree9ecf558a0e3d128534b56200b0f411aab315fc0f /drivers/s390/block
parent55d3a85cd2fa3274a6dfa0901a3be342b433bfa0 (diff)
s390/dasd: add safe offline interface
The regular behavior of the DASD device driver when setting a device offline is to return all outstanding I/O as failed. This behavior is different from that of other System z operating systems and may lead to unexpected data loss. Adding an explicit 'safe' offline function will allow customers to use DASDs in the way they expect them to work. Signed-off-by: Stefan Haberland <stefan.haberland@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/block')
-rw-r--r--drivers/s390/block/dasd.c97
-rw-r--r--drivers/s390/block/dasd_devmap.c34
-rw-r--r--drivers/s390/block/dasd_int.h2
3 files changed, 116 insertions, 17 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 0595c763dafd..29225e1c159c 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -349,6 +349,16 @@ static int dasd_state_basic_to_ready(struct dasd_device *device)
349 return rc; 349 return rc;
350} 350}
351 351
352static inline
353int _wait_for_empty_queues(struct dasd_device *device)
354{
355 if (device->block)
356 return list_empty(&device->ccw_queue) &&
357 list_empty(&device->block->ccw_queue);
358 else
359 return list_empty(&device->ccw_queue);
360}
361
352/* 362/*
353 * Remove device from block device layer. Destroy dirty buffers. 363 * Remove device from block device layer. Destroy dirty buffers.
354 * Forget format information. Check if the target level is basic 364 * Forget format information. Check if the target level is basic
@@ -1841,6 +1851,13 @@ static void __dasd_device_check_expire(struct dasd_device *device)
1841 cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist); 1851 cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist);
1842 if ((cqr->status == DASD_CQR_IN_IO && cqr->expires != 0) && 1852 if ((cqr->status == DASD_CQR_IN_IO && cqr->expires != 0) &&
1843 (time_after_eq(jiffies, cqr->expires + cqr->starttime))) { 1853 (time_after_eq(jiffies, cqr->expires + cqr->starttime))) {
1854 if (test_bit(DASD_FLAG_SAFE_OFFLINE_RUNNING, &device->flags)) {
1855 /*
1856 * IO in safe offline processing should not
1857 * run out of retries
1858 */
1859 cqr->retries++;
1860 }
1844 if (device->discipline->term_IO(cqr) != 0) { 1861 if (device->discipline->term_IO(cqr) != 0) {
1845 /* Hmpf, try again in 5 sec */ 1862 /* Hmpf, try again in 5 sec */
1846 dev_err(&device->cdev->dev, 1863 dev_err(&device->cdev->dev,
@@ -3024,11 +3041,11 @@ void dasd_generic_remove(struct ccw_device *cdev)
3024 3041
3025 cdev->handler = NULL; 3042 cdev->handler = NULL;
3026 3043
3027 dasd_remove_sysfs_files(cdev);
3028 device = dasd_device_from_cdev(cdev); 3044 device = dasd_device_from_cdev(cdev);
3029 if (IS_ERR(device)) 3045 if (IS_ERR(device))
3030 return; 3046 return;
3031 if (test_and_set_bit(DASD_FLAG_OFFLINE, &device->flags)) { 3047 if (test_and_set_bit(DASD_FLAG_OFFLINE, &device->flags) &&
3048 !test_bit(DASD_FLAG_SAFE_OFFLINE_RUNNING, &device->flags)) {
3032 /* Already doing offline processing */ 3049 /* Already doing offline processing */
3033 dasd_put_device(device); 3050 dasd_put_device(device);
3034 return; 3051 return;
@@ -3048,6 +3065,8 @@ void dasd_generic_remove(struct ccw_device *cdev)
3048 */ 3065 */
3049 if (block) 3066 if (block)
3050 dasd_free_block(block); 3067 dasd_free_block(block);
3068
3069 dasd_remove_sysfs_files(cdev);
3051} 3070}
3052 3071
3053/* 3072/*
@@ -3126,16 +3145,13 @@ int dasd_generic_set_offline(struct ccw_device *cdev)
3126{ 3145{
3127 struct dasd_device *device; 3146 struct dasd_device *device;
3128 struct dasd_block *block; 3147 struct dasd_block *block;
3129 int max_count, open_count; 3148 int max_count, open_count, rc;
3130 3149
3150 rc = 0;
3131 device = dasd_device_from_cdev(cdev); 3151 device = dasd_device_from_cdev(cdev);
3132 if (IS_ERR(device)) 3152 if (IS_ERR(device))
3133 return PTR_ERR(device); 3153 return PTR_ERR(device);
3134 if (test_and_set_bit(DASD_FLAG_OFFLINE, &device->flags)) { 3154
3135 /* Already doing offline processing */
3136 dasd_put_device(device);
3137 return 0;
3138 }
3139 /* 3155 /*
3140 * We must make sure that this device is currently not in use. 3156 * We must make sure that this device is currently not in use.
3141 * The open_count is increased for every opener, that includes 3157 * The open_count is increased for every opener, that includes
@@ -3159,6 +3175,54 @@ int dasd_generic_set_offline(struct ccw_device *cdev)
3159 return -EBUSY; 3175 return -EBUSY;
3160 } 3176 }
3161 } 3177 }
3178
3179 if (test_bit(DASD_FLAG_SAFE_OFFLINE_RUNNING, &device->flags)) {
3180 /*
3181 * safe offline allready running
3182 * could only be called by normal offline so safe_offline flag
3183 * needs to be removed to run normal offline and kill all I/O
3184 */
3185 if (test_and_set_bit(DASD_FLAG_OFFLINE, &device->flags)) {
3186 /* Already doing normal offline processing */
3187 dasd_put_device(device);
3188 return -EBUSY;
3189 } else
3190 clear_bit(DASD_FLAG_SAFE_OFFLINE, &device->flags);
3191
3192 } else
3193 if (test_bit(DASD_FLAG_OFFLINE, &device->flags)) {
3194 /* Already doing offline processing */
3195 dasd_put_device(device);
3196 return -EBUSY;
3197 }
3198
3199 /*
3200 * if safe_offline called set safe_offline_running flag and
3201 * clear safe_offline so that a call to normal offline
3202 * can overrun safe_offline processing
3203 */
3204 if (test_and_clear_bit(DASD_FLAG_SAFE_OFFLINE, &device->flags) &&
3205 !test_and_set_bit(DASD_FLAG_SAFE_OFFLINE_RUNNING, &device->flags)) {
3206 /*
3207 * If we want to set the device safe offline all IO operations
3208 * should be finished before continuing the offline process
3209 * so sync bdev first and then wait for our queues to become
3210 * empty
3211 */
3212 /* sync blockdev and partitions */
3213 rc = fsync_bdev(device->block->bdev);
3214 if (rc != 0)
3215 goto interrupted;
3216
3217 /* schedule device tasklet and wait for completion */
3218 dasd_schedule_device_bh(device);
3219 rc = wait_event_interruptible(shutdown_waitq,
3220 _wait_for_empty_queues(device));
3221 if (rc != 0)
3222 goto interrupted;
3223 }
3224
3225 set_bit(DASD_FLAG_OFFLINE, &device->flags);
3162 dasd_set_target_state(device, DASD_STATE_NEW); 3226 dasd_set_target_state(device, DASD_STATE_NEW);
3163 /* dasd_delete_device destroys the device reference. */ 3227 /* dasd_delete_device destroys the device reference. */
3164 block = device->block; 3228 block = device->block;
@@ -3170,6 +3234,14 @@ int dasd_generic_set_offline(struct ccw_device *cdev)
3170 if (block) 3234 if (block)
3171 dasd_free_block(block); 3235 dasd_free_block(block);
3172 return 0; 3236 return 0;
3237
3238interrupted:
3239 /* interrupted by signal */
3240 clear_bit(DASD_FLAG_SAFE_OFFLINE, &device->flags);
3241 clear_bit(DASD_FLAG_SAFE_OFFLINE_RUNNING, &device->flags);
3242 clear_bit(DASD_FLAG_OFFLINE, &device->flags);
3243 dasd_put_device(device);
3244 return rc;
3173} 3245}
3174 3246
3175int dasd_generic_last_path_gone(struct dasd_device *device) 3247int dasd_generic_last_path_gone(struct dasd_device *device)
@@ -3489,15 +3561,6 @@ char *dasd_get_sense(struct irb *irb)
3489} 3561}
3490EXPORT_SYMBOL_GPL(dasd_get_sense); 3562EXPORT_SYMBOL_GPL(dasd_get_sense);
3491 3563
3492static inline int _wait_for_empty_queues(struct dasd_device *device)
3493{
3494 if (device->block)
3495 return list_empty(&device->ccw_queue) &&
3496 list_empty(&device->block->ccw_queue);
3497 else
3498 return list_empty(&device->ccw_queue);
3499}
3500
3501void dasd_generic_shutdown(struct ccw_device *cdev) 3564void dasd_generic_shutdown(struct ccw_device *cdev)
3502{ 3565{
3503 struct dasd_device *device; 3566 struct dasd_device *device;
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index b2b8c18eeced..4d12370337aa 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -952,6 +952,39 @@ static DEVICE_ATTR(raw_track_access, 0644, dasd_use_raw_show,
952 dasd_use_raw_store); 952 dasd_use_raw_store);
953 953
954static ssize_t 954static ssize_t
955dasd_safe_offline_store(struct device *dev, struct device_attribute *attr,
956 const char *buf, size_t count)
957{
958 struct ccw_device *cdev = to_ccwdev(dev);
959 struct dasd_device *device;
960 int rc;
961
962 device = dasd_device_from_cdev(cdev);
963 if (IS_ERR(device)) {
964 rc = PTR_ERR(device);
965 goto out;
966 }
967
968 if (test_bit(DASD_FLAG_OFFLINE, &device->flags) ||
969 test_bit(DASD_FLAG_SAFE_OFFLINE_RUNNING, &device->flags)) {
970 /* Already doing offline processing */
971 dasd_put_device(device);
972 rc = -EBUSY;
973 goto out;
974 }
975
976 set_bit(DASD_FLAG_SAFE_OFFLINE, &device->flags);
977 dasd_put_device(device);
978
979 rc = ccw_device_set_offline(cdev);
980
981out:
982 return rc ? rc : count;
983}
984
985static DEVICE_ATTR(safe_offline, 0200, NULL, dasd_safe_offline_store);
986
987static ssize_t
955dasd_discipline_show(struct device *dev, struct device_attribute *attr, 988dasd_discipline_show(struct device *dev, struct device_attribute *attr,
956 char *buf) 989 char *buf)
957{ 990{
@@ -1320,6 +1353,7 @@ static struct attribute * dasd_attrs[] = {
1320 &dev_attr_expires.attr, 1353 &dev_attr_expires.attr,
1321 &dev_attr_reservation_policy.attr, 1354 &dev_attr_reservation_policy.attr,
1322 &dev_attr_last_known_reservation_state.attr, 1355 &dev_attr_last_known_reservation_state.attr,
1356 &dev_attr_safe_offline.attr,
1323 NULL, 1357 NULL,
1324}; 1358};
1325 1359
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index 7ff93eea673d..899e3f5a56e5 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -516,6 +516,8 @@ struct dasd_block {
516#define DASD_FLAG_IS_RESERVED 7 /* The device is reserved */ 516#define DASD_FLAG_IS_RESERVED 7 /* The device is reserved */
517#define DASD_FLAG_LOCK_STOLEN 8 /* The device lock was stolen */ 517#define DASD_FLAG_LOCK_STOLEN 8 /* The device lock was stolen */
518#define DASD_FLAG_SUSPENDED 9 /* The device was suspended */ 518#define DASD_FLAG_SUSPENDED 9 /* The device was suspended */
519#define DASD_FLAG_SAFE_OFFLINE 10 /* safe offline processing requested*/
520#define DASD_FLAG_SAFE_OFFLINE_RUNNING 11 /* safe offline running */
519 521
520 522
521void dasd_put_device_wake(struct dasd_device *); 523void dasd_put_device_wake(struct dasd_device *);