On Wed, Mar 17, 2010 at 10:44:40AM +1100, Nick Piggin wrote: > On Tue, Mar 16, 2010 at 01:01:09PM -0600, Andreas Dilger wrote: > > On 2010-03-16, at 06:22, Nick Piggin wrote: > > What makes these macros unpleasant is that it is no longer possible > > to tag to the implementation to see what it does, since there is no > > real declaration for these locks. > > > > Is it possible to change the macros to take the lock name as a > > parameter, like normal lock/unlock functions do, and then have a > > single declaration for br_lock_init(), br_wlock(), etc. macros? > > The problem is that then you can't do out of line functions, and > things like wlock/wunlock are rather large. > > What I think I can do is add macros in the brlock.h file > > #define br_rlock(name) ##name_rlock() > > So the macro calls the right function and your tag should take > you pretty close to the right place. > > Any better ideas how to implement this nicely would be welcome. > It must be as light-weight as possible in the rlock path though. It looks like this. Is it better? -- brlock: introduce special brlocks This patch introduces special brlocks, these can only be used as global locks, and use some preprocessor trickery to allow us to retain a more optimal per-cpu lock implementation. We don't bother working around lockdep yet. The other thing we can do in future is a really neat atomic-free implementation like Dave M did for the old brlocks, so we might actually be able to speed up the single-thread path for these things. Signed-off-by: Nick Piggin <npiggin@xxxxxxx> --- include/linux/brlock.h | 120 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) Index: linux-2.6/include/linux/brlock.h =================================================================== --- /dev/null +++ linux-2.6/include/linux/brlock.h @@ -0,0 +1,120 @@ +/* + * Specialised big-reader spinlock. Can only be declared as global variables + * to avoid overhead and keep things simple (and we don't want to start using + * these inside dynamically allocated structures). + * + * Copyright 2009, Nick Piggin, Novell Inc. + */ +#ifndef __LINUX_BRLOCK_H +#define __LINUX_BRLOCK_H + +#include <linux/spinlock.h> +#include <linux/percpu.h> +#include <asm/atomic.h> + +#define br_lock_init(name) name##_lock_init() +#define br_read_lock(name) name##_read_lock() +#define br_read_unlock(name) name##_read_unlock() +#define br_write_lock(name) name##_write_lock() +#define br_write_unlock(name) name##_write_unlock() +#define atomic_dec_and_br_read_lock(atomic, name) name##_atomic_dec_and_read_lock(atomic) +#define atomic_dec_and_br_write_lock(atomic, name) name##_atomic_dec_and_write_lock(atomic) + +#if defined(CONFIG_SMP) && !defined(CONFIG_LOCKDEP) +#define DECLARE_BRLOCK(name) \ + DECLARE_PER_CPU(spinlock_t, name##_lock); \ + extern void name##_lock_init(void); \ + static inline void name##_read_lock(void) { \ + spinlock_t *lock; \ + lock = &get_cpu_var(name##_lock); \ + spin_lock(lock); \ + put_cpu_var(name##_lock); \ + } \ + static inline void name##_read_unlock(void) { \ + spinlock_t *lock; \ + lock = &__get_cpu_var(name##_lock); \ + spin_unlock(lock); \ + } \ + extern void name##_write_lock(void); \ + extern void name##_write_unlock(void); \ + static inline int name##_atomic_dec_and_read_lock(atomic_t *a) { \ + int ret; \ + spinlock_t *lock; \ + lock = &get_cpu_var(name##_lock); \ + ret = atomic_dec_and_lock(a, lock); \ + put_cpu_var(name##_lock); \ + return ret; \ + } \ + extern int name##_atomic_dec_and_write_lock__failed(atomic_t *a); \ + static inline int name##_atomic_dec_and_write_lock(atomic_t *a) { \ + if (atomic_add_unless(a, -1, 1)) \ + return 0; \ + return name##_atomic_dec_and_write_lock__failed(a); \ + } + +#define DEFINE_BRLOCK(name) \ + DEFINE_PER_CPU(spinlock_t, name##_lock); \ + void name##_lock_init(void) { \ + int i; \ + for_each_possible_cpu(i) { \ + spinlock_t *lock; \ + lock = &per_cpu(name##_lock, i); \ + spin_lock_init(lock); \ + } \ + } \ + void name##_write_lock(void) { \ + int i; \ + for_each_online_cpu(i) { \ + spinlock_t *lock; \ + lock = &per_cpu(name##_lock, i); \ + spin_lock(lock); \ + } \ + } \ + void name##_write_unlock(void) { \ + int i; \ + for_each_online_cpu(i) { \ + spinlock_t *lock; \ + lock = &per_cpu(name##_lock, i); \ + spin_unlock(lock); \ + } \ + } \ + int name##_atomic_dec_and_write_lock__failed(atomic_t *a) { \ + name##_write_lock(); \ + if (!atomic_dec_and_test(a)) { \ + name##_write_unlock(); \ + return 0; \ + } \ + return 1; \ + } + +#else + +#define DECLARE_BRLOCK(name) \ + extern spinlock_t name##_lock; \ + static inline void name##_lock_init(void) { \ + spin_lock_init(&name##_lock); \ + } \ + static inline void name##_read_lock(void) { \ + spin_lock(&name##_lock); \ + } \ + static inline void name##_read_unlock(void) { \ + spin_unlock(&name##_lock); \ + } \ + static inline void name##_write_lock(void) { \ + spin_lock(&name##_lock); \ + } \ + static inline void name##_write_unlock(void) { \ + spin_unlock(&name##_lock); \ + } \ + static inline int name##_atomic_dec_and_read_lock(atomic_t *a) { \ + return atomic_dec_and_lock(a, &name##_lock); \ + } \ + static inline int name##_atomic_dec_and_write_lock(atomic_t *a) { \ + return atomic_dec_and_lock(a, &name##_lock); \ + } + +#define DEFINE_BRLOCK(name) \ + spinlock_t name##_lock +#endif + +#endif -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html