linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [GIT] Sparc
@ 2010-08-18  1:03 David Miller
  2010-08-18  1:31 ` Linus Torvalds
  0 siblings, 1 reply; 25+ messages in thread
From: David Miller @ 2010-08-18  1:03 UTC (permalink / raw)
  To: torvalds; +Cc: akpm, sparclinux, linux-kernel


Among other things, this fixes the rwsem signedness issue we
were discussing earlier today.

Add entries for the new 2.6.36 system calls.

Make console=tty* on the kernel command line work properly
for serial consoles.

Please pull, thanks a lot!

The following changes since commit da5cabf80e2433131bf0ed8993abc0f7ea618c73:

  Linux 2.6.36-rc1 (2010-08-15 17:41:37 -0700)

are available in the git repository at:
  master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6.git master

David S. Miller (5):
      sparc: Really fix "console=" for serial consoles.
      Merge branch 'master' of git://git.kernel.org/.../torvalds/linux-2.6
      sparc: Hook up new fanotify and prlimit64 syscalls.
      sparc64: Fix rwsem constant bug leading to hangs.
      sparc64: Fix atomic64_t routine return values.

 arch/sparc/include/asm/atomic_64.h   |    6 +++---
 arch/sparc/include/asm/fb.h          |    4 ++++
 arch/sparc/include/asm/rwsem-const.h |    2 +-
 arch/sparc/include/asm/unistd.h      |    5 ++++-
 arch/sparc/kernel/sys32.S            |    9 +++++++++
 arch/sparc/kernel/systbls_32.S       |    3 ++-
 arch/sparc/kernel/systbls_64.S       |    6 ++++--
 drivers/serial/suncore.c             |   15 +++++++++------
 8 files changed, 36 insertions(+), 14 deletions(-)

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [GIT] Sparc
  2010-08-18  1:03 [GIT] Sparc David Miller
@ 2010-08-18  1:31 ` Linus Torvalds
  2010-08-18  1:59   ` Linus Torvalds
  2010-08-18  2:12   ` [GIT] Sparc David Miller
  0 siblings, 2 replies; 25+ messages in thread
From: Linus Torvalds @ 2010-08-18  1:31 UTC (permalink / raw)
  To: David Miller; +Cc: akpm, sparclinux, linux-kernel

On Tue, Aug 17, 2010 at 6:03 PM, David Miller <davem@davemloft.net> wrote:
>
> Among other things, this fixes the rwsem signedness issue we
> were discussing earlier today.

Your commit message is missing the C rules for hex constants. It says

  "hex constants are unsigned unless explicitly casted or negated."

and that's not true.

The rule is that hex constants are signed _except_ if they don't fit
in a signed.

So with a 32-bit 'int', 0x123 is signed, but 0x80000000 is unsigned.

So the reason (-0x00010000) is signed is _not_ because of the
negation, but simply because 0x00010000 fits in a signed int. So for
example, the constant (-0xf0000000) is still unsigned, despite the
negation.

So to make something signed, you need to either cast it, make sure it
fits in a signed int, use the 'l' postfix (which also makes it long,
of course), or use a decimal representation. So

   #define X 4294901760

is a _signed_ constant with same value as 0xffff0000 (but it's "signed
long", because the rules for decimal numbers and hex numbers are
different: a decimal number is always signed and because it doesn't
fit in 'int' it will extend to 'long'. A hex number is first done as
unsigned, and only extended to long if it doesn't fit in that.

To make things _really_ confused, sometimes the types actually depend
on whether you're compiling with the c90 standards. A decimal constant
is _always_ signed in traditional C - it goes from 'int' to 'long',
and stays 'long' even if it doesn't fit (ie with a 32-bit long,
2147483648 is of type 'long' even though it doesn't fit in 'long' and
is negative). But in c90, it does from 'int' to 'long' to 'unsigned
long'.

Or maybe it was the other way around. I forget.

Confused yet?

The basic rule becomes: never _ever_ overflow 'int' in a constant,
without specifying the exact type you want. That way you avoid all the
subtle cases.

                     Linus

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [GIT] Sparc
  2010-08-18  1:31 ` Linus Torvalds
@ 2010-08-18  1:59   ` Linus Torvalds
  2010-08-18  2:14     ` David Miller
  2010-08-18  2:12   ` [GIT] Sparc David Miller
  1 sibling, 1 reply; 25+ messages in thread
From: Linus Torvalds @ 2010-08-18  1:59 UTC (permalink / raw)
  To: David Miller; +Cc: akpm, sparclinux, linux-kernel

Oh,
 I noticed another thing:

In commit 86fa04b8742ac681d470786f55e2403ada0075b2 you fix the return
type, but you still have the wrong _argument_ type:

  extern void atomic64_add(int, atomic64_t *);
  extern void atomic64_sub(int, atomic64_t *);
  extern long atomic64_add_ret(int, atomic64_t *);
  extern long atomic64_sub_ret(int, atomic64_t *);

note how if somebody does

   atomic64_add(0x100000000ull, &x)

sparc64 will get it wrong, because it will only take the low 32 bits
of the first argument, and add zero to the 64-bit counter.

Which is definitely not what the code intended, I think.

I merged your pull request, but you've got some fixing up to do,
methinks. I also really think you need to make your rwsem's use 64-bit
values on sparc64, because otherwise you can overflow the mmap_sem by
having more than 65536 threads doing page-faults (on 32-bit, having
more than 2**16 threads in one process is unlikely to work for other
reasons, like just pure stack usage, so we don't really care about the
32-bit case)

                         Linus

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [GIT] Sparc
  2010-08-18  1:31 ` Linus Torvalds
  2010-08-18  1:59   ` Linus Torvalds
@ 2010-08-18  2:12   ` David Miller
  2010-08-18  2:50     ` Al Viro
  1 sibling, 1 reply; 25+ messages in thread
From: David Miller @ 2010-08-18  2:12 UTC (permalink / raw)
  To: torvalds; +Cc: akpm, sparclinux, linux-kernel

From: Linus Torvalds <torvalds@linux-foundation.org>
Date: Tue, 17 Aug 2010 18:31:50 -0700

> Confused yet?

Beyond...

> The basic rule becomes: never _ever_ overflow 'int' in a constant,
> without specifying the exact type you want. That way you avoid all the
> subtle cases.

That's easier to understand.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [GIT] Sparc
  2010-08-18  1:59   ` Linus Torvalds
@ 2010-08-18  2:14     ` David Miller
  2010-08-18  4:38       ` 64-bit ppc rwsem (was: Re: [GIT] Sparc) Benjamin Herrenschmidt
  0 siblings, 1 reply; 25+ messages in thread
From: David Miller @ 2010-08-18  2:14 UTC (permalink / raw)
  To: torvalds; +Cc: akpm, sparclinux, linux-kernel, paulus, benh

From: Linus Torvalds <torvalds@linux-foundation.org>
Date: Tue, 17 Aug 2010 18:59:17 -0700

> In commit 86fa04b8742ac681d470786f55e2403ada0075b2 you fix the return
> type, but you still have the wrong _argument_ type:
> 
>   extern void atomic64_add(int, atomic64_t *);
>   extern void atomic64_sub(int, atomic64_t *);
>   extern long atomic64_add_ret(int, atomic64_t *);
>   extern long atomic64_sub_ret(int, atomic64_t *);

Thanks, I'll fix that up.

> I merged your pull request, but you've got some fixing up to do,
> methinks. I also really think you need to make your rwsem's use 64-bit
> values on sparc64, because otherwise you can overflow the mmap_sem by
> having more than 65536 threads doing page-faults (on 32-bit, having
> more than 2**16 threads in one process is unlikely to work for other
> reasons, like just pure stack usage, so we don't really care about the
> 32-bit case)

I have a patch to do this already, just need to test it.

You should bug the powerpc folks too :-)

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [GIT] Sparc
  2010-08-18  2:12   ` [GIT] Sparc David Miller
@ 2010-08-18  2:50     ` Al Viro
  0 siblings, 0 replies; 25+ messages in thread
From: Al Viro @ 2010-08-18  2:50 UTC (permalink / raw)
  To: David Miller; +Cc: torvalds, akpm, sparclinux, linux-kernel

On Tue, Aug 17, 2010 at 07:12:45PM -0700, David Miller wrote:
> From: Linus Torvalds <torvalds@linux-foundation.org>
> Date: Tue, 17 Aug 2010 18:31:50 -0700
> 
> > Confused yet?
> 
> Beyond...
> 
> > The basic rule becomes: never _ever_ overflow 'int' in a constant,
> > without specifying the exact type you want. That way you avoid all the
> > subtle cases.
> 
> That's easier to understand.

Actually, it's not that complicated:

1) base and suffices choose the possible types.
2) order of types is always the same: int -> unsigned -> long -> unsigned
long -> long long -> unsigned long long
3) we always choose the first type the value would fit into
4) L in suffix == "at least long"
5) LL in suffix == "at least long long"
6) U in suffix == "unsigned"
7) without U in suffix, base 10 == "signed"

That's it.  C90 differs from C99 only in one thing - long long (and LL) isn't
there.  The subtle mess Linus has mentioned is C90 gccism: gcc has allowed
unsigned long for decimal constants, as the last resort.  I.e. if you had
a plain decimal constant that wouldn't fit into long but would fit into
unsigned long, gcc generated a warning and treated it as unsigned long.
C90 would reject the damn thing.  _Bad_ extension, since in C99 the same
constant would be a legitimate signed long long.

But yes, "use the suffix when unsure" is a damn good idea, _especially_ since
the sizeof(long) actually varies between the targets we care about.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* 64-bit ppc rwsem (was: Re: [GIT] Sparc)
  2010-08-18  2:14     ` David Miller
