diff mbox series

[v3,16/17] NFS: Improve handling of directory verifiers

Message ID 20201104161638.300324-17-trond.myklebust@hammerspace.com (mailing list archive)
State New
Headers show
Series Readdir enhancements | expand

Commit Message

Trond Myklebust Nov. 4, 2020, 4:16 p.m. UTC
From: Trond Myklebust <trond.myklebust@hammerspace.com>

If the server insists on using the readdir verifiers in order to allow
cookies to expire, then we should ensure that we cache the verifier
with the cookie, so that we can return an error if the application
tries to use the expired cookie.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
---
 fs/nfs/dir.c           | 35 +++++++++++++++++++++++------------
 fs/nfs/inode.c         |  7 -------
 include/linux/nfs_fs.h |  8 +++++++-
 3 files changed, 30 insertions(+), 20 deletions(-)

Comments

David Wysochanski Nov. 4, 2020, 9:01 p.m. UTC | #1
On Wed, Nov 4, 2020 at 11:28 AM <trondmy@gmail.com> wrote:
>
> From: Trond Myklebust <trond.myklebust@hammerspace.com>
>
> If the server insists on using the readdir verifiers in order to allow
> cookies to expire, then we should ensure that we cache the verifier
> with the cookie, so that we can return an error if the application
> tries to use the expired cookie.
>
> Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
> ---
>  fs/nfs/dir.c           | 35 +++++++++++++++++++++++------------
>  fs/nfs/inode.c         |  7 -------
>  include/linux/nfs_fs.h |  8 +++++++-
>  3 files changed, 30 insertions(+), 20 deletions(-)
>
> diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
> index 3b44bef3a1b4..454377228167 100644
> --- a/fs/nfs/dir.c
> +++ b/fs/nfs/dir.c
> @@ -155,6 +155,7 @@ struct nfs_readdir_descriptor {
>         loff_t          current_index;
>         loff_t          prev_index;
>
> +       __be32          verf[NFS_DIR_VERIFIER_SIZE];
>         unsigned long   dir_verifier;
>         unsigned long   timestamp;
>         unsigned long   gencount;
> @@ -466,15 +467,15 @@ static int nfs_readdir_search_array(struct nfs_readdir_descriptor *desc)
>
>  /* Fill a page with xdr information before transferring to the cache page */
>  static int nfs_readdir_xdr_filler(struct nfs_readdir_descriptor *desc,
> -                                 u64 cookie, struct page **pages,
> -                                 size_t bufsize)
> +                                 __be32 *verf, u64 cookie,
> +                                 struct page **pages, size_t bufsize,
> +                                 __be32 *verf_res)
>  {
>         struct inode *inode = file_inode(desc->file);
> -       __be32 verf_res[2];
>         struct nfs_readdir_arg arg = {
>                 .dentry = file_dentry(desc->file),
>                 .cred = desc->file->f_cred,
> -               .verf = NFS_I(inode)->cookieverf,
> +               .verf = verf,
>                 .cookie = cookie,
>                 .pages = pages,
>                 .page_len = bufsize,
> @@ -503,8 +504,6 @@ static int nfs_readdir_xdr_filler(struct nfs_readdir_descriptor *desc,
>         }
>         desc->timestamp = timestamp;
>         desc->gencount = gencount;
> -       memcpy(NFS_I(inode)->cookieverf, res.verf,
> -              sizeof(NFS_I(inode)->cookieverf));
>  error:
>         return error;
>  }
> @@ -770,11 +769,13 @@ static struct page **nfs_readdir_alloc_pages(size_t npages)
>  }
>
>  static int nfs_readdir_xdr_to_array(struct nfs_readdir_descriptor *desc,
> -                                   struct page *page, struct inode *inode)
> +                                   struct page *page, __be32 *verf_arg,
> +                                   __be32 *verf_res)
>  {
>         struct page **pages;
>         struct nfs_entry *entry;
>         size_t array_size;
> +       struct inode *inode = file_inode(desc->file);
>         size_t dtsize = NFS_SERVER(inode)->dtsize;
>         int status = -ENOMEM;
>
> @@ -801,8 +802,9 @@ static int nfs_readdir_xdr_to_array(struct nfs_readdir_descriptor *desc,
>
>         do {
>                 unsigned int pglen;
> -               status = nfs_readdir_xdr_filler(desc, entry->cookie,
> -                                               pages, dtsize);
> +               status = nfs_readdir_xdr_filler(desc, verf_arg, entry->cookie,
> +                                               pages, dtsize,
> +                                               verf_res);
>                 if (status < 0)
>                         break;
>
> @@ -854,13 +856,15 @@ static int find_and_lock_cache_page(struct nfs_readdir_descriptor *desc)
>  {
>         struct inode *inode = file_inode(desc->file);
>         struct nfs_inode *nfsi = NFS_I(inode);
> +       __be32 verf[NFS_DIR_VERIFIER_SIZE];
>         int res;
>
>         desc->page = nfs_readdir_page_get_cached(desc);
>         if (!desc->page)
>                 return -ENOMEM;
>         if (nfs_readdir_page_needs_filling(desc->page)) {
> -               res = nfs_readdir_xdr_to_array(desc, desc->page, inode);
> +               res = nfs_readdir_xdr_to_array(desc, desc->page,
> +                                              nfsi->cookieverf, verf);
>                 if (res < 0) {
>                         nfs_readdir_page_unlock_and_put_cached(desc);
>                         if (res == -EBADCOOKIE || res == -ENOTSYNC) {
> @@ -870,6 +874,7 @@ static int find_and_lock_cache_page(struct nfs_readdir_descriptor *desc)
>                         }
>                         return res;
>                 }
> +               memcpy(nfsi->cookieverf, verf, sizeof(nfsi->cookieverf));
>         }
>         res = nfs_readdir_search_array(desc);
>         if (res == 0) {
> @@ -902,6 +907,7 @@ static int readdir_search_pagecache(struct nfs_readdir_descriptor *desc)
>  static void nfs_do_filldir(struct nfs_readdir_descriptor *desc)
>  {
>         struct file     *file = desc->file;
> +       struct nfs_inode *nfsi = NFS_I(file_inode(file));
>         struct nfs_cache_array *array;
>         unsigned int i = 0;
>
> @@ -915,6 +921,7 @@ static void nfs_do_filldir(struct nfs_readdir_descriptor *desc)
>                         desc->eof = true;
>                         break;
>                 }
> +               memcpy(desc->verf, nfsi->cookieverf, sizeof(desc->verf));
>                 if (i < (array->size-1))
>                         desc->dir_cookie = array->array[i+1].cookie;
>                 else
> @@ -949,8 +956,8 @@ static void nfs_do_filldir(struct nfs_readdir_descriptor *desc)
>  static int uncached_readdir(struct nfs_readdir_descriptor *desc)
>  {
>         struct page     *page = NULL;
> +       __be32          verf[NFS_DIR_VERIFIER_SIZE];
>         int             status;
> -       struct inode *inode = file_inode(desc->file);
>
>         dfprintk(DIRCACHE, "NFS: uncached_readdir() searching for cookie %Lu\n",
>                         (unsigned long long)desc->dir_cookie);
> @@ -967,7 +974,7 @@ static int uncached_readdir(struct nfs_readdir_descriptor *desc)
>         desc->duped = 0;
>
>         nfs_readdir_page_init_array(page, desc->dir_cookie);
> -       status = nfs_readdir_xdr_to_array(desc, page, inode);
> +       status = nfs_readdir_xdr_to_array(desc, page, desc->verf, verf);
>         if (status < 0)
>                 goto out_release;
>
> @@ -1023,6 +1030,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
>         desc->dup_cookie = dir_ctx->dup_cookie;
>         desc->duped = dir_ctx->duped;
>         desc->attr_gencount = dir_ctx->attr_gencount;
> +       memcpy(desc->verf, dir_ctx->verf, sizeof(desc->verf));
>         spin_unlock(&file->f_lock);
>
>         do {
> @@ -1061,6 +1069,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
>         dir_ctx->dup_cookie = desc->dup_cookie;
>         dir_ctx->duped = desc->duped;
>         dir_ctx->attr_gencount = desc->attr_gencount;
> +       memcpy(dir_ctx->verf, desc->verf, sizeof(dir_ctx->verf));
>         spin_unlock(&file->f_lock);
>
>         kfree(desc);
> @@ -1101,6 +1110,8 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int whence)
>                         dir_ctx->dir_cookie = offset;
>                 else
>                         dir_ctx->dir_cookie = 0;
> +               if (offset == 0)
> +                       memset(dir_ctx->verf, 0, sizeof(dir_ctx->verf));
>                 dir_ctx->duped = 0;
>         }
>         spin_unlock(&filp->f_lock);

Thanks for doing these patches!

For some reason this patch does not apply but I get a problem at this hunk.
Is there a fixup or hunk or two missing from 01/17 ?
I'm starting at 3cea11cd5e3b (Linux 5.10-rc2).

Problem looks like it's at the spin_unlock - here's what the hunk
looks like for me:
fs/nfs/dir.c
1092         inode_lock(inode);
1093         offset += filp->f_pos;
1094         if (offset < 0) {
1095             inode_unlock(inode);
1096             return -EINVAL;
1097         }
1098     }
1099     if (offset != filp->f_pos) {
1100         filp->f_pos = offset;
1101         if (nfs_readdir_use_cookie(filp))
1102             dir_ctx->dir_cookie = offset;
1103         else
1104             dir_ctx->dir_cookie = 0;
1105         dir_ctx->duped = 0;
1106     }
1107     inode_unlock(inode);
1108     return offset;
1109 }



$ git reset --hard 3cea11cd5e3b
HEAD is now at 3cea11cd5e3b Linux 5.10-rc2
$ for f in
~/Downloads/trond-nfs-readdir/v3/*; do echo applying $(basename "$f");
git am "$f"; done
applying [PATCH v3 01_17] NFS_ Ensure contents of struct
nfs_open_dir_context are consistent.eml
Applying: NFS: Ensure contents of struct nfs_open_dir_context are consistent
applying [PATCH v3 02_17] NFS_ Clean up readdir struct nfs_cache_array.eml
Applying: NFS: Clean up readdir struct nfs_cache_array
applying [PATCH v3 03_17] NFS_ Clean up nfs_readdir_page_filler().eml
Applying: NFS: Clean up nfs_readdir_page_filler()
applying [PATCH v3 04_17] NFS_ Clean up directory array handling.eml
Applying: NFS: Clean up directory array handling
applying [PATCH v3 05_17] NFS_ Don't discard readdir results.eml
Applying: NFS: Don't discard readdir results
applying [PATCH v3 06_17] NFS_ Remove unnecessary kmap in
nfs_readdir_xdr_to_array().eml
Applying: NFS: Remove unnecessary kmap in nfs_readdir_xdr_to_array()
applying [PATCH v3 07_17] NFS_ Replace kmap() with kmap_atomic() in
nfs_readdir_search_array().eml
Applying: NFS: Replace kmap() with kmap_atomic() in nfs_readdir_search_array()
applying [PATCH v3 08_17] NFS_ Simplify struct nfs_cache_array_entry.eml
Applying: NFS: Simplify struct nfs_cache_array_entry
applying [PATCH v3 09_17] NFS_ Support larger readdir buffers.eml
Applying: NFS: Support larger readdir buffers
applying [PATCH v3 10_17] NFS_ More readdir cleanups.eml
Applying: NFS: More readdir cleanups
applying [PATCH v3 11_17] NFS_ nfs_do_filldir() does not return a value.eml
Applying: NFS: nfs_do_filldir() does not return a value
applying [PATCH v3 12_17] NFS_ Reduce readdir stack usage.eml
Applying: NFS: Reduce readdir stack usage
applying [PATCH v3 13_17] NFS_ Cleanup to remove
nfs_readdir_descriptor_t typedef.eml
Applying: NFS: Cleanup to remove nfs_readdir_descriptor_t typedef
applying [PATCH v3 14_17] NFS_ Allow the NFS generic code to pass in a
verifier to readdir.eml
Applying: NFS: Allow the NFS generic code to pass in a verifier to readdir
applying [PATCH v3 15_17] NFS_ Handle NFS4ERR_NOT_SAME and
NFSERR_BADCOOKIE from readdir calls.eml
Applying: NFS: Handle NFS4ERR_NOT_SAME and NFSERR_BADCOOKIE from readdir calls
applying [PATCH v3 16_17] NFS_ Improve handling of directory verifiers.eml
Applying: NFS: Improve handling of directory verifiers
error: patch failed: fs/nfs/dir.c:1101
error: fs/nfs/dir.c: patch does not apply
Patch failed at 0001 NFS: Improve handling of directory verifiers
The copy of the patch that failed is found in:
   /home/dwysocha/git/kernel/.git/rebase-apply/patch
When you have resolved this problem, run "git am --resolved".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".
applying [PATCH v3 17_17] NFS_ Optimisations for monotonically
increasing readdir cookies.eml
previous rebase directory /home/dwysocha/git/kernel/.git/rebase-apply
still exists but mbox given.
Trond Myklebust Nov. 4, 2020, 9:31 p.m. UTC | #2
> On Nov 4, 2020, at 16:01, David Wysochanski <dwysocha@redhat.com> wrote:
> 
> On Wed, Nov 4, 2020 at 11:28 AM <trondmy@gmail.com> wrote:
>> 
>> From: Trond Myklebust <trond.myklebust@hammerspace.com>
>> 
>> If the server insists on using the readdir verifiers in order to allow
>> cookies to expire, then we should ensure that we cache the verifier
>> with the cookie, so that we can return an error if the application
>> tries to use the expired cookie.
>> 
>> Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
>> ---
>> fs/nfs/dir.c           | 35 +++++++++++++++++++++++------------
>> fs/nfs/inode.c         |  7 -------
>> include/linux/nfs_fs.h |  8 +++++++-
>> 3 files changed, 30 insertions(+), 20 deletions(-)
>> 
>> diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
>> index 3b44bef3a1b4..454377228167 100644
>> --- a/fs/nfs/dir.c
>> +++ b/fs/nfs/dir.c
>> @@ -155,6 +155,7 @@ struct nfs_readdir_descriptor {
>>        loff_t          current_index;
>>        loff_t          prev_index;
>> 
>> +       __be32          verf[NFS_DIR_VERIFIER_SIZE];
>>        unsigned long   dir_verifier;
>>        unsigned long   timestamp;
>>        unsigned long   gencount;
>> @@ -466,15 +467,15 @@ static int nfs_readdir_search_array(struct nfs_readdir_descriptor *desc)
>> 
>> /* Fill a page with xdr information before transferring to the cache page */
>> static int nfs_readdir_xdr_filler(struct nfs_readdir_descriptor *desc,
>> -                                 u64 cookie, struct page **pages,
>> -                                 size_t bufsize)
>> +                                 __be32 *verf, u64 cookie,
>> +                                 struct page **pages, size_t bufsize,
>> +                                 __be32 *verf_res)
>> {
>>        struct inode *inode = file_inode(desc->file);
>> -       __be32 verf_res[2];
>>        struct nfs_readdir_arg arg = {
>>                .dentry = file_dentry(desc->file),
>>                .cred = desc->file->f_cred,
>> -               .verf = NFS_I(inode)->cookieverf,
>> +               .verf = verf,
>>                .cookie = cookie,
>>                .pages = pages,
>>                .page_len = bufsize,
>> @@ -503,8 +504,6 @@ static int nfs_readdir_xdr_filler(struct nfs_readdir_descriptor *desc,
>>        }
>>        desc->timestamp = timestamp;
>>        desc->gencount = gencount;
>> -       memcpy(NFS_I(inode)->cookieverf, res.verf,
>> -              sizeof(NFS_I(inode)->cookieverf));
>> error:
>>        return error;
>> }
>> @@ -770,11 +769,13 @@ static struct page **nfs_readdir_alloc_pages(size_t npages)
>> }
>> 
>> static int nfs_readdir_xdr_to_array(struct nfs_readdir_descriptor *desc,
>> -                                   struct page *page, struct inode *inode)
>> +                                   struct page *page, __be32 *verf_arg,
>> +                                   __be32 *verf_res)
>> {
>>        struct page **pages;
>>        struct nfs_entry *entry;
>>        size_t array_size;
>> +       struct inode *inode = file_inode(desc->file);
>>        size_t dtsize = NFS_SERVER(inode)->dtsize;
>>        int status = -ENOMEM;
>> 
>> @@ -801,8 +802,9 @@ static int nfs_readdir_xdr_to_array(struct nfs_readdir_descriptor *desc,
>> 
>>        do {
>>                unsigned int pglen;
>> -               status = nfs_readdir_xdr_filler(desc, entry->cookie,
>> -                                               pages, dtsize);
>> +               status = nfs_readdir_xdr_filler(desc, verf_arg, entry->cookie,
>> +                                               pages, dtsize,
>> +                                               verf_res);
>>                if (status < 0)
>>                        break;
>> 
>> @@ -854,13 +856,15 @@ static int find_and_lock_cache_page(struct nfs_readdir_descriptor *desc)
>> {
>>        struct inode *inode = file_inode(desc->file);
>>        struct nfs_inode *nfsi = NFS_I(inode);
>> +       __be32 verf[NFS_DIR_VERIFIER_SIZE];
>>        int res;
>> 
>>        desc->page = nfs_readdir_page_get_cached(desc);
>>        if (!desc->page)
>>                return -ENOMEM;
>>        if (nfs_readdir_page_needs_filling(desc->page)) {
>> -               res = nfs_readdir_xdr_to_array(desc, desc->page, inode);
>> +               res = nfs_readdir_xdr_to_array(desc, desc->page,
>> +                                              nfsi->cookieverf, verf);
>>                if (res < 0) {
>>                        nfs_readdir_page_unlock_and_put_cached(desc);
>>                        if (res == -EBADCOOKIE || res == -ENOTSYNC) {
>> @@ -870,6 +874,7 @@ static int find_and_lock_cache_page(struct nfs_readdir_descriptor *desc)
>>                        }
>>                        return res;
>>                }
>> +               memcpy(nfsi->cookieverf, verf, sizeof(nfsi->cookieverf));
>>        }
>>        res = nfs_readdir_search_array(desc);
>>        if (res == 0) {
>> @@ -902,6 +907,7 @@ static int readdir_search_pagecache(struct nfs_readdir_descriptor *desc)
>> static void nfs_do_filldir(struct nfs_readdir_descriptor *desc)
>> {
>>        struct file     *file = desc->file;
>> +       struct nfs_inode *nfsi = NFS_I(file_inode(file));
>>        struct nfs_cache_array *array;
>>        unsigned int i = 0;
>> 
>> @@ -915,6 +921,7 @@ static void nfs_do_filldir(struct nfs_readdir_descriptor *desc)
>>                        desc->eof = true;
>>                        break;
>>                }
>> +               memcpy(desc->verf, nfsi->cookieverf, sizeof(desc->verf));
>>                if (i < (array->size-1))
>>                        desc->dir_cookie = array->array[i+1].cookie;
>>                else
>> @@ -949,8 +956,8 @@ static void nfs_do_filldir(struct nfs_readdir_descriptor *desc)
>> static int uncached_readdir(struct nfs_readdir_descriptor *desc)
>> {
>>        struct page     *page = NULL;
>> +       __be32          verf[NFS_DIR_VERIFIER_SIZE];
>>        int             status;
>> -       struct inode *inode = file_inode(desc->file);
>> 
>>        dfprintk(DIRCACHE, "NFS: uncached_readdir() searching for cookie %Lu\n",
>>                        (unsigned long long)desc->dir_cookie);
>> @@ -967,7 +974,7 @@ static int uncached_readdir(struct nfs_readdir_descriptor *desc)
>>        desc->duped = 0;
>> 
>>        nfs_readdir_page_init_array(page, desc->dir_cookie);
>> -       status = nfs_readdir_xdr_to_array(desc, page, inode);
>> +       status = nfs_readdir_xdr_to_array(desc, page, desc->verf, verf);
>>        if (status < 0)
>>                goto out_release;
>> 
>> @@ -1023,6 +1030,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
>>        desc->dup_cookie = dir_ctx->dup_cookie;
>>        desc->duped = dir_ctx->duped;
>>        desc->attr_gencount = dir_ctx->attr_gencount;
>> +       memcpy(desc->verf, dir_ctx->verf, sizeof(desc->verf));
>>        spin_unlock(&file->f_lock);
>> 
>>        do {
>> @@ -1061,6 +1069,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
>>        dir_ctx->dup_cookie = desc->dup_cookie;
>>        dir_ctx->duped = desc->duped;
>>        dir_ctx->attr_gencount = desc->attr_gencount;
>> +       memcpy(dir_ctx->verf, desc->verf, sizeof(dir_ctx->verf));
>>        spin_unlock(&file->f_lock);
>> 
>>        kfree(desc);
>> @@ -1101,6 +1110,8 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int whence)
>>                        dir_ctx->dir_cookie = offset;
>>                else
>>                        dir_ctx->dir_cookie = 0;
>> +               if (offset == 0)
>> +                       memset(dir_ctx->verf, 0, sizeof(dir_ctx->verf));
>>                dir_ctx->duped = 0;
>>        }
>>        spin_unlock(&filp->f_lock);
> 
> Thanks for doing these patches!
> 
> For some reason this patch does not apply but I get a problem at this hunk.
> Is there a fixup or hunk or two missing from 01/17 ?
> I'm starting at 3cea11cd5e3b (Linux 5.10-rc2).
> 
> Problem looks like it's at the spin_unlock - here's what the hunk
> looks like for me:
> fs/nfs/dir.c
> 1092         inode_lock(inode);
> 1093         offset += filp->f_pos;
> 1094         if (offset < 0) {
> 1095             inode_unlock(inode);
> 1096             return -EINVAL;
> 1097         }
> 1098     }
> 1099     if (offset != filp->f_pos) {
> 1100         filp->f_pos = offset;
> 1101         if (nfs_readdir_use_cookie(filp))
> 1102             dir_ctx->dir_cookie = offset;
> 1103         else
> 1104             dir_ctx->dir_cookie = 0;
> 1105         dir_ctx->duped = 0;
> 1106     }
> 1107     inode_unlock(inode);
> 1108     return offset;
> 1109 }
> 

Yes, it depends on the patch "[PATCH 1/2] NFS: Remove unnecessary inode locking in nfs_llseek_dir()” that I sent out to the list on Oct 30.
I can include that in future updates of this patchset.
David Wysochanski Nov. 4, 2020, 9:40 p.m. UTC | #3
On Wed, Nov 4, 2020 at 4:32 PM Trond Myklebust <trondmy@hammerspace.com> wrote:
>
>
>
> > On Nov 4, 2020, at 16:01, David Wysochanski <dwysocha@redhat.com> wrote:
> >
> > On Wed, Nov 4, 2020 at 11:28 AM <trondmy@gmail.com> wrote:
> >>
> >> From: Trond Myklebust <trond.myklebust@hammerspace.com>
> >>
> >> If the server insists on using the readdir verifiers in order to allow
> >> cookies to expire, then we should ensure that we cache the verifier
> >> with the cookie, so that we can return an error if the application
> >> tries to use the expired cookie.
> >>
> >> Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
> >> ---
> >> fs/nfs/dir.c           | 35 +++++++++++++++++++++++------------
> >> fs/nfs/inode.c         |  7 -------
> >> include/linux/nfs_fs.h |  8 +++++++-
> >> 3 files changed, 30 insertions(+), 20 deletions(-)
> >>
> >> diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
> >> index 3b44bef3a1b4..454377228167 100644
> >> --- a/fs/nfs/dir.c
> >> +++ b/fs/nfs/dir.c
> >> @@ -155,6 +155,7 @@ struct nfs_readdir_descriptor {
> >>        loff_t          current_index;
> >>        loff_t          prev_index;
> >>
> >> +       __be32          verf[NFS_DIR_VERIFIER_SIZE];
> >>        unsigned long   dir_verifier;
> >>        unsigned long   timestamp;
> >>        unsigned long   gencount;
> >> @@ -466,15 +467,15 @@ static int nfs_readdir_search_array(struct nfs_readdir_descriptor *desc)
> >>
> >> /* Fill a page with xdr information before transferring to the cache page */
> >> static int nfs_readdir_xdr_filler(struct nfs_readdir_descriptor *desc,
> >> -                                 u64 cookie, struct page **pages,
> >> -                                 size_t bufsize)
> >> +                                 __be32 *verf, u64 cookie,
> >> +                                 struct page **pages, size_t bufsize,
> >> +                                 __be32 *verf_res)
> >> {
> >>        struct inode *inode = file_inode(desc->file);
> >> -       __be32 verf_res[2];
> >>        struct nfs_readdir_arg arg = {
> >>                .dentry = file_dentry(desc->file),
> >>                .cred = desc->file->f_cred,
> >> -               .verf = NFS_I(inode)->cookieverf,
> >> +               .verf = verf,
> >>                .cookie = cookie,
> >>                .pages = pages,
> >>                .page_len = bufsize,
> >> @@ -503,8 +504,6 @@ static int nfs_readdir_xdr_filler(struct nfs_readdir_descriptor *desc,
> >>        }
> >>        desc->timestamp = timestamp;
> >>        desc->gencount = gencount;
> >> -       memcpy(NFS_I(inode)->cookieverf, res.verf,
> >> -              sizeof(NFS_I(inode)->cookieverf));
> >> error:
> >>        return error;
> >> }
> >> @@ -770,11 +769,13 @@ static struct page **nfs_readdir_alloc_pages(size_t npages)
> >> }
> >>
> >> static int nfs_readdir_xdr_to_array(struct nfs_readdir_descriptor *desc,
> >> -                                   struct page *page, struct inode *inode)
> >> +                                   struct page *page, __be32 *verf_arg,
> >> +                                   __be32 *verf_res)
> >> {
> >>        struct page **pages;
> >>        struct nfs_entry *entry;
> >>        size_t array_size;
> >> +       struct inode *inode = file_inode(desc->file);
> >>        size_t dtsize = NFS_SERVER(inode)->dtsize;
> >>        int status = -ENOMEM;
> >>
> >> @@ -801,8 +802,9 @@ static int nfs_readdir_xdr_to_array(struct nfs_readdir_descriptor *desc,
> >>
> >>        do {
> >>                unsigned int pglen;
> >> -               status = nfs_readdir_xdr_filler(desc, entry->cookie,
> >> -                                               pages, dtsize);
> >> +               status = nfs_readdir_xdr_filler(desc, verf_arg, entry->cookie,
> >> +                                               pages, dtsize,
> >> +                                               verf_res);
> >>                if (status < 0)
> >>                        break;
> >>
> >> @@ -854,13 +856,15 @@ static int find_and_lock_cache_page(struct nfs_readdir_descriptor *desc)
> >> {
> >>        struct inode *inode = file_inode(desc->file);
> >>        struct nfs_inode *nfsi = NFS_I(inode);
> >> +       __be32 verf[NFS_DIR_VERIFIER_SIZE];
> >>        int res;
> >>
> >>        desc->page = nfs_readdir_page_get_cached(desc);
> >>        if (!desc->page)
> >>                return -ENOMEM;
> >>        if (nfs_readdir_page_needs_filling(desc->page)) {
> >> -               res = nfs_readdir_xdr_to_array(desc, desc->page, inode);
> >> +               res = nfs_readdir_xdr_to_array(desc, desc->page,
> >> +                                              nfsi->cookieverf, verf);
> >>                if (res < 0) {
> >>                        nfs_readdir_page_unlock_and_put_cached(desc);
> >>                        if (res == -EBADCOOKIE || res == -ENOTSYNC) {
> >> @@ -870,6 +874,7 @@ static int find_and_lock_cache_page(struct nfs_readdir_descriptor *desc)
> >>                        }
> >>                        return res;
> >>                }
> >> +               memcpy(nfsi->cookieverf, verf, sizeof(nfsi->cookieverf));
> >>        }
> >>        res = nfs_readdir_search_array(desc);
> >>        if (res == 0) {
> >> @@ -902,6 +907,7 @@ static int readdir_search_pagecache(struct nfs_readdir_descriptor *desc)
> >> static void nfs_do_filldir(struct nfs_readdir_descriptor *desc)
> >> {
> >>        struct file     *file = desc->file;
> >> +       struct nfs_inode *nfsi = NFS_I(file_inode(file));
> >>        struct nfs_cache_array *array;
> >>        unsigned int i = 0;
> >>
> >> @@ -915,6 +921,7 @@ static void nfs_do_filldir(struct nfs_readdir_descriptor *desc)
> >>                        desc->eof = true;
> >>                        break;
> >>                }
> >> +               memcpy(desc->verf, nfsi->cookieverf, sizeof(desc->verf));
> >>                if (i < (array->size-1))
> >>                        desc->dir_cookie = array->array[i+1].cookie;
> >>                else
> >> @@ -949,8 +956,8 @@ static void nfs_do_filldir(struct nfs_readdir_descriptor *desc)
> >> static int uncached_readdir(struct nfs_readdir_descriptor *desc)
> >> {
> >>        struct page     *page = NULL;
> >> +       __be32          verf[NFS_DIR_VERIFIER_SIZE];
> >>        int             status;
> >> -       struct inode *inode = file_inode(desc->file);
> >>
> >>        dfprintk(DIRCACHE, "NFS: uncached_readdir() searching for cookie %Lu\n",
> >>                        (unsigned long long)desc->dir_cookie);
> >> @@ -967,7 +974,7 @@ static int uncached_readdir(struct nfs_readdir_descriptor *desc)
> >>        desc->duped = 0;
> >>
> >>        nfs_readdir_page_init_array(page, desc->dir_cookie);
> >> -       status = nfs_readdir_xdr_to_array(desc, page, inode);
> >> +       status = nfs_readdir_xdr_to_array(desc, page, desc->verf, verf);
> >>        if (status < 0)
> >>                goto out_release;
> >>
> >> @@ -1023,6 +1030,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
> >>        desc->dup_cookie = dir_ctx->dup_cookie;
> >>        desc->duped = dir_ctx->duped;
> >>        desc->attr_gencount = dir_ctx->attr_gencount;
> >> +       memcpy(desc->verf, dir_ctx->verf, sizeof(desc->verf));
> >>        spin_unlock(&file->f_lock);
> >>
> >>        do {
> >> @@ -1061,6 +1069,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
> >>        dir_ctx->dup_cookie = desc->dup_cookie;
> >>        dir_ctx->duped = desc->duped;
> >>        dir_ctx->attr_gencount = desc->attr_gencount;
> >> +       memcpy(dir_ctx->verf, desc->verf, sizeof(dir_ctx->verf));
> >>        spin_unlock(&file->f_lock);
> >>
> >>        kfree(desc);
> >> @@ -1101,6 +1110,8 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int whence)
> >>                        dir_ctx->dir_cookie = offset;
> >>                else
> >>                        dir_ctx->dir_cookie = 0;
> >> +               if (offset == 0)
> >> +                       memset(dir_ctx->verf, 0, sizeof(dir_ctx->verf));
> >>                dir_ctx->duped = 0;
> >>        }
> >>        spin_unlock(&filp->f_lock);
> >
> > Thanks for doing these patches!
> >
> > For some reason this patch does not apply but I get a problem at this hunk.
> > Is there a fixup or hunk or two missing from 01/17 ?
> > I'm starting at 3cea11cd5e3b (Linux 5.10-rc2).
> >
> > Problem looks like it's at the spin_unlock - here's what the hunk
> > looks like for me:
> > fs/nfs/dir.c
> > 1092         inode_lock(inode);
> > 1093         offset += filp->f_pos;
> > 1094         if (offset < 0) {
> > 1095             inode_unlock(inode);
> > 1096             return -EINVAL;
> > 1097         }
> > 1098     }
> > 1099     if (offset != filp->f_pos) {
> > 1100         filp->f_pos = offset;
> > 1101         if (nfs_readdir_use_cookie(filp))
> > 1102             dir_ctx->dir_cookie = offset;
> > 1103         else
> > 1104             dir_ctx->dir_cookie = 0;
> > 1105         dir_ctx->duped = 0;
> > 1106     }
> > 1107     inode_unlock(inode);
> > 1108     return offset;
> > 1109 }
> >
>
> Yes, it depends on the patch "[PATCH 1/2] NFS: Remove unnecessary inode locking in nfs_llseek_dir()” that I sent out to the list on Oct 30.
> I can include that in future updates of this patchset.
>

FWIW, the statement of the dependency is fine with me - I grabbed the
other two patches and now applies cleanly.
Thanks!
diff mbox series

Patch

diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 3b44bef3a1b4..454377228167 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -155,6 +155,7 @@  struct nfs_readdir_descriptor {
 	loff_t		current_index;
 	loff_t		prev_index;
 
+	__be32		verf[NFS_DIR_VERIFIER_SIZE];
 	unsigned long	dir_verifier;
 	unsigned long	timestamp;
 	unsigned long	gencount;
@@ -466,15 +467,15 @@  static int nfs_readdir_search_array(struct nfs_readdir_descriptor *desc)
 
 /* Fill a page with xdr information before transferring to the cache page */
 static int nfs_readdir_xdr_filler(struct nfs_readdir_descriptor *desc,
-				  u64 cookie, struct page **pages,
-				  size_t bufsize)
+				  __be32 *verf, u64 cookie,
+				  struct page **pages, size_t bufsize,
+				  __be32 *verf_res)
 {
 	struct inode *inode = file_inode(desc->file);
-	__be32 verf_res[2];
 	struct nfs_readdir_arg arg = {
 		.dentry = file_dentry(desc->file),
 		.cred = desc->file->f_cred,
-		.verf = NFS_I(inode)->cookieverf,
+		.verf = verf,
 		.cookie = cookie,
 		.pages = pages,
 		.page_len = bufsize,
@@ -503,8 +504,6 @@  static int nfs_readdir_xdr_filler(struct nfs_readdir_descriptor *desc,
 	}
 	desc->timestamp = timestamp;
 	desc->gencount = gencount;
-	memcpy(NFS_I(inode)->cookieverf, res.verf,
-	       sizeof(NFS_I(inode)->cookieverf));
 error:
 	return error;
 }
@@ -770,11 +769,13 @@  static struct page **nfs_readdir_alloc_pages(size_t npages)
 }
 
 static int nfs_readdir_xdr_to_array(struct nfs_readdir_descriptor *desc,
-				    struct page *page, struct inode *inode)
+				    struct page *page, __be32 *verf_arg,
+				    __be32 *verf_res)
 {
 	struct page **pages;
 	struct nfs_entry *entry;
 	size_t array_size;
+	struct inode *inode = file_inode(desc->file);
 	size_t dtsize = NFS_SERVER(inode)->dtsize;
 	int status = -ENOMEM;
 
@@ -801,8 +802,9 @@  static int nfs_readdir_xdr_to_array(struct nfs_readdir_descriptor *desc,
 
 	do {
 		unsigned int pglen;
-		status = nfs_readdir_xdr_filler(desc, entry->cookie,
-						pages, dtsize);
+		status = nfs_readdir_xdr_filler(desc, verf_arg, entry->cookie,
+						pages, dtsize,
+						verf_res);
 		if (status < 0)
 			break;
 
@@ -854,13 +856,15 @@  static int find_and_lock_cache_page(struct nfs_readdir_descriptor *desc)
 {
 	struct inode *inode = file_inode(desc->file);
 	struct nfs_inode *nfsi = NFS_I(inode);
+	__be32 verf[NFS_DIR_VERIFIER_SIZE];
 	int res;
 
 	desc->page = nfs_readdir_page_get_cached(desc);
 	if (!desc->page)
 		return -ENOMEM;
 	if (nfs_readdir_page_needs_filling(desc->page)) {
-		res = nfs_readdir_xdr_to_array(desc, desc->page, inode);
+		res = nfs_readdir_xdr_to_array(desc, desc->page,
+					       nfsi->cookieverf, verf);
 		if (res < 0) {
 			nfs_readdir_page_unlock_and_put_cached(desc);
 			if (res == -EBADCOOKIE || res == -ENOTSYNC) {
@@ -870,6 +874,7 @@  static int find_and_lock_cache_page(struct nfs_readdir_descriptor *desc)
 			}
 			return res;
 		}
+		memcpy(nfsi->cookieverf, verf, sizeof(nfsi->cookieverf));
 	}
 	res = nfs_readdir_search_array(desc);
 	if (res == 0) {
@@ -902,6 +907,7 @@  static int readdir_search_pagecache(struct nfs_readdir_descriptor *desc)
 static void nfs_do_filldir(struct nfs_readdir_descriptor *desc)
 {
 	struct file	*file = desc->file;
+	struct nfs_inode *nfsi = NFS_I(file_inode(file));
 	struct nfs_cache_array *array;
 	unsigned int i = 0;
 
@@ -915,6 +921,7 @@  static void nfs_do_filldir(struct nfs_readdir_descriptor *desc)
 			desc->eof = true;
 			break;
 		}
+		memcpy(desc->verf, nfsi->cookieverf, sizeof(desc->verf));
 		if (i < (array->size-1))
 			desc->dir_cookie = array->array[i+1].cookie;
 		else
@@ -949,8 +956,8 @@  static void nfs_do_filldir(struct nfs_readdir_descriptor *desc)
 static int uncached_readdir(struct nfs_readdir_descriptor *desc)
 {
 	struct page	*page = NULL;
+	__be32		verf[NFS_DIR_VERIFIER_SIZE];
 	int		status;
-	struct inode *inode = file_inode(desc->file);
 
 	dfprintk(DIRCACHE, "NFS: uncached_readdir() searching for cookie %Lu\n",
 			(unsigned long long)desc->dir_cookie);
@@ -967,7 +974,7 @@  static int uncached_readdir(struct nfs_readdir_descriptor *desc)
 	desc->duped = 0;
 
 	nfs_readdir_page_init_array(page, desc->dir_cookie);
-	status = nfs_readdir_xdr_to_array(desc, page, inode);
+	status = nfs_readdir_xdr_to_array(desc, page, desc->verf, verf);
 	if (status < 0)
 		goto out_release;
 
@@ -1023,6 +1030,7 @@  static int nfs_readdir(struct file *file, struct dir_context *ctx)
 	desc->dup_cookie = dir_ctx->dup_cookie;
 	desc->duped = dir_ctx->duped;
 	desc->attr_gencount = dir_ctx->attr_gencount;
+	memcpy(desc->verf, dir_ctx->verf, sizeof(desc->verf));
 	spin_unlock(&file->f_lock);
 
 	do {
@@ -1061,6 +1069,7 @@  static int nfs_readdir(struct file *file, struct dir_context *ctx)
 	dir_ctx->dup_cookie = desc->dup_cookie;
 	dir_ctx->duped = desc->duped;
 	dir_ctx->attr_gencount = desc->attr_gencount;
+	memcpy(dir_ctx->verf, desc->verf, sizeof(dir_ctx->verf));
 	spin_unlock(&file->f_lock);
 
 	kfree(desc);
@@ -1101,6 +1110,8 @@  static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int whence)
 			dir_ctx->dir_cookie = offset;
 		else
 			dir_ctx->dir_cookie = 0;
+		if (offset == 0)
+			memset(dir_ctx->verf, 0, sizeof(dir_ctx->verf));
 		dir_ctx->duped = 0;
 	}
 	spin_unlock(&filp->f_lock);
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index aa6493905bbe..9b765a900b28 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -229,7 +229,6 @@  static void nfs_zap_caches_locked(struct inode *inode)
 	nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
 	nfsi->attrtimeo_timestamp = jiffies;
 
-	memset(NFS_I(inode)->cookieverf, 0, sizeof(NFS_I(inode)->cookieverf));
 	if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) {
 		nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR
 					| NFS_INO_INVALID_DATA
@@ -1237,7 +1236,6 @@  EXPORT_SYMBOL_GPL(nfs_revalidate_inode);
 
 static int nfs_invalidate_mapping(struct inode *inode, struct address_space *mapping)
 {
-	struct nfs_inode *nfsi = NFS_I(inode);
 	int ret;
 
 	if (mapping->nrpages != 0) {
@@ -1250,11 +1248,6 @@  static int nfs_invalidate_mapping(struct inode *inode, struct address_space *map
 		if (ret < 0)
 			return ret;
 	}
-	if (S_ISDIR(inode->i_mode)) {
-		spin_lock(&inode->i_lock);
-		memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
-		spin_unlock(&inode->i_lock);
-	}
 	nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE);
 	nfs_fscache_wait_on_invalidate(inode);
 
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index dd6b463dda80..681ed98e4ba8 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -45,6 +45,11 @@ 
  */
 #define NFS_RPC_SWAPFLAGS		(RPC_TASK_SWAPPER|RPC_TASK_ROOTCREDS)
 
+/*
+ * Size of the NFS directory verifier
+ */
+#define NFS_DIR_VERIFIER_SIZE		2
+
 /*
  * NFSv3/v4 Access mode cache entry
  */
@@ -89,6 +94,7 @@  struct nfs_open_context {
 struct nfs_open_dir_context {
 	struct list_head list;
 	unsigned long attr_gencount;
+	__be32	verf[NFS_DIR_VERIFIER_SIZE];
 	__u64 dir_cookie;
 	__u64 dup_cookie;
 	signed char duped;
@@ -156,7 +162,7 @@  struct nfs_inode {
 	 * This is the cookie verifier used for NFSv3 readdir
 	 * operations
 	 */
-	__be32			cookieverf[2];
+	__be32			cookieverf[NFS_DIR_VERIFIER_SIZE];
 
 	atomic_long_t		nrequests;
 	struct nfs_mds_commit_info commit_info;