Skip to content

Commit

Permalink
spinlock: lockbreak cleanup
Browse files Browse the repository at this point in the history
The break_lock data structure and code for spinlocks is quite nasty.
Not only does it double the size of a spinlock but it changes locking to
a potentially less optimal trylock.

Put all of that under CONFIG_GENERIC_LOCKBREAK, and introduce a
__raw_spin_is_contended that uses the lock data itself to determine whether
there are waiters on the lock, to be used if CONFIG_GENERIC_LOCKBREAK is
not set.

Rename need_lockbreak to spin_needbreak, make it use spin_is_contended to
decouple it from the spinlock implementation, and make it typesafe (rwlocks
do not have any need_lockbreak sites -- why do they even get bloated up
with that break_lock then?).

Signed-off-by: Nick Piggin <[email protected]>
Signed-off-by: Ingo Molnar <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>
  • Loading branch information
Nick Piggin authored and Ingo Molnar committed Jan 30, 2008
1 parent a95d67f commit 95c354f
Show file tree
Hide file tree
Showing 19 changed files with 72 additions and 37 deletions.
5 changes: 5 additions & 0 deletions arch/arm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ config GENERIC_IRQ_PROBE
bool
default y

config GENERIC_LOCKBREAK
bool
default y
depends on SMP && PREEMPT

config RWSEM_GENERIC_SPINLOCK
bool
default y
Expand Down
5 changes: 5 additions & 0 deletions arch/ia64/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ config MMU
config SWIOTLB
bool

config GENERIC_LOCKBREAK
bool
default y
depends on SMP && PREEMPT

config RWSEM_XCHGADD_ALGORITHM
bool
default y
Expand Down
5 changes: 5 additions & 0 deletions arch/m32r/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,11 @@ config IRAM_SIZE
# Define implied options from the CPU selection here
#

config GENERIC_LOCKBREAK
bool
default y
depends on SMP && PREEMPT

config RWSEM_GENERIC_SPINLOCK
bool
depends on M32R
Expand Down
5 changes: 5 additions & 0 deletions arch/mips/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,11 @@ source "arch/mips/vr41xx/Kconfig"

endmenu

config GENERIC_LOCKBREAK
bool
default y
depends on SMP && PREEMPT

config RWSEM_GENERIC_SPINLOCK
bool
default y
Expand Down
5 changes: 5 additions & 0 deletions arch/parisc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ config MMU
config STACK_GROWSUP
def_bool y

config GENERIC_LOCKBREAK
bool
default y
depends on SMP && PREEMPT

config RWSEM_GENERIC_SPINLOCK
def_bool y

Expand Down
5 changes: 5 additions & 0 deletions arch/powerpc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ config RWSEM_XCHGADD_ALGORITHM
bool
default y

config GENERIC_LOCKBREAK
bool
default y
depends on SMP && PREEMPT

config ARCH_HAS_ILOG2_U32
bool
default y
Expand Down
5 changes: 5 additions & 0 deletions arch/sparc64/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,11 @@ config US2E_FREQ
If in doubt, say N.

# Global things across all Sun machines.
config GENERIC_LOCKBREAK
bool
default y
depends on SMP && PREEMPT

config RWSEM_GENERIC_SPINLOCK
bool

Expand Down
4 changes: 4 additions & 0 deletions arch/x86/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ config X86_64
config X86
def_bool y

config GENERIC_LOCKBREAK
def_bool y
depends on SMP && PREEMPT

config GENERIC_TIME
def_bool y

