• J. Bruce Fields's avatar
    fs/dcache: allow d_obtain_alias() to return unhashed dentries · d891eedb
    J. Bruce Fields authored
    Without this patch, inodes are not promptly freed on last close of an
    unlinked file by an nfs client:
    
    	client$ mount -tnfs4 server:/export/ /mnt/
    	client$ tail -f /mnt/FOO
    	...
    	server$ df -i /export
    	server$ rm /export/FOO
    	(^C the tail -f)
    	server$ df -i /export
    	server$ echo 2 >/proc/sys/vm/drop_caches
    	server$ df -i /export
    
    the df's will show that the inode is not freed on the filesystem until
    the last step, when it could have been freed after killing the client's
    tail -f. On-disk data won't be deallocated either, leading to possible
    spurious ENOSPC.
    
    This occurs because when the client does the close, it arrives in a
    compound with a putfh and a close, processed like:
    
    	- putfh: look up the filehandle.  The only alias found for the
    	  inode will be DCACHE_UNHASHED alias referenced by the filp
    	  this, so it creates a new DCACHE_DISCONECTED dentry and
    	  returns that instead.
    	- close: closes the existing filp, which is destroyed
    	  immediately by dput() since it's DCACHE_UNHASHED.
    	- end of the compound: release the reference
    	  to the current filehandle, and dput() the new
    	  DCACHE_DISCONECTED dentry, which gets put on the
    	  unused list instead of being destroyed immediately.
    
    Nick Piggin suggested fixing this by allowing d_obtain_alias to return
    the unhashed dentry that is referenced by the filp, instead of making it
    create a new dentry.
    
    Leave __d_find_alias() alone to avoid changing behavior of other
    callers.
    
    Also nfsd doesn't need all the checks of __d_find_alias(); any dentry,
    hashed or unhashed, disconnected or not, should work.
    Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
    Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
    d891eedb
dcache.c 78.4 KB