[PATCH 2/3] smb/client: use d_alloc_trylock in cifs_silly_fullpath()

From: NeilBrown

Date: Sun Sep 27 2026 - 21:28:59 EST


From: NeilBrown <neil@xxxxxxxxxx>

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@xxxxxxxxxx>
---
fs/smb/client/dir.c | 27 +++++++++++++++++++--------
1 file changed, 19 insertions(+), 8 deletions(-)

diff --git a/fs/smb/client/dir.c b/fs/smb/client/dir.c
index 88fff65320f5..2faac93c6758 100644
--- a/fs/smb/client/dir.c
+++ b/fs/smb/client/dir.c
@@ -1183,23 +1183,34 @@ char *cifs_silly_fullpath(struct dentry *dentry)
unsigned char name[CIFS_SILLYNAME_LEN + 1];
int retries = 0, max_retries = 16;
size_t namesize = sizeof(name);
- struct dentry *sdentry = NULL;
+ struct dentry *sdentry = NULL, *alias;
char *path;

do {
dput(sdentry);
scnprintf(name, namesize, CIFS_SILLYNAME_PREFIX "%x",
atomic_inc_return(&cifs_sillycounter));
- sdentry = lookup_noperm(&QSTR(name), dentry->d_parent);
+ sdentry = d_alloc_trylock(dentry->d_parent, &QSTR(name));
+ if (sdentry == ERR_PTR(-EWOULDBLOCK)) {
+ sdentry = NULL;
+ continue;
+ }
if (IS_ERR(sdentry))
return ERR_CAST(sdentry);
- if (d_is_negative(sdentry)) {
- dput(sdentry);
- path = alloc_parent_path(dentry, CIFS_SILLYNAME_LEN);
- if (!IS_ERR(path))
- strcat(path, name);
- return path;
+ if (!d_in_lookup(sdentry))
+ continue;
+ alias = cifs_lookup(sdentry->d_parent->d_inode, sdentry, 0);
+ d_lookup_done(sdentry);
+ if (alias || d_is_positive(dentry)) {
+ if (!IS_ERR(alias))
+ dput(alias);
+ continue;
}
+ dput(sdentry);
+ path = alloc_parent_path(dentry, CIFS_SILLYNAME_LEN);
+ if (!IS_ERR(path))
+ strcat(path, name);
+ return path;
} while (++retries < max_retries);
dput(sdentry);
return ERR_PTR(-EBUSY);
--
2.50.0.107.gf914562f5916.dirty