NeilBrown 5ca83d
From: Trond Myklebust <trond.myklebust@hammerspace.com>
NeilBrown 5ca83d
Date: Fri, 6 Nov 2020 20:47:05 -0500
NeilBrown 5ca83d
Subject: [PATCH] NFS: Do uncached readdir when we're seeking a cookie in an
NeilBrown 5ca83d
 empty page cache
NeilBrown 5ca83d
Git-commit: 794092c57f89c2c833da00f82f38a0afcb4033bc
Michal Kubecek b7dfcc
Patch-mainline: v5.11-rc1
NeilBrown ee8ec2
References: bsc#1191628 bsc#1192549
NeilBrown 5ca83d
NeilBrown 5ca83d
If the directory is changing, causing the page cache to get invalidated
NeilBrown 5ca83d
while we are listing the contents, then the NFS client is currently forced
NeilBrown 5ca83d
to read in the entire directory contents from scratch, because it needs
NeilBrown 5ca83d
to perform a linear search for the readdir cookie. While this is not
NeilBrown 5ca83d
an issue for small directories, it does not scale to directories with
NeilBrown 5ca83d
millions of entries.
NeilBrown 5ca83d
In order to be able to deal with large directories that are changing,
NeilBrown 5ca83d
add a heuristic to ensure that if the page cache is empty, and we are
NeilBrown 5ca83d
searching for a cookie that is not the zero cookie, we just default to
NeilBrown 5ca83d
performing uncached readdir.
NeilBrown 5ca83d
NeilBrown 5ca83d
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
NeilBrown 5ca83d
Reviewed-by: Benjamin Coddington <bcodding@redhat.com>
NeilBrown 5ca83d
Tested-by: Benjamin Coddington <bcodding@redhat.com>
NeilBrown 5ca83d
Tested-by: Dave Wysochanski <dwysocha@redhat.com>
NeilBrown 5ca83d
Acked-by: NeilBrown <neilb@suse.com>
NeilBrown 5ca83d
NeilBrown 5ca83d
---
NeilBrown 5ca83d
 fs/nfs/dir.c |   17 +++++++++++++++++
NeilBrown 5ca83d
 1 file changed, 17 insertions(+)
NeilBrown 5ca83d
NeilBrown 5ca83d
--- a/fs/nfs/dir.c
NeilBrown 5ca83d
+++ b/fs/nfs/dir.c
NeilBrown 5ca83d
@@ -743,12 +743,29 @@ error:
NeilBrown 5ca83d
 	return res;
NeilBrown 5ca83d
 }
NeilBrown 5ca83d
 
NeilBrown 5ca83d
+static bool nfs_readdir_dont_search_cache(nfs_readdir_descriptor_t *desc)
NeilBrown 5ca83d
+{
NeilBrown 5ca83d
+	struct address_space *mapping = desc->file->f_mapping;
NeilBrown 5ca83d
+	struct inode *dir = file_inode(desc->file);
NeilBrown 5ca83d
+	unsigned int dtsize = NFS_SERVER(dir)->dtsize;
NeilBrown 5ca83d
+	loff_t size = i_size_read(dir);
NeilBrown 5ca83d
+
NeilBrown 5ca83d
+	/*
NeilBrown 5ca83d
+	 * Default to uncached readdir if the page cache is empty, and
NeilBrown 5ca83d
+	 * we're looking for a non-zero cookie in a large directory.
NeilBrown 5ca83d
+	 */
NeilBrown ee8ec2
+	return *desc->dir_cookie != 0 && mapping->nrpages == 0 && size > dtsize;
NeilBrown 5ca83d
+}
NeilBrown 5ca83d
+
NeilBrown 5ca83d
 /* Search for desc->dir_cookie from the beginning of the page cache */
NeilBrown 5ca83d
 static inline
NeilBrown 5ca83d
 int readdir_search_pagecache(nfs_readdir_descriptor_t *desc)
NeilBrown 5ca83d
 {
NeilBrown 5ca83d
 	int res;
NeilBrown 5ca83d
 
NeilBrown 5ca83d
+	if (nfs_readdir_dont_search_cache(desc))
NeilBrown 5ca83d
+		return -EBADCOOKIE;
NeilBrown 5ca83d
+
NeilBrown 5ca83d
 	if (desc->page_index == 0) {
NeilBrown 5ca83d
 		desc->current_index = 0;
NeilBrown 5ca83d
 		desc->last_cookie = 0;