mirror of
https://github.com/clearlinux/kvmtool.git
synced 2026-09-05 21:21:54 +00:00
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 <asias.hejun@gmail.com> Tested-by: Cyrill Gorcunov <gorcunov@gmail.com> Signed-off-by: Pekka Enberg <penberg@kernel.org>
This commit is contained in:
committed by
Will Deacon
parent
db34045c54
commit
c4d7847b22
@@ -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
|
||||
|
||||
+12
-26
@@ -1,5 +1,6 @@
|
||||
#include "kvm/disk-image.h"
|
||||
|
||||
#include "kvm/read-write.h"
|
||||
#include "kvm/util.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
@@ -12,19 +13,6 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#define SECTOR_SIZE (1UL << SECTOR_SHIFT)
|
||||
|
||||
struct disk_image {
|
||||
void *mmap;
|
||||
int fd;
|
||||
uint64_t size;
|
||||
};
|
||||
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user