[PATCH] generic/676: Unstable d_type handling for NFS READDIR

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



The NFS client may send READDIR or READDIRPLUS to populate the dentry
cache, and switch between them to optimize for least RPC calls based on the
process' behavior.  When using READDIR, dentries will have d_type =
DT_UNKNOWN but with READDIRPLUS d_type will be set from the mode.

This heuristic will cause generic/676 to fail when comparing dentries
cached from one or the other call, since we compare d_type directly. Fix
this by bypassing the comparison of d_type if any entry is loaded with
DT_UNKNOWN.

Signed-off-by: Benjamin Coddington <bcodding@xxxxxxxxxx>
---
 src/t_readdir_3.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/src/t_readdir_3.c b/src/t_readdir_3.c
index e5179ab27c51..8f9bb326dccb 100644
--- a/src/t_readdir_3.c
+++ b/src/t_readdir_3.c
@@ -27,6 +27,7 @@ struct linux_dirent64 {
 static DIR *dir;
 static int dfd;
 static int ignore_error;
+static int ignore_dtype = 0;
 
 struct dir_ops {
 	loff_t (*getpos)(void);
@@ -61,6 +62,10 @@ static void libc_getentry(struct dirent *entry)
 		exit(1);
 	}
 	memcpy(entry, ret, sizeof(struct dirent));
+
+	/* NFS may or may not set d_type, depending on READDIRPLUS */
+	if (!ignore_dtype && entry->d_type == DT_UNKNOWN)
+		ignore_dtype = 1;
 }
 
 static off64_t kernel_getpos(void)
@@ -95,6 +100,10 @@ static void kernel_getentry(struct dirent *entry)
 	entry->d_reclen = lentry->d_reclen;
 	entry->d_type = lentry->d_type;
 	strcpy(entry->d_name, lentry->d_name);
+
+	/* NFS may or may not set d_type, depending on READDIRPLUS */
+	if (!ignore_dtype && entry->d_type == DT_UNKNOWN)
+		ignore_dtype = 1;
 }
 
 struct dir_ops libc_ops = {
@@ -168,8 +177,9 @@ static void test(int count, struct dir_ops *ops)
 		pos = random() % count;
 		ops->setpos(pbuf[pos]);
 		ops->getentry(&entry);
+
 		if (dbuf[pos].d_ino != entry.d_ino ||
-		    dbuf[pos].d_type != entry.d_type ||
+		    (!ignore_dtype && dbuf[pos].d_type != entry.d_type) ||
 		    strcmp(dbuf[pos].d_name, entry.d_name)) {
 			fprintf(stderr,
 				"Mismatch in dir entry %u at pos %llu\n", pos,
-- 
2.31.1




[Index of Archives]     [Linux Filesystems Development]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux