]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
kvm tools: Fix read-only support in QCOW
authorPekka Enberg <penberg@kernel.org>
Wed, 11 May 2011 18:23:03 +0000 (21:23 +0300)
committerPekka Enberg <penberg@kernel.org>
Wed, 11 May 2011 18:24:15 +0000 (21:24 +0300)
If the user specifies a read-only image, make sure we never write to it.
Booting to a read-only image looks like this now:

  $ ./kvm run -i ~/images/linux-0.2.qcow2,ro

  [ snip ]
  [    1.250236] end_request: I/O error, dev vda, sector 32856
  [    1.252867] Buffer I/O error on device vda, logical block 16428
  [    1.255706] lost page write due to I/O error on vda
  [    1.258120] EXT4-fs (vda): previous I/O error to superblock detected
  [    1.261157] end_request: I/O error, dev vda, sector 2
  [    1.263333] Buffer I/O error on device vda, logical block 1
  [    1.264944] lost page write due to I/O error on vda
  [    1.266139] EXT4-fs (vda): re-mounted. Opts:
  [    1.284390] end_request: I/O error, dev vda, sector 35842
  [    1.285679] Buffer I/O error on device vda, logical block 17921
  [    1.287175] EXT4-fs warning (device vda): ext4_end_bio:259: I/O error writing to inode 3756 (offset 0 size 1024 starting block 17922)

Reported-by: Sasha Levin <levinsasha928@gmail.com>
Cc: Asias He <asias.hejun@gmail.com>
Cc: Avi Kivity <avi@redhat.com>
Cc: Cyrill Gorcunov <gorcunov@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Prasad Joshi <prasadjoshi124@gmail.com>
Cc: Sasha Levin <levinsasha928@gmail.com>
Signed-off-by: Pekka Enberg <penberg@kernel.org>
tools/kvm/disk-image.c
tools/kvm/include/kvm/disk-image.h
tools/kvm/include/kvm/qcow.h
tools/kvm/qcow.c

index bddbdb349c0185976a5a742d9225e33875adf89d..1a704b3de9d6cdea9d46ef5a274cf56594da8372 100644 (file)
@@ -144,7 +144,7 @@ struct disk_image *disk_image__open(const char *filename, bool readonly)
        if (fd < 0)
                return NULL;
 
-       disk = qcow_probe(fd);
+       disk = qcow_probe(fd, readonly);
        if (disk)
                return disk;
 
index d5bf98174c4d7e3874959f3d919260e280a1fbe7..9d7b572d47655e69e5bc14e242eacdd0ff8fd950 100644 (file)
@@ -46,7 +46,9 @@ static inline ssize_t disk_image__read_sector_iov(struct disk_image *disk, u64 s
                return disk->ops->read_sector_iov(disk, sector, iov, iovcount);
 
        while (iovcount--) {
-               disk->ops->read_sector(disk, sector, iov->iov_base, iov->iov_len);
+               if (disk->ops->read_sector(disk, sector, iov->iov_base, iov->iov_len) < 0)
+                       return -1;
+
                sector += iov->iov_len >> SECTOR_SHIFT;
                iov++;
        }
@@ -60,7 +62,9 @@ static inline ssize_t disk_image__write_sector_iov(struct disk_image *disk, u64
                return disk->ops->write_sector_iov(disk, sector, iov, iovcount);
 
        while (iovcount--) {
-               disk->ops->write_sector(disk, sector, iov->iov_base, iov->iov_len);
+               if (disk->ops->write_sector(disk, sector, iov->iov_base, iov->iov_len) < 0)
+                       return -1;
+
                sector += iov->iov_len >> SECTOR_SHIFT;
                iov++;
        }
index 3d84aad808f302c9bc397b370b8030c5943d67c3..b6e74934e13291ab585e99c952a92fa45195462a 100644 (file)
@@ -2,6 +2,7 @@
 #define KVM__QCOW_H
 
 #include <linux/types.h>
+#include <stdbool.h>
 
 #define QCOW_MAGIC             (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
 
@@ -74,6 +75,6 @@ struct qcow2_header_disk {
        u64                     snapshots_offset;
 };
 
-struct disk_image *qcow_probe(int fd);
+struct disk_image *qcow_probe(int fd, bool readonly);
 
 #endif /* KVM__QCOW_H */
index f8b52d48bea5ac99bc219d9f98c7e010fa043d12..8e1b70d79441c6fa3f6faab98a246f9931b05597 100644 (file)
@@ -320,6 +320,12 @@ static int qcow1_write_sector(struct disk_image *disk, u64 sector, void *src, u3
        return 0;
 }
 
+static int qcow1_nowrite_sector(struct disk_image *disk, u64 sector, void *src, u32 src_len)
+{
+       /* I/O error */
+       return -1;
+}
+
 static void qcow1_disk_close(struct disk_image *disk)
 {
        struct qcow *q;
@@ -334,7 +340,13 @@ static void qcow1_disk_close(struct disk_image *disk)
        free(q);
 }
 
-struct disk_image_operations qcow1_disk_ops = {
+static struct disk_image_operations qcow1_disk_readonly_ops = {
+       .read_sector            = qcow1_read_sector,
+       .write_sector           = qcow1_nowrite_sector,
+       .close                  = qcow1_disk_close
+};
+
+static struct disk_image_operations qcow1_disk_ops = {
        .read_sector            = qcow1_read_sector,
        .write_sector           = qcow1_write_sector,
        .close                  = qcow1_disk_close
@@ -402,7 +414,7 @@ static void *qcow2_read_header(int fd)
        return header;
 }
 
-static struct disk_image *qcow2_probe(int fd)
+static struct disk_image *qcow2_probe(int fd, bool readonly)
 {
        struct qcow *q;
        struct qcow_header *h;
@@ -421,7 +433,11 @@ static struct disk_image *qcow2_probe(int fd)
        if (qcow_read_l1_table(q) < 0)
                goto error;
 
-       disk_image = disk_image__new(fd, h->size, &qcow1_disk_ops);
+       if (readonly)
+               disk_image = disk_image__new(fd, h->size, &qcow1_disk_readonly_ops);
+       else
+               disk_image = disk_image__new(fd, h->size, &qcow1_disk_ops);
+
        if (!disk_image)
                goto error;
        disk_image->priv = q;
@@ -492,7 +508,7 @@ static void *qcow1_read_header(int fd)
        return header;
 }
 
-static struct disk_image *qcow1_probe(int fd)
+static struct disk_image *qcow1_probe(int fd, bool readonly)
 {
        struct qcow *q;
        struct qcow_header *h;
@@ -511,7 +527,11 @@ static struct disk_image *qcow1_probe(int fd)
        if (qcow_read_l1_table(q) < 0)
                goto error;
 
-       disk_image = disk_image__new(fd, h->size, &qcow1_disk_ops);
+       if (readonly)
+               disk_image = disk_image__new(fd, h->size, &qcow1_disk_readonly_ops);
+       else
+               disk_image = disk_image__new(fd, h->size, &qcow1_disk_ops);
+
        if (!disk_image)
                goto error;
        disk_image->priv = q;
@@ -547,13 +567,13 @@ static bool qcow1_check_image(int fd)
        return true;
 }
 
-struct disk_image *qcow_probe(int fd)
+struct disk_image *qcow_probe(int fd, bool readonly)
 {
        if (qcow1_check_image(fd))
-               return qcow1_probe(fd);
+               return qcow1_probe(fd, readonly);
 
        if (qcow2_check_image(fd))
-               return qcow2_probe(fd);
+               return qcow2_probe(fd, readonly);
 
        return NULL;
 }