kvm tools: Add option to load disk image read only

As suggested by Christoph Hellwig and Pekka Enberg, Add a '--readonly' flag to
prevent runtime changes to the disk to be saved in the image file.  Please note
that since the changes are saved in the VM instead of being written out, a
large amount of modified blocks may kill the tool.

Signed-off-by: Sasha Levin <levinsasha928@gmail.com>
Signed-off-by: Pekka Enberg <penberg@kernel.org>
This commit is contained in:
Sasha Levin
2015-06-01 16:39:42 +01:00
committed by Will Deacon
parent fffb37a932
commit 9ac38fe149
3 changed files with 51 additions and 9 deletions
+44 -6
View File
@@ -13,7 +13,7 @@
#include <unistd.h>
#include <fcntl.h>
struct disk_image *disk_image__new(int fd, uint64_t size, struct disk_image_operations *ops)
struct disk_image *disk_image__new(int fd, uint64_t size, struct disk_image_operations *ops, bool readonly)
{
struct disk_image *self;
@@ -24,6 +24,12 @@ struct disk_image *disk_image__new(int fd, uint64_t size, struct disk_image_oper
self->fd = fd;
self->size = size;
self->ops = ops;
if (readonly) {
self->priv = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_NORESERVE, fd, 0);
if (self->priv == MAP_FAILED)
die("mmap() failed");
} else
self->priv = MAP_FAILED;
return self;
}
@@ -54,31 +60,60 @@ static int raw_image__write_sector(struct disk_image *self, uint64_t sector, voi
return 0;
}
static int raw_image__read_sector_ro_mmap(struct disk_image *self, uint64_t sector, void *dst, uint32_t dst_len)
{
uint64_t offset = sector << SECTOR_SHIFT;
if (offset + dst_len > self->size)
return -1;
memcpy(dst, self->priv + offset, dst_len);
return 0;
}
static int raw_image__write_sector_ro_mmap(struct disk_image *self, uint64_t sector, void *src, uint32_t src_len)
{
uint64_t offset = sector << SECTOR_SHIFT;
if (offset + src_len > self->size)
return -1;
memcpy(self->priv + offset, src, src_len);
return 0;
}
static struct disk_image_operations raw_image_ops = {
.read_sector = raw_image__read_sector,
.write_sector = raw_image__write_sector,
};
static struct disk_image *raw_image__probe(int fd)
static struct disk_image_operations raw_image_ro_mmap_ops = {
.read_sector = raw_image__read_sector_ro_mmap,
.write_sector = raw_image__write_sector_ro_mmap,
};
static struct disk_image *raw_image__probe(int fd, bool readonly)
{
struct stat st;
if (fstat(fd, &st) < 0)
return NULL;
return disk_image__new(fd, st.st_size, &raw_image_ops);
return disk_image__new(fd, st.st_size, readonly ? &raw_image_ro_mmap_ops : &raw_image_ops, readonly);
}
struct disk_image *disk_image__open(const char *filename)
struct disk_image *disk_image__open(const char *filename, bool readonly)
{
struct disk_image *self;
int fd;
fd = open(filename, O_RDWR);
fd = open(filename, readonly ? O_RDONLY : O_RDWR);
if (fd < 0)
return NULL;
self = raw_image__probe(fd);
self = raw_image__probe(fd, readonly);
if (self)
return self;
@@ -94,6 +129,9 @@ void disk_image__close(struct disk_image *self)
if (!self)
return;
if (self->priv != MAP_FAILED)
munmap(self->priv, self->size);
if (self->ops->close)
self->ops->close(self);
+3 -2
View File
@@ -2,6 +2,7 @@
#define KVM__DISK_IMAGE_H
#include <stdint.h>
#include <stdbool.h>
#define SECTOR_SHIFT 9
#define SECTOR_SIZE (1UL << SECTOR_SHIFT)
@@ -21,8 +22,8 @@ struct disk_image {
void *priv;
};
struct disk_image *disk_image__open(const char *filename);
struct disk_image *disk_image__new(int fd, uint64_t size, struct disk_image_operations *ops);
struct disk_image *disk_image__open(const char *filename, bool readonly);
struct disk_image *disk_image__new(int fd, uint64_t size, struct disk_image_operations *ops, bool readonly);
void disk_image__close(struct disk_image *self);
static inline int disk_image__read_sector(struct disk_image *self, uint64_t sector, void *dst, uint32_t dst_len)
+4 -1
View File
@@ -61,6 +61,7 @@ static const char *image_filename;
static const char *console;
static const char *kvm_dev;
static bool single_step;
static bool readonly_image;
extern bool ioport_debug;
extern int active_console;
@@ -80,6 +81,8 @@ static const struct option options[] = {
OPT_STRING('k', "kernel", &kernel_filename, "kernel",
"Kernel to boot in virtual machine"),
OPT_STRING('i', "image", &image_filename, "image", "Disk image"),
OPT_BOOLEAN('\0', "readonly", &readonly_image,
"Don't write changes back to disk image"),
OPT_STRING('d', "kvm-dev", &kvm_dev, "kvm-dev", "KVM device file"),
OPT_BOOLEAN('s', "single-step", &single_step,
"Enable single stepping"),
@@ -183,7 +186,7 @@ int kvm_cmd_run(int argc, const char **argv, const char *prefix)
kvm = kvm__init(kvm_dev, ram_size);
if (image_filename) {
kvm->disk_image = disk_image__open(image_filename);
kvm->disk_image = disk_image__open(image_filename, readonly_image);
if (!kvm->disk_image)
die("unable to load disk image %s", image_filename);
}