@ 2010-08-18  4:38       ` Benjamin Herrenschmidt
  2010-08-18  5:03         ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 25+ messages in thread
From: Benjamin Herrenschmidt @ 2010-08-18  4:38 UTC (permalink / raw)
  To: David Miller
  Cc: torvalds, akpm, sparclinux, linux-kernel, paulus, linuxppc-dev

On Tue, 2010-08-17 at 19:14 -0700, David Miller wrote:

> > I merged your pull request, but you've got some fixing up to do,
> > methinks. I also really think you need to make your rwsem's use 64-bit
> > values on sparc64, because otherwise you can overflow the mmap_sem by
> > having more than 65536 threads doing page-faults (on 32-bit, having
> > more than 2**16 threads in one process is unlikely to work for other
> > reasons, like just pure stack usage, so we don't really care about the
> > 32-bit case)
> 
> I have a patch to do this already, just need to test it.
> 
> You should bug the powerpc folks too :-)

32K threads :-) you guys are nuts !

Here's an untested patch for the folks on linuxppc-dev to look at, I'll
review my own stuff & test tomorrow.

Cheers,
Ben.

powerpc: Make rwsem use "long" types on 64-bit platforms

This should avoid overflow of the mmap_sem when playing with insane
number of threads.

Not-signed-off-by-yet.

diff --git a/arch/powerpc/include/asm/rwsem.h b/arch/powerpc/include/asm/rwsem.h
index 24cd928..ca64a98 100644
--- a/arch/powerpc/include/asm/rwsem.h
+++ b/arch/powerpc/include/asm/rwsem.h
@@ -21,15 +21,20 @@
 /*
  * the semaphore definition
  */
-struct rw_semaphore {
-	/* XXX this should be able to be an atomic_t  -- paulus */
-	signed int		count;
-#define RWSEM_UNLOCKED_VALUE		0x00000000
-#define RWSEM_ACTIVE_BIAS		0x00000001
-#define RWSEM_ACTIVE_MASK		0x0000ffff
-#define RWSEM_WAITING_BIAS		(-0x00010000)
+#ifdef CONFIG_PPC64
+# define RWSEM_ACTIVE_MASK		0xffffffffL
+#else
+# define RWSEM_ACTIVE_MASK		0x0000ffffL
+#endif
+
+#define RWSEM_UNLOCKED_VALUE		0x00000000L
+#define RWSEM_ACTIVE_BIAS		0x00000001L
+#define RWSEM_WAITING_BIAS		(-RWSEM_ACTIVE_MASK-1)
 #define RWSEM_ACTIVE_READ_BIAS		RWSEM_ACTIVE_BIAS
 #define RWSEM_ACTIVE_WRITE_BIAS		(RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
+
+struct rw_semaphore {
+	atomic_long_t		count;
 	spinlock_t		wait_lock;
 	struct list_head	wait_list;
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
@@ -43,9 +48,13 @@ struct rw_semaphore {
 # define __RWSEM_DEP_MAP_INIT(lockname)
 #endif
 
-#define __RWSEM_INITIALIZER(name) \
-	{ RWSEM_UNLOCKED_VALUE, __SPIN_LOCK_UNLOCKED((name).wait_lock), \
-	  LIST_HEAD_INIT((name).wait_list) __RWSEM_DEP_MAP_INIT(name) }
+#define __RWSEM_INITIALIZER(name)				\
+{								\
+	ATOMIC_LONG_INIT(RWSEM_UNLOCKED_VALUE),			\
+	__SPIN_LOCK_UNLOCKED((name).wait_lock),			\
+	LIST_HEAD_INIT((name).wait_list)			\
+	__RWSEM_DEP_MAP_INIT(name)				\
+}
 
 #define DECLARE_RWSEM(name)		\
 	struct rw_semaphore name = __RWSEM_INITIALIZER(name)
@@ -70,16 +79,16 @@ extern void __init_rwsem(struct rw_semaphore *sem, const char *name,
  */
 static inline void __down_read(struct rw_semaphore *sem)
 {
-	if (unlikely(atomic_inc_return((atomic_t *)(&sem->count)) <= 0))
+	if (unlikely(atomic_long_inc_return(&sem->count) <= 0))
 		rwsem_down_read_failed(sem);
 }
 
 static inline int __down_read_trylock(struct rw_semaphore *sem)
 {
-	int tmp;
+	long tmp;
 
-	while ((tmp = sem->count) >= 0) {
-		if (tmp == cmpxchg(&sem->count, tmp,
+	while ((tmp = atomic_long_read(&sem->count)) >= 0) {
+		if (tmp == cmpxchg((long *)&sem->count, tmp,
 				   tmp + RWSEM_ACTIVE_READ_BIAS)) {
 			return 1;
 		}
@@ -92,10 +101,10 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
  */
 static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
 {
-	int tmp;
+	long tmp;
 
-	tmp = atomic_add_return(RWSEM_ACTIVE_WRITE_BIAS,
-				(atomic_t *)(&sem->count));
+	tmp = atomic_long_add_return(RWSEM_ACTIVE_WRITE_BIAS,
+				     &sem->count);
 	if (unlikely(tmp != RWSEM_ACTIVE_WRITE_BIAS))
 		rwsem_down_write_failed(sem);
 }
@@ -107,9 +116,9 @@ static inline void __down_write(struct rw_semaphore *sem)
 
 static inline int __down_write_trylock(struct rw_semaphore *sem)
 {
-	int tmp;
+	long tmp;
 
-	tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
+	tmp = cmpxchg((long *)&sem->count, RWSEM_UNLOCKED_VALUE,
 		      RWSEM_ACTIVE_WRITE_BIAS);
 	return tmp == RWSEM_UNLOCKED_VALUE;
 }
@@ -119,9 +128,9 @@ static inline int __down_write_trylock(struct rw_semaphore *sem)
  */
 static inline void __up_read(struct rw_semaphore *sem)
 {
-	int tmp;
+	long tmp;
 
-	tmp = atomic_dec_return((atomic_t *)(&sem->count));
+	tmp = atomic_long_dec_return(&sem->count);
 	if (unlikely(tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0))
 		rwsem_wake(sem);
 }
@@ -131,17 +140,17 @@ static inline void __up_read(struct rw_semaphore *sem)
  */
 static inline void __up_write(struct rw_semaphore *sem)
 {
-	if (unlikely(atomic_sub_return(RWSEM_ACTIVE_WRITE_BIAS,
-			      (atomic_t *)(&sem->count)) < 0))
+	if (unlikely(atomic_long_sub_return(RWSEM_ACTIVE_WRITE_BIAS,
+					    &sem->count) < 0))
 		rwsem_wake(sem);
 }
 
 /*
  * implement atomic add functionality
  */
-static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem)
+static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem)
 {
-	atomic_add(delta, (atomic_t *)(&sem->count));
+	atomic_long_add(delta, &sem->count);
 }
 
 /*
@@ -149,9 +158,9 @@ static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem)
  */
 static inline void __downgrade_write(struct rw_semaphore *sem)
 {
-	int tmp;
+	long tmp;
 
-	tmp = atomic_add_return(-RWSEM_WAITING_BIAS, (atomic_t *)(&sem->count));
+	tmp = atomic_long_add_return(-RWSEM_WAITING_BIAS, &sem->count);
 	if (tmp < 0)
 		rwsem_downgrade_wake(sem);
 }
@@ -159,14 +168,14 @@ static inline void __downgrade_write(struct rw_semaphore *sem)
 /*
  * implement exchange and add functionality
  */
-static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
+static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem)
 {
-	return atomic_add_return(delta, (atomic_t *)(&sem->count));
+	return atomic_long_add_return(delta, &sem->count);
 }
 
 static inline int rwsem_is_locked(struct rw_semaphore *sem)
 {
-	return (sem->count != 0);
+	return atomic_long_read(&sem->count) != 0;
 }
 
 #endif	/* __KERNEL__ */



^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: 64-bit ppc rwsem (was: Re: [GIT] Sparc)
  2010-08-18  4:38       ` 64-bit ppc rwsem (was: Re: [GIT] Sparc) Benjamin Herrenschmidt
@ 2010-08-18  5:03         ` Benjamin Herrenschmidt
  2010-08-18  5:28           ` 64-bit ppc rwsem David Miller
  0 siblings, 1 reply; 25+ messages in thread
From: Benjamin Herrenschmidt @ 2010-08-18  5:03 UTC (permalink / raw)
  To: David Miller
  Cc: torvalds, akpm, sparclinux, linux-kernel, paulus, linuxppc-dev

On Wed, 2010-08-18 at 14:38 +1000, Benjamin Herrenschmidt wrote:
> 
> Here's an untested patch for the folks on linuxppc-dev to look at,
> I'll
> review my own stuff & test tomorrow. 

Allright, gcc's being a pain, and atomics are a struct so we can't that
easily assign.

I tried various tricks but so far they didn't work. I'll have another
look tomorrow, but I may end up having to keep all the crap typecasts.

Cheers,
Ben.



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: 64-bit ppc rwsem
  2010-08-18  5:03         ` Benjamin Herrenschmidt
@ 2010-08-18  5:28           ` David Miller
  2010-08-18  5:39             ` Sam Ravnborg
  2010-08-19  5:23             ` Benjamin Herrenschmidt
  0 siblings, 2 replies; 25+ messages in thread
From: David Miller @ 2010-08-18  5:28 UTC (permalink / raw)
  To: benh; +Cc: torvalds, akpm, sparclinux, linux-kernel, paulus, linuxppc-dev

From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date: Wed, 18 Aug 2010 15:03:23 +1000

> I tried various tricks but so far they didn't work. I'll have another
> look tomorrow, but I may end up having to keep all the crap typecasts.

The casts are pretty much unavoidable.

Here's what I'm going to end up using on sparc64:

--------------------
sparc64: Make rwsems 64-bit.

Basically tip-off the powerpc code, use a 64-bit type and atomic64_t
interfaces for the implementation.

This gets us off of the by-hand asm code I wrote, which frankly I
think probably ruins I-cache hit rates.

The idea was the keep the call chains less deep, but anything taking
the rw-semaphores probably is also calling other stuff and therefore
already has allocated a stack-frame.  So no real stack frame savings
ever.

