From 2e761ce184d18dfd2d11eaf8c0b1f4841f6051f4 Mon Sep 17 00:00:00 2001 From: Renata Saiakhova Date: Tue, 6 Apr 2021 16:46:14 +0200 Subject: [PATCH] eal: add synchronous interrupt unregister Avoid race with unregister interrupt handler if interrupt source has some active callbacks at the moment, use wrapper around rte_intr_callback_unregister() to check for -EAGAIN return value and to loop until rte_intr_callback_unregister() succeeds. Signed-off-by: Renata Saiakhova Acked-by: Anatoly Burakov Acked-by: Harman Kalra --- drivers/bus/pci/linux/pci_vfio.c | 2 +- lib/librte_eal/freebsd/eal_interrupts.c | 12 ++++++++++++ lib/librte_eal/include/rte_interrupts.h | 25 +++++++++++++++++++++++++ lib/librte_eal/linux/eal_interrupts.c | 12 ++++++++++++ lib/librte_eal/rte_eal_exports.def | 1 + lib/librte_eal/version.map | 1 + lib/librte_eal/windows/eal_interrupts.c | 8 ++++++++ 7 files changed, 60 insertions(+), 1 deletion(-) diff --git a/drivers/bus/pci/linux/pci_vfio.c b/drivers/bus/pci/linux/pci_vfio.c index 9d689d6fd9..d3a59a1179 100644 --- a/drivers/bus/pci/linux/pci_vfio.c +++ b/drivers/bus/pci/linux/pci_vfio.c @@ -409,7 +409,7 @@ pci_vfio_disable_notifier(struct rte_pci_device *dev) return -1; } - ret = rte_intr_callback_unregister(&dev->vfio_req_intr_handle, + ret = rte_intr_callback_unregister_sync(&dev->vfio_req_intr_handle, pci_vfio_req_handler, (void *)&dev->device); if (ret < 0) { diff --git a/lib/librte_eal/freebsd/eal_interrupts.c b/lib/librte_eal/freebsd/eal_interrupts.c index 72eeacbc14..86810845fe 100644 --- a/lib/librte_eal/freebsd/eal_interrupts.c +++ b/lib/librte_eal/freebsd/eal_interrupts.c @@ -345,6 +345,18 @@ rte_intr_callback_unregister(const struct rte_intr_handle *intr_handle, return ret; } +int +rte_intr_callback_unregister_sync(const struct rte_intr_handle *intr_handle, + rte_intr_callback_fn cb_fn, void *cb_arg) +{ + int ret = 0; + + while ((ret = rte_intr_callback_unregister(intr_handle, cb_fn, cb_arg)) == -EAGAIN) + rte_pause(); + + return ret; +} + int rte_intr_enable(const struct rte_intr_handle *intr_handle) { diff --git a/lib/librte_eal/include/rte_interrupts.h b/lib/librte_eal/include/rte_interrupts.h index e3b406abc2..cc3bf45d8c 100644 --- a/lib/librte_eal/include/rte_interrupts.h +++ b/lib/librte_eal/include/rte_interrupts.h @@ -94,6 +94,31 @@ rte_intr_callback_unregister_pending(const struct rte_intr_handle *intr_handle, rte_intr_callback_fn cb_fn, void *cb_arg, rte_intr_unregister_callback_fn ucb_fn); +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Loop until rte_intr_callback_unregister() succeeds. + * After a call to this function, + * the callback provided by the specified interrupt handle is unregistered. + * + * @param intr_handle + * pointer to the interrupt handle. + * @param cb + * callback address. + * @param cb_arg + * address of parameter for callback, (void *)-1 means to remove all + * registered which has the same callback address. + * + * @return + * - On success, return the number of callback entities removed. + * - On failure, a negative value. + */ +__rte_experimental +int +rte_intr_callback_unregister_sync(const struct rte_intr_handle *intr_handle, + rte_intr_callback_fn cb, void *cb_arg); + /** * It enables the interrupt for the specified handle. * diff --git a/lib/librte_eal/linux/eal_interrupts.c b/lib/librte_eal/linux/eal_interrupts.c index 1dd994bd1f..22b3b7bcd9 100644 --- a/lib/librte_eal/linux/eal_interrupts.c +++ b/lib/librte_eal/linux/eal_interrupts.c @@ -662,6 +662,18 @@ rte_intr_callback_unregister(const struct rte_intr_handle *intr_handle, return ret; } +int +rte_intr_callback_unregister_sync(const struct rte_intr_handle *intr_handle, + rte_intr_callback_fn cb_fn, void *cb_arg) +{ + int ret = 0; + + while ((ret = rte_intr_callback_unregister(intr_handle, cb_fn, cb_arg)) == -EAGAIN) + rte_pause(); + + return ret; +} + int rte_intr_enable(const struct rte_intr_handle *intr_handle) { diff --git a/lib/librte_eal/rte_eal_exports.def b/lib/librte_eal/rte_eal_exports.def index c320077547..ad426f2169 100644 --- a/lib/librte_eal/rte_eal_exports.def +++ b/lib/librte_eal/rte_eal_exports.def @@ -325,6 +325,7 @@ EXPORTS rte_vect_get_max_simd_bitwidth rte_vect_set_max_simd_bitwidth + rte_intr_callback_unregister_sync rte_thread_key_create rte_thread_key_delete rte_thread_value_get diff --git a/lib/librte_eal/version.map b/lib/librte_eal/version.map index e23745ae6e..fc305c1c71 100644 --- a/lib/librte_eal/version.map +++ b/lib/librte_eal/version.map @@ -411,6 +411,7 @@ EXPERIMENTAL { rte_power_pause; # added in 21.05 + rte_intr_callback_unregister_sync; rte_thread_key_create; rte_thread_key_delete; rte_thread_value_get; diff --git a/lib/librte_eal/windows/eal_interrupts.c b/lib/librte_eal/windows/eal_interrupts.c index 3b8266d388..1d4cf794df 100644 --- a/lib/librte_eal/windows/eal_interrupts.c +++ b/lib/librte_eal/windows/eal_interrupts.c @@ -131,6 +131,14 @@ rte_intr_callback_unregister( return 0; } +int +rte_intr_callback_unregister_sync( + __rte_unused const struct rte_intr_handle *intr_handle, + __rte_unused rte_intr_callback_fn cb_fn, __rte_unused void *cb_arg) +{ + return 0; +} + int rte_intr_enable(__rte_unused const struct rte_intr_handle *intr_handle) {