[PATCH 10/11] vfs: trylock inode->i_rwsem in iterate_dir() to support nowait

From: Hao Xu
Date: Sun Aug 27 2023 - 09:36:48 EST


From: Hao Xu <howeyxu@xxxxxxxxxxx>

Trylock inode->i_rwsem in iterate_dir() to support nowait semantics and
error out -EAGAIN when there is contention.

Signed-off-by: Hao Xu <howeyxu@xxxxxxxxxxx>
---
fs/readdir.c | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/fs/readdir.c b/fs/readdir.c
index 6469f076ba6e..664ecd9665a1 100644
--- a/fs/readdir.c
+++ b/fs/readdir.c
@@ -43,6 +43,8 @@ int iterate_dir(struct file *file, struct dir_context *ctx)
struct inode *inode = file_inode(file);
bool shared = false;
int res = -ENOTDIR;
+ bool nowait;
+
if (file->f_op->iterate_shared)
shared = true;
else if (!file->f_op->iterate)
@@ -52,16 +54,22 @@ int iterate_dir(struct file *file, struct dir_context *ctx)
if (res)
goto out;

- if (shared)
- res = down_read_killable(&inode->i_rwsem);
- else
- res = down_write_killable(&inode->i_rwsem);
- if (res)
+ nowait = ctx->flags & DIR_CONTEXT_F_NOWAIT;
+ if (nowait) {
+ res = shared ? down_read_trylock(&inode->i_rwsem) :
+ down_write_trylock(&inode->i_rwsem);
+ if (!res)
+ res = -EAGAIN;
+ } else {
+ res = shared ? down_read_killable(&inode->i_rwsem) :
+ down_write_killable(&inode->i_rwsem);
+ }
+ if (res < 0)
goto out;

res = -ENOENT;
if (!IS_DEADDIR(inode)) {
- res = file_accessed(file, ctx->flags & DIR_CONTEXT_F_NOWAIT);
+ res = file_accessed(file, nowait);
if (res == -EAGAIN)
goto out_unlock;

--
2.25.1