Ben H. has posted patches to make powerpc use 64-bit too and with some
abstractions we can probably use a shared header file somewhere.

Signed-off-by: David S. Miller <davem@davemloft.net>
---
 arch/sparc/include/asm/rwsem-const.h |   12 ---
 arch/sparc/include/asm/rwsem.h       |  120 +++++++++++++++++++++----
 arch/sparc/lib/Makefile              |    2 +-
 arch/sparc/lib/rwsem_64.S            |  163 ----------------------------------
 4 files changed, 104 insertions(+), 193 deletions(-)
 delete mode 100644 arch/sparc/include/asm/rwsem-const.h
 delete mode 100644 arch/sparc/lib/rwsem_64.S

diff --git a/arch/sparc/include/asm/rwsem-const.h b/arch/sparc/include/asm/rwsem-const.h
deleted file mode 100644
index e4c61a1..0000000
--- a/arch/sparc/include/asm/rwsem-const.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* rwsem-const.h: RW semaphore counter constants.  */
-#ifndef _SPARC64_RWSEM_CONST_H
-#define _SPARC64_RWSEM_CONST_H
-
-#define RWSEM_UNLOCKED_VALUE		0x00000000
-#define RWSEM_ACTIVE_BIAS		0x00000001
-#define RWSEM_ACTIVE_MASK		0x0000ffff
-#define RWSEM_WAITING_BIAS		(-0x00010000)
-#define RWSEM_ACTIVE_READ_BIAS		RWSEM_ACTIVE_BIAS
-#define RWSEM_ACTIVE_WRITE_BIAS		(RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
-
-#endif /* _SPARC64_RWSEM_CONST_H */
diff --git a/arch/sparc/include/asm/rwsem.h b/arch/sparc/include/asm/rwsem.h
index 6e56210..a2b4302 100644
--- a/arch/sparc/include/asm/rwsem.h
+++ b/arch/sparc/include/asm/rwsem.h
@@ -15,16 +15,21 @@
 
 #include <linux/list.h>
 #include <linux/spinlock.h>
-#include <asm/rwsem-const.h>
 
 struct rwsem_waiter;
 
 struct rw_semaphore {
-	signed int count;
-	spinlock_t		wait_lock;
-	struct list_head	wait_list;
+	signed long			count;
+#define RWSEM_UNLOCKED_VALUE		0x00000000L
+#define RWSEM_ACTIVE_BIAS		0x00000001L
+#define RWSEM_ACTIVE_MASK		0xffffffffL
+#define RWSEM_WAITING_BIAS		(-RWSEM_ACTIVE_MASK-1)
+#define RWSEM_ACTIVE_READ_BIAS		RWSEM_ACTIVE_BIAS
+#define RWSEM_ACTIVE_WRITE_BIAS		(RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
+	spinlock_t			wait_lock;
+	struct list_head		wait_list;
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
-	struct lockdep_map	dep_map;
+	struct lockdep_map		dep_map;
 #endif
 };
 
@@ -41,6 +46,11 @@ struct rw_semaphore {
 #define DECLARE_RWSEM(name) \
 	struct rw_semaphore name = __RWSEM_INITIALIZER(name)
 
+extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem);
+
 extern void __init_rwsem(struct rw_semaphore *sem, const char *name,
 			 struct lock_class_key *key);
 
@@ -51,27 +61,103 @@ do {								\
 	__init_rwsem((sem), #sem, &__key);			\
 } while (0)
 
-extern void __down_read(struct rw_semaphore *sem);
-extern int __down_read_trylock(struct rw_semaphore *sem);
-extern void __down_write(struct rw_semaphore *sem);
-extern int __down_write_trylock(struct rw_semaphore *sem);
-extern void __up_read(struct rw_semaphore *sem);
-extern void __up_write(struct rw_semaphore *sem);
-extern void __downgrade_write(struct rw_semaphore *sem);
+/*
+ * lock for reading
+ */
+static inline void __down_read(struct rw_semaphore *sem)
+{
+	if (unlikely(atomic64_inc_return((atomic64_t *)(&sem->count)) <= 0L))
+		rwsem_down_read_failed(sem);
+}
+
+static inline int __down_read_trylock(struct rw_semaphore *sem)
+{
+	long tmp;
+
+	while ((tmp = sem->count) >= 0L) {
+		if (tmp == cmpxchg(&sem->count, tmp,
+				   tmp + RWSEM_ACTIVE_READ_BIAS)) {
+			return 1;
+		}
+	}
+	return 0;
+}
 
+/*
+ * lock for writing
+ */
 static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
 {
-	__down_write(sem);
+	long tmp;
+
+	tmp = atomic64_add_return(RWSEM_ACTIVE_WRITE_BIAS,
+				  (atomic64_t *)(&sem->count));
+	if (unlikely(tmp != RWSEM_ACTIVE_WRITE_BIAS))
+		rwsem_down_write_failed(sem);
 }
 
-static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
+static inline void __down_write(struct rw_semaphore *sem)
 {
-	return atomic_add_return(delta, (atomic_t *)(&sem->count));
+	__down_write_nested(sem, 0);
+}
+
+static inline int __down_write_trylock(struct rw_semaphore *sem)
+{
+	long tmp;
+
+	tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
+		      RWSEM_ACTIVE_WRITE_BIAS);
+	return tmp == RWSEM_UNLOCKED_VALUE;
 }
 
-static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem)
+/*
+ * unlock after reading
+ */
+static inline void __up_read(struct rw_semaphore *sem)
+{
+	long tmp;
+
+	tmp = atomic64_dec_return((atomic64_t *)(&sem->count));
+	if (unlikely(tmp < -1L && (tmp & RWSEM_ACTIVE_MASK) == 0L))
+		rwsem_wake(sem);
+}
+
+/*
+ * unlock after writing
+ */
+static inline void __up_write(struct rw_semaphore *sem)
+{
+	if (unlikely(atomic64_sub_return(RWSEM_ACTIVE_WRITE_BIAS,
+					 (atomic64_t *)(&sem->count)) < 0L))
+		rwsem_wake(sem);
+}
+
+/*
+ * implement atomic add functionality
+ */
+static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem)
+{
+	atomic64_add(delta, (atomic64_t *)(&sem->count));
+}
+
+/*
+ * downgrade write lock to read lock
+ */
+static inline void __downgrade_write(struct rw_semaphore *sem)
+{
+	long tmp;
+
+	tmp = atomic64_add_return(-RWSEM_WAITING_BIAS, (atomic64_t *)(&sem->count));
+	if (tmp < 0L)
+		rwsem_downgrade_wake(sem);
+}
+
+/*
+ * implement exchange and add functionality
+ */
+static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem)
 {
-	atomic_add(delta, (atomic_t *)(&sem->count));
+	return atomic64_add_return(delta, (atomic64_t *)(&sem->count));
 }
 
 static inline int rwsem_is_locked(struct rw_semaphore *sem)
diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile
index c4b5e03..fa4c3ea 100644
--- a/arch/sparc/lib/Makefile
+++ b/arch/sparc/lib/Makefile
@@ -15,7 +15,7 @@ lib-$(CONFIG_SPARC32) += divdi3.o udivdi3.o
 lib-$(CONFIG_SPARC32) += copy_user.o locks.o
 lib-y                 += atomic_$(BITS).o
 lib-$(CONFIG_SPARC32) += lshrdi3.o ashldi3.o
-lib-y                 += rwsem_$(BITS).o
+lib-$(CONFIG_SPARC32) += rwsem_$(BITS).o
 lib-$(CONFIG_SPARC32) += muldi3.o bitext.o cmpdi2.o
 
 lib-$(CONFIG_SPARC64) += copy_page.o clear_page.o bzero.o
