From 1da9bf2f6b56e814f6e26465f79c16c2b7455aca Mon Sep 17 00:00:00 2001 From: Naphtali Sprei <nsprei@redhat.com> Date: Thu, 15 Apr 2010 11:56:45 -0300 Subject: [PATCH 09/12] read-only: Open backing file read-only where possible RH-Author: Naphtali Sprei <nsprei@redhat.com> Message-id: <1271332608-5243-9-git-send-email-nsprei@redhat.com> Patchwork-id: 8656 O-Subject: [RHEL 5.6 kvm PATCH v4 08/11] read-only: Open backing file read-only where possible Bugzilla: 510630 RH-Acked-by: Kevin Wolf <kwolf@redhat.com> RH-Acked-by: Christoph Hellwig <chellwig@redhat.com> RH-Acked-by: Juan Quintela <quintela@redhat.com> Open backing file read-only where possible Upgrade backing file to read-write during commit, back to read-only after commit If upgrade fail, back to read-only. If also fail, "disconnect" the drive. based on upstream commit: 4dca4b639cb20fee38f6eec0a391aecc0ad8848d Signed-off-by: Naphtali Sprei <nsprei@redhat.com> --- qemu/block.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++------ qemu/block_int.h | 2 + 2 files changed, 71 insertions(+), 9 deletions(-) Signed-off-by: Eduardo Habkost <ehabkost@redhat.com> --- qemu/block.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++------ qemu/block_int.h | 2 + 2 files changed, 71 insertions(+), 9 deletions(-) diff --git a/qemu/block.c b/qemu/block.c index cfbd3da..fb6c657 100644 --- a/qemu/block.c +++ b/qemu/block.c @@ -392,6 +392,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, bs->read_only = 0; bs->is_temporary = 0; bs->encrypted = 0; + bs->open_flags = flags; if (flags & BDRV_O_SNAPSHOT) { BlockDriverState *bs1; @@ -476,7 +477,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, ret = -ENOTSUP; else ret = drv->bdrv_open(bs, filename, open_flags); - bs->read_only = !(open_flags & BDRV_O_RDWR); + bs->keep_read_only = bs->read_only = !(open_flags & BDRV_O_RDWR); if (ret < 0) { qemu_free(bs->opaque); bs->opaque = NULL; @@ -504,11 +505,19 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, filename, bs->backing_file); if (bs->backing_format[0] != '\0') back_drv = bdrv_find_format(bs->backing_format); - open_flags = (flags & (BDRV_O_CACHE_MASK | BDRV_O_RDWR)); + /* backing files always opened read-only */ + open_flags &= ~BDRV_O_RDWR; ret = bdrv_open2(bs->backing_hd, backing_filename, open_flags, back_drv); if (ret < 0) goto fail; + + if (bs->is_temporary) { + bs->backing_hd->keep_read_only = !(flags & BDRV_O_RDWR); + } else { + /* base image inherits from "parent" */ + bs->backing_hd->keep_read_only = bs->keep_read_only; + } } /* call the change callback */ @@ -575,17 +584,48 @@ int bdrv_commit(BlockDriverState *bs) BlockDriver *drv = bs->drv; int64_t i, total_sectors; int n, j; + int ro, open_flags; + int ret = 0, rw_ret = 0; + char filename[1024]; + BlockDriverState *bs_rw, *bs_ro; unsigned char sector[512]; if (!drv) return -ENOMEDIUM; - if (bs->read_only) { - return -EACCES; + if (!bs->backing_hd) { + return -ENOTSUP; } - if (!bs->backing_hd) { - return -ENOTSUP; + if (bs->backing_hd->keep_read_only) { + return -EACCES; + } + + ro = bs->backing_hd->read_only; + strncpy(filename, bs->backing_hd->filename, sizeof(filename)); + open_flags = bs->backing_hd->open_flags; + + if (ro) { + /* re-open as RW */ + bdrv_delete(bs->backing_hd); + bs->backing_hd = NULL; + bs_rw = bdrv_new(""); + rw_ret = bdrv_open2(bs_rw, filename, open_flags | BDRV_O_RDWR, NULL); + if (rw_ret < 0) { + bdrv_delete(bs_rw); + /* try to re-open read-only */ + bs_ro = bdrv_new(""); + ret = bdrv_open2(bs_ro, filename, open_flags & ~BDRV_O_RDWR, NULL); + if (ret < 0) { + bdrv_delete(bs_ro); + /* drive not functional anymore */ + bs->drv = NULL; + return ret; + } + bs->backing_hd = bs_ro; + return rw_ret; + } + bs->backing_hd = bs_rw; } total_sectors = bdrv_getlength(bs) >> SECTOR_BITS; @@ -593,11 +633,13 @@ int bdrv_commit(BlockDriverState *bs) if (drv->bdrv_is_allocated(bs, i, 65536, &n)) { for(j = 0; j < n; j++) { if (bdrv_read(bs, i, sector, 1) != 0) { - return -EIO; + ret = -EIO; + goto ro_cleanup; } if (bdrv_write(bs->backing_hd, i, sector, 1) != 0) { - return -EIO; + ret = -EIO; + goto ro_cleanup; } i++; } @@ -607,7 +649,25 @@ int bdrv_commit(BlockDriverState *bs) } if (drv->bdrv_make_empty) - return drv->bdrv_make_empty(bs); + ret = drv->bdrv_make_empty(bs); + +ro_cleanup: + + if (ro) { + /* re-open as RO */ + bdrv_delete(bs->backing_hd); + bs->backing_hd = NULL; + bs_ro = bdrv_new(""); + ret = bdrv_open2(bs_ro, filename, open_flags & ~BDRV_O_RDWR, NULL); + if (ret < 0) { + bdrv_delete(bs_ro); + /* drive not functional anymore */ + bs->drv = NULL; + return ret; + } + bs->backing_hd = bs_ro; + bs->backing_hd->keep_read_only = 0; + } return 0; } diff --git a/qemu/block_int.h b/qemu/block_int.h index 2f8093c..634c29b 100644 --- a/qemu/block_int.h +++ b/qemu/block_int.h @@ -112,6 +112,8 @@ struct BlockDriverState { int64_t total_sectors; /* if we are reading a disk image, give its size in sectors */ int read_only; /* if true, the media is read only */ + int keep_read_only; /* if true, the media was requested to stay read only */ + int open_flags; /* flags used to open the file, re-used for re-open */ int removable; /* if true, the media can be removed */ int locked; /* if true, the media cannot temporarily be ejected */ int encrypted; /* if true, the media is encrypted */ -- 1.7.0.3