This is the mail archive of the
libc-alpha@sources.redhat.com
mailing list for the glibc project.
[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