diff --git a/arch/sparc/lib/rwsem_64.S b/arch/sparc/lib/rwsem_64.S
deleted file mode 100644
index 91a7d29..0000000
--- a/arch/sparc/lib/rwsem_64.S
+++ /dev/null
@@ -1,163 +0,0 @@
-/* rwsem.S: RW semaphore assembler.
- *
- * Written by David S. Miller (davem@redhat.com), 2001.
- * Derived from asm-i386/rwsem.h
- */
-
-#include <asm/rwsem-const.h>
-
-	.section	.sched.text, "ax"
-
-	.globl		__down_read
-__down_read:
-1:	lduw		[%o0], %g1
-	add		%g1, 1, %g7
-	cas		[%o0], %g1, %g7
-	cmp		%g1, %g7
-	bne,pn		%icc, 1b
-	 add		%g7, 1, %g7
-	cmp		%g7, 0
-	bl,pn		%icc, 3f
-	 nop
-2:
-	retl
-	 nop
-3:
-	save		%sp, -192, %sp
-	call		rwsem_down_read_failed
-	 mov		%i0, %o0
-	ret
-	 restore
-	.size		__down_read, .-__down_read
-
-	.globl		__down_read_trylock
-__down_read_trylock:
-1:	lduw		[%o0], %g1
-	add		%g1, 1, %g7
-	cmp		%g7, 0
-	bl,pn		%icc, 2f
-	 mov		0, %o1
-	cas		[%o0], %g1, %g7
-	cmp		%g1, %g7
-	bne,pn		%icc, 1b
-	 mov		1, %o1
-2:	retl
-	 mov		%o1, %o0
-	.size		__down_read_trylock, .-__down_read_trylock
-
-	.globl		__down_write
-__down_write:
-	sethi		%hi(RWSEM_ACTIVE_WRITE_BIAS), %g1
-	or		%g1, %lo(RWSEM_ACTIVE_WRITE_BIAS), %g1
-1:
-	lduw		[%o0], %g3
-	add		%g3, %g1, %g7
-	cas		[%o0], %g3, %g7
-	cmp		%g3, %g7
-	bne,pn		%icc, 1b
-	 cmp		%g7, 0
-	bne,pn		%icc, 3f
-	 nop
-2:	retl
-	 nop
-3:
-	save		%sp, -192, %sp
-	call		rwsem_down_write_failed
-	 mov		%i0, %o0
-	ret
-	 restore
-	.size		__down_write, .-__down_write
-
-	.globl		__down_write_trylock
-__down_write_trylock:
-	sethi		%hi(RWSEM_ACTIVE_WRITE_BIAS), %g1
-	or		%g1, %lo(RWSEM_ACTIVE_WRITE_BIAS), %g1
-1:
-	lduw		[%o0], %g3
-	cmp		%g3, 0
-	bne,pn		%icc, 2f
-	 mov		0, %o1
-	add		%g3, %g1, %g7
-	cas		[%o0], %g3, %g7
-	cmp		%g3, %g7
-	bne,pn		%icc, 1b
-	 mov		1, %o1
-2:	retl
-	 mov		%o1, %o0
-	.size		__down_write_trylock, .-__down_write_trylock
-
-	.globl		__up_read
-__up_read:
-1:
-	lduw		[%o0], %g1
-	sub		%g1, 1, %g7
-	cas		[%o0], %g1, %g7
-	cmp		%g1, %g7
-	bne,pn		%icc, 1b
-	 cmp		%g7, 0
-	bl,pn		%icc, 3f
-	 nop
-2:	retl
-	 nop
-3:	sethi		%hi(RWSEM_ACTIVE_MASK), %g1
-	sub		%g7, 1, %g7
-	or		%g1, %lo(RWSEM_ACTIVE_MASK), %g1
-	andcc		%g7, %g1, %g0
-	bne,pn		%icc, 2b
-	 nop
-	save		%sp, -192, %sp
-	call		rwsem_wake
-	 mov		%i0, %o0
-	ret
-	 restore
-	.size		__up_read, .-__up_read
-
-	.globl		__up_write
-__up_write:
-	sethi		%hi(RWSEM_ACTIVE_WRITE_BIAS), %g1
-	or		%g1, %lo(RWSEM_ACTIVE_WRITE_BIAS), %g1
-1:
-	lduw		[%o0], %g3
-	sub		%g3, %g1, %g7
-	cas		[%o0], %g3, %g7
-	cmp		%g3, %g7
-	bne,pn		%icc, 1b
-	 sub		%g7, %g1, %g7
-	cmp		%g7, 0
-	bl,pn		%icc, 3f
-	 nop
-2:
-	retl
-	 nop
-3:
-	save		%sp, -192, %sp
-	call		rwsem_wake
-	 mov		%i0, %o0
-	ret
-	 restore
-	.size		__up_write, .-__up_write
-
-	.globl		__downgrade_write
-__downgrade_write:
-	sethi		%hi(RWSEM_WAITING_BIAS), %g1
-	or		%g1, %lo(RWSEM_WAITING_BIAS), %g1
-1:
-	lduw		[%o0], %g3
-	sub		%g3, %g1, %g7
-	cas		[%o0], %g3, %g7
-	cmp		%g3, %g7
-	bne,pn		%icc, 1b
-	 sub		%g7, %g1, %g7
-	cmp		%g7, 0
-	bl,pn		%icc, 3f
-	 nop
-2:
-	retl
-	 nop
-3:
-	save		%sp, -192, %sp
-	call		rwsem_downgrade_wake
-	 mov		%i0, %o0
-	ret
-	 restore
-	.size		__downgrade_write, .-__downgrade_write
-- 
1.7.2.1


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: 64-bit ppc rwsem
  2010-08-18  5:28           ` 64-bit ppc rwsem David Miller
@ 2010-08-18  5:39             ` Sam Ravnborg
  2010-08-18  5:48               ` David Miller
  2010-08-19  5:23             ` Benjamin Herrenschmidt
  1 sibling, 1 reply; 25+ messages in thread
From: Sam Ravnborg @ 2010-08-18  5:39 UTC (permalink / raw)
  To: David Miller
  Cc: benh, torvalds, akpm, sparclinux, linux-kernel, paulus, linuxppc-dev

> diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile
> index c4b5e03..fa4c3ea 100644
> --- a/arch/sparc/lib/Makefile
> +++ b/arch/sparc/lib/Makefile
> @@ -15,7 +15,7 @@ lib-$(CONFIG_SPARC32) += divdi3.o udivdi3.o
>  lib-$(CONFIG_SPARC32) += copy_user.o locks.o
>  lib-y                 += atomic_$(BITS).o
>  lib-$(CONFIG_SPARC32) += lshrdi3.o ashldi3.o
> -lib-y                 += rwsem_$(BITS).o
> +lib-$(CONFIG_SPARC32) += rwsem_$(BITS).o

You could write this explicit as:

> +lib-$(CONFIG_SPARC32) += rwsem_32.o

As rwsem_64 is gone now.

	Sam

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: 64-bit ppc rwsem
  2010-08-18  5:39             ` Sam Ravnborg
@ 2010-08-18  5:48               ` David Miller
  0 siblings, 0 replies; 25+ messages in thread
From: David Miller @ 2010-08-18  5:48 UTC (permalink / raw)
  To: sam; +Cc: benh, torvalds, akpm, sparclinux, linux-kernel, paulus, linuxppc-dev

From: Sam Ravnborg <sam@ravnborg.org>
Date: Wed, 18 Aug 2010 07:39:55 +0200

>> @@ -15,7 +15,7 @@ lib-$(CONFIG_SPARC32) += divdi3.o udivdi3.o
>>  lib-$(CONFIG_SPARC32) += copy_user.o locks.o
>>  lib-y                 += atomic_$(BITS).o
>>  lib-$(CONFIG_SPARC32) += lshrdi3.o ashldi3.o
>> -lib-y                 += rwsem_$(BITS).o
>> +lib-$(CONFIG_SPARC32) += rwsem_$(BITS).o
> 
> You could write this explicit as:
> 
>> +lib-$(CONFIG_SPARC32) += rwsem_32.o
> 
> As rwsem_64 is gone now.

Sure, I'll make that change, thanks Sam.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: 64-bit ppc rwsem
  2010-08-18  5:28           ` 64-bit ppc rwsem David Miller
  2010-08-18  5:39             ` Sam Ravnborg
@ 2010-08-19  5:23             ` Benjamin Herrenschmidt
  2010-08-19  5:29               ` David Miller
  1 sibling, 1 reply; 25+ messages in thread
From: Benjamin Herrenschmidt @ 2010-08-19  5:23 UTC (permalink / raw)
  To: David Miller
  Cc: torvalds, akpm, sparclinux, linux-kernel, paulus, linuxppc-dev

On Tue, 2010-08-17 at 22:28 -0700, David Miller wrote:
> From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> Date: Wed, 18 Aug 2010 15:03:23 +1000
> 
> > I tried various tricks but so far they didn't work. I'll have another
> > look tomorrow, but I may end up having to keep all the crap typecasts.
> 
> The casts are pretty much unavoidable.
> 
> Here's what I'm going to end up using on sparc64:

Similar here, but using atomic_long_t instead so it works for 32-bit too
for me. I suppose we could make that part common indeed.

What about asm-generic/rwsem-atomic.h  or rwsem-cmpxchg.h ?

Below is my current patch, seems to boot fine here so far.

Cheers,
Ben

Subject: [PATCH] powerpc: Make rwsem use "long" type

This makes the 64-bit kernel use 64-bit signed integers for the counter
(effectively supporting 32-bit of active count in the semaphore), thus
avoiding things like overflow of the mmap_sem if you use a really crazy
number of threads

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 arch/powerpc/include/asm/rwsem.h |   64 ++++++++++++++++++++++----------------
 1 files changed, 37 insertions(+), 27 deletions(-)

diff --git a/arch/powerpc/include/asm/rwsem.h b/arch/powerpc/include/asm/rwsem.h
index 24cd928..8447d89 100644
--- a/arch/powerpc/include/asm/rwsem.h
+++ b/arch/powerpc/include/asm/rwsem.h
@@ -21,15 +21,20 @@
 /*
  * the semaphore definition
  */
