Patchwork e2fsprogs: m68k bitops fixes

login
register
mail settings
Submitter Mikael Pettersson
Date Dec. 16, 2012, 1:40 p.m.
Message ID <20685.53075.403265.997210@pilspetsen.it.uu.se>
Download mbox | patch
Permalink /patch/206677/
State Superseded
Headers show

Comments

Mikael Pettersson - Dec. 16, 2012, 1:40 p.m.
This patch fixes two problems with the m68k-specific bitops
in e2fsprogs.

The first problem is that tst_bitops SEGVs:

LD_LIBRARY_PATH=../../lib DYLD_LIBRARY_PATH=../../lib ./tst_bitops
make[1]: *** [check] Segmentation fault

Post-mortem debugging shows that this occurs in the m68k-specific
ext2fs_set_bit() when called with BIG_TEST_BIT as bit number:

Core was generated by `./tst_bitops'.
Program terminated with signal 11, Segmentation fault.
#0  0x80000820 in ext2fs_set_bit (addr=0xc01ba008, nr=2147483690) at ../../lib/ext2fs/bitops.h:357
357             __asm__ __volatile__ ("bfset %2@{%1:#1}; sne %0"
(gdb) bt
#0  0x80000820 in ext2fs_set_bit (addr=0xc01ba008, nr=2147483690) at ../../lib/ext2fs/bitops.h:357
#1  main (argc=1, argv=0xefc31174) at tst_bitops.c:112
(gdb) up
#1  main (argc=1, argv=0xefc31174) at tst_bitops.c:112
112             ext2fs_set_bit(BIG_TEST_BIT, bigarray);

The SEGV occurs because bfset et al interpret the bit number as a
_signed_ value, so 2147483690 is actually -2147483606, causing an
access to a location about 1/4 GB before 'bigarray'.

To fix this I adjust the base address to point to the correct byte,
and limit the bit number to be within that byte, before performing
the bfset (and likewise in the clear_bit and test_bit functions).
This is similar to what the x86-specific bitops do.

With this in place the SEGV is gone and the tests pass, but there
is still some strange output from tst_bitops:

big bit number (2147483690) test: 0, expected 4
big bit number (2147483690) test: 4, expected 0
ext2fs_set_bit big_test successful

The test and expected values differ, yet the test case doesn't fail.

A second look at the m68k bitop asm() statements makes the reason clear:
there are _no_ dependencies whatsoever between the asm()s and the
memory locations being accessed (a dependency on the address isn't
enough to create a dependency on memory locations reachable from it,
and __volatile__ doesn't create memory dependencies either).  The
simplest fix is to add "memory" clobbers (the kernel's bitops also
have memory clobbers), and with those in place the tests still pass
and the debug output looks sane:

big bit number (2147483690) test: 4, expected 4
big bit number (2147483690) test: 0, expected 0
ext2fs_set_bit big_test successful

Tested on m68k-linux with e2fsprogs-1.42.6 and gcc-4.6.3.

Signed-off-by: Mikael Pettersson <mikpe@it.uu.se>
---
The Linux/m68k kernel's bfset et al bitops may also be broken,
but that depends on whether they can ever be applied to large
enough bitmaps to make the bit numbers negative.  I'll raise
the issue on the linux-m68k list at vger.

 lib/ext2fs/bitops.h |    9 ++++++---
 1 files changed, 6 insertions(+), 3 deletions(-)

--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch

--- e2fsprogs-1.42.6/lib/ext2fs/bitops.h.~1~	2012-09-10 04:53:00.000000000 +0200
+++ e2fsprogs-1.42.6/lib/ext2fs/bitops.h	2012-12-16 13:39:46.000000000 +0100
@@ -354,8 +354,9 @@  _INLINE_ int ext2fs_set_bit(unsigned int
 {
 	char retval;
 
+	addr = (void *) ((unsigned char *) addr + (nr >> 3));
 	__asm__ __volatile__ ("bfset %2@{%1:#1}; sne %0"
-	     : "=d" (retval) : "d" (nr^7), "a" (addr));
+	     : "=d" (retval) : "d" ((nr & 7) ^ 7), "a" (addr) : "memory");
 
 	return retval;
 }
@@ -364,8 +365,9 @@  _INLINE_ int ext2fs_clear_bit(unsigned i
 {
 	char retval;
 
+	addr = (void *) ((unsigned char *) addr + (nr >> 3));
 	__asm__ __volatile__ ("bfclr %2@{%1:#1}; sne %0"
-	     : "=d" (retval) : "d" (nr^7), "a" (addr));
+	     : "=d" (retval) : "d" ((nr & 7) ^ 7), "a" (addr) : "memory");
 
 	return retval;
 }
@@ -374,8 +376,9 @@  _INLINE_ int ext2fs_test_bit(unsigned in
 {
 	char retval;
 
+	addr = (const void *) ((const unsigned char *) addr + (nr >> 3));
 	__asm__ __volatile__ ("bftst %2@{%1:#1}; sne %0"
-	     : "=d" (retval) : "d" (nr^7), "a" (addr));
+	     : "=d" (retval) : "d" ((nr & 7) ^ 7), "a" (addr) : "memory");
 
 	return retval;
 }