diff mbox

NFS: remove BUG possibility in nfs4_open_and_get_state

Message ID 20140911161937.29dd4a31@notabene.brown (mailing list archive)
State New, archived
Headers show

Commit Message

NeilBrown Sept. 11, 2014, 6:19 a.m. UTC
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>

Comments

Jeff Layton Sept. 11, 2014, 11:15 a.m. UTC | #1
On Thu, 11 Sep 2014 16:19:37 +1000
NeilBrown <neilb@suse.de> wrote:

> 
> 
> 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>
> 
> 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;

Acked-by: Jeff Layton <jlayton@primarydata.com>
diff mbox

Patch

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;