Patchwork [RFT,2/5] virtio: Convert VirtioDevice to QOM realize/unrealize

login
register
mail settings
Submitter Andreas Färber
Date June 7, 2013, 6:18 p.m.
Message ID <1370629140-30841-3-git-send-email-afaerber@suse.de>
Download mbox | patch
Permalink /patch/249786/
State New
Headers show

Comments

Andreas Färber - June 7, 2013, 6:18 p.m.
VirtioDevice's DeviceClass::exit code cleaning up bus_name is no longer
overwritten by virtio-{blk,serial,net,scsi,balloon,rng} and vhost-scsi.

Note: VirtIOSCSI and VHostSCSI now perform some initializations after
VirtIOSCSICommon's realize calls virtio_bus_plug_device(), namely
creating the SCSIBus and initializing /dev/vhost-scsi respectively.

While at it, drop duplicate VIRTIO_DEVICE() casts and avoid qdev.

Signed-off-by: Andreas Färber <afaerber@suse.de>
---
 hw/9pfs/virtio-9p-device.c         | 67 ++++++++++++++++--------------
 hw/9pfs/virtio-9p.h                | 13 ++++++
 hw/block/virtio-blk.c              | 52 ++++++++++++++---------
 hw/char/virtio-serial-bus.c        | 49 ++++++++++++++--------
 hw/net/virtio-net.c                | 48 ++++++++++++---------
 hw/scsi/vhost-scsi.c               | 59 +++++++++++++++-----------
 hw/scsi/virtio-scsi.c              | 85 ++++++++++++++++++++++++--------------
 hw/virtio/virtio-balloon.c         | 50 +++++++++++++---------
 hw/virtio/virtio-rng.c             | 53 ++++++++++++++----------
 hw/virtio/virtio.c                 | 20 ++++-----
 include/hw/virtio/vhost-scsi.h     | 13 ++++++
 include/hw/virtio/virtio-balloon.h | 13 ++++++
 include/hw/virtio/virtio-blk.h     | 13 ++++++
 include/hw/virtio/virtio-net.h     | 13 ++++++
 include/hw/virtio/virtio-rng.h     | 13 ++++++
 include/hw/virtio/virtio-scsi.h    | 29 +++++++++++--
 include/hw/virtio/virtio-serial.h  | 13 ++++++
 include/hw/virtio/virtio.h         |  6 ++-
 18 files changed, 406 insertions(+), 203 deletions(-)
Michael S. Tsirkin - June 9, 2013, 10:36 a.m.
On Fri, Jun 07, 2013 at 08:18:57PM +0200, Andreas Färber wrote:
> VirtioDevice's DeviceClass::exit code cleaning up bus_name is no longer
> overwritten by virtio-{blk,serial,net,scsi,balloon,rng} and vhost-scsi.
> 
> Note: VirtIOSCSI and VHostSCSI now perform some initializations after
> VirtIOSCSICommon's realize calls virtio_bus_plug_device(), namely
> creating the SCSIBus and initializing /dev/vhost-scsi respectively.
> 
> While at it, drop duplicate VIRTIO_DEVICE() casts and avoid qdev.

There are also improvements to error handling here, they can
be done by a separate patch.

Please don't mix refactoring and functional changes -
this patch is huge as it is.

Also, could changes to each device be done in a separate patch?
This last might be hard, not a must IMO.

> Signed-off-by: Andreas Färber <afaerber@suse.de>
> ---
>  hw/9pfs/virtio-9p-device.c         | 67 ++++++++++++++++--------------
>  hw/9pfs/virtio-9p.h                | 13 ++++++
>  hw/block/virtio-blk.c              | 52 ++++++++++++++---------
>  hw/char/virtio-serial-bus.c        | 49 ++++++++++++++--------
>  hw/net/virtio-net.c                | 48 ++++++++++++---------
>  hw/scsi/vhost-scsi.c               | 59 +++++++++++++++-----------
>  hw/scsi/virtio-scsi.c              | 85 ++++++++++++++++++++++++--------------
>  hw/virtio/virtio-balloon.c         | 50 +++++++++++++---------
>  hw/virtio/virtio-rng.c             | 53 ++++++++++++++----------
>  hw/virtio/virtio.c                 | 20 ++++-----
>  include/hw/virtio/vhost-scsi.h     | 13 ++++++
>  include/hw/virtio/virtio-balloon.h | 13 ++++++
>  include/hw/virtio/virtio-blk.h     | 13 ++++++
>  include/hw/virtio/virtio-net.h     | 13 ++++++
>  include/hw/virtio/virtio-rng.h     | 13 ++++++
>  include/hw/virtio/virtio-scsi.h    | 29 +++++++++++--
>  include/hw/virtio/virtio-serial.h  | 13 ++++++
>  include/hw/virtio/virtio.h         |  6 ++-
>  18 files changed, 406 insertions(+), 203 deletions(-)
> 
> diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
> index dc6f4e4..409d315 100644
> --- a/hw/9pfs/virtio-9p-device.c
> +++ b/hw/9pfs/virtio-9p-device.c
> @@ -41,15 +41,17 @@ static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config)
>      g_free(cfg);
>  }
>  
> -static int virtio_9p_device_init(VirtIODevice *vdev)
> +static void virtio_9p_device_realize(DeviceState *dev, Error **errp)
>  {
> -    V9fsState *s = VIRTIO_9P(vdev);
> +    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
> +    V9fsState *s = VIRTIO_9P(dev);
> +    V9fsClass *v9c = VIRTIO_9P_GET_CLASS(dev);
>      int i, len;
>      struct stat stat;
>      FsDriverEntry *fse;
>      V9fsPath path;
>  
> -    virtio_init(VIRTIO_DEVICE(s), "virtio-9p", VIRTIO_ID_9P,
> +    virtio_init(vdev, "virtio-9p", VIRTIO_ID_9P,
>                  sizeof(struct virtio_9p_config) + MAX_TAG_LEN);
>  
>      /* initialize pdu allocator */
> @@ -65,17 +67,17 @@ static int virtio_9p_device_init(VirtIODevice *vdev)
>  
>      if (!fse) {
>          /* We don't have a fsdev identified by fsdev_id */
> -        fprintf(stderr, "Virtio-9p device couldn't find fsdev with the "
> -                "id = %s\n",
> -                s->fsconf.fsdev_id ? s->fsconf.fsdev_id : "NULL");
> -        return -1;
> +        error_setg(errp, "Virtio-9p device couldn't find fsdev with the "
> +                   "id = %s",
> +                   s->fsconf.fsdev_id ? s->fsconf.fsdev_id : "NULL");
> +        return;
>      }
>  
>      if (!s->fsconf.tag) {
>          /* we haven't specified a mount_tag */
> -        fprintf(stderr, "fsdev with id %s needs mount_tag arguments\n",
> -                s->fsconf.fsdev_id);
> -        return -1;
> +        error_setg(errp, "fsdev with id %s needs mount_tag arguments",
> +                   s->fsconf.fsdev_id);
> +        return;
>      }
>  
>      s->ctx.export_flags = fse->export_flags;
> @@ -83,9 +85,9 @@ static int virtio_9p_device_init(VirtIODevice *vdev)
>      s->ctx.exops.get_st_gen = NULL;
>      len = strlen(s->fsconf.tag);
>      if (len > MAX_TAG_LEN - 1) {
> -        fprintf(stderr, "mount tag '%s' (%d bytes) is longer than "
> -                "maximum (%d bytes)", s->fsconf.tag, len, MAX_TAG_LEN - 1);
> -        return -1;
> +        error_setg(errp, "mount tag '%s' (%d bytes) is longer than "
> +                   "maximum (%d bytes)", s->fsconf.tag, len, MAX_TAG_LEN - 1);
> +        return;
>      }
>  
>      s->tag = strdup(s->fsconf.tag);
> @@ -97,13 +99,13 @@ static int virtio_9p_device_init(VirtIODevice *vdev)
>      qemu_co_rwlock_init(&s->rename_lock);
>  
>      if (s->ops->init(&s->ctx) < 0) {
> -        fprintf(stderr, "Virtio-9p Failed to initialize fs-driver with id:%s"
> -                " and export path:%s\n", s->fsconf.fsdev_id, s->ctx.fs_root);
> -        return -1;
> +        error_setg(errp, "Virtio-9p Failed to initialize fs-driver with id:%s"
> +                   " and export path:%s", s->fsconf.fsdev_id, s->ctx.fs_root);
> +        return;
>      }
>      if (v9fs_init_worker_threads() < 0) {
> -        fprintf(stderr, "worker thread initialization failed\n");
> -        return -1;
> +        error_setg(errp, "worker thread initialization failed");
> +        return;
>      }
>  
>      /*
> @@ -113,20 +115,20 @@ static int virtio_9p_device_init(VirtIODevice *vdev)
>       */
>      v9fs_path_init(&path);
>      if (s->ops->name_to_path(&s->ctx, NULL, "/", &path) < 0) {
> -        fprintf(stderr,
> -                "error in converting name to path %s", strerror(errno));
> -        return -1;
> +        error_setg(errp,
> +                   "error in converting name to path %s", strerror(errno));
> +        return;
>      }
>      if (s->ops->lstat(&s->ctx, &path, &stat)) {
> -        fprintf(stderr, "share path %s does not exist\n", fse->path);
> -        return -1;
> +        error_setg(errp, "share path %s does not exist", fse->path);
> +        return;
>      } else if (!S_ISDIR(stat.st_mode)) {
> -        fprintf(stderr, "share path %s is not a directory\n", fse->path);
> -        return -1;
> +        error_setg(errp, "share path %s is not a directory", fse->path);
> +        return;
>      }
>      v9fs_path_free(&path);
>  
> -    return 0;
> +    v9c->parent_realize(dev, errp);
>  }
>  
>  /* virtio-9p device */
> @@ -136,12 +138,16 @@ static Property virtio_9p_properties[] = {
>      DEFINE_PROP_END_OF_LIST(),
>  };
>  
> -static void virtio_9p_class_init(ObjectClass *klass, void *data)
> +static void virtio_9p_class_init(ObjectClass *oc, void *data)
>  {
> -    DeviceClass *dc = DEVICE_CLASS(klass);
> -    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
> +    DeviceClass *dc = DEVICE_CLASS(oc);
> +    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(oc);
> +    V9fsClass *v9c = VIRTIO_9P_CLASS(oc);
> +
> +    v9c->parent_realize = dc->realize;
> +    dc->realize = virtio_9p_device_realize;
> +
>      dc->props = virtio_9p_properties;
> -    vdc->init = virtio_9p_device_init;
>      vdc->get_features = virtio_9p_get_features;
>      vdc->get_config = virtio_9p_get_config;
>  }
> @@ -151,6 +157,7 @@ static const TypeInfo virtio_device_info = {
>      .parent = TYPE_VIRTIO_DEVICE,
>      .instance_size = sizeof(V9fsState),
>      .class_init = virtio_9p_class_init,
> +    .class_size = sizeof(V9fsClass),
>  };
>  
>  static void virtio_9p_register_types(void)
> diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
> index 1d6eedb..85699a7 100644
> --- a/hw/9pfs/virtio-9p.h
> +++ b/hw/9pfs/virtio-9p.h
> @@ -227,6 +227,15 @@ typedef struct V9fsState
>      V9fsConf fsconf;
>  } V9fsState;
>  
> +typedef struct V9fsClass {
> +    /*< private >*/
> +    VirtioDeviceClass parent_class;
> +    /*< public >*/
> +
> +    DeviceRealize parent_realize;
> +} V9fsClass;
> +
> +

One empty line please.

