From c4d7847b220c2cccfc0cf6c4d78da631b3edcd6b Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Thu, 31 Mar 2011 11:50:09 +0300 Subject: [PATCH] kvm tools: Fix large disk images on 32-bit 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 Tested-by: Cyrill Gorcunov Signed-off-by: Pekka Enberg --- Makefile | 4 ++ disk-image.c | 38 ++++++------------- include/kvm/disk-image.h | 1 - include/kvm/read-write.h | 13 +++++++ read-write.c | 79 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 108 insertions(+), 27 deletions(-) create mode 100644 include/kvm/read-write.h create mode 100644 read-write.c diff --git a/Makefile b/Makefile index 2d3f476..bfb3dee 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/disk-image.c b/disk-image.c index 7aca1cc..6780008 100644 --- a/disk-image.c +++ b/disk-image.c @@ -1,5 +1,6 @@ #include "kvm/disk-image.h" +#include "kvm/read-write.h" #include "kvm/util.h" #include @@ -12,19 +13,6 @@ #include #include -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; } diff --git a/include/kvm/disk-image.h b/include/kvm/disk-image.h index 25b31d6..0599fc7 100644 --- a/include/kvm/disk-image.h +++ b/include/kvm/disk-image.h @@ -7,7 +7,6 @@ #define SECTOR_SIZE (1UL << SECTOR_SHIFT) struct disk_image { - void *mmap; int fd; uint64_t size; }; diff --git a/include/kvm/read-write.h b/include/kvm/read-write.h new file mode 100644 index 0000000..a49394b --- /dev/null +++ b/include/kvm/read-write.h @@ -0,0 +1,13 @@ +#ifndef KVM_READ_WRITE_H +#define KVM_READ_WRITE_H + +#include +#include + +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/read-write.c b/read-write.c new file mode 100644 index 0000000..46b147d --- /dev/null +++ b/read-write.c @@ -0,0 +1,79 @@ +#include "kvm/read-write.h" + +#include +#include +#include +#include + +/* 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; +}