Fix the same bug reported by Kirill Malkin <kirill.malkin@starboardstorage.com> and
authorJeremy Allison <jra@samba.org>
Thu, 12 Apr 2012 20:15:23 +0000 (13:15 -0700)
committerJeremy Allison <jra@samba.org>
Thu, 12 Apr 2012 22:06:58 +0000 (15:06 -0700)
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

index d49dc49cc46fab151bcfb8f0e1524626e6535839..aa65b948594ce153fc37aa9a7d5f7c310a89c919 100644 (file)
@@ -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;
                }
        }