From: Hao Xu <howe...@tencent.com>

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

Signed-off-by: Hao Xu <howe...@tencent.com>
---
 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

Reply via email to