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
