diff mbox

kvm tools: Add option to load disk image read only

Message ID 1302608571-28504-1-git-send-email-levinsasha928@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Sasha Levin April 12, 2011, 11:42 a.m. UTC
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>
---
 tools/kvm/disk-image.c             |   52 +++++++++++++++++++++++++++++++----
 tools/kvm/include/kvm/disk-image.h |    5 ++-
 tools/kvm/kvm-run.c                |    5 +++-
 3 files changed, 53 insertions(+), 9 deletions(-)
diff mbox

Patch

diff --git a/tools/kvm/disk-image.c b/tools/kvm/disk-image.c
index 9deaf45..0f6ddfe 100644
--- a/tools/kvm/disk-image.c
+++ b/tools/kvm/disk-image.c
@@ -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,14 @@  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 +62,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;
 
@@ -93,6 +130,9 @@  void disk_image__close(struct disk_image *self)
 	/* If there was no disk image then there's nothing to do: */
 	if (!self)
 		return;
+	
+	if (self->priv != MAP_FAILED)
+		munmap(self->priv, self->size);
 
 	if (self->ops->close)
 		self->ops->close(self);
diff --git a/tools/kvm/include/kvm/disk-image.h b/tools/kvm/include/kvm/disk-image.h
index df0a15d..91240c2 100644
--- a/tools/kvm/include/kvm/disk-image.h
+++ b/tools/kvm/include/kvm/disk-image.h
@@ -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)
diff --git a/tools/kvm/kvm-run.c b/tools/kvm/kvm-run.c
index 8f6ebdc..ba02172 100644
--- a/tools/kvm/kvm-run.c
+++ b/tools/kvm/kvm-run.c
@@ -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);
 	}