aio: block io_destroy() until all context requests are completed
authorAnatol Pomozov <anatol.pomozov@gmail.com>
Tue, 15 Apr 2014 18:31:33 +0000 (11:31 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 9 Jul 2014 18:18:28 +0000 (11:18 -0700)
commit199f5458a1271586f5241fe5f5d28b7be3d2845c
treeead763e48242a457ca93af82c071fcf93f9982fa
parent2d29f7576d8a79e4effb79404e76ea911488a44e
aio: block io_destroy() until all context requests are completed

commit e02ba72aabfade4c9cd6e3263e9b57bf890ad25c upstream.

deletes aio context and all resources related to. It makes sense that
no IO operations connected to the context should be running after the context
is destroyed. As we removed io_context we have no chance to
get requests status or call io_getevents().

man page for io_destroy says that this function may block until
all context's requests are completed. Before kernel 3.11 io_destroy()
blocked indeed, but since aio refactoring in 3.11 it is not true anymore.

Here is a pseudo-code that shows a testcase for a race condition discovered
in 3.11:

  initialize io_context
  io_submit(read to buffer)
  io_destroy()

  // context is destroyed so we can free the resources
  free(buffers);

  // if the buffer is allocated by some other user he'll be surprised
  // to learn that the buffer still filled by an outstanding operation
  // from the destroyed io_context

The fix is straight-forward - add a completion struct and wait on it
in io_destroy, complete() should be called when number of in-fligh requests
reaches zero.

If two or more io_destroy() called for the same context simultaneously then
only the first one waits for IO completion, other calls behaviour is undefined.

Tested: ran http://pastebin.com/LrPsQ4RL testcase for several hours and
  do not see the race condition anymore.

Signed-off-by: Anatol Pomozov <anatol.pomozov@gmail.com>
Signed-off-by: Benjamin LaHaise <bcrl@kvack.org>
Cc: Jan Kara <jack@suse.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/aio.c