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


Reply via email to