[PATCH 23/53] afs: lookup_atsys to drop and reclaim lock.
NeilBrown
neilb at ownmail.net
Thu Mar 12 14:12:10 PDT 2026
From: NeilBrown <neil at brown.name>
If afs is asked to lookup a name ending with @sys, it needs to look up
a different name for which is allocates a dentry with
d_alloc_parallel().
This is done while the parent lock is held which will be a problem in
a future patch where the ordering of the parent lock and
d_alloc_parallel() locking is reversed.
There is no actual need to hold the lock while d_alloc_parallel() is
called, so with this patch we drop the lock and reclaim it.
Signed-off-by: NeilBrown <neil at brown.name>
---
fs/afs/dir.c | 22 +++++++++++++++++++---
1 file changed, 19 insertions(+), 3 deletions(-)
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index 1e472768e1f1..c195ee851191 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -908,12 +908,14 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry)
/*
* Look up an entry in a directory with @sys substitution.
*/
-static struct dentry *afs_lookup_atsys(struct inode *dir, struct dentry *dentry)
+static struct dentry *afs_lookup_atsys(struct inode *dir, struct dentry *dentry,
+ unsigned int flags)
{
struct afs_sysnames *subs;
struct afs_net *net = afs_i2net(dir);
struct dentry *ret;
char *buf, *p, *name;
+ struct qstr nm;
int len, i;
_enter("");
@@ -933,6 +935,13 @@ static struct dentry *afs_lookup_atsys(struct inode *dir, struct dentry *dentry)
refcount_inc(&subs->usage);
read_unlock(&net->sysnames_lock);
+ /* Calling d_alloc_parallel() while holding parent locked is undesirable.
+ * We don't really need the lock any more.
+ */
+ if (flags & LOOKUP_SHARED)
+ inode_unlock_shared(dir);
+ else
+ inode_unlock(dir);
for (i = 0; i < subs->nr; i++) {
name = subs->subs[i];
len = dentry->d_name.len - 4 + strlen(name);
@@ -942,7 +951,10 @@ static struct dentry *afs_lookup_atsys(struct inode *dir, struct dentry *dentry)
}
strcpy(p, name);
- ret = lookup_noperm(&QSTR(buf), dentry->d_parent);
+ nm = QSTR(buf);
+ ret = try_lookup_noperm(&nm, dentry->d_parent);
+ if (!ret)
+ ret = d_alloc_parallel(dentry->d_parent, &nm);
if (IS_ERR(ret) || d_is_positive(ret))
goto out_s;
dput(ret);
@@ -953,6 +965,10 @@ static struct dentry *afs_lookup_atsys(struct inode *dir, struct dentry *dentry)
*/
ret = NULL;
out_s:
+ if (flags & LOOKUP_SHARED)
+ inode_lock_shared(dir);
+ else
+ inode_lock_nested(dir, I_MUTEX_PARENT);
afs_put_sysnames(subs);
kfree(buf);
out_p:
@@ -998,7 +1014,7 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
dentry->d_name.name[dentry->d_name.len - 3] == 's' &&
dentry->d_name.name[dentry->d_name.len - 2] == 'y' &&
dentry->d_name.name[dentry->d_name.len - 1] == 's')
- return afs_lookup_atsys(dir, dentry);
+ return afs_lookup_atsys(dir, dentry, flags);
afs_stat_v(dvnode, n_lookup);
inode = afs_do_lookup(dir, dentry);
--
2.50.0.107.gf914562f5916.dirty
More information about the linux-afs
mailing list