Re: [EXTERNAL] [PATCH] NFS: Fix handling of cookie verifier in uncached_readdir()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, 2021-03-17 at 10:39 +0000, Nagendra Tomar wrote:
> Ignore this, we do need the inode cookieverifier for the cached
> cookies in the absence
> of any open dir handle. I was clearly overthinking!
> 

Right. When we're caching cookies, then we should also cache the
verifier that is needed to use them. That's why we cache in both the
inode and in the directory context.

> I've a question on your patch:
> If the server changes the cookieverifier for a directory, shouldn't
> we zap the
> cached directory pages since the cached cookies do not correspond to
> this new cookie
> verifier for this directory? Or, do we depend on the server to return
> BADCOOKIE when we
> present a bad cookieverifier+cookie combo, and then we invalidate. I
> guess that's fine too.
> 

When the server changes the verifier it will start replying to requests
that use the older verifier with NFS4ERR_NOT_SAME (NFSv4), which we
convert into ENOTSYNC, or NFS3ERR_BAD_COOKIE (NFSv3), which we convert
into EBADCOOKIE.
Both errors are handled in the generic readdir code.

> Also my earlier comment about find_and_lock_cache_page() accessing
> nfsi->cookieverf
> w/o locking the inode. This one is not introduced by your current
> patch.

Yes. I'm aware of that issue. We can just add a check for desc-
>page_index == 0. Nothing should be changing the verifier unless the
cache is empty.

