• David Howells's avatar
    afs: Fix race between post-modification dir edit and readdir/d_revalidate · 2105c282
    David Howells authored
    AFS directories are retained locally as a structured file, with lookup
    being effected by a local search of the file contents.  When a modification
    (such as mkdir) happens, the dir file content is modified locally rather
    than redownloading the directory.
    
    The directory contents are accessed in a number of ways, with a number of
    different locks schemes:
    
     (1) Download of contents - dvnode->validate_lock/write in afs_read_dir().
    
     (2) Lookup and readdir - dvnode->validate_lock/read in afs_dir_iterate(),
         downgrading from (1) if necessary.
    
     (3) d_revalidate of child dentry - dvnode->validate_lock/read in
         afs_do_lookup_one() downgrading from (1) if necessary.
    
     (4) Edit of dir after modification - page locks on individual dir pages.
    
    Unfortunately, because (4) uses different locking scheme to (1) - (3),
    nothing protects against the page being scanned whilst the edit is
    underway.  Even download is not safe as it doesn't lock the pages - relying
    instead on the validate_lock to serialise as a whole (the theory being that
    directory contents are treated as a block and always downloaded as a
    block).
    
    Fix this by write-locking dvnode->validate_lock around the edits.  Care
    must be taken in the rename case as there may be two different dirs - but
    they need not be locked at the same time.  In any case, once the lock is
    taken, the directory version must be rechecked, and the edit skipped if a
    later version has been downloaded by revalidation (there can't have been
    any local changes because the VFS holds the inode lock, but there can have
    been remote changes).
    
    Fixes: 63a4681f ("afs: Locally edit directory data for mkdir/create/unlink/...")
    Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
    2105c282
dir.c 52.8 KB