[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v2 12/13] virtio-scsi-dataplane: Add backend lock li
From: |
Fam Zheng |
Subject: |
[Qemu-devel] [PATCH v2 12/13] virtio-scsi-dataplane: Add backend lock listener |
Date: |
Tue, 2 Jun 2015 11:22:01 +0800 |
When a disk is attached to scsi-bus, virtio_scsi_hotplug will take care
of protecting the block device with op blockers. Currently we haven't
enabled block jobs (like what's done in virtio_blk_data_plane_create),
but it is better to disable ioeventfd when backend is locked. This is
useful to make sure that guest IO requests are paused during qmp
transactions (such as multi-disk snapshot or backup).
A counter is added to the virtio-scsi device, which keeps track of
currently blocked disks. If it goes from 0 to 1, the ioeventfds are
disabled; when it goes back to 0, they are re-enabled.
Also in device initialization, push the enabling of ioeventfds to before
return, so the virtio_scsi_clear_aio is not needed there. Rename it,
pair with an enabling variant, fix one coding style issue, then use it
in the device pause points.
Signed-off-by: Fam Zheng <address@hidden>
---
hw/scsi/virtio-scsi-dataplane.c | 78 ++++++++++++++++++++++++++++++-----------
hw/scsi/virtio-scsi.c | 3 ++
include/hw/virtio/virtio-scsi.h | 3 ++
3 files changed, 64 insertions(+), 20 deletions(-)
diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c
index 5575648..28706a2 100644
--- a/hw/scsi/virtio-scsi-dataplane.c
+++ b/hw/scsi/virtio-scsi-dataplane.c
@@ -40,7 +40,6 @@ void virtio_scsi_set_iothread(VirtIOSCSI *s, IOThread
*iothread)
static VirtIOSCSIVring *virtio_scsi_vring_init(VirtIOSCSI *s,
VirtQueue *vq,
- EventNotifierHandler *handler,
int n)
{
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s)));
@@ -60,7 +59,6 @@ static VirtIOSCSIVring *virtio_scsi_vring_init(VirtIOSCSI *s,
r = g_slice_new(VirtIOSCSIVring);
r->host_notifier = *virtio_queue_get_host_notifier(vq);
r->guest_notifier = *virtio_queue_get_guest_notifier(vq);
- aio_set_event_notifier(s->ctx, &r->host_notifier, handler);
r->parent = s;
@@ -71,7 +69,6 @@ static VirtIOSCSIVring *virtio_scsi_vring_init(VirtIOSCSI *s,
return r;
fail_vring:
- aio_set_event_notifier(s->ctx, &r->host_notifier, NULL);
k->set_host_notifier(qbus->parent, n, false);
g_slice_free(VirtIOSCSIVring, r);
return NULL;
@@ -104,6 +101,9 @@ void virtio_scsi_vring_push_notify(VirtIOSCSIReq *req)
}
}
+static void virtio_scsi_start_ioeventfd(VirtIOSCSI *s);
+static void virtio_scsi_stop_ioeventfd(VirtIOSCSI *s);
+
static void virtio_scsi_iothread_handle_ctrl(EventNotifier *notifier)
{
VirtIOSCSIVring *vring = container_of(notifier,
@@ -111,6 +111,7 @@ static void virtio_scsi_iothread_handle_ctrl(EventNotifier
*notifier)
VirtIOSCSI *s = VIRTIO_SCSI(vring->parent);
VirtIOSCSIReq *req;
+ assert(!s->pause_counter);
event_notifier_test_and_clear(notifier);
while ((req = virtio_scsi_pop_req_vring(s, vring))) {
virtio_scsi_handle_ctrl_req(s, req);
@@ -124,6 +125,7 @@ static void virtio_scsi_iothread_handle_event(EventNotifier
*notifier)
VirtIOSCSI *s = vring->parent;
VirtIODevice *vdev = VIRTIO_DEVICE(s);
+ assert(!s->pause_counter);
event_notifier_test_and_clear(notifier);
if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
@@ -143,6 +145,7 @@ static void virtio_scsi_iothread_handle_cmd(EventNotifier
*notifier)
VirtIOSCSIReq *req, *next;
QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs);
+ assert(!s->pause_counter);
event_notifier_test_and_clear(notifier);
while ((req = virtio_scsi_pop_req_vring(s, vring))) {
if (virtio_scsi_handle_cmd_req_prepare(s, req)) {
@@ -155,8 +158,52 @@ static void virtio_scsi_iothread_handle_cmd(EventNotifier
*notifier)
}
}
+void virtio_scsi_dataplane_pause_handler(Notifier *notifier, void *data)
+{
+ VirtIOSCSI *s = container_of(notifier, VirtIOSCSI, pause_notifier);
+ BdrvLockEvent *event = data;
+
+ if (event->locking) {
+ s->pause_counter++;
+ if (s->pause_counter == 1) {
+ virtio_scsi_stop_ioeventfd(s);
+ }
+ } else {
+ s->pause_counter--;
+ if (s->pause_counter == 0) {
+ virtio_scsi_start_ioeventfd(s);
+ }
+ }
+ assert(s->pause_counter >= 0);
+}
+
/* assumes s->ctx held */
-static void virtio_scsi_clear_aio(VirtIOSCSI *s)
+static void virtio_scsi_start_ioeventfd(VirtIOSCSI *s)
+{
+ VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
+ int i;
+
+ if (!s->dataplane_started || s->dataplane_stopping) {
+ return;
+ }
+ if (s->ctrl_vring) {
+ aio_set_event_notifier(s->ctx, &s->ctrl_vring->host_notifier,
+ virtio_scsi_iothread_handle_ctrl);
+ }
+ if (s->event_vring) {
+ aio_set_event_notifier(s->ctx, &s->event_vring->host_notifier,
+ virtio_scsi_iothread_handle_event);
+ }
+ if (s->cmd_vrings) {
+ for (i = 0; i < vs->conf.num_queues && s->cmd_vrings[i]; i++) {
+ aio_set_event_notifier(s->ctx, &s->cmd_vrings[i]->host_notifier,
+ virtio_scsi_iothread_handle_cmd);
+ }
+ }
+}
+
+/* assumes s->ctx held */
+static void virtio_scsi_stop_ioeventfd(VirtIOSCSI *s)
{
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
int i;
@@ -169,7 +216,8 @@ static void virtio_scsi_clear_aio(VirtIOSCSI *s)
}
if (s->cmd_vrings) {
for (i = 0; i < vs->conf.num_queues && s->cmd_vrings[i]; i++) {
- aio_set_event_notifier(s->ctx, &s->cmd_vrings[i]->host_notifier,
NULL);
+ aio_set_event_notifier(s->ctx, &s->cmd_vrings[i]->host_notifier,
+ NULL);
}
}
}
@@ -229,24 +277,18 @@ void virtio_scsi_dataplane_start(VirtIOSCSI *s)
}
aio_context_acquire(s->ctx);
- s->ctrl_vring = virtio_scsi_vring_init(s, vs->ctrl_vq,
- virtio_scsi_iothread_handle_ctrl,
- 0);
+ s->ctrl_vring = virtio_scsi_vring_init(s, vs->ctrl_vq, 0);
if (!s->ctrl_vring) {
goto fail_vrings;
}
- s->event_vring = virtio_scsi_vring_init(s, vs->event_vq,
- virtio_scsi_iothread_handle_event,
- 1);
+ s->event_vring = virtio_scsi_vring_init(s, vs->event_vq, 1);
if (!s->event_vring) {
goto fail_vrings;
}
s->cmd_vrings = g_new(VirtIOSCSIVring *, vs->conf.num_queues);
for (i = 0; i < vs->conf.num_queues; i++) {
s->cmd_vrings[i] =
- virtio_scsi_vring_init(s, vs->cmd_vqs[i],
- virtio_scsi_iothread_handle_cmd,
- i + 2);
+ virtio_scsi_vring_init(s, vs->cmd_vqs[i], i + 2);
if (!s->cmd_vrings[i]) {
goto fail_vrings;
}
@@ -254,11 +296,11 @@ void virtio_scsi_dataplane_start(VirtIOSCSI *s)
s->dataplane_starting = false;
s->dataplane_started = true;
+ virtio_scsi_start_ioeventfd(s);
aio_context_release(s->ctx);
return;
fail_vrings:
- virtio_scsi_clear_aio(s);
aio_context_release(s->ctx);
virtio_scsi_vring_teardown(s);
for (i = 0; i < vs->conf.num_queues + 2; i++) {
@@ -290,11 +332,7 @@ void virtio_scsi_dataplane_stop(VirtIOSCSI *s)
aio_context_acquire(s->ctx);
- aio_set_event_notifier(s->ctx, &s->ctrl_vring->host_notifier, NULL);
- aio_set_event_notifier(s->ctx, &s->event_vring->host_notifier, NULL);
- for (i = 0; i < vs->conf.num_queues; i++) {
- aio_set_event_notifier(s->ctx, &s->cmd_vrings[i]->host_notifier, NULL);
- }
+ virtio_scsi_stop_ioeventfd(s);
blk_drain_all(); /* ensure there are no in-flight requests */
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index b0dee29..0a770d2 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -774,6 +774,8 @@ static void virtio_scsi_hotplug(HotplugHandler
*hotplug_dev, DeviceState *dev,
blk_op_block_all(sd->conf.blk, s->blocker);
aio_context_acquire(s->ctx);
blk_set_aio_context(sd->conf.blk, s->ctx);
+ s->pause_notifier.notify = virtio_scsi_dataplane_pause_handler;
+ blk_add_lock_unlock_notifier(sd->conf.blk, &s->pause_notifier);
aio_context_release(s->ctx);
}
@@ -798,6 +800,7 @@ static void virtio_scsi_hotunplug(HotplugHandler
*hotplug_dev, DeviceState *dev,
}
if (s->ctx) {
+ notifier_remove(&s->pause_notifier);
blk_op_unblock_all(sd->conf.blk, s->blocker);
}
qdev_simple_device_unplug_cb(hotplug_dev, dev, errp);
diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h
index b42e7f1..928b87e 100644
--- a/include/hw/virtio/virtio-scsi.h
+++ b/include/hw/virtio/virtio-scsi.h
@@ -97,6 +97,8 @@ typedef struct VirtIOSCSI {
bool dataplane_disabled;
bool dataplane_fenced;
Error *blocker;
+ Notifier pause_notifier;
+ int pause_counter;
Notifier migration_state_notifier;
uint32_t host_features;
} VirtIOSCSI;
@@ -170,6 +172,7 @@ void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
uint32_t event, uint32_t reason);
void virtio_scsi_set_iothread(VirtIOSCSI *s, IOThread *iothread);
+void virtio_scsi_dataplane_pause_handler(Notifier *notifier, void *data);
void virtio_scsi_dataplane_start(VirtIOSCSI *s);
void virtio_scsi_dataplane_stop(VirtIOSCSI *s);
void virtio_scsi_vring_push_notify(VirtIOSCSIReq *req);
--
2.4.1
- Re: [Qemu-devel] [Qemu-block] [PATCH v2 02/13] block: Introduce bdrv_lock and bdrv_unlock API, (continued)
- [Qemu-devel] [PATCH v2 03/13] blockdev: Lock BDS during internal snapshot transaction, Fam Zheng, 2015/06/01
- [Qemu-devel] [PATCH v2 04/13] blockdev: Lock BDS during external snapshot transaction, Fam Zheng, 2015/06/01
- [Qemu-devel] [PATCH v2 05/13] blockdev: Lock BDS during drive-backup transaction, Fam Zheng, 2015/06/01
- [Qemu-devel] [PATCH v2 06/13] blockdev: Lock BDS during blockdev-backup transaction, Fam Zheng, 2015/06/01
- [Qemu-devel] [PATCH v2 07/13] mirror: Protect source between bdrv_drain and bdrv_swap, Fam Zheng, 2015/06/01
- [Qemu-devel] [PATCH v2 08/13] block: Add bdrv_add_lock_unlock_notifier, Fam Zheng, 2015/06/01
- [Qemu-devel] [PATCH v2 09/13] block-backend: Add blk_add_lock_unlock_notifier, Fam Zheng, 2015/06/01
- [Qemu-devel] [PATCH v2 10/13] virtio-blk: Move complete_request to 'ops' structure, Fam Zheng, 2015/06/01
- [Qemu-devel] [PATCH v2 11/13] virtio-blk: Don't handle output when backend is locked, Fam Zheng, 2015/06/01
- [Qemu-devel] [PATCH v2 12/13] virtio-scsi-dataplane: Add backend lock listener,
Fam Zheng <=
- [Qemu-devel] [PATCH v2 13/13] nbd-server: Clear "can_read" when backend is locked, Fam Zheng, 2015/06/01