• Josef Bacik's avatar
    btrfs: take the dio extent lock during O_DIRECT operations · 07d399cb
    Josef Bacik authored
    Currently we hold the extent lock for the entire duration of a read.
    This isn't really necessary in the buffered case, we're protected by the
    page lock, however it's necessary for O_DIRECT.
    
    For O_DIRECT reads, if we only locked the extent for the part where we
    get the extent, we could potentially race with an O_DIRECT write in the
    same region.  This isn't really a problem, unless the read is delayed so
    much that the write does the COW, unpins the old extent, and some other
    application re-allocates the extent before the read is actually able to
    be submitted.  At that point at best we'd have a checksum mismatch, but
    at worse we could read data that doesn't belong to us.
    
    To address this potential race we need to make sure we don't have
    overlapping, concurrent direct io reads and writes.
    
    To accomplish this use the new EXTENT_DIO_LOCKED bit in the direct IO
    case in the same spot as the current extent lock.  The writes will take
    this while they're creating the ordered extent, which is also used to
    make sure concurrent buffered reads or concurrent direct reads are not
    allowed to occur, and drop it after the ordered extent is taken.  For
    reads it will act as the current read behavior for the EXTENT_LOCKED
    bit, we set it when we're starting the read, we clear it in the end_io
    to allow other direct writes to continue.
    
    This still has the drawback of disallowing concurrent overlapping direct
    reads from occurring, but that exists with the current extent locking.
    Signed-off-by: default avatarJosef Bacik <josef@toxicpanda.com>
    Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    07d399cb
direct-io.c 32.6 KB