summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2014-09-11 16:19:37 +1000
committerTrond Myklebust <trond.myklebust@primarydata.com>2014-09-12 13:10:53 -0400
commitf39c01047994e66e7f3d89ddb4c6141f23349d8d (patch)
treef529a1bcb1a4c63d0396049e9444859dd3424fde /fs
parent224ecbf5a674ec7da3a3b3ea21ca62e2853653fa (diff)
downloadlinux-f39c01047994e66e7f3d89ddb4c6141f23349d8d.tar.gz
linux-f39c01047994e66e7f3d89ddb4c6141f23349d8d.tar.xz
NFS: remove BUG possibility in nfs4_open_and_get_state
commit 4fa2c54b5198d09607a534e2fd436581064587ed NFS: nfs4_do_open should add negative results to the dcache. used "d_drop(); d_add();" to ensure that a dentry was hashed as a negative cached entry. This is not safe if the dentry has an non-NULL ->d_inode. It will trigger a BUG_ON in d_instantiate(). In that case, d_delete() is needed. Also, only d_add if the dentry is currently unhashed, it seems pointless removed and re-adding it unchanged. Reported-by: Christoph Hellwig <hch@infradead.org> Fixes: 4fa2c54b5198d09607a534e2fd436581064587ed Cc: Jeff Layton <jeff.layton@primarydata.com> Link: http://lkml.kernel.org/r/20140908144525.GB19811@infradead.org Signed-off-by: NeilBrown <neilb@suse.de> Acked-by: Jeff Layton <jlayton@primarydata.com> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfs/nfs4proc.c10
1 files changed, 7 insertions, 3 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 7dd8aca31c29..ac2dd953fc18 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -2226,9 +2226,13 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
ret = _nfs4_proc_open(opendata);
if (ret != 0) {
if (ret == -ENOENT) {
- d_drop(opendata->dentry);
- d_add(opendata->dentry, NULL);
- nfs_set_verifier(opendata->dentry,
+ dentry = opendata->dentry;
+ if (dentry->d_inode)
+ d_delete(dentry);
+ else if (d_unhashed(dentry))
+ d_add(dentry, NULL);
+
+ nfs_set_verifier(dentry,
nfs_save_change_attribute(opendata->dir->d_inode));
}
goto out;