summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorAndrew Morton <akpm@digeo.com>2003-04-12 13:00:40 -0700
committerJames Bottomley <jejb@raven.il.steeleye.com>2003-04-12 13:00:40 -0700
commitc14c1a4417026e137246bbdf464d38b8671232fa (patch)
tree3751743de748d2fb375645bc0eb4525c03a31560 /include
parentc9db333ac1f16a11dfc8b5a84637f89d014f6316 (diff)
[PATCH] use spinlocking in the ext2 block allocator
From Alex Tomas and myself ext2 currently uses lock_super() to protect the filesystem's in-core block allocation bitmaps. On big SMP machines the contention on that semaphore is causing high context switch rates, large amounts of idle time and reduced throughput. The context switch rate can also worsen block allocation: if several tasks are trying to allocate blocks inside the same blockgroup for different files, madly rotating between those tasks will cause the files' blocks to be intermingled. On SDET and dbench-style worloads (lots of tasks doing lots of allocation) this patch (and a similar one for the inode allocator) improve throughout on an 8-way by ~15%. On 16-way NUMAQ the speedup is 150%. What wedo isto remove the lock altogether and just rely on the atomic semantics of test_and_set_bit(): if the allocator sees a block was free it runs test_and_set_bit(). If that fails, then we raced and the allocator will go and look for another block. Of course, we don't really use test_and_set_bit() because that isn'tendian-dependent. New atomic endian-independent functions are introduced: ext2_set_bit_atomic() and ext2_clear_bit_atomic(). We do not need ext2_test_bit_atomic(), since even if ext2_test_bit() returns the wrong result, that error will be detected and naturally handled in the subsequent ext2_set_bit_atomic(). For little-endian machines the new atomic ops map directly onto the test_and_set_bit(), etc. For big-endian machines we provide the architecture's impementation with the address of a spinlock whcih can be taken around the nonatomic ext2_set_bit(). The spinlocks are hashed, and the hash is scaled according to the machine size. Architectures are free to implement optimised versions of ext2_set_bit_atomic() and ext2_clear_bit_atomic().
Diffstat (limited to 'include')
-rw-r--r--include/asm-alpha/bitops.h2
-rw-r--r--include/asm-arm/bitops.h4
-rw-r--r--include/asm-cris/bitops.h2
-rw-r--r--include/asm-i386/bitops.h4
-rw-r--r--include/asm-ia64/bitops.h2
-rw-r--r--include/asm-m68k/bitops.h18
-rw-r--r--include/asm-m68knommu/bitops.h18
-rw-r--r--include/asm-mips/bitops.h20
-rw-r--r--include/asm-mips64/bitops.h20
-rw-r--r--include/asm-parisc/bitops.h4
-rw-r--r--include/asm-ppc/bitops.h2
-rw-r--r--include/asm-ppc64/bitops.h19
-rw-r--r--include/asm-s390/bitops.h4
-rw-r--r--include/asm-s390x/bitops.h4
-rw-r--r--include/asm-sh/bitops.h18
-rw-r--r--include/asm-sparc/bitops.h19
-rw-r--r--include/asm-sparc64/bitops.h2
-rw-r--r--include/asm-v850/bitops.h2
-rw-r--r--include/asm-x86_64/bitops.h4
-rw-r--r--include/linux/ext2_fs_sb.h5
20 files changed, 173 insertions, 0 deletions
diff --git a/include/asm-alpha/bitops.h b/include/asm-alpha/bitops.h
index 14879b4f33b5..25263777a35f 100644
--- a/include/asm-alpha/bitops.h
+++ b/include/asm-alpha/bitops.h
@@ -487,7 +487,9 @@ sched_find_first_bit(unsigned long b[3])
#define ext2_set_bit __test_and_set_bit
+#define ext2_set_bit_atomic(l,n,a) test_and_set_bit(n,a)
#define ext2_clear_bit __test_and_clear_bit
+#define ext2_clear_bit_atomic(l,n,a) test_and_clear_bit(n,a)
#define ext2_test_bit test_bit
#define ext2_find_first_zero_bit find_first_zero_bit
#define ext2_find_next_zero_bit find_next_zero_bit
diff --git a/include/asm-arm/bitops.h b/include/asm-arm/bitops.h
index 622bde7dbf60..819c89592d62 100644
--- a/include/asm-arm/bitops.h
+++ b/include/asm-arm/bitops.h
@@ -357,8 +357,12 @@ static inline int sched_find_first_bit(unsigned long *b)
*/
#define ext2_set_bit(nr,p) \
__test_and_set_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p))
+#define ext2_set_bit_atomic(lock,nr,p) \
+ test_and_set_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p))
#define ext2_clear_bit(nr,p) \
__test_and_clear_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p))
+#define ext2_clear_bit_atomic(lock,nr,p) \
+ test_and_clear_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p))
#define ext2_test_bit(nr,p) \
__test_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p))
#define ext2_find_first_zero_bit(p,sz) \
diff --git a/include/asm-cris/bitops.h b/include/asm-cris/bitops.h
index 4d9856538d92..563cc9f6a998 100644
--- a/include/asm-cris/bitops.h
+++ b/include/asm-cris/bitops.h
@@ -360,7 +360,9 @@ static inline int find_next_zero_bit (void * addr, int size, int offset)
#define hweight8(x) generic_hweight8(x)
#define ext2_set_bit test_and_set_bit
+#define ext2_set_bit_atomic(l,n,a) test_and_set_bit(n,a)
#define ext2_clear_bit test_and_clear_bit
+#define ext2_clear_bit_atomic(l,n,a) test_and_clear_bit(n,a)
#define ext2_test_bit test_bit
#define ext2_find_first_zero_bit find_first_zero_bit
#define ext2_find_next_zero_bit find_next_zero_bit
diff --git a/include/asm-i386/bitops.h b/include/asm-i386/bitops.h
index 130cf2404585..f854ed354038 100644
--- a/include/asm-i386/bitops.h
+++ b/include/asm-i386/bitops.h
@@ -479,8 +479,12 @@ static __inline__ int ffs(int x)
#define ext2_set_bit(nr,addr) \
__test_and_set_bit((nr),(unsigned long*)addr)
+#define ext2_set_bit_atomic(lock,nr,addr) \
+ test_and_set_bit((nr),(unsigned long*)addr)
#define ext2_clear_bit(nr, addr) \
__test_and_clear_bit((nr),(unsigned long*)addr)
+#define ext2_clear_bit_atomic(lock,nr, addr) \
+ test_and_clear_bit((nr),(unsigned long*)addr)
#define ext2_test_bit(nr, addr) test_bit((nr),(unsigned long*)addr)
#define ext2_find_first_zero_bit(addr, size) \
find_first_zero_bit((unsigned long*)addr, size)
diff --git a/include/asm-ia64/bitops.h b/include/asm-ia64/bitops.h
index 8a61b49df8b1..af58934491f0 100644
--- a/include/asm-ia64/bitops.h
+++ b/include/asm-ia64/bitops.h
@@ -453,7 +453,9 @@ find_next_bit (void *addr, unsigned long size, unsigned long offset)
#define __clear_bit(nr, addr) clear_bit(nr, addr)
#define ext2_set_bit test_and_set_bit
+#define ext2_set_atomic(l,n,a) test_and_set_bit(n,a)
#define ext2_clear_bit test_and_clear_bit
+#define ext2_clear_atomic(l,n,a) test_and_clear_bit(n,a)
#define ext2_test_bit test_bit
#define ext2_find_first_zero_bit find_first_zero_bit
#define ext2_find_next_zero_bit find_next_zero_bit
diff --git a/include/asm-m68k/bitops.h b/include/asm-m68k/bitops.h
index fb9146e78ecc..0940cb3c1cff 100644
--- a/include/asm-m68k/bitops.h
+++ b/include/asm-m68k/bitops.h
@@ -365,6 +365,24 @@ ext2_clear_bit (int nr, volatile void *vaddr)
return retval;
}
+#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; \
+ })
+
extern __inline__ int
ext2_test_bit (int nr, const volatile void *vaddr)
{
diff --git a/include/asm-m68knommu/bitops.h b/include/asm-m68knommu/bitops.h
index 29c2ffab0913..351f6fdeae34 100644
--- a/include/asm-m68knommu/bitops.h
+++ b/include/asm-m68knommu/bitops.h
@@ -402,6 +402,24 @@ extern __inline__ int ext2_clear_bit(int nr, volatile void * addr)
return retval;
}
+#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; \
+ })
+
extern __inline__ int ext2_test_bit(int nr, const volatile void * addr)
{
int mask;
diff --git a/include/asm-mips/bitops.h b/include/asm-mips/bitops.h
index a8d323251189..d76387979544 100644
--- a/include/asm-mips/bitops.h
+++ b/include/asm-mips/bitops.h
@@ -824,6 +824,24 @@ extern __inline__ int ext2_clear_bit(int nr, void * addr)
return retval;
}
+#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; \
+ })
+
extern __inline__ int ext2_test_bit(int nr, const void * addr)
{
int mask;
@@ -890,7 +908,9 @@ found_middle:
/* Native ext2 byte ordering, just collapse using defines. */
#define ext2_set_bit(nr, addr) test_and_set_bit((nr), (addr))
+#define ext2_set_bit_atomic(lock, nr, addr) test_and_set_bit((nr), (addr))
#define ext2_clear_bit(nr, addr) test_and_clear_bit((nr), (addr))
+#define ext2_clear_bit_atomic(lock, nr, addr) test_and_clear_bit((nr), (addr))
#define ext2_test_bit(nr, addr) test_bit((nr), (addr))
#define ext2_find_first_zero_bit(addr, size) find_first_zero_bit((addr), (size))
#define ext2_find_next_zero_bit(addr, size, offset) \
diff --git a/include/asm-mips64/bitops.h b/include/asm-mips64/bitops.h
index dc1675415acc..b30ea151511a 100644
--- a/include/asm-mips64/bitops.h
+++ b/include/asm-mips64/bitops.h
@@ -531,6 +531,24 @@ ext2_clear_bit(int nr, void * addr)
return retval;
}
+#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; \
+ })
+
extern inline int
ext2_test_bit(int nr, const void * addr)
{
@@ -599,7 +617,9 @@ found_middle:
/* Native ext2 byte ordering, just collapse using defines. */
#define ext2_set_bit(nr, addr) test_and_set_bit((nr), (addr))
+#define ext2_set_bit_atomic(lock, nr, addr) test_and_set_bit((nr), (addr))
#define ext2_clear_bit(nr, addr) test_and_clear_bit((nr), (addr))
+#define ext2_clear_bit_atomic(lock, nr, addr) test_and_clear_bit((nr), (addr))
#define ext2_test_bit(nr, addr) test_bit((nr), (addr))
#define ext2_find_first_zero_bit(addr, size) find_first_zero_bit((addr), (size))
#define ext2_find_next_zero_bit(addr, size, offset) \
diff --git a/include/asm-parisc/bitops.h b/include/asm-parisc/bitops.h
index c2eed7aa218b..711e7d154afa 100644
--- a/include/asm-parisc/bitops.h
+++ b/include/asm-parisc/bitops.h
@@ -389,10 +389,14 @@ found_middle:
*/
#ifdef __LP64__
#define ext2_set_bit(nr, addr) test_and_set_bit((nr) ^ 0x38, addr)
+#define ext2_set_bit_atomic(l,nr,addr) test_and_set_bit((nr) ^ 0x38, addr)
#define ext2_clear_bit(nr, addr) test_and_clear_bit((nr) ^ 0x38, addr)
+#define ext2_clear_bit_atomic(l,nr,addr) test_and_clear_bit((nr) ^ 0x38, addr)
#else
#define ext2_set_bit(nr, addr) test_and_set_bit((nr) ^ 0x18, addr)
+#define ext2_set_bit_atomic(l,nr,addr) test_and_set_bit((nr) ^ 0x18, addr)
#define ext2_clear_bit(nr, addr) test_and_clear_bit((nr) ^ 0x18, addr)
+#define ext2_clear_bit_atomic(l,nr,addr) test_and_clear_bit((nr) ^ 0x18, addr)
#endif
#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/bitops.h b/include/asm-ppc/bitops.h
index da32a543c856..68e4a5963fb3 100644
--- a/include/asm-ppc/bitops.h
+++ b/include/asm-ppc/bitops.h
@@ -392,7 +392,9 @@ found_middle:
#define ext2_set_bit(nr, addr) __test_and_set_bit((nr) ^ 0x18, (unsigned long *)(addr))
+#define ext2_set_bit_atomic(lock, nr, addr) test_and_set_bit((nr) ^ 0x18, (unsigned long *)(addr))
#define ext2_clear_bit(nr, addr) __test_and_clear_bit((nr) ^ 0x18, (unsigned long *)(addr))
+#define ext2_clear_bit_atomic(lock, nr, addr) test_and_clear_bit((nr) ^ 0x18, (unsigned long *)(addr))
static __inline__ int ext2_test_bit(int nr, __const__ void * addr)
{
diff --git a/include/asm-ppc64/bitops.h b/include/asm-ppc64/bitops.h
index 05c66df61a0a..6bd06208e3e2 100644
--- a/include/asm-ppc64/bitops.h
+++ b/include/asm-ppc64/bitops.h
@@ -338,6 +338,25 @@ static __inline__ int __test_and_clear_le_bit(unsigned long nr, unsigned long *a
__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; \
+ })
+
#define ext2_test_bit(nr, addr) test_le_bit((nr),(unsigned long*)addr)
#define ext2_find_first_zero_bit(addr, size) \
find_first_zero_le_bit((unsigned long*)addr, size)
diff --git a/include/asm-s390/bitops.h b/include/asm-s390/bitops.h
index e680985331bd..bef5812337a3 100644
--- a/include/asm-s390/bitops.h
+++ b/include/asm-s390/bitops.h
@@ -805,8 +805,12 @@ extern __inline__ int fls(int x)
#define ext2_set_bit(nr, addr) \
test_and_set_bit((nr)^24, (unsigned long *)addr)
+#define ext2_set_bit_atomic(lock, nr, addr) \
+ test_and_set_bit((nr)^24, (unsigned long *)addr)
#define ext2_clear_bit(nr, addr) \
test_and_clear_bit((nr)^24, (unsigned long *)addr)
+#define ext2_clear_bit_atomic(lock, nr, addr) \
+ test_and_clear_bit((nr)^24, (unsigned long *)addr)
#define ext2_test_bit(nr, addr) \
test_bit((nr)^24, (unsigned long *)addr)
diff --git a/include/asm-s390x/bitops.h b/include/asm-s390x/bitops.h
index c8bb2d04b7ce..18911f98504a 100644
--- a/include/asm-s390x/bitops.h
+++ b/include/asm-s390x/bitops.h
@@ -838,8 +838,12 @@ extern __inline__ int fls(int x)
#define ext2_set_bit(nr, addr) \
test_and_set_bit((nr)^56, (unsigned long *)addr)
+#define ext2_set_bit_atomic(lock, nr, addr) \
+ test_and_set_bit((nr)^56, (unsigned long *)addr)
#define ext2_clear_bit(nr, addr) \
test_and_clear_bit((nr)^56, (unsigned long *)addr)
+#define ext2_clear_bit_atomic(lock, nr, addr) \
+ test_and_clear_bit((nr)^56, (unsigned long *)addr)
#define ext2_test_bit(nr, addr) \
test_bit((nr)^56, (unsigned long *)addr)
diff --git a/include/asm-sh/bitops.h b/include/asm-sh/bitops.h
index a897f7bdd4ee..856ce04fc424 100644
--- a/include/asm-sh/bitops.h
+++ b/include/asm-sh/bitops.h
@@ -344,6 +344,24 @@ found_middle:
}
#endif
+#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; \
+ })
+
/* Bitmap functions for the minix filesystem. */
#define minix_test_and_set_bit(nr,addr) test_and_set_bit(nr,addr)
#define minix_set_bit(nr,addr) set_bit(nr,addr)
diff --git a/include/asm-sparc/bitops.h b/include/asm-sparc/bitops.h
index 5b9707927b43..5b3226834489 100644
--- a/include/asm-sparc/bitops.h
+++ b/include/asm-sparc/bitops.h
@@ -455,6 +455,25 @@ found_middle:
#define ext2_set_bit __test_and_set_le_bit
#define ext2_clear_bit __test_and_clear_le_bit
+
+#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; \
+ })
+
#define ext2_test_bit test_le_bit
#define ext2_find_first_zero_bit find_first_zero_le_bit
#define ext2_find_next_zero_bit find_next_zero_le_bit
diff --git a/include/asm-sparc64/bitops.h b/include/asm-sparc64/bitops.h
index 0cccb55ec8c9..79adf5b5384b 100644
--- a/include/asm-sparc64/bitops.h
+++ b/include/asm-sparc64/bitops.h
@@ -351,7 +351,9 @@ found_middle:
#ifdef __KERNEL__
#define ext2_set_bit(nr,addr) test_and_set_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(nr,addr) test_and_clear_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) \
find_first_zero_le_bit((unsigned long *)(addr), (size))
diff --git a/include/asm-v850/bitops.h b/include/asm-v850/bitops.h
index 21c0b3c1c0a3..13c558d48d4f 100644
--- a/include/asm-v850/bitops.h
+++ b/include/asm-v850/bitops.h
@@ -252,7 +252,9 @@ static inline int sched_find_first_bit(unsigned long *b)
#define hweight8(x) generic_hweight8 (x)
#define ext2_set_bit test_and_set_bit
+#define ext2_set_bit_atomic(l,n,a) test_and_set_bit(n,a)
#define ext2_clear_bit test_and_clear_bit
+#define ext2_clear_bit_atomic(l,n,a) test_and_clear_bit(n,a)
#define ext2_test_bit test_bit
#define ext2_find_first_zero_bit find_first_zero_bit
#define ext2_find_next_zero_bit find_next_zero_bit
diff --git a/include/asm-x86_64/bitops.h b/include/asm-x86_64/bitops.h
index 7b3578dd2da9..493aa82d889c 100644
--- a/include/asm-x86_64/bitops.h
+++ b/include/asm-x86_64/bitops.h
@@ -487,8 +487,12 @@ static __inline__ int ffs(int x)
#define ext2_set_bit(nr,addr) \
__test_and_set_bit((nr),(unsigned long*)addr)
+#define ext2_set_bit_atomic(lock,nr,addr) \
+ test_and_set_bit((nr),(unsigned long*)addr)
#define ext2_clear_bit(nr, addr) \
__test_and_clear_bit((nr),(unsigned long*)addr)
+#define ext2_clear_bit_atomic(lock,nr,addr) \
+ test_and_clear_bit((nr),(unsigned long*)addr)
#define ext2_test_bit(nr, addr) test_bit((nr),(unsigned long*)addr)
#define ext2_find_first_zero_bit(addr, size) \
find_first_zero_bit((unsigned long*)addr, size)
diff --git a/include/linux/ext2_fs_sb.h b/include/linux/ext2_fs_sb.h
index 3c07d4ecf898..f6139acdac5c 100644
--- a/include/linux/ext2_fs_sb.h
+++ b/include/linux/ext2_fs_sb.h
@@ -16,6 +16,9 @@
#ifndef _LINUX_EXT2_FS_SB
#define _LINUX_EXT2_FS_SB
+#include <linux/blockgroup_lock.h>
+#include <linux/percpu_counter.h>
+
/*
* second extended-fs super-block data in memory
*/
@@ -45,6 +48,8 @@ struct ext2_sb_info {
u32 s_next_generation;
unsigned long s_dir_count;
u8 *s_debts;
+ struct percpu_counter s_freeblocks_counter;
+ struct blockgroup_lock s_blockgroup_lock;
};
#endif /* _LINUX_EXT2_FS_SB */