Skip to content

Commit 77542d4

Browse files
Xie Yongjimstsirkin
Xie Yongji
authored andcommitted
vhost-user-blk: Add support to reconnect backend
Since we now support the message VHOST_USER_GET_INFLIGHT_FD and VHOST_USER_SET_INFLIGHT_FD. The backend is able to restart safely because it can track inflight I/O in shared memory. This patch allows qemu to reconnect the backend after connection closed. Signed-off-by: Xie Yongji <xieyongji@baidu.com> Signed-off-by: Ni Xun <nixun@baidu.com> Signed-off-by: Zhang Yu <zhangyu31@baidu.com> Message-Id: <20190320112646.3712-7-xieyongji@baidu.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
1 parent a57f009 commit 77542d4

File tree

2 files changed

+139
-23
lines changed

2 files changed

+139
-23
lines changed

hw/block/vhost-user-blk.c

+136-23
Original file line numberDiff line numberDiff line change
@@ -192,17 +192,27 @@ static void vhost_user_blk_set_status(VirtIODevice *vdev, uint8_t status)
192192
{
193193
VHostUserBlk *s = VHOST_USER_BLK(vdev);
194194
bool should_start = vdev->started;
195+
int ret;
195196

196197
if (!vdev->vm_running) {
197198
should_start = false;
198199
}
199200

201+
if (!s->connected) {
202+
return;
203+
}
204+
200205
if (s->dev.started == should_start) {
201206
return;
202207
}
203208

204209
if (should_start) {
205-
vhost_user_blk_start(vdev);
210+
ret = vhost_user_blk_start(vdev);
211+
if (ret < 0) {
212+
error_report("vhost-user-blk: vhost start failed: %s",
213+
strerror(-ret));
214+
qemu_chr_fe_disconnect(&s->chardev);
215+
}
206216
} else {
207217
vhost_user_blk_stop(vdev);
208218
}
@@ -238,20 +248,30 @@ static uint64_t vhost_user_blk_get_features(VirtIODevice *vdev,
238248
static void vhost_user_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
239249
{
240250
VHostUserBlk *s = VHOST_USER_BLK(vdev);
241-
int i;
251+
int i, ret;
242252

243253
if (!vdev->start_on_kick) {
244254
return;
245255
}
246256

257+
if (!s->connected) {
258+
return;
259+
}
260+
247261
if (s->dev.started) {
248262
return;
249263
}
250264

251265
/* Some guests kick before setting VIRTIO_CONFIG_S_DRIVER_OK so start
252266
* vhost here instead of waiting for .set_status().
253267
*/
254-
vhost_user_blk_start(vdev);
268+
ret = vhost_user_blk_start(vdev);
269+
if (ret < 0) {
270+
error_report("vhost-user-blk: vhost start failed: %s",
271+
strerror(-ret));
272+
qemu_chr_fe_disconnect(&s->chardev);
273+
return;
274+
}
255275

256276
/* Kick right away to begin processing requests already in vring */
257277
for (i = 0; i < s->dev.nvqs; i++) {
@@ -271,11 +291,103 @@ static void vhost_user_blk_reset(VirtIODevice *vdev)
271291
vhost_dev_free_inflight(s->inflight);
272292
}
273293

294+
static int vhost_user_blk_connect(DeviceState *dev)
295+
{
296+
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
297+
VHostUserBlk *s = VHOST_USER_BLK(vdev);
298+
int ret = 0;
299+
300+
if (s->connected) {
301+
return 0;
302+
}
303+
s->connected = true;
304+
305+
s->dev.nvqs = s->num_queues;
306+
s->dev.vqs = s->vqs;
307+
s->dev.vq_index = 0;
308+
s->dev.backend_features = 0;
309+
310+
vhost_dev_set_config_notifier(&s->dev, &blk_ops);
311+
312+
ret = vhost_dev_init(&s->dev, &s->vhost_user, VHOST_BACKEND_TYPE_USER, 0);
313+
if (ret < 0) {
314+
error_report("vhost-user-blk: vhost initialization failed: %s",
315+
strerror(-ret));
316+
return ret;
317+
}
318+
319+
/* restore vhost state */
320+
if (vdev->started) {
321+
ret = vhost_user_blk_start(vdev);
322+
if (ret < 0) {
323+
error_report("vhost-user-blk: vhost start failed: %s",
324+
strerror(-ret));
325+
return ret;
326+
}
327+
}
328+
329+
return 0;
330+
}
331+
332+
static void vhost_user_blk_disconnect(DeviceState *dev)
333+
{
334+
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
335+
VHostUserBlk *s = VHOST_USER_BLK(vdev);
336+
337+
if (!s->connected) {
338+
return;
339+
}
340+
s->connected = false;
341+
342+
if (s->dev.started) {
343+
vhost_user_blk_stop(vdev);
344+
}
345+
346+
vhost_dev_cleanup(&s->dev);
347+
}
348+
349+
static gboolean vhost_user_blk_watch(GIOChannel *chan, GIOCondition cond,
350+
void *opaque)
351+
{
352+
DeviceState *dev = opaque;
353+
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
354+
VHostUserBlk *s = VHOST_USER_BLK(vdev);
355+
356+
qemu_chr_fe_disconnect(&s->chardev);
357+
358+
return true;
359+
}
360+
361+
static void vhost_user_blk_event(void *opaque, int event)
362+
{
363+
DeviceState *dev = opaque;
364+
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
365+
VHostUserBlk *s = VHOST_USER_BLK(vdev);
366+
367+
switch (event) {
368+
case CHR_EVENT_OPENED:
369+
if (vhost_user_blk_connect(dev) < 0) {
370+
qemu_chr_fe_disconnect(&s->chardev);
371+
return;
372+
}
373+
s->watch = qemu_chr_fe_add_watch(&s->chardev, G_IO_HUP,
374+
vhost_user_blk_watch, dev);
375+
break;
376+
case CHR_EVENT_CLOSED:
377+
vhost_user_blk_disconnect(dev);
378+
if (s->watch) {
379+
g_source_remove(s->watch);
380+
s->watch = 0;
381+
}
382+
break;
383+
}
384+
}
385+
274386
static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
275387
{
276388
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
277389
VHostUserBlk *s = VHOST_USER_BLK(vdev);
278-
struct vhost_virtqueue *vqs = NULL;
390+
Error *err = NULL;
279391
int i, ret;
280392

281393
if (!s->chardev.chr) {
@@ -306,27 +418,29 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
306418
}
307419

308420
s->inflight = g_new0(struct vhost_inflight, 1);
421+
s->vqs = g_new(struct vhost_virtqueue, s->num_queues);
422+
s->watch = 0;
423+
s->connected = false;
309424

310-
s->dev.nvqs = s->num_queues;
311-
s->dev.vqs = g_new(struct vhost_virtqueue, s->dev.nvqs);
312-
s->dev.vq_index = 0;
313-
s->dev.backend_features = 0;
314-
vqs = s->dev.vqs;
315-
316-
vhost_dev_set_config_notifier(&s->dev, &blk_ops);
425+
qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, vhost_user_blk_event,
426+
NULL, (void *)dev, NULL, true);
317427

318-
ret = vhost_dev_init(&s->dev, &s->vhost_user, VHOST_BACKEND_TYPE_USER, 0);
319-
if (ret < 0) {
320-
error_setg(errp, "vhost-user-blk: vhost initialization failed: %s",
321-
strerror(-ret));
428+
reconnect:
429+
if (qemu_chr_fe_wait_connected(&s->chardev, &err) < 0) {
430+
error_report_err(err);
322431
goto virtio_err;
323432
}
324433

434+
/* check whether vhost_user_blk_connect() failed or not */
435+
if (!s->connected) {
436+
goto reconnect;
437+
}
438+
325439
ret = vhost_dev_get_config(&s->dev, (uint8_t *)&s->blkcfg,
326-
sizeof(struct virtio_blk_config));
440+
sizeof(struct virtio_blk_config));
327441
if (ret < 0) {
328-
error_setg(errp, "vhost-user-blk: get block config failed");
329-
goto vhost_err;
442+
error_report("vhost-user-blk: get block config failed");
443+
goto reconnect;
330444
}
331445

332446
if (s->blkcfg.num_queues != s->num_queues) {
@@ -335,10 +449,8 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
335449

336450
return;
337451

338-
vhost_err:
339-
vhost_dev_cleanup(&s->dev);
340452
virtio_err:
341-
g_free(vqs);
453+
g_free(s->vqs);
342454
g_free(s->inflight);
343455
virtio_cleanup(vdev);
344456
vhost_user_cleanup(&s->vhost_user);
@@ -348,12 +460,13 @@ static void vhost_user_blk_device_unrealize(DeviceState *dev, Error **errp)
348460
{
349461
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
350462
VHostUserBlk *s = VHOST_USER_BLK(dev);
351-
struct vhost_virtqueue *vqs = s->dev.vqs;
352463

353464
virtio_set_status(vdev, 0);
465+
qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, NULL,
466+
NULL, NULL, NULL, false);
354467
vhost_dev_cleanup(&s->dev);
355468
vhost_dev_free_inflight(s->inflight);
356-
g_free(vqs);
469+
g_free(s->vqs);
357470
g_free(s->inflight);
358471
virtio_cleanup(vdev);
359472
vhost_user_cleanup(&s->vhost_user);

include/hw/virtio/vhost-user-blk.h

+3
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ typedef struct VHostUserBlk {
3838
struct vhost_dev dev;
3939
struct vhost_inflight *inflight;
4040
VhostUserState vhost_user;
41+
struct vhost_virtqueue *vqs;
42+
guint watch;
43+
bool connected;
4144
} VHostUserBlk;
4245

4346
#endif

0 commit comments

Comments
 (0)