[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH] A different way to ask for readonly drive
From: |
Kevin Wolf |
Subject: |
Re: [Qemu-devel] [PATCH] A different way to ask for readonly drive |
Date: |
Tue, 15 Dec 2009 18:45:33 +0100 |
User-agent: |
Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.4pre) Gecko/20091014 Fedora/3.0-2.8.b4.fc11 Thunderbird/3.0b4 |
Am 14.12.2009 14:35, schrieb Naphtali Sprei:
> Hi,
> After feedback from Red Hat guys, I've decided to slightly modify the
> approach to drive's readonly.
> The new approach also addresses the silent fall-back to open the drives' file
> as read-only when read-write fails
> (permission denied) that causes unexpected behavior.
> Instead of the 'readonly' boolean flag, another flag introduced (a
> replacement), 'read_write' with three values [on|off|try]:
> read_write=on : open with read and write permission, no fall-back to read-only
> read_write=off: open with read-only permission
> read_write=try: open with read and write permission and if fails, fall-back
> to read-only (the default if nothing specified)
>
> Suggestions for better naming for flag/values welcomed.
>
> I've tried to explicitly pass the required flags for the bdrv_open function
> in callers, but probably missed some.
>
> Naphtali
>
>
>
> Signed-off-by: Naphtali Sprei <address@hidden>
> ---
> block.c | 29 +++++++++++++++++------------
> block.h | 7 +++++--
> hw/xen_disk.c | 3 ++-
> monitor.c | 2 +-
> qemu-config.c | 4 ++--
> qemu-img.c | 14 ++++++++------
> qemu-nbd.c | 2 +-
> vl.c | 42 +++++++++++++++++++++++++++++++++---------
> 8 files changed, 69 insertions(+), 34 deletions(-)
>
> diff --git a/block.c b/block.c
> index 3f3496e..75788ca 100644
> --- a/block.c
> +++ b/block.c
> @@ -356,7 +356,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename,
> int flags)
> int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
> BlockDriver *drv)
> {
> - int ret, open_flags, try_rw;
> + int ret, open_flags;
> char tmp_filename[PATH_MAX];
> char backing_filename[PATH_MAX];
>
> @@ -378,7 +378,7 @@ int bdrv_open2(BlockDriverState *bs, const char
> *filename, int flags,
>
> /* if there is a backing file, use it */
> bs1 = bdrv_new("");
> - ret = bdrv_open2(bs1, filename, 0, drv);
> + ret = bdrv_open2(bs1, filename, BDRV_O_RDONLY, drv);
> if (ret < 0) {
> bdrv_delete(bs1);
> return ret;
> @@ -445,19 +445,22 @@ int bdrv_open2(BlockDriverState *bs, const char
> *filename, int flags,
> bs->enable_write_cache = 1;
>
> /* Note: for compatibility, we open disk image files as RDWR, and
> - RDONLY as fallback */
> - try_rw = !bs->read_only || bs->is_temporary;
> - if (!(flags & BDRV_O_FILE))
> - open_flags = (try_rw ? BDRV_O_RDWR : 0) |
> - (flags & (BDRV_O_CACHE_MASK|BDRV_O_NATIVE_AIO));
> - else
> + RDONLY as fallback (if flag BDRV_O_RO_FBCK is on) */
> + bs->read_only = BDRV_FLAGS_IS_RO(flags);
> + if (!(flags & BDRV_O_FILE)) {
> + open_flags = (flags & (BDRV_O_ACCESS |
> BDRV_O_CACHE_MASK|BDRV_O_NATIVE_AIO));
> + if (bs->is_temporary) { /* snapshot */
> + open_flags |= BDRV_O_RDWR;
open_flags = (open_flags & ~BDRV_O_ACCESS) | BDRV_O_RDWR;
Yes, I know, RDONLY is 0 anyway, but still... Or move the first
open_flags line into the if and have a second one for is_temporary that
doesn't copy BDRV_O_ACCESS.
> + }
> + } else
> open_flags = flags & ~(BDRV_O_FILE | BDRV_O_SNAPSHOT);
> if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv))
> ret = -ENOTSUP;
> else
> ret = drv->bdrv_open(bs, filename, open_flags);
> - if ((ret == -EACCES || ret == -EPERM) && !(flags & BDRV_O_FILE)) {
> - ret = drv->bdrv_open(bs, filename, open_flags & ~BDRV_O_RDWR);
> + if ((ret == -EACCES || ret == -EPERM) && !(flags & BDRV_O_FILE) &&
> + (flags & BDRV_O_RO_FBCK)) {
> + ret = drv->bdrv_open(bs, filename, (open_flags & ~BDRV_O_RDWR) |
> BDRV_O_RDONLY);
Mask BDRV_O_ACCESS out, not only BDRV_O_RDWR.
> bs->read_only = 1;
> }
> if (ret < 0) {
> @@ -481,12 +484,14 @@ int bdrv_open2(BlockDriverState *bs, const char
> *filename, int flags,
> /* if there is a backing file, use it */
> BlockDriver *back_drv = NULL;
> bs->backing_hd = bdrv_new("");
> - /* pass on read_only property to the backing_hd */
> - bs->backing_hd->read_only = bs->read_only;
> path_combine(backing_filename, sizeof(backing_filename),
> filename, bs->backing_file);
> if (bs->backing_format[0] != '\0')
> back_drv = bdrv_find_format(bs->backing_format);
> + /* pass on ro flags to the backing_hd */
> + bs->backing_hd->read_only = BDRV_FLAGS_IS_RO(flags);
> + open_flags &= ~BDRV_O_ACCESS;
> + open_flags |= (flags & BDRV_O_ACCESS);
> ret = bdrv_open2(bs->backing_hd, backing_filename, open_flags,
> back_drv);
> if (ret < 0) {
> diff --git a/block.h b/block.h
> index fa51ddf..b32c6a4 100644
> --- a/block.h
> +++ b/block.h
> @@ -28,8 +28,9 @@ typedef struct QEMUSnapshotInfo {
> } QEMUSnapshotInfo;
>
> #define BDRV_O_RDONLY 0x0000
> -#define BDRV_O_RDWR 0x0002
> -#define BDRV_O_ACCESS 0x0003
> +#define BDRV_O_RDWR 0x0001
> +#define BDRV_O_ACCESS 0x0001
Is this needed? I can't see why we would need more than a flag that says
if we are read-write or not, but if you were to remove the old two-bit
field, you should do the complete cleanup. There is not reason for
BDRV_O_ACCESS to exist then any more.
In any case I don't think that saving the wasted bit belong into this
patch, so better separate it out.
> +#define BDRV_O_RO_FBCK 0x0002
Come on, we can afford the four additional letters to make it
BDRV_O_RO_FALLBACK and suddenly it becomes readable.
> #define BDRV_O_CREAT 0x0004 /* create an empty file */
> #define BDRV_O_SNAPSHOT 0x0008 /* open the file read only and save writes
> in a snapshot */
> #define BDRV_O_FILE 0x0010 /* open as a raw file (do not try to
> @@ -41,6 +42,8 @@ typedef struct QEMUSnapshotInfo {
> #define BDRV_O_NATIVE_AIO 0x0080 /* use native AIO instead of the thread
> pool */
>
> #define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_CACHE_WB)
> +#define BDRV_O_DFLT_OPEN (BDRV_O_RDWR | BDRV_O_RO_FBCK)
Same here, what's wrong with spelling DEFAULT out?
> +#define BDRV_FLAGS_IS_RO(flags) ((flags & BDRV_O_ACCESS) == BDRV_O_RDONLY)
>
> #define BDRV_SECTOR_BITS 9
> #define BDRV_SECTOR_SIZE (1 << BDRV_SECTOR_BITS)
> diff --git a/hw/xen_disk.c b/hw/xen_disk.c
> index 5c55251..13688db 100644
> --- a/hw/xen_disk.c
> +++ b/hw/xen_disk.c
> @@ -610,7 +610,8 @@ static int blk_init(struct XenDevice *xendev)
> /* read-only ? */
> if (strcmp(blkdev->mode, "w") == 0) {
> mode = O_RDWR;
> - qflags = BDRV_O_RDWR;
> + /* for compatibility, also allow readonly fallback, for now */
> + qflags = BDRV_O_RDWR | BDRV_O_RO_FBCK;
> } else {
> mode = O_RDONLY;
> qflags = BDRV_O_RDONLY;
> diff --git a/monitor.c b/monitor.c
> index d97d529..440e17e 100644
> --- a/monitor.c
> +++ b/monitor.c
> @@ -910,7 +910,7 @@ static void do_change_block(Monitor *mon, const char
> *device,
> }
> if (eject_device(mon, bs, 0) < 0)
> return;
> - bdrv_open2(bs, filename, 0, drv);
> + bdrv_open2(bs, filename, BDRV_O_DFLT_OPEN, drv);
> monitor_read_bdrv_key_start(mon, bs, NULL, NULL);
> }
>
> diff --git a/qemu-config.c b/qemu-config.c
> index c3203c8..b559459 100644
> --- a/qemu-config.c
> +++ b/qemu-config.c
> @@ -76,8 +76,8 @@ QemuOptsList qemu_drive_opts = {
> .type = QEMU_OPT_STRING,
> .help = "pci address (virtio only)",
> },{
> - .name = "readonly",
> - .type = QEMU_OPT_BOOL,
> + .name = "read_write",
> + .type = QEMU_OPT_STRING,
> },
> { /* end if list */ }
> },
> diff --git a/qemu-img.c b/qemu-img.c
> index 1d97f2e..dee3e60 100644
> --- a/qemu-img.c
> +++ b/qemu-img.c
> @@ -201,7 +201,7 @@ static BlockDriverState *bdrv_new_open(const char
> *filename,
> } else {
> drv = NULL;
> }
> - if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
> + if (bdrv_open2(bs, filename, BRDV_O_FLAGS | BDRV_O_DFLT_OPEN, drv) < 0) {
> error("Could not open '%s'", filename);
> }
> if (bdrv_is_encrypted(bs)) {
> @@ -406,7 +406,7 @@ static int img_check(int argc, char **argv)
> } else {
> drv = NULL;
> }
> - if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
> + if (bdrv_open2(bs, filename, BRDV_O_FLAGS | BDRV_O_RDONLY, drv) < 0) {
> error("Could not open '%s'", filename);
> }
> ret = bdrv_check(bs);
> @@ -465,7 +465,7 @@ static int img_commit(int argc, char **argv)
> } else {
> drv = NULL;
> }
> - if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
> + if (bdrv_open2(bs, filename, BRDV_O_FLAGS | BDRV_O_RDWR, drv) < 0) {
> error("Could not open '%s'", filename);
> }
> ret = bdrv_commit(bs);
> @@ -884,7 +884,7 @@ static int img_info(int argc, char **argv)
> } else {
> drv = NULL;
> }
> - if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
> + if (bdrv_open2(bs, filename, BRDV_O_FLAGS | BDRV_O_RDONLY, drv) < 0) {
> error("Could not open '%s'", filename);
> }
> bdrv_get_format(bs, fmt_name, sizeof(fmt_name));
> @@ -932,10 +932,11 @@ static int img_snapshot(int argc, char **argv)
> BlockDriverState *bs;
> QEMUSnapshotInfo sn;
> char *filename, *snapshot_name = NULL;
> - int c, ret;
> + int c, ret, bdrv_oflags;
> int action = 0;
> qemu_timeval tv;
>
> + bdrv_oflags = BDRV_O_RDWR; /* but no read-only fallback */
> /* Parse commandline parameters */
> for(;;) {
> c = getopt(argc, argv, "la:c:d:h");
> @@ -951,6 +952,7 @@ static int img_snapshot(int argc, char **argv)
> return 0;
> }
> action = SNAPSHOT_LIST;
> + bdrv_oflags = BDRV_O_RDONLY; /* no need for RW */
> break;
> case 'a':
> if (action) {
> @@ -988,7 +990,7 @@ static int img_snapshot(int argc, char **argv)
> if (!bs)
> error("Not enough memory");
>
> - if (bdrv_open2(bs, filename, 0, NULL) < 0) {
> + if (bdrv_open2(bs, filename, bdrv_oflags, NULL) < 0) {
Not related to your patch, but I think we want to have BRDV_O_FLAGS
here, too. And we need to get rid of that typo some time. Well, I guess
something for my own to-do list.
> error("Could not open '%s'", filename);
> }
>
> diff --git a/qemu-nbd.c b/qemu-nbd.c
> index 6cdb834..64f4c68 100644
> --- a/qemu-nbd.c
> +++ b/qemu-nbd.c
> @@ -212,7 +212,7 @@ int main(int argc, char **argv)
> int opt_ind = 0;
> int li;
> char *end;
> - int flags = 0;
> + int flags = BDRV_O_DFLT_OPEN;
> int partition = -1;
> int ret;
> int shared = 1;
> diff --git a/vl.c b/vl.c
> index c0d98f5..cef2d67 100644
> --- a/vl.c
> +++ b/vl.c
> @@ -2090,6 +2090,7 @@ DriveInfo *drive_init(QemuOpts *opts, void *opaque,
> int *fatal_error)
> {
> const char *buf;
> + const char *rw_buf = 0;
> const char *file = NULL;
> char devname[128];
> const char *serial;
> @@ -2104,12 +2105,12 @@ DriveInfo *drive_init(QemuOpts *opts, void *opaque,
> int index;
> int cache;
> int aio = 0;
> - int ro = 0;
> int bdrv_flags;
> int on_read_error, on_write_error;
> const char *devaddr;
> DriveInfo *dinfo;
> int snapshot = 0;
> + int read_write, ro_fallback;
>
> *fatal_error = 1;
>
> @@ -2137,7 +2138,7 @@ DriveInfo *drive_init(QemuOpts *opts, void *opaque,
> secs = qemu_opt_get_number(opts, "secs", 0);
>
> snapshot = qemu_opt_get_bool(opts, "snapshot", 0);
> - ro = qemu_opt_get_bool(opts, "readonly", 0);
> + rw_buf = qemu_opt_get(opts, "read_write");
>
> file = qemu_opt_get(opts, "file");
> serial = qemu_opt_get(opts, "serial");
> @@ -2420,6 +2421,29 @@ DriveInfo *drive_init(QemuOpts *opts, void *opaque,
> *fatal_error = 0;
> return NULL;
> }
> +
> + read_write = 1;
> + ro_fallback = 1;
> + if (rw_buf) {
> + if (!strcmp(rw_buf, "off")) {
> + read_write = 0;
> + ro_fallback = 0;
> + if (type != IF_SCSI && type != IF_VIRTIO && type != IF_FLOPPY) {
> + fprintf(stderr, "qemu: read_write=off flag not supported for
> drive of this interface\n");
> + return NULL;
> + }
> + } else if (!strcmp(rw_buf, "on")) {
> + read_write = 1;
> + ro_fallback = 0;
> + } else if (!strcmp(rw_buf, "try")) { /* default, but keep it
> explicit */
> + read_write = 1;
> + ro_fallback = 1;
We probably should have the check or SCSI/virtio/floppy here, too. If
the user explicitly requests that we should try read-only and it's not
available with the device I think that's a reason to exit with an error.
> + } else {
> + fprintf(stderr, "qemu: '%s' invalid read_write option (valid
> values: [on|off|try] )\n", buf);
> + return NULL;
> + }
> + }
> +
> bdrv_flags = 0;
> if (snapshot) {
> bdrv_flags |= BDRV_O_SNAPSHOT;
> @@ -2436,16 +2460,16 @@ DriveInfo *drive_init(QemuOpts *opts, void *opaque,
> bdrv_flags &= ~BDRV_O_NATIVE_AIO;
> }
>
> - if (ro == 1) {
> - if (type == IF_IDE) {
> - fprintf(stderr, "qemu: readonly flag not supported for drive
> with ide interface\n");
> - return NULL;
> - }
> - (void)bdrv_set_read_only(dinfo->bdrv, 1);
> + if (read_write) {
> + bdrv_flags |= BDRV_O_RDWR;
> + }
If BDRV_O_ACCESS continues to exist, BDRV_O_RDWR is not a flag but a
value for that field. To make things clearer, I'd prefer something like
this then:
/* Set BDRV_O_ACCESS value */
bdrv_flags |= read_write ? BDRV_O_RDWR : BDRV_O_RDONLY;
> + if (ro_fallback) {
> + bdrv_flags |= BDRV_O_RO_FBCK;
> }
> +
>
> if (bdrv_open2(dinfo->bdrv, file, bdrv_flags, drv) < 0) {
> - fprintf(stderr, "qemu: could not open disk image %s: %s\n",
> + fprintf(stderr, "qemu: could not open disk image %s with requested
> permission: %s\n",
> file, strerror(errno));
> return NULL;
> }
Kevin
- [Qemu-devel] [PATCH] A different way to ask for readonly drive, Naphtali Sprei, 2009/12/14
- Re: [Qemu-devel] [PATCH] A different way to ask for readonly drive, Stefan Weil, 2009/12/14
- Re: [Qemu-devel] [PATCH] A different way to ask for readonly drive, Jamie Lokier, 2009/12/15
- Re: [Qemu-devel] [PATCH] A different way to ask for readonly drive, Stefan Weil, 2009/12/15
- Re: [Qemu-devel] [PATCH] A different way to ask for readonly drive, Christoph Hellwig, 2009/12/17
- Re: [Qemu-devel] [PATCH] A different way to ask for readonly drive, Jamie Lokier, 2009/12/17
- Re: [Qemu-devel] [PATCH] A different way to ask for readonly drive, Kevin Wolf, 2009/12/17
- Re: [Qemu-devel] [PATCH] A different way to ask for readonly drive, Jamie Lokier, 2009/12/17
- Re: [Qemu-devel] [PATCH] A different way to ask for readonly drive, Markus Armbruster, 2009/12/17
Re: [Qemu-devel] [PATCH] A different way to ask for readonly drive,
Kevin Wolf <=
Re: [Qemu-devel] [PATCH] A different way to ask for readonly drive, Richard W.M. Jones, 2009/12/17