> 
> Thanks,
> Tomar 
> 
> -----Original Message-----
> From: Nagendra Tomar 
> Sent: 17 March 2021 14:59
> To: trondmy@xxxxxxxxxx
> Cc: linux-nfs@xxxxxxxxxxxxxxx
> Subject: RE: [EXTERNAL] [PATCH] NFS: Fix handling of cookie verifier
> in uncached_readdir()
> 
> Hi Trond,
>      I think it'll be better to remove cookieverifier from nfs_inode,
> as truly speaking
> it doesn't belong there. A cookie verifier (along with the cookie) is
> part of a readdir
> context, and context is per open dir instance and not per file.
> Ideally we should have
> the following sequence
> 
> 1. Application opens directory, nfs_open_dir_context->verf is set to
> 0.
>     nfs_open_dir_context->verf is used to populate
> nfs_readdir_descriptor->verf, which is our cursor.
> 2. The first readdir call using the above newly opened handle carries
> the 0 cookie verifier (with cookie==0).
> 3. A cookie verifier received as  a response of #2 is saved in
> nfs_readdir_descriptor->verf, which
>     is later saved in nfs_open_dir_context->verf. Thus subsequent
> readdir calls carry the cookie
>     verifier (and cookie) returned by the server.
> 
> What do you think about this patch?
> It includes the patch that I sent y'day so only this should be
> enough.
> 
> PS: Currently find_and_lock_cache_page() seems to be accessing
> nfs_inode->cookieverifier
>        w/o locking the inode.
> 
> Signed-off-by: Nagendra S Tomar <natomar@xxxxxxxxxxxxx>
> ---
> diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
> index fc4f490f2d78..a52917800e37 100644
> --- a/fs/nfs/dir.c
> +++ b/fs/nfs/dir.c
> @@ -76,6 +76,7 @@ static struct nfs_open_dir_context
> *alloc_nfs_open_dir_context(struct inode *dir
>         if (ctx != NULL) {
>                 ctx->duped = 0;
>                 ctx->attr_gencount = nfsi->attr_gencount;
> +               memset(ctx->verf, 0, sizeof(ctx->verf));
>                 ctx->dir_cookie = 0;
>                 ctx->dup_cookie = 0;
>                 spin_lock(&dir->i_lock);
> @@ -820,7 +821,6 @@ static struct page
> **nfs_readdir_alloc_pages(size_t npages)
>  }
>  
>  static int nfs_readdir_xdr_to_array(struct nfs_readdir_descriptor
> *desc,
> -                                   __be32 *verf_arg, __be32
> *verf_res,
>                                     struct page **arrays, size_t
> narrays)
>  {
>         struct page **pages;
> @@ -829,6 +829,7 @@ static int nfs_readdir_xdr_to_array(struct
> nfs_readdir_descriptor *desc,
>         size_t array_size;
>         struct inode *inode = file_inode(desc->file);
>         size_t dtsize = NFS_SERVER(inode)->dtsize;
> +       __be32 verf[NFS_DIR_VERIFIER_SIZE];
>         int status = -ENOMEM;
>  
>         entry = kzalloc(sizeof(*entry), GFP_KERNEL);
> @@ -854,9 +855,9 @@ static int nfs_readdir_xdr_to_array(struct
> nfs_readdir_descriptor *desc,
>  
>         do {
>                 unsigned int pglen;
> -               status = nfs_readdir_xdr_filler(desc, verf_arg,
> entry->cookie,
> +               status = nfs_readdir_xdr_filler(desc, desc->verf,
> entry->cookie,
>                                                 pages, dtsize,
> -                                               verf_res);
> +                                               verf);
>                 if (status < 0)
>                         break;
>  
> @@ -866,6 +867,8 @@ static int nfs_readdir_xdr_to_array(struct
> nfs_readdir_descriptor *desc,
>                         break;
>                 }
>  
> +               memcpy(desc->verf, verf, sizeof(desc->verf));
> +
>                 status = nfs_readdir_page_filler(desc, entry, pages,
> pglen,
>                                                  arrays, narrays);
>         } while (!status && nfs_readdir_page_needs_filling(page));
> @@ -909,15 +912,13 @@ 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, nfsi-
> >cookieverf, verf,
> -                                              &desc->page, 1);
> +               res = nfs_readdir_xdr_to_array(desc, &desc->page, 1);
>                 if (res < 0) {
>                         nfs_readdir_page_unlock_and_put_cached(desc);
>                         if (res == -EBADCOOKIE || res == -ENOTSYNC) {
> @@ -927,7 +928,6 @@ 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) {
> @@ -977,7 +977,6 @@ 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;
>  
> @@ -991,7 +990,6 @@ 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
> @@ -1027,7 +1025,6 @@ static int uncached_readdir(struct
> nfs_readdir_descriptor *desc)
>  {
>         struct page     **arrays;
>         size_t          i, sz = 512;
> -       __be32          verf[NFS_DIR_VERIFIER_SIZE];
>         int             status = -ENOMEM;
>  
>         dfprintk(DIRCACHE, "NFS: uncached_readdir() searching for
> cookie %llu\n",
> @@ -1044,7 +1041,7 @@ static int uncached_readdir(struct
> nfs_readdir_descriptor *desc)
>         desc->last_cookie = desc->dir_cookie;
>         desc->duped = 0;
>  
> -       status = nfs_readdir_xdr_to_array(desc, desc->verf, verf,
> arrays, sz);
> +       status = nfs_readdir_xdr_to_array(desc, arrays, sz);
>  
>         for (i = 0; !desc->eof && i < sz && arrays[i]; i++) {
>                 desc->page = arrays[i];
> diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
> index a7fb076a5f44..ab3e666ed097 100644
> --- a/fs/nfs/inode.c
> +++ b/fs/nfs/inode.c
> @@ -522,7 +522,6 @@ nfs_fhget(struct super_block *sb, struct nfs_fh
> *fh, struct nfs_fattr *fattr, st
>                 inode->i_uid = make_kuid(&init_user_ns, -2);
>                 inode->i_gid = make_kgid(&init_user_ns, -2);
>                 inode->i_blocks = 0;
> -               memset(nfsi->cookieverf, 0, sizeof(nfsi-
> >cookieverf));
>                 nfsi->write_io = 0;
>                 nfsi->read_io = 0;
>  
> diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
> index eadaabd18dc7..752de9e43e36 100644
> --- a/include/linux/nfs_fs.h
> +++ b/include/linux/nfs_fs.h
> @@ -158,12 +158,6 @@ struct nfs_inode {
>         struct list_head        access_cache_entry_lru;
>         struct list_head        access_cache_inode_lru;
>  
> -       /*
> -        * This is the cookie verifier used for NFSv3 readdir
> -        * operations
> -        */
> -       __be32                  cookieverf[NFS_DIR_VERIFIER_SIZE];
> -
>         atomic_long_t           nrequests;
>         struct nfs_mds_commit_info commit_info;
> 
> 
> -----Original Message-----
> From: trondmy@xxxxxxxxxx <trondmy@xxxxxxxxxx> 
> Sent: 16 March 2021 19:06
> To: Nagendra Tomar <Nagendra.Tomar@xxxxxxxxxxxxx>
> Cc: linux-nfs@xxxxxxxxxxxxxxx
> Subject: [EXTERNAL] [PATCH] NFS: Fix handling of cookie verifier in
> uncached_readdir()
> 
> From: Trond Myklebust <trond.myklebust@xxxxxxxxxxxxxxx>
> 
> If we're doing uncached readdir(), then the readdir cookie could be
> different from the one cached in the nfs_inode. We should therefore
> ensure that we save that one in the struct nfs_open_dir_context.
> 
> Fixes: 35df59d3ef69 ("NFS: Reduce number of RPC calls when doing
> uncached readdir")
> Signed-off-by: Trond Myklebust <trond.myklebust@xxxxxxxxxxxxxxx>
> ---
>  fs/nfs/dir.c | 13 +++++++------
>  1 file changed, 7 insertions(+), 6 deletions(-)
> 
> diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
> index 08a1e2e31d0b..2cf2a7d92faf 100644
> --- a/fs/nfs/dir.c
> +++ b/fs/nfs/dir.c
> @@ -976,10 +976,10 @@ static int readdir_search_pagecache(struct
> nfs_readdir_descriptor *desc)
>  /*
>   * Once we've found the start of the dirent within a page: fill 'er
> up...
>   */
> -static void nfs_do_filldir(struct nfs_readdir_descriptor *desc)
> +static void nfs_do_filldir(struct nfs_readdir_descriptor *desc,
> +                          const __be32 *verf)
>  {
>         struct file     *file = desc->file;
> -       struct nfs_inode *nfsi = NFS_I(file_inode(file));
>         struct nfs_cache_array *array;
>         unsigned int i = 0;
>  
> @@ -993,7 +993,7 @@ static void nfs_do_filldir(struct
> nfs_readdir_descriptor *desc)
>                         desc->eof = true;
>                         break;
>                 }
> -               memcpy(desc->verf, nfsi->cookieverf, sizeof(desc-
> >verf));
> +               memcpy(desc->verf, verf, sizeof(desc->verf));
>                 if (i < (array->size-1))
>                         desc->dir_cookie = array->array[i+1].cookie;
>                 else
> @@ -1050,7 +1050,7 @@ static int uncached_readdir(struct
> nfs_readdir_descriptor *desc)
>  
>         for (i = 0; !desc->eof && i < sz && arrays[i]; i++) {
>                 desc->page = arrays[i];
> -               nfs_do_filldir(desc);
> +               nfs_do_filldir(desc, verf);
>         }
>         desc->page = NULL;
>  
> @@ -1071,6 +1071,7 @@ static int nfs_readdir(struct file *file,
> struct dir_context *ctx)
>  {
>         struct dentry   *dentry = file_dentry(file);
>         struct inode    *inode = d_inode(dentry);
> +       struct nfs_inode *nfsi = NFS_I(inode);
>         struct nfs_open_dir_context *dir_ctx = file->private_data;
>         struct nfs_readdir_descriptor *desc;
>         int res;
> @@ -1124,7 +1125,7 @@ static int nfs_readdir(struct file *file,
> struct dir_context *ctx)
>                         break;
>                 }
>                 if (res == -ETOOSMALL && desc->plus) {
> -                       clear_bit(NFS_INO_ADVISE_RDPLUS,
> &NFS_I(inode)->flags);
> +                       clear_bit(NFS_INO_ADVISE_RDPLUS, &nfsi-
> >flags);
>                         nfs_zap_caches(inode);
>                         desc->page_index = 0;
>                         desc->plus = false;
> @@ -1134,7 +1135,7 @@ static int nfs_readdir(struct file *file,
> struct dir_context *ctx)
>                 if (res < 0)
>                         break;
>  
> -               nfs_do_filldir(desc);
> +               nfs_do_filldir(desc, nfsi->cookieverf);
>                 nfs_readdir_page_unlock_and_put_cached(desc);
>         } while (!desc->eof);
>  

-- 
Trond Myklebust
Linux NFS client maintainer, Hammerspace
trond.myklebust@xxxxxxxxxxxxxxx






[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux