diff mbox series

generic/676: Unstable d_type handling for NFS READDIR

Message ID 42d3218724fbe3758005f984ad85934a50c33611.1675348307.git.bcodding@redhat.com (mailing list archive)
State New, archived
Headers show
Series generic/676: Unstable d_type handling for NFS READDIR | expand

Commit Message

Benjamin Coddington Feb. 2, 2023, 2:48 p.m. UTC
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@redhat.com>
---
 src/t_readdir_3.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

Comments

Zorro Lang Feb. 9, 2023, 2:54 p.m. UTC | #1
On Thu, Feb 02, 2023 at 09:48:04AM -0500, Benjamin Coddington wrote:
> 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@redhat.com>
> ---

OK, thanks for this fix from nfs side. I think it doesn't affect other fs
testing, then I'd like to merge it if it's helpful for nfs side. If anyone
has objection, please tell us.

Reviewed-by: Zorro Lang <zlang@redhat.com>

Thanks,
Zorro

>  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
>
diff mbox series

Patch

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,