diff options
author | limiao-intel <105205746+limiao-intel@users.noreply.github.com> | 2023-06-09 04:51:04 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-06-08 21:51:04 +0100 |
commit | 74e7348f253c04d43c11082c83f2a51720c7643e (patch) | |
tree | f6f24b896e9846c36b9a688f3a8c2caab3d3d7d8 | |
parent | e817d2e67835a80761fd33c4a1ed445c3309f3e7 (diff) | |
download | libvfio-user-74e7348f253c04d43c11082c83f2a51720c7643e.zip libvfio-user-74e7348f253c04d43c11082c83f2a51720c7643e.tar.gz libvfio-user-74e7348f253c04d43c11082c83f2a51720c7643e.tar.bz2 |
fix err/req irq fd issue (#731)
When handle_device_set_irqs set err irq/req irq, fd will be filled
in vfu_ctx->irqs->efds[] rather than vfu_ctx->irqs->err_efd or
vfu_ctx->irqs->req_efd. This patch adds irq index judgment before
filling in fd to make sure fd is filled in the correct place.
Signed-off-by: Miao Li <miao.li@intel.com>
Reviewed-by: John Levon <john.levon@nutanix.com>
Reviewed-by: Thanos Makatos <thanos.makatos@nutanix.com>
-rw-r--r-- | lib/irq.c | 63 | ||||
-rw-r--r-- | test/py/test_device_set_irqs.py | 18 |
2 files changed, 64 insertions, 17 deletions
@@ -180,19 +180,32 @@ irqs_set_state(vfu_ctx_t *vfu_ctx, struct vfio_irq_set *irq_set) cb(vfu_ctx, irq_set->start, irq_set->count, mask); } +static int * +irqs_get_efd(vfu_ctx_t *vfu_ctx, int index, int fd_idx) +{ + switch (index) { + case VFIO_PCI_ERR_IRQ_INDEX: + return &vfu_ctx->irqs->err_efd; + case VFIO_PCI_REQ_IRQ_INDEX: + return &vfu_ctx->irqs->req_efd; + default: + return &vfu_ctx->irqs->efds[fd_idx]; + } +} + static int irqs_set_data_none(vfu_ctx_t *vfu_ctx, struct vfio_irq_set *irq_set) { - int efd; + int *efd; uint32_t i; long ret; eventfd_t val; for (i = irq_set->start; i < (irq_set->start + irq_set->count); i++) { - efd = vfu_ctx->irqs->efds[i]; - if (efd >= 0) { + efd = irqs_get_efd(vfu_ctx, irq_set->index, i); + if (*efd >= 0) { val = 1; - ret = eventfd_write(efd, val); + ret = eventfd_write(*efd, val); if (ret == -1) { vfu_log(vfu_ctx, LOG_DEBUG, "IRQ: failed to set data to none: %m"); @@ -208,7 +221,7 @@ static int irqs_set_data_bool(vfu_ctx_t *vfu_ctx, struct vfio_irq_set *irq_set, void *data) { uint8_t *d8; - int efd; + int *efd; uint32_t i; long ret; eventfd_t val; @@ -217,10 +230,10 @@ irqs_set_data_bool(vfu_ctx_t *vfu_ctx, struct vfio_irq_set *irq_set, void *data) for (i = irq_set->start, d8 = data; i < (irq_set->start + irq_set->count); i++, d8++) { - efd = vfu_ctx->irqs->efds[i]; - if (efd >= 0 && *d8 == 1) { + efd = irqs_get_efd(vfu_ctx, irq_set->index, i); + if (*efd >= 0 && *d8 == 1) { val = 1; - ret = eventfd_write(efd, val); + ret = eventfd_write(*efd, val); if (ret == -1) { vfu_log(vfu_ctx, LOG_DEBUG, "IRQ: failed to set data to bool: %m"); @@ -236,28 +249,37 @@ static int irqs_set_data_eventfd(vfu_ctx_t *vfu_ctx, struct vfio_irq_set *irq_set, int *data) { - int efd; + int *efd; uint32_t i; size_t j; assert(data != NULL); for (i = irq_set->start, j = 0; i < (irq_set->start + irq_set->count); i++, j++) { - efd = vfu_ctx->irqs->efds[i]; - if (efd >= 0) { - if (close(efd) == -1) { - vfu_log(vfu_ctx, LOG_DEBUG, "failed to close IRQ fd %d: %m", efd); + efd = irqs_get_efd(vfu_ctx, irq_set->index, i); + if (*efd >= 0) { + if (close(*efd) == -1) { + vfu_log(vfu_ctx, LOG_DEBUG, "failed to close IRQ fd %d: %m", *efd); } - - vfu_ctx->irqs->efds[i] = -1; + *efd = -1; } assert(data[j] >= 0); /* * We've already checked in handle_device_set_irqs that * nr_fds == irq_set->count. */ - vfu_ctx->irqs->efds[i] = consume_fd(data, irq_set->count, j); - vfu_log(vfu_ctx, LOG_DEBUG, "event fd[%d]=%d", i, vfu_ctx->irqs->efds[i]); + *efd = consume_fd(data, irq_set->count, j); + switch (irq_set->index) { + case VFIO_PCI_ERR_IRQ_INDEX: + vfu_log(vfu_ctx, LOG_DEBUG, "err fd=%d", *efd); + break; + case VFIO_PCI_REQ_IRQ_INDEX: + vfu_log(vfu_ctx, LOG_DEBUG, "req fd=%d", *efd); + break; + default: + vfu_log(vfu_ctx, LOG_DEBUG, "event fd[%d]=%d", i, *efd); + break; + } } return 0; @@ -322,6 +344,13 @@ device_set_irqs_validate(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg) line = __LINE__; goto invalid; } + // count must be 0 or 1 for ERR/REQ + if (((irq_set->index == VFIO_PCI_ERR_IRQ_INDEX) || + (irq_set->index == VFIO_PCI_REQ_IRQ_INDEX)) && + (irq_set->count > 1)) { + line = __LINE__; + goto invalid; + } // if count == 0, start must be 0 too if ((irq_set->count == 0) && (irq_set->start != 0)) { line = __LINE__; diff --git a/test/py/test_device_set_irqs.py b/test/py/test_device_set_irqs.py index 4118cb2..1aead71 100644 --- a/test/py/test_device_set_irqs.py +++ b/test/py/test_device_set_irqs.py @@ -151,6 +151,24 @@ def test_device_set_irqs_bad_action_for_req_irq(): expect=errno.EINVAL) +def test_device_set_irqs_bad_start_count_range_for_err_irq(): + payload = vfio_irq_set(argsz=argsz, flags=VFIO_IRQ_SET_ACTION_TRIGGER | + VFIO_IRQ_SET_DATA_NONE, index=VFU_DEV_ERR_IRQ, + start=0, count=2) + + msg(ctx, sock, VFIO_USER_DEVICE_SET_IRQS, payload, + expect=errno.EINVAL) + + +def test_device_set_irqs_bad_start_count_range_for_req_irq(): + payload = vfio_irq_set(argsz=argsz, flags=VFIO_IRQ_SET_ACTION_TRIGGER | + VFIO_IRQ_SET_DATA_NONE, index=VFU_DEV_REQ_IRQ, + start=0, count=2) + + msg(ctx, sock, VFIO_USER_DEVICE_SET_IRQS, payload, + expect=errno.EINVAL) + + def test_device_set_irqs_bad_start_for_count_0(): payload = vfio_irq_set(argsz=argsz, flags=VFIO_IRQ_SET_ACTION_MASK | VFIO_IRQ_SET_DATA_NONE, index=VFU_DEV_MSIX_IRQ, |