From patchwork Tue Apr 12 11:42:51 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sasha Levin X-Patchwork-Id: 699831 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p3CBhERh002304 for ; Tue, 12 Apr 2011 11:43:14 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752224Ab1DLLnL (ORCPT ); Tue, 12 Apr 2011 07:43:11 -0400 Received: from mail-wy0-f174.google.com ([74.125.82.174]:53748 "EHLO mail-wy0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750720Ab1DLLnJ (ORCPT ); Tue, 12 Apr 2011 07:43:09 -0400 Received: by wya21 with SMTP id 21so5602207wya.19 for ; Tue, 12 Apr 2011 04:43:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:from:to:cc:subject:date:message-id:x-mailer; bh=KCPsN8dXcHcQL7QEaBHG6PRyr/4x7WBBW5Mt2L/oZH8=; b=ZPgZbyXg2KX/espu4L+o03pjFgQiudo4LQWThBP2Ess1I484Dmhluj81R1m33YtNSB 28kjdHXaRrs0YuJqaeNRuUUaUJ6DuP4EF+l8ldeEFNHWpBgufMeO61nqvGPWFcM/SMjO 3EOxLyHX5BQXhC83ccQshtpzWOfg3IUNxeYhU= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer; b=kvKp7OcKwIgUuJ9c6+1IYTK4+eqZ81ZV2wVMXQIiFJfOyUtvqnsjf0BJ9yuJzi/DrB U+6guZOE/GE2Hk+8t9HjpvBlJunzHUMMGpU0gYv4TJ10la8OjI7/gI0BhxJ5Hbhg6LJ8 ftgfE/CskT7P7NRjz8KDxoXBXkJl51gZN6qZE= Received: by 10.227.36.203 with SMTP id u11mr6770650wbd.162.1302608588142; Tue, 12 Apr 2011 04:43:08 -0700 (PDT) Received: from localhost.localdomain ([94.230.81.151]) by mx.google.com with ESMTPS id x1sm3978904wbh.19.2011.04.12.04.43.06 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 12 Apr 2011 04:43:07 -0700 (PDT) From: Sasha Levin To: penberg@kernel.org Cc: hch@infradead.org, kvm@vger.kernel.org, Sasha Levin Subject: [PATCH] kvm tools: Add option to load disk image read only Date: Tue, 12 Apr 2011 14:42:51 +0300 Message-Id: <1302608571-28504-1-git-send-email-levinsasha928@gmail.com> X-Mailer: git-send-email 1.7.5.rc1 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Tue, 12 Apr 2011 11:43:14 +0000 (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 --- 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 --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 #include -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 +#include #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); }