}
if (io->ci_dio_aio) {
+ struct cl_sync_io *anchor = &io->ci_dio_aio->cda_sync;
+ bool creator_free;
+
/* set the number of bytes successfully moved in the aio */
if (result > 0)
io->ci_dio_aio->cda_bytes = result;
* in our end_io(). (cda_no_aio_complete is always set for
* normal DIO.)
*
+ * Returning !EIOCBQUEUED indicates we didn't do the IO
+ * successfully as pure AIO, but we may have done some of the
+ * IO as AIO. If we return to userspace with an rc other than
+ * EIOCBQUEUED, userspace assumes we completed all IO and
+ * continues without waiting, so we must wait for all IO to
+ * complete.
+ *
* NB: Setting cda_no_aio_complete like this is safe because
* the atomic_dec_and_lock in cl_sync_io_note has implicit
* memory barriers, so this will be seen by whichever thread
* completes the DIO/AIO, even if it's not this one.
*/
- if (is_aio && rc != -EIOCBQUEUED)
+ if (is_aio && rc != -EIOCBQUEUED) {
io->ci_dio_aio->cda_no_aio_complete = 1;
+ LASSERT(ergo(!io->ci_dio_aio->cda_creator_free, is_aio));
+ io->ci_dio_aio->cda_creator_free = 1;
+
+ rc2 = cl_sync_io_wait_recycle(env, anchor, 0, 0);
+ if (rc2 < 0)
+ rc = rc2;
+ }
/* if an aio enqueued successfully (-EIOCBQUEUED), then Lustre
* will call aio_complete rather than the vfs, so we return 0
* to tell the VFS we're handling it
* For DIO, this frees it here, since IO is complete, and for
* AIO, we will call aio_complete() (and then free this top
* level context) once all the outstanding chunks of this AIO
- * have completed.
+ * have completed. NB: for AIO which is only partially done as
+ * AIO, we also complete it here. See call to
+ * cl_sync_io_wait_recycle just above.
+ */
+ /* grab creator_free value before doing final cl_sync_io_note,
+ * since the ci_dio_aio may be freed after that
*/
- cl_sync_io_note(env, &io->ci_dio_aio->cda_sync,
- rc == -EIOCBQUEUED ? 0 : rc);
- if (!is_aio) {
- LASSERT(io->ci_dio_aio->cda_creator_free);
+ creator_free = io->ci_dio_aio->cda_creator_free;
+ cl_sync_io_note(env, anchor, rc == -EIOCBQUEUED ? 0 : rc);
+ if (creator_free) {
+ /* aio is only freed here if it wasn't 100% successful*/
+ LASSERT(!is_aio || rc != -EIOCBQUEUED);
cl_dio_aio_free(env, io->ci_dio_aio);
io->ci_dio_aio = NULL;
}