qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Maxim Levitsky <mlevitsk@redhat.com>
To: Paolo Bonzini <pbonzini@redhat.com>, qemu-devel@nongnu.org
Cc: stefanha@redhat.com
Subject: Re: [PATCH 05/10] device-core: use RCU for list of children of a bus
Date: Wed, 30 Sep 2020 17:29:30 +0300	[thread overview]
Message-ID: <b19d5fb160f2a1f959531d2389300f32eee6bec2.camel@redhat.com> (raw)
In-Reply-To: <20200925172604.2142227-6-pbonzini@redhat.com>

On Fri, 2020-09-25 at 13:25 -0400, Paolo Bonzini wrote:
> From: Maxim Levitsky <mlevitsk@redhat.com>
> 
> This fixes the race between device emulation code that tries to find
> a child device to dispatch the request to (e.g a scsi disk),
> and hotplug of a new device to that bus.
> 
> Note that this doesn't convert all the readers of the list
> but only these that might go over that list without BQL held.
> 
> This is a very small first step to make this code thread safe.
> 
> Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
> Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
> Message-Id: <20200913160259.32145-5-mlevitsk@redhat.com>
> [Use RCU_READ_LOCK_GUARD in more places. - Paolo]
This is a good idea which I don't yet use much.


Best regards,
	Maxim Levitsky

> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  hw/core/bus.c          | 28 +++++++++++++++++-----------
>  hw/core/qdev.c         | 37 +++++++++++++++++++++++--------------
>  hw/scsi/scsi-bus.c     | 12 +++++++++---
>  hw/scsi/virtio-scsi.c  |  6 +++++-
>  include/hw/qdev-core.h |  9 +++++++++
>  5 files changed, 63 insertions(+), 29 deletions(-)
> 
> diff --git a/hw/core/bus.c b/hw/core/bus.c
> index 6b987b6946..a0483859ae 100644
> --- a/hw/core/bus.c
> +++ b/hw/core/bus.c
> @@ -49,12 +49,14 @@ int qbus_walk_children(BusState *bus,
>          }
>      }
>  
> -    QTAILQ_FOREACH(kid, &bus->children, sibling) {
> -        err = qdev_walk_children(kid->child,
> -                                 pre_devfn, pre_busfn,
> -                                 post_devfn, post_busfn, opaque);
> -        if (err < 0) {
> -            return err;
> +    WITH_RCU_READ_LOCK_GUARD() {
> +        QTAILQ_FOREACH_RCU(kid, &bus->children, sibling) {
> +            err = qdev_walk_children(kid->child,
> +                                     pre_devfn, pre_busfn,
> +                                     post_devfn, post_busfn, opaque);
> +            if (err < 0) {
> +                return err;
> +            }
>          }
>      }
>  
> @@ -90,8 +92,10 @@ static void bus_reset_child_foreach(Object *obj, ResettableChildCallback cb,
>      BusState *bus = BUS(obj);
>      BusChild *kid;
>  
> -    QTAILQ_FOREACH(kid, &bus->children, sibling) {
> -        cb(OBJECT(kid->child), opaque, type);
> +    WITH_RCU_READ_LOCK_GUARD() {
> +        QTAILQ_FOREACH_RCU(kid, &bus->children, sibling) {
> +            cb(OBJECT(kid->child), opaque, type);
> +        }
>      }
>  }
>  
> @@ -194,9 +198,11 @@ static void bus_set_realized(Object *obj, bool value, Error **errp)
>  
>          /* TODO: recursive realization */
>      } else if (!value && bus->realized) {
> -        QTAILQ_FOREACH(kid, &bus->children, sibling) {
> -            DeviceState *dev = kid->child;
> -            qdev_unrealize(dev);
> +        WITH_RCU_READ_LOCK_GUARD() {
> +            QTAILQ_FOREACH_RCU(kid, &bus->children, sibling) {
> +                DeviceState *dev = kid->child;
> +                qdev_unrealize(dev);
> +            }
>          }
>          if (bc->unrealize) {
>              bc->unrealize(bus);
> diff --git a/hw/core/qdev.c b/hw/core/qdev.c
> index 74db78df36..59e5e710b7 100644
> --- a/hw/core/qdev.c
> +++ b/hw/core/qdev.c
> @@ -51,6 +51,12 @@ const VMStateDescription *qdev_get_vmsd(DeviceState *dev)
>      return dc->vmsd;
>  }
>  
> +static void bus_free_bus_child(BusChild *kid)
> +{
> +    object_unref(OBJECT(kid->child));
> +    g_free(kid);
> +}
> +
>  static void bus_remove_child(BusState *bus, DeviceState *child)
>  {
>      BusChild *kid;
> @@ -60,15 +66,16 @@ static void bus_remove_child(BusState *bus, DeviceState *child)
>              char name[32];
>  
>              snprintf(name, sizeof(name), "child[%d]", kid->index);
> -            QTAILQ_REMOVE(&bus->children, kid, sibling);
> +            QTAILQ_REMOVE_RCU(&bus->children, kid, sibling);
>  
>              bus->num_children--;
>  
>              /* This gives back ownership of kid->child back to us.  */
>              object_property_del(OBJECT(bus), name);
> -            object_unref(OBJECT(kid->child));
> -            g_free(kid);
> -            return;
> +
> +            /* free the bus kid, when it is safe to do so*/
> +            call_rcu(kid, bus_free_bus_child, rcu);
> +            break;
>          }
>      }
>  }
> @@ -83,7 +90,7 @@ static void bus_add_child(BusState *bus, DeviceState *child)
>      kid->child = child;
>      object_ref(OBJECT(kid->child));
>  
> -    QTAILQ_INSERT_HEAD(&bus->children, kid, sibling);
> +    QTAILQ_INSERT_HEAD_RCU(&bus->children, kid, sibling);
>  
>      /* This transfers ownership of kid->child to the property.  */
>      snprintf(name, sizeof(name), "child[%d]", kid->index);
> @@ -672,17 +679,19 @@ DeviceState *qdev_find_recursive(BusState *bus, const char *id)
>      DeviceState *ret;
>      BusState *child;
>  
> -    QTAILQ_FOREACH(kid, &bus->children, sibling) {
> -        DeviceState *dev = kid->child;
> +    WITH_RCU_READ_LOCK_GUARD() {
> +        QTAILQ_FOREACH_RCU(kid, &bus->children, sibling) {
> +            DeviceState *dev = kid->child;
>  
> -        if (dev->id && strcmp(dev->id, id) == 0) {
> -            return dev;
> -        }
> +            if (dev->id && strcmp(dev->id, id) == 0) {
> +                return dev;
> +            }
>  
> -        QLIST_FOREACH(child, &dev->child_bus, sibling) {
> -            ret = qdev_find_recursive(child, id);
> -            if (ret) {
> -                return ret;
> +            QLIST_FOREACH(child, &dev->child_bus, sibling) {
> +                ret = qdev_find_recursive(child, id);
> +                if (ret) {
> +                    return ret;
> +                }
>              }
>          }
>      }
> diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
> index 69d7c3f90c..4ab9811cd8 100644
> --- a/hw/scsi/scsi-bus.c
> +++ b/hw/scsi/scsi-bus.c
> @@ -399,7 +399,10 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
>      id = r->req.dev->id;
>      found_lun0 = false;
>      n = 0;
> -    QTAILQ_FOREACH(kid, &r->req.bus->qbus.children, sibling) {
> +
> +    RCU_READ_LOCK_GUARD();
> +
> +    QTAILQ_FOREACH_RCU(kid, &r->req.bus->qbus.children, sibling) {
>          DeviceState *qdev = kid->child;
>          SCSIDevice *dev = SCSI_DEVICE(qdev);
>  
> @@ -420,7 +423,7 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
>      memset(r->buf, 0, len);
>      stl_be_p(&r->buf[0], n);
>      i = found_lun0 ? 8 : 16;
> -    QTAILQ_FOREACH(kid, &r->req.bus->qbus.children, sibling) {
> +    QTAILQ_FOREACH_RCU(kid, &r->req.bus->qbus.children, sibling) {
>          DeviceState *qdev = kid->child;
>          SCSIDevice *dev = SCSI_DEVICE(qdev);
>  
> @@ -429,6 +432,7 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
>              i += 8;
>          }
>      }
> +
>      assert(i == n + 8);
>      r->len = len;
>      return true;
> @@ -1571,7 +1575,8 @@ SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int lun)
>      BusChild *kid;
>      SCSIDevice *target_dev = NULL;
>  
> -    QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
> +    RCU_READ_LOCK_GUARD();
> +    QTAILQ_FOREACH_RCU(kid, &bus->qbus.children, sibling) {
>          DeviceState *qdev = kid->child;
>          SCSIDevice *dev = SCSI_DEVICE(qdev);
>  
> @@ -1590,6 +1595,7 @@ SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int lun)
>              }
>          }
>      }
> +
>      return target_dev;
>  }
>  
> diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
> index 3a71ea7097..971afbb217 100644
> --- a/hw/scsi/virtio-scsi.c
> +++ b/hw/scsi/virtio-scsi.c
> @@ -367,12 +367,16 @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
>      case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET:
>          target = req->req.tmf.lun[1];
>          s->resetting++;
> -        QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
> +
> +        rcu_read_lock();
> +        QTAILQ_FOREACH_RCU(kid, &s->bus.qbus.children, sibling) {
>               d = SCSI_DEVICE(kid->child);
>               if (d->channel == 0 && d->id == target) {
>                  qdev_reset_all(&d->qdev);
>               }
>          }
> +        rcu_read_unlock();
> +
>          s->resetting--;
>          break;
>  
> diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
> index e62da68a26..8067497074 100644
> --- a/include/hw/qdev-core.h
> +++ b/include/hw/qdev-core.h
> @@ -3,6 +3,8 @@
>  
>  #include "qemu/queue.h"
>  #include "qemu/bitmap.h"
> +#include "qemu/rcu.h"
> +#include "qemu/rcu_queue.h"
>  #include "qom/object.h"
>  #include "hw/hotplug.h"
>  #include "hw/resettable.h"
> @@ -228,6 +230,7 @@ struct BusClass {
>  };
>  
>  typedef struct BusChild {
> +    struct rcu_head rcu;
>      DeviceState *child;
>      int index;
>      QTAILQ_ENTRY(BusChild) sibling;
> @@ -248,6 +251,12 @@ struct BusState {
>      int max_index;
>      bool realized;
>      int num_children;
> +
> +    /*
> +     * children is a RCU QTAILQ, thus readers must use RCU to access it,
> +     * and writers must hold the big qemu lock
> +     */
> +
>      QTAILQ_HEAD(, BusChild) children;
>      QLIST_ENTRY(BusState) sibling;
>      ResettableState reset;




  reply	other threads:[~2020-09-30 14:31 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-09-25 17:25 [PATCH 00/10] Fix scsi devices plug/unplug races w.r.t virtio-scsi iothread Paolo Bonzini
2020-09-25 17:25 ` [PATCH 01/10] qdev: add "check if address free" callback for buses Paolo Bonzini
2020-09-28  9:30   ` Stefan Hajnoczi
2020-09-30 17:48     ` Paolo Bonzini
2020-09-30 14:27   ` Maxim Levitsky
2020-09-30 23:37     ` Paolo Bonzini
2020-09-25 17:25 ` [PATCH 02/10] scsi: switch to bus->check_address Paolo Bonzini
2020-09-28  9:43   ` Stefan Hajnoczi
2020-09-30 14:28   ` Maxim Levitsky
2020-09-25 17:25 ` [PATCH 03/10] scsi/scsi_bus: switch search direction in scsi_device_find Paolo Bonzini
2020-09-25 17:25 ` [PATCH 04/10] device_core: use drain_call_rcu in in hmp_device_del/qmp_device_add Paolo Bonzini
2020-09-25 17:25 ` [PATCH 05/10] device-core: use RCU for list of children of a bus Paolo Bonzini
2020-09-30 14:29   ` Maxim Levitsky [this message]
2020-09-25 17:26 ` [PATCH 06/10] device-core: use atomic_set on .realized property Paolo Bonzini
2020-09-30 14:31   ` Maxim Levitsky
2020-09-30 17:44     ` Paolo Bonzini
2020-09-30 18:03       ` Maxim Levitsky
2020-09-25 17:26 ` [PATCH 07/10] scsi/scsi-bus: scsi_device_find: don't return unrealized devices Paolo Bonzini
2020-09-30 14:32   ` Maxim Levitsky
2020-09-25 17:26 ` [PATCH 08/10] scsi/scsi_bus: Add scsi_device_get Paolo Bonzini
2020-09-30 14:32   ` Maxim Levitsky
2020-09-30 17:46     ` Paolo Bonzini
2020-09-30 18:04       ` Maxim Levitsky
2020-09-25 17:26 ` [PATCH 09/10] virtio-scsi: use scsi_device_get Paolo Bonzini
2020-09-25 17:26 ` [PATCH 10/10] scsi/scsi_bus: fix races in REPORT LUNS Paolo Bonzini
2020-09-30 14:34   ` Maxim Levitsky
2020-09-25 19:26 ` [PATCH 00/10] Fix scsi devices plug/unplug races w.r.t virtio-scsi iothread no-reply
2020-09-25 22:52 ` no-reply
2020-09-26  0:28 ` no-reply
2020-09-26  0:44 ` no-reply
2020-09-26  1:05 ` no-reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=b19d5fb160f2a1f959531d2389300f32eee6bec2.camel@redhat.com \
    --to=mlevitsk@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).