NFS: Don't re-read the entire page cache to find the next cookie
authorTrond Myklebust <trond.myklebust@hammerspace.com>
Tue, 22 Feb 2022 13:59:33 +0000 (08:59 -0500)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Wed, 2 Mar 2022 13:43:38 +0000 (08:43 -0500)
If the page cache entry that was last read gets invalidated for some
reason, then make sure we can re-create it on the next call to readdir.
This, combined with the cache page validation, allows us to reuse the
cached value of page-index on successive calls to nfs_readdir.

Credit is due to Benjamin Coddington for showing that the concept works,
and that it allows for improved cache sharing between processes even in
the case where pages are lost due to LRU or active invalidation.

Suggested-by: Benjamin Coddington <bcodding@redhat.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
fs/nfs/dir.c
include/linux/nfs_fs.h

index a1767f75546080b0e374d550d5c14b70faf57658..93f70698e4012ad4b280531af89fe98871ceadb8 100644 (file)
@@ -1120,6 +1120,8 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
        desc->dup_cookie = dir_ctx->dup_cookie;
        desc->duped = dir_ctx->duped;
        page_index = dir_ctx->page_index;
+       desc->page_index = page_index;
+       desc->last_cookie = dir_ctx->last_cookie;
        desc->attr_gencount = dir_ctx->attr_gencount;
        desc->eof = dir_ctx->eof;
        memcpy(desc->verf, dir_ctx->verf, sizeof(desc->verf));
@@ -1168,6 +1170,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
        spin_lock(&file->f_lock);
        dir_ctx->dir_cookie = desc->dir_cookie;
        dir_ctx->dup_cookie = desc->dup_cookie;
+       dir_ctx->last_cookie = desc->last_cookie;
        dir_ctx->duped = desc->duped;
        dir_ctx->attr_gencount = desc->attr_gencount;
        dir_ctx->page_index = desc->page_index;
@@ -1209,10 +1212,11 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int whence)
        }
        if (offset != filp->f_pos) {
                filp->f_pos = offset;
-               if (nfs_readdir_use_cookie(filp))
-                       dir_ctx->dir_cookie = offset;
-               else
+               if (!nfs_readdir_use_cookie(filp)) {
                        dir_ctx->dir_cookie = 0;
+                       dir_ctx->page_index = 0;
+               } else
+                       dir_ctx->dir_cookie = offset;
                if (offset == 0)
                        memset(dir_ctx->verf, 0, sizeof(dir_ctx->verf));
                dir_ctx->duped = 0;
index 6e10725887d104cdca746cf3e464892effb2893a..1c533f2c1f36c96daf221f4f41bd9d94620f0f2f 100644 (file)
@@ -105,6 +105,7 @@ struct nfs_open_dir_context {
        __be32  verf[NFS_DIR_VERIFIER_SIZE];
        __u64 dir_cookie;
        __u64 dup_cookie;
+       __u64 last_cookie;
        pgoff_t page_index;
        signed char duped;
        bool eof;