• NeilBrown's avatar
    NFS: only invalidate dentrys that are clearly invalid. · cc89684c
    NeilBrown authored
    Since commit bafc9b75 ("vfs: More precise tests in d_invalidate")
    in v3.18, a return of '0' from ->d_revalidate() will cause the dentry
    to be invalidated even if it has filesystems mounted on or it or on a
    descendant.  The mounted filesystem is unmounted.
    
    This means we need to be careful not to return 0 unless the directory
    referred to truly is invalid.  So -ESTALE or -ENOENT should invalidate
    the directory.  Other errors such a -EPERM or -ERESTARTSYS should be
    returned from ->d_revalidate() so they are propagated to the caller.
    
    A particular problem can be demonstrated by:
    
    1/ mount an NFS filesystem using NFSv3 on /mnt
    2/ mount any other filesystem on /mnt/foo
    3/ ls /mnt/foo
    4/ turn off network, or otherwise make the server unable to respond
    5/ ls /mnt/foo &
    6/ cat /proc/$!/stack # note that nfs_lookup_revalidate is in the call stack
    7/ kill -9 $! # this results in -ERESTARTSYS being returned
    8/ observe that /mnt/foo has been unmounted.
    
    This patch changes nfs_lookup_revalidate() to only treat
      -ESTALE from nfs_lookup_verify_inode() and
      -ESTALE or -ENOENT from ->lookup()
    as indicating an invalid inode.  Other errors are returned.
    
    Also nfs_check_inode_attributes() is changed to return -ESTALE rather
    than -EIO.  This is consistent with the error returned in similar
    circumstances from nfs_update_inode().
    
    As this bug allows any user to unmount a filesystem mounted on an NFS
    filesystem, this fix is suitable for stable kernels.
    
    Fixes: bafc9b75 ("vfs: More precise tests in d_invalidate")
    Cc: stable@vger.kernel.org (v3.18+)
    Signed-off-by: default avatarNeilBrown <neilb@suse.com>
    Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
    cc89684c
dir.c 63.8 KB