-struct rw_semaphore {
-	/* XXX this should be able to be an atomic_t  -- paulus */
-	signed int		count;
-#define RWSEM_UNLOCKED_VALUE		0x00000000
-#define RWSEM_ACTIVE_BIAS		0x00000001
-#define RWSEM_ACTIVE_MASK		0x0000ffff
-#define RWSEM_WAITING_BIAS		(-0x00010000)
+#ifdef CONFIG_PPC64
+# define RWSEM_ACTIVE_MASK		0xffffffffL
+#else
+# define RWSEM_ACTIVE_MASK		0x0000ffffL
+#endif
+
+#define RWSEM_UNLOCKED_VALUE		0x00000000L
+#define RWSEM_ACTIVE_BIAS		0x00000001L
+#define RWSEM_WAITING_BIAS		(-RWSEM_ACTIVE_MASK-1)
 #define RWSEM_ACTIVE_READ_BIAS		RWSEM_ACTIVE_BIAS
 #define RWSEM_ACTIVE_WRITE_BIAS		(RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
+
+struct rw_semaphore {
+	long			count;
 	spinlock_t		wait_lock;
 	struct list_head	wait_list;
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
@@ -43,9 +48,13 @@ struct rw_semaphore {
 # define __RWSEM_DEP_MAP_INIT(lockname)
 #endif
 
-#define __RWSEM_INITIALIZER(name) \
-	{ RWSEM_UNLOCKED_VALUE, __SPIN_LOCK_UNLOCKED((name).wait_lock), \
-	  LIST_HEAD_INIT((name).wait_list) __RWSEM_DEP_MAP_INIT(name) }
+#define __RWSEM_INITIALIZER(name)				\
+{								\
+	RWSEM_UNLOCKED_VALUE,					\
+	__SPIN_LOCK_UNLOCKED((name).wait_lock),			\
+	LIST_HEAD_INIT((name).wait_list)			\
+	__RWSEM_DEP_MAP_INIT(name)				\
+}
 
 #define DECLARE_RWSEM(name)		\
 	struct rw_semaphore name = __RWSEM_INITIALIZER(name)
@@ -70,13 +79,13 @@ extern void __init_rwsem(struct rw_semaphore *sem, const char *name,
  */
 static inline void __down_read(struct rw_semaphore *sem)
 {
-	if (unlikely(atomic_inc_return((atomic_t *)(&sem->count)) <= 0))
+	if (unlikely(atomic_long_inc_return((atomic_long_t *)&sem->count) <= 0))
 		rwsem_down_read_failed(sem);
 }
 
 static inline int __down_read_trylock(struct rw_semaphore *sem)
 {
-	int tmp;
+	long tmp;
 
 	while ((tmp = sem->count) >= 0) {
 		if (tmp == cmpxchg(&sem->count, tmp,
@@ -92,10 +101,10 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
  */
 static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
 {
-	int tmp;
+	long tmp;
 
-	tmp = atomic_add_return(RWSEM_ACTIVE_WRITE_BIAS,
-				(atomic_t *)(&sem->count));
+	tmp = atomic_long_add_return(RWSEM_ACTIVE_WRITE_BIAS,
+				     (atomic_long_t *)&sem->count);
 	if (unlikely(tmp != RWSEM_ACTIVE_WRITE_BIAS))
 		rwsem_down_write_failed(sem);
 }
@@ -107,7 +116,7 @@ static inline void __down_write(struct rw_semaphore *sem)
 
 static inline int __down_write_trylock(struct rw_semaphore *sem)
 {
-	int tmp;
+	long tmp;
 
 	tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
 		      RWSEM_ACTIVE_WRITE_BIAS);
@@ -119,9 +128,9 @@ static inline int __down_write_trylock(struct rw_semaphore *sem)
  */
 static inline void __up_read(struct rw_semaphore *sem)
 {
-	int tmp;
+	long tmp;
 
-	tmp = atomic_dec_return((atomic_t *)(&sem->count));
+	tmp = atomic_long_dec_return((atomic_long_t *)&sem->count);
 	if (unlikely(tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0))
 		rwsem_wake(sem);
 }
@@ -131,17 +140,17 @@ static inline void __up_read(struct rw_semaphore *sem)
  */
 static inline void __up_write(struct rw_semaphore *sem)
 {
-	if (unlikely(atomic_sub_return(RWSEM_ACTIVE_WRITE_BIAS,
-			      (atomic_t *)(&sem->count)) < 0))
+	if (unlikely(atomic_long_sub_return(RWSEM_ACTIVE_WRITE_BIAS,
+				 (atomic_long_t *)&sem->count) < 0))
 		rwsem_wake(sem);
 }
 
 /*
  * implement atomic add functionality
  */
-static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem)
+static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem)
 {
-	atomic_add(delta, (atomic_t *)(&sem->count));
+	atomic_long_add(delta, (atomic_long_t *)&sem->count);
 }
 
 /*
@@ -149,9 +158,10 @@ static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem)
  */
 static inline void __downgrade_write(struct rw_semaphore *sem)
 {
-	int tmp;
+	long tmp;
 
-	tmp = atomic_add_return(-RWSEM_WAITING_BIAS, (atomic_t *)(&sem->count));
+	tmp = atomic_long_add_return(-RWSEM_WAITING_BIAS,
+				     (atomic_long_t *)&sem->count);
 	if (tmp < 0)
 		rwsem_downgrade_wake(sem);
 }
@@ -159,14 +169,14 @@ static inline void __downgrade_write(struct rw_semaphore *sem)
 /*
  * implement exchange and add functionality
  */
-static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
+static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem)
 {
-	return atomic_add_return(delta, (atomic_t *)(&sem->count));
+	return atomic_long_add_return(delta, (atomic_long_t *)&sem->count);
 }
 
 static inline int rwsem_is_locked(struct rw_semaphore *sem)
 {
-	return (sem->count != 0);
+	return sem->count != 0;
 }
 
 #endif	/* __KERNEL__ */



^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: 64-bit ppc rwsem
  2010-08-19  5:23             ` Benjamin Herrenschmidt
@ 2010-08-19  5:29               ` David Miller
  2010-08-19 10:24                 ` Benjamin Herrenschmidt
                                   ` (3 more replies)
  0 siblings, 4 replies; 25+ messages in thread
From: David Miller @ 2010-08-19  5:29 UTC (permalink / raw)
  To: benh; +Cc: torvalds, akpm, sparclinux, linux-kernel, paulus, linuxppc-dev

From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date: Thu, 19 Aug 2010 15:23:23 +1000

> Similar here, but using atomic_long_t instead so it works for 32-bit too
> for me. I suppose we could make that part common indeed.
> 
> What about asm-generic/rwsem-atomic.h  or rwsem-cmpxchg.h ?

Using rwsem-cmpxchg.h sounds best I guess.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: 64-bit ppc rwsem
  2010-08-19  5:29               ` David Miller
@ 2010-08-19 10:24                 ` Benjamin Herrenschmidt
  2010-08-20  5:14                 ` [PATCH 1/2] powerpc: Make rwsem use "long" type Benjamin Herrenschmidt
                                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 25+ messages in thread
From: Benjamin Herrenschmidt @ 2010-08-19 10:24 UTC (permalink / raw)
  To: David Miller
  Cc: torvalds, akpm, sparclinux, linux-kernel, paulus, linuxppc-dev

On Wed, 2010-08-18 at 22:29 -0700, David Miller wrote:
> From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> Date: Thu, 19 Aug 2010 15:23:23 +1000
> 
> > Similar here, but using atomic_long_t instead so it works for 32-bit too
> > for me. I suppose we could make that part common indeed.
> > 
> > What about asm-generic/rwsem-atomic.h  or rwsem-cmpxchg.h ?
> 
> Using rwsem-cmpxchg.h sounds best I guess.

Ok, I'll send a new patch tomorrow that does that.

Cheers,
Ben.



^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 1/2] powerpc: Make rwsem use "long" type
  2010-08-19  5:29               ` David Miller
  2010-08-19 10:24                 ` Benjamin Herrenschmidt
@ 2010-08-20  5:14                 ` Benjamin Herrenschmidt
  2010-08-24  1:37                   ` Timur Tabi
  2010-08-20  5:14                 ` [PATCH 2/2] rwsem: Move powerpc atomic-long based implementation to asm-generic Benjamin Herrenschmidt
  2010-08-23 13:44                 ` 64-bit ppc rwsem Arnd Bergmann
  3 siblings, 1 reply; 25+ messages in thread
From: Benjamin Herrenschmidt @ 2010-08-20  5:14 UTC (permalink / raw)
  To: torvalds
  Cc: akpm, sparclinux, linux-kernel, paulus, linuxppc-dev, David Miller

This makes the 64-bit kernel use 64-bit signed integers for the counter
(effectively supporting 32-bit of active count in the semaphore), thus
avoiding things like overflow of the mmap_sem if you use a really crazy
number of threads

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 arch/powerpc/include/asm/rwsem.h |   64 ++++++++++++++++++++++----------------
 1 files changed, 37 insertions(+), 27 deletions(-)

diff --git a/arch/powerpc/include/asm/rwsem.h b/arch/powerpc/include/asm/rwsem.h
index 24cd928..8447d89 100644
--- a/arch/powerpc/include/asm/rwsem.h
+++ b/arch/powerpc/include/asm/rwsem.h
@@ -21,15 +21,20 @@
 /*
  * the semaphore definition
  */
-struct rw_semaphore {
-	/* XXX this should be able to be an atomic_t  -- paulus */
-	signed int		count;
-#define RWSEM_UNLOCKED_VALUE		0x00000000
-#define RWSEM_ACTIVE_BIAS		0x00000001
-#define RWSEM_ACTIVE_MASK		0x0000ffff
-#define RWSEM_WAITING_BIAS		(-0x00010000)
+#ifdef CONFIG_PPC64
+# define RWSEM_ACTIVE_MASK		0xffffffffL
+#else
+# define RWSEM_ACTIVE_MASK		0x0000ffffL
+#endif
+
+#define RWSEM_UNLOCKED_VALUE		0x00000000L
+#define RWSEM_ACTIVE_BIAS		0x00000001L
+#define RWSEM_WAITING_BIAS		(-RWSEM_ACTIVE_MASK-1)
 #define RWSEM_ACTIVE_READ_BIAS		RWSEM_ACTIVE_BIAS
 #define RWSEM_ACTIVE_WRITE_BIAS		(RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
+
+struct rw_semaphore {
+	long			count;
 	spinlock_t		wait_lock;
 	struct list_head	wait_list;
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
@@ -43,9 +48,13 @@ struct rw_semaphore {
 # define __RWSEM_DEP_MAP_INIT(lockname)
 #endif
 
-#define __RWSEM_INITIALIZER(name) \
-	{ RWSEM_UNLOCKED_VALUE, __SPIN_LOCK_UNLOCKED((name).wait_lock), \
-	  LIST_HEAD_INIT((name).wait_list) __RWSEM_DEP_MAP_INIT(name) }
+#define __RWSEM_INITIALIZER(name)				\
+{								\
+	RWSEM_UNLOCKED_VALUE,					\
+	__SPIN_LOCK_UNLOCKED((name).wait_lock),			\
+	LIST_HEAD_INIT((name).wait_list)			\
+	__RWSEM_DEP_MAP_INIT(name)				\
+}
 
 #define DECLARE_RWSEM(name)		\
 	struct rw_semaphore name = __RWSEM_INITIALIZER(name)
@@ -70,13 +79,13 @@ extern void __init_rwsem(struct rw_semaphore *sem, const char *name,
  */
 static inline void __down_read(struct rw_semaphore *sem)
 {
-	if (unlikely(atomic_inc_return((atomic_t *)(&sem->count)) <= 0))
+	if (unlikely(atomic_long_inc_return((atomic_long_t *)&sem->count) <= 0))
 		rwsem_down_read_failed(sem);
 }
 
 static inline int __down_read_trylock(struct rw_semaphore *sem)
 {
-	int tmp;
+	long tmp;
 
 	while ((tmp = sem->count) >= 0) {
 		if (tmp == cmpxchg(&sem->count, tmp,
@@ -92,10 +101,10 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
  */
 static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
 {
-	int tmp;
+	long tmp;
 
-	tmp = atomic_add_return(RWSEM_ACTIVE_WRITE_BIAS,
-				(atomic_t *)(&sem->count));
+	tmp = atomic_long_add_return(RWSEM_ACTIVE_WRITE_BIAS,
+				     (atomic_long_t *)&sem->count);
 	if (unlikely(tmp != RWSEM_ACTIVE_WRITE_BIAS))
 		rwsem_down_write_failed(sem);
 }
@@ -107,7 +116,7 @@ static inline void __down_write(struct rw_semaphore *sem)
 
 static inline int __down_write_trylock(struct rw_semaphore *sem)
 {
-	int tmp;
+	long tmp;
 
 	tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
 		      RWSEM_ACTIVE_WRITE_BIAS);
@@ -119,9 +128,9 @@ static inline int __down_write_trylock(struct rw_semaphore *sem)
  */
 static inline void __up_read(struct rw_semaphore *sem)
 {
-	int tmp;
+	long tmp;
 
-	tmp = atomic_dec_return((atomic_t *)(&sem->count));
+	tmp = atomic_long_dec_return((atomic_long_t *)&sem->count);
 	if (unlikely(tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0))
 		rwsem_wake(sem);
 }
@@ -131,17 +140,17 @@ static inline void __up_read(struct rw_semaphore *sem)
  */
 static inline void __up_write(struct rw_semaphore *sem)
 {
-	if (unlikely(atomic_sub_return(RWSEM_ACTIVE_WRITE_BIAS,
-			      (atomic_t *)(&sem->count)) < 0))
+	if (unlikely(atomic_long_sub_return(RWSEM_ACTIVE_WRITE_BIAS,
+				 (atomic_long_t *)&sem->count) < 0))
 		rwsem_wake(sem);
 }
 
 /*
  * implement atomic add functionality
  */
-static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem)
+static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem)
 {
-	atomic_add(delta, (atomic_t *)(&sem->count));
+	atomic_long_add(delta, (atomic_long_t *)&sem->count);
 }
 
 /*
@@ -149,9 +158,10 @@ static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem)
  */
 static inline void __downgrade_write(struct rw_semaphore *sem)
 {
-	int tmp;
+	long tmp;
 
-	tmp = atomic_add_return(-RWSEM_WAITING_BIAS, (atomic_t *)(&sem->count));
+	tmp = atomic_long_add_return(-RWSEM_WAITING_BIAS,
+				     (atomic_long_t *)&sem->count);
 	if (tmp < 0)
 		rwsem_downgrade_wake(sem);
 }
@@ -159,14 +169,14 @@ static inline void __downgrade_write(struct rw_semaphore *sem)
 /*
  * implement exchange and add functionality
  */
-static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
+static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem)
 {
-	return atomic_add_return(delta, (atomic_t *)(&sem->count));
+	return atomic_long_add_return(delta, (atomic_long_t *)&sem->count);
 }
 
 static inline int rwsem_is_locked(struct rw_semaphore *sem)
 {
-	return (sem->count != 0);
+	return sem->count != 0;
 }
 
 #endif	/* __KERNEL__ */



^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 2/2] rwsem: Move powerpc atomic-long based implementation to asm-generic
  2010-08-19  5:29               ` David Miller
  2010-08-19 10:24                 ` Benjamin Herrenschmidt
  2010-08-20  5:14                 ` [PATCH 1/2] powerpc: Make rwsem use "long" type Benjamin Herrenschmidt
@ 2010-08-20  5:14                 ` Benjamin Herrenschmidt
  2010-08-20  6:43                   ` Sam Ravnborg
  2010-08-23  4:39                   ` David Miller
  2010-08-23 13:44                 ` 64-bit ppc rwsem Arnd Bergmann
  3 siblings, 2 replies; 25+ messages in thread
From: Benjamin Herrenschmidt @ 2010-08-20  5:14 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: akpm, sparclinux, linux-kernel, paulus, linuxppc-dev, David Miller

Other architectures who support cmpxchg and atomic_long can
use that directly.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 arch/powerpc/include/asm/rwsem.h    |  184 +----------------------------------
 include/asm-generic/rwsem-cmpxchg.h |  183 ++++++++++++++++++++++++++++++++++
 2 files changed, 184 insertions(+), 183 deletions(-)
 create mode 100644 include/asm-generic/rwsem-cmpxchg.h

diff --git a/arch/powerpc/include/asm/rwsem.h b/arch/powerpc/include/asm/rwsem.h
index 8447d89..1237ad6 100644
--- a/arch/powerpc/include/asm/rwsem.h
+++ b/arch/powerpc/include/asm/rwsem.h
@@ -1,183 +1 @@
-#ifndef _ASM_POWERPC_RWSEM_H
-#define _ASM_POWERPC_RWSEM_H
-
-#ifndef _LINUX_RWSEM_H
-#error "Please don't include <asm/rwsem.h> directly, use <linux/rwsem.h> instead."
-#endif
-
-#ifdef __KERNEL__
-
-/*
- * R/W semaphores for PPC using the stuff in lib/rwsem.c.
- * Adapted largely from include/asm-i386/rwsem.h
- * by Paul Mackerras <paulus@samba.org>.
- */
-
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <asm/atomic.h>
-#include <asm/system.h>
-
-/*
- * the semaphore definition
- */
-#ifdef CONFIG_PPC64
-# define RWSEM_ACTIVE_MASK		0xffffffffL
-#else
-# define RWSEM_ACTIVE_MASK		0x0000ffffL
-#endif
-
-#define RWSEM_UNLOCKED_VALUE		0x00000000L
-#define RWSEM_ACTIVE_BIAS		0x00000001L
-#define RWSEM_WAITING_BIAS		(-RWSEM_ACTIVE_MASK-1)
-#define RWSEM_ACTIVE_READ_BIAS		RWSEM_ACTIVE_BIAS
-#define RWSEM_ACTIVE_WRITE_BIAS		(RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
-
-struct rw_semaphore {
-	long			count;
-	spinlock_t		wait_lock;
-	struct list_head	wait_list;
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-	struct lockdep_map	dep_map;
-#endif
-};
-
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-# define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname }
-#else
-# define __RWSEM_DEP_MAP_INIT(lockname)
-#endif
-
-#define __RWSEM_INITIALIZER(name)				\
-{								\
-	RWSEM_UNLOCKED_VALUE,					\
-	__SPIN_LOCK_UNLOCKED((name).wait_lock),			\
-	LIST_HEAD_INIT((name).wait_list)			\
-	__RWSEM_DEP_MAP_INIT(name)				\
-}
-
-#define DECLARE_RWSEM(name)		\
-	struct rw_semaphore name = __RWSEM_INITIALIZER(name)
-
-extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
-extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
-extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem);
-extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem);
-
-extern void __init_rwsem(struct rw_semaphore *sem, const char *name,
-			 struct lock_class_key *key);
-
-#define init_rwsem(sem)					\
-	do {						\
-		static struct lock_class_key __key;	\
-							\
-		__init_rwsem((sem), #sem, &__key);	\
-	} while (0)
-
-/*
- * lock for reading
- */
-static inline void __down_read(struct rw_semaphore *sem)
-{
-	if (unlikely(atomic_long_inc_return((atomic_long_t *)&sem->count) <= 0))
-		rwsem_down_read_failed(sem);
-}
-
-static inline int __down_read_trylock(struct rw_semaphore *sem)
-{
-	long tmp;
-
-	while ((tmp = sem->count) >= 0) {
-		if (tmp == cmpxchg(&sem->count, tmp,
-				   tmp + RWSEM_ACTIVE_READ_BIAS)) {
-			return 1;
-		}
-	}
-	return 0;
-}
-
-/*
- * lock for writing
- */
-static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
-{
-	long tmp;
-
-	tmp = atomic_long_add_return(RWSEM_ACTIVE_WRITE_BIAS,
-				     (atomic_long_t *)&sem->count);
-	if (unlikely(tmp != RWSEM_ACTIVE_WRITE_BIAS))
-		rwsem_down_write_failed(sem);
-}
-
-static inline void __down_write(struct rw_semaphore *sem)
-{
-	__down_write_nested(sem, 0);
-}
-
-static inline int __down_write_trylock(struct rw_semaphore *sem)
-{
-	long tmp;
-
-	tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
-		      RWSEM_ACTIVE_WRITE_BIAS);
-	return tmp == RWSEM_UNLOCKED_VALUE;
-}
-
-/*
- * unlock after reading
- */
-static inline void __up_read(struct rw_semaphore *sem)
-{
-	long tmp;
-
-	tmp = atomic_long_dec_return((atomic_long_t *)&sem->count);
-	if (unlikely(tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0))
-		rwsem_wake(sem);
-}
-
-/*
- * unlock after writing
- */
-static inline void __up_write(struct rw_semaphore *sem)
-{
-	if (unlikely(atomic_long_sub_return(RWSEM_ACTIVE_WRITE_BIAS,
-				 (atomic_long_t *)&sem->count) < 0))
-		rwsem_wake(sem);
-}
-
-/*
- * implement atomic add functionality
- */
-static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem)
-{
-	atomic_long_add(delta, (atomic_long_t *)&sem->count);
-}
-
-/*
- * downgrade write lock to read lock
- */
-static inline void __downgrade_write(struct rw_semaphore *sem)
-{
-	long tmp;
-
-	tmp = atomic_long_add_return(-RWSEM_WAITING_BIAS,
-				     (atomic_long_t *)&sem->count);
-	if (tmp < 0)
-		rwsem_downgrade_wake(sem);
-}
-
-/*
- * implement exchange and add functionality
- */
-static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem)
-{
-	return atomic_long_add_return(delta, (atomic_long_t *)&sem->count);
-}
-
-static inline int rwsem_is_locked(struct rw_semaphore *sem)
-{
-	return sem->count != 0;
-}
-
-#endif	/* __KERNEL__ */
-#endif	/* _ASM_POWERPC_RWSEM_H */
+#include <asm-generic/rwsem-cmpxchg.h>
diff --git a/include/asm-generic/rwsem-cmpxchg.h b/include/asm-generic/rwsem-cmpxchg.h
new file mode 100644
index 0000000..2b1c859
--- /dev/null
+++ b/include/asm-generic/rwsem-cmpxchg.h
@@ -0,0 +1,183 @@
+#ifndef _RWSEM_CMPXCHG_H
+#define _RWSEM_CMPXCHG_H
+
+#ifndef _LINUX_RWSEM_H
+#error "Please don't include <asm/rwsem.h> directly, use <linux/rwsem.h> instead."
+#endif
+
+#ifdef __KERNEL__
+
+/*
+ * Generic R/W semaphores the stuff in lib/rwsem.c.
+ * Adapted largely from include/asm-i386/rwsem.h
+ * by Paul Mackerras <paulus@samba.org>.
+ */
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+#include <asm/system.h>
+
+/*
+ * the semaphore definition
+ */
+#if BITS_PER_LONG == 64
+# define RWSEM_ACTIVE_MASK		0xffffffffL
+#else
+# define RWSEM_ACTIVE_MASK		0x0000ffffL
+#endif
+
+#define RWSEM_UNLOCKED_VALUE		0x00000000L
+#define RWSEM_ACTIVE_BIAS		0x00000001L
+#define RWSEM_WAITING_BIAS		(-RWSEM_ACTIVE_MASK-1)
+#define RWSEM_ACTIVE_READ_BIAS		RWSEM_ACTIVE_BIAS
+#define RWSEM_ACTIVE_WRITE_BIAS		(RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
+
+struct rw_semaphore {
+	long			count;
+	spinlock_t		wait_lock;
+	struct list_head	wait_list;
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+	struct lockdep_map	dep_map;
+#endif
+};
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+# define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname }
+#else
+# define __RWSEM_DEP_MAP_INIT(lockname)
+#endif
+
+#define __RWSEM_INITIALIZER(name)				\
+{								\
+	RWSEM_UNLOCKED_VALUE,					\
+	__SPIN_LOCK_UNLOCKED((name).wait_lock),			\
+	LIST_HEAD_INIT((name).wait_list)			\
+	__RWSEM_DEP_MAP_INIT(name)				\
+}
+
+#define DECLARE_RWSEM(name)		\
+	struct rw_semaphore name = __RWSEM_INITIALIZER(name)
+
+extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem);
+
+extern void __init_rwsem(struct rw_semaphore *sem, const char *name,
+			 struct lock_class_key *key);
+
+#define init_rwsem(sem)					\
+	do {						\
+		static struct lock_class_key __key;	\
+							\
+		__init_rwsem((sem), #sem, &__key);	\
+	} while (0)
+
+/*
+ * lock for reading
+ */
+static inline void __down_read(struct rw_semaphore *sem)
+{
+	if (unlikely(atomic_long_inc_return((atomic_long_t *)&sem->count) <= 0))
+		rwsem_down_read_failed(sem);
+}
+
+static inline int __down_read_trylock(struct rw_semaphore *sem)
+{
+	long tmp;
+
+	while ((tmp = sem->count) >= 0) {
+		if (tmp == cmpxchg(&sem->count, tmp,
+				   tmp + RWSEM_ACTIVE_READ_BIAS)) {
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * lock for writing
+ */
+static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
+{
+	long tmp;
+
+	tmp = atomic_long_add_return(RWSEM_ACTIVE_WRITE_BIAS,
+				     (atomic_long_t *)&sem->count);
+	if (unlikely(tmp != RWSEM_ACTIVE_WRITE_BIAS))
+		rwsem_down_write_failed(sem);
+}
+
+static inline void __down_write(struct rw_semaphore *sem)
+{
+	__down_write_nested(sem, 0);
+}
+
+static inline int __down_write_trylock(struct rw_semaphore *sem)
+{
+	long tmp;
+
+	tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
+		      RWSEM_ACTIVE_WRITE_BIAS);
+	return tmp == RWSEM_UNLOCKED_VALUE;
+}
+
+/*
+ * unlock after reading
+ */
+static inline void __up_read(struct rw_semaphore *sem)
+{
+	long tmp;
+
+	tmp = atomic_long_dec_return((atomic_long_t *)&sem->count);
+	if (unlikely(tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0))
+		rwsem_wake(sem);
+}
+
+/*
+ * unlock after writing
+ */
+static inline void __up_write(struct rw_semaphore *sem)
+{
+	if (unlikely(atomic_long_sub_return(RWSEM_ACTIVE_WRITE_BIAS,
+				 (atomic_long_t *)&sem->count) < 0))
+		rwsem_wake(sem);
+}
+
+/*
+ * implement atomic add functionality
+ */
+static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem)
+{
+	atomic_long_add(delta, (atomic_long_t *)&sem->count);
+}
+
+/*
+ * downgrade write lock to read lock
+ */
+static inline void __downgrade_write(struct rw_semaphore *sem)
+{
+	long tmp;
+
+	tmp = atomic_long_add_return(-RWSEM_WAITING_BIAS,
+				     (atomic_long_t *)&sem->count);
+	if (tmp < 0)
+		rwsem_downgrade_wake(sem);
+}
+
+/*
+ * implement exchange and add functionality
+ */
+static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem)
+{
+	return atomic_long_add_return(delta, (atomic_long_t *)&sem->count);
+}
+
+static inline int rwsem_is_locked(struct rw_semaphore *sem)
+{
+	return sem->count != 0;
+}
+
+#endif	/* __KERNEL__ */
+#endif	/* _RWSEM_CMPXCHG_H */



^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH 2/2] rwsem: Move powerpc atomic-long based implementation to asm-generic
  2010-08-20  5:14                 ` [PATCH 2/2] rwsem: Move powerpc atomic-long based implementation to asm-generic Benjamin Herrenschmidt
@ 2010-08-20  6:43                   ` Sam Ravnborg
  2010-08-24  1:32                     ` Benjamin Herrenschmidt
  2010-08-23  4:39                   ` David Miller
  1 sibling, 1 reply; 25+ messages in thread
