virtio-scsi: dataplane: fail setup gracefully
The dataplane code is currently doing a hard exit on various setup failures. In practice, this may mean that a guest suddenly dies after a dataplane device failed to come up (e.g., when a file descriptor limit is hit for the nth device). Let's just try to unwind the setup instead and return. Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
		
				
					committed by
					
						 Paolo Bonzini
						Paolo Bonzini
					
				
			
			
				
	
			
			
			
						parent
						
							6d2c83165b
						
					
				
				
					commit
					361dcc790d
				
			| @@ -53,7 +53,7 @@ static VirtIOSCSIVring *virtio_scsi_vring_init(VirtIOSCSI *s, | ||||
|     if (rc != 0) { | ||||
|         fprintf(stderr, "virtio-scsi: Failed to set host notifier (%d)\n", | ||||
|                 rc); | ||||
|         exit(1); | ||||
|         return NULL; | ||||
|     } | ||||
|     r->host_notifier = *virtio_queue_get_host_notifier(vq); | ||||
|     r->guest_notifier = *virtio_queue_get_guest_notifier(vq); | ||||
| @@ -63,9 +63,15 @@ static VirtIOSCSIVring *virtio_scsi_vring_init(VirtIOSCSI *s, | ||||
|  | ||||
|     if (!vring_setup(&r->vring, VIRTIO_DEVICE(s), n)) { | ||||
|         fprintf(stderr, "virtio-scsi: VRing setup failed\n"); | ||||
|         exit(1); | ||||
|         goto fail_vring; | ||||
|     } | ||||
|     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; | ||||
| } | ||||
|  | ||||
| VirtIOSCSIReq *virtio_scsi_pop_req_vring(VirtIOSCSI *s, | ||||
| @@ -141,6 +147,46 @@ static void virtio_scsi_iothread_handle_cmd(EventNotifier *notifier) | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* assumes s->ctx held */ | ||||
| static void virtio_scsi_clear_aio(VirtIOSCSI *s) | ||||
| { | ||||
|     VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); | ||||
|     int i; | ||||
|  | ||||
|     if (s->ctrl_vring) { | ||||
|         aio_set_event_notifier(s->ctx, &s->ctrl_vring->host_notifier, NULL); | ||||
|     } | ||||
|     if (s->event_vring) { | ||||
|         aio_set_event_notifier(s->ctx, &s->event_vring->host_notifier, NULL); | ||||
|     } | ||||
|     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); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void virtio_scsi_vring_teardown(VirtIOSCSI *s) | ||||
| { | ||||
|     VirtIODevice *vdev = VIRTIO_DEVICE(s); | ||||
|     VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); | ||||
|     int i; | ||||
|  | ||||
|     if (s->ctrl_vring) { | ||||
|         vring_teardown(&s->ctrl_vring->vring, vdev, 0); | ||||
|     } | ||||
|     if (s->event_vring) { | ||||
|         vring_teardown(&s->event_vring->vring, vdev, 1); | ||||
|     } | ||||
|     if (s->cmd_vrings) { | ||||
|         for (i = 0; i < vs->conf.num_queues && s->cmd_vrings[i]; i++) { | ||||
|             vring_teardown(&s->cmd_vrings[i]->vring, vdev, 2 + i); | ||||
|         } | ||||
|         free(s->cmd_vrings); | ||||
|         s->cmd_vrings = NULL; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* Context: QEMU global mutex held */ | ||||
| void virtio_scsi_dataplane_start(VirtIOSCSI *s) | ||||
| { | ||||
| @@ -165,27 +211,47 @@ void virtio_scsi_dataplane_start(VirtIOSCSI *s) | ||||
|     if (rc != 0) { | ||||
|         fprintf(stderr, "virtio-scsi: Failed to set guest notifiers (%d), " | ||||
|                 "ensure -enable-kvm is set\n", rc); | ||||
|         exit(1); | ||||
|         goto fail_guest_notifiers; | ||||
|     } | ||||
|  | ||||
|     aio_context_acquire(s->ctx); | ||||
|     s->ctrl_vring = virtio_scsi_vring_init(s, vs->ctrl_vq, | ||||
|                                            virtio_scsi_iothread_handle_ctrl, | ||||
|                                            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); | ||||
|     if (!s->event_vring) { | ||||
|         goto fail_vrings; | ||||
|     } | ||||
|     s->cmd_vrings = g_malloc0(sizeof(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); | ||||
|         if (!s->cmd_vrings[i]) { | ||||
|             goto fail_vrings; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     aio_context_release(s->ctx); | ||||
|     s->dataplane_starting = false; | ||||
|     s->dataplane_started = true; | ||||
|  | ||||
| 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++) { | ||||
|         k->set_host_notifier(qbus->parent, i, false); | ||||
|     } | ||||
|     k->set_guest_notifiers(qbus->parent, vs->conf.num_queues + 2, false); | ||||
| fail_guest_notifiers: | ||||
|     s->dataplane_starting = false; | ||||
| } | ||||
|  | ||||
| /* Context: QEMU global mutex held */ | ||||
| @@ -193,7 +259,6 @@ void virtio_scsi_dataplane_stop(VirtIOSCSI *s) | ||||
| { | ||||
|     BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s))); | ||||
|     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); | ||||
|     VirtIODevice *vdev = VIRTIO_DEVICE(s); | ||||
|     VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); | ||||
|     int i; | ||||
|  | ||||
| @@ -220,11 +285,7 @@ void virtio_scsi_dataplane_stop(VirtIOSCSI *s) | ||||
|     /* Sync vring state back to virtqueue so that non-dataplane request | ||||
|      * processing can continue when we disable the host notifier below. | ||||
|      */ | ||||
|     vring_teardown(&s->ctrl_vring->vring, vdev, 0); | ||||
|     vring_teardown(&s->event_vring->vring, vdev, 1); | ||||
|     for (i = 0; i < vs->conf.num_queues; i++) { | ||||
|         vring_teardown(&s->cmd_vrings[i]->vring, vdev, 2 + i); | ||||
|     } | ||||
|     virtio_scsi_vring_teardown(s); | ||||
|  | ||||
|     for (i = 0; i < vs->conf.num_queues + 2; i++) { | ||||
|         k->set_host_notifier(qbus->parent, i, false); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user