diff --git a/autotest.sh b/autotest.sh index f4dbffdf76..27ecbf215a 100755 --- a/autotest.sh +++ b/autotest.sh @@ -188,6 +188,7 @@ if [ $SPDK_RUN_FUNCTIONAL_TEST -eq 1 ]; then run_test "bdevperf_config" test/bdev/bdevperf/test_config.sh if [[ $(uname -s) == Linux ]]; then run_test "reactor_set_interrupt" test/interrupt/reactor_set_interrupt.sh + run_test "reap_unregistered_poller" test/interrupt/reap_unregistered_poller.sh fi fi diff --git a/lib/thread/thread.c b/lib/thread/thread.c index 4a829f0e12..17a760c710 100644 --- a/lib/thread/thread.c +++ b/lib/thread/thread.c @@ -94,6 +94,7 @@ struct spdk_poller { spdk_poller_fn fn; void *arg; struct spdk_thread *thread; + /* Native interruptfd for period or busy poller */ int interruptfd; spdk_poller_set_interrupt_mode_cb set_intr_cb_fn; void *set_intr_cb_arg; @@ -153,6 +154,7 @@ struct spdk_thread { /* Indicates whether this spdk_thread currently runs in interrupt. */ bool in_interrupt; + bool poller_unregistered; struct spdk_fd_group *fgrp; /* User context allocated at the end */ @@ -737,7 +739,6 @@ poller_insert_timer(struct spdk_thread *thread, struct spdk_poller *poller, uint } } -#ifdef __linux__ static inline void poller_remove_timer(struct spdk_thread *thread, struct spdk_poller *poller) { @@ -753,7 +754,6 @@ poller_remove_timer(struct spdk_thread *thread, struct spdk_poller *poller) thread->first_timed_poller = RB_MIN(timed_pollers_tree, &thread->timed_pollers); } } -#endif static void thread_insert_poller(struct spdk_thread *thread, struct spdk_poller *poller) @@ -996,6 +996,28 @@ spdk_thread_poll(struct spdk_thread *thread, uint32_t max_msgs, uint64_t now) SPDK_ERRLOG("failed to acknowledge msg queue: %s.\n", spdk_strerror(errno)); } } + + /* Reap unregistered pollers out of poller execution in intr mode */ + if (spdk_unlikely(thread->poller_unregistered)) { + struct spdk_poller *poller, *tmp; + + TAILQ_FOREACH_REVERSE_SAFE(poller, &thread->active_pollers, + active_pollers_head, tailq, tmp) { + if (poller->state == SPDK_POLLER_STATE_UNREGISTERED) { + TAILQ_REMOVE(&thread->active_pollers, poller, tailq); + free(poller); + } + } + + RB_FOREACH_SAFE(poller, timed_pollers_tree, &thread->timed_pollers, tmp) { + if (poller->state == SPDK_POLLER_STATE_UNREGISTERED) { + poller_remove_timer(thread, poller); + free(poller); + } + } + + thread->poller_unregistered = false; + } } @@ -1582,8 +1604,16 @@ spdk_poller_unregister(struct spdk_poller **ppoller) return; } - if (spdk_interrupt_mode_is_enabled() && poller->interruptfd >= 0) { - poller_interrupt_fini(poller); + if (spdk_interrupt_mode_is_enabled()) { + /* Release the interrupt resource for period or busy poller */ + if (poller->interruptfd >= 0) { + poller_interrupt_fini(poller); + } + + /* Mark there is poller unregistered. Then unregistered pollers will + * get reaped by spdk_thread_poll also in intr mode. + */ + thread->poller_unregistered = true; } /* If the poller was paused, put it on the active_pollers list so that diff --git a/test/interrupt/reap_unregistered_poller.sh b/test/interrupt/reap_unregistered_poller.sh new file mode 100755 index 0000000000..88c13a69fa --- /dev/null +++ b/test/interrupt/reap_unregistered_poller.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash + +testdir=$(readlink -f $(dirname $0)) +rootdir=$(readlink -f $testdir/../..) +source $rootdir/test/common/autotest_common.sh +source $testdir/interrupt_common.sh + +export PYTHONPATH=$rootdir/examples/interrupt_tgt + +# Set reactors with intr_tgt in intr mode +start_intr_tgt + +# Record names of native created pollers. +app_thread=$(rpc_cmd thread_get_pollers | jq -r '.threads[0]') +native_pollers=$(jq -r '.active_pollers[].name' <<< $app_thread) +native_pollers+=" " +native_pollers+=$(jq -r '.timed_pollers[].name' <<< $app_thread) + +# Create one aio_bdev. +# During the creation, vbdev examine process will get bdev_aio create +# pollers like bdev_aio_group_poll poller, and then unregister it. +setup_bdev_aio + +# Record names of remaining pollers. +app_thread=$(rpc_cmd thread_get_pollers | jq -r '.threads[0]') +remaining_pollers=$(jq -r '.active_pollers[].name' <<< $app_thread) +remaining_pollers+=" " +remaining_pollers+=$(jq -r '.timed_pollers[].name' <<< $app_thread) + +# Since bdev_aio created pollers were already unregistered, so +# remaining_pollers should be same with native_pollers. +if [[ "$remaining_pollers" != "$native_pollers" ]]; then + return 1 +fi + +trap - SIGINT SIGTERM EXIT +killprocess $intr_tgt_pid +cleanup