From: Sam Ravnborg @ 2010-08-20  6:43 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Linus Torvalds, akpm, sparclinux, linux-kernel, paulus,
	linuxppc-dev, David Miller

> diff --git a/include/asm-generic/rwsem-cmpxchg.h b/include/asm-generic/rwsem-cmpxchg.h
> new file mode 100644
> index 0000000..2b1c859
> --- /dev/null
> +++ b/include/asm-generic/rwsem-cmpxchg.h
> @@ -0,0 +1,183 @@
> +#ifndef _RWSEM_CMPXCHG_H
> +#define _RWSEM_CMPXCHG_H
> +
> +#ifndef _LINUX_RWSEM_H
> +#error "Please don't include <asm/rwsem.h> directly, use <linux/rwsem.h> instead."
> +#endif
> +
> +#ifdef __KERNEL__

#ifdef __KERNEL__ is only relevant for exported headers.
For kernel only headers like this is does not make sense,
but it does not harm.

	Sam

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 2/2] rwsem: Move powerpc atomic-long based implementation to asm-generic
  2010-08-20  5:14                 ` [PATCH 2/2] rwsem: Move powerpc atomic-long based implementation to asm-generic Benjamin Herrenschmidt
  2010-08-20  6:43                   ` Sam Ravnborg
@ 2010-08-23  4:39                   ` David Miller
  1 sibling, 0 replies; 25+ messages in thread
From: David Miller @ 2010-08-23  4:39 UTC (permalink / raw)
  To: benh; +Cc: torvalds, akpm, sparclinux, linux-kernel, paulus, linuxppc-dev

From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date: Fri, 20 Aug 2010 15:14:55 +1000

> Other architectures who support cmpxchg and atomic_long can
> use that directly.
> 
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

Acked-by: David S. Miller <davem@davemloft.net>

I'll move sparc64 over to this once it hits Linus's tree.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: 64-bit ppc rwsem
  2010-08-19  5:29               ` David Miller
                                   ` (2 preceding siblings ...)
  2010-08-20  5:14                 ` [PATCH 2/2] rwsem: Move powerpc atomic-long based implementation to asm-generic Benjamin Herrenschmidt
