From 80a4e38d6465d8ae47ca113027421af852d34316 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 12 Apr 2012 13:15:23 -0700 Subject: Fix the same bug reported by Kirill Malkin and fixed by Volker for vfs_aio_fork as ref 0aacdbfada46329e0ad9dacfa90041a1c7dbf3e8. From that change: aio_suspend does not signal the main process with a signal, it just waits. The aio_fork module does not use the signal at all, it directly calls back into the main smbd by calling smbd_aio_complete_aio_ex. This is an abstraction violation, but the alternative would have been to use signals where they are not needed. However, in wait_for_aio_completion this bites us: With aio_fork we call handle_aio_completed twice on the same aio_ex struct: Once from the call to handle_aio_completion within the aio_fork module and once from the code in wait_for_aio_completion. Fix this differently here by not calling directly back into smbd, but using a new function aio_linux_setup_returns() to setup the return values that wait_for_aio_completion() in the main smbd will pick up by calling handle_aio_completd(). --- source3/modules/vfs_aio_linux.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/source3/modules/vfs_aio_linux.c b/source3/modules/vfs_aio_linux.c index d49dc49cc4..aa65b94859 100644 --- a/source3/modules/vfs_aio_linux.c +++ b/source3/modules/vfs_aio_linux.c @@ -280,12 +280,12 @@ static int aio_linux_write(struct vfs_handle_struct *handle, } /************************************************************************ - Handle a single finished io. + Save off the error / success conditions from the io_event. + Is idempotent (can be called multiple times given the same ioev). ***********************************************************************/ -static void aio_linux_handle_io_finished(struct io_event *ioev) +static void aio_linux_setup_returns(struct io_event *ioev) { - struct aio_extra *aio_ex = NULL; struct aio_private_data *pd = (struct aio_private_data *)ioev->data; /* ioev->res2 contains the -errno if error. */ @@ -297,6 +297,18 @@ static void aio_linux_handle_io_finished(struct io_event *ioev) pd->ret_size = ioev->res; pd->ret_errno = 0; } +} + +/************************************************************************ + Handle a single finished io. +***********************************************************************/ + +static void aio_linux_handle_io_finished(struct io_event *ioev) +{ + struct aio_extra *aio_ex = NULL; + struct aio_private_data *pd = (struct aio_private_data *)ioev->data; + + aio_linux_setup_returns(ioev); aio_ex = (struct aio_extra *)pd->aiocb->aio_sigevent.sigev_value.sival_ptr; smbd_aio_complete_aio_ex(aio_ex); @@ -512,7 +524,15 @@ static void aio_linux_handle_suspend_io_finished(struct suspend_private *sp, for (i = 0; i < sp->num_entries; i++) { if (sp->aiocb_array[i] == pd->aiocb) { sp->num_finished++; - aio_linux_handle_io_finished(ioev); + /* + * We don't call aio_linux_handle_io_finished() + * here, but only the function that sets up the + * return values. This allows + * aio_linux_handle_io_finished() to be successfully + * called from smbd/aio.c:wait_for_aio_completion() + * once we return from here with all io's done. + */ + aio_linux_setup_returns(ioev); return; } } -- cgit