]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
kvm tools: Fix large disk images on 32-bit
authorPekka Enberg <penberg@kernel.org>
Thu, 31 Mar 2011 08:50:09 +0000 (11:50 +0300)
committerPekka Enberg <penberg@kernel.org>
Thu, 31 Mar 2011 16:09:54 +0000 (19:09 +0300)
Use read()/write() instead of mmap() for virtio block device emulation to
support large disk images on 32-bit.

Reported-and-tested-by: Asias He <asias.hejun@gmail.com>
Tested-by: Cyrill Gorcunov <gorcunov@gmail.com>
Signed-off-by: Pekka Enberg <penberg@kernel.org>
tools/kvm/Makefile
tools/kvm/disk-image.c
tools/kvm/include/kvm/disk-image.h
tools/kvm/include/kvm/read-write.h [new file with mode: 0644]
tools/kvm/read-write.c [new file with mode: 0644]

index 2d3f47603d8c7f95307e6009bad44d6e569bd088..bfb3deedd76b4c343fab1444b646fd7d7d72b7fa 100644 (file)
@@ -15,6 +15,7 @@ TAGS = ctags
 OBJS   += 8250-serial.o
 OBJS   += blk-virtio.o
 OBJS   += cpuid.o
+OBJS   += read-write.o
 OBJS   += disk-image.o
 OBJS   += interrupt.o
 OBJS   += ioport.o
@@ -40,6 +41,9 @@ ifeq ($(uname_M),x86_64)
 endif
 endif
 
+DEFINES        += -D_FILE_OFFSET_BITS=64
+DEFINES        += -D_GNU_SOURCE
+
 CFLAGS += $(CPPFLAGS) $(DEFINES) -Iinclude -I../../include -Os -g
 
 WARNINGS += -Werror
index 7aca1cc2ab946ae64006ab9037dab93b9549a493..678000865b63e56fc81e4070e9e83bd9e16bf19c 100644 (file)
@@ -1,5 +1,6 @@
 #include "kvm/disk-image.h"
 
+#include "kvm/read-write.h"
 #include "kvm/util.h"
 
 #include <sys/types.h>
 #include <unistd.h>
 #include <fcntl.h>
 
-static const char QCOW_MAGIC[] = { 'Q', 'F', 'I', 0xfb };
-
-struct qcow_header {
-       uint8_t                 magic[5];
-};
-
-static bool disk_image__is_qcow(struct disk_image *self)
-{
-       struct qcow_header *header = self->mmap;
-
-       return !memcmp(header->magic, QCOW_MAGIC, ARRAY_SIZE(QCOW_MAGIC));
-}
-
 struct disk_image *disk_image__open(const char *filename)
 {
        struct disk_image *self;
@@ -34,7 +22,7 @@ struct disk_image *disk_image__open(const char *filename)
        if (!self)
                return NULL;
 
-       self->fd        = open(filename, O_RDONLY);
+       self->fd        = open(filename, O_RDWR);
        if (self->fd < 0)
                goto failed_free;
 
@@ -43,13 +31,6 @@ struct disk_image *disk_image__open(const char *filename)
 
        self->size      = st.st_size;
 
-       self->mmap      = mmap(NULL, self->size, PROT_READ|PROT_WRITE, MAP_PRIVATE, self->fd, 0);
-       if (self->mmap == MAP_FAILED)
-               goto failed_close_fd;
-
-       if (disk_image__is_qcow(self))
-               die("QCOW disk image format is not supported.");
-
        return self;
 
 failed_close_fd:
@@ -62,9 +43,6 @@ failed_free:
 
 void disk_image__close(struct disk_image *self)
 {
-       if (munmap(self->mmap, self->size) < 0)
-               warning("munmap() failed");
-
        if (close(self->fd) < 0)
                warning("close() failed");
 
@@ -78,7 +56,11 @@ int disk_image__read_sector(struct disk_image *self, uint64_t sector, void *dst,
        if (offset + dst_len > self->size)
                return -1;
 
-       memcpy(dst, self->mmap + offset, dst_len);
+       if (lseek(self->fd, offset, SEEK_SET) < 0)
+               return -1;
+
+       if (read_in_full(self->fd, dst, dst_len) < 0)
+               return -1;
 
        return 0;
 }
@@ -90,7 +72,11 @@ int disk_image__write_sector(struct disk_image *self, uint64_t sector, void *src
        if (offset + src_len > self->size)
                return -1;
 
-       memcpy(self->mmap + offset, src, src_len);
+       if (lseek(self->fd, offset, SEEK_SET) < 0)
+               return -1;
+
+       if (write_in_full(self->fd, src, src_len) < 0)
+               return -1;
 
        return 0;
 }
index 25b31d6ae96ef286fce83cb3c3629c1488fbc6ca..0599fc7670e1acae1c2652e4be9bf7a4a8493238 100644 (file)
@@ -7,7 +7,6 @@
 #define SECTOR_SIZE            (1UL << SECTOR_SHIFT)
 
 struct disk_image {
-       void            *mmap;
        int             fd;
        uint64_t        size;
 };
diff --git a/tools/kvm/include/kvm/read-write.h b/tools/kvm/include/kvm/read-write.h
new file mode 100644 (file)
index 0000000..a49394b
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef KVM_READ_WRITE_H
+#define KVM_READ_WRITE_H
+
+#include <sys/types.h>
+#include <unistd.h>
+
+ssize_t xread(int fd, void *buf, size_t count);
+ssize_t xwrite(int fd, const void *buf, size_t count);
+
+ssize_t read_in_full(int fd, void *buf, size_t count);
+ssize_t write_in_full(int fd, const void *buf, size_t count);
+
+#endif /* KVM_READ_WRITE_H */
diff --git a/tools/kvm/read-write.c b/tools/kvm/read-write.c
new file mode 100644 (file)
index 0000000..46b147d
--- /dev/null
@@ -0,0 +1,79 @@
+#include "kvm/read-write.h"
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+/* Same as read(2) except that this function never returns EAGAIN or EINTR. */
+ssize_t xread(int fd, void *buf, size_t count)
+{
+       ssize_t nr;
+
+restart:
+       nr = read(fd, buf, count);
+       if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
+               goto restart;
+
+       return nr;
+}
+
+/* Same as write(2) except that this function never returns EAGAIN or EINTR. */
+ssize_t xwrite(int fd, const void *buf, size_t count)
+{
+       ssize_t nr;
+
+restart:
+       nr = write(fd, buf, count);
+       if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
+               goto restart;
+
+       return nr;
+}
+
+ssize_t read_in_full(int fd, void *buf, size_t count)
+{
+       ssize_t total = 0;
+       char *p = buf;
+
+       while (count > 0) {
+               ssize_t nr;
+
+               nr = xread(fd, p, count);
+               if (nr <= 0) {
+                       if (total > 0)
+                               return total;
+
+                       return -1;
+               }
+
+               count -= nr;
+               total += nr;
+               p += nr;
+       }
+
+       return total;
+}
+
+ssize_t write_in_full(int fd, const void *buf, size_t count)
+{
+       const char *p = buf;
+       ssize_t total = 0;
+
+       while (count > 0) {
+               ssize_t nr;
+
+               nr = xwrite(fd, p, count);
+               if (nr < 0)
+                       return -1;
+               if (nr == 0) {
+                       errno = ENOSPC;
+                       return -1;
+               }
+               count -= nr;
+               total += nr;
+               p += nr;
+       }
+
+       return total;
+}