[PATCH v2 3/5] afs: use d_alloc_trylock in afs_sillyrename()
NeilBrown
neilb at ownmail.net
Mon Sep 28 19:29:29 PDT 2026
From: NeilBrown <neil at brown.name>
Rather than performing a normal lookup (which will be awkward with future
locking changes) use d_alloc_trylock() 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 <neil at brown.name>
---
fs/afs/dir.c | 6 ++----
fs/afs/dir_silly.c | 54 +++++++++++++++++++++++++++++++---------------
fs/afs/internal.h | 2 ++
3 files changed, 41 insertions(+), 21 deletions(-)
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index c790fa9432ab..1edaa7323428 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -19,8 +19,6 @@
#include "afs_fs.h"
#include "xdr_fs.h"
-static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
- unsigned int flags);
static int afs_dir_open(struct inode *inode, struct file *file);
static int afs_readdir(struct file *file, struct dir_context *ctx);
static int afs_d_revalidate(struct inode *dir, const struct qstr *name,
@@ -967,8 +965,8 @@ static struct dentry *afs_lookup_atsys(struct inode *dir, struct dentry *dentry)
/*
* look up an entry in a directory
*/
-static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
- unsigned int flags)
+struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
+ unsigned int flags)
{
struct afs_vnode *dvnode = AFS_FS_I(dir);
struct afs_fid fid = {};
diff --git a/fs/afs/dir_silly.c b/fs/afs/dir_silly.c
index 982bb6ec15f0..12cd2b340392 100644
--- a/fs/afs/dir_silly.c
+++ b/fs/afs/dir_silly.c
@@ -112,7 +112,8 @@ 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;
unsigned char silly[16];
int ret = -EBUSY;
@@ -122,23 +123,42 @@ 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);
+ sdentry = d_alloc_trylock(dentry->d_parent, &QSTR(silly));
+ 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_in_lookup(sdentry)) {
+ if (d_really_is_negative(sdentry)) {
+ /* try to get an in-lookup dentry */
+ d_drop(sdentry);
+ sillycounter--;
+ }
+ dput(sdentry);
+ goto newname;
+ }
+ /* This name isn't known locally - check on server */
+ old = afs_lookup(dir, sdentry, 0);
+ d_lookup_done(sdentry);
+ if (IS_ERR(old))
+ goto out;
+ if (old || d_is_positive(sdentry)) {
+ dput(old);
+ dput(sdentry);
+ goto newname;
+ }
ihold(&vnode->netfs.inode);
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 5815ce1f1bfd..d3fd108041cf 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -1109,6 +1109,8 @@ ssize_t afs_read_dir(struct afs_vnode *dvnode, struct file *file)
__acquires(&dvnode->validate_lock);
extern void afs_d_release(struct dentry *);
extern void afs_check_for_remote_deletion(struct afs_operation *);
+extern struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
+ unsigned int flags);
/*
* dir_edit.c
--
2.50.0.107.gf914562f5916.dirty
More information about the linux-afs
mailing list