]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
one more .28 patch to sneak in.
authorGreg Kroah-Hartman <gregkh@suse.de>
Thu, 15 Jan 2009 21:06:06 +0000 (13:06 -0800)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 15 Jan 2009 21:06:06 +0000 (13:06 -0800)
review-2.6.28/series
review-2.6.28/xfs-truncate-readdir-offsets-to-signed-32-bit-values.patch [new file with mode: 0644]

index ea80dbc5f333a14932f322c4da6823e8a67e4a45..6857bd37ed302927abfcb5ccd0c3471875cdf359 100644 (file)
@@ -92,3 +92,4 @@ ibmvfc-improve-async-event-handling.patch
 getrusage-rusage_thread-should-return-ru_utime-and-ru_stime.patch
 ath5k-ignore-the-return-value-of-ath5k_hw_noise_floor_calibration.patch
 mm-fix-assertion.patch
+xfs-truncate-readdir-offsets-to-signed-32-bit-values.patch
diff --git a/review-2.6.28/xfs-truncate-readdir-offsets-to-signed-32-bit-values.patch b/review-2.6.28/xfs-truncate-readdir-offsets-to-signed-32-bit-values.patch
new file mode 100644 (file)
index 0000000..3754055
--- /dev/null
@@ -0,0 +1,130 @@
+From 15440319767942a363f282d6585303d3d75088ba Mon Sep 17 00:00:00 2001
+From: Christoph Hellwig <hch@infradead.org>
+Date: Thu, 8 Jan 2009 14:00:00 -0500
+Subject: XFS: truncate readdir offsets to signed 32 bit values
+
+From: Christoph Hellwig <hch@infradead.org>
+
+commit 15440319767942a363f282d6585303d3d75088ba upstream.
+
+John Stanley reported EOVERFLOW errors in readdir from his self-build
+glibc.  I traced this down to glibc enabling d_off overflow checks
+in one of the about five million different getdents implementations.
+
+In 2.6.28 Dave Woodhouse moved our readdir double buffering required
+for NFS4 readdirplus into nfsd and at that point we lost the capping
+of the directory offsets to 32 bit signed values.  Johns glibc used
+getdents64 to even implement readdir for normal 32 bit offset dirents,
+and failed with EOVERFLOW only if this happens on the first dirent in
+a getdents call.  I managed to come up with a testcase that uses
+raw getdents and does the EOVERFLOW check manually.  We always hit
+it with our last entry due to the special end of directory marker.
+
+The patch below is a dumb version of just putting back the masking,
+to make sure we have the same behavior as in 2.6.27 and earlier.
+
+I will work on a better and cleaner fix for 2.6.30.
+
+Reported-by: John Stanley <jpsinthemix@verizon.net>
+Tested-by: John Stanley <jpsinthemix@verizon.net>
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: Dave Chinner <david@fromorbit.com>
+Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ fs/xfs/xfs_dir2_block.c |    7 ++++---
+ fs/xfs/xfs_dir2_leaf.c  |    6 +++---
+ fs/xfs/xfs_dir2_sf.c    |   15 ++++++++-------
+ 3 files changed, 15 insertions(+), 13 deletions(-)
+
+--- a/fs/xfs/xfs_dir2_block.c
++++ b/fs/xfs/xfs_dir2_block.c
+@@ -517,9 +517,9 @@ xfs_dir2_block_getdents(
+               /*
+                * If it didn't fit, set the final offset to here & return.
+                */
+-              if (filldir(dirent, dep->name, dep->namelen, cook,
++              if (filldir(dirent, dep->name, dep->namelen, cook & 0x7fffffff,
+                           ino, DT_UNKNOWN)) {
+-                      *offset = cook;
++                      *offset = cook & 0x7fffffff;
+                       xfs_da_brelse(NULL, bp);
+                       return 0;
+               }
+@@ -529,7 +529,8 @@ xfs_dir2_block_getdents(
+        * Reached the end of the block.
+        * Set the offset to a non-existent block 1 and return.
+        */
+-      *offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0);
++      *offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0) &
++                      0x7fffffff;
+       xfs_da_brelse(NULL, bp);
+       return 0;
+ }
+--- a/fs/xfs/xfs_dir2_leaf.c
++++ b/fs/xfs/xfs_dir2_leaf.c
+@@ -1092,7 +1092,7 @@ xfs_dir2_leaf_getdents(
+                * Won't fit.  Return to caller.
+                */
+               if (filldir(dirent, dep->name, dep->namelen,
+-                          xfs_dir2_byte_to_dataptr(mp, curoff),
++                          xfs_dir2_byte_to_dataptr(mp, curoff) & 0x7fffffff,
+                           ino, DT_UNKNOWN))
+                       break;
+@@ -1108,9 +1108,9 @@ xfs_dir2_leaf_getdents(
+        * All done.  Set output offset value to current offset.
+        */
+       if (curoff > xfs_dir2_dataptr_to_byte(mp, XFS_DIR2_MAX_DATAPTR))
+-              *offset = XFS_DIR2_MAX_DATAPTR;
++              *offset = XFS_DIR2_MAX_DATAPTR & 0x7fffffff;
+       else
+-              *offset = xfs_dir2_byte_to_dataptr(mp, curoff);
++              *offset = xfs_dir2_byte_to_dataptr(mp, curoff) & 0x7fffffff;
+       kmem_free(map);
+       if (bp)
+               xfs_da_brelse(NULL, bp);
+--- a/fs/xfs/xfs_dir2_sf.c
++++ b/fs/xfs/xfs_dir2_sf.c
+@@ -752,8 +752,8 @@ xfs_dir2_sf_getdents(
+ #if XFS_BIG_INUMS
+               ino += mp->m_inoadd;
+ #endif
+-              if (filldir(dirent, ".", 1, dot_offset, ino, DT_DIR)) {
+-                      *offset = dot_offset;
++              if (filldir(dirent, ".", 1, dot_offset & 0x7fffffff, ino, DT_DIR)) {
++                      *offset = dot_offset & 0x7fffffff;
+                       return 0;
+               }
+       }
+@@ -766,8 +766,8 @@ xfs_dir2_sf_getdents(
+ #if XFS_BIG_INUMS
+               ino += mp->m_inoadd;
+ #endif
+-              if (filldir(dirent, "..", 2, dotdot_offset, ino, DT_DIR)) {
+-                      *offset = dotdot_offset;
++              if (filldir(dirent, "..", 2, dotdot_offset & 0x7fffffff, ino, DT_DIR)) {
++                      *offset = dotdot_offset & 0x7fffffff;
+                       return 0;
+               }
+       }
+@@ -791,14 +791,15 @@ xfs_dir2_sf_getdents(
+ #endif
+               if (filldir(dirent, sfep->name, sfep->namelen,
+-                                          off, ino, DT_UNKNOWN)) {
+-                      *offset = off;
++                          off & 0x7fffffff, ino, DT_UNKNOWN)) {
++                      *offset = off & 0x7fffffff;
+                       return 0;
+               }
+               sfep = xfs_dir2_sf_nextentry(sfp, sfep);
+       }
+-      *offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0);
++      *offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0) &
++                      0x7fffffff;
+       return 0;
+ }