This is the mail archive of the libc-alpha@sources.redhat.com mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[PATCH] for glibc-2.2 getdents code


On Mon, Feb 19, 2001 at 04:45:34PM +0100, Trond Myklebust wrote:
> >>>>> " " == H J Lu <hjl@valinux.com> writes:
> 
>      > I couldn't reproduce it. I got
> 
>      > getdents64(3, {{d_ino=2, d_off=18446744071562067980,
>      > d_reclen=24, d_type=0, d_name="."} {d_ino=2,
>      > d_off=18446744071562067992, d_reclen=24, d_type=0, d_name=".."} 
>      > {d_ino=11, d_off=18446744071562068012, d_reclen=32, d_type=0,
>      > d_name="lost+found"} {d_ino=32705, d_off=18446744071562068028,
>      > d_reclen=32, d_type=0, d_name="build"} {d_ino=98428,
>      > d_off=4096, d_reclen=32, d_type=0, d_name="release"}}, 16384) =
>      > 144
> 
>      > Anyway, everything works fine for me.
> 
> 
> Apply the appended patch to a stock 2.4.1 kernel on the knfsd server
> (the patch merely causes the last cookie of the directory to be set to
> 0xFFFFFFFF). Then try the following program on the NFS client:
> 
> #include <unistd.h>
> #include <dirent.h>
> #include <errno.h>
> 
> int main()
> {
>         DIR *dir;
>         struct dirent *dirent;
> 
>         errno = 0;
>         dir = opendir(".");
>         while ((dirent = readdir(dir)) != NULL)
>                 printf("%s\n",dirent->d_name);
>         if (errno != 0)
>                 perror("Dirent error!");
>         closedir(dir);
> }
> 
> 
> On an NFS mounted directory with 3 entries ('.','..', and
> 'kernel-2.4.0") and stock glibc-2.2 this gives me:
> 
> getdents64(3, {{d_ino=2163019, d_off=12, d_reclen=24, d_type=0, d_name="."} {d_ino=2179509, d_off=24, d_reclen=24, d_type=0, d_name=".."} {d_ino=1934168, d_off=4294967295, d_reclen=32, d_type=0, d_name="kernel-2.4.0"}}, 8192) = 80
> lseek(3, 24, SEEK_SET)                  = 24
> write(1, ".\n", 2.
> )                      = 2
> write(1, "..\n", 3..
> )                     = 3
> getdents64(3, {{d_ino=1934168, d_off=4294967295, d_reclen=32, d_type=0, d_name="kernel-2.4.0"}}, 8192) = 32
> write(2, "Dirent error!: Value too large f"..., 53Dirent error!: Value too large for defined data type
> 
> 
> Cheers,
>   Trond
> 
> 
> 
> --- linux-2.4.1/fs/nfsd/vfs.c	Fri Dec 29 23:07:23 2000
> +++ linux-2.4.1-fakedir/fs/nfsd/vfs.c	Mon Feb 19 16:04:27 2001
> @@ -1441,10 +1441,11 @@
>  	eof = !cd.eob;
>  
>  	if (cd.offset) {
> +		u32 offset = 0xFFFFFFFFUL;
>  		if (rqstp->rq_vers == 3)
> -			(void)xdr_encode_hyper(cd.offset, file.f_pos);
> +			(void)xdr_encode_hyper(cd.offset, (u64)offset);
>  		else
> -			*cd.offset = htonl(file.f_pos);
> +			*cd.offset = htonl(offset);
>  	}
>  
>  	p = cd.buffer;
> 

Thanks for your testcase. But I believe your proposed patch is
incorrect. It won't work with telldir/seekdir. I think the glibc
bug is to use the getdents64 system call to implement getdents ()
on a 32bit system. It doesn't make any senses since getdents () is
a 32bit interface on a 32bit system.  Here is a patch.



-- 
H.J. Lu (hjl@valinux.com)
--
2001-02-20  H.J. Lu  <hjl@gnu.org>

	* sysdeps/unix/sysv/linux/getdents.c: Use the getdents64 system
	call only if __GETDENTS or DO_GETDENTS64_SYSCALL is defined
	* sysdeps/unix/sysv/linux/alpha/getdents.c: Define
	DO_GETDENTS64_SYSCALL.
	* sysdeps/unix/sysv/linux/ia64/getdents.c: Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc64/getdents.c: Likewise.

Index: sysdeps/unix/sysv/linux/getdents.c
===================================================================
RCS file: /work/cvs/gnu/glibc/sysdeps/unix/sysv/linux/getdents.c,v
retrieving revision 1.1.1.6
diff -u -p -r1.1.1.6 getdents.c
--- sysdeps/unix/sysv/linux/getdents.c	2001/02/13 19:16:21	1.1.1.6
+++ sysdeps/unix/sysv/linux/getdents.c	2001/02/21 00:22:52
@@ -42,6 +42,10 @@
 int __have_no_getdents64;
 #else
 extern int __have_no_getdents64;
+/* The d_off overflow may happen when using the getdents64 system call
+   for getdents () on a 32bit system. We should only try the getdents64
+   system call for getdents64 () or getdents64 == getdents.  */
+# define DO_GETDENTS64_SYSCALL
 #endif
 #endif
 #endif
@@ -101,7 +105,7 @@ __GETDENTS (int fd, char *buf, size_t nb
   off64_t last_offset = -1;
   ssize_t retval;
 
-#ifdef __NR_getdents64
+#if defined __NR_getdents64 && defined DO_GETDENTS64_SYSCALL
 # ifndef __ASSUME_GETDENTS64_SYSCALL
   if (!__have_no_getdents64)
 # endif
Index: sysdeps/unix/sysv/linux/alpha/getdents.c
===================================================================
RCS file: /work/cvs/gnu/glibc/sysdeps/unix/sysv/linux/alpha/getdents.c,v
retrieving revision 1.1.1.2
diff -u -p -r1.1.1.2 getdents.c
--- sysdeps/unix/sysv/linux/alpha/getdents.c	2000/08/21 05:13:09	1.1.1.2
+++ sysdeps/unix/sysv/linux/alpha/getdents.c	2001/02/21 00:22:22
@@ -1,3 +1,4 @@
+#define DO_GETDENTS64_SYSCALL
 #define DIRENT_SET_DP_INO(dp, value) \
   do { (dp)->d_ino = (value); (dp)->__pad = 0; } while (0)
 #include <sysdeps/unix/sysv/linux/getdents.c>
Index: sysdeps/unix/sysv/linux/ia64/getdents.c
===================================================================
RCS file: /work/cvs/gnu/glibc/sysdeps/unix/sysv/linux/ia64/getdents.c,v
retrieving revision 1.1.1.1
diff -u -p -r1.1.1.1 getdents.c
--- sysdeps/unix/sysv/linux/ia64/getdents.c	2000/08/16 00:58:58	1.1.1.1
+++ sysdeps/unix/sysv/linux/ia64/getdents.c	2001/02/21 00:22:28
@@ -1,3 +1,4 @@
+#define DO_GETDENTS64_SYSCALL
 #define __getdents64 __no___getdents64_decl
 #include <sysdeps/unix/sysv/linux/getdents.c>
 #undef __getdents64
Index: sysdeps/unix/sysv/linux/sparc/sparc64/getdents.c
===================================================================
RCS file: /work/cvs/gnu/glibc/sysdeps/unix/sysv/linux/sparc/sparc64/getdents.c,v
retrieving revision 1.1.1.1
diff -u -p -r1.1.1.1 getdents.c
--- sysdeps/unix/sysv/linux/sparc/sparc64/getdents.c	2000/08/16 00:59:16	1.1.1.1
+++ sysdeps/unix/sysv/linux/sparc/sparc64/getdents.c	2001/02/21 00:22:49
@@ -1,3 +1,4 @@
+#define DO_GETDENTS64_SYSCALL
 #define __getdents64 __no___getdents64_decl
 #include <sysdeps/unix/sysv/linux/getdents.c>
 #undef __getdents64


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]