NFS: Handle NFS4ERR_NOT_SAME and NFSERR_BADCOOKIE from readdir calls
authorTrond Myklebust <trond.myklebust@hammerspace.com>
Tue, 3 Nov 2020 01:11:32 +0000 (20:11 -0500)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Wed, 2 Dec 2020 19:05:52 +0000 (14:05 -0500)
If the server returns NFS4ERR_NOT_SAME or tells us that the cookie is
bad in response to a READDIR call, then we should empty the page cache
so that we can fill it from scratch again.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Reviewed-by: Benjamin Coddington <bcodding@redhat.com>
Tested-by: Benjamin Coddington <bcodding@redhat.com>
Tested-by: Dave Wysochanski <dwysocha@redhat.com>
fs/nfs/dir.c
fs/nfs/nfs4proc.c

index 3ee0668a971921901184aa344305f6d743e24c59..3b44bef3a1b44676ef1b0e1278cac8a10e9bab6c 100644 (file)
@@ -861,15 +861,21 @@ static int find_and_lock_cache_page(struct nfs_readdir_descriptor *desc)
                return -ENOMEM;
        if (nfs_readdir_page_needs_filling(desc->page)) {
                res = nfs_readdir_xdr_to_array(desc, desc->page, inode);
-               if (res < 0)
-                       goto error;
+               if (res < 0) {
+                       nfs_readdir_page_unlock_and_put_cached(desc);
+                       if (res == -EBADCOOKIE || res == -ENOTSYNC) {
+                               invalidate_inode_pages2(desc->file->f_mapping);
+                               desc->page_index = 0;
+                               return -EAGAIN;
+                       }
+                       return res;
+               }
        }
        res = nfs_readdir_search_array(desc);
        if (res == 0) {
                nfsi->page_index = desc->page_index;
                return 0;
        }
-error:
        nfs_readdir_page_unlock_and_put_cached(desc);
        return res;
 }
@@ -879,12 +885,12 @@ static int readdir_search_pagecache(struct nfs_readdir_descriptor *desc)
 {
        int res;
 
-       if (desc->page_index == 0) {
-               desc->current_index = 0;
-               desc->prev_index = 0;
-               desc->last_cookie = 0;
-       }
        do {
+               if (desc->page_index == 0) {
+                       desc->current_index = 0;
+                       desc->prev_index = 0;
+                       desc->last_cookie = 0;
+               }
                res = find_and_lock_cache_page(desc);
        } while (res == -EAGAIN);
        return res;
@@ -1030,6 +1036,8 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
                                res = uncached_readdir(desc);
                                if (res == 0)
                                        continue;
+                               if (res == -EBADCOOKIE || res == -ENOTSYNC)
+                                       res = 0;
                        }
                        break;
                }
index adcaba68eaeda8242fc73bfde229a15a019574ee..7ab40d0e6a74ca9a5254e6f80bc33568490e8ead 100644 (file)
@@ -184,6 +184,8 @@ static int nfs4_map_errors(int err)
                return -EPROTONOSUPPORT;
        case -NFS4ERR_FILE_OPEN:
                return -EBUSY;
+       case -NFS4ERR_NOT_SAME:
+               return -ENOTSYNC;
        default:
                dprintk("%s could not handle NFSv4 error %d\n",
                                __func__, -err);