• NeilBrown's avatar
    NFS: don't try to cross a mountpount when there isn't one there. · 99bbf6ec
    NeilBrown authored
    consider the sequence of commands:
     mkdir -p /import/nfs /import/bind /import/etc
     mount --bind / /import/bind
     mount --make-private /import/bind
     mount --bind /import/etc /import/bind/etc
    
     exportfs -o rw,no_root_squash,crossmnt,async,no_subtree_check localhost:/
     mount -o vers=4 localhost:/ /import/nfs
     ls -l /import/nfs/etc
    
    You would not expect this to report a stale file handle.
    Yet it does.
    
    The manipulations under /import/bind cause the dentry for
    /etc to get the DCACHE_MOUNTED flag set, even though nothing
    is mounted on /etc.  This causes nfsd to call
    nfsd_cross_mnt() even though there is no mountpoint.  So an
    upcall to mountd for "/etc" is performed.
    
    The 'crossmnt' flag on the export of / causes mountd to
    report that /etc is exported as it is a descendant of /.  It
    assumes the kernel wouldn't ask about something that wasn't
    a mountpoint.  The filehandle returned identifies the
    filesystem and the inode number of /etc.
    
    When this filehandle is presented to rpc.mountd, via
    "nfsd.fh", the inode cannot be found associated with any
    name in /etc/exports, or with any mountpoint listed by
    getmntent().  So rpc.mountd says the filehandle doesn't
    exist. Hence ESTALE.
    
    This is fixed by teaching nfsd not to trust DCACHE_MOUNTED
    too much.  It is just a hint, not a guarantee.
    Change nfsd_mountpoint() to return '1' for a certain mountpoint,
    '2' for a possible mountpoint, and 0 otherwise.
    
    Then change nfsd_crossmnt() to check if follow_down()
    actually found a mountpount and, if not, to avoid performing
    a lookup if the location is not known to certainly require
    an export-point.
    Signed-off-by: default avatarNeilBrown <neilb@suse.com>
    Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
    99bbf6ec
vfs.c 50.4 KB