@ 2010-08-23 13:44                 ` Arnd Bergmann
  2010-08-23 22:01                   ` Benjamin Herrenschmidt
  3 siblings, 1 reply; 25+ messages in thread
From: Arnd Bergmann @ 2010-08-23 13:44 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: David Miller, benh, torvalds, paulus, linux-kernel, sparclinux, akpm

On Thursday 19 August 2010, David Miller wrote:
> From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> Date: Thu, 19 Aug 2010 15:23:23 +1000
> 
> > Similar here, but using atomic_long_t instead so it works for 32-bit too
> > for me. I suppose we could make that part common indeed.
> > 
> > What about asm-generic/rwsem-atomic.h  or rwsem-cmpxchg.h ?
> 
> Using rwsem-cmpxchg.h sounds best I guess.

The implementation looks good for asm-generic, but there is now an asymmetry
between the spinlock and the atomic_long_t based version.

Maybe we can make them both do the same thing, either of

1. create include/linux/rwsem-cmpxchg.h and add an
   #elif defined(CONFIG_RWSEM_GENERIC_ATOMIC) to include/linux/rwsem.h

2. move include/linux/rwsem-spinlock.h to include/asm-generic/ and
   include that from all architectures that want the spinlock based version.

Further comments:

* Alpha has an optimization for the uniprocessor case, where the atomic
instructions get turned into nonatomic additions. The spinlock based
version uses no locks on UP but disables interrupts for reasons I don't
understand (nothing running at interrupt time should try to access an rwsem).
Should the generic version do the same as Alpha?