>  typedef struct V9fsStatState {
>      V9fsPDU *pdu;
>      size_t offset;
> @@ -404,6 +413,10 @@ extern int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath,
>  #define TYPE_VIRTIO_9P "virtio-9p-device"
>  #define VIRTIO_9P(obj) \
>          OBJECT_CHECK(V9fsState, (obj), TYPE_VIRTIO_9P)
> +#define VIRTIO_9P_GET_CLASS(obj) \
> +        OBJECT_GET_CLASS(V9fsClass, (obj), TYPE_VIRTIO_9P)
> +#define VIRTIO_9P_CLASS(cls) \
> +        OBJECT_CLASS_CHECK(V9fsClass, (cls), TYPE_VIRTIO_9P)
>  
>  #define DEFINE_VIRTIO_9P_PROPERTIES(_state, _field)             \
>          DEFINE_PROP_STRING("mount_tag", _state, _field.tag),    \
> diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
> index 8ea1f03..88e99a6 100644
> --- a/hw/block/virtio-blk.c
> +++ b/hw/block/virtio-blk.c
> @@ -628,10 +628,11 @@ void virtio_blk_set_conf(DeviceState *dev, VirtIOBlkConf *blk)
>      memcpy(&(s->blk), blk, sizeof(struct VirtIOBlkConf));
>  }
>  
> -static int virtio_blk_device_init(VirtIODevice *vdev)
> +static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
>  {
> -    DeviceState *qdev = DEVICE(vdev);
> +    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
>      VirtIOBlock *s = VIRTIO_BLK(vdev);
> +    VirtIOBlockClass *vbc = VIRTIO_BLK_GET_CLASS(dev);
>      VirtIOBlkConf *blk = &(s->blk);
>  #ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
>      Error *err = NULL;
> @@ -639,17 +640,18 @@ static int virtio_blk_device_init(VirtIODevice *vdev)
>      static int virtio_blk_id;
>  
>      if (!blk->conf.bs) {
> -        error_report("drive property not set");
> -        return -1;
> +        error_setg(errp, "drive property not set");
> +        return;
>      }
>      if (!bdrv_is_inserted(blk->conf.bs)) {
> -        error_report("Device needs media, but drive is empty");
> -        return -1;
> +        error_setg(errp, "Device needs media, but drive is empty");
> +        return;
>      }
>  
>      blkconf_serial(&blk->conf, &blk->serial);
>      if (blkconf_geometry(&blk->conf, NULL, 65535, 255, 255) < 0) {
> -        return -1;
> +        error_setg(errp, "Error setting geometry");
> +        return;
>      }
>  
>      virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK,
> @@ -665,29 +667,31 @@ static int virtio_blk_device_init(VirtIODevice *vdev)
>  #ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
>      virtio_blk_data_plane_create(vdev, blk, &s->dataplane, &err);
>      if (err != NULL) {
> -        error_report("%s", error_get_pretty(err));
> -        error_free(err);
> +        error_propagate(errp, err);
>          virtio_cleanup(vdev);
> -        return -1;
> +        return;
>      }
>  #endif
>  
>      s->change = qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s);
> -    register_savevm(qdev, "virtio-blk", virtio_blk_id++, 2,
> +    register_savevm(dev, "virtio-blk", virtio_blk_id++, 2,
>                      virtio_blk_save, virtio_blk_load, s);
>      bdrv_set_dev_ops(s->bs, &virtio_block_ops, s);
>      bdrv_set_buffer_alignment(s->bs, s->conf->logical_block_size);
>  
>      bdrv_iostatus_enable(s->bs);
>  
> -    add_boot_device_path(s->conf->bootindex, qdev, "/disk@0,0");
> -    return 0;
> +    add_boot_device_path(s->conf->bootindex, dev, "/disk@0,0");
> +
> +    vbc->parent_realize(dev, errp);
>  }
>  
> -static int virtio_blk_device_exit(DeviceState *dev)
> +static void virtio_blk_device_unrealize(DeviceState *dev, Error **errp)
>  {
>      VirtIODevice *vdev = VIRTIO_DEVICE(dev);
>      VirtIOBlock *s = VIRTIO_BLK(dev);
> +    VirtIOBlockClass *vbc = VIRTIO_BLK_GET_CLASS(dev);
> +
>  #ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
>      virtio_blk_data_plane_destroy(s->dataplane);
>      s->dataplane = NULL;
> @@ -696,7 +700,8 @@ static int virtio_blk_device_exit(DeviceState *dev)
>      unregister_savevm(dev, "virtio-blk", s);
>      blockdev_mark_auto_del(s->bs);
>      virtio_cleanup(vdev);
> -    return 0;
> +
> +    vbc->parent_unrealize(dev, errp);
>  }
>  
>  static Property virtio_blk_properties[] = {
> @@ -704,13 +709,19 @@ static Property virtio_blk_properties[] = {
>      DEFINE_PROP_END_OF_LIST(),
>  };
>  
> -static void virtio_blk_class_init(ObjectClass *klass, void *data)
> +static void virtio_blk_class_init(ObjectClass *oc, void *data)
>  {
> -    DeviceClass *dc = DEVICE_CLASS(klass);
> -    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
> -    dc->exit = virtio_blk_device_exit;
> +    DeviceClass *dc = DEVICE_CLASS(oc);
> +    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(oc);
> +    VirtIOBlockClass *vbc = VIRTIO_BLK_CLASS(oc);
> +
> +    vbc->parent_realize = dc->realize;
> +    dc->realize = virtio_blk_device_realize;
> +
> +    vbc->parent_unrealize = dc->unrealize;
> +    dc->unrealize = virtio_blk_device_unrealize;
> +
>      dc->props = virtio_blk_properties;
> -    vdc->init = virtio_blk_device_init;
>      vdc->get_config = virtio_blk_update_config;
>      vdc->set_config = virtio_blk_set_config;
>      vdc->get_features = virtio_blk_get_features;
> @@ -723,6 +734,7 @@ static const TypeInfo virtio_device_info = {
>      .parent = TYPE_VIRTIO_DEVICE,
>      .instance_size = sizeof(VirtIOBlock),
>      .class_init = virtio_blk_class_init,
> +    .class_size = sizeof(VirtIOBlockClass),
>  };
>  
>  static void virtio_register_types(void)
> diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
> index cc3d1dd..1cdd659 100644
> --- a/hw/char/virtio-serial-bus.c
> +++ b/hw/char/virtio-serial-bus.c
> @@ -889,31 +889,35 @@ static int virtser_port_qdev_exit(DeviceState *qdev)
>      return 0;
>  }
>  
> -static int virtio_serial_device_init(VirtIODevice *vdev)
> +static void virtio_serial_device_realize(DeviceState *dev, Error **errp)
>  {
> -    DeviceState *qdev = DEVICE(vdev);
> -    VirtIOSerial *vser = VIRTIO_SERIAL(vdev);
> +    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
> +    VirtIOSerial *vser = VIRTIO_SERIAL(dev);
> +    VirtIOSerialClass *vsc = VIRTIO_SERIAL_GET_CLASS(dev);
> +    BusState *bus;
>      uint32_t i, max_supported_ports;
>  
>      if (!vser->serial.max_virtserial_ports) {
> -        return -1;
> +        error_setg(errp, "Maximum number of serial ports not specified");
> +        return;
>      }
>  
>      /* Each port takes 2 queues, and one pair is for the control queue */
>      max_supported_ports = VIRTIO_PCI_QUEUE_MAX / 2 - 1;
>  
>      if (vser->serial.max_virtserial_ports > max_supported_ports) {
> -        error_report("maximum ports supported: %u", max_supported_ports);
> -        return -1;
> +        error_setg(errp, "maximum ports supported: %u", max_supported_ports);
> +        return;
>      }
>  
>      virtio_init(vdev, "virtio-serial", VIRTIO_ID_CONSOLE,
>                  sizeof(struct virtio_console_config));
>  
>      /* Spawn a new virtio-serial bus on which the ports will ride as devices */
> -    qbus_create_inplace(&vser->bus.qbus, TYPE_VIRTIO_SERIAL_BUS, qdev,
> +    qbus_create_inplace(&vser->bus, TYPE_VIRTIO_SERIAL_BUS, dev,
>                          vdev->bus_name);
> -    vser->bus.qbus.allow_hotplug = 1;
> +    bus = BUS(&vser->bus);
> +    bus->allow_hotplug = 1;
>      vser->bus.vser = vser;
>      QTAILQ_INIT(&vser->ports);
>  
> @@ -961,10 +965,10 @@ static int virtio_serial_device_init(VirtIODevice *vdev)
>       * Register for the savevm section with the virtio-console name
>       * to preserve backward compat
>       */
> -    register_savevm(qdev, "virtio-console", -1, 3, virtio_serial_save,
> +    register_savevm(dev, "virtio-console", -1, 3, virtio_serial_save,
>                      virtio_serial_load, vser);
>  
> -    return 0;
> +    vsc->parent_realize(dev, errp);
>  }
>  
>  static void virtio_serial_port_class_init(ObjectClass *klass, void *data)
> @@ -986,10 +990,11 @@ static const TypeInfo virtio_serial_port_type_info = {
>      .class_init = virtio_serial_port_class_init,
>  };
>  
> -static int virtio_serial_device_exit(DeviceState *dev)
> +static void virtio_serial_device_unrealize(DeviceState *dev, Error **errp)
>  {
> -    VirtIOSerial *vser = VIRTIO_SERIAL(dev);
>      VirtIODevice *vdev = VIRTIO_DEVICE(dev);
> +    VirtIOSerial *vser = VIRTIO_SERIAL(dev);
> +    VirtIOSerialClass *vsc = VIRTIO_SERIAL_GET_CLASS(dev);
>  
>      unregister_savevm(dev, "virtio-console", vser);
>  
> @@ -1003,7 +1008,8 @@ static int virtio_serial_device_exit(DeviceState *dev)
>          g_free(vser->post_load);
>      }
>      virtio_cleanup(vdev);
> -    return 0;
> +
> +    vsc->parent_unrealize(dev, errp);
>  }
>  
>  static Property virtio_serial_properties[] = {
> @@ -1011,13 +1017,19 @@ static Property virtio_serial_properties[] = {
>      DEFINE_PROP_END_OF_LIST(),
>  };
>  
> -static void virtio_serial_class_init(ObjectClass *klass, void *data)
> +static void virtio_serial_class_init(ObjectClass *oc, void *data)
>  {
> -    DeviceClass *dc = DEVICE_CLASS(klass);
> -    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
> -    dc->exit = virtio_serial_device_exit;
> +    DeviceClass *dc = DEVICE_CLASS(oc);
> +    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(oc);
> +    VirtIOSerialClass *vsc = VIRTIO_SERIAL_CLASS(oc);
> +
> +    vsc->parent_realize = dc->realize;
> +    dc->realize = virtio_serial_device_realize;
> +
> +    vsc->parent_unrealize = dc->unrealize;
> +    dc->unrealize = virtio_serial_device_unrealize;
> +
>      dc->props = virtio_serial_properties;
> -    vdc->init = virtio_serial_device_init;
>      vdc->get_features = get_features;
>      vdc->get_config = get_config;
>      vdc->set_config = set_config;
> @@ -1030,6 +1042,7 @@ static const TypeInfo virtio_device_info = {
>      .parent = TYPE_VIRTIO_DEVICE,
>      .instance_size = sizeof(VirtIOSerial),
>      .class_init = virtio_serial_class_init,
> +    .class_size = sizeof(VirtIOSerialClass),
>  };
>  
>  static void virtio_serial_register_types(void)
> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
> index 1ea9556..9a3680c 100644
> --- a/hw/net/virtio-net.c
> +++ b/hw/net/virtio-net.c
> @@ -1367,15 +1367,16 @@ void virtio_net_set_netclient_name(VirtIONet *n, const char *name,
>      n->netclient_type = g_strdup(type);
>  }
>  
> -static int virtio_net_device_init(VirtIODevice *vdev)
> +static void virtio_net_device_realize(DeviceState *dev, Error **errp)
>  {
>      int i;
>  
> -    DeviceState *qdev = DEVICE(vdev);
> -    VirtIONet *n = VIRTIO_NET(vdev);
> +    DeviceState *qdev = DEVICE(dev);
> +    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
> +    VirtIONet *n = VIRTIO_NET(dev);
> +    VirtIONetClass *vnc = VIRTIO_NET_GET_CLASS(dev);
>  
> -    virtio_init(VIRTIO_DEVICE(n), "virtio-net", VIRTIO_ID_NET,
> -                                  n->config_size);
> +    virtio_init(vdev, "virtio-net", VIRTIO_ID_NET, n->config_size);
>  
>      n->max_queues = MAX(n->nic_conf.queues, 1);
>      n->vqs = g_malloc0(sizeof(VirtIONetQueue) * n->max_queues);
> @@ -1439,24 +1440,26 @@ static int virtio_net_device_init(VirtIODevice *vdev)
>  
>      n->vlans = g_malloc0(MAX_VLAN >> 3);
>  
> -    n->qdev = qdev;
> -    register_savevm(qdev, "virtio-net", -1, VIRTIO_NET_VM_VERSION,
> +    n->qdev = dev;
> +    register_savevm(dev, "virtio-net", -1, VIRTIO_NET_VM_VERSION,
>                      virtio_net_save, virtio_net_load, n);
>  
> -    add_boot_device_path(n->nic_conf.bootindex, qdev, "/ethernet-phy@0");
> -    return 0;
> +    add_boot_device_path(n->nic_conf.bootindex, dev, "/ethernet-phy@0");
> +
> +    vnc->parent_realize(dev, errp);
>  }
>  
> -static int virtio_net_device_exit(DeviceState *qdev)
> +static void virtio_net_device_unrealize(DeviceState *dev, Error **errp)
>  {
> -    VirtIONet *n = VIRTIO_NET(qdev);
> -    VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
> +    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
> +    VirtIONet *n = VIRTIO_NET(dev);
> +    VirtIONetClass *vnc = VIRTIO_NET_GET_CLASS(dev);
>      int i;
>  
>      /* This will stop vhost backend if appropriate. */
>      virtio_net_set_status(vdev, 0);
>  
> -    unregister_savevm(qdev, "virtio-net", n);
> +    unregister_savevm(dev, "virtio-net", n);
>  
>      if (n->netclient_name) {
>          g_free(n->netclient_name);
> @@ -1488,7 +1491,7 @@ static int virtio_net_device_exit(DeviceState *qdev)
>      qemu_del_nic(n->nic);
>      virtio_cleanup(vdev);
>  
> -    return 0;
> +    vnc->parent_unrealize(dev, errp);
>  }
>  
>  static void virtio_net_instance_init(Object *obj)
> @@ -1511,13 +1514,19 @@ static Property virtio_net_properties[] = {
>      DEFINE_PROP_END_OF_LIST(),
>  };
>  
> -static void virtio_net_class_init(ObjectClass *klass, void *data)
> +static void virtio_net_class_init(ObjectClass *oc, void *data)
>  {
> -    DeviceClass *dc = DEVICE_CLASS(klass);
> -    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
> -    dc->exit = virtio_net_device_exit;
> +    DeviceClass *dc = DEVICE_CLASS(oc);
> +    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(oc);
> +    VirtIONetClass *vnc = VIRTIO_NET_CLASS(oc);
> +
> +    vnc->parent_realize = dc->realize;
> +    dc->realize = virtio_net_device_realize;
> +
> +    vnc->parent_unrealize = dc->unrealize;
> +    dc->unrealize = virtio_net_device_unrealize;
> +
>      dc->props = virtio_net_properties;
> -    vdc->init = virtio_net_device_init;
>      vdc->get_config = virtio_net_get_config;
>      vdc->set_config = virtio_net_set_config;
>      vdc->get_features = virtio_net_get_features;
> @@ -1535,6 +1544,7 @@ static const TypeInfo virtio_net_info = {
>      .instance_size = sizeof(VirtIONet),
>      .instance_init = virtio_net_instance_init,
>      .class_init = virtio_net_class_init,
> +    .class_size = sizeof(VirtIONetClass),
>  };
>  
>  static void virtio_register_types(void)
> diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c
> index d7a1c33..cacaf64 100644
> --- a/hw/scsi/vhost-scsi.c
> +++ b/hw/scsi/vhost-scsi.c
> @@ -196,29 +196,32 @@ static void vhost_scsi_set_status(VirtIODevice *vdev, uint8_t val)
>      }
>  }
>  
> -static int vhost_scsi_init(VirtIODevice *vdev)
> +static void vhost_scsi_realize(DeviceState *dev, Error **errp)
>  {
> -    VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
> -    VHostSCSI *s = VHOST_SCSI(vdev);
> +    VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev);
> +    VHostSCSI *s = VHOST_SCSI(dev);
> +    VHostSCSIClass *vsc = VHOST_SCSI_GET_CLASS(dev);
> +    Error *err = NULL;
>      int vhostfd = -1;
>      int ret;
>  
>      if (!vs->conf.wwpn) {
> -        error_report("vhost-scsi: missing wwpn\n");
> -        return -EINVAL;
> +        error_setg(errp, "vhost-scsi: missing wwpn");
> +        return;
>      }
>  
>      if (vs->conf.vhostfd) {
>          vhostfd = monitor_handle_fd_param(cur_mon, vs->conf.vhostfd);
>          if (vhostfd == -1) {
> -            error_report("vhost-scsi: unable to parse vhostfd\n");
> -            return -EINVAL;
> +            error_setg(errp, "vhost-scsi: unable to parse vhostfd");
> +            return;
>          }
>      }
>  
> -    ret = virtio_scsi_common_init(vs);
> -    if (ret < 0) {
> -        return ret;
> +    vsc->parent_realize(dev, &err);
> +    if (err != NULL) {
> +        error_propagate(errp, err);
> +        return;
>      }
>  
>      s->dev.nvqs = VHOST_SCSI_VQ_NUM_FIXED + vs->conf.num_queues;
> @@ -227,24 +230,22 @@ static int vhost_scsi_init(VirtIODevice *vdev)
>  
>      ret = vhost_dev_init(&s->dev, vhostfd, "/dev/vhost-scsi", true);
>      if (ret < 0) {
> -        error_report("vhost-scsi: vhost initialization failed: %s\n",
> -                strerror(-ret));
> -        return ret;
> +        error_setg(errp, "vhost-scsi: vhost initialization failed: %s",
> +                   strerror(-ret));
> +        return;
>      }
>      s->dev.backend_features = 0;
>  
>      error_setg(&s->migration_blocker,
>              "vhost-scsi does not support migration");
>      migrate_add_blocker(s->migration_blocker);
> -
> -    return 0;
>  }
>  
> -static int vhost_scsi_exit(DeviceState *qdev)
> +static void vhost_scsi_unrealize(DeviceState *dev, Error **errp)
>  {
> -    VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
> -    VHostSCSI *s = VHOST_SCSI(qdev);
> -    VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(qdev);
> +    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
> +    VHostSCSI *s = VHOST_SCSI(dev);
> +    VHostSCSIClass *vsc = VHOST_SCSI_GET_CLASS(dev);
>  
>      migrate_del_blocker(s->migration_blocker);
>      error_free(s->migration_blocker);
> @@ -253,7 +254,8 @@ static int vhost_scsi_exit(DeviceState *qdev)
>      vhost_scsi_set_status(vdev, 0);
>  
>      g_free(s->dev.vqs);
> -    return virtio_scsi_common_exit(vs);
> +
> +    vsc->parent_unrealize(dev, errp);
>  }
>  
>  static Property vhost_scsi_properties[] = {
> @@ -261,13 +263,19 @@ static Property vhost_scsi_properties[] = {
>      DEFINE_PROP_END_OF_LIST(),
>  };
>  
> -static void vhost_scsi_class_init(ObjectClass *klass, void *data)
> +static void vhost_scsi_class_init(ObjectClass *oc, void *data)
>  {
> -    DeviceClass *dc = DEVICE_CLASS(klass);
> -    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
> -    dc->exit = vhost_scsi_exit;
> +    DeviceClass *dc = DEVICE_CLASS(oc);
> +    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(oc);
> +    VHostSCSIClass *vsc = VHOST_SCSI_CLASS(oc);
> +
> +    vsc->parent_realize = dc->realize;
> +    dc->realize = vhost_scsi_realize;
> +
> +    vsc->parent_unrealize = dc->unrealize;
> +    dc->unrealize = vhost_scsi_unrealize;
> +
>      dc->props = vhost_scsi_properties;
> -    vdc->init = vhost_scsi_init;
>      vdc->get_features = vhost_scsi_get_features;
>      vdc->set_config = vhost_scsi_set_config;
>      vdc->set_status = vhost_scsi_set_status;
> @@ -278,6 +286,7 @@ static const TypeInfo vhost_scsi_info = {
>      .parent = TYPE_VIRTIO_SCSI_COMMON,
>      .instance_size = sizeof(VHostSCSI),
>      .class_init = vhost_scsi_class_init,
> +    .class_size = sizeof(VHostSCSIClass),
>  };
>  
>  static void virtio_register_types(void)
> diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
> index 08dd3f3..6704f78 100644
> --- a/hw/scsi/virtio-scsi.c
> +++ b/hw/scsi/virtio-scsi.c
> @@ -587,12 +587,14 @@ static struct SCSIBusInfo virtio_scsi_scsi_info = {
>      .load_request = virtio_scsi_load_request,
>  };
>  
> -int virtio_scsi_common_init(VirtIOSCSICommon *s)
> +static void virtio_scsi_common_realize(DeviceState *dev, Error **errp)
>  {
> -    VirtIODevice *vdev = VIRTIO_DEVICE(s);
> +    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
> +    VirtIOSCSICommon *s = VIRTIO_SCSI_COMMON(dev);
> +    VirtIOSCSICommonClass *vscc = VIRTIO_SCSI_COMMON_GET_CLASS(dev);
>      int i;
>  
> -    virtio_init(VIRTIO_DEVICE(s), "virtio-scsi", VIRTIO_ID_SCSI,
> +    virtio_init(vdev, "virtio-scsi", VIRTIO_ID_SCSI,
>                  sizeof(VirtIOSCSIConfig));
>  
>      s->cmd_vqs = g_malloc0(s->conf.num_queues * sizeof(VirtQueue *));
> @@ -608,50 +610,53 @@ int virtio_scsi_common_init(VirtIOSCSICommon *s)
>                                           virtio_scsi_handle_cmd);
>      }
>  
> -    return 0;
> +    vscc->parent_realize(dev, errp);
>  }
>  
> -static int virtio_scsi_device_init(VirtIODevice *vdev)
> +static void virtio_scsi_device_realize(DeviceState *dev, Error **errp)
>  {
> -    DeviceState *qdev = DEVICE(vdev);
> -    VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
> -    VirtIOSCSI *s = VIRTIO_SCSI(vdev);
> +    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
> +    VirtIOSCSI *s = VIRTIO_SCSI(dev);
> +    VirtIOSCSIClass *vsc = VIRTIO_SCSI_GET_CLASS(dev);
>      static int virtio_scsi_id;
> -    int ret;
> +    Error *err = NULL;
>  
> -    ret = virtio_scsi_common_init(vs);
> -    if (ret < 0) {
> -        return ret;
> +    vsc->parent_realize(dev, &err);
> +    if (err != NULL) {
> +        error_propagate(errp, err);
> +        return;
>      }
>  
> -    scsi_bus_new(&s->bus, qdev, &virtio_scsi_scsi_info, vdev->bus_name);
> +    scsi_bus_new(&s->bus, dev, &virtio_scsi_scsi_info, vdev->bus_name);
>  
> -    if (!qdev->hotplugged) {
> +    if (!dev->hotplugged) {
>          scsi_bus_legacy_handle_cmdline(&s->bus);
>      }
>  
> -    register_savevm(qdev, "virtio-scsi", virtio_scsi_id++, 1,
> +    register_savevm(dev, "virtio-scsi", virtio_scsi_id++, 1,
>                      virtio_scsi_save, virtio_scsi_load, s);
> -
> -    return 0;
>  }
>  
> -int virtio_scsi_common_exit(VirtIOSCSICommon *vs)
> +static void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp)
>  {
> -    VirtIODevice *vdev = VIRTIO_DEVICE(vs);
> +    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
> +    VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev);
> +    VirtIOSCSICommonClass *vscc = VIRTIO_SCSI_COMMON_GET_CLASS(dev);
>  
>      g_free(vs->cmd_vqs);
>      virtio_cleanup(vdev);
> -    return 0;
> +
> +    vscc->parent_unrealize(dev, errp);
>  }
>  
> -static int virtio_scsi_device_exit(DeviceState *qdev)
> +static void virtio_scsi_device_unrealize(DeviceState *dev, Error **errp)
>  {
> -    VirtIOSCSI *s = VIRTIO_SCSI(qdev);
> -    VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(qdev);
> +    VirtIOSCSI *s = VIRTIO_SCSI(dev);
> +    VirtIOSCSIClass *vsc = VIRTIO_SCSI_GET_CLASS(dev);
>  
> -    unregister_savevm(qdev, "virtio-scsi", s);
> -    return virtio_scsi_common_exit(vs);
> +    unregister_savevm(dev, "virtio-scsi", s);
> +
> +    vsc->parent_unrealize(dev, errp);
>  }
>  
>  static Property virtio_scsi_properties[] = {
> @@ -659,20 +664,34 @@ static Property virtio_scsi_properties[] = {
>      DEFINE_PROP_END_OF_LIST(),
>  };
>  
> -static void virtio_scsi_common_class_init(ObjectClass *klass, void *data)
> +static void virtio_scsi_common_class_init(ObjectClass *oc, void *data)
>  {
> -    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
> +    DeviceClass *dc = DEVICE_CLASS(oc);
> +    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(oc);
> +    VirtIOSCSICommonClass *vscc = VIRTIO_SCSI_COMMON_CLASS(oc);
> +
> +    vscc->parent_realize = dc->realize;
> +    dc->realize = virtio_scsi_common_realize;
> +
> +    vscc->parent_unrealize = dc->unrealize;
> +    dc->unrealize = virtio_scsi_common_unrealize;
>  
>      vdc->get_config = virtio_scsi_get_config;
>  }
>  
> -static void virtio_scsi_class_init(ObjectClass *klass, void *data)
> +static void virtio_scsi_class_init(ObjectClass *oc, void *data)
>  {
> -    DeviceClass *dc = DEVICE_CLASS(klass);
> -    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
> -    dc->exit = virtio_scsi_device_exit;
> +    DeviceClass *dc = DEVICE_CLASS(oc);
> +    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(oc);
> +    VirtIOSCSIClass *vsc = VIRTIO_SCSI_CLASS(oc);
> +
> +    vsc->parent_realize = dc->realize;
> +    dc->realize = virtio_scsi_device_realize;
> +
> +    vsc->parent_unrealize = dc->unrealize;
> +    dc->unrealize = virtio_scsi_device_unrealize;
> +
>      dc->props = virtio_scsi_properties;
> -    vdc->init = virtio_scsi_device_init;
>      vdc->set_config = virtio_scsi_set_config;
>      vdc->get_features = virtio_scsi_get_features;
>      vdc->reset = virtio_scsi_reset;
> @@ -683,6 +702,7 @@ static const TypeInfo virtio_scsi_common_info = {
>      .parent = TYPE_VIRTIO_DEVICE,
>      .instance_size = sizeof(VirtIOSCSICommon),
>      .class_init = virtio_scsi_common_class_init,
> +    .class_size = sizeof(VirtIOSCSICommonClass),
>  };
>  
>  static const TypeInfo virtio_scsi_info = {
> @@ -690,6 +710,7 @@ static const TypeInfo virtio_scsi_info = {
>      .parent = TYPE_VIRTIO_SCSI_COMMON,
>      .instance_size = sizeof(VirtIOSCSI),
>      .class_init = virtio_scsi_class_init,
> +    .class_size = sizeof(VirtIOSCSIClass),
>  };
>  
>  static void virtio_register_types(void)
> diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
> index d669756..0535062 100644
> --- a/hw/virtio/virtio-balloon.c
> +++ b/hw/virtio/virtio-balloon.c
> @@ -336,10 +336,11 @@ static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id)
>      return 0;
>  }
>  
> -static int virtio_balloon_device_init(VirtIODevice *vdev)
> +static void virtio_balloon_device_realize(DeviceState *dev, Error **errp)
>  {
> -    DeviceState *qdev = DEVICE(vdev);
> -    VirtIOBalloon *s = VIRTIO_BALLOON(vdev);
> +    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
> +    VirtIOBalloon *s = VIRTIO_BALLOON(dev);
> +    VirtIOBalloonClass *vbc = VIRTIO_BALLOON_GET_CLASS(dev);
>      int ret;
>  
>      virtio_init(vdev, "virtio-balloon", VIRTIO_ID_BALLOON, 8);
> @@ -348,50 +349,60 @@ static int virtio_balloon_device_init(VirtIODevice *vdev)
>                                     virtio_balloon_stat, s);
>  
>      if (ret < 0) {
> -        virtio_cleanup(VIRTIO_DEVICE(s));
> -        return -1;
> +        error_setg(errp, "Adding balloon handler failed");
> +        virtio_cleanup(vdev);
> +        return;
>      }
>  
>      s->ivq = virtio_add_queue(vdev, 128, virtio_balloon_handle_output);
>      s->dvq = virtio_add_queue(vdev, 128, virtio_balloon_handle_output);
>      s->svq = virtio_add_queue(vdev, 128, virtio_balloon_receive_stats);
>  
> -    register_savevm(qdev, "virtio-balloon", -1, 1,
> +    register_savevm(dev, "virtio-balloon", -1, 1,
>                      virtio_balloon_save, virtio_balloon_load, s);
>  
> -    object_property_add(OBJECT(qdev), "guest-stats", "guest statistics",
> +    object_property_add(OBJECT(dev), "guest-stats", "guest statistics",
>                          balloon_stats_get_all, NULL, NULL, s, NULL);
>  
> -    object_property_add(OBJECT(qdev), "guest-stats-polling-interval", "int",
> +    object_property_add(OBJECT(dev), "guest-stats-polling-interval", "int",
>                          balloon_stats_get_poll_interval,
>                          balloon_stats_set_poll_interval,
>                          NULL, s, NULL);
> -    return 0;
> +
> +    vbc->parent_realize(dev, errp);
>  }
>  
> -static int virtio_balloon_device_exit(DeviceState *qdev)
> +static void virtio_balloon_device_unrealize(DeviceState *dev, Error **errp)
>  {
> -    VirtIOBalloon *s = VIRTIO_BALLOON(qdev);
> -    VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
> +    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
> +    VirtIOBalloon *s = VIRTIO_BALLOON(dev);
> +    VirtIOBalloonClass *vbc = VIRTIO_BALLOON_GET_CLASS(dev);
>  
>      balloon_stats_destroy_timer(s);
>      qemu_remove_balloon_handler(s);
> -    unregister_savevm(qdev, "virtio-balloon", s);
> +    unregister_savevm(dev, "virtio-balloon", s);
>      virtio_cleanup(vdev);
> -    return 0;
> +
> +    vbc->parent_unrealize(dev, errp);
>  }
>  
>  static Property virtio_balloon_properties[] = {
>      DEFINE_PROP_END_OF_LIST(),
>  };
>  
> -static void virtio_balloon_class_init(ObjectClass *klass, void *data)
> +static void virtio_balloon_class_init(ObjectClass *oc, void *data)
>  {
> -    DeviceClass *dc = DEVICE_CLASS(klass);
> -    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
> -    dc->exit = virtio_balloon_device_exit;
> +    DeviceClass *dc = DEVICE_CLASS(oc);
> +    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(oc);
> +    VirtIOBalloonClass *vbc = VIRTIO_BALLOON_CLASS(oc);
> +
> +    vbc->parent_realize = dc->realize;
> +    dc->realize = virtio_balloon_device_realize;
> +
> +    vbc->parent_unrealize = dc->unrealize;
> +    dc->unrealize = virtio_balloon_device_unrealize;
> +
>      dc->props = virtio_balloon_properties;
> -    vdc->init = virtio_balloon_device_init;
>      vdc->get_config = virtio_balloon_get_config;
>      vdc->set_config = virtio_balloon_set_config;
>      vdc->get_features = virtio_balloon_get_features;
> @@ -402,6 +413,7 @@ static const TypeInfo virtio_balloon_info = {
>      .parent = TYPE_VIRTIO_DEVICE,
>      .instance_size = sizeof(VirtIOBalloon),
>      .class_init = virtio_balloon_class_init,
> +    .class_size = sizeof(VirtIOBalloonClass),
>  };
>  
>  static void virtio_register_types(void)
> diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c
> index cb787c7..108cfc9 100644
> --- a/hw/virtio/virtio-rng.c
> +++ b/hw/virtio/virtio-rng.c
> @@ -133,21 +133,22 @@ static void check_rate_limit(void *opaque)
>                     qemu_get_clock_ms(vm_clock) + vrng->conf.period_ms);
>  }
>  
> -static int virtio_rng_device_init(VirtIODevice *vdev)
> +static void virtio_rng_device_realize(DeviceState *dev, Error **errp)
>  {
> -    DeviceState *qdev = DEVICE(vdev);
> -    VirtIORNG *vrng = VIRTIO_RNG(vdev);
> +    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
> +    VirtIORNG *vrng = VIRTIO_RNG(dev);
> +    VirtIORNGClass *vrc = VIRTIO_RNG_GET_CLASS(dev);
>      Error *local_err = NULL;
>  
>      if (vrng->conf.rng == NULL) {
>          vrng->conf.default_backend = RNG_RANDOM(object_new(TYPE_RNG_RANDOM));
>  
> -        object_property_add_child(OBJECT(qdev),
> +        object_property_add_child(OBJECT(dev),
>                                    "default-backend",
>                                    OBJECT(vrng->conf.default_backend),
>                                    NULL);
>  
> -        object_property_set_link(OBJECT(qdev),
> +        object_property_set_link(OBJECT(dev),
>                                   OBJECT(vrng->conf.default_backend),
>                                   "rng", NULL);
>      }
> @@ -156,15 +157,14 @@ static int virtio_rng_device_init(VirtIODevice *vdev)
>  
>      vrng->rng = vrng->conf.rng;
>      if (vrng->rng == NULL) {
> -        qerror_report(QERR_INVALID_PARAMETER_VALUE, "rng", "a valid object");
> -        return -1;
> +        error_set(errp, QERR_INVALID_PARAMETER_VALUE, "rng", "a valid object");
> +        return;
>      }
>  
>      rng_backend_open(vrng->rng, &local_err);
>      if (local_err) {
> -        qerror_report_err(local_err);
> -        error_free(local_err);
> -        return -1;
> +        error_propagate(errp, local_err);
> +        return;
>      }
>  
>      vrng->vq = virtio_add_queue(vdev, 8, handle_input);
> @@ -178,22 +178,24 @@ static int virtio_rng_device_init(VirtIODevice *vdev)
>      qemu_mod_timer(vrng->rate_limit_timer,
>                     qemu_get_clock_ms(vm_clock) + vrng->conf.period_ms);
>  
> -    register_savevm(qdev, "virtio-rng", -1, 1, virtio_rng_save,
> +    register_savevm(dev, "virtio-rng", -1, 1, virtio_rng_save,
>                      virtio_rng_load, vrng);
>  
> -    return 0;
> +    vrc->parent_realize(dev, errp);
>  }
>  
> -static int virtio_rng_device_exit(DeviceState *qdev)
> +static void virtio_rng_device_unrealize(DeviceState *dev, Error **errp)
>  {
> -    VirtIORNG *vrng = VIRTIO_RNG(qdev);
> -    VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
> +    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
> +    VirtIORNG *vrng = VIRTIO_RNG(dev);
> +    VirtIORNGClass *vrc = VIRTIO_RNG_GET_CLASS(dev);
>  
>      qemu_del_timer(vrng->rate_limit_timer);
>      qemu_free_timer(vrng->rate_limit_timer);
> -    unregister_savevm(qdev, "virtio-rng", vrng);
> +    unregister_savevm(dev, "virtio-rng", vrng);
>      virtio_cleanup(vdev);
> -    return 0;
> +
> +    vrc->parent_unrealize(dev, errp);
>  }
>  
>  static Property virtio_rng_properties[] = {
> @@ -201,13 +203,19 @@ static Property virtio_rng_properties[] = {
>      DEFINE_PROP_END_OF_LIST(),
>  };
>  
> -static void virtio_rng_class_init(ObjectClass *klass, void *data)
> +static void virtio_rng_class_init(ObjectClass *oc, void *data)
>  {
> -    DeviceClass *dc = DEVICE_CLASS(klass);
> -    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
> -    dc->exit = virtio_rng_device_exit;
> +    DeviceClass *dc = DEVICE_CLASS(oc);
> +    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(oc);
> +    VirtIORNGClass *vrc = VIRTIO_RNG_CLASS(oc);
> +
> +    vrc->parent_realize = dc->realize;
> +    dc->realize = virtio_rng_device_realize;
> +
> +    vrc->parent_unrealize = dc->unrealize;
> +    dc->unrealize = virtio_rng_device_unrealize;
> +
>      dc->props = virtio_rng_properties;
> -    vdc->init = virtio_rng_device_init;
>      vdc->get_features = get_features;
>  }
>  
> @@ -225,6 +233,7 @@ static const TypeInfo virtio_rng_info = {
>      .instance_size = sizeof(VirtIORNG),
>      .instance_init = virtio_rng_initfn,
>      .class_init = virtio_rng_class_init,
> +    .class_size = sizeof(VirtIORNGClass),
>  };
>  
>  static void virtio_register_types(void)
> diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
> index 8176c14..d369f9a 100644
> --- a/hw/virtio/virtio.c
> +++ b/hw/virtio/virtio.c
> @@ -1105,35 +1105,29 @@ void virtio_device_set_child_bus_name(VirtIODevice *vdev, char *bus_name)
>      }
>  }
>  
> -static int virtio_device_init(DeviceState *qdev)
> +static void virtio_device_realize(DeviceState *dev, Error **errp)
>  {
> -    VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
> -    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(qdev);
> -    assert(k->init != NULL);
> -    if (k->init(vdev) < 0) {
> -        return -1;
> -    }
> +    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
> +
>      virtio_bus_plug_device(vdev);
> -    return 0;
>  }
>  
> -static int virtio_device_exit(DeviceState *qdev)
> +static void virtio_device_unrealize(DeviceState *dev, Error **errp)
>  {
> -    VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
> +    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
>  
>      if (vdev->bus_name) {
>          g_free(vdev->bus_name);
>          vdev->bus_name = NULL;
>      }
> -    return 0;
>  }
>  
>  static void virtio_device_class_init(ObjectClass *klass, void *data)
>  {
>      /* Set the default value here. */
>      DeviceClass *dc = DEVICE_CLASS(klass);
> -    dc->init = virtio_device_init;
> -    dc->exit = virtio_device_exit;
> +    dc->realize = virtio_device_realize;
> +    dc->unrealize = virtio_device_unrealize;
>      dc->bus_type = TYPE_VIRTIO_BUS;
>  }
>  
> diff --git a/include/hw/virtio/vhost-scsi.h b/include/hw/virtio/vhost-scsi.h
> index 85cc031..b0d64e4 100644
> --- a/include/hw/virtio/vhost-scsi.h
> +++ b/include/hw/virtio/vhost-scsi.h
> @@ -53,6 +53,10 @@ enum vhost_scsi_vq_list {
>  #define TYPE_VHOST_SCSI "vhost-scsi"
>  #define VHOST_SCSI(obj) \
>          OBJECT_CHECK(VHostSCSI, (obj), TYPE_VHOST_SCSI)
> +#define VHOST_SCSI_GET_CLASS(obj) \
> +        OBJECT_GET_CLASS(VHostSCSIClass, (obj), TYPE_VHOST_SCSI)
> +#define VHOST_SCSI_CLASS(cls) \
> +        OBJECT_CLASS_CHECK(VHostSCSIClass, (cls), TYPE_VHOST_SCSI)
>  
>  typedef struct VHostSCSI {
>      VirtIOSCSICommon parent_obj;
> @@ -62,6 +66,15 @@ typedef struct VHostSCSI {
>      struct vhost_dev dev;
>  } VHostSCSI;
>  
> +typedef struct VHostSCSIClass {
> +    /*< private >*/
> +    VirtIOSCSICommonClass parent_class;
> +    /*< public >*/
> +
> +    DeviceRealize parent_realize;
> +    DeviceUnrealize parent_unrealize;
> +} VHostSCSIClass;
> +
>  #define DEFINE_VHOST_SCSI_PROPERTIES(_state, _conf_field) \
>      DEFINE_PROP_STRING("vhostfd", _state, _conf_field.vhostfd), \
>      DEFINE_PROP_STRING("wwpn", _state, _conf_field.wwpn), \
> diff --git a/include/hw/virtio/virtio-balloon.h b/include/hw/virtio/virtio-balloon.h
> index f863bfe..146fa04 100644
> --- a/include/hw/virtio/virtio-balloon.h
> +++ b/include/hw/virtio/virtio-balloon.h
> @@ -21,6 +21,10 @@
>  #define TYPE_VIRTIO_BALLOON "virtio-balloon-device"
>  #define VIRTIO_BALLOON(obj) \
>          OBJECT_CHECK(VirtIOBalloon, (obj), TYPE_VIRTIO_BALLOON)
> +#define VIRTIO_BALLOON_GET_CLASS(obj) \
> +        OBJECT_GET_CLASS(VirtIOBalloonClass, (obj), TYPE_VIRTIO_BALLOON)
> +#define VIRTIO_BALLOON_CLASS(cls) \
> +        OBJECT_CLASS_CHECK(VirtIOBalloonClass, (cls), TYPE_VIRTIO_BALLOON)
>  
>  /* from Linux's linux/virtio_balloon.h */
>  
> @@ -69,4 +73,13 @@ typedef struct VirtIOBalloon {
>      int64_t stats_poll_interval;
>  } VirtIOBalloon;
>  
> +typedef struct VirtIOBalloonClass {
> +    /*< private >*/
> +    VirtioDeviceClass parent_class;
> +    /*< public >*/
> +
> +    DeviceRealize parent_realize;
> +    DeviceUnrealize parent_unrealize;
> +} VirtIOBalloonClass;
> +
>  #endif
> diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h
> index fc71853..5ed703d 100644
> --- a/include/hw/virtio/virtio-blk.h
> +++ b/include/hw/virtio/virtio-blk.h
> @@ -20,6 +20,10 @@
>  #define TYPE_VIRTIO_BLK "virtio-blk-device"
>  #define VIRTIO_BLK(obj) \
>          OBJECT_CHECK(VirtIOBlock, (obj), TYPE_VIRTIO_BLK)
> +#define VIRTIO_BLK_GET_CLASS(obj) \
> +        OBJECT_GET_CLASS(VirtIOBlockClass, (obj), TYPE_VIRTIO_BLK)
> +#define VIRTIO_BLK_CLASS(cls) \
> +        OBJECT_CLASS_CHECK(VirtIOBlockClass, (cls), TYPE_VIRTIO_BLK)
>  
>  /* from Linux's linux/virtio_blk.h */
>  
> @@ -129,6 +133,15 @@ typedef struct VirtIOBlock {
>  #endif
>  } VirtIOBlock;
>  
> +typedef struct VirtIOBlockClass {
> +    /*< private >*/
> +    VirtioDeviceClass parent_class;
> +    /*< public >*/
> +
> +    DeviceRealize parent_realize;
> +    DeviceUnrealize parent_unrealize;
> +} VirtIOBlockClass;
> +
>  #define DEFINE_VIRTIO_BLK_FEATURES(_state, _field) \
>          DEFINE_VIRTIO_COMMON_FEATURES(_state, _field)
>  
> diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
> index b315ac9..0b8a06e 100644
> --- a/include/hw/virtio/virtio-net.h
> +++ b/include/hw/virtio/virtio-net.h
> @@ -20,6 +20,10 @@
>  #define TYPE_VIRTIO_NET "virtio-net-device"
>  #define VIRTIO_NET(obj) \
>          OBJECT_CHECK(VirtIONet, (obj), TYPE_VIRTIO_NET)
> +#define VIRTIO_NET_GET_CLASS(obj) \
> +        OBJECT_GET_CLASS(VirtIONetClass, (obj), TYPE_VIRTIO_NET)
> +#define VIRTIO_NET_CLASS(cls) \
> +        OBJECT_CLASS_CHECK(VirtIONetClass, (cls), TYPE_VIRTIO_NET)
>  
>  #define ETH_ALEN    6
>  
> @@ -195,6 +199,15 @@ typedef struct VirtIONet {
>      uint64_t curr_guest_offloads;
>  } VirtIONet;
>  
> +typedef struct VirtIONetClass {
> +    /*< private >*/
> +    VirtioDeviceClass parent_class;
> +    /*< public >*/
> +
> +    DeviceRealize parent_realize;
> +    DeviceUnrealize parent_unrealize;
> +} VirtIONetClass;
> +
>  #define VIRTIO_NET_CTRL_MAC    1
>   #define VIRTIO_NET_CTRL_MAC_TABLE_SET        0
>   #define VIRTIO_NET_CTRL_MAC_ADDR_SET         1
> diff --git a/include/hw/virtio/virtio-rng.h b/include/hw/virtio/virtio-rng.h
> index debaa15..528f70c 100644
> --- a/include/hw/virtio/virtio-rng.h
> +++ b/include/hw/virtio/virtio-rng.h
> @@ -18,6 +18,10 @@
>  #define TYPE_VIRTIO_RNG "virtio-rng-device"
>  #define VIRTIO_RNG(obj) \
>          OBJECT_CHECK(VirtIORNG, (obj), TYPE_VIRTIO_RNG)
> +#define VIRTIO_RNG_GET_CLASS(obj) \
> +        OBJECT_GET_CLASS(VirtIORNGClass, (obj), TYPE_VIRTIO_RNG)
> +#define VIRTIO_RNG_CLASS(cls) \
> +        OBJECT_CLASS_CHECK(VirtIORNGClass, (cls), TYPE_VIRTIO_RNG)
>  
>  /* The Virtio ID for the virtio rng device */
>  #define VIRTIO_ID_RNG    4
> @@ -46,6 +50,15 @@ typedef struct VirtIORNG {
>      int64_t quota_remaining;
>  } VirtIORNG;
>  
> +typedef struct VirtIORNGClass {
> +    /*< private >*/
> +    VirtioDeviceClass parent_class;
> +    /*< public >*/
> +
> +    DeviceRealize parent_realize;
> +    DeviceUnrealize parent_unrealize;
> +} VirtIORNGClass;
> +
>  /* Set a default rate limit of 2^47 bytes per minute or roughly 2TB/s.  If
>     you have an entropy source capable of generating more entropy than this
>     and you can pass it through via virtio-rng, then hats off to you.  Until
> diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h
> index 9a98540..2ce58cd 100644
> --- a/include/hw/virtio/virtio-scsi.h
> +++ b/include/hw/virtio/virtio-scsi.h
> @@ -21,10 +21,18 @@
>  #define TYPE_VIRTIO_SCSI_COMMON "virtio-scsi-common"
>  #define VIRTIO_SCSI_COMMON(obj) \
>          OBJECT_CHECK(VirtIOSCSICommon, (obj), TYPE_VIRTIO_SCSI_COMMON)
> +#define VIRTIO_SCSI_COMMON_GET_CLASS(obj) \
> +        OBJECT_GET_CLASS(VirtIOSCSICommonClass, (obj), TYPE_VIRTIO_SCSI_COMMON)
> +#define VIRTIO_SCSI_COMMON_CLASS(cls) \
> +        OBJECT_CHECK(VirtIOSCSICommonClass, (cls), TYPE_VIRTIO_SCSI_COMMON)
>  
>  #define TYPE_VIRTIO_SCSI "virtio-scsi-device"
>  #define VIRTIO_SCSI(obj) \
>          OBJECT_CHECK(VirtIOSCSI, (obj), TYPE_VIRTIO_SCSI)
> +#define VIRTIO_SCSI_GET_CLASS(obj) \
> +        OBJECT_GET_CLASS(VirtIOSCSIClass, (obj), TYPE_VIRTIO_SCSI)
> +#define VIRTIO_SCSI_CLASS(cls) \
> +        OBJECT_CHECK(VirtIOSCSIClass, (cls), TYPE_VIRTIO_SCSI)
>  
>  
>  /* The ID for virtio_scsi */
> @@ -166,6 +174,15 @@ typedef struct VirtIOSCSICommon {
>      VirtQueue **cmd_vqs;
>  } VirtIOSCSICommon;
>  
> +typedef struct VirtIOSCSICommonClass {
> +    /*< private >*/
> +    VirtioDeviceClass parent_class;
> +    /*< public >*/
> +
> +    DeviceRealize parent_realize;
> +    DeviceUnrealize parent_unrealize;
> +} VirtIOSCSICommonClass;
> +
>  typedef struct {
>      VirtIOSCSICommon parent_obj;
>  
> @@ -174,6 +191,15 @@ typedef struct {
>      bool events_dropped;
>  } VirtIOSCSI;
>  
> +typedef struct VirtIOSCSIClass {
> +    /*< private >*/
> +    VirtIOSCSICommonClass parent_class;
> +    /*< public >*/
> +
> +    DeviceRealize parent_realize;
> +    DeviceUnrealize parent_unrealize;
> +} VirtIOSCSIClass;
> +
>  #define DEFINE_VIRTIO_SCSI_PROPERTIES(_state, _conf_field)                     \
>      DEFINE_PROP_UINT32("num_queues", _state, _conf_field.num_queues, 1),       \
>      DEFINE_PROP_UINT32("max_sectors", _state, _conf_field.max_sectors, 0xFFFF),\
> @@ -186,7 +212,4 @@ typedef struct {
>      DEFINE_PROP_BIT("param_change", _state, _feature_field,                    \
>                                              VIRTIO_SCSI_F_CHANGE, true)
>  
> -int virtio_scsi_common_init(VirtIOSCSICommon *vs);
> -int virtio_scsi_common_exit(VirtIOSCSICommon *vs);
> -
>  #endif /* _QEMU_VIRTIO_SCSI_H */
> diff --git a/include/hw/virtio/virtio-serial.h b/include/hw/virtio/virtio-serial.h
> index 1d2040b..49af9e3 100644
> --- a/include/hw/virtio/virtio-serial.h
> +++ b/include/hw/virtio/virtio-serial.h
> @@ -212,6 +212,15 @@ struct VirtIOSerial {
>      virtio_serial_conf serial;
>  };
>  
> +typedef struct VirtIOSerialClass {
> +    /*< private >*/
> +    VirtioDeviceClass parent_class;
> +    /*< public >*/
> +
> +    DeviceRealize parent_realize;
> +    DeviceUnrealize parent_unrealize;
> +} VirtIOSerialClass;
> +
>  /* Interface to the virtio-serial bus */
>  
>  /*
> @@ -247,6 +256,10 @@ void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle);
>  #define TYPE_VIRTIO_SERIAL "virtio-serial-device"
>  #define VIRTIO_SERIAL(obj) \
>          OBJECT_CHECK(VirtIOSerial, (obj), TYPE_VIRTIO_SERIAL)
> +#define VIRTIO_SERIAL_GET_CLASS(obj) \
> +        OBJECT_GET_CLASS(VirtIOSerialClass, (obj), TYPE_VIRTIO_SERIAL)
> +#define VIRTIO_SERIAL_CLASS(cls) \
> +        OBJECT_CLASS_CHECK(VirtIOSerialClass, (cls), TYPE_VIRTIO_SERIAL)
>  
>  #define DEFINE_VIRTIO_SERIAL_PROPERTIES(_state, _field) \
>          DEFINE_PROP_UINT32("max_ports", _state, _field.max_virtserial_ports, 31)
> diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
> index a6c5c53..7e1854a 100644
> --- a/include/hw/virtio/virtio.h
> +++ b/include/hw/virtio/virtio.h
> @@ -122,9 +122,11 @@ struct VirtIODevice
>  };
>  
>  typedef struct VirtioDeviceClass {
> -    /* This is what a VirtioDevice must implement */
> +    /*< private >*/
>      DeviceClass parent;
> -    int (*init)(VirtIODevice *vdev);
> +    /*< public >*/
> +
> +    /* This is what a VirtioDevice must implement */
>      uint32_t (*get_features)(VirtIODevice *vdev, uint32_t requested_features);
>      uint32_t (*bad_features)(VirtIODevice *vdev);
>      void (*set_features)(VirtIODevice *vdev, uint32_t val);
> -- 
> 1.8.1.4

Patch

diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index dc6f4e4..409d315 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -41,15 +41,17 @@  static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config)
     g_free(cfg);
 }
 
-static int virtio_9p_device_init(VirtIODevice *vdev)
+static void virtio_9p_device_realize(DeviceState *dev, Error **errp)
 {
-    V9fsState *s = VIRTIO_9P(vdev);
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    V9fsState *s = VIRTIO_9P(dev);
+    V9fsClass *v9c = VIRTIO_9P_GET_CLASS(dev);
     int i, len;
     struct stat stat;
     FsDriverEntry *fse;
     V9fsPath path;
 
-    virtio_init(VIRTIO_DEVICE(s), "virtio-9p", VIRTIO_ID_9P,
+    virtio_init(vdev, "virtio-9p", VIRTIO_ID_9P,
                 sizeof(struct virtio_9p_config) + MAX_TAG_LEN);
 
     /* initialize pdu allocator */
@@ -65,17 +67,17 @@  static int virtio_9p_device_init(VirtIODevice *vdev)
 
     if (!fse) {
         /* We don't have a fsdev identified by fsdev_id */
-        fprintf(stderr, "Virtio-9p device couldn't find fsdev with the "
-                "id = %s\n",
-                s->fsconf.fsdev_id ? s->fsconf.fsdev_id : "NULL");
-        return -1;
+        error_setg(errp, "Virtio-9p device couldn't find fsdev with the "
+                   "id = %s",
+                   s->fsconf.fsdev_id ? s->fsconf.fsdev_id : "NULL");
+        return;
     }
 
     if (!s->fsconf.tag) {
         /* we haven't specified a mount_tag */
-        fprintf(stderr, "fsdev with id %s needs mount_tag arguments\n",
-                s->fsconf.fsdev_id);
-        return -1;
+        error_setg(errp, "fsdev with id %s needs mount_tag arguments",
+                   s->fsconf.fsdev_id);
+        return;
     }
 
     s->ctx.export_flags = fse->export_flags;
@@ -83,9 +85,9 @@  static int virtio_9p_device_init(VirtIODevice *vdev)
     s->ctx.exops.get_st_gen = NULL;
     len = strlen(s->fsconf.tag);
     if (len > MAX_TAG_LEN - 1) {
-        fprintf(stderr, "mount tag '%s' (%d bytes) is longer than "
-                "maximum (%d bytes)", s->fsconf.tag, len, MAX_TAG_LEN - 1);
-        return -1;
+        error_setg(errp, "mount tag '%s' (%d bytes) is longer than "
+                   "maximum (%d bytes)", s->fsconf.tag, len, MAX_TAG_LEN - 1);
+        return;
     }
 
     s->tag = strdup(s->fsconf.tag);
@@ -97,13 +99,13 @@  static int virtio_9p_device_init(VirtIODevice *vdev)
     qemu_co_rwlock_init(&s->rename_lock);
 
     if (s->ops->init(&s->ctx) < 0) {
-        fprintf(stderr, "Virtio-9p Failed to initialize fs-driver with id:%s"
-                " and export path:%s\n", s->fsconf.fsdev_id, s->ctx.fs_root);
-        return -1;
+        error_setg(errp, "Virtio-9p Failed to initialize fs-driver with id:%s"
+                   " and export path:%s", s->fsconf.fsdev_id, s->ctx.fs_root);
+        return;
     }
     if (v9fs_init_worker_threads() < 0) {
-        fprintf(stderr, "worker thread initialization failed\n");
-        return -1;
+        error_setg(errp, "worker thread initialization failed");
+        return;
     }
 
     /*
@@ -113,20 +115,20 @@  static int virtio_9p_device_init(VirtIODevice *vdev)
      */
     v9fs_path_init(&path);
     if (s->ops->name_to_path(&s->ctx, NULL, "/", &path) < 0) {
-        fprintf(stderr,
-                "error in converting name to path %s", strerror(errno));
-        return -1;
+        error_setg(errp,
+                   "error in converting name to path %s", strerror(errno));
+        return;
     }
     if (s->ops->lstat(&s->ctx, &path, &stat)) {
-        fprintf(stderr, "share path %s does not exist\n", fse->path);
-        return -1;
+        error_setg(errp, "share path %s does not exist", fse->path);
+        return;
     } else if (!S_ISDIR(stat.st_mode)) {
-        fprintf(stderr, "share path %s is not a directory\n", fse->path);
-        return -1;
+        error_setg(errp, "share path %s is not a directory", fse->path);
+        return;
     }
     v9fs_path_free(&path);
 
-    return 0;
+    v9c->parent_realize(dev, errp);
 }
 
 /* virtio-9p device */
@@ -136,12 +138,16 @@  static Property virtio_9p_properties[] = {
     DEFINE_PROP_END_OF_LIST(),
 };
 
-static void virtio_9p_class_init(ObjectClass *klass, void *data)
+static void virtio_9p_class_init(ObjectClass *oc, void *data)
 {
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(oc);
+    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(oc);
+    V9fsClass *v9c = VIRTIO_9P_CLASS(oc);
+
+    v9c->parent_realize = dc->realize;
+    dc->realize = virtio_9p_device_realize;
+
     dc->props = virtio_9p_properties;
-    vdc->init = virtio_9p_device_init;
     vdc->get_features = virtio_9p_get_features;
     vdc->get_config = virtio_9p_get_config;
 }
@@ -151,6 +157,7 @@  static const TypeInfo virtio_device_info = {
     .parent = TYPE_VIRTIO_DEVICE,
     .instance_size = sizeof(V9fsState),
     .class_init = virtio_9p_class_init,
+    .class_size = sizeof(V9fsClass),
 };
 
 static void virtio_9p_register_types(void)
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
index 1d6eedb..85699a7 100644
--- a/hw/9pfs/virtio-9p.h
+++ b/hw/9pfs/virtio-9p.h
@@ -227,6 +227,15 @@  typedef struct V9fsState
     V9fsConf fsconf;
 } V9fsState;
 
+typedef struct V9fsClass {
+    /*< private >*/
+    VirtioDeviceClass parent_class;
+    /*< public >*/
+
+    DeviceRealize parent_realize;
+} V9fsClass;
+
+
 typedef struct V9fsStatState {
     V9fsPDU *pdu;
     size_t offset;
@@ -404,6 +413,10 @@  extern int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath,
 #define TYPE_VIRTIO_9P "virtio-9p-device"
 #define VIRTIO_9P(obj) \
         OBJECT_CHECK(V9fsState, (obj), TYPE_VIRTIO_9P)
+#define VIRTIO_9P_GET_CLASS(obj) \
+        OBJECT_GET_CLASS(V9fsClass, (obj), TYPE_VIRTIO_9P)
+#define VIRTIO_9P_CLASS(cls) \
+        OBJECT_CLASS_CHECK(V9fsClass, (cls), TYPE_VIRTIO_9P)
 
 #define DEFINE_VIRTIO_9P_PROPERTIES(_state, _field)             \
         DEFINE_PROP_STRING("mount_tag", _state, _field.tag),    \
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index 8ea1f03..88e99a6 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -628,10 +628,11 @@  void virtio_blk_set_conf(DeviceState *dev, VirtIOBlkConf *blk)
     memcpy(&(s->blk), blk, sizeof(struct VirtIOBlkConf));
 }
 
-static int virtio_blk_device_init(VirtIODevice *vdev)
+static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
 {
-    DeviceState *qdev = DEVICE(vdev);
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
     VirtIOBlock *s = VIRTIO_BLK(vdev);
+    VirtIOBlockClass *vbc = VIRTIO_BLK_GET_CLASS(dev);
     VirtIOBlkConf *blk = &(s->blk);
 #ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
     Error *err = NULL;
@@ -639,17 +640,18 @@  static int virtio_blk_device_init(VirtIODevice *vdev)
     static int virtio_blk_id;
 
     if (!blk->conf.bs) {
-        error_report("drive property not set");
-        return -1;
+        error_setg(errp, "drive property not set");
+        return;
     }
     if (!bdrv_is_inserted(blk->conf.bs)) {
-        error_report("Device needs media, but drive is empty");
-        return -1;
+        error_setg(errp, "Device needs media, but drive is empty");
+        return;
     }
 
     blkconf_serial(&blk->conf, &blk->serial);
     if (blkconf_geometry(&blk->conf, NULL, 65535, 255, 255) < 0) {
-        return -1;
+        error_setg(errp, "Error setting geometry");
+        return;
     }
 
     virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK,
@@ -665,29 +667,31 @@  static int virtio_blk_device_init(VirtIODevice *vdev)
 #ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
     virtio_blk_data_plane_create(vdev, blk, &s->dataplane, &err);
     if (err != NULL) {
-        error_report("%s", error_get_pretty(err));
-        error_free(err);
+        error_propagate(errp, err);
         virtio_cleanup(vdev);
-        return -1;
+        return;
     }
 #endif
 
     s->change = qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s);
-    register_savevm(qdev, "virtio-blk", virtio_blk_id++, 2,
+    register_savevm(dev, "virtio-blk", virtio_blk_id++, 2,
                     virtio_blk_save, virtio_blk_load, s);
     bdrv_set_dev_ops(s->bs, &virtio_block_ops, s);
     bdrv_set_buffer_alignment(s->bs, s->conf->logical_block_size);
 
     bdrv_iostatus_enable(s->bs);
 
-    add_boot_device_path(s->conf->bootindex, qdev, "/disk@0,0");
-    return 0;
+    add_boot_device_path(s->conf->bootindex, dev, "/disk@0,0");
+
+    vbc->parent_realize(dev, errp);
 }
 
-static int virtio_blk_device_exit(DeviceState *dev)
+static void virtio_blk_device_unrealize(DeviceState *dev, Error **errp)
 {
     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
     VirtIOBlock *s = VIRTIO_BLK(dev);
+    VirtIOBlockClass *vbc = VIRTIO_BLK_GET_CLASS(dev);
+
 #ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
     virtio_blk_data_plane_destroy(s->dataplane);
     s->dataplane = NULL;
@@ -696,7 +700,8 @@  static int virtio_blk_device_exit(DeviceState *dev)
     unregister_savevm(dev, "virtio-blk", s);
     blockdev_mark_auto_del(s->bs);
     virtio_cleanup(vdev);
-    return 0;
+
+    vbc->parent_unrealize(dev, errp);
 }
 
 static Property virtio_blk_properties[] = {
@@ -704,13 +709,19 @@  static Property virtio_blk_properties[] = {
     DEFINE_PROP_END_OF_LIST(),
 };
 
-static void virtio_blk_class_init(ObjectClass *klass, void *data)
+static void virtio_blk_class_init(ObjectClass *oc, void *data)
 {
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
-    dc->exit = virtio_blk_device_exit;
+    DeviceClass *dc = DEVICE_CLASS(oc);
+    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(oc);
+    VirtIOBlockClass *vbc = VIRTIO_BLK_CLASS(oc);
+
+    vbc->parent_realize = dc->realize;
+    dc->realize = virtio_blk_device_realize;
+
+    vbc->parent_unrealize = dc->unrealize;
+    dc->unrealize = virtio_blk_device_unrealize;
+
     dc->props = virtio_blk_properties;
-    vdc->init = virtio_blk_device_init;
     vdc->get_config = virtio_blk_update_config;
     vdc->set_config = virtio_blk_set_config;
     vdc->get_features = virtio_blk_get_features;
@@ -723,6 +734,7 @@  static const TypeInfo virtio_device_info = {
     .parent = TYPE_VIRTIO_DEVICE,
     .instance_size = sizeof(VirtIOBlock),
     .class_init = virtio_blk_class_init,
+    .class_size = sizeof(VirtIOBlockClass),
 };
 
 static void virtio_register_types(void)
diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
index cc3d1dd..1cdd659 100644
--- a/hw/char/virtio-serial-bus.c
+++ b/hw/char/virtio-serial-bus.c
@@ -889,31 +889,35 @@  static int virtser_port_qdev_exit(DeviceState *qdev)
     return 0;
 }
 
-static int virtio_serial_device_init(VirtIODevice *vdev)
+static void virtio_serial_device_realize(DeviceState *dev, Error **errp)
 {
-    DeviceState *qdev = DEVICE(vdev);
-    VirtIOSerial *vser = VIRTIO_SERIAL(vdev);
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VirtIOSerial *vser = VIRTIO_SERIAL(dev);
+    VirtIOSerialClass *vsc = VIRTIO_SERIAL_GET_CLASS(dev);
+    BusState *bus;
     uint32_t i, max_supported_ports;
 
     if (!vser->serial.max_virtserial_ports) {
-        return -1;
+        error_setg(errp, "Maximum number of serial ports not specified");
+        return;
     }
 
     /* Each port takes 2 queues, and one pair is for the control queue */
     max_supported_ports = VIRTIO_PCI_QUEUE_MAX / 2 - 1;
 
     if (vser->serial.max_virtserial_ports > max_supported_ports) {
-        error_report("maximum ports supported: %u", max_supported_ports);
-        return -1;
+        error_setg(errp, "maximum ports supported: %u", max_supported_ports);
+        return;
     }
 
     virtio_init(vdev, "virtio-serial", VIRTIO_ID_CONSOLE,
                 sizeof(struct virtio_console_config));
 
     /* Spawn a new virtio-serial bus on which the ports will ride as devices */
-    qbus_create_inplace(&vser->bus.qbus, TYPE_VIRTIO_SERIAL_BUS, qdev,
+    qbus_create_inplace(&vser->bus, TYPE_VIRTIO_SERIAL_BUS, dev,
                         vdev->bus_name);
-    vser->bus.qbus.allow_hotplug = 1;
+    bus = BUS(&vser->bus);
+    bus->allow_hotplug = 1;
     vser->bus.vser = vser;
     QTAILQ_INIT(&vser->ports);
 
@@ -961,10 +965,10 @@  static int virtio_serial_device_init(VirtIODevice *vdev)
      * Register for the savevm section with the virtio-console name
      * to preserve backward compat
      */
-    register_savevm(qdev, "virtio-console", -1, 3, virtio_serial_save,
+    register_savevm(dev, "virtio-console", -1, 3, virtio_serial_save,
                     virtio_serial_load, vser);
 
-    return 0;
+    vsc->parent_realize(dev, errp);
 }
 
 static void virtio_serial_port_class_init(ObjectClass *klass, void *data)
@@ -986,10 +990,11 @@  static const TypeInfo virtio_serial_port_type_info = {
     .class_init = virtio_serial_port_class_init,
 };
 
-static int virtio_serial_device_exit(DeviceState *dev)
+static void virtio_serial_device_unrealize(DeviceState *dev, Error **errp)
 {
-    VirtIOSerial *vser = VIRTIO_SERIAL(dev);
     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VirtIOSerial *vser = VIRTIO_SERIAL(dev);
+    VirtIOSerialClass *vsc = VIRTIO_SERIAL_GET_CLASS(dev);
 
     unregister_savevm(dev, "virtio-console", vser);
 
@@ -1003,7 +1008,8 @@  static int virtio_serial_device_exit(DeviceState *dev)
         g_free(vser->post_load);
     }
     virtio_cleanup(vdev);
-    return 0;
+
+    vsc->parent_unrealize(dev, errp);
 }
 
 static Property virtio_serial_properties[] = {
@@ -1011,13 +1017,19 @@  static Property virtio_serial_properties[] = {
     DEFINE_PROP_END_OF_LIST(),
 };
 
-static void virtio_serial_class_init(ObjectClass *klass, void *data)
+static void virtio_serial_class_init(ObjectClass *oc, void *data)
 {
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
-    dc->exit = virtio_serial_device_exit;
+    DeviceClass *dc = DEVICE_CLASS(oc);
+    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(oc);
+    VirtIOSerialClass *vsc = VIRTIO_SERIAL_CLASS(oc);
+
+    vsc->parent_realize = dc->realize;
+    dc->realize = virtio_serial_device_realize;
+
+    vsc->parent_unrealize = dc->unrealize;
+    dc->unrealize = virtio_serial_device_unrealize;
+
     dc->props = virtio_serial_properties;
-    vdc->init = virtio_serial_device_init;
     vdc->get_features = get_features;
     vdc->get_config = get_config;
     vdc->set_config = set_config;
@@ -1030,6 +1042,7 @@  static const TypeInfo virtio_device_info = {
     .parent = TYPE_VIRTIO_DEVICE,
     .instance_size = sizeof(VirtIOSerial),
     .class_init = virtio_serial_class_init,
+    .class_size = sizeof(VirtIOSerialClass),
 };
 
 static void virtio_serial_register_types(void)
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 1ea9556..9a3680c 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -1367,15 +1367,16 @@  void virtio_net_set_netclient_name(VirtIONet *n, const char *name,
     n->netclient_type = g_strdup(type);
 }
 
-static int virtio_net_device_init(VirtIODevice *vdev)
+static void virtio_net_device_realize(DeviceState *dev, Error **errp)
 {
     int i;
 
-    DeviceState *qdev = DEVICE(vdev);
-    VirtIONet *n = VIRTIO_NET(vdev);
+    DeviceState *qdev = DEVICE(dev);
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VirtIONet *n = VIRTIO_NET(dev);
+    VirtIONetClass *vnc = VIRTIO_NET_GET_CLASS(dev);
 
-    virtio_init(VIRTIO_DEVICE(n), "virtio-net", VIRTIO_ID_NET,
-                                  n->config_size);
+    virtio_init(vdev, "virtio-net", VIRTIO_ID_NET, n->config_size);
 
     n->max_queues = MAX(n->nic_conf.queues, 1);
     n->vqs = g_malloc0(sizeof(VirtIONetQueue) * n->max_queues);
@@ -1439,24 +1440,26 @@  static int virtio_net_device_init(VirtIODevice *vdev)
 
     n->vlans = g_malloc0(MAX_VLAN >> 3);
 
-    n->qdev = qdev;
-    register_savevm(qdev, "virtio-net", -1, VIRTIO_NET_VM_VERSION,
+    n->qdev = dev;
+    register_savevm(dev, "virtio-net", -1, VIRTIO_NET_VM_VERSION,
                     virtio_net_save, virtio_net_load, n);
 
-    add_boot_device_path(n->nic_conf.bootindex, qdev, "/ethernet-phy@0");
-    return 0;
+    add_boot_device_path(n->nic_conf.bootindex, dev, "/ethernet-phy@0");
+
+    vnc->parent_realize(dev, errp);
 }
 
-static int virtio_net_device_exit(DeviceState *qdev)
+static void virtio_net_device_unrealize(DeviceState *dev, Error **errp)
 {
-    VirtIONet *n = VIRTIO_NET(qdev);
-    VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VirtIONet *n = VIRTIO_NET(dev);
+    VirtIONetClass *vnc = VIRTIO_NET_GET_CLASS(dev);
     int i;
 
     /* This will stop vhost backend if appropriate. */
     virtio_net_set_status(vdev, 0);
 
-    unregister_savevm(qdev, "virtio-net", n);
+    unregister_savevm(dev, "virtio-net", n);
 
     if (n->netclient_name) {
         g_free(n->netclient_name);
@@ -1488,7 +1491,7 @@  static int virtio_net_device_exit(DeviceState *qdev)
     qemu_del_nic(n->nic);
     virtio_cleanup(vdev);
 
-    return 0;
+    vnc->parent_unrealize(dev, errp);
 }
 
 static void virtio_net_instance_init(Object *obj)
@@ -1511,13 +1514,19 @@  static Property virtio_net_properties[] = {
     DEFINE_PROP_END_OF_LIST(),
 };
 
-static void virtio_net_class_init(ObjectClass *klass, void *data)
+static void virtio_net_class_init(ObjectClass *oc, void *data)
 {
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
-    dc->exit = virtio_net_device_exit;
+    DeviceClass *dc = DEVICE_CLASS(oc);
+    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(oc);
+    VirtIONetClass *vnc = VIRTIO_NET_CLASS(oc);
+
+    vnc->parent_realize = dc->realize;
+    dc->realize = virtio_net_device_realize;
+
+    vnc->parent_unrealize = dc->unrealize;
+    dc->unrealize = virtio_net_device_unrealize;
+
     dc->props = virtio_net_properties;
-    vdc->init = virtio_net_device_init;
     vdc->get_config = virtio_net_get_config;
     vdc->set_config = virtio_net_set_config;
     vdc->get_features = virtio_net_get_features;
@@ -1535,6 +1544,7 @@  static const TypeInfo virtio_net_info = {
     .instance_size = sizeof(VirtIONet),
     .instance_init = virtio_net_instance_init,
     .class_init = virtio_net_class_init,
+    .class_size = sizeof(VirtIONetClass),
 };
 
 static void virtio_register_types(void)
diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c
index d7a1c33..cacaf64 100644
--- a/hw/scsi/vhost-scsi.c
+++ b/hw/scsi/vhost-scsi.c
@@ -196,29 +196,32 @@  static void vhost_scsi_set_status(VirtIODevice *vdev, uint8_t val)
     }
 }
 
-static int vhost_scsi_init(VirtIODevice *vdev)
+static void vhost_scsi_realize(DeviceState *dev, Error **errp)
 {
-    VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
-    VHostSCSI *s = VHOST_SCSI(vdev);
+    VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev);
+    VHostSCSI *s = VHOST_SCSI(dev);
+    VHostSCSIClass *vsc = VHOST_SCSI_GET_CLASS(dev);
+    Error *err = NULL;
     int vhostfd = -1;
     int ret;
 
     if (!vs->conf.wwpn) {
-        error_report("vhost-scsi: missing wwpn\n");
-        return -EINVAL;
+        error_setg(errp, "vhost-scsi: missing wwpn");
+        return;
     }
 
     if (vs->conf.vhostfd) {
         vhostfd = monitor_handle_fd_param(cur_mon, vs->conf.vhostfd);
         if (vhostfd == -1) {
-            error_report("vhost-scsi: unable to parse vhostfd\n");
-            return -EINVAL;
+            error_setg(errp, "vhost-scsi: unable to parse vhostfd");
+            return;
         }
     }
 
-    ret = virtio_scsi_common_init(vs);
-    if (ret < 0) {
-        return ret;
+    vsc->parent_realize(dev, &err);
+    if (err != NULL) {
+        error_propagate(errp, err);
+        return;
     }
 
     s->dev.nvqs = VHOST_SCSI_VQ_NUM_FIXED + vs->conf.num_queues;
@@ -227,24 +230,22 @@  static int vhost_scsi_init(VirtIODevice *vdev)
 
     ret = vhost_dev_init(&s->dev, vhostfd, "/dev/vhost-scsi", true);
     if (ret < 0) {
-        error_report("vhost-scsi: vhost initialization failed: %s\n",
-                strerror(-ret));
-        return ret;
+        error_setg(errp, "vhost-scsi: vhost initialization failed: %s",
+                   strerror(-ret));
+        return;
     }
     s->dev.backend_features = 0;
 
     error_setg(&s->migration_blocker,
             "vhost-scsi does not support migration");
     migrate_add_blocker(s->migration_blocker);
-
-    return 0;
 }
 
-static int vhost_scsi_exit(DeviceState *qdev)
+static void vhost_scsi_unrealize(DeviceState *dev, Error **errp)
 {
-    VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
-    VHostSCSI *s = VHOST_SCSI(qdev);
-    VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(qdev);
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VHostSCSI *s = VHOST_SCSI(dev);
+    VHostSCSIClass *vsc = VHOST_SCSI_GET_CLASS(dev);
 
     migrate_del_blocker(s->migration_blocker);
     error_free(s->migration_blocker);
@@ -253,7 +254,8 @@  static int vhost_scsi_exit(DeviceState *qdev)
     vhost_scsi_set_status(vdev, 0);
 
     g_free(s->dev.vqs);
-    return virtio_scsi_common_exit(vs);
+
+    vsc->parent_unrealize(dev, errp);
 }
 
 static Property vhost_scsi_properties[] = {
@@ -261,13 +263,19 @@  static Property vhost_scsi_properties[] = {
     DEFINE_PROP_END_OF_LIST(),
 };
 
-static void vhost_scsi_class_init(ObjectClass *klass, void *data)
+static void vhost_scsi_class_init(ObjectClass *oc, void *data)
 {
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
-    dc->exit = vhost_scsi_exit;
+    DeviceClass *dc = DEVICE_CLASS(oc);
+    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(oc);
+    VHostSCSIClass *vsc = VHOST_SCSI_CLASS(oc);
+
+    vsc->parent_realize = dc->realize;
+    dc->realize = vhost_scsi_realize;
+
+    vsc->parent_unrealize = dc->unrealize;
+    dc->unrealize = vhost_scsi_unrealize;
+
     dc->props = vhost_scsi_properties;
-    vdc->init = vhost_scsi_init;
     vdc->get_features = vhost_scsi_get_features;
     vdc->set_config = vhost_scsi_set_config;
     vdc->set_status = vhost_scsi_set_status;
@@ -278,6 +286,7 @@  static const TypeInfo vhost_scsi_info = {
     .parent = TYPE_VIRTIO_SCSI_COMMON,
     .instance_size = sizeof(VHostSCSI),
     .class_init = vhost_scsi_class_init,
+    .class_size = sizeof(VHostSCSIClass),
 };
 
 static void virtio_register_types(void)
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index 08dd3f3..6704f78 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -587,12 +587,14 @@  static struct SCSIBusInfo virtio_scsi_scsi_info = {
     .load_request = virtio_scsi_load_request,
 };
 
-int virtio_scsi_common_init(VirtIOSCSICommon *s)
+static void virtio_scsi_common_realize(DeviceState *dev, Error **errp)
 {
-    VirtIODevice *vdev = VIRTIO_DEVICE(s);
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VirtIOSCSICommon *s = VIRTIO_SCSI_COMMON(dev);
+    VirtIOSCSICommonClass *vscc = VIRTIO_SCSI_COMMON_GET_CLASS(dev);
     int i;
 
-    virtio_init(VIRTIO_DEVICE(s), "virtio-scsi", VIRTIO_ID_SCSI,
+    virtio_init(vdev, "virtio-scsi", VIRTIO_ID_SCSI,
                 sizeof(VirtIOSCSIConfig));
 
     s->cmd_vqs = g_malloc0(s->conf.num_queues * sizeof(VirtQueue *));
@@ -608,50 +610,53 @@  int virtio_scsi_common_init(VirtIOSCSICommon *s)
                                          virtio_scsi_handle_cmd);
     }
 
-    return 0;
+    vscc->parent_realize(dev, errp);
 }
 
-static int virtio_scsi_device_init(VirtIODevice *vdev)
+static void virtio_scsi_device_realize(DeviceState *dev, Error **errp)
 {
-    DeviceState *qdev = DEVICE(vdev);
-    VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
-    VirtIOSCSI *s = VIRTIO_SCSI(vdev);
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VirtIOSCSI *s = VIRTIO_SCSI(dev);
+    VirtIOSCSIClass *vsc = VIRTIO_SCSI_GET_CLASS(dev);
     static int virtio_scsi_id;
-    int ret;
+    Error *err = NULL;
 
-    ret = virtio_scsi_common_init(vs);
-    if (ret < 0) {
-        return ret;
+    vsc->parent_realize(dev, &err);
+    if (err != NULL) {
+        error_propagate(errp, err);
+        return;
     }
 
-    scsi_bus_new(&s->bus, qdev, &virtio_scsi_scsi_info, vdev->bus_name);
+    scsi_bus_new(&s->bus, dev, &virtio_scsi_scsi_info, vdev->bus_name);
 
-    if (!qdev->hotplugged) {
+    if (!dev->hotplugged) {
         scsi_bus_legacy_handle_cmdline(&s->bus);
     }
 
-    register_savevm(qdev, "virtio-scsi", virtio_scsi_id++, 1,
+    register_savevm(dev, "virtio-scsi", virtio_scsi_id++, 1,
                     virtio_scsi_save, virtio_scsi_load, s);
-
-    return 0;
 }
 
-int virtio_scsi_common_exit(VirtIOSCSICommon *vs)
+static void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp)
 {
-    VirtIODevice *vdev = VIRTIO_DEVICE(vs);
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev);
+    VirtIOSCSICommonClass *vscc = VIRTIO_SCSI_COMMON_GET_CLASS(dev);
 
     g_free(vs->cmd_vqs);
     virtio_cleanup(vdev);
-    return 0;
+
+    vscc->parent_unrealize(dev, errp);
 }
 
-static int virtio_scsi_device_exit(DeviceState *qdev)
+static void virtio_scsi_device_unrealize(DeviceState *dev, Error **errp)
 {
-    VirtIOSCSI *s = VIRTIO_SCSI(qdev);
-    VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(qdev);
+    VirtIOSCSI *s = VIRTIO_SCSI(dev);
+    VirtIOSCSIClass *vsc = VIRTIO_SCSI_GET_CLASS(dev);
 
-    unregister_savevm(qdev, "virtio-scsi", s);
-    return virtio_scsi_common_exit(vs);
+    unregister_savevm(dev, "virtio-scsi", s);
+
+    vsc->parent_unrealize(dev, errp);
 }
 
 static Property virtio_scsi_properties[] = {
@@ -659,20 +664,34 @@  static Property virtio_scsi_properties[] = {
     DEFINE_PROP_END_OF_LIST(),
 };
 
-static void virtio_scsi_common_class_init(ObjectClass *klass, void *data)
+static void virtio_scsi_common_class_init(ObjectClass *oc, void *data)
 {
-    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(oc);
+    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(oc);
+    VirtIOSCSICommonClass *vscc = VIRTIO_SCSI_COMMON_CLASS(oc);
+
+    vscc->parent_realize = dc->realize;
+    dc->realize = virtio_scsi_common_realize;
+
+    vscc->parent_unrealize = dc->unrealize;
+    dc->unrealize = virtio_scsi_common_unrealize;
 
     vdc->get_config = virtio_scsi_get_config;
 }
 
-static void virtio_scsi_class_init(ObjectClass *klass, void *data)
+static void virtio_scsi_class_init(ObjectClass *oc, void *data)
 {
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
-    dc->exit = virtio_scsi_device_exit;
+    DeviceClass *dc = DEVICE_CLASS(oc);
+    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(oc);
+    VirtIOSCSIClass *vsc = VIRTIO_SCSI_CLASS(oc);
+
+    vsc->parent_realize = dc->realize;
+    dc->realize = virtio_scsi_device_realize;
+
+    vsc->parent_unrealize = dc->unrealize;
+    dc->unrealize = virtio_scsi_device_unrealize;
+
     dc->props = virtio_scsi_properties;
-    vdc->init = virtio_scsi_device_init;
     vdc->set_config = virtio_scsi_set_config;
     vdc->get_features = virtio_scsi_get_features;
     vdc->reset = virtio_scsi_reset;
@@ -683,6 +702,7 @@  static const TypeInfo virtio_scsi_common_info = {
     .parent = TYPE_VIRTIO_DEVICE,
     .instance_size = sizeof(VirtIOSCSICommon),
     .class_init = virtio_scsi_common_class_init,
+    .class_size = sizeof(VirtIOSCSICommonClass),
 };
 
 static const TypeInfo virtio_scsi_info = {
@@ -690,6 +710,7 @@  static const TypeInfo virtio_scsi_info = {
     .parent = TYPE_VIRTIO_SCSI_COMMON,
     .instance_size = sizeof(VirtIOSCSI),
     .class_init = virtio_scsi_class_init,
+    .class_size = sizeof(VirtIOSCSIClass),
 };
 
 static void virtio_register_types(void)
diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
index d669756..0535062 100644
--- a/hw/virtio/virtio-balloon.c
+++ b/hw/virtio/virtio-balloon.c
@@ -336,10 +336,11 @@  static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id)
     return 0;
 }
 
-static int virtio_balloon_device_init(VirtIODevice *vdev)
+static void virtio_balloon_device_realize(DeviceState *dev, Error **errp)
 {
-    DeviceState *qdev = DEVICE(vdev);
-    VirtIOBalloon *s = VIRTIO_BALLOON(vdev);
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VirtIOBalloon *s = VIRTIO_BALLOON(dev);
+    VirtIOBalloonClass *vbc = VIRTIO_BALLOON_GET_CLASS(dev);
     int ret;
 
     virtio_init(vdev, "virtio-balloon", VIRTIO_ID_BALLOON, 8);
@@ -348,50 +349,60 @@  static int virtio_balloon_device_init(VirtIODevice *vdev)
                                    virtio_balloon_stat, s);
 
     if (ret < 0) {
-        virtio_cleanup(VIRTIO_DEVICE(s));
-        return -1;
+        error_setg(errp, "Adding balloon handler failed");
+        virtio_cleanup(vdev);
+        return;
     }
 
     s->ivq = virtio_add_queue(vdev, 128, virtio_balloon_handle_output);
     s->dvq = virtio_add_queue(vdev, 128, virtio_balloon_handle_output);
     s->svq = virtio_add_queue(vdev, 128, virtio_balloon_receive_stats);
 
-    register_savevm(qdev, "virtio-balloon", -1, 1,
+    register_savevm(dev, "virtio-balloon", -1, 1,
                     virtio_balloon_save, virtio_balloon_load, s);
 
-    object_property_add(OBJECT(qdev), "guest-stats", "guest statistics",
+    object_property_add(OBJECT(dev), "guest-stats", "guest statistics",
                         balloon_stats_get_all, NULL, NULL, s, NULL);
 
-    object_property_add(OBJECT(qdev), "guest-stats-polling-interval", "int",
+    object_property_add(OBJECT(dev), "guest-stats-polling-interval", "int",
                         balloon_stats_get_poll_interval,
                         balloon_stats_set_poll_interval,
                         NULL, s, NULL);
-    return 0;
+
+    vbc->parent_realize(dev, errp);
 }
 
-static int virtio_balloon_device_exit(DeviceState *qdev)
+static void virtio_balloon_device_unrealize(DeviceState *dev, Error **errp)
 {
-    VirtIOBalloon *s = VIRTIO_BALLOON(qdev);
-    VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VirtIOBalloon *s = VIRTIO_BALLOON(dev);
+    VirtIOBalloonClass *vbc = VIRTIO_BALLOON_GET_CLASS(dev);
 
     balloon_stats_destroy_timer(s);
     qemu_remove_balloon_handler(s);
-    unregister_savevm(qdev, "virtio-balloon", s);
+    unregister_savevm(dev, "virtio-balloon", s);
     virtio_cleanup(vdev);
-    return 0;
+
+    vbc->parent_unrealize(dev, errp);
 }
 
 static Property virtio_balloon_properties[] = {
     DEFINE_PROP_END_OF_LIST(),
 };
 
-static void virtio_balloon_class_init(ObjectClass *klass, void *data)
+static void virtio_balloon_class_init(ObjectClass *oc, void *data)
 {
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
-    dc->exit = virtio_balloon_device_exit;
+    DeviceClass *dc = DEVICE_CLASS(oc);
+    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(oc);
+    VirtIOBalloonClass *vbc = VIRTIO_BALLOON_CLASS(oc);
+
+    vbc->parent_realize = dc->realize;
+    dc->realize = virtio_balloon_device_realize;
+
+    vbc->parent_unrealize = dc->unrealize;
+    dc->unrealize = virtio_balloon_device_unrealize;
+
     dc->props = virtio_balloon_properties;
-    vdc->init = virtio_balloon_device_init;
     vdc->get_config = virtio_balloon_get_config;
     vdc->set_config = virtio_balloon_set_config;
     vdc->get_features = virtio_balloon_get_features;
@@ -402,6 +413,7 @@  static const TypeInfo virtio_balloon_info = {
     .parent = TYPE_VIRTIO_DEVICE,
     .instance_size = sizeof(VirtIOBalloon),
     .class_init = virtio_balloon_class_init,
+    .class_size = sizeof(VirtIOBalloonClass),
 };
 
 static void virtio_register_types(void)
diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c
index cb787c7..108cfc9 100644
--- a/hw/virtio/virtio-rng.c
+++ b/hw/virtio/virtio-rng.c
@@ -133,21 +133,22 @@  static void check_rate_limit(void *opaque)
                    qemu_get_clock_ms(vm_clock) + vrng->conf.period_ms);
 }
 
-static int virtio_rng_device_init(VirtIODevice *vdev)
+static void virtio_rng_device_realize(DeviceState *dev, Error **errp)
 {
-    DeviceState *qdev = DEVICE(vdev);
-    VirtIORNG *vrng = VIRTIO_RNG(vdev);
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VirtIORNG *vrng = VIRTIO_RNG(dev);
+    VirtIORNGClass *vrc = VIRTIO_RNG_GET_CLASS(dev);
     Error *local_err = NULL;
 
     if (vrng->conf.rng == NULL) {
         vrng->conf.default_backend = RNG_RANDOM(object_new(TYPE_RNG_RANDOM));
 
-        object_property_add_child(OBJECT(qdev),
+        object_property_add_child(OBJECT(dev),
                                   "default-backend",
                                   OBJECT(vrng->conf.default_backend),
                                   NULL);
 
-        object_property_set_link(OBJECT(qdev),
+        object_property_set_link(OBJECT(dev),
                                  OBJECT(vrng->conf.default_backend),
                                  "rng", NULL);
     }
@@ -156,15 +157,14 @@  static int virtio_rng_device_init(VirtIODevice *vdev)
 
     vrng->rng = vrng->conf.rng;
     if (vrng->rng == NULL) {
-        qerror_report(QERR_INVALID_PARAMETER_VALUE, "rng", "a valid object");
-        return -1;
+        error_set(errp, QERR_INVALID_PARAMETER_VALUE, "rng", "a valid object");
+        return;
     }
 
     rng_backend_open(vrng->rng, &local_err);
     if (local_err) {
-        qerror_report_err(local_err);
-        error_free(local_err);
-        return -1;
+        error_propagate(errp, local_err);
+        return;
     }
 
     vrng->vq = virtio_add_queue(vdev, 8, handle_input);
@@ -178,22 +178,24 @@  static int virtio_rng_device_init(VirtIODevice *vdev)
     qemu_mod_timer(vrng->rate_limit_timer,
                    qemu_get_clock_ms(vm_clock) + vrng->conf.period_ms);
 
-    register_savevm(qdev, "virtio-rng", -1, 1, virtio_rng_save,
+    register_savevm(dev, "virtio-rng", -1, 1, virtio_rng_save,
                     virtio_rng_load, vrng);
 
-    return 0;
+    vrc->parent_realize(dev, errp);
 }
 
-static int virtio_rng_device_exit(DeviceState *qdev)
+static void virtio_rng_device_unrealize(DeviceState *dev, Error **errp)
 {
-    VirtIORNG *vrng = VIRTIO_RNG(qdev);
-    VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VirtIORNG *vrng = VIRTIO_RNG(dev);
+    VirtIORNGClass *vrc = VIRTIO_RNG_GET_CLASS(dev);
 
     qemu_del_timer(vrng->rate_limit_timer);
     qemu_free_timer(vrng->rate_limit_timer);
-    unregister_savevm(qdev, "virtio-rng", vrng);
+    unregister_savevm(dev, "virtio-rng", vrng);
     virtio_cleanup(vdev);
-    return 0;
+
+    vrc->parent_unrealize(dev, errp);
 }
 
 static Property virtio_rng_properties[] = {
@@ -201,13 +203,19 @@  static Property virtio_rng_properties[] = {
     DEFINE_PROP_END_OF_LIST(),
 };
 
-static void virtio_rng_class_init(ObjectClass *klass, void *data)
+static void virtio_rng_class_init(ObjectClass *oc, void *data)
 {
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
-    dc->exit = virtio_rng_device_exit;
+    DeviceClass *dc = DEVICE_CLASS(oc);
+    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(oc);
+    VirtIORNGClass *vrc = VIRTIO_RNG_CLASS(oc);
+
+    vrc->parent_realize = dc->realize;
+    dc->realize = virtio_rng_device_realize;
+
+    vrc->parent_unrealize = dc->unrealize;
+    dc->unrealize = virtio_rng_device_unrealize;
+
     dc->props = virtio_rng_properties;
-    vdc->init = virtio_rng_device_init;
     vdc->get_features = get_features;
 }
 
@@ -225,6 +233,7 @@  static const TypeInfo virtio_rng_info = {
     .instance_size = sizeof(VirtIORNG),
     .instance_init = virtio_rng_initfn,
     .class_init = virtio_rng_class_init,
+    .class_size = sizeof(VirtIORNGClass),
 };
 
 static void virtio_register_types(void)
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 8176c14..d369f9a 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -1105,35 +1105,29 @@  void virtio_device_set_child_bus_name(VirtIODevice *vdev, char *bus_name)
     }
 }
 
-static int virtio_device_init(DeviceState *qdev)
+static void virtio_device_realize(DeviceState *dev, Error **errp)
 {
-    VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
-    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(qdev);
-    assert(k->init != NULL);
-    if (k->init(vdev) < 0) {
-        return -1;
-    }
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+
     virtio_bus_plug_device(vdev);
-    return 0;
 }
 
-static int virtio_device_exit(DeviceState *qdev)
+static void virtio_device_unrealize(DeviceState *dev, Error **errp)
 {
-    VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
 
     if (vdev->bus_name) {
         g_free(vdev->bus_name);
         vdev->bus_name = NULL;
     }
-    return 0;
 }
 
 static void virtio_device_class_init(ObjectClass *klass, void *data)
 {
     /* Set the default value here. */
     DeviceClass *dc = DEVICE_CLASS(klass);
-    dc->init = virtio_device_init;
-    dc->exit = virtio_device_exit;
+    dc->realize = virtio_device_realize;
+    dc->unrealize = virtio_device_unrealize;
     dc->bus_type = TYPE_VIRTIO_BUS;
 }
 
diff --git a/include/hw/virtio/vhost-scsi.h b/include/hw/virtio/vhost-scsi.h
index 85cc031..b0d64e4 100644
--- a/include/hw/virtio/vhost-scsi.h
+++ b/include/hw/virtio/vhost-scsi.h
@@ -53,6 +53,10 @@  enum vhost_scsi_vq_list {
 #define TYPE_VHOST_SCSI "vhost-scsi"
 #define VHOST_SCSI(obj) \
         OBJECT_CHECK(VHostSCSI, (obj), TYPE_VHOST_SCSI)
+#define VHOST_SCSI_GET_CLASS(obj) \
+        OBJECT_GET_CLASS(VHostSCSIClass, (obj), TYPE_VHOST_SCSI)
+#define VHOST_SCSI_CLASS(cls) \
+        OBJECT_CLASS_CHECK(VHostSCSIClass, (cls), TYPE_VHOST_SCSI)
 
 typedef struct VHostSCSI {
     VirtIOSCSICommon parent_obj;
@@ -62,6 +66,15 @@  typedef struct VHostSCSI {
     struct vhost_dev dev;
 } VHostSCSI;
 
+typedef struct VHostSCSIClass {
+    /*< private >*/
+    VirtIOSCSICommonClass parent_class;
+    /*< public >*/
+
+    DeviceRealize parent_realize;
+    DeviceUnrealize parent_unrealize;
+} VHostSCSIClass;
+
 #define DEFINE_VHOST_SCSI_PROPERTIES(_state, _conf_field) \
     DEFINE_PROP_STRING("vhostfd", _state, _conf_field.vhostfd), \
     DEFINE_PROP_STRING("wwpn", _state, _conf_field.wwpn), \
diff --git a/include/hw/virtio/virtio-balloon.h b/include/hw/virtio/virtio-balloon.h
index f863bfe..146fa04 100644
--- a/include/hw/virtio/virtio-balloon.h
+++ b/include/hw/virtio/virtio-balloon.h
@@ -21,6 +21,10 @@ 
 #define TYPE_VIRTIO_BALLOON "virtio-balloon-device"
 #define VIRTIO_BALLOON(obj) \
         OBJECT_CHECK(VirtIOBalloon, (obj), TYPE_VIRTIO_BALLOON)
+#define VIRTIO_BALLOON_GET_CLASS(obj) \
+        OBJECT_GET_CLASS(VirtIOBalloonClass, (obj), TYPE_VIRTIO_BALLOON)
+#define VIRTIO_BALLOON_CLASS(cls) \
+        OBJECT_CLASS_CHECK(VirtIOBalloonClass, (cls), TYPE_VIRTIO_BALLOON)
 
 /* from Linux's linux/virtio_balloon.h */
 
@@ -69,4 +73,13 @@  typedef struct VirtIOBalloon {
     int64_t stats_poll_interval;
 } VirtIOBalloon;
 
+typedef struct VirtIOBalloonClass {
+    /*< private >*/
+    VirtioDeviceClass parent_class;
+    /*< public >*/
+
+    DeviceRealize parent_realize;
+    DeviceUnrealize parent_unrealize;
+} VirtIOBalloonClass;
+
 #endif
diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h
index fc71853..5ed703d 100644
--- a/include/hw/virtio/virtio-blk.h
+++ b/include/hw/virtio/virtio-blk.h
@@ -20,6 +20,10 @@ 
 #define TYPE_VIRTIO_BLK "virtio-blk-device"
 #define VIRTIO_BLK(obj) \
         OBJECT_CHECK(VirtIOBlock, (obj), TYPE_VIRTIO_BLK)
+#define VIRTIO_BLK_GET_CLASS(obj) \
+        OBJECT_GET_CLASS(VirtIOBlockClass, (obj), TYPE_VIRTIO_BLK)
+#define VIRTIO_BLK_CLASS(cls) \
+        OBJECT_CLASS_CHECK(VirtIOBlockClass, (cls), TYPE_VIRTIO_BLK)
 
 /* from Linux's linux/virtio_blk.h */
 
@@ -129,6 +133,15 @@  typedef struct VirtIOBlock {
 #endif
 } VirtIOBlock;
 
+typedef struct VirtIOBlockClass {
+    /*< private >*/
+    VirtioDeviceClass parent_class;
+    /*< public >*/
+
+    DeviceRealize parent_realize;
+    DeviceUnrealize parent_unrealize;
+} VirtIOBlockClass;
+
 #define DEFINE_VIRTIO_BLK_FEATURES(_state, _field) \
         DEFINE_VIRTIO_COMMON_FEATURES(_state, _field)
 
diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
index b315ac9..0b8a06e 100644
--- a/include/hw/virtio/virtio-net.h
+++ b/include/hw/virtio/virtio-net.h
@@ -20,6 +20,10 @@ 
 #define TYPE_VIRTIO_NET "virtio-net-device"
 #define VIRTIO_NET(obj) \
         OBJECT_CHECK(VirtIONet, (obj), TYPE_VIRTIO_NET)
+#define VIRTIO_NET_GET_CLASS(obj) \
+        OBJECT_GET_CLASS(VirtIONetClass, (obj), TYPE_VIRTIO_NET)
+#define VIRTIO_NET_CLASS(cls) \
+        OBJECT_CLASS_CHECK(VirtIONetClass, (cls), TYPE_VIRTIO_NET)
 
 #define ETH_ALEN    6
 
@@ -195,6 +199,15 @@  typedef struct VirtIONet {
     uint64_t curr_guest_offloads;
 } VirtIONet;
 
+typedef struct VirtIONetClass {
+    /*< private >*/
+    VirtioDeviceClass parent_class;
+    /*< public >*/
+
+    DeviceRealize parent_realize;
+    DeviceUnrealize parent_unrealize;
+} VirtIONetClass;
+
 #define VIRTIO_NET_CTRL_MAC    1
  #define VIRTIO_NET_CTRL_MAC_TABLE_SET        0
  #define VIRTIO_NET_CTRL_MAC_ADDR_SET         1
diff --git a/include/hw/virtio/virtio-rng.h b/include/hw/virtio/virtio-rng.h
index debaa15..528f70c 100644
--- a/include/hw/virtio/virtio-rng.h
+++ b/include/hw/virtio/virtio-rng.h
@@ -18,6 +18,10 @@ 
 #define TYPE_VIRTIO_RNG "virtio-rng-device"
 #define VIRTIO_RNG(obj) \
         OBJECT_CHECK(VirtIORNG, (obj), TYPE_VIRTIO_RNG)
+#define VIRTIO_RNG_GET_CLASS(obj) \
+        OBJECT_GET_CLASS(VirtIORNGClass, (obj), TYPE_VIRTIO_RNG)
+#define VIRTIO_RNG_CLASS(cls) \
+        OBJECT_CLASS_CHECK(VirtIORNGClass, (cls), TYPE_VIRTIO_RNG)
 
 /* The Virtio ID for the virtio rng device */
 #define VIRTIO_ID_RNG    4
@@ -46,6 +50,15 @@  typedef struct VirtIORNG {
     int64_t quota_remaining;
 } VirtIORNG;
 
+typedef struct VirtIORNGClass {
+    /*< private >*/
+    VirtioDeviceClass parent_class;
+    /*< public >*/
+
+    DeviceRealize parent_realize;
+    DeviceUnrealize parent_unrealize;
+} VirtIORNGClass;
+
 /* Set a default rate limit of 2^47 bytes per minute or roughly 2TB/s.  If
    you have an entropy source capable of generating more entropy than this
    and you can pass it through via virtio-rng, then hats off to you.  Until
diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h
index 9a98540..2ce58cd 100644
--- a/include/hw/virtio/virtio-scsi.h
+++ b/include/hw/virtio/virtio-scsi.h
@@ -21,10 +21,18 @@ 
 #define TYPE_VIRTIO_SCSI_COMMON "virtio-scsi-common"
 #define VIRTIO_SCSI_COMMON(obj) \
         OBJECT_CHECK(VirtIOSCSICommon, (obj), TYPE_VIRTIO_SCSI_COMMON)
+#define VIRTIO_SCSI_COMMON_GET_CLASS(obj) \
+        OBJECT_GET_CLASS(VirtIOSCSICommonClass, (obj), TYPE_VIRTIO_SCSI_COMMON)
+#define VIRTIO_SCSI_COMMON_CLASS(cls) \
+        OBJECT_CHECK(VirtIOSCSICommonClass, (cls), TYPE_VIRTIO_SCSI_COMMON)
 
 #define TYPE_VIRTIO_SCSI "virtio-scsi-device"
 #define VIRTIO_SCSI(obj) \
         OBJECT_CHECK(VirtIOSCSI, (obj), TYPE_VIRTIO_SCSI)
+#define VIRTIO_SCSI_GET_CLASS(obj) \
+        OBJECT_GET_CLASS(VirtIOSCSIClass, (obj), TYPE_VIRTIO_SCSI)
+#define VIRTIO_SCSI_CLASS(cls) \
+        OBJECT_CHECK(VirtIOSCSIClass, (cls), TYPE_VIRTIO_SCSI)
 
 
 /* The ID for virtio_scsi */
@@ -166,6 +174,15 @@  typedef struct VirtIOSCSICommon {
     VirtQueue **cmd_vqs;
 } VirtIOSCSICommon;
 
+typedef struct VirtIOSCSICommonClass {
+    /*< private >*/
+    VirtioDeviceClass parent_class;
+    /*< public >*/
+
+    DeviceRealize parent_realize;
+    DeviceUnrealize parent_unrealize;
+} VirtIOSCSICommonClass;
+
 typedef struct {
     VirtIOSCSICommon parent_obj;
 
@@ -174,6 +191,15 @@  typedef struct {
     bool events_dropped;
 } VirtIOSCSI;
 
+typedef struct VirtIOSCSIClass {
+    /*< private >*/
+    VirtIOSCSICommonClass parent_class;
+    /*< public >*/
+
+    DeviceRealize parent_realize;
+    DeviceUnrealize parent_unrealize;
+} VirtIOSCSIClass;
+
 #define DEFINE_VIRTIO_SCSI_PROPERTIES(_state, _conf_field)                     \
     DEFINE_PROP_UINT32("num_queues", _state, _conf_field.num_queues, 1),       \
     DEFINE_PROP_UINT32("max_sectors", _state, _conf_field.max_sectors, 0xFFFF),\
@@ -186,7 +212,4 @@  typedef struct {
     DEFINE_PROP_BIT("param_change", _state, _feature_field,                    \
                                             VIRTIO_SCSI_F_CHANGE, true)
 
-int virtio_scsi_common_init(VirtIOSCSICommon *vs);
-int virtio_scsi_common_exit(VirtIOSCSICommon *vs);
-
 #endif /* _QEMU_VIRTIO_SCSI_H */
diff --git a/include/hw/virtio/virtio-serial.h b/include/hw/virtio/virtio-serial.h
index 1d2040b..49af9e3 100644
--- a/include/hw/virtio/virtio-serial.h
+++ b/include/hw/virtio/virtio-serial.h
@@ -212,6 +212,15 @@  struct VirtIOSerial {
     virtio_serial_conf serial;
 };
 
+typedef struct VirtIOSerialClass {
+    /*< private >*/
+    VirtioDeviceClass parent_class;
+    /*< public >*/
+
+    DeviceRealize parent_realize;
+    DeviceUnrealize parent_unrealize;
+} VirtIOSerialClass;
+
 /* Interface to the virtio-serial bus */
 
 /*
@@ -247,6 +256,10 @@  void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle);
 #define TYPE_VIRTIO_SERIAL "virtio-serial-device"
 #define VIRTIO_SERIAL(obj) \
         OBJECT_CHECK(VirtIOSerial, (obj), TYPE_VIRTIO_SERIAL)
+#define VIRTIO_SERIAL_GET_CLASS(obj) \
+        OBJECT_GET_CLASS(VirtIOSerialClass, (obj), TYPE_VIRTIO_SERIAL)
+#define VIRTIO_SERIAL_CLASS(cls) \
+        OBJECT_CLASS_CHECK(VirtIOSerialClass, (cls), TYPE_VIRTIO_SERIAL)
 
 #define DEFINE_VIRTIO_SERIAL_PROPERTIES(_state, _field) \
         DEFINE_PROP_UINT32("max_ports", _state, _field.max_virtserial_ports, 31)
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index a6c5c53..7e1854a 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -122,9 +122,11 @@  struct VirtIODevice
 };
 
 typedef struct VirtioDeviceClass {
-    /* This is what a VirtioDevice must implement */
+    /*< private >*/
     DeviceClass parent;
-    int (*init)(VirtIODevice *vdev);
+    /*< public >*/
+
+    /* This is what a VirtioDevice must implement */
     uint32_t (*get_features)(VirtIODevice *vdev, uint32_t requested_features);
     uint32_t (*bad_features)(VirtIODevice *vdev);
     void (*set_features)(VirtIODevice *vdev, uint32_t val);