• NeilBrown's avatar
    VFS: filename_create(): fix incorrect intent. · b3d4650d
    NeilBrown authored
    When asked to create a path ending '/', but which is not to be a
    directory (LOOKUP_DIRECTORY not set), filename_create() will never try
    to create the file.  If it doesn't exist, -ENOENT is reported.
    
    However, it still passes LOOKUP_CREATE|LOOKUP_EXCL to the filesystems
    ->lookup() function, even though there is no intent to create.  This is
    misleading and can cause incorrect behaviour.
    
    If you try
    
       ln -s foo /path/dir/
    
    where 'dir' is a directory on an NFS filesystem which is not currently
    known in the dcache, this will fail with ENOENT.
    
    But as the name is not in the dcache, nfs_lookup gets called with
    LOOKUP_CREATE|LOOKUP_EXCL and so it returns NULL without performing any
    lookup, with the expectation that a subsequent call to create the target
    will be made, and the lookup can be combined with the creation.  In the
    case with a trailing '/' and no LOOKUP_DIRECTORY, that call is never
    made.  Instead filename_create() sees that the dentry is not (yet)
    positive and returns -ENOENT - even though the directory actually
    exists.
    
    So only set LOOKUP_CREATE|LOOKUP_EXCL if there really is an intent to
    create, and use the absence of these flags to decide if -ENOENT should
    be returned.
    
    Note that filename_parentat() is only interested in LOOKUP_REVAL, so we
    split that out and store it in 'reval_flag'.  __lookup_hash() then gets
    reval_flag combined with whatever create flags were determined to be
    needed.
    Reviewed-by: default avatarDavid Disseldorp <ddiss@suse.de>
    Reviewed-by: default avatarJeff Layton <jlayton@kernel.org>
    Signed-off-by: default avatarNeilBrown <neilb@suse.de>
    Cc: Al Viro <viro@zeniv.linux.org.uk>
    Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    b3d4650d
namei.c 134 KB