diff options
author | Stefan Weinhuber <wein@de.ibm.com> | 2010-03-08 12:26:24 +0100 |
---|---|---|
committer | Martin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com> | 2010-03-08 12:26:27 +0100 |
commit | 33b62a30f78536b976183cc764c08038ac011e0a (patch) | |
tree | 60a18b4478c68082835fa6fee9a24bb1e7e8b312 /drivers/s390/block/dasd.c | |
parent | 584dfddfce1bd81d877f14de2b56d4bc747af821 (diff) |
[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>
Diffstat (limited to 'drivers/s390/block/dasd.c')
-rw-r--r-- | drivers/s390/block/dasd.c | 36 |
1 files changed, 36 insertions, 0 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 4951aa82e9f..bbea90baf98 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -26,6 +26,7 @@ #include <asm/ebcdic.h> #include <asm/idals.h> #include <asm/itcw.h> +#include <asm/diag.h> /* This is ugly... */ #define PRINTK_HEADER "dasd:" @@ -2212,6 +2213,13 @@ static int dasd_open(struct block_device *bdev, fmode_t mode) goto out; } + if ((mode & FMODE_WRITE) && + (test_bit(DASD_FLAG_DEVICE_RO, &base->flags) || + (base->features & DASD_FEATURE_READONLY))) { + rc = -EROFS; + goto out; + } + return 0; out: @@ -2289,6 +2297,34 @@ dasd_exit(void) * SECTION: common functions for ccw_driver use */ +/* + * Is the device read-only? + * Note that this function does not report the setting of the + * readonly device attribute, but how it is configured in z/VM. + */ +int dasd_device_is_ro(struct dasd_device *device) +{ + struct ccw_dev_id dev_id; + struct diag210 diag_data; + int rc; + + if (!MACHINE_IS_VM) + return 0; + ccw_device_get_id(device->cdev, &dev_id); + memset(&diag_data, 0, sizeof(diag_data)); + diag_data.vrdcdvno = dev_id.devno; + diag_data.vrdclen = sizeof(diag_data); + rc = diag210(&diag_data); + if (rc == 0 || rc == 2) { + return diag_data.vrdcvfla & 0x80; + } else { + DBF_EVENT(DBF_WARNING, "diag210 failed for dev=%04x with rc=%d", + dev_id.devno, rc); + return 0; + } +} +EXPORT_SYMBOL_GPL(dasd_device_is_ro); + static void dasd_generic_auto_online(void *data, async_cookie_t cookie) { struct ccw_device *cdev = data; |