]> xenbits.xensource.com Git - qemu-xen-4.3-testing.git/commitdiff
Fix read-only image file handling
authorIan Jackson <ian.jackson@eu.citrix.com>
Wed, 9 Jun 2010 16:10:59 +0000 (17:10 +0100)
committerIan Jackson <Ian.Jackson@eu.citrix.com>
Wed, 9 Jun 2010 16:10:59 +0000 (17:10 +0100)
Hi,
this is the patch for qemu-xen-3.4-testing to fix the read-only
image file handling since the image file was always treated as
read-write which means that all the HVM guests were able to
write to all the disk images available in domain configuration
file no matter what the mode of the image was defined. This
patch fixes this functionality to honor the O_RDONLY in the
BDRV_O_ACCESS flag in block.c and also fixes the IDE and SCSI
interfaces that uses it.

It's been tested on RHEL-5 with xen-3.4-testing version of
upstream xen with xen-3.4-testing qemu implementation. The
patch is applicable to qemu-xen-unstable.git as well with no
modifications.

When you want to mount an image that is set as read-only in the
domain configuration file but you omit to set mode to read-only
it results into I/O errors when processing the requests.
Remounting as read-only or unmounting and remounting using the
`mount /dev/* /path/to/mount -o ro` shall do the mounting the
correct way, i.e. with no I/O errors, so make sure you mount
those disks as read-only otherwise you can be getting errors like:

end_request: I/O error, dev hdb, sector 52
Buffer I/O error on device hdb1, logical block 1
lost page write due to I/O error on hdb1

and for IDE devices you'll be getting several additional DeviceFault
errors since mounting the device read-write (default setting) writes
some data onto a disk at the mount-time.

For SCSI devices the DATA PROTECT request sense has been added
as found at: http://en.wikipedia.org/wiki/SCSI_Request_Sense_Command

Michal

Signed-off-by: Michal Novotny <minovotn@redhat.com>
block.c
hw/ide.c
hw/scsi-disk.c
xenstore.c

diff --git a/block.c b/block.c
index 88e70d3e15f9b0865242ab0162359cdf1e33a351..05ff8cbc3f98c669a1908b63c4551e6943a750d1 100644 (file)
--- a/block.c
+++ b/block.c
@@ -422,7 +422,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
     /* Note: for compatibility, we open disk image files as RDWR, and
        RDONLY as fallback */
     if (!(flags & BDRV_O_FILE))
-        open_flags = BDRV_O_RDWR | (flags & BDRV_O_CACHE_MASK);
+        open_flags = (flags & BDRV_O_ACCESS) | (flags & BDRV_O_CACHE_MASK);
     else
         open_flags = flags & ~(BDRV_O_FILE | BDRV_O_SNAPSHOT);
     ret = drv->bdrv_open(bs, filename, open_flags);
index b38de553695bfd228398f66f06a5c2952e8f3a53..791666b898732bcd08b83e84f3f27d78886deb9e 100644 (file)
--- a/hw/ide.c
+++ b/hw/ide.c
@@ -2551,6 +2551,15 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
         case WIN_WRITE_ONCE:
         case CFA_WRITE_SECT_WO_ERASE:
         case WIN_WRITE_VERIFY:
+            if (bdrv_is_read_only(s->bs)) {
+#if defined(DEBUG_IDE)
+                printf("Attempt to write on read-only device %s\n", s->bs->filename);
+#endif
+                s->status = WRERR_STAT;
+                s->error = ABRT_ERR;
+                ide_set_irq(s);
+                break;
+            }
            ide_cmd_lba48_transform(s, lba48);
             s->error = 0;
             s->status = SEEK_STAT | READY_STAT;
@@ -2573,6 +2582,15 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
         case CFA_WRITE_MULTI_WO_ERASE:
             if (!s->mult_sectors)
                 goto abort_cmd;
+           if (bdrv_is_read_only(s->bs)) {
+#if defined(DEBUG_IDE)
+                printf("Attempt to multiwrite on read-only device %s\n", s->bs->filename);
+#endif
+                s->status = WRERR_STAT;
+                s->error = ABRT_ERR;
+                ide_set_irq(s);
+                break;
+           }
            ide_cmd_lba48_transform(s, lba48);
             s->error = 0;
             s->status = SEEK_STAT | READY_STAT;
