fs/dcache: allow d_obtain_alias() to return unhashed dentries
authorJ. Bruce Fields <bfields@fieldses.org>
Tue, 18 Jan 2011 20:45:09 +0000 (15:45 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Thu, 10 Mar 2011 10:18:54 +0000 (05:18 -0500)
commitd891eedbc3b1b0fade8a9ce60cc0eba1cccb59e5
tree55dd6aa9e17cd763efda6291d740bafd7f05d802
parent1ca551c6caae7b52178555cdedea6ca26444be46
fs/dcache: allow d_obtain_alias() to return unhashed dentries

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: J. Bruce Fields <bfields@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/dcache.c