[S390] dasd: automatic recognition of read-only devices

In z/VM it is possible to attach a device as read-only. To prevent
unintentional write requests and subsequent I/O errors, we can detect
this configuration using the z/VM DIAG 210 interface and set the
respective linux block device to read-only as well.

Signed-off-by: Stefan Weinhuber <wein@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

authored by Stefan Weinhuber and committed by Martin Schwidefsky 33b62a30 584dfddf

+79 -16
+36
drivers/s390/block/dasd.c
··· 26 26 #include <asm/ebcdic.h> 27 27 #include <asm/idals.h> 28 28 #include <asm/itcw.h> 29 + #include <asm/diag.h> 29 30 30 31 /* This is ugly... */ 31 32 #define PRINTK_HEADER "dasd:" ··· 2213 2212 goto out; 2214 2213 } 2215 2214 2215 + if ((mode & FMODE_WRITE) && 2216 + (test_bit(DASD_FLAG_DEVICE_RO, &base->flags) || 2217 + (base->features & DASD_FEATURE_READONLY))) { 2218 + rc = -EROFS; 2219 + goto out; 2220 + } 2221 + 2216 2222 return 0; 2217 2223 2218 2224 out: ··· 2296 2288 /* 2297 2289 * SECTION: common functions for ccw_driver use 2298 2290 */ 2291 + 2292 + /* 2293 + * Is the device read-only? 2294 + * Note that this function does not report the setting of the 2295 + * readonly device attribute, but how it is configured in z/VM. 2296 + */ 2297 + int dasd_device_is_ro(struct dasd_device *device) 2298 + { 2299 + struct ccw_dev_id dev_id; 2300 + struct diag210 diag_data; 2301 + int rc; 2302 + 2303 + if (!MACHINE_IS_VM) 2304 + return 0; 2305 + ccw_device_get_id(device->cdev, &dev_id); 2306 + memset(&diag_data, 0, sizeof(diag_data)); 2307 + diag_data.vrdcdvno = dev_id.devno; 2308 + diag_data.vrdclen = sizeof(diag_data); 2309 + rc = diag210(&diag_data); 2310 + if (rc == 0 || rc == 2) { 2311 + return diag_data.vrdcvfla & 0x80; 2312 + } else { 2313 + DBF_EVENT(DBF_WARNING, "diag210 failed for dev=%04x with rc=%d", 2314 + dev_id.devno, rc); 2315 + return 0; 2316 + } 2317 + } 2318 + EXPORT_SYMBOL_GPL(dasd_device_is_ro); 2299 2319 2300 2320 static void dasd_generic_auto_online(void *data, async_cookie_t cookie) 2301 2321 {
+4
drivers/s390/block/dasd_3990_erp.c
··· 1045 1045 1046 1046 erp->retries = 5; 1047 1047 1048 + } else if (sense[1] & SNS1_WRITE_INHIBITED) { 1049 + dev_err(&device->cdev->dev, "An I/O request was rejected" 1050 + " because writing is inhibited\n"); 1051 + erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED); 1048 1052 } else { 1049 1053 /* fatal error - set status to FAILED 1050 1054 internal error 09 - Command Reject */
+8 -5
drivers/s390/block/dasd_devmap.c
··· 742 742 const char *buf, size_t count) 743 743 { 744 744 struct dasd_devmap *devmap; 745 + struct dasd_device *device; 745 746 int val; 746 747 char *endp; 747 748 ··· 759 758 devmap->features |= DASD_FEATURE_READONLY; 760 759 else 761 760 devmap->features &= ~DASD_FEATURE_READONLY; 762 - if (devmap->device) 763 - devmap->device->features = devmap->features; 764 - if (devmap->device && devmap->device->block 765 - && devmap->device->block->gdp) 766 - set_disk_ro(devmap->device->block->gdp, val); 761 + device = devmap->device; 762 + if (device) { 763 + device->features = devmap->features; 764 + val = val || test_bit(DASD_FLAG_DEVICE_RO, &device->flags); 765 + } 767 766 spin_unlock(&dasd_devmap_lock); 767 + if (device && device->block && device->block->gdp) 768 + set_disk_ro(device->block->gdp, val); 768 769 return count; 769 770 } 770 771
+2 -4
drivers/s390/block/dasd_diag.c
··· 145 145 mdsk_term_io(device); 146 146 rc = mdsk_init_io(device, device->block->bp_block, 0, NULL); 147 147 if (rc == 4) { 148 - if (!(device->features & DASD_FEATURE_READONLY)) { 148 + if (!(test_and_set_bit(DASD_FLAG_DEVICE_RO, &device->flags))) 149 149 pr_warning("%s: The access mode of a DIAG device " 150 150 "changed to read-only\n", 151 151 dev_name(&device->cdev->dev)); 152 - device->features |= DASD_FEATURE_READONLY; 153 - } 154 152 rc = 0; 155 153 } 156 154 if (rc) ··· 447 449 rc = -EIO; 448 450 } else { 449 451 if (rc == 4) 450 - device->features |= DASD_FEATURE_READONLY; 452 + set_bit(DASD_FLAG_DEVICE_RO, &device->flags); 451 453 pr_info("%s: New DASD with %ld byte/block, total size %ld " 452 454 "KB%s\n", dev_name(&device->cdev->dev), 453 455 (unsigned long) block->bp_block,
+8 -2
drivers/s390/block/dasd_eckd.c
··· 1089 1089 struct dasd_eckd_private *private; 1090 1090 struct dasd_block *block; 1091 1091 int is_known, rc; 1092 + int readonly; 1092 1093 1093 1094 if (!ccw_device_is_pathgroup(device->cdev)) { 1094 1095 dev_warn(&device->cdev->dev, ··· 1183 1182 else 1184 1183 private->real_cyl = private->rdc_data.no_cyl; 1185 1184 1185 + readonly = dasd_device_is_ro(device); 1186 + if (readonly) 1187 + set_bit(DASD_FLAG_DEVICE_RO, &device->flags); 1188 + 1186 1189 dev_info(&device->cdev->dev, "New DASD %04X/%02X (CU %04X/%02X) " 1187 - "with %d cylinders, %d heads, %d sectors\n", 1190 + "with %d cylinders, %d heads, %d sectors%s\n", 1188 1191 private->rdc_data.dev_type, 1189 1192 private->rdc_data.dev_model, 1190 1193 private->rdc_data.cu_type, 1191 1194 private->rdc_data.cu_model.model, 1192 1195 private->real_cyl, 1193 1196 private->rdc_data.trk_per_cyl, 1194 - private->rdc_data.sec_per_trk); 1197 + private->rdc_data.sec_per_trk, 1198 + readonly ? ", read-only device" : ""); 1195 1199 return 0; 1196 1200 1197 1201 out_err3:
+8 -2
drivers/s390/block/dasd_fba.c
··· 124 124 struct dasd_fba_private *private; 125 125 struct ccw_device *cdev = device->cdev; 126 126 int rc; 127 + int readonly; 127 128 128 129 private = (struct dasd_fba_private *) device->private; 129 130 if (!private) { ··· 163 162 return rc; 164 163 } 165 164 165 + readonly = dasd_device_is_ro(device); 166 + if (readonly) 167 + set_bit(DASD_FLAG_DEVICE_RO, &device->flags); 168 + 166 169 dev_info(&device->cdev->dev, 167 170 "New FBA DASD %04X/%02X (CU %04X/%02X) with %d MB " 168 - "and %d B/blk\n", 171 + "and %d B/blk%s\n", 169 172 cdev->id.dev_type, 170 173 cdev->id.dev_model, 171 174 cdev->id.cu_type, 172 175 cdev->id.cu_model, 173 176 ((private->rdc_data.blk_bdsa * 174 177 (private->rdc_data.blk_size >> 9)) >> 11), 175 - private->rdc_data.blk_size); 178 + private->rdc_data.blk_size, 179 + readonly ? ", read-only device" : ""); 176 180 return 0; 177 181 } 178 182
+2 -1
drivers/s390/block/dasd_genhd.c
··· 70 70 } 71 71 len += sprintf(gdp->disk_name + len, "%c", 'a'+(base->devindex%26)); 72 72 73 - if (block->base->features & DASD_FEATURE_READONLY) 73 + if (base->features & DASD_FEATURE_READONLY || 74 + test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) 74 75 set_disk_ro(gdp, 1); 75 76 gdp->private_data = block; 76 77 gdp->queue = block->request_queue;
+7
drivers/s390/block/dasd_int.h
··· 436 436 #define DASD_FLAG_OFFLINE 3 /* device is in offline processing */ 437 437 #define DASD_FLAG_EER_SNSS 4 /* A SNSS is required */ 438 438 #define DASD_FLAG_EER_IN_USE 5 /* A SNSS request is running */ 439 + #define DASD_FLAG_DEVICE_RO 6 /* The device itself is read-only. Don't 440 + * confuse this with the user specified 441 + * read-only feature. 442 + */ 439 443 440 444 void dasd_put_device_wake(struct dasd_device *); 441 445 ··· 612 608 613 609 void dasd_device_set_stop_bits(struct dasd_device *, int); 614 610 void dasd_device_remove_stop_bits(struct dasd_device *, int); 611 + 612 + int dasd_device_is_ro(struct dasd_device *); 613 + 615 614 616 615 /* externals in dasd_devmap.c */ 617 616 extern int dasd_max_devindex;
+4 -2
drivers/s390/block/dasd_ioctl.c
··· 199 199 if (!argp) 200 200 return -EINVAL; 201 201 202 - if (block->base->features & DASD_FEATURE_READONLY) 202 + if (block->base->features & DASD_FEATURE_READONLY || 203 + test_bit(DASD_FLAG_DEVICE_RO, &block->base->flags)) 203 204 return -EROFS; 204 205 if (copy_from_user(&fdata, argp, sizeof(struct format_data_t))) 205 206 return -EFAULT; ··· 350 349 return -EINVAL; 351 350 if (get_user(intval, (int __user *)argp)) 352 351 return -EFAULT; 353 - 352 + if (!intval && test_bit(DASD_FLAG_DEVICE_RO, &block->base->flags)) 353 + return -EROFS; 354 354 set_disk_ro(bdev->bd_disk, intval); 355 355 return dasd_set_feature(block->base->cdev, DASD_FEATURE_READONLY, intval); 356 356 }