Expand Down
3 changes: 2 additions & 1 deletion fs/jbd/checkpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,8 @@ int log_do_checkpoint(journal_t *journal)
break;
}
retry = __process_buffer(journal, jh, bhs,&batch_count);
if (!retry && lock_need_resched(&journal->j_list_lock)){
if (!retry && (need_resched() ||
spin_needbreak(&journal->j_list_lock))) {
spin_unlock(&journal->j_list_lock);
retry = 1;
break;
Expand Down
2 changes: 1 addition & 1 deletion fs/jbd/commit.c
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ static void journal_submit_data_buffers(journal_t *journal,
put_bh(bh);
}

if (lock_need_resched(&journal->j_list_lock)) {
if (need_resched() || spin_needbreak(&journal->j_list_lock)) {
spin_unlock(&journal->j_list_lock);
goto write_out_data;
}
Expand Down
3 changes: 2 additions & 1 deletion fs/jbd2/checkpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,8 @@ int jbd2_log_do_checkpoint(journal_t *journal)
}
retry = __process_buffer(journal, jh, bhs, &batch_count,
transaction);
if (!retry && lock_need_resched(&journal->j_list_lock)){
if (!retry && (need_resched() ||
spin_needbreak(&journal->j_list_lock))) {
spin_unlock(&journal->j_list_lock);
retry = 1;
break;
Expand Down
2 changes: 1 addition & 1 deletion fs/jbd2/commit.c
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ static void journal_submit_data_buffers(journal_t *journal,
put_bh(bh);
}

if (lock_need_resched(&journal->j_list_lock)) {
if (need_resched() || spin_needbreak(&journal->j_list_lock)) {
spin_unlock(&journal->j_list_lock);
goto write_out_data;
}
Expand Down
21 changes: 7 additions & 14 deletions include/linux/sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -1922,23 +1922,16 @@ extern int cond_resched_softirq(void);

/*
* Does a critical section need to be broken due to another
* task waiting?:
* task waiting?: (technically does not depend on CONFIG_PREEMPT,
* but a general need for low latency)
*/
#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP)
# define need_lockbreak(lock) ((lock)->break_lock)
#else
# define need_lockbreak(lock) 0
#endif

/*
* Does a critical section need to be broken due to another
* task waiting or preemption being signalled:
*/
static inline int lock_need_resched(spinlock_t *lock)
static inline int spin_needbreak(spinlock_t *lock)
{
if (need_lockbreak(lock) || need_resched())
return 1;
#ifdef CONFIG_PREEMPT
return spin_is_contended(lock);
#else
return 0;
#endif
}

/*
Expand Down
6 changes: 6 additions & 0 deletions include/linux/spinlock.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@ do { \

#define spin_is_locked(lock) __raw_spin_is_locked(&(lock)->raw_lock)

#ifdef CONFIG_GENERIC_LOCKBREAK
#define spin_is_contended(lock) ((lock)->break_lock)
#else
#define spin_is_contended(lock) __raw_spin_is_contended(&(lock)->raw_lock)
#endif

/**
* spin_unlock_wait - wait until the spinlock gets unlocked
* @lock: the spinlock in question.
Expand Down
4 changes: 2 additions & 2 deletions include/linux/spinlock_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

typedef struct {
raw_spinlock_t raw_lock;
#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP)
#ifdef CONFIG_GENERIC_LOCKBREAK
unsigned int break_lock;
#endif
#ifdef CONFIG_DEBUG_SPINLOCK
Expand All @@ -35,7 +35,7 @@ typedef struct {

typedef struct {
raw_rwlock_t raw_lock;
#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP)
#ifdef CONFIG_GENERIC_LOCKBREAK
unsigned int break_lock;
#endif
#ifdef CONFIG_DEBUG_SPINLOCK
Expand Down
2 changes: 2 additions & 0 deletions include/linux/spinlock_up.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ static inline void __raw_spin_unlock(raw_spinlock_t *lock)
# define __raw_spin_trylock(lock) ({ (void)(lock); 1; })
#endif /* DEBUG_SPINLOCK */

#define __raw_spin_is_contended(lock) (((void)(lock), 0))

#define __raw_read_can_lock(lock) (((void)(lock), 1))
#define __raw_write_can_lock(lock) (((void)(lock), 1))

Expand Down
16 changes: 6 additions & 10 deletions kernel/sched.c
Original file line number Diff line number Diff line change
Expand Up @@ -4945,19 +4945,15 @@ EXPORT_SYMBOL(_cond_resched);
*/
int cond_resched_lock(spinlock_t *lock)
{
int resched = need_resched() && system_state == SYSTEM_RUNNING;
int ret = 0;

if (need_lockbreak(lock)) {
if (spin_needbreak(lock) || resched) {
spin_unlock(lock);
cpu_relax();
ret = 1;
spin_lock(lock);
}
if (need_resched() && system_state == SYSTEM_RUNNING) {
spin_release(&lock->dep_map, 1, _THIS_IP_);
_raw_spin_unlock(lock);
preempt_enable_no_resched();
__cond_resched();
if (resched && need_resched())
__cond_resched();
else
cpu_relax();
ret = 1;
spin_lock(lock);
}
Expand Down
3 changes: 1 addition & 2 deletions kernel/spinlock.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@ EXPORT_SYMBOL(_write_trylock);
* even on CONFIG_PREEMPT, because lockdep assumes that interrupts are
* not re-enabled during lock-acquire (which the preempt-spin-ops do):
*/
#if !defined(CONFIG_PREEMPT) || !defined(CONFIG_SMP) || \
defined(CONFIG_DEBUG_LOCK_ALLOC)
#if !defined(CONFIG_GENERIC_LOCKBREAK) || defined(CONFIG_DEBUG_LOCK_ALLOC)

void __lockfunc _read_lock(rwlock_t *lock)
{
Expand Down
8 changes: 3 additions & 5 deletions mm/memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -513,8 +513,7 @@ static int copy_pte_range(struct mm_struct *dst_mm, struct mm_struct *src_mm,
if (progress >= 32) {
progress = 0;
if (need_resched() ||
need_lockbreak(src_ptl) ||
need_lockbreak(dst_ptl))
spin_needbreak(src_ptl) || spin_needbreak(dst_ptl))
break;
}
if (pte_none(*src_pte)) {
Expand Down Expand Up @@ -853,7 +852,7 @@ unsigned long unmap_vmas(struct mmu_gather **tlbp,
tlb_finish_mmu(*tlbp, tlb_start, start);

if (need_resched() ||
(i_mmap_lock && need_lockbreak(i_mmap_lock))) {
(i_mmap_lock && spin_needbreak(i_mmap_lock))) {
if (i_mmap_lock) {
*tlbp = NULL;
goto out;
Expand Down Expand Up @@ -1768,8 +1767,7 @@ static int unmap_mapping_range_vma(struct vm_area_struct *vma,

restart_addr = zap_page_range(vma, start_addr,
end_addr - start_addr, details);
need_break = need_resched() ||
need_lockbreak(details->i_mmap_lock);
need_break = need_resched() || spin_needbreak(details->i_mmap_lock);

if (restart_addr >= end_addr) {
/* We have now completed this vma: mark it so */
Expand Down

0 comments on commit 95c354f

Please sign in to comment.