Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Stefan Haberland and committed by
Martin Schwidefsky
d07dc5d8 55d3a85c

+116 -17
+80 -17
drivers/s390/block/dasd.c
··· 349 349 return rc; 350 350 } 351 351 352 + static inline 353 + int _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 363 * Remove device from block device layer. Destroy dirty buffers. 354 364 * Forget format information. Check if the target level is basic ··· 1851 1841 cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist); 1852 1842 if ((cqr->status == DASD_CQR_IN_IO && cqr->expires != 0) && 1853 1843 (time_after_eq(jiffies, cqr->expires + cqr->starttime))) { 1844 + if (test_bit(DASD_FLAG_SAFE_OFFLINE_RUNNING, &device->flags)) { 1845 + /* 1846 + * IO in safe offline processing should not 1847 + * run out of retries 1848 + */ 1849 + cqr->retries++; 1850 + } 1854 1851 if (device->discipline->term_IO(cqr) != 0) { 1855 1852 /* Hmpf, try again in 5 sec */ 1856 1853 dev_err(&device->cdev->dev, ··· 3041 3024 3042 3025 cdev->handler = NULL; 3043 3026 3044 - dasd_remove_sysfs_files(cdev); 3045 3027 device = dasd_device_from_cdev(cdev); 3046 3028 if (IS_ERR(device)) 3047 3029 return; 3048 - if (test_and_set_bit(DASD_FLAG_OFFLINE, &device->flags)) { 3030 + if (test_and_set_bit(DASD_FLAG_OFFLINE, &device->flags) && 3031 + !test_bit(DASD_FLAG_SAFE_OFFLINE_RUNNING, &device->flags)) { 3049 3032 /* Already doing offline processing */ 3050 3033 dasd_put_device(device); 3051 3034 return; ··· 3065 3048 */ 3066 3049 if (block) 3067 3050 dasd_free_block(block); 3051 + 3052 + dasd_remove_sysfs_files(cdev); 3068 3053 } 3069 3054 3070 3055 /* ··· 3145 3126 { 3146 3127 struct dasd_device *device; 3147 3128 struct dasd_block *block; 3148 - int max_count, open_count; 3129 + int max_count, open_count, rc; 3149 3130 3131 + rc = 0; 3150 3132 device = dasd_device_from_cdev(cdev); 3151 3133 if (IS_ERR(device)) 3152 3134 return PTR_ERR(device); 3153 - if (test_and_set_bit(DASD_FLAG_OFFLINE, &device->flags)) { 3154 - /* Already doing offline processing */ 3155 - dasd_put_device(device); 3156 - return 0; 3157 - } 3135 + 3158 3136 /* 3159 3137 * We must make sure that this device is currently not in use. 3160 3138 * The open_count is increased for every opener, that includes ··· 3175 3159 return -EBUSY; 3176 3160 } 3177 3161 } 3162 + 3163 + if (test_bit(DASD_FLAG_SAFE_OFFLINE_RUNNING, &device->flags)) { 3164 + /* 3165 + * safe offline allready running 3166 + * could only be called by normal offline so safe_offline flag 3167 + * needs to be removed to run normal offline and kill all I/O 3168 + */ 3169 + if (test_and_set_bit(DASD_FLAG_OFFLINE, &device->flags)) { 3170 + /* Already doing normal offline processing */ 3171 + dasd_put_device(device); 3172 + return -EBUSY; 3173 + } else 3174 + clear_bit(DASD_FLAG_SAFE_OFFLINE, &device->flags); 3175 + 3176 + } else 3177 + if (test_bit(DASD_FLAG_OFFLINE, &device->flags)) { 3178 + /* Already doing offline processing */ 3179 + dasd_put_device(device); 3180 + return -EBUSY; 3181 + } 3182 + 3183 + /* 3184 + * if safe_offline called set safe_offline_running flag and 3185 + * clear safe_offline so that a call to normal offline 3186 + * can overrun safe_offline processing 3187 + */ 3188 + if (test_and_clear_bit(DASD_FLAG_SAFE_OFFLINE, &device->flags) && 3189 + !test_and_set_bit(DASD_FLAG_SAFE_OFFLINE_RUNNING, &device->flags)) { 3190 + /* 3191 + * If we want to set the device safe offline all IO operations 3192 + * should be finished before continuing the offline process 3193 + * so sync bdev first and then wait for our queues to become 3194 + * empty 3195 + */ 3196 + /* sync blockdev and partitions */ 3197 + rc = fsync_bdev(device->block->bdev); 3198 + if (rc != 0) 3199 + goto interrupted; 3200 + 3201 + /* schedule device tasklet and wait for completion */ 3202 + dasd_schedule_device_bh(device); 3203 + rc = wait_event_interruptible(shutdown_waitq, 3204 + _wait_for_empty_queues(device)); 3205 + if (rc != 0) 3206 + goto interrupted; 3207 + } 3208 + 3209 + set_bit(DASD_FLAG_OFFLINE, &device->flags); 3178 3210 dasd_set_target_state(device, DASD_STATE_NEW); 3179 3211 /* dasd_delete_device destroys the device reference. */ 3180 3212 block = device->block; ··· 3234 3170 if (block) 3235 3171 dasd_free_block(block); 3236 3172 return 0; 3173 + 3174 + interrupted: 3175 + /* interrupted by signal */ 3176 + clear_bit(DASD_FLAG_SAFE_OFFLINE, &device->flags); 3177 + clear_bit(DASD_FLAG_SAFE_OFFLINE_RUNNING, &device->flags); 3178 + clear_bit(DASD_FLAG_OFFLINE, &device->flags); 3179 + dasd_put_device(device); 3180 + return rc; 3237 3181 } 3238 3182 3239 3183 int dasd_generic_last_path_gone(struct dasd_device *device) ··· 3560 3488 return sense; 3561 3489 } 3562 3490 EXPORT_SYMBOL_GPL(dasd_get_sense); 3563 - 3564 - static inline int _wait_for_empty_queues(struct dasd_device *device) 3565 - { 3566 - if (device->block) 3567 - return list_empty(&device->ccw_queue) && 3568 - list_empty(&device->block->ccw_queue); 3569 - else 3570 - return list_empty(&device->ccw_queue); 3571 - } 3572 3491 3573 3492 void dasd_generic_shutdown(struct ccw_device *cdev) 3574 3493 {
+34
drivers/s390/block/dasd_devmap.c
··· 952 952 dasd_use_raw_store); 953 953 954 954 static ssize_t 955 + dasd_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 + 981 + out: 982 + return rc ? rc : count; 983 + } 984 + 985 + static DEVICE_ATTR(safe_offline, 0200, NULL, dasd_safe_offline_store); 986 + 987 + static ssize_t 955 988 dasd_discipline_show(struct device *dev, struct device_attribute *attr, 956 989 char *buf) 957 990 { ··· 1353 1320 &dev_attr_expires.attr, 1354 1321 &dev_attr_reservation_policy.attr, 1355 1322 &dev_attr_last_known_reservation_state.attr, 1323 + &dev_attr_safe_offline.attr, 1356 1324 NULL, 1357 1325 }; 1358 1326
+2
drivers/s390/block/dasd_int.h
··· 516 516 #define DASD_FLAG_IS_RESERVED 7 /* The device is reserved */ 517 517 #define DASD_FLAG_LOCK_STOLEN 8 /* The device lock was stolen */ 518 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 521 523 void dasd_put_device_wake(struct dasd_device *);