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 use an open-coded lookup_slow() to see if it is free on
the server.

Signed-off-by: NeilBrown <[email protected]>
---
 fs/afs/dir_silly.c | 51 ++++++++++++++++++++++++++++++----------------
 1 file changed, 34 insertions(+), 17 deletions(-)

diff --git a/fs/afs/dir_silly.c b/fs/afs/dir_silly.c
index 982bb6ec15f0..699143b21cdd 100644
--- a/fs/afs/dir_silly.c
+++ b/fs/afs/dir_silly.c
@@ -112,7 +112,9 @@ int afs_sillyrename(struct afs_vnode *dvnode, struct 
afs_vnode *vnode,
                    struct dentry *dentry, struct key *key)
 {
        static unsigned int sillycounter;
-       struct dentry *sdentry = NULL;
+       struct dentry *sdentry = NULL, *old;
+       struct inode *dir = dentry->d_parent->d_inode;
+       struct qstr qsilly;
        unsigned char silly[16];
        int ret = -EBUSY;
 
@@ -122,23 +124,38 @@ int afs_sillyrename(struct afs_vnode *dvnode, struct 
afs_vnode *vnode,
        if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
                return -EBUSY;
 
-       sdentry = NULL;
-       do {
-               dput(sdentry);
-               sillycounter++;
-
-               /* Create a silly name.  Note that the ".__afs" prefix is
-                * understood by the salvager and must not be changed.
-                */
-               scnprintf(silly, sizeof(silly), ".__afs%04X", sillycounter);
-               sdentry = lookup_noperm(&QSTR(silly), dentry->d_parent);
+newname:
+       sillycounter++;
 
-               /* 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_is_negative(sdentry));
+       /* Create a silly name.  Note that the ".__afs" prefix is
+        * understood by the salvager and must not be changed.
+        */
+       scnprintf(silly, sizeof(silly), ".__afs%04X", sillycounter);
+       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))
+               /* try another name */
+               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);
+               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(&vnode->netfs.inode);
 
-- 
2.50.0.107.gf914562f5916.dirty


Reply via email to