• Andrew Morton's avatar
    [PATCH] AIO+DIO bio_count race fix · c58d3aeb
    Andrew Morton authored
    From: Suparna Bhattacharya <suparna@in.ibm.com>,
          Daniel McNeil <daniel@osdl.org>
    
    This patch ensures that when the DIO code falls back to buffered i/o after
    having submitted part of the i/o, then buffered i/o is issued only for the
    remaining part of the request (i.e.  the part not already covered by DIO),
    rather than redo the entire i/o.  Now, instead of returning written ==
    -ENOTBLK, generic_file_direct_IO returns the number of bytes already handled
    by DIO, so that the caller knows how much of the I/O is left to be handled
    via fallback to buffered write.
    
    We need to careful not to access dio fields if its possible that the dio
    could already have been freed asynchronously during i/o completion.  A tricky
    part of this involves plugging the window between the decrement of bio_count
    and accessing dio->waiter during i/o completion where the dio could get freed
    by the submission path.  This potential "bio_count race" was tackled (by
    Daniel) by changing bio_list_lock into bio_lock and using that for all the
    bio fields.  Now bio_count and bios_in_flight have been converted from
    atomics into int and are both protected by the bio_lock.  The race in
    finished_one_bio() could thus be fixed by leaving the bio_count at 1 until
    after the dio_complete() and then doing the bio_count decrement and wakeup
    holding the bio_lock.  It appears that shifting to the spin_lock instead of
    atomic_inc/decs is ok performance wise as well.
    
    Update:
    
    An AIO O_DIRECT request was extending the file so it was done
    synchronously.  However, the request got an EFAULT and direct_io_worker()
    was calling aio_complete() on the iocb and returning the EFAULT.  When
    io_submit_one() got the EFAULT return, it assume it had to call
    aio_complete() since the i/o never got queued.
    
    The fix is for direct_io_worker() to only call aio_complete() when the
    upper layer is going to return -EIOCBQUEUED and not when getting errors
    that are being return to the submit path.
    c58d3aeb
filemap.c 49.6 KB