re: the getdents/lseek discussion.
> Well, the -retval SEEK_CUR is completely broken. The rest looks right:
> kdp->d_off is computed by the kernel and should remain a valid seek
> point after the syscall returns.
We've run into a different problem in the same routine...
When running a 2.3.99-pre2 kernel as a client using a NFS server
exporting a 64-bit file system, we can get a directory offset
cookie back across the wire that uses all 32 bits of the d_off
field, that, combined with the more efficient readdir routines
in 2.3.99 NFS causes us to get into the 'failed heuristic' code
in getdents and lose some dentries.
Since the SEEK_SET lseek in the getdents64 case is still an lseek,
not an lseek64, combined with d_off being signed, the lseek( , , SEEK_SET)
can also fail, discarding some un-processed dentries.
In this particular case the server is an Irix 6.5 system exporting
a 50Gb XFS file system, using the "32bit-clients" exports option.
I believe the NFS protocol allows more than 32 bits for the directory
offset cookie, but know from snooping the packets that we didn't see
more than 32 bits, but do indeed eventually use all 32 bits, resulting
in what "looks like" a negative offset.
We have a patch that "fixes" this that I'm not too happy with, wishing
there was a "better" way than kludging an unsigned assignment of d_off
into last offset...
Here's what we did...
--- glibc-2.1.3/sysdeps/unix/sysv/linux/getdents.c.orig Fri May 7 09:41:08 1999+++ glibc-2.1.3/sysdeps/unix/sysv/linux/getdents.c Thu Mar 23 11:49:11 2000@@ -53,6 +53,9 @@
#ifdef GETDENTS64
# define __getdents __getdents64
# define dirent dirent64
+# undef off_t
+# define off_t off64_t
+# define __lseek __lseek64
#endif
/* The problem here is that we cannot simply read the next NBYTES
@@ -107,6 +110,33 @@
}
last_offset = kdp->d_off;
+
+#ifdef GETDENTS64
+ if (sizeof(__kernel_off_t) < sizeof(off64_t)) {
+ /*
+ * The kernel returns d_off as a 'cookie' that can be used
+ * in an lseek() to re-position the directory stream.
+ * "d_off" is signed by current definition of "__kernel_off_t",
+ * which is consistent with lseek() "off_t" semantics.
+ * Some file systems, most commonly NFS, may return "d_off"
+ * 'cookies' that use all 32 bits, or more specifically the
+ * sign bit.
+ * This means we need to be careful how we save "last_offset"
+ * in the case where "last_offset" is defined to be a larger
+ * container than "__kernel_off_t", we want to prevent the sign
+ * extension; it's only the lower 32 bits that we want to be
+ * able to pass back in via lseek64().
+ */
+ switch(sizeof(__kernel_off_t)) {
+ case 4:
+ {
+ last_offset = (u_int32_t)kdp->d_off;
+
+ break;
+ }
+ }
+ }
+#endif
dp->d_ino = kdp->d_ino;
dp->d_off = kdp->d_off;
dp->d_reclen = new_reclen;
-Ted Kline
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/
This archive was generated by hypermail 2b29 : Fri Apr 07 2000 - 21:00:15 EST