All callers now pass is_external=false to aio_set_fd_handler() and aio_set_event_notifier(). The aio_disable_external() API that temporarily disables fd handlers that were registered is_external=true is therefore dead code. Remove aio_disable_external(), aio_enable_external(), and the is_external arguments to aio_set_fd_handler() and aio_set_event_notifier(). The entire test-fdmon-epoll test is removed because its sole purpose was testing aio_disable_external(). Parts of this patch were generated using the following coccinelle (https://coccinelle.lip6.fr/) semantic patch: @@ expression ctx, fd, is_external, io_read, io_write, io_poll, io_poll_ready, opaque; @@ - aio_set_fd_handler(ctx, fd, is_external, io_read, io_write, io_poll, io_poll_ready, opaque) + aio_set_fd_handler(ctx, fd, io_read, io_write, io_poll, io_poll_ready, opaque) @@ expression ctx, notifier, is_external, io_read, io_poll, io_poll_ready; @@ - aio_set_event_notifier(ctx, notifier, is_external, io_read, io_poll, io_poll_ready) + aio_set_event_notifier(ctx, notifier, io_read, io_poll, io_poll_ready) Reviewed-by: Juan Quintela <quintela@redhat.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Message-Id: <20230516190238.8401-21-stefanha@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
		
			
				
	
	
		
			130 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			130 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* SPDX-License-Identifier: GPL-2.0-or-later */
 | 
						|
/*
 | 
						|
 * Test that poll handlers are not re-entrant in nested aio_poll()
 | 
						|
 *
 | 
						|
 * Copyright Red Hat
 | 
						|
 *
 | 
						|
 * Poll handlers are usually level-triggered. That means they continue firing
 | 
						|
 * until the condition is reset (e.g. a virtqueue becomes empty). If a poll
 | 
						|
 * handler calls nested aio_poll() before the condition is reset, then infinite
 | 
						|
 * recursion occurs.
 | 
						|
 *
 | 
						|
 * aio_poll() is supposed to prevent this by disabling poll handlers in nested
 | 
						|
 * aio_poll() calls. This test case checks that this is indeed what happens.
 | 
						|
 */
 | 
						|
#include "qemu/osdep.h"
 | 
						|
#include "block/aio.h"
 | 
						|
#include "qapi/error.h"
 | 
						|
 | 
						|
typedef struct {
 | 
						|
    AioContext *ctx;
 | 
						|
 | 
						|
    /* This is the EventNotifier that drives the test */
 | 
						|
    EventNotifier poll_notifier;
 | 
						|
 | 
						|
    /* This EventNotifier is only used to wake aio_poll() */
 | 
						|
    EventNotifier dummy_notifier;
 | 
						|
 | 
						|
    bool nested;
 | 
						|
} TestData;
 | 
						|
 | 
						|
static void io_read(EventNotifier *notifier)
 | 
						|
{
 | 
						|
    fprintf(stderr, "%s %p\n", __func__, notifier);
 | 
						|
    event_notifier_test_and_clear(notifier);
 | 
						|
}
 | 
						|
 | 
						|
static bool io_poll_true(void *opaque)
 | 
						|
{
 | 
						|
    fprintf(stderr, "%s %p\n", __func__, opaque);
 | 
						|
    return true;
 | 
						|
}
 | 
						|
 | 
						|
static bool io_poll_false(void *opaque)
 | 
						|
{
 | 
						|
    fprintf(stderr, "%s %p\n", __func__, opaque);
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
static void io_poll_ready(EventNotifier *notifier)
 | 
						|
{
 | 
						|
    TestData *td = container_of(notifier, TestData, poll_notifier);
 | 
						|
 | 
						|
    fprintf(stderr, "> %s\n", __func__);
 | 
						|
 | 
						|
    g_assert(!td->nested);
 | 
						|
    td->nested = true;
 | 
						|
 | 
						|
    /* Wake the following nested aio_poll() call */
 | 
						|
    event_notifier_set(&td->dummy_notifier);
 | 
						|
 | 
						|
    /* This nested event loop must not call io_poll()/io_poll_ready() */
 | 
						|
    g_assert(aio_poll(td->ctx, true));
 | 
						|
 | 
						|
    td->nested = false;
 | 
						|
 | 
						|
    fprintf(stderr, "< %s\n", __func__);
 | 
						|
}
 | 
						|
 | 
						|
/* dummy_notifier never triggers */
 | 
						|
static void io_poll_never_ready(EventNotifier *notifier)
 | 
						|
{
 | 
						|
    g_assert_not_reached();
 | 
						|
}
 | 
						|
 | 
						|
static void test(void)
 | 
						|
{
 | 
						|
    TestData td = {
 | 
						|
        .ctx = aio_context_new(&error_abort),
 | 
						|
    };
 | 
						|
 | 
						|
    qemu_set_current_aio_context(td.ctx);
 | 
						|
 | 
						|
    /* Enable polling */
 | 
						|
    aio_context_set_poll_params(td.ctx, 1000000, 2, 2, &error_abort);
 | 
						|
 | 
						|
    /*
 | 
						|
     * The GSource is unused but this has the side-effect of changing the fdmon
 | 
						|
     * that AioContext uses.
 | 
						|
     */
 | 
						|
    aio_get_g_source(td.ctx);
 | 
						|
 | 
						|
    /* Make the event notifier active (set) right away */
 | 
						|
    event_notifier_init(&td.poll_notifier, 1);
 | 
						|
    aio_set_event_notifier(td.ctx, &td.poll_notifier,
 | 
						|
                           io_read, io_poll_true, io_poll_ready);
 | 
						|
 | 
						|
    /* This event notifier will be used later */
 | 
						|
    event_notifier_init(&td.dummy_notifier, 0);
 | 
						|
    aio_set_event_notifier(td.ctx, &td.dummy_notifier,
 | 
						|
                           io_read, io_poll_false, io_poll_never_ready);
 | 
						|
 | 
						|
    /* Consume aio_notify() */
 | 
						|
    g_assert(!aio_poll(td.ctx, false));
 | 
						|
 | 
						|
    /*
 | 
						|
     * Run the io_read() handler. This has the side-effect of activating
 | 
						|
     * polling in future aio_poll() calls.
 | 
						|
     */
 | 
						|
    g_assert(aio_poll(td.ctx, true));
 | 
						|
 | 
						|
    /* The second time around the io_poll()/io_poll_ready() handler runs */
 | 
						|
    g_assert(aio_poll(td.ctx, true));
 | 
						|
 | 
						|
    /* Run io_poll()/io_poll_ready() one more time to show it keeps working */
 | 
						|
    g_assert(aio_poll(td.ctx, true));
 | 
						|
 | 
						|
    aio_set_event_notifier(td.ctx, &td.dummy_notifier, NULL, NULL, NULL);
 | 
						|
    aio_set_event_notifier(td.ctx, &td.poll_notifier, NULL, NULL, NULL);
 | 
						|
    event_notifier_cleanup(&td.dummy_notifier);
 | 
						|
    event_notifier_cleanup(&td.poll_notifier);
 | 
						|
    aio_context_unref(td.ctx);
 | 
						|
}
 | 
						|
 | 
						|
int main(int argc, char **argv)
 | 
						|
{
 | 
						|
    g_test_init(&argc, &argv, NULL);
 | 
						|
    g_test_add_func("/nested-aio-poll", test);
 | 
						|
    return g_test_run();
 | 
						|
}
 |