From: NeilBrown <[email protected]> Rather than performing a normal lookup (which will be awkward with future locking changes) use d_alloc_noblock() to find a dentry for an unused name, and then open-code the rest of lookup_slow() to see if it is free on the server.
Signed-off-by: NeilBrown <[email protected]> --- fs/nfs/unlink.c | 56 +++++++++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 43ea897943c0..f112c13d97a1 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c @@ -445,7 +445,8 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry) static unsigned int sillycounter; unsigned char silly[SILLYNAME_LEN + 1]; unsigned long long fileid; - struct dentry *sdentry; + struct dentry *sdentry, *old; + struct qstr qsilly; struct inode *inode = d_inode(dentry); struct rpc_task *task; int error = -EBUSY; @@ -462,26 +463,41 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry) fileid = NFS_FILEID(d_inode(dentry)); - sdentry = NULL; - do { +newname: + sillycounter++; + scnprintf(silly, sizeof(silly), + SILLYNAME_PREFIX "%0*llx%0*x", + SILLYNAME_FILEID_LEN, fileid, + SILLYNAME_COUNTER_LEN, sillycounter); + + dfprintk(VFS, "NFS: trying to rename %pd to %s\n", + dentry, silly); + qsilly = QSTR(silly); + sdentry = try_lookup_noperm(&qsilly, dentry->d_parent); + if (!sdentry) + sdentry = d_alloc_noblock(dentry->d_parent, &qsilly); + if (sdentry == ERR_PTR(-EWOULDBLOCK)) + /* Name currently being looked up */ + goto newname; + /* + * N.B. Better to return EBUSY here ... it could be + * dangerous to delete the file while it's in use. + */ + if (IS_ERR(sdentry)) + goto out; + if (d_is_positive(sdentry)) { dput(sdentry); - sillycounter++; - scnprintf(silly, sizeof(silly), - SILLYNAME_PREFIX "%0*llx%0*x", - SILLYNAME_FILEID_LEN, fileid, - SILLYNAME_COUNTER_LEN, sillycounter); - - dfprintk(VFS, "NFS: trying to rename %pd to %s\n", - dentry, silly); - - sdentry = lookup_noperm(&QSTR(silly), dentry->d_parent); - /* - * N.B. Better to return EBUSY here ... it could be - * dangerous to delete the file while it's in use. - */ - if (IS_ERR(sdentry)) - goto out; - } while (d_inode(sdentry) != NULL); /* need negative lookup */ + goto newname; + } + /* This name isn't known locally - check on server */ + old = dir->i_op->lookup(dir, sdentry, 0); + d_lookup_done(sdentry); + if (old || d_is_positive(sdentry)) { + if (!IS_ERR(old)) + dput(old); + dput(sdentry); + goto newname; + } ihold(inode); -- 2.50.0.107.gf914562f5916.dirty