@@ -2598,6 +2616,15 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
         case WIN_WRITEDMA_ONCE:
             if (!s->bs)
                 goto abort_cmd;
+            if (bdrv_is_read_only(s->bs)) {
+#if defined(DEBUG_IDE)
+                printf("Attempt to DMA write to read-only device %s\n", s->bs->filename);
+#endif
+                s->status = WRERR_STAT;
+                s->error = ABRT_ERR;
+                ide_set_irq(s);
+                break;
+            }
            ide_cmd_lba48_transform(s, lba48);
             ide_sector_write_dma(s);
             s->media_changed = 1;
index 4fc18f01ff5369fffc57586ba0b1a1ddcd7dae70..520009e1088e335ef07c80813369956961a6c17f 100644 (file)
@@ -35,6 +35,7 @@ do { fprintf(stderr, "scsi-disk: " fmt , ##args); } while (0)
 #define SENSE_NOT_READY       2
 #define SENSE_HARDWARE_ERROR  4
 #define SENSE_ILLEGAL_REQUEST 5
+#define SENSE_DATA_PROTECT    7
 
 #define STATUS_GOOD            0
 #define STATUS_CHECK_CONDITION 2
@@ -234,6 +235,9 @@ static int scsi_handle_write_error(SCSIRequest *r, int error)
             || action == BLOCK_ERR_STOP_ANY) {
         r->status |= SCSI_REQ_STATUS_RETRY;
         vm_stop(0);
+    } else if (error == SENSE_DATA_PROTECT) {
+        scsi_command_complete(r, STATUS_CHECK_CONDITION,
+                SENSE_DATA_PROTECT);
     } else {
         scsi_command_complete(r, STATUS_CHECK_CONDITION,
                 SENSE_HARDWARE_ERROR);
@@ -305,6 +309,11 @@ static int scsi_write_data(SCSIDevice *d, uint32_t tag)
         return 1;
     }
 
+    if (bdrv_is_read_only(r->dev->bdrv)) {
+        scsi_write_complete(r, SENSE_DATA_PROTECT);
+        return 1;
+    }
+
     if (r->aiocb)
         BADF("Data transfer already in progress\n");
 
index c8244595cc256ad576f2e46903391325fc874be9..4a35f55ffabaf2d65cbb7923e23f1c6095e30b1f 100644 (file)
@@ -403,6 +403,11 @@ void xenstore_parse_domain_config(int hvm_domid)
     BlockDriverState *bs;
     BlockDriver *format;
 
+    /* Read-only handling for image files */
+    char *mode = NULL;
+    int flags;
+    int is_readonly;
+
     /* paths controlled by untrustworthy guest, and values read from them */
     char *danger_path;
     char *danger_buf = NULL;
@@ -595,7 +600,24 @@ void xenstore_parse_domain_config(int hvm_domid)
                }
            }
             pstrcpy(bs->filename, sizeof(bs->filename), params);
-            if (bdrv_open2(bs, params, BDRV_O_CACHE_WB /* snapshot and write-back */, format) < 0)
+
+            flags = BDRV_O_CACHE_WB; /* snapshot and write-back */
+            is_readonly = 0;
+            if (pasprintf(&buf, "%s/mode", bpath) == -1)
+                continue;
+            free(mode);
+            mode = xs_read(xsh, XBT_NULL, buf, &len);
+            if (mode == NULL)
+                continue;
+            if (strchr(mode, 'r') && !strchr(mode, 'w'))
+                is_readonly = 1;
+
+            if (!is_readonly)
+                flags |= BDRV_O_ACCESS & O_RDWR;
+
+            fprintf(stderr, "Using file %s in read-%s mode\n", bs->filename, is_readonly ? "only" : "write");
+
+            if (bdrv_open2(bs, params, flags, format) < 0)
                 fprintf(stderr, "qemu: could not open vbd '%s' or hard disk image '%s' (drv '%s' format '%s')\n", buf, params, drv ? drv : "?", format ? format->format_name : "0");
         }
 
@@ -703,6 +725,7 @@ void xenstore_parse_domain_config(int hvm_domid)
 
  out:
     free(danger_type);
+    free(mode);
     free(params);
     free(dev);
     free(bpath);