Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757368Ab0KOOZd (ORCPT ); Mon, 15 Nov 2010 09:25:33 -0500 Received: from king.tilera.com ([72.1.168.226]:30224 "EHLO king.tilera.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757075Ab0KOOZb (ORCPT ); Mon, 15 Nov 2010 09:25:31 -0500 Message-Id: <201011151425.oAFEPU3W005682@farm-0010.internal.tilera.com> From: Chris Metcalf Date: Mon, 15 Nov 2010 09:18:49 -0500 Subject: [PATCH] arch/tile: fix rwlock so would-be write lockers don't block new readers References: <1289489007.17691.1310.camel@edumazet-laptop> <4CDF1945.8090101@tilera.com> In-Reply-To: To: CC: =?ISO-8859-1?Q?Am=E9rico_Wang?= , Eric Dumazet , netdev , Cypher Wu X-OriginalArrivalTime: 15 Nov 2010 14:25:30.0514 (UTC) FILETIME=[F4CA1720:01CB84D0] Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 2355 Lines: 71 This avoids a deadlock in the IGMP code where one core gets a read lock, another core starts trying to get a write lock (thus blocking new readers), and then the first core tries to recursively re-acquire the read lock. We still try to preserve some degree of balance by giving priority to additional write lockers that come along while the lock is held for write, so they can all complete quickly and return the lock to the readers. Signed-off-by: Chris Metcalf --- This should apply relatively cleanly to 2.6.26.7 source code too. arch/tile/lib/spinlock_32.c | 29 ++++++++++++++++++----------- 1 files changed, 18 insertions(+), 11 deletions(-) diff --git a/arch/tile/lib/spinlock_32.c b/arch/tile/lib/spinlock_32.c index 485e24d..5cd1c40 100644 --- a/arch/tile/lib/spinlock_32.c +++ b/arch/tile/lib/spinlock_32.c @@ -167,23 +167,30 @@ void arch_write_lock_slow(arch_rwlock_t *rwlock, u32 val) * when we compare them. */ u32 my_ticket_; + u32 iterations = 0; - /* Take out the next ticket; this will also stop would-be readers. */ - if (val & 1) - val = get_rwlock(rwlock); - rwlock->lock = __insn_addb(val, 1 << WR_NEXT_SHIFT); + /* + * Wait until there are no readers, then bump up the next + * field and capture the ticket value. + */ + for (;;) { + if (!(val & 1)) { + if ((val >> RD_COUNT_SHIFT) == 0) + break; + rwlock->lock = val; + } + delay_backoff(iterations++); + val = __insn_tns((int *)&rwlock->lock); + } - /* Extract my ticket value from the original word. */ + /* Take out the next ticket and extract my ticket value. */ + rwlock->lock = __insn_addb(val, 1 << WR_NEXT_SHIFT); my_ticket_ = val >> WR_NEXT_SHIFT; - /* - * Wait until the "current" field matches our ticket, and - * there are no remaining readers. - */ + /* Wait until the "current" field matches our ticket. */ for (;;) { u32 curr_ = val >> WR_CURR_SHIFT; - u32 readers = val >> RD_COUNT_SHIFT; - u32 delta = ((my_ticket_ - curr_) & WR_MASK) + !!readers; + u32 delta = ((my_ticket_ - curr_) & WR_MASK); if (likely(delta == 0)) break; -- 1.6.5.2 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/