Commit ec2a9baf authored by Paul Mackerras's avatar Paul Mackerras Committed by Linus Torvalds

[PATCH] ppc64: better little-endian bitops

Below patch reuses the big-endian bitops for the little endian ones, and
moves the ext2_{set,clear}_bit_atomic functions to be truly atomic instead
of lock based.

This requires that the bitmaps passed to the ext2_* bitop functions are
8-byte aligned.  I have been assured that they will be 512-byte or
1024-byte aligned, and sparc and ppc32 also impose an alignment requirement
on the bitmap.
Signed-off-by: default avatarOlof Johansson <olof@austin.ibm.com>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent e7af9387
......@@ -22,6 +22,15 @@
* it will be a bad memory reference since we want to store in chunks
* of unsigned long (64 bits here) size.
*
* There are a few little-endian macros used mostly for filesystem bitmaps,
* these work on similar bit arrays layouts, but byte-oriented:
*
* |7...0|15...8|23...16|31...24|39...32|47...40|55...48|63...56|
*
* The main difference is that bit 3-5 in the bit number field needs to be
* reversed compared to the big-endian bit fields. This can be achieved
* by XOR with 0b111000 (0x38).
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
......@@ -306,71 +315,34 @@ static __inline__ int test_le_bit(unsigned long nr, __const__ unsigned long * ad
return (ADDR[nr >> 3] >> (nr & 7)) & 1;
}
#define test_and_clear_le_bit(nr, addr) \
test_and_clear_bit((nr) ^ 0x38, (addr))
#define test_and_set_le_bit(nr, addr) \
test_and_set_bit((nr) ^ 0x38, (addr))
/*
* non-atomic versions
*/
static __inline__ void __set_le_bit(unsigned long nr, unsigned long *addr)
{
unsigned char *ADDR = (unsigned char *)addr;
ADDR += nr >> 3;
*ADDR |= 1 << (nr & 0x07);
}
static __inline__ void __clear_le_bit(unsigned long nr, unsigned long *addr)
{
unsigned char *ADDR = (unsigned char *)addr;
ADDR += nr >> 3;
*ADDR &= ~(1 << (nr & 0x07));
}
static __inline__ int __test_and_set_le_bit(unsigned long nr, unsigned long *addr)
{
int mask, retval;
unsigned char *ADDR = (unsigned char *)addr;
ADDR += nr >> 3;
mask = 1 << (nr & 0x07);
retval = (mask & *ADDR) != 0;
*ADDR |= mask;
return retval;
}
static __inline__ int __test_and_clear_le_bit(unsigned long nr, unsigned long *addr)
{
int mask, retval;
unsigned char *ADDR = (unsigned char *)addr;
ADDR += nr >> 3;
mask = 1 << (nr & 0x07);
retval = (mask & *ADDR) != 0;
*ADDR &= ~mask;
return retval;
}
#define __set_le_bit(nr, addr) \
__set_bit((nr) ^ 0x38, (addr))
#define __clear_le_bit(nr, addr) \
__clear_bit((nr) ^ 0x38, (addr))
#define __test_and_clear_le_bit(nr, addr) \
__test_and_clear_bit((nr) ^ 0x38, (addr))
#define __test_and_set_le_bit(nr, addr) \
__test_and_set_bit((nr) ^ 0x38, (addr))
#define ext2_set_bit(nr,addr) \
__test_and_set_le_bit((nr),(unsigned long*)addr)
__test_and_set_le_bit((nr), (unsigned long*)addr)
#define ext2_clear_bit(nr, addr) \
__test_and_clear_le_bit((nr),(unsigned long*)addr)
#define ext2_set_bit_atomic(lock, nr, addr) \
({ \
int ret; \
spin_lock(lock); \
ret = ext2_set_bit((nr), (addr)); \
spin_unlock(lock); \
ret; \
})
#define ext2_clear_bit_atomic(lock, nr, addr) \
({ \
int ret; \
spin_lock(lock); \
ret = ext2_clear_bit((nr), (addr)); \
spin_unlock(lock); \
ret; \
})
__test_and_clear_le_bit((nr), (unsigned long*)addr)
#define ext2_set_bit_atomic(lock, nr, addr) \
test_and_set_le_bit((nr), (unsigned long*)addr)
#define ext2_clear_bit_atomic(lock, nr, addr) \
test_and_clear_le_bit((nr), (unsigned long*)addr)
#define ext2_test_bit(nr, addr) test_le_bit((nr),(unsigned long*)addr)
#define ext2_find_first_zero_bit(addr, size) \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment