diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 49394123bd09..741144f04932 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1935,7 +1935,7 @@ static int nfs_dentry_delete(const struct dentry *dentry) } /* Ensure that we revalidate inode->i_nlink */ -static void nfs_drop_nlink(struct inode *inode, unsigned long gencount) +void nfs_drop_nlink(struct inode *inode, unsigned long gencount) { struct nfs_inode *nfsi = NFS_I(inode); @@ -1949,6 +1949,7 @@ static void nfs_drop_nlink(struct inode *inode, unsigned long gencount) NFS_INO_INVALID_NLINK); spin_unlock(&inode->i_lock); } +EXPORT_SYMBOL_GPL(nfs_drop_nlink); /* * Called when the dentry loses inode. @@ -2554,7 +2555,6 @@ EXPORT_SYMBOL_GPL(nfs_rmdir); static int nfs_safe_remove(struct dentry *dentry) { struct inode *dir = d_inode(dentry->d_parent); - struct inode *inode = d_inode(dentry); int error = -EBUSY; dfprintk(VFS, "NFS: safe_remove(%pd2)\n", dentry); @@ -2566,14 +2566,7 @@ static int nfs_safe_remove(struct dentry *dentry) } trace_nfs_remove_enter(dir, dentry); - if (inode != NULL) { - unsigned long gencount = READ_ONCE(NFS_I(inode)->attr_gencount); - - error = NFS_PROTO(dir)->remove(dir, dentry); - if (error == 0) - nfs_drop_nlink(inode, gencount); - } else - error = NFS_PROTO(dir)->remove(dir, dentry); + error = NFS_PROTO(dir)->remove(dir, dentry); if (error == -ENOENT) nfs_dentry_handle_enoent(dentry); trace_nfs_remove_exit(dir, dentry, error); diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 959edbc9add2..42f170973000 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -395,6 +395,7 @@ extern unsigned long nfs_access_cache_count(struct shrinker *shrink, struct shrink_control *sc); extern unsigned long nfs_access_cache_scan(struct shrinker *shrink, struct shrink_control *sc); +extern void nfs_drop_nlink(struct inode *inode, unsigned long gencount); struct dentry *nfs_lookup(struct inode *, struct dentry *, unsigned int); void nfs_d_prune_case_insensitive_aliases(struct inode *inode); int nfs_create(struct mnt_idmap *, struct inode *, struct dentry *, diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index b80d0c5efc27..b5aa3100b627 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -448,13 +448,21 @@ nfs3_proc_remove(struct inode *dir, struct dentry *dentry) .rpc_resp = &res, }; int status = -ENOMEM; + struct inode *inode = d_inode(dentry); + unsigned long gencount; dprintk("NFS call remove %pd2\n", dentry); res.dir_attr = nfs_alloc_fattr(); if (res.dir_attr == NULL) goto out; + if (inode) + gencount = READ_ONCE(NFS_I(inode)->attr_gencount); + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + if (status == 0 && inode) + nfs_drop_nlink(inode, gencount); + nfs_post_op_update_inode(dir, res.dir_attr); nfs_free_fattr(res.dir_attr); out: diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 518348e87dd8..0adc209dc5df 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -4969,12 +4969,14 @@ static int nfs4_proc_remove(struct inode *dir, struct dentry *dentry) }; struct inode *inode = d_inode(dentry); int err; + unsigned long gencount; if (inode) { if (inode->i_nlink == 1) nfs4_inode_return_delegation(inode); else nfs4_inode_make_writeable(inode); + gencount = READ_ONCE(NFS_I(inode)->attr_gencount); } do { err = _nfs4_proc_remove(dir, &dentry->d_name, NF4REG); @@ -4982,6 +4984,9 @@ static int nfs4_proc_remove(struct inode *dir, struct dentry *dentry) err = nfs4_handle_exception(NFS_SERVER(dir), err, &exception); } while (exception.retry); + + if (err == 0 && inode) + nfs_drop_nlink(inode, gencount); return err; } diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index 03c2c1f31be9..406d04b52a7d 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c @@ -323,9 +323,17 @@ nfs_proc_remove(struct inode *dir, struct dentry *dentry) .rpc_argp = &arg, }; int status; + struct inode *inode = d_inode(dentry); + unsigned long gencount; dprintk("NFS call remove %pd2\n",dentry); + if (inode) + gencount = READ_ONCE(NFS_I(inode)->attr_gencount); + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + if (status == 0 && inode) + nfs_drop_nlink(inode, gencount); + nfs_mark_for_revalidate(dir); dprintk("NFS reply remove: %d\n", status);