* Is there any architecture that would still benefit from having a separate
rwsem implementation? AFAICT all the remaining ones are just variations of
the same concept of using cmpxchg (or xadd in case of x86), which is what
atomics typically end up doing anyway.

	Arnd

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: 64-bit ppc rwsem
  2010-08-23 13:44                 ` 64-bit ppc rwsem Arnd Bergmann
@ 2010-08-23 22:01                   ` Benjamin Herrenschmidt
  2010-08-23 22:18                     ` David Miller
  0 siblings, 1 reply; 25+ messages in thread
From: Benjamin Herrenschmidt @ 2010-08-23 22:01 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linuxppc-dev, David Miller, torvalds, paulus, linux-kernel,
	sparclinux, akpm

On Mon, 2010-08-23 at 15:44 +0200, Arnd Bergmann wrote:
> 
> * Alpha has an optimization for the uniprocessor case, where the atomic
> instructions get turned into nonatomic additions. The spinlock based
> version uses no locks on UP but disables interrupts for reasons I don't
> understand (nothing running at interrupt time should try to access an rwsem).
> Should the generic version do the same as Alpha?

I've seen drivers in the past do trylocks at interrupt time ... tho I
agree it sucks.

> * Is there any architecture that would still benefit from having a separate
> rwsem implementation? AFAICT all the remaining ones are just variations of
> the same concept of using cmpxchg (or xadd in case of x86), which is what
> atomics typically end up doing anyway.

It depends how sensitive rwsems are. 

The "generic" variant based on atomic's and cmpxchg on powerpc is
sub-optimal in the sense that it has stronger memory barriers that would
be necessary (atomic_inc_return for example has both acquire and
release).

But that vs. one more pile of inline asm, we decided it wasn't hot
enough a spot for us to care back then.

Cheers,
Ben.


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: 64-bit ppc rwsem
  2010-08-23 22:01                   ` Benjamin Herrenschmidt
@ 2010-08-23 22:18                     ` David Miller
  2010-08-24  1:31                       ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 25+ messages in thread
From: David Miller @ 2010-08-23 22:18 UTC (permalink / raw)
  To: benh; +Cc: arnd, linuxppc-dev, torvalds, paulus, linux-kernel, sparclinux, akpm

From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date: Tue, 24 Aug 2010 08:01:25 +1000

> On Mon, 2010-08-23 at 15:44 +0200, Arnd Bergmann wrote:
>> 
>> * Alpha has an optimization for the uniprocessor case, where the atomic
>> instructions get turned into nonatomic additions. The spinlock based
>> version uses no locks on UP but disables interrupts for reasons I don't
>> understand (nothing running at interrupt time should try to access an rwsem).
>> Should the generic version do the same as Alpha?
> 
> I've seen drivers in the past do trylocks at interrupt time ... tho I
> agree it sucks.

Recently there was a thread where this was declared absolutely illegal.

Maybe it was allowed, or sort-of worked before, and that's why it's
accounted for with IRQ disables in some implementations.  I don't
know.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: 64-bit ppc rwsem
  2010-08-23 22:18                     ` David Miller
@ 2010-08-24  1:31                       ` Benjamin Herrenschmidt
  2010-08-24 12:06                         ` Arnd Bergmann
  0 siblings, 1 reply; 25+ messages in thread
From: Benjamin Herrenschmidt @ 2010-08-24  1:31 UTC (permalink / raw)
  To: David Miller
  Cc: arnd, linuxppc-dev, torvalds, paulus, linux-kernel, sparclinux, akpm

On Mon, 2010-08-23 at 15:18 -0700, David Miller wrote:
> > I've seen drivers in the past do trylocks at interrupt time ... tho
> I
> > agree it sucks.
> 
> Recently there was a thread where this was declared absolutely
> illegal.
> 
> Maybe it was allowed, or sort-of worked before, and that's why it's
> accounted for with IRQ disables in some implementations.  I don't
> know. 

Ok, I'm happy to say it's a big no-no then.

Arnd, do you want to take over the moving to asm-generic and take care
of the spinlock case as well ? I can send Linus the first patch that
changes powerpc to use atomic_long now along with a few other things I
have pending, then you can pickup from there. Or do you want me to
continue pushing my patch as-is and we can look at cleaning up the
spinlock case separately ?

Cheers,
Ben.


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 2/2] rwsem: Move powerpc atomic-long based implementation to asm-generic
  2010-08-20  6:43                   ` Sam Ravnborg
@ 2010-08-24  1:32                     ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 25+ messages in thread
From: Benjamin Herrenschmidt @ 2010-08-24  1:32 UTC (permalink / raw)
  To: Sam Ravnborg
  Cc: Linus Torvalds, akpm, sparclinux, linux-kernel, paulus,
	linuxppc-dev, David Miller

On Fri, 2010-08-20 at 08:43 +0200, Sam Ravnborg wrote:
> > diff --git a/include/asm-generic/rwsem-cmpxchg.h b/include/asm-generic/rwsem-cmpxchg.h
> > new file mode 100644
> > index 0000000..2b1c859
> > --- /dev/null
> > +++ b/include/asm-generic/rwsem-cmpxchg.h
> > @@ -0,0 +1,183 @@
> > +#ifndef _RWSEM_CMPXCHG_H
> > +#define _RWSEM_CMPXCHG_H
> > +
> > +#ifndef _LINUX_RWSEM_H
> > +#error "Please don't include <asm/rwsem.h> directly, use <linux/rwsem.h> instead."
> > +#endif
> > +
> > +#ifdef __KERNEL__
> 
> #ifdef __KERNEL__ is only relevant for exported headers.
> For kernel only headers like this is does not make sense,
> but it does not harm.

Well, it was there in the first place, I think we've carried around
forever, but as you say, it doesn't really harm.

Ben.



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 1/2] powerpc: Make rwsem use "long" type
  2010-08-20  5:14                 ` [PATCH 1/2] powerpc: Make rwsem use "long" type Benjamin Herrenschmidt
@ 2010-08-24  1:37                   ` Timur Tabi
  0 siblings, 0 replies; 25+ messages in thread
From: Timur Tabi @ 2010-08-24  1:37 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: torvalds, akpm, sparclinux, linux-kernel, paulus, linuxppc-dev,
	David Miller

On Fri, Aug 20, 2010 at 12:14 AM, Benjamin Herrenschmidt
<benh@kernel.crashing.org> wrote:

>  static inline int rwsem_is_locked(struct rw_semaphore *sem)
>  {
> -       return (sem->count != 0);
> +       return sem->count != 0;
>  }

Does this change make the code do anything different?

-- 
Timur Tabi
Linux kernel developer at Freescale

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: 64-bit ppc rwsem
  2010-08-24  1:31                       ` Benjamin Herrenschmidt
@ 2010-08-24 12:06                         ` Arnd Bergmann
  0 siblings, 0 replies; 25+ messages in thread
From: Arnd Bergmann @ 2010-08-24 12:06 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: David Miller, linuxppc-dev, torvalds, paulus, linux-kernel,
	sparclinux, akpm

On Tuesday 24 August 2010, Benjamin Herrenschmidt wrote:
> On Mon, 2010-08-23 at 15:18 -0700, David Miller wrote:
> > > I've seen drivers in the past do trylocks at interrupt time ... tho
> > I
> > > agree it sucks.
> > 
> > Recently there was a thread where this was declared absolutely
> > illegal.
> > 
> > Maybe it was allowed, or sort-of worked before, and that's why it's
> > accounted for with IRQ disables in some implementations.  I don't
> > know. 
> 
> Ok, I'm happy to say it's a big no-no then.
> 
> Arnd, do you want to take over the moving to asm-generic and take care
> of the spinlock case as well ? I can send Linus the first patch that
> changes powerpc to use atomic_long now along with a few other things I
> have pending, then you can pickup from there. Or do you want me to
> continue pushing my patch as-is and we can look at cleaning up the
> spinlock case separately ?

I'm currently doing too many things at once, please push in your existing
patch for now, we can continue from there.

For the asm-generic patch:
Acked-by: Arnd Bergmann <arnd@arndb.de>

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2010-08-24 12:06 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-08-18  1:03 [GIT] Sparc David Miller
2010-08-18  1:31 ` Linus Torvalds
2010-08-18  1:59   ` Linus Torvalds
2010-08-18  2:14     ` David Miller
2010-08-18  4:38       ` 64-bit ppc rwsem (was: Re: [GIT] Sparc) Benjamin Herrenschmidt
2010-08-18  5:03         ` Benjamin Herrenschmidt
2010-08-18  5:28           ` 64-bit ppc rwsem David Miller
2010-08-18  5:39             ` Sam Ravnborg
2010-08-18  5:48               ` David Miller
2010-08-19  5:23             ` Benjamin Herrenschmidt
2010-08-19  5:29               ` David Miller
2010-08-19 10:24                 ` Benjamin Herrenschmidt
2010-08-20  5:14                 ` [PATCH 1/2] powerpc: Make rwsem use "long" type Benjamin Herrenschmidt
2010-08-24  1:37                   ` Timur Tabi
2010-08-20  5:14                 ` [PATCH 2/2] rwsem: Move powerpc atomic-long based implementation to asm-generic Benjamin Herrenschmidt
2010-08-20  6:43                   ` Sam Ravnborg
2010-08-24  1:32                     ` Benjamin Herrenschmidt
2010-08-23  4:39                   ` David Miller
2010-08-23 13:44                 ` 64-bit ppc rwsem Arnd Bergmann
2010-08-23 22:01                   ` Benjamin Herrenschmidt
2010-08-23 22:18                     ` David Miller
2010-08-24  1:31                       ` Benjamin Herrenschmidt
2010-08-24 12:06                         ` Arnd Bergmann
2010-08-18  2:12   ` [GIT] Sparc David Miller
2010-08-18  2:50     ` Al Viro

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).