NFS: Optimisations for monotonically increasing readdir cookies
authorTrond Myklebust <trond.myklebust@hammerspace.com>
Wed, 4 Nov 2020 13:32:19 +0000 (08:32 -0500)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Wed, 2 Dec 2020 19:05:52 +0000 (14:05 -0500)
If the server is handing out monotonically increasing readdir cookie values,
then we can optimise away searches through pages that contain cookies that
lie outside our search range.

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

index 4543772..b6c3501 100644 (file)
@@ -140,7 +140,8 @@ struct nfs_cache_array {
        u64 last_cookie;
        unsigned int size;
        unsigned char page_full : 1,
-                     page_is_eof : 1;
+                     page_is_eof : 1,
+                     cookies_are_ordered : 1;
        struct nfs_cache_array_entry array[];
 };
 
@@ -178,6 +179,7 @@ static void nfs_readdir_page_init_array(struct page *page, u64 last_cookie)
        array = kmap_atomic(page);
        nfs_readdir_array_init(array);
        array->last_cookie = last_cookie;
+       array->cookies_are_ordered = 1;
        kunmap_atomic(array);
 }
 
@@ -269,6 +271,8 @@ int nfs_readdir_add_to_array(struct nfs_entry *entry, struct page *page)
        cache_entry->name_len = entry->len;
        cache_entry->name = name;
        array->last_cookie = entry->cookie;
+       if (array->last_cookie <= cache_entry->cookie)
+               array->cookies_are_ordered = 0;
        array->size++;
        if (entry->eof != 0)
                nfs_readdir_array_set_eof(array);
@@ -395,6 +399,19 @@ nfs_readdir_inode_mapping_valid(struct nfs_inode *nfsi)
        return !test_bit(NFS_INO_INVALIDATING, &nfsi->flags);
 }
 
+static bool nfs_readdir_array_cookie_in_range(struct nfs_cache_array *array,
+                                             u64 cookie)
+{
+       if (!array->cookies_are_ordered)
+               return true;
+       /* Optimisation for monotonically increasing cookies */
+       if (cookie >= array->last_cookie)
+               return false;
+       if (array->size && cookie < array->array[0].cookie)
+               return false;
+       return true;
+}
+
 static int nfs_readdir_search_for_cookie(struct nfs_cache_array *array,
                                         struct nfs_readdir_descriptor *desc)
 {
@@ -402,6 +419,9 @@ static int nfs_readdir_search_for_cookie(struct nfs_cache_array *array,
        loff_t new_pos;
        int status = -EAGAIN;
 
+       if (!nfs_readdir_array_cookie_in_range(array, desc->dir_cookie))
+               goto check_eof;
+
        for (i = 0; i < array->size; i++) {
                if (array->array[i].cookie == desc->dir_cookie) {
                        struct nfs_inode *nfsi = NFS_I(file_inode(desc->file));
@@ -435,6 +455,7 @@ static int nfs_readdir_search_for_cookie(struct nfs_cache_array *array,
                        return 0;
                }
        }
+check_eof:
        if (array->page_is_eof) {
                status = -EBADCOOKIE;
                if (desc->dir_cookie == array->last_cookie)