On 10.11.2019 22:03, Denis Plotnikov wrote: > This allows to change (replace) the file on a block device and is useful > to workaround exclusive file access restrictions, e.g. to implement VM > migration with a shared disk stored on some storage with the exclusive > file opening model: a destination VM is started waiting for incomming > migration with a fake image drive, and later, on the last migration > phase, the fake image file is replaced with the real one. > > Signed-off-by: Denis Plotnikov <dplotni...@virtuozzo.com> > --- > hw/core/qdev-properties-system.c | 89 +++++++++++++++++++++++++++----- > 1 file changed, 77 insertions(+), 12 deletions(-) > > diff --git a/hw/core/qdev-properties-system.c > b/hw/core/qdev-properties-system.c > index c534590dcd..aaab1370a4 100644 > --- a/hw/core/qdev-properties-system.c > +++ b/hw/core/qdev-properties-system.c > @@ -79,8 +79,55 @@ static void set_pointer(Object *obj, Visitor *v, Property > *prop, > > /* --- drive --- */ > > -static void do_parse_drive(DeviceState *dev, const char *str, void **ptr, > - const char *propname, bool iothread, Error **errp) > +static void do_parse_drive_realized(DeviceState *dev, const char *str, > + void **ptr, const char *propname, > + bool iothread, Error **errp) > +{ > + BlockBackend *blk = *ptr; > + BlockDriverState *bs = bdrv_lookup_bs(NULL, str, NULL); > + int ret; > + bool blk_created = false; > + > + if (!bs) { > + error_setg(errp, "Can't find blockdev '%s'", str); > + return; > + } > + > + if (!blk) { > + AioContext *ctx = iothread ? bdrv_get_aio_context(bs) : > + qemu_get_aio_context(); > + blk = blk_new(ctx, BLK_PERM_ALL, BLK_PERM_ALL); > + blk_created = true;
Actually, I have concerns about situation where blk=null. Is there any case when scsi-hd (or others) doesn't have a blk assigned and it's legal? > + } else { > + if (blk_bs(blk)) { > + blk_remove_bs(blk); > + } > + } > + > + ret = blk_insert_bs(blk, bs, errp); > + > + if (!ret && blk_created) { > + if (blk_attach_dev(blk, dev) < 0) { > + /* > + * Shouldn't be any errors here since we just created > + * the new blk because the device doesn't have any. > + * Leave the message here in case blk_attach_dev is changed > + */ > + error_setg(errp, "Can't attach drive '%s' to device '%s'", > + str, object_get_typename(OBJECT(dev))); > + } else { > + *ptr = blk; > + } > + } > + > + if (blk_created) { > + blk_unref(blk); > + } > +} > + > +static void do_parse_drive_unrealized(DeviceState *dev, const char *str, > + void **ptr, const char *propname, > + bool iothread, Error **errp) > { > BlockBackend *blk; > bool blk_created = false; > @@ -137,18 +184,34 @@ fail: > } > } > > -static void parse_drive(DeviceState *dev, const char *str, void **ptr, > - const char *propname, Error **errp) > -{ > - do_parse_drive(dev, str, ptr, propname, false, errp); > -} > - > -static void parse_drive_iothread(DeviceState *dev, const char *str, void > **ptr, > +static void parse_drive_realized(DeviceState *dev, const char *str, void > **ptr, > const char *propname, Error **errp) > { > - do_parse_drive(dev, str, ptr, propname, true, errp); > + do_parse_drive_realized(dev, str, ptr, propname, false, errp); > } > > +static void parse_drive_realized_iothread(DeviceState *dev, const char *str, > + void **ptr, const char *propname, > + Error **errp) > +{ > + do_parse_drive_realized(dev, str, ptr, propname, true, errp); > +} > + > +static void parse_drive_unrealized(DeviceState *dev, const char *str, > + void **ptr, const char *propname, > + Error **errp) > +{ > + do_parse_drive_unrealized(dev, str, ptr, propname, false, errp); > +} > + > +static void parse_drive_unrealized_iothread(DeviceState *dev, const char > *str, > + void **ptr, const char *propname, > + Error **errp) > +{ > + do_parse_drive_unrealized(dev, str, ptr, propname, true, errp); > +} > + > + > static void release_drive(Object *obj, const char *name, void *opaque) > { > DeviceState *dev = DEVICE(obj); > @@ -188,13 +251,15 @@ static void get_drive(Object *obj, Visitor *v, const > char *name, void *opaque, > static void set_drive(Object *obj, Visitor *v, const char *name, void > *opaque, > Error **errp) > { > - set_pointer(obj, v, opaque, NULL, parse_drive, name, errp); > + set_pointer(obj, v, opaque, parse_drive_realized, parse_drive_unrealized, > + name, errp); > } > > static void set_drive_iothread(Object *obj, Visitor *v, const char *name, > void *opaque, Error **errp) > { > - set_pointer(obj, v, opaque, NULL, parse_drive_iothread, name, errp); > + set_pointer(obj, v, opaque, parse_drive_realized_iothread, > + parse_drive_unrealized_iothread, name, errp); > } > > const PropertyInfo qdev_prop_drive = {